aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristophe Lyon <christophe.lyon@linaro.org>2020-03-18 14:43:40 +0000
committerChristophe Lyon <christophe.lyon@linaro.org>2020-03-18 14:43:40 +0000
commit63bda3a85d9639fa9672ff1d4883c147a81e58a5 (patch)
treed8f4389a64acc92583e4e7d04a0535c1fc11bc9a
parent3081f59a48222850f51c24b85fbd6c7fc29e90b0 (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.c30
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,