aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorRichard Earnshaw <rearnsha@arm.com>2004-02-25 17:03:27 +0000
committerRichard Earnshaw <rearnsha@gcc.gnu.org>2004-02-25 17:03:27 +0000
commit6f5b4f3e5ae86e31fd507ff4d0f986e58febb829 (patch)
tree9c596d8d604250dbf6c92a3954245e9c749242cf /gcc
parent8a7988f51a78c05841fad17683cbb94b9dc33fd0 (diff)
downloadgcc-6f5b4f3e5ae86e31fd507ff4d0f986e58febb829.zip
gcc-6f5b4f3e5ae86e31fd507ff4d0f986e58febb829.tar.gz
gcc-6f5b4f3e5ae86e31fd507ff4d0f986e58febb829.tar.bz2
arm.c (thumb_legitimize_address): New function.
* arm.c (thumb_legitimize_address): New function. * arm-protos.h: Prototype it. * arm.h (THUMB_LEGITIMIZE_ADDRESS): Define. (LEGITIMIZE_ADDRESS): Use it. From-SVN: r78437
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog7
-rw-r--r--gcc/config/arm/arm-protos.h1
-rw-r--r--gcc/config/arm/arm.c68
-rw-r--r--gcc/config/arm/arm.h13
4 files changed, 82 insertions, 7 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 4405cd9..8f405e7 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,10 @@
+2004-02-25 Richard Earnshaw <rearnsha@arm.com>
+
+ * arm.c (thumb_legitimize_address): New function.
+ * arm-protos.h: Prototype it.
+ * arm.h (THUMB_LEGITIMIZE_ADDRESS): Define.
+ (LEGITIMIZE_ADDRESS): Use it.
+
2004-02-25 J"orn Rennecke <joern.rennecke@superh.com>
* reload1.c (reload): Only spill eliminable register with multiple
diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h
index 25f5631..4c0575d 100644
--- a/gcc/config/arm/arm-protos.h
+++ b/gcc/config/arm/arm-protos.h
@@ -54,6 +54,7 @@ extern int arm_legitimate_address_p (enum machine_mode, rtx, int);
extern int thumb_legitimate_address_p (enum machine_mode, rtx, int);
extern int thumb_legitimate_offset_p (enum machine_mode, HOST_WIDE_INT);
extern rtx arm_legitimize_address (rtx, rtx, enum machine_mode);
+extern rtx thumb_legitimize_address (rtx, rtx, enum machine_mode);
extern int arm_const_double_rtx (rtx);
extern int neg_const_double_rtx_ok_for_fpa (rtx);
extern enum reg_class vfp_secondary_reload_class (enum machine_mode, rtx);
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index 98c05cb..0a61e1b 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -3232,6 +3232,74 @@ arm_legitimize_address (rtx x, rtx orig_x, enum machine_mode mode)
return x;
}
+
+/* Try machine-dependent ways of modifying an illegitimate Thumb address
+ to be legitimate. If we find one, return the new, valid address. */
+rtx
+thumb_legitimize_address (rtx x, rtx orig_x, enum machine_mode mode)
+{
+ if (GET_CODE (x) == PLUS
+ && GET_CODE (XEXP (x, 1)) == CONST_INT
+ && (INTVAL (XEXP (x, 1)) >= 32 * GET_MODE_SIZE (mode)
+ || INTVAL (XEXP (x, 1)) < 0))
+ {
+ rtx xop0 = XEXP (x, 0);
+ rtx xop1 = XEXP (x, 1);
+ HOST_WIDE_INT offset = INTVAL (xop1);
+
+ /* Try and fold the offset into a biasing of the base register and
+ then offsetting that. Don't do this when optimizing for space
+ since it can cause too many CSEs. */
+ if (optimize_size && offset >= 0
+ && offset < 256 + 31 * GET_MODE_SIZE (mode))
+ {
+ HOST_WIDE_INT delta;
+
+ if (offset >= 256)
+ delta = offset - (256 - GET_MODE_SIZE (mode));
+ else if (offset < 32 * GET_MODE_SIZE (mode) + 8)
+ delta = 31 * GET_MODE_SIZE (mode);
+ else
+ delta = offset & (~31 * GET_MODE_SIZE (mode));
+
+ xop0 = force_operand (plus_constant (xop0, offset - delta),
+ NULL_RTX);
+ x = plus_constant (xop0, delta);
+ }
+ else if (offset < 0 && offset > -256)
+ /* Small negative offsets are best done with a subtract before the
+ dereference, forcing these into a register normally takes two
+ instructions. */
+ x = force_operand (x, NULL_RTX);
+ else
+ {
+ /* For the remaining cases, force the constant into a register. */
+ xop1 = force_reg (SImode, xop1);
+ x = gen_rtx_PLUS (SImode, xop0, xop1);
+ }
+ }
+ else if (GET_CODE (x) == PLUS
+ && s_register_operand (XEXP (x, 1), SImode)
+ && !s_register_operand (XEXP (x, 0), SImode))
+ {
+ rtx xop0 = force_operand (XEXP (x, 0), NULL_RTX);
+
+ x = gen_rtx_PLUS (SImode, xop0, XEXP (x, 1));
+ }
+
+ if (flag_pic)
+ {
+ /* We need to find and carefully transform any SYMBOL and LABEL
+ references; so go back to the original address expression. */
+ rtx new_x = legitimize_pic_address (orig_x, mode, NULL_RTX);
+
+ if (new_x != orig_x)
+ x = new_x;
+ }
+
+ return x;
+}
+
#define REG_OR_SUBREG_REG(X) \
diff --git a/gcc/config/arm/arm.h b/gcc/config/arm/arm.h
index 320bee0..5b85e75 100644
--- a/gcc/config/arm/arm.h
+++ b/gcc/config/arm/arm.h
@@ -2361,15 +2361,11 @@ typedef struct
#define ARM_LEGITIMIZE_ADDRESS(X, OLDX, MODE, WIN) \
do { \
X = arm_legitimize_address (X, OLDX, MODE); \
- \
- if (memory_address_p (MODE, X)) \
- goto WIN; \
} while (0)
-#define THUMB_LEGITIMIZE_ADDRESS(X, OLDX, MODE, WIN) \
-do { \
- if (flag_pic) \
- (X) = legitimize_pic_address (OLDX, MODE, NULL_RTX); \
+#define THUMB_LEGITIMIZE_ADDRESS(X, OLDX, MODE, WIN) \
+do { \
+ X = thumb_legitimize_address (X, OLDX, MODE); \
} while (0)
#define LEGITIMIZE_ADDRESS(X, OLDX, MODE, WIN) \
@@ -2378,6 +2374,9 @@ do { \
ARM_LEGITIMIZE_ADDRESS (X, OLDX, MODE, WIN); \
else \
THUMB_LEGITIMIZE_ADDRESS (X, OLDX, MODE, WIN); \
+ \
+ if (memory_address_p (MODE, X)) \
+ goto WIN; \
} while (0)
/* Go to LABEL if ADDR (a legitimate address expression)