This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
patch for arm_gen_constant
- To: gcc-patches at gcc dot gnu dot org
- Subject: patch for arm_gen_constant
- From: Philip Blundell <philb at gnu dot org>
- Date: Sat, 30 Dec 2000 21:28:40 +0000
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
{