A right shift by 24 or 16 can also be written UXTB/SXTB Rd, Rm, ROR #24
or UXTH/SXTH Rd, Rm, ROR #16 on Armv6 and later. On Cortex-A53 (a Pi
Zero 2 W) the extend is one cycle cheaper when Rm is a load result (3.13
against 4.13 cycles per load, extract and add, all four forms, Arm and
Thumb-2) and the same after an ALU result; on ARM1176 (a Pi Zero) UXTB
ROR #24 and LSR #24 cost the same. In Thumb-2 the extend is only used
where the shift would be 32-bit: thumb2_reorg still narrows to LSRS/ASRS,
and IT blocks keep the 16-bit shift. The new patterns keep the shift's
scheduling type: typed as extend, they reschedule for Cortex-A7, A17, A72
and Exynos-M1 tuning, and some code grows. Over gcc.c-torture/compile
and gcc.target/arm only the mnemonic changes.
Regression tested on arm-none-eabi (arm.exp, dg.exp and tree-ssa.exp for
Cortex-A15 Arm and Thumb-2 and Armv8-A Thumb-2); gcc.c-torture/execute is
unchanged under qemu.
Assisted-by: Claude Opus 5 (Anthropic)
gcc/ChangeLog:
* config/arm/iterators.md (US): Add ashiftrt and lshiftrt.
* config/arm/arm.md (*arm_<shift>si3_ext): New insn.
(*thumb2_<shift>si3_ext): Likewise.
gcc/testsuite/ChangeLog:
* gcc.target/arm/armv8_2-fp16-neon-1.c: Accept UXTH for the
high-half extract.
* gcc.target/arm/armv8_2-fp16-neon-2.c: Likewise.
* gcc.target/arm/extend-ror-2.c: New test.
* gcc.target/arm/extend-ror-3.c: New test.
* gcc.target/arm/extend-ror-4.c: New test.
* gcc.target/arm/extend-ror-5.c: New test.
Signed-off-by: Dominic P <[email protected]>
---
OK for trunk?
gcc/config/arm/arm.md | 30 +++++++
gcc/config/arm/iterators.md | 3 +-
.../gcc.target/arm/armv8_2-fp16-neon-1.c | 4 +-
.../gcc.target/arm/armv8_2-fp16-neon-2.c | 4 +-
gcc/testsuite/gcc.target/arm/extend-ror-2.c | 87 +++++++++++++++++++
gcc/testsuite/gcc.target/arm/extend-ror-3.c | 67 ++++++++++++++
gcc/testsuite/gcc.target/arm/extend-ror-4.c | 28 ++++++
gcc/testsuite/gcc.target/arm/extend-ror-5.c | 28 ++++++
8 files changed, 246 insertions(+), 5 deletions(-)
create mode 100644 gcc/testsuite/gcc.target/arm/extend-ror-2.c
create mode 100644 gcc/testsuite/gcc.target/arm/extend-ror-3.c
create mode 100644 gcc/testsuite/gcc.target/arm/extend-ror-4.c
create mode 100644 gcc/testsuite/gcc.target/arm/extend-ror-5.c
diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md
index febff17df0b..a88fcc52c7f 100644
--- a/gcc/config/arm/arm.md
+++ b/gcc/config/arm/arm.md
@@ -4725,6 +4725,36 @@
"
)
+(define_insn "*arm_<shift>si3_ext"
+ [(set (match_operand:SI 0 "s_register_operand" "=r")
+ (RSHIFTS:SI (match_operand:SI 1 "s_register_operand" "r")
+ (match_operand:SI 2 "const_int_operand")))]
+ "TARGET_ARM && arm_arch6
+ && (INTVAL (operands[2]) == 16 || INTVAL (operands[2]) == 24)"
+ {
+ return INTVAL (operands[2]) == 24 ? "<US>xtb%?\t%0, %1, ror #24"
+ : "<US>xth%?\t%0, %1, ror #16";
+ }
+ [(set_attr "predicable" "yes")
+ (set_attr "type" "alu_shift_imm_other")]
+)
+
+;; Not predicable, so that an IT block keeps the 16-bit shift. The "l"
+;; alternative mirrors *arm_shiftsi3, so register allocation and
+;; thumb2_reorg's narrowing to LSRS/ASRS are unchanged.
+(define_insn "*thumb2_<shift>si3_ext"
+ [(set (match_operand:SI 0 "s_register_operand" "=l,r")
+ (RSHIFTS:SI (match_operand:SI 1 "s_register_operand" "l,r")
+ (match_operand:SI 2 "const_int_operand")))]
+ "TARGET_THUMB2
+ && (INTVAL (operands[2]) == 16 || INTVAL (operands[2]) == 24)"
+ {
+ return INTVAL (operands[2]) == 24 ? "<US>xtb\t%0, %1, ror #24"
+ : "<US>xth\t%0, %1, ror #16";
+ }
+ [(set_attr "type" "alu_shift_imm_other")]
+)
+
(define_insn "*arm_shiftsi3"
[(set (match_operand:SI 0 "s_register_operand" "=l,l,r,r")
(match_operator:SI 3 "shift_operator"
diff --git a/gcc/config/arm/iterators.md b/gcc/config/arm/iterators.md
index c8fd31b52c5..a5e3d318d35 100644
--- a/gcc/config/arm/iterators.md
+++ b/gcc/config/arm/iterators.md
@@ -2096,7 +2096,8 @@
(xor "xor")])
;; Assembler mnemonics for signedness of widening operations.
-(define_code_attr US [(sign_extend "s") (zero_extend "u")])
+(define_code_attr US [(sign_extend "s") (zero_extend "u")
+ (ashiftrt "s") (lshiftrt "u")])
(define_code_attr Us [(sign_extend "") (zero_extend "u")])
;; Signedness suffix for float->fixed conversions. Empty for signed
diff --git a/gcc/testsuite/gcc.target/arm/armv8_2-fp16-neon-1.c
b/gcc/testsuite/gcc.target/arm/armv8_2-fp16-neon-1.c
index 2292be5bccc..2b86e9d67cc 100644
--- a/gcc/testsuite/gcc.target/arm/armv8_2-fp16-neon-1.c
+++ b/gcc/testsuite/gcc.target/arm/armv8_2-fp16-neon-1.c
@@ -459,7 +459,7 @@ test_vdup_lane_f16 (float16x4_t a)
** test_vdup_lane_f16:
** (
softfp
-** lsrs? (r[0-9]+), r0, #16
+** (?:lsrs|uxth) (r[0-9]+), r0, (?:ror )?#16
** vdup.16 (d[0-9]+), \1
** vmov r0, r1, \2 @ v4hf
** |
@@ -478,7 +478,7 @@ test_vdupq_lane_f16 (float16x4_t a)
** test_vdupq_lane_f16:
** (
softfp
-** lsrs? (r[0-9]+), r0, #16
+** (?:lsrs|uxth) (r[0-9]+), r0, (?:ror )?#16
** vdup.16 q[0-9], \1
** vmov r0, r1, d[0-9]+ @ v8hf
** vmov r2, r3, d[0-9]+
diff --git a/gcc/testsuite/gcc.target/arm/armv8_2-fp16-neon-2.c
b/gcc/testsuite/gcc.target/arm/armv8_2-fp16-neon-2.c
index a07dca3228f..f5f14fbd030 100644
--- a/gcc/testsuite/gcc.target/arm/armv8_2-fp16-neon-2.c
+++ b/gcc/testsuite/gcc.target/arm/armv8_2-fp16-neon-2.c
@@ -488,7 +488,7 @@ test_vdup_lane_f16 (float16x4_t a)
** test_vdup_lane_f16:
** (
softfp
-** lsrs? (r[0-9]+), r0, #16
+** (?:lsrs|uxth) (r[0-9]+), r0, (?:ror )?#16
** vdup.16 (d[0-9]+), \1
** vmov r0, r1, \2 @ v4hf
** |
@@ -507,7 +507,7 @@ test_vdupq_lane_f16 (float16x4_t a)
** test_vdupq_lane_f16:
** (
softfp
-** lsrs? (r[0-9]+), r0, #16
+** (?:lsrs|uxth) (r[0-9]+), r0, (?:ror )?#16
** vdup.16 q[0-9], \1
** vmov r0, r1, d[0-9]+ @ v8hf
** vmov r2, r3, d[0-9]+
diff --git a/gcc/testsuite/gcc.target/arm/extend-ror-2.c
b/gcc/testsuite/gcc.target/arm/extend-ror-2.c
new file mode 100644
index 00000000000..8bf0a3c1e43
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/extend-ror-2.c
@@ -0,0 +1,87 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v6_arm_ok } */
+/* { dg-options "-O2" } */
+/* { dg-add-options arm_arch_v6_arm } */
+/* { dg-add-options check_function_bodies } */
+/* { dg-final { check-function-bodies "**" "" } } */
+
+/*
+** u24:
+** uxtb r0, r0, ror #24
+** bx lr
+*/
+unsigned int
+u24 (unsigned int x)
+{
+ return x >> 24;
+}
+
+/*
+** u16:
+** uxth r0, r0, ror #16
+** bx lr
+*/
+unsigned int
+u16 (unsigned int x)
+{
+ return x >> 16;
+}
+
+/*
+** s24:
+** sxtb r0, r0, ror #24
+** bx lr
+*/
+int
+s24 (int x)
+{
+ return x >> 24;
+}
+
+/*
+** s16:
+** sxth r0, r0, ror #16
+** bx lr
+*/
+int
+s16 (int x)
+{
+ return x >> 16;
+}
+
+/*
+** cond24:
+** cmp r2, #3
+** uxtbeq r1, r0, ror #24
+** mov r0, r1
+** bx lr
+*/
+unsigned int
+cond24 (unsigned int x, unsigned int y, int c)
+{
+ if (c == 3)
+ y = x >> 24;
+ return y;
+}
+
+/*
+** u8:
+** lsr r0, r0, #8
+** bx lr
+*/
+unsigned int
+u8 (unsigned int x)
+{
+ return x >> 8;
+}
+
+/*
+** flag24:
+** lsrs r0, r0, #24
+** ...
+*/
+int
+flag24 (unsigned int x, int a, int b)
+{
+ return (x >> 24) ? a : b;
+}
diff --git a/gcc/testsuite/gcc.target/arm/extend-ror-3.c
b/gcc/testsuite/gcc.target/arm/extend-ror-3.c
new file mode 100644
index 00000000000..28369c719bb
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/extend-ror-3.c
@@ -0,0 +1,67 @@
+/* Cortex-A15 tuning keeps these shifts 32-bit at -O2, so the extend costs no
size. */
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v7a_thumb_ok } */
+/* { dg-options "-O2 -mtune=cortex-a15" } */
+/* { dg-add-options arm_arch_v7a_thumb } */
+/* { dg-add-options check_function_bodies } */
+/* { dg-final { check-function-bodies "**" "" } } */
+
+/*
+** u24:
+** uxtb r0, r0, ror #24
+** bx lr
+*/
+unsigned int
+u24 (unsigned int x)
+{
+ return x >> 24;
+}
+
+/*
+** u16:
+** uxth r0, r0, ror #16
+** bx lr
+*/
+unsigned int
+u16 (unsigned int x)
+{
+ return x >> 16;
+}
+
+/*
+** s24:
+** sxtb r0, r0, ror #24
+** bx lr
+*/
+int
+s24 (int x)
+{
+ return x >> 24;
+}
+
+/*
+** s16:
+** sxth r0, r0, ror #16
+** bx lr
+*/
+int
+s16 (int x)
+{
+ return x >> 16;
+}
+
+/*
+** cond24:
+** cmp r2, #3
+** it eq
+** lsreq r1, r0, #24
+** mov r0, r1
+** bx lr
+*/
+unsigned int
+cond24 (unsigned int x, unsigned int y, int c)
+{
+ if (c == 3)
+ y = x >> 24;
+ return y;
+}
diff --git a/gcc/testsuite/gcc.target/arm/extend-ror-4.c
b/gcc/testsuite/gcc.target/arm/extend-ror-4.c
new file mode 100644
index 00000000000..ff84258c9e1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/extend-ror-4.c
@@ -0,0 +1,28 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v7a_thumb_ok } */
+/* { dg-options "-Os" } */
+/* { dg-add-options arm_arch_v7a_thumb } */
+/* { dg-add-options check_function_bodies } */
+/* { dg-final { check-function-bodies "**" "" } } */
+
+/*
+** u24:
+** lsrs r0, r0, #24
+** bx lr
+*/
+unsigned int
+u24 (unsigned int x)
+{
+ return x >> 24;
+}
+
+/*
+** s16:
+** asrs r0, r0, #16
+** bx lr
+*/
+int
+s16 (int x)
+{
+ return x >> 16;
+}
diff --git a/gcc/testsuite/gcc.target/arm/extend-ror-5.c
b/gcc/testsuite/gcc.target/arm/extend-ror-5.c
new file mode 100644
index 00000000000..855b1995671
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/extend-ror-5.c
@@ -0,0 +1,28 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v5te_arm_ok } */
+/* { dg-options "-O2" } */
+/* { dg-add-options arm_arch_v5te_arm } */
+/* { dg-add-options check_function_bodies } */
+/* { dg-final { check-function-bodies "**" "" } } */
+
+/*
+** u24:
+** lsr r0, r0, #24
+** bx lr
+*/
+unsigned int
+u24 (unsigned int x)
+{
+ return x >> 24;
+}
+
+/*
+** s16:
+** asr r0, r0, #16
+** bx lr
+*/
+int
+s16 (int x)
+{
+ return x >> 16;
+}
--
2.55.0