Use bitreverse rtl code for them. Purposely leaving out some codegen
(ie. himode) and relying on widen_bswap_or_bitreverse and
expand_doubleword_bswap_or_bitreverse to provide such transformations.

Leaving MIPS DSP bitrev out of the patch for now.

gcc/ChangeLog:

        * config/mips/mips.h (ISA_HAS_DSBH_DSHD): New macro.
        (ISA_HAS_BITSWAP): Likewise.
        * config/mips/mips.md (mips_<d>bitswap): New MIPS32r6 instructions.
        (allegrex_bitrev): New MIPS allegrex instruction.
        (bitreversesi2): New insns.
        (bitreversedi2): Likewise.
        (bitreverseqi2): Likewise.

gcc/testsuite/ChangeLog:

        * gcc.target/mips/bitrev-1.c: New test.
        * gcc.target/mips/bitrev-10.c: New test.
        * gcc.target/mips/bitrev-11.c: New test.
        * gcc.target/mips/bitrev-12.c: New test.
        * gcc.target/mips/bitrev-2.c: New test.
        * gcc.target/mips/bitrev-3.c: New test.
        * gcc.target/mips/bitrev-4.c: New test.
        * gcc.target/mips/bitrev-5.c: New test.
        * gcc.target/mips/bitrev-6.c: New test.
        * gcc.target/mips/bitrev-7.c: New test.
        * gcc.target/mips/bitrev-8.c: New test.
        * gcc.target/mips/bitrev-9.c: New test.

Signed-off-by: David Guillen Fandos <[email protected]>
---
 gcc/config/mips/mips.h                    |  9 +++-
 gcc/config/mips/mips.md                   | 64 ++++++++++++++++++++++-
 gcc/testsuite/gcc.target/mips/bitrev-1.c  | 10 ++++
 gcc/testsuite/gcc.target/mips/bitrev-10.c |  9 ++++
 gcc/testsuite/gcc.target/mips/bitrev-11.c | 10 ++++
 gcc/testsuite/gcc.target/mips/bitrev-12.c | 10 ++++
 gcc/testsuite/gcc.target/mips/bitrev-2.c  | 18 +++++++
 gcc/testsuite/gcc.target/mips/bitrev-3.c  | 10 ++++
 gcc/testsuite/gcc.target/mips/bitrev-4.c  | 20 +++++++
 gcc/testsuite/gcc.target/mips/bitrev-5.c  |  9 ++++
 gcc/testsuite/gcc.target/mips/bitrev-6.c  | 11 ++++
 gcc/testsuite/gcc.target/mips/bitrev-7.c  | 10 ++++
 gcc/testsuite/gcc.target/mips/bitrev-8.c  | 10 ++++
 gcc/testsuite/gcc.target/mips/bitrev-9.c  | 10 ++++
 14 files changed, 208 insertions(+), 2 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/mips/bitrev-1.c
 create mode 100644 gcc/testsuite/gcc.target/mips/bitrev-10.c
 create mode 100644 gcc/testsuite/gcc.target/mips/bitrev-11.c
 create mode 100644 gcc/testsuite/gcc.target/mips/bitrev-12.c
 create mode 100644 gcc/testsuite/gcc.target/mips/bitrev-2.c
 create mode 100644 gcc/testsuite/gcc.target/mips/bitrev-3.c
 create mode 100644 gcc/testsuite/gcc.target/mips/bitrev-4.c
 create mode 100644 gcc/testsuite/gcc.target/mips/bitrev-5.c
 create mode 100644 gcc/testsuite/gcc.target/mips/bitrev-6.c
 create mode 100644 gcc/testsuite/gcc.target/mips/bitrev-7.c
 create mode 100644 gcc/testsuite/gcc.target/mips/bitrev-8.c
 create mode 100644 gcc/testsuite/gcc.target/mips/bitrev-9.c

diff --git a/gcc/config/mips/mips.h b/gcc/config/mips/mips.h
index 48a562f2d39..cd43b679e6a 100644
--- a/gcc/config/mips/mips.h
+++ b/gcc/config/mips/mips.h
@@ -1264,9 +1264,16 @@ struct mips_cpu_info {
 #define ISA_HAS_WSBH           ((mips_isa_rev >= 2 && !TARGET_MIPS16)  \
                                  || TARGET_ALLEGREX)
 
-/* Similar to WSBH but for 32 bit words (byte swap within a word). */
+/* Similar to WSBH but for 32 bit words (byte swap within a word).  */
 #define ISA_HAS_WSBW           (TARGET_ALLEGREX)
 
+/* MIPS64 has some instructions (DSBH & DSHD) similar to WSBH.  */
+#define ISA_HAS_DSBH_DSHD      (TARGET_64BIT && mips_isa_rev >= 2      \
+                                && !TARGET_MIPS16)
+
+/* ISA has the (D)BITSWAP (reverse bits within bytes) instruction.  */
+#define ISA_HAS_BITSWAP                (mips_isa_rev >= 6 && !TARGET_MIPS16)
+
 /* ISA has data prefetch instructions.  This controls use of 'pref'.  */
 #define ISA_HAS_PREFETCH       ((ISA_MIPS4                             \
                                  || TARGET_LOONGSON_2EF                \
diff --git a/gcc/config/mips/mips.md b/gcc/config/mips/mips.md
index 18244e4abcc..d53e5822118 100644
--- a/gcc/config/mips/mips.md
+++ b/gcc/config/mips/mips.md
@@ -86,6 +86,7 @@
   UNSPEC_WSBH
   UNSPEC_DSBH
   UNSPEC_DSHD
+  UNSPEC_BITSWAP
 
   ;; Floating-point moves.
   UNSPEC_LOAD_LOW
@@ -6040,6 +6041,67 @@
   [(set_attr "type" "shift")
    (set_attr "mode" "<MODE>")])
 
+;; BITSWAP: reverses the bits within each byte.
+(define_insn "mips_<d>bitswap"
+  [(set (match_operand:GPR 0 "register_operand" "=d")
+       (unspec:GPR [(match_operand:GPR 1 "register_operand" "d")]
+                    UNSPEC_BITSWAP))]
+  "ISA_HAS_BITSWAP"
+  "<d>bitswap\t%0,%1"
+  [(set_attr "type" "shift")
+   (set_attr "mode" "<MODE>")])
+
+;; BITREV: full 32 bit reverse.
+(define_insn "allegrex_bitrev"
+  [(set (match_operand:SI 0 "register_operand" "=d")
+       (bitreverse:SI (match_operand:SI 1 "register_operand" "d")))]
+  "TARGET_ALLEGREX"
+  "bitrev\t%0,%1"
+  [(set_attr "type" "shift")
+   (set_attr "mode" "SI")])
+
+(define_expand "bitreversedi2"
+  [(set (match_operand:DI 0 "register_operand")
+       (bitreverse:DI (match_operand:DI 1 "register_operand")))]
+  "TARGET_64BIT && ISA_HAS_BITSWAP && ISA_HAS_DSBH_DSHD"
+{
+  rtx tmp = gen_reg_rtx (DImode);
+
+  /* DBITSWAP reverses within each byte, BSWAP then reverses the bytes.  */
+  emit_insn (gen_mips_dbitswap (tmp, operands[1]));
+  emit_insn (gen_bswapdi2 (operands[0], tmp));
+  DONE;
+})
+
+(define_expand "bitreversesi2"
+  [(set (match_operand:SI 0 "register_operand")
+       (bitreverse:SI (match_operand:SI 1 "register_operand")))]
+  "TARGET_ALLEGREX || (ISA_HAS_BITSWAP && ISA_HAS_WSBH && ISA_HAS_ROR)"
+{
+  if (TARGET_ALLEGREX)
+    emit_insn (gen_allegrex_bitrev (operands[0], operands[1]));
+  else
+    {
+      rtx tmp = gen_reg_rtx (SImode);
+      emit_insn (gen_mips_bitswap (tmp, operands[1]));
+      emit_insn (gen_bswapsi2 (operands[0], tmp));
+    }
+  DONE;
+})
+
+(define_expand "bitreverseqi2"
+  [(set (match_operand:QI 0 "register_operand")
+       (bitreverse:QI (match_operand:QI 1 "register_operand")))]
+  "ISA_HAS_BITSWAP"
+{
+  /* BITSWAP already reverses within each byte, prevent widening.  */
+  rtx in = lowpart_subreg (SImode, operands[1], QImode);
+  rtx tmp = gen_reg_rtx (SImode);
+  emit_insn (gen_mips_bitswap (tmp, in));
+  emit_move_insn (operands[0], gen_lowpart (QImode, tmp));
+  DONE;
+})
+
 (define_insn "bswaphi2"
   [(set (match_operand:HI 0 "register_operand" "=d")
        (bswap:HI (match_operand:HI 1 "register_operand" "d")))]
@@ -6074,7 +6136,7 @@
 (define_insn_and_split "bswapdi2"
   [(set (match_operand:DI 0 "register_operand" "=d")
        (bswap:DI (match_operand:DI 1 "register_operand" "d")))]
-  "TARGET_64BIT && ISA_HAS_WSBH"
+  "TARGET_64BIT && ISA_HAS_DSBH_DSHD"
   "#"
   "&& 1"
   [(set (match_dup 0) (unspec:DI [(match_dup 1)] UNSPEC_DSBH))
diff --git a/gcc/testsuite/gcc.target/mips/bitrev-1.c 
b/gcc/testsuite/gcc.target/mips/bitrev-1.c
new file mode 100644
index 00000000000..dd7b57cfa4f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/mips/bitrev-1.c
@@ -0,0 +1,10 @@
+/* { dg-options "isa_rev>=6" } */
+NOMIPS16 unsigned int
+foo (unsigned int x)
+{
+  return __builtin_bitreverse32 (x);
+}
+/* { dg-final { scan-assembler-times "\tbitswap\t" 1 } } */
+/* { dg-final { scan-assembler-times "\twsbh\t" 1 } } */
+/* { dg-final { scan-assembler-times "\tror\t" 1 } } */
+/* { dg-final { scan-assembler-not "\tbitrev\t" } } */
diff --git a/gcc/testsuite/gcc.target/mips/bitrev-10.c 
b/gcc/testsuite/gcc.target/mips/bitrev-10.c
new file mode 100644
index 00000000000..857239b95e7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/mips/bitrev-10.c
@@ -0,0 +1,9 @@
+/* { dg-options "isa_rev>=6 -mgp64" } */
+NOMIPS16 unsigned long long
+foo (unsigned long long x)
+{
+  return __builtin_bitreverse64 (x);
+}
+/* { dg-final { scan-assembler-times "\tdbitswap\t" 1 } } */
+/* { dg-final { scan-assembler-times "\tdsbh\t" 1 } } */
+/* { dg-final { scan-assembler-times "\tdshd\t" 1 } } */
diff --git a/gcc/testsuite/gcc.target/mips/bitrev-11.c 
b/gcc/testsuite/gcc.target/mips/bitrev-11.c
new file mode 100644
index 00000000000..a77a99d8735
--- /dev/null
+++ b/gcc/testsuite/gcc.target/mips/bitrev-11.c
@@ -0,0 +1,10 @@
+/* { dg-options "isa_rev=1 -mgp64" } */
+NOMIPS16 unsigned long long
+foo (unsigned long long x)
+{
+  return __builtin_bitreverse64 (x);
+}
+/* { dg-final { scan-assembler-not "\tdbitswap\t" } } */
+/* { dg-final { scan-assembler-not "\tbitswap\t" } } */
+/* { dg-final { scan-assembler-not "\tdshd\t" } } */
+/* { dg-final { scan-assembler-not "\tdsbh\t" } } */
diff --git a/gcc/testsuite/gcc.target/mips/bitrev-12.c 
b/gcc/testsuite/gcc.target/mips/bitrev-12.c
new file mode 100644
index 00000000000..847bbb05f20
--- /dev/null
+++ b/gcc/testsuite/gcc.target/mips/bitrev-12.c
@@ -0,0 +1,10 @@
+/* { dg-options "isa_rev>=6 -mgp32" } */
+NOMIPS16 unsigned long long
+foo (unsigned long long x)
+{
+  return __builtin_bitreverse64 (x);
+}
+/* { dg-final { scan-assembler-times "\tbitswap\t" 2 } } */
+/* { dg-final { scan-assembler-times "\twsbh\t" 2 } } */
+/* { dg-final { scan-assembler-times "\tror\t" 2 } } */
+/* { dg-final { scan-assembler-not "\tdbitswap\t" } } */
diff --git a/gcc/testsuite/gcc.target/mips/bitrev-2.c 
b/gcc/testsuite/gcc.target/mips/bitrev-2.c
new file mode 100644
index 00000000000..8dcf7f2aa01
--- /dev/null
+++ b/gcc/testsuite/gcc.target/mips/bitrev-2.c
@@ -0,0 +1,18 @@
+/* { dg-options "isa_rev=1" } */
+NOMIPS16 unsigned int
+foo32 (unsigned int x)
+{
+  return __builtin_bitreverse32 (x);
+}
+NOMIPS16 unsigned short
+foo16 (unsigned short x)
+{
+  return __builtin_bitreverse16 (x);
+}
+NOMIPS16 unsigned char
+foo8 (unsigned char x)
+{
+  return __builtin_bitreverse8 (x);
+}
+/* { dg-final { scan-assembler-not "\tbitrev\t" } } */
+/* { dg-final { scan-assembler-not "\tbitswap\t" } } */
diff --git a/gcc/testsuite/gcc.target/mips/bitrev-3.c 
b/gcc/testsuite/gcc.target/mips/bitrev-3.c
new file mode 100644
index 00000000000..8b59615c22b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/mips/bitrev-3.c
@@ -0,0 +1,10 @@
+/* { dg-options "isa_rev>=2" } */
+NOMIPS16 unsigned int
+foo (unsigned int x)
+{
+  return __builtin_bitreverse32 (x);
+}
+/* { dg-final { scan-assembler "\twsbh\t" } } */
+/* { dg-final { scan-assembler "\tror\t" } } */
+/* { dg-final { scan-assembler-not "\tbitrev\t" } } */
+/* { dg-final { scan-assembler-not "\tbitswap\t" } } */
diff --git a/gcc/testsuite/gcc.target/mips/bitrev-4.c 
b/gcc/testsuite/gcc.target/mips/bitrev-4.c
new file mode 100644
index 00000000000..6b3b75e3113
--- /dev/null
+++ b/gcc/testsuite/gcc.target/mips/bitrev-4.c
@@ -0,0 +1,20 @@
+/* { dg-options "-mips32" } */
+NOMIPS16 unsigned int
+foo32 (unsigned int x)
+{
+  return __builtin_bitreverse32 (x);
+}
+NOMIPS16 unsigned short
+foo16 (unsigned short x)
+{
+  return __builtin_bitreverse16 (x);
+}
+NOMIPS16 unsigned char
+foo8 (unsigned char x)
+{
+  return __builtin_bitreverse8 (x);
+}
+/* { dg-final { scan-assembler-not "\twsbh\t" } } */
+/* { dg-final { scan-assembler-not "\tror\t" } } */
+/* { dg-final { scan-assembler-not "\tbitrev\t" } } */
+/* { dg-final { scan-assembler-not "\tbitswap\t" } } */
diff --git a/gcc/testsuite/gcc.target/mips/bitrev-5.c 
b/gcc/testsuite/gcc.target/mips/bitrev-5.c
new file mode 100644
index 00000000000..e9d132b64b9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/mips/bitrev-5.c
@@ -0,0 +1,9 @@
+/* { dg-options "-march=allegrex" } */
+NOMIPS16 unsigned int
+foo (unsigned int x)
+{
+  return __builtin_bitreverse32 (x);
+}
+/* { dg-final { scan-assembler-times "\tbitrev\t" 1 } } */
+/* { dg-final { scan-assembler-not "\twsbh\t" } } */
+/* { dg-final { scan-assembler-not "\tror\t" } } */
diff --git a/gcc/testsuite/gcc.target/mips/bitrev-6.c 
b/gcc/testsuite/gcc.target/mips/bitrev-6.c
new file mode 100644
index 00000000000..174f0b63003
--- /dev/null
+++ b/gcc/testsuite/gcc.target/mips/bitrev-6.c
@@ -0,0 +1,11 @@
+/* { dg-options "isa_rev>=6" } */
+/* { dg-skip-if "bswap recognition needs expensive optimizations" { *-*-* } { 
"-O0" "-O1" } { "" } } */
+NOMIPS16 unsigned short
+foo (unsigned short x)
+{
+  return __builtin_bitreverse16 (x);
+}
+/* { dg-final { scan-assembler-times "\tbitswap\t" 1 } } */
+/* { dg-final { scan-assembler-times "\twsbh\t" 1 } } */
+/* { dg-final { scan-assembler-not "\tror\t" } } */
+/* { dg-final { scan-assembler-not "\tbitrev\t" } } */
diff --git a/gcc/testsuite/gcc.target/mips/bitrev-7.c 
b/gcc/testsuite/gcc.target/mips/bitrev-7.c
new file mode 100644
index 00000000000..6c5e2f215a1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/mips/bitrev-7.c
@@ -0,0 +1,10 @@
+/* { dg-options "isa_rev>=6" } */
+NOMIPS16 unsigned char
+foo (unsigned char x)
+{
+  return __builtin_bitreverse8 (x);
+}
+/* { dg-final { scan-assembler-times "\tbitswap\t" 1 } } */
+/* { dg-final { scan-assembler-not "\twsbh\t" } } */
+/* { dg-final { scan-assembler-not "\tror\t" } } */
+/* { dg-final { scan-assembler-not "\tbitrev\t" } } */
diff --git a/gcc/testsuite/gcc.target/mips/bitrev-8.c 
b/gcc/testsuite/gcc.target/mips/bitrev-8.c
new file mode 100644
index 00000000000..f137a7f42c3
--- /dev/null
+++ b/gcc/testsuite/gcc.target/mips/bitrev-8.c
@@ -0,0 +1,10 @@
+/* { dg-options "-march=allegrex" } */
+NOMIPS16 unsigned short
+foo (unsigned short x)
+{
+  return __builtin_bitreverse16 (x);
+}
+/* { dg-final { scan-assembler-times "\tbitrev\t" 1 } } */
+/* { dg-final { scan-assembler-times "\tsrl\t" 1 } } */
+/* { dg-final { scan-assembler-not "\twsbh\t" } } */
+/* { dg-final { scan-assembler-not "\tbitswap\t" } } */
diff --git a/gcc/testsuite/gcc.target/mips/bitrev-9.c 
b/gcc/testsuite/gcc.target/mips/bitrev-9.c
new file mode 100644
index 00000000000..7522f3a5b36
--- /dev/null
+++ b/gcc/testsuite/gcc.target/mips/bitrev-9.c
@@ -0,0 +1,10 @@
+/* { dg-options "-march=allegrex" } */
+NOMIPS16 unsigned char
+foo (unsigned char x)
+{
+  return __builtin_bitreverse8 (x);
+}
+/* { dg-final { scan-assembler-times "\tbitrev\t" 1 } } */
+/* { dg-final { scan-assembler-times "\tsrl\t" 1 } } */
+/* { dg-final { scan-assembler-not "\twsbh\t" } } */
+/* { dg-final { scan-assembler-not "\tbitswap\t" } } */
-- 
2.55.0

Reply via email to