Message ID | 001701cda6f8$5f19a9b0$1d4cfd10$@yorsh@arm.com |
---|---|
State | New |
Headers | show |
On 10/10/12 16:03, Greta Yorsh wrote: > This patch adds define_insn patterns for LDRD and STRD in Thumb mode. > > ChangeLog > > gcc/ > > 2012-09-13 Sameera Deshpande <sameera.deshpande@arm.com> > Greta Yorsh <Greta.Yorsh@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 (Dd): New constraint. > > > 1-thumb-patterns.patch.txt > > > diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h > index c590ef4..317bca7 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 3fce8c4..b3a3774 100644 > --- a/gcc/config/arm/arm.c > +++ b/gcc/config/arm/arm.c > @@ -12123,6 +12123,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 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/ > +bool > +operands_ok_ldrd_strd (rtx rt, rtx rt2, rtx rtn, HOST_WIDE_INT offset, s/rtn/rn/ > + 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 (rtn); > + > + 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 e9da56d..ed82634 100644 > --- a/gcc/config/arm/arm.md > +++ b/gcc/config/arm/arm.md > @@ -11472,6 +11472,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 && !optimize_function_for_size_p (cfun)) All these should be gated on "reload_completed" and not on the tune or size optimization. > + && ((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 && !optimize_function_for_size_p (cfun)) > + && (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 && !optimize_function_for_size_p (cfun)) > + && (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 && !optimize_function_for_size_p (cfun)) > + && ((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 && !optimize_function_for_size_p (cfun)) > + && (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 && !optimize_function_for_size_p (cfun)) > + && (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..231d910 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 "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 8ae26ca..badb68b 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 "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"))) > 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. > /* Offset must be a multiple of 4 in Thumb mode. */ > if (TARGET_THUMB2 && ((offset & 3) != 0)) > return false; >
diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h index c590ef4..317bca7 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 3fce8c4..b3a3774 100644 --- a/gcc/config/arm/arm.c +++ b/gcc/config/arm/arm.c @@ -12123,6 +12123,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 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. */ +bool +operands_ok_ldrd_strd (rtx rt, rtx rt2, rtx rtn, 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 (rtn); + + 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 e9da56d..ed82634 100644 --- a/gcc/config/arm/arm.md +++ b/gcc/config/arm/arm.md @@ -11472,6 +11472,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 && !optimize_function_for_size_p (cfun)) + && ((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 && !optimize_function_for_size_p (cfun)) + && (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 && !optimize_function_for_size_p (cfun)) + && (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 && !optimize_function_for_size_p (cfun)) + && ((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 && !optimize_function_for_size_p (cfun)) + && (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 && !optimize_function_for_size_p (cfun)) + && (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..231d910 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 "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 8ae26ca..badb68b 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 "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"))) 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; + /* Offset must be a multiple of 4 in Thumb mode. */ if (TARGET_THUMB2 && ((offset & 3) != 0)) return false;