Hi,
While working on a bug, I found some code in ARM port that I don't
understand.
In ARM_LEGITIMIZE_RELOAD_ADDRESS and arm_legitimize_address, we allow a
very small offset for DImode addressing.
In ARM_LEGITIMIZE_RELOAD_ADDRESS:
if (MODE == DImode || (MODE == DFmode && TARGET_SOFT_FLOAT)) \
low = ((val & 0xf) ^ 0x8) - 0x8; \
In arm_legitimize_address
/* VFP addressing modes actually allow greater offsets, but for
now we just stick with the lowest common denominator. */
if (mode == DImode
|| ((TARGET_SOFT_FLOAT || TARGET_VFP) && mode == DFmode))
{
low_n = n & 0x0f;
n &= ~0x0f;
if (low_n > 4)
{
n += 16;
low_n -= 16;
}
}
AFAIK, we could use two LDRs, or one LDRD, or one VLDR to access DImode
in memory when the address is in the form of (REG + CONST_INT). The
offset ranges for these three cases are:
LDR -4095,4091
LDRD -255,255
VLDR -1020,1020 && (ADDR & 3) == 0
so the lowest common denominator is
-1020,1020 && (ADDR & 3) == 0 if ! TARGET_LDRD
-255,255 && (ADDR & 3) == 0 if TARGET_LDRD
Both are much larger than what we have now in the ARM port.
Did I miss some other cases? That two pieces of code are rather old
(more than 15 years). The main code was added by
svn: revision 7536 by erich, Thu Jun 23 16:02:41 1994 UTC in arm.h
git: fac435147512513c1b8fa55bee061c8e3a767ba9
log: (LEGITIMIZE_ADDRESS): Push constants that will never be legitimate
-- symbols
and labels -- into registers. Handle DImode better.
I checked out that revision to take a look but didn't find an obvious
reason for such small index range. Did I miss something tricky?
If there is nothing I missed, I'd like to propose the attached patch.
Regards,
--
Jie Zhang
Index: config/arm/arm.c
===================================================================
--- config/arm/arm.c (revision 168085)
+++ config/arm/arm.c (working copy)
@@ -6221,13 +6221,9 @@ arm_legitimize_address (rtx x, rtx orig_
if (mode == DImode
|| ((TARGET_SOFT_FLOAT || TARGET_VFP) && mode == DFmode))
{
- low_n = n & 0x0f;
- n &= ~0x0f;
- if (low_n > 4)
- {
- n += 16;
- low_n -= 16;
- }
+ HOST_WIDE_INT mask = (TARGET_LDRD ? 0xfc : 0x3fc);
+ low_n = (n >= 0 ? (n & mask) : -((-n) & mask));
+ n -= low_n;
}
else
{
Index: config/arm/arm.h
===================================================================
--- config/arm/arm.h (revision 168085)
+++ config/arm/arm.h (working copy)
@@ -1283,7 +1283,12 @@ enum reg_class
HOST_WIDE_INT low, high; \
\
if (MODE == DImode || (MODE == DFmode && TARGET_SOFT_FLOAT)) \
- low = ((val & 0xf) ^ 0x8) - 0x8; \
+ { \
+ /* VFP addressing modes actually allow greater offsets, but for \
+ now we just stick with the lowest common denominator. */ \
+ HOST_WIDE_INT mask = (TARGET_LDRD ? 0xfc : 0x3fc); \
+ low = (val >= 0 ? (val & mask) : -((-val) & mask)); \
+ } \
else if (TARGET_MAVERICK && TARGET_HARD_FLOAT) \
/* Need to be careful, -256 is not a valid offset. */ \
low = val >= 0 ? (val & 0xff) : -((-val) & 0xff); \