From 06eb52cab5c99abcdb3adcbdfba8cf75d38705c4 Mon Sep 17 00:00:00 2001 From: Chung-Lin Tang Date: Tue, 12 Apr 2011 04:42:55 +0000 Subject: [PATCH] re PR target/48250 (ICE in reload_cse_simplify_operands, at postreload.c:403) 2011-04-11 Chung-Lin Tang Richard Earnshaw PR target/48250 * config/arm/arm.c (arm_legitimize_reload_address): Update cases to use sign-magnitude offsets. Reject unsupported unaligned cases. Add detailed description in comments. * config/arm/arm.md (reload_outdf): Disable for ARM mode; change condition from TARGET_32BIT to TARGET_ARM. Co-Authored-By: Richard Earnshaw From-SVN: r172297 --- gcc/ChangeLog | 10 +++ gcc/config/arm/arm.c | 137 ++++++++++++++++++++++++++++++++++++------ gcc/config/arm/arm.md | 2 +- 3 files changed, 131 insertions(+), 18 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index b034a2eb521..bf897c9b80e 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,13 @@ +2011-04-11 Chung-Lin Tang + Richard Earnshaw + + PR target/48250 + * config/arm/arm.c (arm_legitimize_reload_address): Update cases + to use sign-magnitude offsets. Reject unsupported unaligned + cases. Add detailed description in comments. + * config/arm/arm.md (reload_outdf): Disable for ARM mode; change + condition from TARGET_32BIT to TARGET_ARM. + 2011-04-11 Nathan Froyd * tree.h (struct typed_tree): New. diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c index 55d5883c983..3dc2fdda200 100644 --- a/gcc/config/arm/arm.c +++ b/gcc/config/arm/arm.c @@ -6262,23 +6262,126 @@ arm_legitimize_reload_address (rtx *p, HOST_WIDE_INT val = INTVAL (XEXP (*p, 1)); HOST_WIDE_INT low, high; - if (mode == DImode || (mode == DFmode && TARGET_SOFT_FLOAT)) - low = ((val & 0xf) ^ 0x8) - 0x8; - else if (TARGET_MAVERICK && TARGET_HARD_FLOAT) - /* Need to be careful, -256 is not a valid offset. */ - low = val >= 0 ? (val & 0xff) : -((-val) & 0xff); - else if (mode == SImode - || (mode == SFmode && TARGET_SOFT_FLOAT) - || ((mode == HImode || mode == QImode) && ! arm_arch4)) - /* Need to be careful, -4096 is not a valid offset. */ - low = val >= 0 ? (val & 0xfff) : -((-val) & 0xfff); - else if ((mode == HImode || mode == QImode) && arm_arch4) - /* Need to be careful, -256 is not a valid offset. */ - low = val >= 0 ? (val & 0xff) : -((-val) & 0xff); - else if (GET_MODE_CLASS (mode) == MODE_FLOAT - && TARGET_HARD_FLOAT && TARGET_FPA) - /* Need to be careful, -1024 is not a valid offset. */ - low = val >= 0 ? (val & 0x3ff) : -((-val) & 0x3ff); + /* Detect coprocessor load/stores. */ + bool coproc_p = ((TARGET_HARD_FLOAT + && (TARGET_VFP || TARGET_FPA || TARGET_MAVERICK) + && (mode == SFmode || mode == DFmode + || (mode == DImode && TARGET_MAVERICK))) + || (TARGET_REALLY_IWMMXT + && VALID_IWMMXT_REG_MODE (mode)) + || (TARGET_NEON + && (VALID_NEON_DREG_MODE (mode) + || VALID_NEON_QREG_MODE (mode)))); + + /* For some conditions, bail out when lower two bits are unaligned. */ + if ((val & 0x3) != 0 + /* Coprocessor load/store indexes are 8-bits + '00' appended. */ + && (coproc_p + /* For DI, and DF under soft-float: */ + || ((mode == DImode || mode == DFmode) + /* Without ldrd, we use stm/ldm, which does not + fair well with unaligned bits. */ + && (! TARGET_LDRD + /* Thumb-2 ldrd/strd is [-1020,+1020] in steps of 4. */ + || TARGET_THUMB2)))) + return false; + + /* When breaking down a [reg+index] reload address into [(reg+high)+low], + of which the (reg+high) gets turned into a reload add insn, + we try to decompose the index into high/low values that can often + also lead to better reload CSE. + For example: + ldr r0, [r2, #4100] // Offset too large + ldr r1, [r2, #4104] // Offset too large + + is best reloaded as: + add t1, r2, #4096 + ldr r0, [t1, #4] + add t2, r2, #4096 + ldr r1, [t2, #8] + + which post-reload CSE can simplify in most cases to eliminate the + second add instruction: + add t1, r2, #4096 + ldr r0, [t1, #4] + ldr r1, [t1, #8] + + The idea here is that we want to split out the bits of the constant + as a mask, rather than as subtracting the maximum offset that the + respective type of load/store used can handle. + + When encountering negative offsets, we can still utilize it even if + the overall offset is positive; sometimes this may lead to an immediate + that can be constructed with fewer instructions. + For example: + ldr r0, [r2, #0x3FFFFC] + + This is best reloaded as: + add t1, r2, #0x400000 + ldr r0, [t1, #-4] + + The trick for spotting this for a load insn with N bits of offset + (i.e. bits N-1:0) is to look at bit N; if it is set, then chose a + negative offset that is going to make bit N and all the bits below + it become zero in the remainder part. + + The SIGN_MAG_LOW_ADDR_BITS macro below implements this, with respect + to sign-magnitude addressing (i.e. separate +- bit, or 1's complement), + used in most cases of ARM load/store instructions. */ + +#define SIGN_MAG_LOW_ADDR_BITS(VAL, N) \ + (((VAL) & ((1 << (N)) - 1)) \ + ? (((VAL) & ((1 << ((N) + 1)) - 1)) ^ (1 << (N))) - (1 << (N)) \ + : 0) + + if (coproc_p) + low = SIGN_MAG_LOW_ADDR_BITS (val, 10); + else if (GET_MODE_SIZE (mode) == 8) + { + if (TARGET_LDRD) + low = (TARGET_THUMB2 + ? SIGN_MAG_LOW_ADDR_BITS (val, 10) + : SIGN_MAG_LOW_ADDR_BITS (val, 8)); + else + /* For pre-ARMv5TE (without ldrd), we use ldm/stm(db/da/ib) + to access doublewords. The supported load/store offsets are + -8, -4, and 4, which we try to produce here. */ + low = ((val & 0xf) ^ 0x8) - 0x8; + } + else if (GET_MODE_SIZE (mode) < 8) + { + /* NEON element load/stores do not have an offset. */ + if (TARGET_NEON_FP16 && mode == HFmode) + return false; + + if (TARGET_THUMB2) + { + /* Thumb-2 has an asymmetrical index range of (-256,4096). + Try the wider 12-bit range first, and re-try if the result + is out of range. */ + low = SIGN_MAG_LOW_ADDR_BITS (val, 12); + if (low < -255) + low = SIGN_MAG_LOW_ADDR_BITS (val, 8); + } + else + { + if (mode == HImode || mode == HFmode) + { + if (arm_arch4) + low = SIGN_MAG_LOW_ADDR_BITS (val, 8); + else + { + /* The storehi/movhi_bytes fallbacks can use only + [-4094,+4094] of the full ldrb/strb index range. */ + low = SIGN_MAG_LOW_ADDR_BITS (val, 12); + if (low == 4095 || low == -4095) + return false; + } + } + else + low = SIGN_MAG_LOW_ADDR_BITS (val, 12); + } + } else return false; diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md index febbbe28aea..e703a73fba0 100644 --- a/gcc/config/arm/arm.md +++ b/gcc/config/arm/arm.md @@ -6188,7 +6188,7 @@ [(match_operand:DF 0 "arm_reload_memory_operand" "=o") (match_operand:DF 1 "s_register_operand" "r") (match_operand:SI 2 "s_register_operand" "=&r")] - "TARGET_32BIT" + "TARGET_THUMB2" " { enum rtx_code code = GET_CODE (XEXP (operands[0], 0)); -- 2.30.2