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