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]

patch for arm_gen_constant


The large-constant-synthesis code in the ARM backend turns out to make a 
fairly bad job of a particular idiom that crops up quite frequently in device 
drivers (though, I suspect, less often in application code).  This patch, 
although not especially elegant, does improve the behaviour for the case in 
question.  The large comment at the top of the patch explains the details.

p.


2000-12-30  Philip Blundell  <philb@gnu.org>

	* config/arm/arm.c (arm_gen_constant): Prefer to emit constants
	from bit 31 downwards, if this requires no more insns.

Index: arm.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/arm/arm.c,v
retrieving revision 1.130
diff -u -p -u -r1.130 arm.c
--- arm.c	2000/12/30 16:34:00	1.130
+++ arm.c	2000/12/30 21:21:42
@@ -1466,9 +1466,83 @@ arm_gen_constant (code, mode, val, targe
 	  }
       }
 
-    /* Now start emitting the insns, starting with the one with the highest
-       bit set: we do this so that the smallest number will be emitted last;
-       this is more likely to be combinable with addressing insns.  */
+    /* So long as it won't require any more insns to do so, it's
+       desirable to emit a small constant (in bits 0...9) in the last
+       insn.  This way there is more chance that it can be combined with
+       a later addressing insn to form a pre-indexed load or store
+       operation.  Consider:
+
+	       *((volatile int *)0xe0000100) = 1;
+	       *((volatile int *)0xe0000110) = 2;
+
+       We want this to wind up as:
+
+		mov rA, #0xe0000000
+		mov rB, #1
+		str rB, [rA, #0x100]
+		mov rB, #2
+		str rB, [rA, #0x110]
+
+       rather than having to synthesise both large constants from scratch.
+
+       Therefore, we calculate how many insns would be required to emit
+       the constant starting from `best_start', and also starting from 
+       zero (ie with bit 31 first to be output).  If `best_start' doesn't 
+       yield a shorter sequence, we may as well use zero.  */
+
+    {
+      unsigned HOST_WIDE_INT temp_remainder;
+      int num_insns = 0, num_insns_zero = 0;
+
+      temp_remainder = remainder;
+      i = best_start;
+      do
+	{
+	  int end;
+	  
+	  if (i <= 0)
+	    i += 32;
+	  if (temp_remainder & (3 << (i - 2)))
+	    {
+	      end = i - 8;
+	      if (end < 0)
+		end += 32;
+	      temp1 = temp_remainder & ((0x0ff << end)
+				   | ((i < end) ? (0xff >> (32 - end)) : 0));
+	      temp_remainder &= ~temp1;
+	      num_insns++;
+	      i -= 6;
+	    }
+	  i -= 2;
+	} while (temp_remainder);
+
+      temp_remainder = remainder;
+      i = 0;
+      do
+	{
+	  int end;
+	  
+	  if (i <= 0)
+	    i += 32;
+	  if (temp_remainder & (3 << (i - 2)))
+	    {
+	      end = i - 8;
+	      if (end < 0)
+		end += 32;
+	      temp1 = temp_remainder & ((0x0ff << end)
+				   | ((i < end) ? (0xff >> (32 - end)) : 0));
+	      temp_remainder &= ~temp1;
+	      num_insns_zero++;
+	      i -= 6;
+	    }
+	  i -= 2;
+	} while (temp_remainder);
+
+      if (num_insns_zero <= num_insns)
+	best_start = 0;
+    }
+
+    /* Now start emitting the insns.  */
     i = best_start;
     do
       {



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