[PATC] MIPS16/GAS: Permit branch swapping with PC-relative insns
Maciej W. Rozycki
macro@codesourcery.com
Tue Aug 2 23:01:00 GMT 2011
Hi,
While at microMIPS branch swapping, I believe it is safe to swap MIPS16
basic instructions that use the PC-relative addressing mode too with a
subsequent jump instruction to fill its delay slot. There are four such
instructions, namely: ADDIU, DADDIU, LD and LW. There are two arguments
standing both at a time that make me think so:
1. The use of any complex expression (one that evaluates to but a plain
number) as the immediate argument of any of these instructions causes
relaxation to trigger (even if the basic form of the instruction is
forced with .set noautoxtend or .t suffix) that marks the instruction
fixed and inhibits branch swapping.
2. All these instructions, if placed in a jump delay slot, use the value
of the PC of the preceding jump rather than that of the delay slot
itself for calculation -- the value of the PC retrieved therefore
remains the same after the swap (note that, contrariwise, this is not
the case with the microMIPS ADDIUPC instruction).
These two programs:
$ mips-sde-elf-objdump -dr addiupc16-2.o
addiupc16-2.o: file format elf32-tradbigmips
Disassembly of section .text:
00000000 <foo>:
0: b301 lw v1,4 <foo+0x4>
2: 0a01 la v0,4 <foo+0x4>
4: ec00 jr a0
6: 6500 nop
$ mips-sde-elf-objdump -dr addiupc16-3.o
addiupc16-3.o: file format elf32-tradbigmips
Disassembly of section .text:
00000000 <foo>:
0: b301 lw v1,4 <foo+0x4>
2: ec00 jr a0
4: 0a01 la v0,4 <foo+0x4>
6: 6500 nop
built from this source:
$ cat addiupc16-2.s
.globl foo
.type foo, @function
.ent foo
foo:
lw $3, 4($pc)
addiu $2, $pc, 4
jr $4
.end foo
are therefore equivalent -- in fact the very dumps above confirm this by
printing the same cooked address in both cases (given the way the
instructions are dumped this might be more obvious if --adjust-vma= was
used, but I think <foo+0x4> makes it clear enough anyway).
As I think would be the same code emitted from this source:
$ cat addiupc16-0.s
.globl foo
.type foo, @function
.ent foo
foo:
0:
lw $3, 1f - 0b($pc)
addiu $2, $pc, 1f - 0b
1:
jr $4
.end foo
but that would require a change complex enough for me not to make at this
time.
While at it I have adjusted a comment about MIPS16 mode fixups that I
believe is no longer accurate -- these days we support MIPS16 mode
relocations on instructions other than branches (hmm, was it jumps that
were meant here instead? -- or relaxed branches that are otherwise fixed
as noted above anyway?) too (but then they are extended instructions).
No regressions for mips-sde-elf or mips-linux-gnu, but then these cases
are probably not covered anyway. OK to apply? And shall I make a test
case out of the snippets above if so (yes, presumably)?
2011-08-02 Maciej W. Rozycki <macro@codesourcery.com>
gas/
* config/tc-mips.c (can_swap_branch_p): Permit the swapping of
PC-relative MIPS16 instructions. Update the comment on MIPS16
fixups.
Maciej
binutils-gas-mips16-pc-swap.diff
Index: binutils-fsf-trunk-quilt/gas/config/tc-mips.c
===================================================================
--- binutils-fsf-trunk-quilt.orig/gas/config/tc-mips.c 2011-08-02 18:07:59.000000000 +0100
+++ binutils-fsf-trunk-quilt/gas/config/tc-mips.c 2011-08-02 22:16:22.000000000 +0100
@@ -3679,8 +3679,8 @@ can_swap_branch_p (struct mips_cl_insn *
return FALSE;
/* If the previous instruction had a fixup in mips16 mode, we can not
- swap. This normally means that the previous instruction was a 4
- byte branch anyhow. */
+ swap. This normally means that the previous instruction was
+ a 4-byte extended instruction anyhow. */
if (mips_opts.mips16 && history[0].fixp[0])
return FALSE;
@@ -3748,10 +3748,9 @@ can_swap_branch_p (struct mips_cl_insn *
&& (prev_pinfo & INSN_READ_COND_CODE))
return FALSE;
- /* If the previous instruction uses the PC, we can not swap. */
+ /* In the microMIPS mode if the previous instruction uses the PC,
+ we cannot swap. */
prev_pinfo2 = history[0].insn_mo->pinfo2;
- if (mips_opts.mips16 && (prev_pinfo & MIPS16_INSN_READ_PC))
- return FALSE;
if (mips_opts.micromips && (prev_pinfo2 & INSN2_READ_PC))
return FALSE;
More information about the Binutils
mailing list