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

Reply via email to