[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