BITSWAP is a byte-wise bitreverse in MIPSr6. For example,
BITSWAP(0x44332211) => 0x22cc4488.
DBITSWAP is similar to BITSWAP but for 64 bit.

This patch adds BITSWAP/DBITSWAP instrutions with corresponding tests.

gcc/ChangeLog:

        * config/mips/i6400.md (i6400_int_arith): Include bitswap
        type.
        * config/mips/mips-ftypes.def: Add function types for
        DBITSWAP builtins.
        * config/mips/mips.cc (CODE_FOR_mipsr6_bitswap)
        (CODE_FOR_mipsr6_dbitswap): New code_aliasing macros.
        (mips_builtins): Add mips32r6 bitswap, dbitswap builtins.
        * config/mips/mips.h (ISA_HAS_BITSWAP): Define a new macro.
        (ISA_HAS_DBITSWAP): Same as above.
        * config/mips/mips.md (UNSPEC_BITSWAP): New unspec.
        (type): Add bitswap.
        (<GPR:d>bitswap): Generates BITSWAP/DBITSWAP instructions.
        * config/mips/p6600.md (p6600_int_arith_4): Include bitswap
        type.

gcc/testsuite/ChangeLog:

        * gcc.target/mips/bitswap.c: New test for MIPSr6.
        * gcc.target/mips/dbitswap.c: Same as above.

Co-developed-by: Rong Zhang <[email protected]>
Signed-off-by: Rong Zhang <[email protected]>
Signed-off-by: Jie Mei <[email protected]>
---
 gcc/config/mips/i6400.md                 |   4 +-
 gcc/config/mips/mips-ftypes.def          |   1 +
 gcc/config/mips/mips.cc                  |   4 +
 gcc/config/mips/mips.h                   |   6 +
 gcc/config/mips/mips.md                  |  20 +++-
 gcc/config/mips/p6600.md                 |   4 +-
 gcc/testsuite/gcc.target/mips/bitswap.c  | 141 +++++++++++++++++++++++
 gcc/testsuite/gcc.target/mips/dbitswap.c | 129 +++++++++++++++++++++
 8 files changed, 302 insertions(+), 7 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/mips/bitswap.c
 create mode 100644 gcc/testsuite/gcc.target/mips/dbitswap.c

diff --git a/gcc/config/mips/i6400.md b/gcc/config/mips/i6400.md
index 62f70c1e816..8eb377a959d 100644
--- a/gcc/config/mips/i6400.md
+++ b/gcc/config/mips/i6400.md
@@ -296,10 +296,10 @@
        (eq_attr "alu_type" "add,sub,or,xor,nor"))
   "i6400_control_alu0 | i6400_agen_alu1")
 
-;; shifts, clo, clz, cond move, arith
+;; shifts, clo, clz, cond move, arith, bitswap
 (define_insn_reservation "i6400_int_arith" 1
   (and (eq_attr "cpu" "i6400")
-       (eq_attr "type" "shift,slt,move,clz,condmove,arith"))
+       (eq_attr "type" "shift,slt,move,clz,condmove,arith,bitswap"))
   "i6400_control_alu0 | i6400_agen_alu1")
 
 ;; nop
diff --git a/gcc/config/mips/mips-ftypes.def b/gcc/config/mips/mips-ftypes.def
index fb72661c682..70fd61e2af5 100644
--- a/gcc/config/mips/mips-ftypes.def
+++ b/gcc/config/mips/mips-ftypes.def
@@ -37,6 +37,7 @@ DEF_MIPS_FTYPE (1, (DF, DF))
 DEF_MIPS_FTYPE (2, (DF, DF, DF))
 DEF_MIPS_FTYPE (1, (DF, V2DF))
 
+DEF_MIPS_FTYPE (1, (DI, DI))
 DEF_MIPS_FTYPE (2, (DI, DI, DI))
 DEF_MIPS_FTYPE (2, (DI, DI, SI))
 DEF_MIPS_FTYPE (3, (DI, DI, SI, SI))
diff --git a/gcc/config/mips/mips.cc b/gcc/config/mips/mips.cc
index cc45a195b89..b8fc6b3cb0c 100644
--- a/gcc/config/mips/mips.cc
+++ b/gcc/config/mips/mips.cc
@@ -16214,6 +16214,8 @@ AVAIL_NON_MIPS16 (r6, mips_isa_rev >= 6)
 #define CODE_FOR_mipsr6_max_a_d CODE_FOR_fmax_a_df
 #define CODE_FOR_mipsr6_class_s CODE_FOR_fclass_sf
 #define CODE_FOR_mipsr6_class_d CODE_FOR_fclass_df
+#define CODE_FOR_mipsr6_bitswap CODE_FOR_bitswap
+#define CODE_FOR_mipsr6_dbitswap CODE_FOR_dbitswap
 
 static const struct mips_builtin_description mips_builtins[] = {
 #define MIPS_GET_FCSR 0
@@ -17044,6 +17046,8 @@ static const struct mips_builtin_description 
mips_builtins[] = {
   MIPSR6_BUILTIN_PURE (max_a_d, MIPS_DF_FTYPE_DF_DF),
   MIPSR6_BUILTIN_PURE (class_s, MIPS_SF_FTYPE_SF),
   MIPSR6_BUILTIN_PURE (class_d, MIPS_DF_FTYPE_DF),
+  MIPSR6_BUILTIN_PURE (bitswap, MIPS_SI_FTYPE_SI),
+  MIPSR6_BUILTIN_PURE (dbitswap, MIPS_DI_FTYPE_DI),
 };
 
 /* Index I is the function declaration for mips_builtins[I], or null if the
diff --git a/gcc/config/mips/mips.h b/gcc/config/mips/mips.h
index f52d0d2358c..8a930b52942 100644
--- a/gcc/config/mips/mips.h
+++ b/gcc/config/mips/mips.h
@@ -1267,6 +1267,12 @@ struct mips_cpu_info {
 /* Similar to WSBH but for 32 bit words (byte swap within a word). */
 #define ISA_HAS_WSBW           (TARGET_ALLEGREX)
 
+/* ISA has the BITSWAP (swaps bits in each byte) instruction.  */
+#define ISA_HAS_BITSWAP                (mips_isa_rev >= 6)
+
+/* Similar to BITSWAP but for 64 bit (swaps bits in each byte).  */
+#define ISA_HAS_DBITSWAP       (TARGET_64BIT && mips_isa_rev >= 6)
+
 /* 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 85e7d67901f..24369163f44 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
@@ -396,9 +397,9 @@
   "unknown,branch,jump,call,load,fpload,fpidxload,store,fpstore,fpidxstore,
    prefetch,prefetchx,condmove,mtc,mfc,mthi,mtlo,mfhi,mflo,const,arith,logical,
    shift,slt,signext,clz,pop,trap,imul,imul3,imul3nc,imadd,idiv,idiv3,move,
-   fmove,fadd,fmul,fmadd,fdiv,frdiv,frdiv1,frdiv2,fabs,fneg,fcmp,fcvt,fsqrt,
-   frsqrt,frsqrt1,frsqrt2,fminmax,frint,fclass,dspmac,dspmacsat,accext,
-   accmod,dspalu,dspalusat,multi,atomic,syncloop,nop,ghost,multimem,
+   bitswap,fmove,fadd,fmul,fmadd,fdiv,frdiv,frdiv1,frdiv2,fabs,fneg,fcmp,
+   fcvt,fsqrt,frsqrt,frsqrt1,frsqrt2,fminmax,frint,fclass,dspmac,dspmacsat,
+   accext,accmod,dspalu,dspalusat,multi,atomic,syncloop,nop,ghost,multimem,
    simd_div,simd_fclass,simd_flog2,simd_fadd,simd_fcvt,simd_fmul,simd_fmadd,
    simd_fdiv,simd_bitins,simd_bitmov,simd_insert,simd_sld,simd_mul,simd_fcmp,
    simd_fexp2,simd_int_arith,simd_bit,simd_shift,simd_splat,simd_fill,
@@ -6102,6 +6103,19 @@
   "TARGET_64BIT && ISA_HAS_WSBH"
   "dshd\t%0,%1"
   [(set_attr "type" "shift")])
+
+;;
+;;  Swaps (reverses) bits in each byte
+;;
+
+(define_insn "<GPR:d>bitswap"
+  [(set (match_operand:GPR 0 "register_operand" "=d")
+       (unspec:GPR [(use (match_operand:GPR 1 "register_operand" "d"))]
+                   UNSPEC_BITSWAP))]
+  "ISA_HAS_<GPR:D>BITSWAP"
+  "<GPR:d>bitswap\t%0,%1"
+  [(set_attr "type" "bitswap")
+   (set_attr "mode" "<GPR:MODE>")])
 
 ;;
 ;;  ....................
diff --git a/gcc/config/mips/p6600.md b/gcc/config/mips/p6600.md
index 05c426e8134..bb6bb128d61 100644
--- a/gcc/config/mips/p6600.md
+++ b/gcc/config/mips/p6600.md
@@ -269,10 +269,10 @@
        (eq_attr "alu_type" "and,not,nor,sub"))
   "p6600_alq_alu")
 
-;; srl, sra, rotr, slt, sllv, srlv
+;; srl, sra, rotr, slt, sllv, srlv, bitswap
 (define_insn_reservation "p6600_int_arith_4" 1
   (and (eq_attr "cpu" "p6600")
-       (eq_attr "type" "shift,slt,move"))
+       (eq_attr "type" "shift,slt,move,bitswap"))
   "p6600_alq_alu | p6600_agq_al2")
 
 ;; nop
diff --git a/gcc/testsuite/gcc.target/mips/bitswap.c 
b/gcc/testsuite/gcc.target/mips/bitswap.c
new file mode 100644
index 00000000000..495c863a40e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/mips/bitswap.c
@@ -0,0 +1,141 @@
+/* { dg-do compile } */
+/* { dg-options "isa_rev>=6 -mabi=32 (REQUIRES_STDLIB)" } */
+/* { dg-final { scan-assembler-times "\tbitswap\t" 22 } } */
+/* { dg-final { scan-assembler-times "\tseb\t" 4 } } */
+/* { dg-final { scan-assembler-times "\tseh\t" 6 } } */
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
+/* Skip -O0 so that we can test against SEB and SEH. */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+
+NOMIPS16 int main()
+{
+
+  int8_t i8_a, i8_b, i8_x;     
+  int16_t i16_a, i16_b, i16_x;
+  int32_t i32_a, i32_b, i32_x;
+
+  i8_a = 0x01;
+  i8_b = 0x80;
+  i8_x = __builtin_mipsr6_bitswap (i8_a);
+  if (i8_x != i8_b)
+    abort ();
+
+  i8_a = 0x10;
+  i8_b = 0x08;
+  i8_x = __builtin_mipsr6_bitswap (i8_a);
+  if (i8_x != i8_b)
+    abort ();
+
+  i8_a = 0x23;
+  i8_b = 0xc4;
+  i8_x = __builtin_mipsr6_bitswap (i8_a);
+  if (i8_x != i8_b)
+    abort ();
+  i8_x = __builtin_mipsr6_bitswap (i8_b);
+  if (i8_x != i8_a)
+    abort ();
+
+  i16_a = 0x0002;
+  i16_b = 0x0040;
+  i16_x = __builtin_mipsr6_bitswap (i16_a);
+  if (i16_x != i16_b)
+    abort ();
+
+  i16_a = 0x0020;
+  i16_b = 0x0004;
+  i16_x = __builtin_mipsr6_bitswap (i16_a);
+  if (i16_x != i16_b)
+    abort ();
+
+  i16_a = 0x0200;
+  i16_b = 0x4000;
+  i16_x = __builtin_mipsr6_bitswap (i16_a);
+  if (i16_x != i16_b)
+    abort ();
+
+  i16_a = 0x2000;
+  i16_b = 0x0400;
+  i16_x = __builtin_mipsr6_bitswap (i16_a);
+  if (i16_x != i16_b)
+    abort ();
+
+  i16_a = 0x1234;
+  i16_b = 0x482c;
+  i16_x = __builtin_mipsr6_bitswap (i16_a);
+  if (i16_x != i16_b)
+    abort ();
+  i16_x = __builtin_mipsr6_bitswap (i16_b);
+  if (i16_x != i16_a)
+    abort ();
+
+  i32_a = 0x00000003;
+  i32_b = 0x000000c0;
+  i32_x = __builtin_mipsr6_bitswap (i32_a);
+  if (i32_x != i32_b)
+    abort ();
+
+  i32_a = 0x00000030;
+  i32_b = 0x0000000c;
+  i32_x = __builtin_mipsr6_bitswap (i32_a);
+  if (i32_x != i32_b)
+    abort ();
+
+  i32_a = 0x00000300;
+  i32_b = 0x0000c000;
+  i32_x = __builtin_mipsr6_bitswap (i32_a);
+  if (i32_x != i32_b)
+    abort ();
+
+  i32_a = 0x00003000;
+  i32_b = 0x00000c00;
+  i32_x = __builtin_mipsr6_bitswap (i32_a);
+  if (i32_x != i32_b)
+    abort ();
+
+  i32_a = 0x00030000;
+  i32_b = 0x00c00000;
+  i32_x = __builtin_mipsr6_bitswap (i32_a);
+  if (i32_x != i32_b)
+    abort ();
+
+  i32_a = 0x00300000;
+  i32_b = 0x000c0000;
+  i32_x = __builtin_mipsr6_bitswap (i32_a);
+  if (i32_x != i32_b)
+    abort ();
+
+  i32_a = 0x03000000;
+  i32_b = 0xc0000000;
+  i32_x = __builtin_mipsr6_bitswap (i32_a);
+  if (i32_x != i32_b)
+    abort ();
+
+  i32_a = 0x30000000;
+  i32_b = 0x0c000000;
+  i32_x = __builtin_mipsr6_bitswap (i32_a);
+  if (i32_x != i32_b)
+    abort ();
+
+  i32_a = 0x11223344;
+  i32_b = 0x8844cc22;
+  i32_x = __builtin_mipsr6_bitswap (i32_a);
+  if (i32_x != i32_b)
+    abort ();
+  i32_x = __builtin_mipsr6_bitswap (i32_b);
+  if (i32_x != i32_a)
+    abort ();
+
+  i32_a = 0x3baf6dec;
+  i32_b = 0xdcf5b637;
+  i32_x = __builtin_mipsr6_bitswap (i32_a);
+  if (i32_x != i32_b)
+    abort ();
+  i32_x = __builtin_mipsr6_bitswap (i32_b);
+  if (i32_x != i32_a)
+    abort ();
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/mips/dbitswap.c 
b/gcc/testsuite/gcc.target/mips/dbitswap.c
new file mode 100644
index 00000000000..be4804abf10
--- /dev/null
+++ b/gcc/testsuite/gcc.target/mips/dbitswap.c
@@ -0,0 +1,129 @@
+/* { dg-do compile } */
+/* { dg-options "isa_rev>=6 -mabi=64 (REQUIRES_STDLIB)" } */
+/* { dg-final { scan-assembler-times "\tdbitswap\t" 20 } } */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+
+NOMIPS16 int main()
+{
+
+  int64_t i64_a, i64_b, i64_x;
+
+  i64_a = 0x0000000000000001LL;
+  i64_b = 0x0000000000000080LL;
+  i64_x = __builtin_mipsr6_dbitswap (i64_a);
+  if (i64_x != i64_b)
+    abort ();
+
+  i64_a = 0x0000000000000010LL;
+  i64_b = 0x0000000000000008LL;
+  i64_x = __builtin_mipsr6_dbitswap (i64_a);
+  if (i64_x != i64_b)
+    abort ();
+
+  i64_a = 0x0000000000000100LL;
+  i64_b = 0x0000000000008000LL;
+  i64_x = __builtin_mipsr6_dbitswap (i64_a);
+  if (i64_x != i64_b)
+    abort ();
+
+  i64_a = 0x0000000000001000LL;
+  i64_b = 0x0000000000000800LL;
+  i64_x = __builtin_mipsr6_dbitswap (i64_a);
+  if (i64_x != i64_b)
+    abort ();
+
+  i64_a = 0x0000000000010000LL;
+  i64_b = 0x0000000000800000LL;
+  i64_x = __builtin_mipsr6_dbitswap (i64_a);
+  if (i64_x != i64_b)
+    abort ();
+
+  i64_a = 0x0000000000100000LL;
+  i64_b = 0x0000000000080000LL;
+  i64_x = __builtin_mipsr6_dbitswap (i64_a);
+  if (i64_x != i64_b)
+    abort ();
+
+  i64_a = 0x0000000001000000LL;
+  i64_b = 0x0000000080000000LL;
+  i64_x = __builtin_mipsr6_dbitswap (i64_a);
+  if (i64_x != i64_b)
+    abort ();
+
+  i64_a = 0x0000000010000000LL;
+  i64_b = 0x0000000008000000LL;
+  i64_x = __builtin_mipsr6_dbitswap (i64_a);
+  if (i64_x != i64_b)
+    abort ();
+
+  i64_a = 0x0000000100000000LL;
+  i64_b = 0x0000008000000000LL;
+  i64_x = __builtin_mipsr6_dbitswap (i64_a);
+  if (i64_x != i64_b)
+    abort ();
+
+  i64_a = 0x0000001000000000LL;
+  i64_b = 0x0000000800000000LL;
+  i64_x = __builtin_mipsr6_dbitswap (i64_a);
+  if (i64_x != i64_b)
+    abort ();
+
+  i64_a = 0x0000010000000000LL;
+  i64_b = 0x0000800000000000LL;
+  i64_x = __builtin_mipsr6_dbitswap (i64_a);
+  if (i64_x != i64_b)
+    abort ();
+
+  i64_a = 0x0000100000000000LL;
+  i64_b = 0x0000080000000000LL;
+  i64_x = __builtin_mipsr6_dbitswap (i64_a);
+  if (i64_x != i64_b)
+    abort ();
+
+  i64_a = 0x0001000000000000LL;
+  i64_b = 0x0080000000000000LL;
+  i64_x = __builtin_mipsr6_dbitswap (i64_a);
+  if (i64_x != i64_b)
+    abort ();
+
+  i64_a = 0x0010000000000000LL;
+  i64_b = 0x0008000000000000LL;
+  i64_x = __builtin_mipsr6_dbitswap (i64_a);
+  if (i64_x != i64_b)
+    abort ();
+
+  i64_a = 0x0100000000000000LL;
+  i64_b = 0x8000000000000000LL;
+  i64_x = __builtin_mipsr6_dbitswap (i64_a);
+  if (i64_x != i64_b)
+    abort ();
+
+  i64_a = 0x1000000000000000LL;
+  i64_b = 0x0800000000000000LL;
+  i64_x = __builtin_mipsr6_dbitswap (i64_a);
+  if (i64_x != i64_b)
+    abort ();
+
+  i64_a = 0x1122334455667788LL;
+  i64_b = 0x8844cc22aa66ee11LL;
+  i64_x = __builtin_mipsr6_dbitswap (i64_a);
+  if (i64_x != i64_b)
+    abort ();
+  i64_x = __builtin_mipsr6_dbitswap (i64_b);
+  if (i64_x != i64_a)
+    abort ();
+
+  i64_a = 0x71e9a43a6791033dLL;
+  i64_b = 0x8e97255ce689c0bcLL;
+  i64_x = __builtin_mipsr6_dbitswap (i64_a);
+  if (i64_x != i64_b)
+    abort ();
+  i64_x = __builtin_mipsr6_dbitswap (i64_b);
+  if (i64_x != i64_a)
+    abort ();
+
+  return 0;
+}
-- 
2.52.0

Reply via email to