This is the mail archive of the mailing list for the binutils project.

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATC] MIPS16/GAS: Permit branch swapping with PC-relative insns


 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
	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
	lw	$3, 1f - 0b($pc)
	addiu	$2, $pc, 1f - 0b
	jr	$4
	.end	foo

but that would require a change complex enough for me not to make at this 

 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  <>

	* config/tc-mips.c (can_swap_branch_p): Permit the swapping of
	PC-relative MIPS16 instructions.  Update the comment on MIPS16


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;

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]