[PATCH] MIPS: Add MIPS32/64 r6 (d)bitswap and Allegrex bitrev

David Guillen Fandos <[email protected]>
Newsgroups gmane.comp.gcc.patches
Message-ID <[email protected]>
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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.