Changes v3-v4:
- use %R0 instead of %R1 in all asrl, lsll, and lsrl patterns
- use an execution test for << 7 (ashll_fn2)
Changes v2->v3:
- use satisfies_constraint_Ph in split condition
- use %R0 instead of %R1 as first input parameter
- improve test to cover more cases (shifting by #34 instead of #33
avoids PR122871)
The second alternative for operand 1 needs a new constraint which does
not overlap with Pg, except that it can handle 32 to generate an
optimal mov.
This patch introduces a new Ph constraint which has the [32..255]
range.
This fixes a lot of regressions when running the testsuite for an MVE
target such as -march=armv8.1-m.main+mve.fp+fp.dp -mfloat-abi=hard.
OK for trunk and gcc-15?
Thanks,
Christophe
gcc/ChangeLog:
PR target/122858
* config/arm/constraints.md (Ph): New constraint.
* config/arm/mve.md (mve_asrl_imm, mve_lsll_imm): Fix constraints
of operand 1 and handle 32 as special shift amount.
gcc/testsuite/ChangeLog:
PR target/122858
* gcc.target/arm/mve/pr122858.c: New test.
---
gcc/config/arm/constraints.md | 9 ++-
gcc/config/arm/mve.md | 71 +++++++++++-------
gcc/testsuite/gcc.target/arm/mve/pr122858.c | 83 +++++++++++++++++++++
3 files changed, 132 insertions(+), 31 deletions(-)
create mode 100644 gcc/testsuite/gcc.target/arm/mve/pr122858.c
diff --git a/gcc/config/arm/constraints.md b/gcc/config/arm/constraints.md
index 86a9e97f514..e3809d31ba9 100644
--- a/gcc/config/arm/constraints.md
+++ b/gcc/config/arm/constraints.md
@@ -35,8 +35,8 @@
;; in ARM/Thumb-2 state: Da, Db, Dc, Dd, Dn, DN, Dm, Dl, DL, Do, Dv, Dy, Di,
;; Dj, Ds, Dt, Dp, Dz, Tu, Te
;; in Thumb-1 state: Pa, Pb, Pc, Pd, Pe
-;; in Thumb-2 state: Ha, Pg, Pj, PJ, Ps, Pt, Pu, Pv, Pw, Px, Py, Pz, Ra, Rb,
-;; Rd, Rf, Rg, Ri
+;; in Thumb-2 state: Ha, Pg, Ph, Pj, PJ, Ps, Pt, Pu, Pv, Pw, Px, Py, Pz, Ra,
+;; Rb, Rd, Rf, Rg, Ri
;; The following memory constraints have been used:
;; in ARM/Thumb-2 state: Uh, Ut, Uv, Un, Um, Us, Uo, Up, Uf, Ux, Ul, Uz
@@ -237,6 +237,11 @@ (define_constraint "Pg"
(and (match_code "const_int")
(match_test "TARGET_THUMB2 && ival >= 1 && ival <= 32")))
+(define_constraint "Ph"
+ "@internal In Thumb-2 state a constant in range 32 to 255"
+ (and (match_code "const_int")
+ (match_test "TARGET_THUMB2 && ival >= 32 && ival <= 255")))
+
(define_constraint "Ps"
"@internal In Thumb-2 state a constant in the range -255 to +255"
(and (match_code "const_int")
diff --git a/gcc/config/arm/mve.md b/gcc/config/arm/mve.md
index b29c5f1bcd5..6a163e4c3bb 100644
--- a/gcc/config/arm/mve.md
+++ b/gcc/config/arm/mve.md
@@ -4762,10 +4762,10 @@ (define_expand "mve_asrl"
(define_insn_and_split "mve_asrl_imm"
[(set (match_operand:DI 0 "arm_general_register_operand" "=r,r")
(ashiftrt:DI (match_operand:DI 1 "arm_general_register_operand" "0,r")
- (match_operand:QI 2 "immediate_operand" "Pg,I")))]
+ (match_operand:QI 2 "immediate_operand" "Pg,Ph")))]
"TARGET_HAVE_MVE"
- "asrl%?\\t%Q0, %R1, %2"
- "&& !satisfies_constraint_Pg (operands[2])"
+ "asrl%?\\t%Q0, %R0, %2"
+ "&& satisfies_constraint_Ph (operands[2])"
[(clobber (const_int 0))]
"
rtx amount = operands[2];
@@ -4781,30 +4781,36 @@ (define_insn_and_split "mve_asrl_imm"
}
/* ival < 0 should have already been handled by mve_asrl. */
- gcc_assert (ival > 32);
+ gcc_assert (ival >= 32);
- /* Shift amount above immediate range (ival > 32).
- out_hi gets the sign bit
- out_lo gets in_hi << (ival - 32) or << 31 if ival >= 64.
- If ival >= 64, the result is either 0 or -1, depending on the
- input sign. */
rtx in_hi = gen_highpart (SImode, operands[1]);
rtx out_lo = gen_lowpart (SImode, operands[0]);
rtx out_hi = gen_highpart (SImode, operands[0]);
- emit_insn (gen_rtx_SET (out_lo,
- gen_rtx_fmt_ee (ASHIFTRT,
- SImode,
- in_hi,
- GEN_INT (MIN (ival - 32,
- 31)))));
+ if (ival == 32)
+ /* out_hi gets the sign bit
+ out_lo gets in_hi. */
+ emit_insn (gen_movsi (out_lo, in_hi));
+ else
+ /* Shift amount above immediate range (ival > 32).
+ out_hi gets the sign bit
+ out_lo gets in_hi << (ival - 32) or << 31 if ival >= 64.
+ If ival >= 64, the result is either 0 or -1, depending on the
+ input sign. */
+ emit_insn (gen_rtx_SET (out_lo,
+ gen_rtx_fmt_ee (ASHIFTRT,
+ SImode,
+ in_hi,
+ GEN_INT (MIN (ival - 32,
+ 31)))));
+
/* Copy sign bit, which is OK even if out_lo == in_hi. */
emit_insn (gen_rtx_SET (out_hi,
gen_rtx_fmt_ee (ASHIFTRT,
SImode,
in_hi,
GEN_INT (31))));
- DONE;
+ DONE;
"
[(set_attr "predicable" "yes,yes")
(set_attr "length" "4,8")])
@@ -4818,7 +4824,7 @@ (define_insn "mve_asrl_internal"
(match_dup 2))
(ashift:DI (match_dup 1) (neg:QI (match_dup 2)))))]
"TARGET_HAVE_MVE"
- "asrl%?\\t%Q0, %R1, %2"
+ "asrl%?\\t%Q0, %R0, %2"
[(set_attr "predicable" "yes")])
;; General pattern for lsll
@@ -4852,10 +4858,10 @@ (define_expand "mve_lsll"
(define_insn_and_split "mve_lsll_imm"
[(set (match_operand:DI 0 "arm_general_register_operand" "=r,r")
(ashift:DI (match_operand:DI 1 "arm_general_register_operand" "0,r")
- (match_operand:QI 2 "immediate_operand" "Pg,I")))]
+ (match_operand:QI 2 "immediate_operand" "Pg,Ph")))]
"TARGET_HAVE_MVE"
- "lsll%?\\t%Q0, %R1, %2"
- "&& !satisfies_constraint_Pg (operands[2])"
+ "lsll%?\\t%Q0, %R0, %2"
+ "&& satisfies_constraint_Ph (operands[2])"
[(clobber (const_int 0))]
"
rtx amount = operands[2];
@@ -4878,17 +4884,24 @@ (define_insn_and_split "mve_lsll_imm"
}
/* ival < 0 should have already been handled by mve_asrl. */
- gcc_assert (ival > 32);
+ gcc_assert (ival >= 32);
- /* Shift amount above immediate range: 32 < ival < 64. */
rtx in_lo = gen_lowpart (SImode, operands[1]);
rtx out_lo = gen_lowpart (SImode, operands[0]);
rtx out_hi = gen_highpart (SImode, operands[0]);
- emit_insn (gen_rtx_SET (out_hi,
- gen_rtx_fmt_ee (ASHIFT,
- SImode,
- in_lo,
- GEN_INT (ival - 32))));
+
+ if (ival == 32)
+ /* Shift by 32 is just a move. */
+ emit_insn (gen_movsi (out_hi, in_lo));
+ else
+ /* Shift amount above immediate range: 32 < ival < 64. */
+ emit_insn (gen_rtx_SET (out_hi,
+ gen_rtx_fmt_ee (ASHIFT,
+ SImode,
+ in_lo,
+ GEN_INT (ival - 32))));
+
+ /* Clear low 32 bits. */
emit_insn (gen_rtx_SET (out_lo, const0_rtx));
DONE;
"
@@ -4904,7 +4917,7 @@ (define_insn "mve_lsll_internal"
(match_dup 2))
(lshiftrt:DI (match_dup 1) (neg:QI (match_dup 2)))))]
"TARGET_HAVE_MVE"
- "lsll%?\\t%Q0, %R1, %2"
+ "lsll%?\\t%Q0, %R0, %2"
[(set_attr "predicable" "yes")])
(define_insn "mve_lsrl"
@@ -4912,5 +4925,5 @@ (define_insn "mve_lsrl"
(lshiftrt:DI (match_operand:DI 1 "arm_general_register_operand" "0")
(match_operand:SI 2 "long_shift_imm" "Pg")))]
"TARGET_HAVE_MVE"
- "lsrl%?\\t%Q0, %R1, %2"
+ "lsrl%?\\t%Q0, %R0, %2"
[(set_attr "predicable" "yes")])
diff --git a/gcc/testsuite/gcc.target/arm/mve/pr122858.c
b/gcc/testsuite/gcc.target/arm/mve/pr122858.c
new file mode 100644
index 00000000000..3e6d29d9ce6
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/mve/pr122858.c
@@ -0,0 +1,83 @@
+/* { dg-do run } */
+/* { dg-require-effective-target arm_mve_hw } */
+/* { dg-options "-O2" } */
+/* { dg-add-options arm_v8_1m_mve } */
+/* { dg-final { check-function-bodies "**" "" "" } } */
+
+extern void abort (void);
+
+/*
+** ashrl_fn:
+**...
+** asrl r[0-9]+, r[0-9]+, #31
+**...
+*/
+__attribute__ ((noipa))
+long long ashrl_fn (long long a)
+{
+ long long c;
+
+ c = a >> 31;
+ c += a;
+ return c;
+}
+
+/*
+** ashll_fn:
+**...
+** add (r[0-9]+), \1, r[0-9]+, lsl #2
+**...
+*/
+__attribute__ ((noipa))
+long long ashll_fn (long long a)
+{
+ long long c;
+
+ /* Use 34, since 33 causes PR122871. */
+ c = a << 34;
+ c += a;
+ return c;
+}
+
+/*
+** ashll_fn2:
+**...
+** lsll r[0-9]+, r[0-9]+, #7
+**...
+*/
+__attribute__ ((noipa))
+long long ashll_fn2 (long long a /* unused */, long long x)
+{
+ return x << 7;
+}
+
+/*
+** ashll_fn3:
+**...
+** lsls r[0-9]+, (r[0-9]+), #2
+** movs \1, #0
+**...
+*/
+__attribute__ ((noipa))
+long long ashll_fn3 (long long x)
+{
+ return x << 34;
+}
+
+int main(void)
+{
+ long long var1 = 1;
+ long long var2 = ashll_fn (var1);
+ if (var2 != 0x400000001)
+ abort ();
+
+ var2 = ashrl_fn (var2);
+ if (var2 != 0x400000009)
+ abort ();
+
+ var2 = ashll_fn2 (var2, 0xa987654350000002LL);
+ if (var2 != 0xc3b2a1a800000100LL)
+ abort ();
+
+ return 0;
+}