[v4,5/9] riscv: thead: Add support for the XTheadBb ISA extension
Checks
Commit Message
From: Christoph Müllner <christoph.muellner@vrull.eu>
This patch adds support for the XTheadBb ISA extension.
Thus, there is a functional overlap of the new instructions with
existing Bitmanip instruction, which allows a good amount of code
sharing. However, the vendor extensions are cleanly separated from
the standard extensions (e.g. by using INSN expand pattern that
will re-emit RTL that matches the patterns of either Bitmanip or
XThead INSNs).
gcc/ChangeLog:
* config/riscv/bitmanip.md (clzdi2): New expand.
(clzsi2): New expand.
(ctz<mode>2): New expand.
(popcount<mode>2): New expand.
(<bitmanip_optab>si2): Rename INSN.
(*<bitmanip_optab>si2): Hide INSN name.
(<bitmanip_optab>di2): Rename INSN.
(*<bitmanip_optab>di2): Hide INSN name.
(rotrsi3): Remove INSN.
(rotr<mode>3): Add expand.
(*rotrsi3): New INSN.
(rotrdi3): Rename INSN.
(*rotrdi3): Hide INSN name.
(rotrsi3_sext): Rename INSN.
(*rotrsi3_sext): Hide INSN name.
(bswap<mode>2): Remove INSN.
(bswapdi2): Add expand.
(bswapsi2): Add expand.
(*bswap<mode>2): Hide INSN name.
* config/riscv/riscv.cc (riscv_rtx_costs): Add costs for sign
extraction.
* config/riscv/riscv.md (extv<mode>): New expand.
(extzv<mode>): New expand.
* config/riscv/thead.md (*th_srri<mode>3): New INSN.
(*th_ext<mode>): New INSN.
(*th_extu<mode>): New INSN.
(*th_clz<mode>2): New INSN.
(*th_rev<mode>2): New INSN.
gcc/testsuite/ChangeLog:
* gcc.target/riscv/xtheadbb-ext.c: New test.
* gcc.target/riscv/xtheadbb-extu-2.c: New test.
* gcc.target/riscv/xtheadbb-extu.c: New test.
* gcc.target/riscv/xtheadbb-ff1.c: New test.
* gcc.target/riscv/xtheadbb-rev.c: New test.
* gcc.target/riscv/xtheadbb-srri.c: New test.
Changes in v4:
- Replace 'immediate_operand' by 'const_int_operand'
- Add number of arguments to pattern names
- Merge th_srri<mode>3 patterns
- Merge th_rev<mode>2 patterns
- Improve coverage of th.srri test
Changes for v2:
- Merge all XTheadB* support patches
- Remove useless operand sanity checks for extv<mode> and extzv<mode>
- Prefer c.andi over th.extu if possible
- Add ff1 tests for clz/ctz
- Fix ext/extu test cases
- Enable tests for RV32
Signed-off-by: Christoph Müllner <christoph.muellner@vrull.eu>
---
gcc/config/riscv/bitmanip.md | 52 ++++++++++++++--
gcc/config/riscv/riscv.cc | 9 +++
gcc/config/riscv/riscv.md | 20 ++++++
gcc/config/riscv/thead.md | 61 +++++++++++++++++++
gcc/testsuite/gcc.target/riscv/xtheadbb-ext.c | 20 ++++++
.../gcc.target/riscv/xtheadbb-extu-2.c | 22 +++++++
.../gcc.target/riscv/xtheadbb-extu.c | 22 +++++++
gcc/testsuite/gcc.target/riscv/xtheadbb-ff1.c | 18 ++++++
gcc/testsuite/gcc.target/riscv/xtheadbb-rev.c | 45 ++++++++++++++
.../gcc.target/riscv/xtheadbb-srri.c | 25 ++++++++
10 files changed, 288 insertions(+), 6 deletions(-)
create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadbb-ext.c
create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadbb-extu-2.c
create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadbb-extu.c
create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadbb-ff1.c
create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadbb-rev.c
create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadbb-srri.c
Comments
On 3/2/23 01:35, Christoph Muellner wrote:
> From: Christoph Müllner <christoph.muellner@vrull.eu>
>
> This patch adds support for the XTheadBb ISA extension.
> Thus, there is a functional overlap of the new instructions with
> existing Bitmanip instruction, which allows a good amount of code
> sharing. However, the vendor extensions are cleanly separated from
> the standard extensions (e.g. by using INSN expand pattern that
> will re-emit RTL that matches the patterns of either Bitmanip or
> XThead INSNs).
>
> diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
> index d6c2265e9d4..fc8ce9f5226 100644
> --- a/gcc/config/riscv/riscv.md
> +++ b/gcc/config/riscv/riscv.md
> @@ -3087,6 +3087,26 @@ (define_insn "riscv_prefetchi_<mode>"
> "prefetch.i\t%a0"
> )
>
> +(define_expand "extv<mode>"
> + [(set (match_operand:GPR 0 "register_operand" "=r")
> + (sign_extract:GPR (match_operand:GPR 1 "register_operand" "r")
> + (match_operand 2 "const_int_operand")
> + (match_operand 3 "const_int_operand")))]
> + "TARGET_XTHEADBB"
> +)
> +
> +(define_expand "extzv<mode>"
> + [(set (match_operand:GPR 0 "register_operand" "=r")
> + (zero_extract:GPR (match_operand:GPR 1 "register_operand" "r")
> + (match_operand 2 "const_int_operand")
> + (match_operand 3 "const_int_operand")))]
> + "TARGET_XTHEADBB"
> +{
> + if (TARGET_XTHEADBB
> + && (INTVAL (operands[2]) < 8) && (INTVAL (operands[3]) == 0))
> + FAIL;
> +})
Note that bitmanip has single bit extractions which probably should be
handed by extzv rather than relying strictly on the combiner to
synthesize them. Similarly for single bit insertions.
I've actually got a TODO on Raphael's plate to see how renaming the
existing bitmanip bit extraction to extzv affects code generation. I'm
not offhand sure where it is on his priority list yet.
I guess the wider point is the ext and ins expanders should probably be
accepting single bit extractions/insertions when ZBS is enabled.
Jeff
@@ -185,6 +185,26 @@ (define_insn "*slliuw"
;; ZBB extension.
+(define_expand "clzdi2"
+ [(set (match_operand:DI 0 "register_operand")
+ (clz:DI (match_operand:DI 1 "register_operand")))]
+ "TARGET_64BIT && (TARGET_ZBB || TARGET_XTHEADBB)")
+
+(define_expand "clzsi2"
+ [(set (match_operand:SI 0 "register_operand")
+ (clz:SI (match_operand:SI 1 "register_operand")))]
+ "TARGET_ZBB || (!TARGET_64BIT && TARGET_XTHEADBB)")
+
+(define_expand "ctz<mode>2"
+ [(set (match_operand:GPR 0 "register_operand")
+ (ctz:GPR (match_operand:GPR 1 "register_operand")))]
+ "TARGET_ZBB")
+
+(define_expand "popcount<mode>2"
+ [(set (match_operand:GPR 0 "register_operand")
+ (popcount:GPR (match_operand:GPR 1 "register_operand")))]
+ "TARGET_ZBB")
+
(define_insn "*<optab>_not<mode>"
[(set (match_operand:X 0 "register_operand" "=r")
(bitmanip_bitwise:X (not:X (match_operand:X 1 "register_operand" "r"))
@@ -216,7 +236,7 @@ (define_insn "*xor_not<mode>"
[(set_attr "type" "bitmanip")
(set_attr "mode" "<X:MODE>")])
-(define_insn "<bitmanip_optab>si2"
+(define_insn "*<bitmanip_optab>si2"
[(set (match_operand:SI 0 "register_operand" "=r")
(clz_ctz_pcnt:SI (match_operand:SI 1 "register_operand" "r")))]
"TARGET_ZBB"
@@ -233,7 +253,7 @@ (define_insn "*<bitmanip_optab>disi2"
[(set_attr "type" "bitmanip")
(set_attr "mode" "SI")])
-(define_insn "<bitmanip_optab>di2"
+(define_insn "*<bitmanip_optab>di2"
[(set (match_operand:DI 0 "register_operand" "=r")
(clz_ctz_pcnt:DI (match_operand:DI 1 "register_operand" "r")))]
"TARGET_64BIT && TARGET_ZBB"
@@ -273,7 +293,17 @@ (define_insn "*zero_extendhi<GPR:mode>2_zbb"
[(set_attr "type" "bitmanip,load")
(set_attr "mode" "HI")])
-(define_insn "rotrsi3"
+(define_expand "rotr<mode>3"
+ [(set (match_operand:GPR 0 "register_operand")
+ (rotatert:GPR (match_operand:GPR 1 "register_operand")
+ (match_operand:QI 2 "arith_operand")))]
+ "TARGET_ZBB || TARGET_XTHEADBB"
+{
+ if (TARGET_XTHEADBB && !immediate_operand (operands[2], VOIDmode))
+ FAIL;
+})
+
+(define_insn "*rotrsi3"
[(set (match_operand:SI 0 "register_operand" "=r")
(rotatert:SI (match_operand:SI 1 "register_operand" "r")
(match_operand:QI 2 "arith_operand" "rI")))]
@@ -281,7 +311,7 @@ (define_insn "rotrsi3"
"ror%i2%~\t%0,%1,%2"
[(set_attr "type" "bitmanip")])
-(define_insn "rotrdi3"
+(define_insn "*rotrdi3"
[(set (match_operand:DI 0 "register_operand" "=r")
(rotatert:DI (match_operand:DI 1 "register_operand" "r")
(match_operand:QI 2 "arith_operand" "rI")))]
@@ -289,7 +319,7 @@ (define_insn "rotrdi3"
"ror%i2\t%0,%1,%2"
[(set_attr "type" "bitmanip")])
-(define_insn "rotrsi3_sext"
+(define_insn "*rotrsi3_sext"
[(set (match_operand:DI 0 "register_operand" "=r")
(sign_extend:DI (rotatert:SI (match_operand:SI 1 "register_operand" "r")
(match_operand:QI 2 "register_operand" "r"))))]
@@ -329,7 +359,17 @@ (define_insn "orcb<mode>2"
"TARGET_ZBB"
"orc.b\t%0,%1")
-(define_insn "bswap<mode>2"
+(define_expand "bswapdi2"
+ [(set (match_operand:DI 0 "register_operand")
+ (bswap:DI (match_operand:DI 1 "register_operand")))]
+ "TARGET_64BIT && (TARGET_ZBB || TARGET_XTHEADBB)")
+
+(define_expand "bswapsi2"
+ [(set (match_operand:SI 0 "register_operand")
+ (bswap:SI (match_operand:SI 1 "register_operand")))]
+ "(!TARGET_64BIT && TARGET_ZBB) || TARGET_XTHEADBB")
+
+(define_insn "*bswap<mode>2"
[(set (match_operand:X 0 "register_operand" "=r")
(bswap:X (match_operand:X 1 "register_operand" "r")))]
"TARGET_ZBB"
@@ -2408,6 +2408,15 @@ riscv_rtx_costs (rtx x, machine_mode mode, int outer_code, int opno ATTRIBUTE_UN
*total = COSTS_N_INSNS (SINGLE_SHIFT_COST);
return true;
}
+ gcc_fallthrough ();
+ case SIGN_EXTRACT:
+ if (TARGET_XTHEADBB && outer_code == SET
+ && CONST_INT_P (XEXP (x, 1))
+ && CONST_INT_P (XEXP (x, 2)))
+ {
+ *total = COSTS_N_INSNS (SINGLE_SHIFT_COST);
+ return true;
+ }
return false;
case ASHIFT:
@@ -3087,6 +3087,26 @@ (define_insn "riscv_prefetchi_<mode>"
"prefetch.i\t%a0"
)
+(define_expand "extv<mode>"
+ [(set (match_operand:GPR 0 "register_operand" "=r")
+ (sign_extract:GPR (match_operand:GPR 1 "register_operand" "r")
+ (match_operand 2 "const_int_operand")
+ (match_operand 3 "const_int_operand")))]
+ "TARGET_XTHEADBB"
+)
+
+(define_expand "extzv<mode>"
+ [(set (match_operand:GPR 0 "register_operand" "=r")
+ (zero_extract:GPR (match_operand:GPR 1 "register_operand" "r")
+ (match_operand 2 "const_int_operand")
+ (match_operand 3 "const_int_operand")))]
+ "TARGET_XTHEADBB"
+{
+ if (TARGET_XTHEADBB
+ && (INTVAL (operands[2]) < 8) && (INTVAL (operands[3]) == 0))
+ FAIL;
+})
+
(include "bitmanip.md")
(include "sync.md")
(include "peephole.md")
@@ -30,6 +30,67 @@ (define_insn "*th_addsl<mode>4"
[(set_attr "type" "bitmanip")
(set_attr "mode" "<X:MODE>")])
+;; XTheadBb
+
+(define_insn "*th_srri<mode>3"
+ [(set (match_operand:GPR 0 "register_operand" "=r")
+ (rotatert:GPR (match_operand:GPR 1 "register_operand" "r")
+ (match_operand 2 "const_int_operand" "n")))]
+ "TARGET_XTHEADBB && (TARGET_64BIT || <MODE>mode == SImode)"
+ {
+ bool wform = TARGET_64BIT && (<MODE>mode == SImode);
+ operands[2] = GEN_INT (INTVAL (operands[2])
+ & (GET_MODE_BITSIZE (<MODE>mode) - 1));
+ return wform ? "th.srriw\t%0,%1,%2" : "th.srri\t%0,%1,%2";
+ }
+ [(set_attr "type" "bitmanip")
+ (set_attr "mode" "<GPR:MODE>")])
+
+(define_insn "*th_ext<mode>4"
+ [(set (match_operand:GPR 0 "register_operand" "=r")
+ (sign_extract:GPR (match_operand:GPR 1 "register_operand" "r")
+ (match_operand 2 "const_int_operand")
+ (match_operand 3 "const_int_operand")))]
+ "TARGET_XTHEADBB"
+{
+ operands[2] = GEN_INT (INTVAL (operands[2]) + INTVAL (operands[3]) - 1);
+ return "th.ext\t%0,%1,%2,%3";
+}
+ [(set_attr "type" "bitmanip")
+ (set_attr "mode" "<GPR:MODE>")])
+
+(define_insn "*th_extu<mode>4"
+ [(set (match_operand:GPR 0 "register_operand" "=r")
+ (zero_extract:GPR (match_operand:GPR 1 "register_operand" "r")
+ (match_operand 2 "const_int_operand")
+ (match_operand 3 "const_int_operand")))]
+ "TARGET_XTHEADBB"
+{
+ operands[2] = GEN_INT (INTVAL (operands[2]) + INTVAL (operands[3]) - 1);
+ return "th.extu\t%0,%1,%2,%3";
+}
+ [(set_attr "type" "bitmanip")
+ (set_attr "mode" "<GPR:MODE>")])
+
+(define_insn "*th_clz<mode>2"
+ [(set (match_operand:X 0 "register_operand" "=r")
+ (clz:X (match_operand:X 1 "register_operand" "r")))]
+ "TARGET_XTHEADBB"
+ "th.ff1\t%0,%1"
+ [(set_attr "type" "bitmanip")
+ (set_attr "mode" "<X:MODE>")])
+
+(define_insn "*th_rev<mode>2"
+ [(set (match_operand:GPR 0 "register_operand" "=r")
+ (bswap:GPR (match_operand:GPR 1 "register_operand" "r")))]
+ "TARGET_XTHEADBB && (TARGET_64BIT || <MODE>mode == SImode)"
+ {
+ bool wform = TARGET_64BIT && (<MODE>mode == SImode);
+ return wform ? "th.revw\t%0,%1" : "th.rev\t%0,%1";
+ }
+ [(set_attr "type" "bitmanip")
+ (set_attr "mode" "<GPR:MODE>")])
+
;; XTheadBs
(define_insn "*th_tst<mode>3"
new file mode 100644
@@ -0,0 +1,20 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv32gc_xtheadbb" { target { rv32 } } } */
+/* { dg-options "-march=rv64gc_xtheadbb" { target { rv64 } } } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Os" "-Og" } } */
+
+struct bar
+{
+ long a:9;
+ long b:26;
+ long c:22;
+};
+
+long
+foo (struct bar *s)
+{
+ return s->b;
+}
+
+/* { dg-final { scan-assembler "th.ext\t" } } */
+/* { dg-final { scan-assembler-not "andi" } } */
new file mode 100644
@@ -0,0 +1,22 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv32gc_xtheadbb" { target { rv32 } } } */
+/* { dg-options "-march=rv64gc_xtheadbb" { target { rv64 } } } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Os" "-Og" } } */
+
+struct bar
+{
+ unsigned long a:6;
+ unsigned long b:26;
+ unsigned long c:22;
+};
+
+/* We prefer andi over th.extu because it can be compressed. */
+
+unsigned long
+foo (struct bar *s)
+{
+ return s->a;
+}
+
+/* { dg-final { scan-assembler-not "th.extu\t" } } */
+/* { dg-final { scan-assembler "andi\t" } } */
new file mode 100644
@@ -0,0 +1,22 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv32gc_xtheadbb" { target { rv32 } } } */
+/* { dg-options "-march=rv64gc_xtheadbb" { target { rv64 } } } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Os" "-Og" } } */
+
+struct bar
+{
+ unsigned long a:5;
+ unsigned long b:26;
+ unsigned long c:22;
+};
+
+unsigned long
+foo (struct bar *s)
+{
+ return s->b;
+}
+
+/* { dg-final { scan-assembler "th.extu\t" } } */
+/* { dg-final { scan-assembler-not "andi" } } */
+/* { dg-final { scan-assembler-not "slli" } } */
+/* { dg-final { scan-assembler-not "srli" } } */
new file mode 100644
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv32gc_xtheadbb" { target { rv32 } } } */
+/* { dg-options "-march=rv64gc_xtheadbb" { target { rv64 } } } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Os" "-Og" } } */
+
+int
+foo (unsigned long a)
+{
+ return __builtin_clzl (a);
+}
+
+int
+bar (unsigned long a)
+{
+ return __builtin_ctzl (a);
+}
+
+/* { dg-final { scan-assembler-times "th.ff1\t" 2 } } */
new file mode 100644
@@ -0,0 +1,45 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv32gc_xtheadbb" { target { rv32 } } } */
+/* { dg-options "-march=rv64gc_xtheadbb" { target { rv64 } } } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-O1" "-Og" } } */
+
+unsigned int
+foo32 (unsigned int x)
+{
+ return (((x << 24) & 0xff000000)
+ | ((x << 8) & 0xff0000)
+ | ((x >> 8) & 0xff00)
+ | ((x >> 24) & 0xff));
+}
+
+unsigned int
+foo32_1 (unsigned int x)
+{
+ return __builtin_bswap32 (x);
+}
+
+#if __riscv_xlen == 64
+unsigned long
+foo64 (unsigned long x)
+{
+ return (((x << 56) & 0xff00000000000000ull)
+ | ((x << 40) & 0xff000000000000ull)
+ | ((x << 24) & 0xff0000000000ull)
+ | ((x << 8) & 0xff00000000ull)
+ | ((x >> 8) & 0xff000000)
+ | ((x >> 24) & 0xff0000)
+ | ((x >> 40) & 0xff00)
+ | ((x >> 56) & 0xff));
+}
+
+unsigned long
+foo64_1 (unsigned long x)
+{
+ return __builtin_bswap64 (x);
+}
+#endif
+
+/* { dg-final { scan-assembler-times "th.rev\t" 2 { target { rv32 } } } } */
+
+/* { dg-final { scan-assembler-times "th.revw\t" 2 { target { rv64 } } } } */
+/* { dg-final { scan-assembler-times "th.rev\t" 2 { target { rv64 } } } } */
new file mode 100644
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv32gc_xtheadbb" { target { rv32 } } } */
+/* { dg-options "-march=rv64gc_xtheadbb" { target { rv64 } } } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } } */
+
+unsigned long
+foo1 (unsigned long rs1)
+{
+ unsigned sz = sizeof(unsigned long) * 8;
+ unsigned shamt = sz - 11;
+ return (rs1 << shamt) | (rs1 >> (sz - shamt));
+}
+
+unsigned int
+foo2 (unsigned int rs1)
+{
+ unsigned sz = sizeof(unsigned int) * 8;
+ unsigned shamt = sz - 11;
+ return (rs1 << shamt) | (rs1 >> (sz - shamt));
+}
+
+/* { dg-final { scan-assembler-times "th.srri\t" 2 { target { rv32 } } } } */
+
+/* { dg-final { scan-assembler-times "th.srri\t" 1 { target { rv64 } } } } */
+/* { dg-final { scan-assembler-times "th.srriw\t" 1 { target { rv64 } } } } */