This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC 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]

PR29230 (Invalid Arm offset)


The patch below fixes PR29230. This is an ARM bug that results in out of range 
constant pools. the arith_adjacentmem pattern is an opportunistic pattern to 
use ldm instead of a pair of ldr instructions.
This currently has a length of 12 (3 insns) on the assumption it will expand 
to:

add r1, r0, #const
ldmia r1, {r1, r2}
arith r1, r1, r2

The problem is that SImode memory addresses accept a wider range of offsets 
than the add instruction, so sometimes this expands to 4 insns. There are two 
ways of fixing this:
- Increase th length to 16.
- Use a pair of ldr instructions.

I've chosen the latter option, on the theory that small code is generally 
important on arm, and 2*add+ldm might not be any faster.

The testcase is sufficiently fragile it only triggers on 4.1, so I haven't 
added it to the testsuite. I'm fairly sure the bug is still latent in 4.2.

Tested with cross to arm-none-eabi.
Applied to head and 4.1-branch.

Paul

2006-09-17  Paul Brook  <paul@codesourcery.com>

	PR target/29230
	* config/arm/arm.md (arith_adjacentmem): Handle large offsets.

Index: gcc/config/arm/arm.md
===================================================================
--- gcc/config/arm/arm.md	(revision 117251)
+++ gcc/config/arm/arm.md	(working copy)
@@ -9508,14 +9508,14 @@ (define_insn "*arith_adjacentmem"
     ldm[0] = base_reg;
     if (val1 !=0 && val2 != 0)
       {
+	rtx ops[3];
+
 	if (val1 == 4 || val2 == 4)
 	  /* Other val must be 8, since we know they are adjacent and neither
 	     is zero.  */
 	  output_asm_insn (\"ldm%?ib\\t%0, {%1, %2}\", ldm);
-	else
+	else if (const_ok_for_arm (val1) || const_ok_for_arm (-val1))
 	  {
-	    rtx ops[3];
-
 	    ldm[0] = ops[0] = operands[4];
 	    ops[1] = base_reg;
 	    ops[2] = GEN_INT (val1);
@@ -9525,6 +9525,17 @@ (define_insn "*arith_adjacentmem"
 	    else
 	      output_asm_insn (\"ldm%?da\\t%0, {%1, %2}\", ldm);
 	  }
+	else
+	  {
+	    /* Offset is out of range for a single add, so use two ldr.  */
+	    ops[0] = ldm[1];
+	    ops[1] = base_reg;
+	    ops[2] = GEN_INT (val1);
+	    output_asm_insn (\"ldr%?\\t%0, [%1, %2]\", ops);
+	    ops[0] = ldm[2];
+	    ops[2] = GEN_INT (val2);
+	    output_asm_insn (\"ldr%?\\t%0, [%1, %2]\", ops);
+	  }
       }
     else if (val1 != 0)
       {


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