On 18 October 2012 14:41, Richard Earnshaw wrote: > > +/* Checks whether the operands are valid for use in an LDRD/STRD instruction. > > + Assumes that RT, RT2, and RTN are REG. This is guaranteed by the patterns. > > + Assumes that the address in the base register RTN is word aligned. Pattern > > + guarantees that both memory accesses use the same base register, > > + the offsets are constants within the range, and the gap between the offsets is 4. > > + If preload complete then check that registers are legal. WBACK indicates whether > > + address is updated. LOAD indicates whether memory access is load or store. */ > > ARM ARM terminology uses Rn for the base reg, so: > > s/RTN/RN/
Fixed. > > > +bool > > +operands_ok_ldrd_strd (rtx rt, rtx rt2, rtx rtn, HOST_WIDE_INT offset, > > s/rtn/rn/ Fixed. > > +;; Patterns for LDRD/STRD in Thumb2 mode > > + > > +(define_insn "*thumb2_ldrd" > > + [(set (match_operand:SI 0 "s_register_operand" "=r") > > + (mem:SI (plus:SI (match_operand:SI 1 "s_register_operand" "rk") > > + (match_operand:SI 2 "ldrd_strd_offset_operand" "Do")))) > > + (set (match_operand:SI 3 "s_register_operand" "=r") > > + (mem:SI (plus:SI (match_dup 1) > > + (match_operand:SI 4 "const_int_operand" ""))))] > > + "TARGET_LDRD && TARGET_THUMB2 > > + && (current_tune->prefer_ldrd_strd && !optimize_function_for_size_p (cfun)) > > All these should be gated on "reload_completed" and not on the tune or > size optimization. Removed the condition "!optimize_function_for_size_p (cfun))". The condition "current_tune->prefer_ldrd_strd" is needed because the patterns for LDRD/STRD appear before the patterns for LDM/STM that can match the same RTL (two register in the list). Condition "reload_completed" does not help with it because peephole optimizations in ldmstm.md may (after reload) create new RTL insn that match this pattern. > > diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c > > index f330da3..21d1aa8 100644 > > --- a/gcc/config/arm/arm.c > > +++ b/gcc/config/arm/arm.c > > @@ -12130,6 +12130,9 @@ offset_ok_for_ldrd_strd (HOST_WIDE_INT offset) > > { > > HOST_WIDE_INT max_offset; > > > > + if (!TARGET_LDRD) > > + return false; > > + > > This seems to be in the wrong place. If we don't have ldrd then the > question as to what is a valid offset is irrelevant. Moved this condition to predicates.md and constraints.md. Other uses of offset_ok_for_ldrd_strd are already guarded by the conditions. I am attaching a new version of this patch. No regression on qemu for arm-none-eabi with cpu cortex-m4 and cortex-a15. Ok for trunk? Thank you, Greta ChangeLog gcc/ 2012-10-19 Sameera Deshpande <sameera.deshpa...@arm.com> Greta Yorsh <greta.yo...@arm.com> * config/arm/arm-protos.h (offset_ok_for_ldrd_strd): New declaration. (operands_ok_ldrd_strd): Likewise. * config/arm/arm.c (offset_ok_for_ldrd_strd): New function. (operands_ok_ldrd_strd): Likewise. * config/arm/arm.md (thumb2_ldrd, thumb2_ldrd_base): New patterns. (thumb2_ldrd_base_neg): Likewise. (thumb2_strd, thumb2_strd_base, thumb_strd_base_neg): Likewise. * predicates.md (ldrd_strd_offset_operand): New predicate. * config/arm/constraints.md (Do): New constraint.
diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h index 010e7fc..bfe96ea 100644 --- a/gcc/config/arm/arm-protos.h +++ b/gcc/config/arm/arm-protos.h @@ -116,6 +116,8 @@ extern bool gen_stm_seq (rtx *, int); extern bool gen_const_stm_seq (rtx *, int); extern rtx arm_gen_load_multiple (int *, int, rtx, int, rtx, HOST_WIDE_INT *); extern rtx arm_gen_store_multiple (int *, int, rtx, int, rtx, HOST_WIDE_INT *); +extern bool offset_ok_for_ldrd_strd (HOST_WIDE_INT); +extern bool operands_ok_ldrd_strd (rtx, rtx, rtx, HOST_WIDE_INT, bool, bool); extern int arm_gen_movmemqi (rtx *); extern enum machine_mode arm_select_cc_mode (RTX_CODE, rtx, rtx); extern enum machine_mode arm_select_dominance_cc_mode (rtx, rtx, diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c index fc3a508..c60e62f 100644 --- a/gcc/config/arm/arm.c +++ b/gcc/config/arm/arm.c @@ -12185,6 +12185,75 @@ arm_pad_reg_upward (enum machine_mode mode, return !BYTES_BIG_ENDIAN; } +/* Returns true iff OFFSET is valid for use in an LDRD/STRD instruction, + assuming that the address in the base register is word aligned. */ +bool +offset_ok_for_ldrd_strd (HOST_WIDE_INT offset) +{ + HOST_WIDE_INT max_offset; + + /* Offset must be a multiple of 4 in Thumb mode. */ + if (TARGET_THUMB2 && ((offset & 3) != 0)) + return false; + + if (TARGET_THUMB2) + max_offset = 1020; + else if (TARGET_ARM) + max_offset = 255; + else + gcc_unreachable (); + + return ((offset <= max_offset) && (offset >= -max_offset)); +} + +/* Checks whether the operands are valid for use in an LDRD/STRD instruction. + Assumes that RT, RT2, and RN are REG. This is guaranteed by the patterns. + Assumes that the address in the base register RN is word aligned. Pattern + guarantees that both memory accesses use the same base register, + the offsets are constants within the range, and the gap between the offsets is 4. + If preload complete then check that registers are legal. WBACK indicates whether + address is updated. LOAD indicates whether memory access is load or store. */ +bool +operands_ok_ldrd_strd (rtx rt, rtx rt2, rtx rn, HOST_WIDE_INT offset, + bool wback, bool load) +{ + unsigned int t, t2, n; + + if (!reload_completed) + return true; + + if (!offset_ok_for_ldrd_strd (offset)) + return false; + + t = REGNO (rt); + t2 = REGNO (rt2); + n = REGNO (rn); + + if ((TARGET_THUMB2) + && ((wback && (n == t || n == t2)) + || (t == SP_REGNUM) + || (t == PC_REGNUM) + || (t2 == SP_REGNUM) + || (t2 == PC_REGNUM) + || (!load && (n == PC_REGNUM)) + || (load && (t == t2)) + /* Triggers Cortex-M3 LDRD errata. */ + || (!wback && load && fix_cm3_ldrd && (n == t)))) + return false; + + if ((TARGET_ARM) + && ((wback && (n == t || n == t2)) + || (t2 == PC_REGNUM) + || (t % 2 != 0) /* First destination register is not even. */ + || (t2 != t + 1) + /* PC can be used as base register (for offset addressing only), + but it is depricated. */ + || (n == PC_REGNUM))) + return false; + + return true; +} + /* Print a symbolic form of X to the debug file, F. */ static void diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md index 7c80f91..3277561 100644 --- a/gcc/config/arm/arm.md +++ b/gcc/config/arm/arm.md @@ -11511,6 +11511,99 @@ "" ) +;; Patterns for LDRD/STRD in Thumb2 mode + +(define_insn "*thumb2_ldrd" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (mem:SI (plus:SI (match_operand:SI 1 "s_register_operand" "rk") + (match_operand:SI 2 "ldrd_strd_offset_operand" "Do")))) + (set (match_operand:SI 3 "s_register_operand" "=r") + (mem:SI (plus:SI (match_dup 1) + (match_operand:SI 4 "const_int_operand" ""))))] + "TARGET_LDRD && TARGET_THUMB2 + && current_tune->prefer_ldrd_strd + && ((INTVAL (operands[2]) + 4) == INTVAL (operands[4])) + && (operands_ok_ldrd_strd (operands[0], operands[3], + operands[1], INTVAL (operands[2]), + false, true))" + "ldrd%?\t%0, %3, [%1, %2]" + [(set_attr "type" "load2") + (set_attr "predicable" "yes")]) + +(define_insn "*thumb2_ldrd_base" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (mem:SI (match_operand:SI 1 "s_register_operand" "rk"))) + (set (match_operand:SI 2 "s_register_operand" "=r") + (mem:SI (plus:SI (match_dup 1) + (const_int 4))))] + "TARGET_LDRD && TARGET_THUMB2 + && current_tune->prefer_ldrd_strd + && (operands_ok_ldrd_strd (operands[0], operands[2], + operands[1], 0, false, true))" + "ldrd%?\t%0, %2, [%1]" + [(set_attr "type" "load2") + (set_attr "predicable" "yes")]) + +(define_insn "*thumb2_ldrd_base_neg" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (mem:SI (plus:SI (match_operand:SI 1 "s_register_operand" "rk") + (const_int -4)))) + (set (match_operand:SI 2 "s_register_operand" "=r") + (mem:SI (match_dup 1)))] + "TARGET_LDRD && TARGET_THUMB2 + && current_tune->prefer_ldrd_strd + && (operands_ok_ldrd_strd (operands[0], operands[2], + operands[1], -4, false, true))" + "ldrd%?\t%0, %2, [%1, #-4]" + [(set_attr "type" "load2") + (set_attr "predicable" "yes")]) + +(define_insn "*thumb2_strd" + [(set (mem:SI (plus:SI (match_operand:SI 0 "s_register_operand" "rk") + (match_operand:SI 1 "ldrd_strd_offset_operand" "Do"))) + (match_operand:SI 2 "s_register_operand" "r")) + (set (mem:SI (plus:SI (match_dup 0) + (match_operand:SI 3 "const_int_operand" ""))) + (match_operand:SI 4 "s_register_operand" "r"))] + "TARGET_LDRD && TARGET_THUMB2 + && current_tune->prefer_ldrd_strd + && ((INTVAL (operands[1]) + 4) == INTVAL (operands[3])) + && (operands_ok_ldrd_strd (operands[2], operands[4], + operands[0], INTVAL (operands[1]), + false, false))" + "strd%?\t%2, %4, [%0, %1]" + [(set_attr "type" "store2") + (set_attr "predicable" "yes")]) + +(define_insn "*thumb2_strd_base" + [(set (mem:SI (match_operand:SI 0 "s_register_operand" "rk")) + (match_operand:SI 1 "s_register_operand" "r")) + (set (mem:SI (plus:SI (match_dup 0) + (const_int 4))) + (match_operand:SI 2 "s_register_operand" "r"))] + "TARGET_LDRD && TARGET_THUMB2 + && current_tune->prefer_ldrd_strd + && (operands_ok_ldrd_strd (operands[1], operands[2], + operands[0], 0, false, false))" + "strd%?\t%1, %2, [%0]" + [(set_attr "type" "store2") + (set_attr "predicable" "yes")]) + +(define_insn "*thumb2_strd_base_neg" + [(set (mem:SI (plus:SI (match_operand:SI 0 "s_register_operand" "rk") + (const_int -4))) + (match_operand:SI 1 "s_register_operand" "r")) + (set (mem:SI (match_dup 0)) + (match_operand:SI 2 "s_register_operand" "r"))] + "TARGET_LDRD && TARGET_THUMB2 + && current_tune->prefer_ldrd_strd + && (operands_ok_ldrd_strd (operands[1], operands[2], + operands[0], -4, false, false))" + "strd%?\t%1, %2, [%0, #-4]" + [(set_attr "type" "store2") + (set_attr "predicable" "yes")]) + + ;; Load the load/store multiple patterns (include "ldmstm.md") diff --git a/gcc/config/arm/constraints.md b/gcc/config/arm/constraints.md index b67df55..1b4167e 100644 --- a/gcc/config/arm/constraints.md +++ b/gcc/config/arm/constraints.md @@ -31,7 +31,7 @@ ;; 'H' was previously used for FPA. ;; The following multi-letter normal constraints have been used: -;; in ARM/Thumb-2 state: Da, Db, Dc, Dd, Dn, Dl, DL, Dv, Dy, Di, Dt, Dz +;; in ARM/Thumb-2 state: Da, Db, Dc, Dd, Dn, Dl, DL, Do, Dv, Dy, Di, Dt, Dz ;; in Thumb-1 state: Pa, Pb, Pc, Pd, Pe ;; in Thumb-2 state: Pj, PJ, Ps, Pt, Pu, Pv, Pw, Px, Py @@ -279,6 +279,12 @@ (match_test "TARGET_32BIT && imm_for_neon_inv_logic_operand (op, GET_MODE (op))"))) +(define_constraint "Do" + "@internal + In ARM/Thumb2 state valid offset for an ldrd/strd instruction." + (and (match_code "const_int") + (match_test "TARGET_LDRD && offset_ok_for_ldrd_strd (ival)"))) + (define_constraint "Dv" "@internal In ARM/Thumb-2 state a const_double which can be used with a VFP fconsts diff --git a/gcc/config/arm/predicates.md b/gcc/config/arm/predicates.md index f55acbf..8f49450 100644 --- a/gcc/config/arm/predicates.md +++ b/gcc/config/arm/predicates.md @@ -137,6 +137,10 @@ (match_test "((unsigned HOST_WIDE_INT) INTVAL (op)) <= GET_MODE_BITSIZE (mode) && ((unsigned HOST_WIDE_INT) INTVAL (op)) > 0"))) +(define_predicate "ldrd_strd_offset_operand" + (and (match_operand 0 "const_int_operand") + (match_test "TARGET_LDRD && offset_ok_for_ldrd_strd (INTVAL (op))"))) + (define_predicate "arm_add_operand" (ior (match_operand 0 "arm_rhs_operand") (match_operand 0 "arm_neg_immediate_operand")))