diff options
author | Richard Sandiford <rdsandiford@googlemail.com> | 2005-03-09 09:22:25 +0000 |
---|---|---|
committer | Richard Sandiford <rdsandiford@googlemail.com> | 2005-03-09 09:22:25 +0000 |
commit | 7d10b47d345a502553140c66912cf3c9505bb93d (patch) | |
tree | 6ec503a4ef6596fad1478dcb0b5add3c485d3f6f /gas/config/tc-mips.c | |
parent | 404a80717cae4ad3273ae1a3920301ed1db91012 (diff) | |
download | gdb-7d10b47d345a502553140c66912cf3c9505bb93d.zip gdb-7d10b47d345a502553140c66912cf3c9505bb93d.tar.gz gdb-7d10b47d345a502553140c66912cf3c9505bb93d.tar.bz2 |
* config/tc-mips.h (mips_flush_pending_output): Delete.
(mips_emit_delays): Declare.
(md_flush_pending_output): Use mips_emit_delays.
* config/tc-mips.c (mips_no_prev_insn): Remove parameter; always forget
the previous instructions.
(md_begin, append_insn, md_parse_option): Update callers.
(mips_emit_delay): Remove parameter. Move INSNS != 0 code to
start_noreorder.
(mips_align, s_change_sec, s_cons, s_float_cons, s_gpword)
(s_gpdword): Update callers.
(start_noreorder, end_noreorder): New functions.
(macro, macro2, mips16_macro, s_mipsset): Use them instead of
manipulating mips_opts or prev_nop_frag directly.
(mips_flush_pending_output): Delete.
Diffstat (limited to 'gas/config/tc-mips.c')
-rw-r--r-- | gas/config/tc-mips.c | 213 |
1 files changed, 97 insertions, 116 deletions
diff --git a/gas/config/tc-mips.c b/gas/config/tc-mips.c index dac2801..8e464f6 100644 --- a/gas/config/tc-mips.c +++ b/gas/config/tc-mips.c @@ -928,7 +928,7 @@ enum mips_regclass { MIPS_GR_REG, MIPS_FP_REG, MIPS16_REG }; static void append_insn (struct mips_cl_insn *ip, expressionS *p, bfd_reloc_code_real_type *r); -static void mips_no_prev_insn (int); +static void mips_no_prev_insn (void); static void mips16_macro_build (expressionS *, const char *, const char *, va_list); static void load_register (int, expressionS *, int); @@ -1477,7 +1477,7 @@ md_begin (void) &zero_address_frag)); } - mips_no_prev_insn (FALSE); + mips_no_prev_insn (); mips_gprmask = 0; mips_cprmask[0] = 0; @@ -2664,7 +2664,7 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr, /* If that was an unconditional branch, forget the previous insn information. */ if (pinfo & INSN_UNCOND_BRANCH_DELAY) - mips_no_prev_insn (FALSE); + mips_no_prev_insn (); } else if (pinfo & INSN_COND_BRANCH_LIKELY) { @@ -2685,49 +2685,57 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr, mips_clear_insn_labels (); } -/* This function forgets that there was any previous instruction or - label. If PRESERVE is non-zero, it remembers enough information to - know whether nops are needed before a noreorder section. */ +/* Forget that there was any previous instruction or label. */ static void -mips_no_prev_insn (int preserve) +mips_no_prev_insn (void) { - size_t i; - - if (! preserve) - { - prev_nop_frag = NULL; - prev_nop_frag_holds = 0; - prev_nop_frag_required = 0; - prev_nop_frag_since = 0; - for (i = 0; i < ARRAY_SIZE (history); i++) - history[i] = (mips_opts.mips16 ? mips16_nop_insn : nop_insn); - } - else - for (i = 0; i < ARRAY_SIZE (history); i++) - { - history[i].fixed_p = 1; - history[i].noreorder_p = 0; - history[i].mips16_absolute_jump_p = 0; - } + prev_nop_frag = NULL; + insert_into_history (0, ARRAY_SIZE (history), NOP_INSN); mips_clear_insn_labels (); } -/* This function must be called whenever we turn on noreorder or emit - something other than instructions. It inserts any NOPS which might - be needed by the previous instruction, and clears the information - kept for the previous instructions. The INSNS parameter is true if - instructions are to follow. */ +/* This function must be called before we emit something other than + instructions. It is like mips_no_prev_insn except that it inserts + any NOPS that might be needed by previous instructions. */ -static void -mips_emit_delays (bfd_boolean insns) +void +mips_emit_delays (void) { if (! mips_opts.noreorder) { int nops = nops_for_insn (history, NULL); if (nops > 0) { - if (insns && mips_optimize != 0) + while (nops-- > 0) + add_fixed_insn (NOP_INSN); + mips_move_labels (); + } + } + mips_no_prev_insn (); +} + +/* Start a (possibly nested) noreorder block. */ + +static void +start_noreorder (void) +{ + if (mips_opts.noreorder == 0) + { + unsigned int i; + int nops; + + /* None of the instructions before the .set noreorder can be moved. */ + for (i = 0; i < ARRAY_SIZE (history); i++) + history[i].fixed_p = 1; + + /* Insert any nops that might be needed between the .set noreorder + block and the previous instructions. We will later remove any + nops that turn out not to be needed. */ + nops = nops_for_insn (history, NULL); + if (nops > 0) + { + if (mips_optimize != 0) { /* Record the frag which holds the nop instructions, so that we can remove them if we don't need them. */ @@ -2741,23 +2749,35 @@ mips_emit_delays (bfd_boolean insns) for (; nops > 0; --nops) add_fixed_insn (NOP_INSN); - if (insns) - { - /* Move on to a new frag, so that it is safe to simply - decrease the size of prev_nop_frag. */ - frag_wane (frag_now); - frag_new (0); - } - + /* Move on to a new frag, so that it is safe to simply + decrease the size of prev_nop_frag. */ + frag_wane (frag_now); + frag_new (0); mips_move_labels (); } + mips16_mark_labels (); + mips_clear_insn_labels (); } + mips_opts.noreorder++; + mips_any_noreorder = 1; +} - /* Mark instruction labels in mips16 mode. */ - if (insns) - mips16_mark_labels (); +/* End a nested noreorder block. */ - mips_no_prev_insn (insns); +static void +end_noreorder (void) +{ + mips_opts.noreorder--; + if (mips_opts.noreorder == 0 && prev_nop_frag != NULL) + { + /* Commit to inserting prev_nop_frag_required nops and go back to + handling nop insertion the .set reorder way. */ + prev_nop_frag->fr_fix -= ((prev_nop_frag_holds - prev_nop_frag_required) + * (mips_opts.mips16 ? 2 : 4)); + insert_into_history (prev_nop_frag_since, + prev_nop_frag_required, NOP_INSN); + prev_nop_frag = NULL; + } } /* Set up global variables for the start of a new macro. */ @@ -4061,9 +4081,7 @@ macro (struct mips_cl_insn *ip) sub v0,$zero,$a0 */ - mips_emit_delays (TRUE); - ++mips_opts.noreorder; - mips_any_noreorder = 1; + start_noreorder (); expr1.X_add_number = 8; macro_build (&expr1, "bgez", "s,p", sreg); @@ -4073,7 +4091,7 @@ macro (struct mips_cl_insn *ip) move_register (dreg, sreg); macro_build (NULL, dbl ? "dsub" : "sub", "d,v,t", dreg, 0, sreg); - --mips_opts.noreorder; + end_noreorder (); break; case M_ADD_I: @@ -4581,9 +4599,7 @@ macro (struct mips_cl_insn *ip) break; } - mips_emit_delays (TRUE); - ++mips_opts.noreorder; - mips_any_noreorder = 1; + start_noreorder (); if (mips_trap) { macro_build (NULL, "teq", "s,t,q", treg, 0, 7); @@ -4617,7 +4633,7 @@ macro (struct mips_cl_insn *ip) macro_build (NULL, "teq", "s,t,q", sreg, AT, 6); /* We want to close the noreorder block as soon as possible, so that later insns are available for delay slot filling. */ - --mips_opts.noreorder; + end_noreorder (); } else { @@ -4627,7 +4643,7 @@ macro (struct mips_cl_insn *ip) /* We want to close the noreorder block as soon as possible, so that later insns are available for delay slot filling. */ - --mips_opts.noreorder; + end_noreorder (); macro_build (NULL, "break", "c", 6); } @@ -4722,16 +4738,14 @@ macro (struct mips_cl_insn *ip) s = "ddivu"; s2 = "mfhi"; do_divu3: - mips_emit_delays (TRUE); - ++mips_opts.noreorder; - mips_any_noreorder = 1; + start_noreorder (); if (mips_trap) { macro_build (NULL, "teq", "s,t,q", treg, 0, 7); macro_build (NULL, s, "z,s,t", sreg, treg); /* We want to close the noreorder block as soon as possible, so that later insns are available for delay slot filling. */ - --mips_opts.noreorder; + end_noreorder (); } else { @@ -4741,7 +4755,7 @@ macro (struct mips_cl_insn *ip) /* We want to close the noreorder block as soon as possible, so that later insns are available for delay slot filling. */ - --mips_opts.noreorder; + end_noreorder (); macro_build (NULL, "break", "c", 7); } macro_build (NULL, s2, "d", dreg); @@ -6669,9 +6683,7 @@ macro2 (struct mips_cl_insn *ip) dbl = 1; case M_MULO: do_mulo: - mips_emit_delays (TRUE); - ++mips_opts.noreorder; - mips_any_noreorder = 1; + start_noreorder (); used_at = 1; if (imm) load_register (AT, &imm_expr, dbl); @@ -6688,7 +6700,7 @@ macro2 (struct mips_cl_insn *ip) macro_build (NULL, "nop", "", 0); macro_build (NULL, "break", "c", 6); } - --mips_opts.noreorder; + end_noreorder (); macro_build (NULL, "mflo", "d", dreg); break; @@ -6702,9 +6714,7 @@ macro2 (struct mips_cl_insn *ip) dbl = 1; case M_MULOU: do_mulou: - mips_emit_delays (TRUE); - ++mips_opts.noreorder; - mips_any_noreorder = 1; + start_noreorder (); used_at = 1; if (imm) load_register (AT, &imm_expr, dbl); @@ -6721,7 +6731,7 @@ macro2 (struct mips_cl_insn *ip) macro_build (NULL, "nop", "", 0); macro_build (NULL, "break", "c", 6); } - --mips_opts.noreorder; + end_noreorder (); break; case M_DROL: @@ -7186,9 +7196,7 @@ macro2 (struct mips_cl_insn *ip) * Is the double cfc1 instruction a bug in the mips assembler; * or is there a reason for it? */ - mips_emit_delays (TRUE); - ++mips_opts.noreorder; - mips_any_noreorder = 1; + start_noreorder (); macro_build (NULL, "cfc1", "t,G", treg, RA); macro_build (NULL, "cfc1", "t,G", treg, RA); macro_build (NULL, "nop", ""); @@ -7202,7 +7210,7 @@ macro2 (struct mips_cl_insn *ip) dreg, sreg); macro_build (NULL, "ctc1", "t,G", treg, RA); macro_build (NULL, "nop", ""); - --mips_opts.noreorder; + end_noreorder (); break; case M_ULH: @@ -7442,9 +7450,7 @@ mips16_macro (struct mips_cl_insn *ip) case M_REM_3: s = "mfhi"; do_div3: - mips_emit_delays (TRUE); - ++mips_opts.noreorder; - mips_any_noreorder = 1; + start_noreorder (); macro_build (NULL, dbl ? "ddiv" : "div", "0,x,y", xreg, yreg); expr1.X_add_number = 2; macro_build (&expr1, "bnez", "x,p", yreg); @@ -7454,7 +7460,7 @@ mips16_macro (struct mips_cl_insn *ip) since that causes an overflow. We should do that as well, but I don't see how to do the comparisons without a temporary register. */ - --mips_opts.noreorder; + end_noreorder (); macro_build (NULL, s, "x", zreg); break; @@ -7474,14 +7480,12 @@ mips16_macro (struct mips_cl_insn *ip) s = "ddivu"; s2 = "mfhi"; do_divu3: - mips_emit_delays (TRUE); - ++mips_opts.noreorder; - mips_any_noreorder = 1; + start_noreorder (); macro_build (NULL, s, "0,x,y", xreg, yreg); expr1.X_add_number = 2; macro_build (&expr1, "bnez", "x,p", yreg); macro_build (NULL, "break", "6", 7); - --mips_opts.noreorder; + end_noreorder (); macro_build (NULL, s2, "x", zreg); break; @@ -10194,12 +10198,12 @@ md_parse_option (int c, char *arg) case OPTION_MIPS16: mips_opts.mips16 = 1; - mips_no_prev_insn (FALSE); + mips_no_prev_insn (); break; case OPTION_NO_MIPS16: mips_opts.mips16 = 0; - mips_no_prev_insn (FALSE); + mips_no_prev_insn (); break; case OPTION_MIPS3D: @@ -11058,7 +11062,7 @@ get_symbol (void) static void mips_align (int to, int fill, symbolS *label) { - mips_emit_delays (FALSE); + mips_emit_delays (); frag_align (to, fill, 0); record_alignment (now_seg, to); if (label != NULL) @@ -11120,13 +11124,6 @@ s_align (int x ATTRIBUTE_UNUSED) demand_empty_rest_of_line (); } -void -mips_flush_pending_output (void) -{ - mips_emit_delays (FALSE); - mips_clear_insn_labels (); -} - static void s_change_sec (int sec) { @@ -11142,7 +11139,7 @@ s_change_sec (int sec) obj_elf_section_change_hook (); #endif - mips_emit_delays (FALSE); + mips_emit_delays (); switch (sec) { case 't': @@ -11273,7 +11270,7 @@ s_cons (int log_size) symbolS *label; label = insn_labels != NULL ? insn_labels->label : NULL; - mips_emit_delays (FALSE); + mips_emit_delays (); if (log_size > 0 && auto_align) mips_align (log_size, 0, label); mips_clear_insn_labels (); @@ -11287,7 +11284,7 @@ s_float_cons (int type) label = insn_labels != NULL ? insn_labels->label : NULL; - mips_emit_delays (FALSE); + mips_emit_delays (); if (auto_align) { @@ -11415,22 +11412,13 @@ s_mipsset (int x ATTRIBUTE_UNUSED) if (strcmp (name, "reorder") == 0) { - if (mips_opts.noreorder && prev_nop_frag != NULL) - { - /* If we still have pending nops, we can discard them. The - usual nop handling will insert any that are still - needed. */ - prev_nop_frag->fr_fix -= (prev_nop_frag_holds - * (mips_opts.mips16 ? 2 : 4)); - prev_nop_frag = NULL; - } - mips_opts.noreorder = 0; + if (mips_opts.noreorder) + end_noreorder (); } else if (strcmp (name, "noreorder") == 0) { - mips_emit_delays (TRUE); - mips_opts.noreorder = 1; - mips_any_noreorder = 1; + if (!mips_opts.noreorder) + start_noreorder (); } else if (strcmp (name, "at") == 0) { @@ -11575,16 +11563,9 @@ s_mipsset (int x ATTRIBUTE_UNUSED) /* If we're changing the reorder mode we need to handle delay slots correctly. */ if (s->options.noreorder && ! mips_opts.noreorder) - mips_emit_delays (TRUE); + start_noreorder (); else if (! s->options.noreorder && mips_opts.noreorder) - { - if (prev_nop_frag != NULL) - { - prev_nop_frag->fr_fix -= (prev_nop_frag_holds - * (mips_opts.mips16 ? 2 : 4)); - prev_nop_frag = NULL; - } - } + end_noreorder (); mips_opts = s->options; mips_opts_stack = s->next; @@ -11924,7 +11905,7 @@ s_gpword (int ignore ATTRIBUTE_UNUSED) } label = insn_labels != NULL ? insn_labels->label : NULL; - mips_emit_delays (TRUE); + mips_emit_delays (); if (auto_align) mips_align (2, 0, label); mips_clear_insn_labels (); @@ -11960,7 +11941,7 @@ s_gpdword (int ignore ATTRIBUTE_UNUSED) } label = insn_labels != NULL ? insn_labels->label : NULL; - mips_emit_delays (TRUE); + mips_emit_delays (); if (auto_align) mips_align (3, 0, label); mips_clear_insn_labels (); |