Add missing AArch64 bitreverse expanders so __builtin_bitreverse*
can lower to existing rbit patterns.

For QI and HI modes we widen to SI, apply rbit, then shift right by 24
or 16 respectively. Unlike Clang, this emits an and for the zero-extend;
I am not entirely sure how to avoid this.

gcc/testsuite/ChangeLog:
- * gcc.target/aarch64/bitreverse.c: New test.

gcc/ChangeLog:
- * config/aarch64/aarch64.md (bitreverse<mode>2, bitreverseqi2,
  bitreversehi2): New expanders.
- * config/aarch64/aarch64-simd.md (bitreverse<mode>2): New expander.

Signed-off-by: Disservin <[email protected]>
---
 gcc/config/aarch64/aarch64-simd.md            |  7 ++-
 gcc/config/aarch64/aarch64.md                 | 32 ++++++++++++
 gcc/testsuite/gcc.target/aarch64/bitreverse.c | 50 +++++++++++++++++++
 3 files changed, 88 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/gcc.target/aarch64/bitreverse.c

diff --git a/gcc/config/aarch64/aarch64-simd.md 
b/gcc/config/aarch64/aarch64-simd.md
index 2e142b1e1ee..da66bd36fe9 100644
--- a/gcc/config/aarch64/aarch64-simd.md
+++ b/gcc/config/aarch64/aarch64-simd.md
@@ -400,6 +400,12 @@
   [(set_attr "type" "neon_rev<q>")]
 )
 
+(define_expand "bitreverse<mode>2"
+  [(set (match_operand:VB 0 "register_operand")
+       (bitreverse:VB (match_operand:VB 1 "register_operand")))]
+  "TARGET_SIMD"
+  "")
+
 (define_insn "aarch64_rbit<mode><vczle><vczbe>"
   [(set (match_operand:VB 0 "register_operand" "=w")
        (bitreverse:VB (match_operand:VB 1 "register_operand" "w")))]
@@ -10697,4 +10703,3 @@
      [ w        , 0 , w , w ] <insn>\t%0.<Vtype>, %2.16b, %3.16b
   }
 )
-
diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md
index 0ef01e889a6..a69317f747f 100644
--- a/gcc/config/aarch64/aarch64.md
+++ b/gcc/config/aarch64/aarch64.md
@@ -5786,6 +5786,38 @@
   [(set_attr "type" "rbit")]
 )
 
+(define_expand "bitreverse<mode>2"
+  [(set (match_operand:GPI 0 "register_operand")
+       (bitreverse:GPI (match_operand:GPI 1 "register_operand")))]
+  ""
+  "")
+
+(define_expand "bitreverseqi2"
+  [(set (match_operand:QI 0 "register_operand")
+       (bitreverse:QI (match_operand:QI 1 "register_operand")))]
+  ""
+  {
+    rtx t = gen_reg_rtx (SImode);
+    emit_insn (gen_aarch64_rbitsi (t, gen_lowpart (SImode, operands[1])));
+    t = expand_simple_binop (SImode, LSHIFTRT, t, GEN_INT (24),
+                            NULL_RTX, false, OPTAB_DIRECT);
+    emit_move_insn (operands[0], gen_lowpart (QImode, t));
+    DONE;
+  })
+
+(define_expand "bitreversehi2"
+  [(set (match_operand:HI 0 "register_operand")
+       (bitreverse:HI (match_operand:HI 1 "register_operand")))]
+  ""
+  {
+    rtx t = gen_reg_rtx (SImode);
+    emit_insn (gen_aarch64_rbitsi (t, gen_lowpart (SImode, operands[1])));
+    t = expand_simple_binop (SImode, LSHIFTRT, t, GEN_INT (16),
+                            NULL_RTX, false, OPTAB_DIRECT);
+    emit_move_insn (operands[0], gen_lowpart (HImode, t));
+    DONE;
+  })
+
 (define_expand "ffs<mode>2"
   [(match_operand:GPI 0 "register_operand")
    (match_operand:GPI 1 "register_operand")]
diff --git a/gcc/testsuite/gcc.target/aarch64/bitreverse.c 
b/gcc/testsuite/gcc.target/aarch64/bitreverse.c
new file mode 100644
index 00000000000..5dbec3a5011
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/bitreverse.c
@@ -0,0 +1,50 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+/*
+** br8:
+**     and     w0, w0, 255
+**     rbit    w0, w0
+**     lsr     w0, w0, 24
+**     ret
+*/
+[[gnu::noipa]] unsigned char
+br8 (unsigned char x)
+{
+  return __builtin_bitreverse8 (x);
+}
+
+/*
+** br16:
+**     and     w0, w0, 65535
+**     rbit    w0, w0
+**     lsr     w0, w0, 16
+**     ret
+*/
+[[gnu::noipa]] unsigned short
+br16 (unsigned short x)
+{
+  return __builtin_bitreverse16 (x);
+}
+
+/*
+** br32:
+**     rbit    w0, w0
+**     ret
+*/
+[[gnu::noipa]] unsigned int
+br32 (unsigned int x)
+{
+  return __builtin_bitreverse32 (x);
+}
+
+/*
+** br64:
+**     rbit    x0, x0
+**     ret
+*/
+[[gnu::noipa]] unsigned long long
+br64 (unsigned long long x)
+{
+  return __builtin_bitreverse64 (x);
+}
\ No newline at end of file
-- 
2.34.1

Reply via email to