diff options
Diffstat (limited to 'gas')
-rw-r--r-- | gas/ChangeLog | 14 | ||||
-rw-r--r-- | gas/config/tc-riscv.c | 96 | ||||
-rw-r--r-- | gas/config/tc-riscv.h | 14 |
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() |