summaryrefslogtreecommitdiff
path: root/gas
diff options
context:
space:
mode:
Diffstat (limited to 'gas')
-rw-r--r--gas/ChangeLog14
-rw-r--r--gas/config/tc-riscv.c96
-rw-r--r--gas/config/tc-riscv.h14
3 files changed, 82 insertions, 42 deletions
diff --git a/gas/ChangeLog b/gas/ChangeLog
index a603984e698..f7d36b50495 100644
--- a/gas/ChangeLog
+++ b/gas/ChangeLog
@@ -1,3 +1,17 @@
+2015-12-20 Andrew Waterman <andrew@sifive.com>
+
+ * config/tc-riscv.c (riscv_pseudo_table): Remove "align",
+ "p2align", and "balign".
+ (s_align): Remove.
+ (riscv_handle_align): New function.
+ (riscv_frag_align_code): Likewise.
+ (riscv_make_nops): Likewise.
+ * config/tc-riscv.h (MAX_MEM_FOR_RS_ALIGN_CODE): Change to 7.
+ (HANDLE_ALIGN): Define.
+ (md_do_align): Define.
+ (riscv_handle_align): Declare.
+ (riscv_frag_align_code): Likewise.
+
2016-12-20 Andrew Waterman <andrew@sifive.com>
* config/tc-riscv.h (xlen): Delete.
diff --git a/gas/config/tc-riscv.c b/gas/config/tc-riscv.c
index 77c92cfac30..2d953c54cad 100644
--- a/gas/config/tc-riscv.c
+++ b/gas/config/tc-riscv.c
@@ -2185,63 +2185,82 @@ s_bss (int ignore ATTRIBUTE_UNUSED)
demand_empty_rest_of_line ();
}
-/* Align to a given power of two. */
-
static void
-s_align (int bytes_p)
+riscv_make_nops (char *buf, bfd_vma bytes)
{
- int fill_value = 0, fill_value_specified = 0;
- int min_text_alignment = riscv_opts.rvc ? 2 : 4;
- int alignment = get_absolute_expression(), bytes;
+ bfd_vma i = 0;
- if (bytes_p)
+ if (bytes % 4 == 2)
{
- bytes = alignment;
- if (bytes < 1 || (bytes & (bytes-1)) != 0)
- as_bad (_("alignment not a power of 2: %d"), bytes);
- for (alignment = 0; bytes > 1; bytes >>= 1)
- alignment++;
+ md_number_to_chars (buf, RVC_NOP, 2);
+ i += 2;
}
- bytes = 1 << alignment;
+ gas_assert ((bytes - i) % 4 == 0);
- if (alignment < 0 || alignment > 31)
- as_bad (_("unsatisfiable alignment: %d"), alignment);
+ for ( ; i < bytes; i += 4)
+ md_number_to_chars (buf + i, RISCV_NOP, 4);
+}
- if (*input_line_pointer == ',')
- {
- ++input_line_pointer;
- fill_value = get_absolute_expression ();
- fill_value_specified = 1;
- }
+/* Called from md_do_align. Used to create an alignment frag in a
+ code section by emitting a worst-case NOP sequence that the linker
+ will later relax to the correct number of NOPs. We can't compute
+ the correct alignment now because of other linker relaxations. */
+
+bfd_boolean
+riscv_frag_align_code (int n)
+{
+ bfd_vma bytes = (bfd_vma)1 << n;
+ bfd_vma min_text_alignment = riscv_opts.rvc ? 2 : 4;
+
+ /* When not relaxing, riscv_handle_align handles code alignment. */
+ if (!riscv_opts.relax)
+ return FALSE;
- if (!fill_value_specified
- && subseg_text_p (now_seg)
- && bytes > min_text_alignment)
+ if (bytes > min_text_alignment)
{
- /* Emit the worst-case NOP string. The linker will delete any
- unnecessary NOPs. This allows us to support code alignment
- in spite of linker relaxations. */
- bfd_vma i, worst_case_bytes = bytes - min_text_alignment;
+ bfd_vma worst_case_bytes = bytes - min_text_alignment;
char *nops = frag_more (worst_case_bytes);
- for (i = 0; i < worst_case_bytes - 2; i += 4)
- md_number_to_chars (nops + i, RISCV_NOP, 4);
- if (i < worst_case_bytes)
- md_number_to_chars (nops + i, RVC_NOP, 2);
-
expressionS ex;
+
ex.X_op = O_constant;
ex.X_add_number = worst_case_bytes;
+ riscv_make_nops (nops, worst_case_bytes);
+
fix_new_exp (frag_now, nops - frag_now->fr_literal, 0,
&ex, FALSE, BFD_RELOC_RISCV_ALIGN);
}
- else if (alignment)
- frag_align (alignment, fill_value, 0);
- record_alignment (now_seg, alignment);
+ return TRUE;
+}
- demand_empty_rest_of_line ();
+/* Implement HANDLE_ALIGN. */
+
+void
+riscv_handle_align (fragS *fragP)
+{
+ switch (fragP->fr_type)
+ {
+ case rs_align_code:
+ /* When relaxing, riscv_frag_align_code handles code alignment. */
+ if (!riscv_opts.relax)
+ {
+ bfd_signed_vma count = fragP->fr_next->fr_address
+ - fragP->fr_address - fragP->fr_fix;
+
+ if (count <= 0)
+ break;
+
+ count &= MAX_MEM_FOR_RS_ALIGN_CODE;
+ riscv_make_nops (fragP->fr_literal + fragP->fr_fix, count);
+ fragP->fr_var = count;
+ }
+ break;
+
+ default:
+ break;
+ }
}
int
@@ -2488,9 +2507,6 @@ static const pseudo_typeS riscv_pseudo_table[] =
{"dtprelword", s_dtprel, 4},
{"dtpreldword", s_dtprel, 8},
{"bss", s_bss, 0},
- {"align", s_align, 0},
- {"p2align", s_align, 0},
- {"balign", s_align, 1},
{"uleb128", s_riscv_leb128, 0},
{"sleb128", s_riscv_leb128, 1},
diff --git a/gas/config/tc-riscv.h b/gas/config/tc-riscv.h
index 5e07fdae643..5d6b83f94af 100644
--- a/gas/config/tc-riscv.h
+++ b/gas/config/tc-riscv.h
@@ -48,8 +48,18 @@ extern int riscv_relax_frag (asection *, struct frag *, long);
#define md_undefined_symbol(name) (0)
#define md_operand(x)
-/* FIXME: it is unclear if this is used, or if it is even correct. */
-#define MAX_MEM_FOR_RS_ALIGN_CODE (1 + 2)
+extern bfd_boolean riscv_frag_align_code (int);
+#define md_do_align(N, FILL, LEN, MAX, LABEL) \
+ if ((N) != 0 && !(FILL) && !need_pass_2 && subseg_text_p (now_seg)) \
+ { \
+ if (riscv_frag_align_code (N)) \
+ goto LABEL; \
+ }
+
+extern void riscv_handle_align (fragS *);
+#define HANDLE_ALIGN riscv_handle_align
+
+#define MAX_MEM_FOR_RS_ALIGN_CODE 7
/* The ISA of the target may change based on command-line arguments. */
#define TARGET_FORMAT riscv_target_format()