aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhilip Blundell <philb@gnu.org>2001-01-04 20:19:48 +0000
committerPhil Blundell <pb@gcc.gnu.org>2001-01-04 20:19:48 +0000
commitceebdb0980bee33cbd7b08dcd350f4faa7634f27 (patch)
tree3ec75373ca28b0ad0d63d95fb668c8f7327670ad
parent1fd4f141391f8f683be28c3353d6753bd24d6905 (diff)
downloadgcc-ceebdb0980bee33cbd7b08dcd350f4faa7634f27.zip
gcc-ceebdb0980bee33cbd7b08dcd350f4faa7634f27.tar.gz
gcc-ceebdb0980bee33cbd7b08dcd350f4faa7634f27.tar.bz2
arm.c (arm_gen_constant): Prefer to emit constants from bit 31 downwards, if this requires no more insns.
2001-01-04 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. (count_insns_for_constant): New helper function for above. From-SVN: r38690
-rw-r--r--gcc/ChangeLog6
-rw-r--r--gcc/config/arm/arm.c60
2 files changed, 63 insertions, 3 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 87503ba..6a2c343 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,9 @@
+2001-01-04 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.
+ (count_insns_for_constant): New helper function for above.
+
2001-01-04 Alexandre Oliva <aoliva@redhat.com>
* gencodes.c (output_predicate_decls): Remove empty initializer.
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index c3a936c..d71dcd1 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -986,6 +986,33 @@ arm_split_constant (code, mode, val, target, source, subtargets)
return arm_gen_constant (code, mode, val, target, source, subtargets, 1);
}
+static int
+count_insns_for_constant (HOST_WIDE_INT remainder, int i)
+{
+ HOST_WIDE_INT temp1;
+ int num_insns = 0;
+ do
+ {
+ int end;
+
+ if (i <= 0)
+ i += 32;
+ if (remainder & (3 << (i - 2)))
+ {
+ end = i - 8;
+ if (end < 0)
+ end += 32;
+ temp1 = remainder & ((0x0ff << end)
+ | ((i < end) ? (0xff >> (32 - end)) : 0));
+ remainder &= ~temp1;
+ num_insns++;
+ i -= 6;
+ }
+ i -= 2;
+ } while (remainder);
+ return num_insns;
+}
+
/* As above, but extra parameter GENERATE which, if clear, suppresses
RTL generation. */
static int
@@ -1466,9 +1493,36 @@ arm_gen_constant (code, mode, val, target, source, subtargets, generate)
}
}
- /* 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 synthesize 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. */
+ if (best_start != 0
+ && ((((unsigned HOST_WIDE_INT) 1) << best_start) < remainder)
+ && (count_insns_for_constant (remainder, 0) <=
+ count_insns_for_constant (remainder, best_start)))
+ best_start = 0;
+
+ /* Now start emitting the insns. */
i = best_start;
do
{