https://gcc.gnu.org/g:9366c328518766d896155388726055624716c0af
commit r14-11101-g9366c328518766d896155388726055624716c0af Author: Wilco Dijkstra <wilco.dijks...@arm.com> Date: Tue Dec 10 14:22:48 2024 +0000 arm: Fix LDRD register overlap [PR117675] The register indexed variants of LDRD have complex register overlap constraints which makes them hard to use without using output_move_double (which can't be used for atomics as it doesn't guarantee to emit atomic LDRD/STRD when required). Add a new predicate and constraint for plain LDRD/STRD with base or base+imm. This blocks register indexing and fixes PR117675. gcc: PR target/117675 * config/arm/arm.cc (arm_ldrd_legitimate_address): New function. * config/arm/arm-protos.h (arm_ldrd_legitimate_address): New prototype. * config/arm/constraints.md: Add new Uo constraint. * config/arm/predicates.md (arm_ldrd_memory_operand): Add new predicate. * config/arm/sync.md (arm_atomic_loaddi2_ldrd): Use arm_ldrd_memory_operand and Uo. gcc/testsuite: PR target/117675 * gcc.target/arm/pr117675.c: Add new test. (cherry picked from commit 21fbfae2e55e1a153820acc6fbd922e66f67e65b) Diff: --- gcc/config/arm/arm-protos.h | 1 + gcc/config/arm/arm.cc | 24 ++++++++++++++++++++++++ gcc/config/arm/constraints.md | 8 +++++++- gcc/config/arm/predicates.md | 4 ++++ gcc/config/arm/sync.md | 2 +- gcc/testsuite/gcc.target/arm/pr117675.c | 17 +++++++++++++++++ 6 files changed, 54 insertions(+), 2 deletions(-) diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h index 2cd560c99254..89e804225a82 100644 --- a/gcc/config/arm/arm-protos.h +++ b/gcc/config/arm/arm-protos.h @@ -202,6 +202,7 @@ extern rtx arm_load_tp (rtx); extern bool arm_coproc_builtin_available (enum unspecv); extern bool arm_coproc_ldc_stc_legitimate_address (rtx); extern rtx arm_stack_protect_tls_canary_mem (bool); +extern bool arm_ldrd_legitimate_address (rtx); #if defined TREE_CODE diff --git a/gcc/config/arm/arm.cc b/gcc/config/arm/arm.cc index 912f2c315769..7b3b26a59512 100644 --- a/gcc/config/arm/arm.cc +++ b/gcc/config/arm/arm.cc @@ -34523,6 +34523,30 @@ arm_coproc_ldc_stc_legitimate_address (rtx op) return false; } +/* Return true if OP is a valid memory operand for LDRD/STRD without any + register overlap restrictions. Allow [base] and [base, imm] for now. */ +bool +arm_ldrd_legitimate_address (rtx op) +{ + if (!MEM_P (op)) + return false; + + op = XEXP (op, 0); + if (REG_P (op)) + return true; + + if (GET_CODE (op) != PLUS) + return false; + if (!REG_P (XEXP (op, 0)) || !CONST_INT_P (XEXP (op, 1))) + return false; + + HOST_WIDE_INT val = INTVAL (XEXP (op, 1)); + + if (TARGET_ARM) + return IN_RANGE (val, -255, 255); + return IN_RANGE (val, -1020, 1020) && (val & 3) == 0; +} + /* Return the diagnostic message string if conversion from FROMTYPE to TOTYPE is not allowed, NULL otherwise. */ diff --git a/gcc/config/arm/constraints.md b/gcc/config/arm/constraints.md index cd1596701453..57d8fef0bd63 100644 --- a/gcc/config/arm/constraints.md +++ b/gcc/config/arm/constraints.md @@ -39,7 +39,7 @@ ;; in all states: Pg ;; The following memory constraints have been used: -;; in ARM/Thumb-2 state: Uh, Ut, Uv, Uy, Un, Um, Us, Up, Uf, Ux, Ul +;; in ARM/Thumb-2 state: Uh, Ut, Uv, Uy, Un, Um, Us, Uo, Up, Uf, Ux, Ul, Uz ;; in ARM state: Uq ;; in Thumb state: Uu, Uw ;; in all states: Q @@ -585,6 +585,12 @@ (and (match_code "mem") (match_test "arm_coproc_ldc_stc_legitimate_address (op)"))) +(define_memory_constraint "Uo" + "@internal + A memory operand for Arm/Thumb-2 LDRD/STRD" + (and (match_code "mem") + (match_test "arm_ldrd_legitimate_address (op)"))) + ;; We used to have constraint letters for S and R in ARM state, but ;; all uses of these now appear to have been removed. diff --git a/gcc/config/arm/predicates.md b/gcc/config/arm/predicates.md index 197054b61189..fca61aeb6997 100644 --- a/gcc/config/arm/predicates.md +++ b/gcc/config/arm/predicates.md @@ -849,6 +849,10 @@ (and (match_operand 0 "memory_operand") (match_code "reg" "0"))) +;; True if the operand is memory reference suitable for a ldrd/strd. +(define_predicate "arm_ldrd_memory_operand" + (match_test "arm_ldrd_legitimate_address (op)")) + ;; Predicates for parallel expanders based on mode. (define_special_predicate "vect_par_constant_high" (match_code "parallel") diff --git a/gcc/config/arm/sync.md b/gcc/config/arm/sync.md index 0a8347fc5980..38974fa76268 100644 --- a/gcc/config/arm/sync.md +++ b/gcc/config/arm/sync.md @@ -161,7 +161,7 @@ (define_insn "arm_atomic_loaddi2_ldrd" [(set (match_operand:DI 0 "register_operand" "=r") (unspec_volatile:DI - [(match_operand:DI 1 "memory_operand" "m")] + [(match_operand:DI 1 "arm_ldrd_memory_operand" "Uo")] VUNSPEC_LDRD_ATOMIC))] "ARM_DOUBLEWORD_ALIGN && TARGET_HAVE_LPAE" "ldrd\t%0, %H0, %1" diff --git a/gcc/testsuite/gcc.target/arm/pr117675.c b/gcc/testsuite/gcc.target/arm/pr117675.c new file mode 100644 index 000000000000..586bc9db90a7 --- /dev/null +++ b/gcc/testsuite/gcc.target/arm/pr117675.c @@ -0,0 +1,17 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -marm" } */ +/* { dg-require-effective-target arm_arch_v7ve_neon_ok } */ +/* { dg-add-options arm_arch_v7ve_neon } */ +/* { dg-final { check-function-bodies "**" "" "" } } */ + +/* +** f1: +** add r0, r0, r1 +** ldrd r0, r1, \[r0\] +** bx lr +*/ +long long f1 (char *p, int i) +{ + return __atomic_load_n ((long long *)(p + i), __ATOMIC_RELAXED); +} +