diff options
author | Christophe Lyon <christophe.lyon@linaro.org> | 2020-03-18 14:43:40 +0000 |
---|---|---|
committer | Christophe Lyon <christophe.lyon@linaro.org> | 2020-03-18 14:43:40 +0000 |
commit | 63bda3a85d9639fa9672ff1d4883c147a81e58a5 (patch) | |
tree | d8f4389a64acc92583e4e7d04a0535c1fc11bc9a | |
parent | 3081f59a48222850f51c24b85fbd6c7fc29e90b0 (diff) |
WIP: equivalent of LLVM's -arm-assume-misaligned-load-storelinaro-local/arm-assume-misaligned-load-store
I've received a support request where GCC generates strd/ldrd which
require aligned memory addresses, while the user code actually
provides sub-aligned pointers.
The sample code is derived from CMSIS:
void foo(short *pDst, int in1, int in2) {
*__SIMD32(pDst)++ = in1;
*__SIMD32(pDst)++ = in2;
}
compiled with arm-none-eabi-gcc -mcpu=cortex-m7 CMSIS.c -S -O2
generates:
foo:
strd r1, r2, [r0]
bx lr
Using -mno-unaligned-access of course makes no change, since the code
is lying to the compiler by casting short* to int*.
However, LLVM has -arm-assume-misaligned-load-store which disables
generation of ldrd/strd in such cases:
https://reviews.llvm.org/D17015?id=48020
Change-Id: I576cbe22d6a109da4bb3bc5bda255dad4cc75ff8
-rw-r--r-- | gcc/config/arm/arm.c | 30 |
1 files changed, 19 insertions, 11 deletions
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c index 983852cc4e3..3974b1ec42e 100644 --- a/gcc/config/arm/arm.c +++ b/gcc/config/arm/arm.c @@ -13642,6 +13642,17 @@ ldm_stm_operation_p (rtx op, bool load, machine_mode mode, return true; } +/* Return true if a 64-bit access with alignment ALIGN and with a + constant offset OFFSET from the base pointer is permitted on this + architecture. */ +static bool +align_ok_ldrd_strd (HOST_WIDE_INT align, HOST_WIDE_INT offset) +{ + return (unaligned_access + ? (align >= BITS_PER_WORD && (offset & 3) == 0) + : (align >= 2 * BITS_PER_WORD && (offset & 7) == 0)); +} + /* Return true iff it would be profitable to turn a sequence of NOPS loads or stores (depending on IS_STORE) into a load-multiple or store-multiple instruction. ADD_OFFSET is nonzero if the base address register needs @@ -13867,6 +13878,10 @@ load_multiple_sequence (rtx *operands, int nops, int *regs, int *saved_order, check_regs ? unsorted_regs : NULL)) return 0; + if (!align_ok_ldrd_strd (MEM_ALIGN(operands[order[0]]), + unsorted_regs[order[0]])) + return 0; + if (saved_order) memcpy (saved_order, order, sizeof order); @@ -14016,6 +14031,10 @@ store_multiple_sequence (rtx *operands, int nops, int nops_total, check_regs ? unsorted_regs : NULL)) return 0; + if (!align_ok_ldrd_strd (MEM_ALIGN(operands[order[0]]), + unsorted_regs[order[0]])) + return 0; + if (saved_order) memcpy (saved_order, order, sizeof order); @@ -16151,17 +16170,6 @@ operands_ok_ldrd_strd (rtx rt, rtx rt2, rtx rn, HOST_WIDE_INT offset, return true; } -/* Return true if a 64-bit access with alignment ALIGN and with a - constant offset OFFSET from the base pointer is permitted on this - architecture. */ -static bool -align_ok_ldrd_strd (HOST_WIDE_INT align, HOST_WIDE_INT offset) -{ - return (unaligned_access - ? (align >= BITS_PER_WORD && (offset & 3) == 0) - : (align >= 2 * BITS_PER_WORD && (offset & 7) == 0)); -} - /* Helper for gen_operands_ldrd_strd. Returns true iff the memory operand MEM's address contains an immediate offset from the base register and has no side effects, in which case it sets BASE, |