diff options
author | Maciej W. Rozycki <macro@linux-mips.org> | 2004-01-14 18:01:09 +0000 |
---|---|---|
committer | Maciej W. Rozycki <macro@linux-mips.org> | 2004-01-14 18:01:09 +0000 |
commit | 895921c97ec40f58b356443e50255d054571ef46 (patch) | |
tree | 0595e8d1ce51eb5d41117bd396ab8b467cd86434 /gas/config | |
parent | 63d06c5c42c2367dcafe44679742b5435463418b (diff) | |
download | gdb-895921c97ec40f58b356443e50255d054571ef46.zip gdb-895921c97ec40f58b356443e50255d054571ef46.tar.gz gdb-895921c97ec40f58b356443e50255d054571ef46.tar.bz2 |
gas/
* config/tc-mips.c (append_insn): Properly detect variant frags
that preclude swapping of relaxed branches. Correctly swap
instructions between frags when dealing with relaxed branches.
gas/testsuite/
* gas/mips/relax-swap1-mips1.d: New test for branch relaxation
with swapping for MIPS1.
* gas/mips/relax-swap1-mips2.d: New test for branch relaxation
with swapping for MIPS2.
* gas/mips/relax-swap1.l: Stderr output for the new tests.
* gas/mips/relax-swap1.s: Source for the new tests.
* gas/mips/relax-swap2.d: New test for branch likely relaxation
with swapping.
* gas/mips/relax-swap2.l: Stderr output for the new test.
* gas/mips/relax-swap2.s: Source for the new test.
* gas/mips/mips.exp: Run the new tests.
Diffstat (limited to 'gas/config')
-rw-r--r-- | gas/config/tc-mips.c | 78 |
1 files changed, 59 insertions, 19 deletions
diff --git a/gas/config/tc-mips.c b/gas/config/tc-mips.c index fcf0a79..55c2482 100644 --- a/gas/config/tc-mips.c +++ b/gas/config/tc-mips.c @@ -1539,6 +1539,8 @@ append_insn (char *place, struct mips_cl_insn *ip, expressionS *address_expr, char *f; fixS *fixp[3]; int nops = 0; + relax_stateT prev_insn_frag_type = 0; + bfd_boolean relaxed_branch = FALSE; bfd_boolean force_new_frag = FALSE; /* Mark instruction labels in mips16 mode. */ @@ -1919,6 +1921,10 @@ append_insn (char *place, struct mips_cl_insn *ip, expressionS *address_expr, } } + /* Record the frag type before frag_var. */ + if (prev_insn_frag) + prev_insn_frag_type = prev_insn_frag->fr_type; + if (place == NULL && address_expr && *reloc_type == BFD_RELOC_16_PCREL_S2 @@ -1932,6 +1938,7 @@ append_insn (char *place, struct mips_cl_insn *ip, expressionS *address_expr, && !(mips_opts.noat && mips_pic != NO_PIC) && !mips_opts.mips16) { + relaxed_branch = TRUE; f = frag_var (rs_machine_dependent, relaxed_branch_length (NULL, NULL, @@ -2262,12 +2269,12 @@ append_insn (char *place, struct mips_cl_insn *ip, expressionS *address_expr, there are any branches to anything other than a label, users must use .set noreorder. */ || insn_labels != NULL - /* If the previous instruction is in a variant frag, we - can not do the swap. This does not apply to the - mips16, which uses variant frags for different - purposes. */ + /* If the previous instruction is in a variant frag + other than this branch's one, we cannot do the swap. + This does not apply to the mips16, which uses variant + frags for different purposes. */ || (! mips_opts.mips16 - && prev_insn_frag->fr_type == rs_machine_dependent) + && prev_insn_frag_type == rs_machine_dependent) /* If the branch reads the condition codes, we don't even try to swap, because in the sequence ctc1 $X,$31 @@ -2452,9 +2459,29 @@ append_insn (char *place, struct mips_cl_insn *ip, expressionS *address_expr, char temp[4]; prev_f = prev_insn_frag->fr_literal + prev_insn_where; - memcpy (temp, prev_f, 4); - memcpy (prev_f, f, 4); - memcpy (f, temp, 4); + if (!relaxed_branch) + { + /* If this is not a relaxed branch, then just + swap the instructions. */ + memcpy (temp, prev_f, 4); + memcpy (prev_f, f, 4); + memcpy (f, temp, 4); + } + else + { + /* If this is a relaxed branch, then we move the + instruction to be placed in the delay slot to + the current frag, shrinking the fixed part of + the originating frag. If the branch occupies + the tail of the latter, we move it backwards, + into the space freed by the moved instruction. */ + f = frag_more (4); + memcpy (f, prev_f, 4); + prev_insn_frag->fr_fix -= 4; + if (prev_insn_frag->fr_type == rs_machine_dependent) + memmove (prev_f, prev_f + 4, prev_insn_frag->fr_var); + } + if (prev_insn_fixp[0]) { prev_insn_fixp[0]->fx_frag = frag_now; @@ -2482,20 +2509,33 @@ append_insn (char *place, struct mips_cl_insn *ip, expressionS *address_expr, frag. */ force_new_frag = TRUE; } - if (fixp[0]) - { - fixp[0]->fx_frag = prev_insn_frag; - fixp[0]->fx_where = prev_insn_where; - } - if (fixp[1]) + + if (!relaxed_branch) { - fixp[1]->fx_frag = prev_insn_frag; - fixp[1]->fx_where = prev_insn_where; + if (fixp[0]) + { + fixp[0]->fx_frag = prev_insn_frag; + fixp[0]->fx_where = prev_insn_where; + } + if (fixp[1]) + { + fixp[1]->fx_frag = prev_insn_frag; + fixp[1]->fx_where = prev_insn_where; + } + if (fixp[2]) + { + fixp[2]->fx_frag = prev_insn_frag; + fixp[2]->fx_where = prev_insn_where; + } } - if (fixp[2]) + else if (prev_insn_frag->fr_type == rs_machine_dependent) { - fixp[2]->fx_frag = prev_insn_frag; - fixp[2]->fx_where = prev_insn_where; + if (fixp[0]) + fixp[0]->fx_where -= 4; + if (fixp[1]) + fixp[1]->fx_where -= 4; + if (fixp[2]) + fixp[2]->fx_where -= 4; } } else |