diff options
author | Jim Wilson <jimw@sifive.com> | 2021-09-02 00:28:47 +0800 |
---|---|---|
committer | Kito Cheng <kito.cheng@sifive.com> | 2021-10-25 17:10:02 +0800 |
commit | 4e1e0d79ecbe8727cb69d4cd97b20c71caaefafc (patch) | |
tree | 0f9b7cfd844b35eaad60a3d4f16fa99f81941296 | |
parent | 26d2818bb73a09622f87df53d6280d18b229bcbc (diff) | |
download | gcc-4e1e0d79ecbe8727cb69d4cd97b20c71caaefafc.zip gcc-4e1e0d79ecbe8727cb69d4cd97b20c71caaefafc.tar.gz gcc-4e1e0d79ecbe8727cb69d4cd97b20c71caaefafc.tar.bz2 |
RISC-V: Implement instruction patterns for ZBS extension.
2021-10-25 Jim Wilson <jimw@sifive.com>
Kito Cheng <kito.cheng@sifive.com>
gcc/ChangeLog:
* config/riscv/bitmanip.md (shiftm1): New.
(*bset<mode>): Ditto.
(*bset<mode>_mask): Ditto.
(*bset<mode>_1): Ditto.
(*bset<mode>_1_mask): Ditto.
(*bseti<mode>): Ditto.
(*bclr<mode>): Ditto.
(*bclri<mode>): Ditto.
(*binv<mode>): Ditto.
(*binvi<mode>): Ditto.
(*bext<mode>): Ditto.
(*bexti): Ditto.
* config/riscv/predicates.md (splittable_const_int_operand):
Handle bseti.
(single_bit_mask_operand): New.
(not_single_bit_mask_operand): Ditto.
(const31_operand): Ditto.
(const63_operand): Ditto.
* config/riscv/riscv.c (riscv_build_integer_1): Handle bseti.
(riscv_output_move): Ditto.
(riscv_print_operand): Handle new operand type: T and S.
* config/riscv/riscv.h (SINGLE_BIT_MASK_OPERAND): New.
2021-10-25 Jia-Wei Chen <jiawei@iscas.ac.cn>
Shi-Hua Liao <shihua@iscas.ac.cn>
gcc/testsuite/ChangeLog:
* gcc.target/riscv/zba-slliuw.c: Apply zbs to this testcase.
* gcc.target/riscv/zbs-bclr.c: New.
* gcc.target/riscv/zbs-bext.c: Ditto.
* gcc.target/riscv/zbs-binv.c: Ditto.
* gcc.target/riscv/zbs-bset.c: Ditto.
Co-authored-by: Kito Cheng <kito.cheng@sifive.com>
Co-authored-by: Jia-Wei Chen <jiawei@iscas.ac.cn>
Co-authored-by: Shi-Hua Liao <shihua@iscas.ac.cn>
-rw-r--r-- | gcc/config/riscv/bitmanip.md | 102 | ||||
-rw-r--r-- | gcc/config/riscv/predicates.md | 22 | ||||
-rw-r--r-- | gcc/config/riscv/riscv.c | 35 | ||||
-rw-r--r-- | gcc/config/riscv/riscv.h | 8 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/riscv/zba-slliuw.c | 4 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/riscv/zbs-bclr.c | 20 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/riscv/zbs-bext.c | 20 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/riscv/zbs-binv.c | 20 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/riscv/zbs-bset.c | 41 |
9 files changed, 268 insertions, 4 deletions
diff --git a/gcc/config/riscv/bitmanip.md b/gcc/config/riscv/bitmanip.md index 4d62451..59779b4 100644 --- a/gcc/config/riscv/bitmanip.md +++ b/gcc/config/riscv/bitmanip.md @@ -40,6 +40,7 @@ (ctz "ctz") (popcount "cpop")]) +(define_mode_attr shiftm1 [(SI "const31_operand") (DI "const63_operand")]) ;; ZBA extension. @@ -238,3 +239,104 @@ "TARGET_ZBB" "<bitmanip_insn>\t%0,%1,%2" [(set_attr "type" "bitmanip")]) + +;; ZBS extension. + +(define_insn "*bset<mode>" + [(set (match_operand:X 0 "register_operand" "=r") + (ior:X (ashift:X (const_int 1) + (match_operand:QI 2 "register_operand" "r")) + (match_operand:X 1 "register_operand" "r")))] + "TARGET_ZBS" + "bset\t%0,%1,%2" + [(set_attr "type" "bitmanip")]) + +(define_insn "*bset<mode>_mask" + [(set (match_operand:X 0 "register_operand" "=r") + (ior:X (ashift:X (const_int 1) + (subreg:QI + (and:X (match_operand:X 2 "register_operand" "r") + (match_operand 3 "<X:shiftm1>" "i")) 0)) + (match_operand:X 1 "register_operand" "r")))] + "TARGET_ZBS" + "bset\t%0,%1,%2" + [(set_attr "type" "bitmanip")]) + +(define_insn "*bset<mode>_1" + [(set (match_operand:X 0 "register_operand" "=r") + (ashift:X (const_int 1) + (match_operand:QI 1 "register_operand" "r")))] + "TARGET_ZBS" + "bset\t%0,x0,%1" + [(set_attr "type" "bitmanip")]) + +(define_insn "*bset<mode>_1_mask" + [(set (match_operand:X 0 "register_operand" "=r") + (ashift:X (const_int 1) + (subreg:QI + (and:X (match_operand:X 1 "register_operand" "r") + (match_operand 2 "<X:shiftm1>" "i")) 0)))] + "TARGET_ZBS" + "bset\t%0,x0,%1" + [(set_attr "type" "bitmanip")]) + +(define_insn "*bseti<mode>" + [(set (match_operand:X 0 "register_operand" "=r") + (ior:X (match_operand:X 1 "register_operand" "r") + (match_operand 2 "single_bit_mask_operand" "i")))] + "TARGET_ZBS" + "bseti\t%0,%1,%S2" + [(set_attr "type" "bitmanip")]) + +(define_insn "*bclr<mode>" + [(set (match_operand:X 0 "register_operand" "=r") + (and:X (rotate:X (const_int -2) + (match_operand:QI 2 "register_operand" "r")) + (match_operand:X 1 "register_operand" "r")))] + "TARGET_ZBS" + "bclr\t%0,%1,%2" + [(set_attr "type" "bitmanip")]) + +(define_insn "*bclri<mode>" + [(set (match_operand:X 0 "register_operand" "=r") + (and:X (match_operand:X 1 "register_operand" "r") + (match_operand 2 "not_single_bit_mask_operand" "i")))] + "TARGET_ZBS" + "bclri\t%0,%1,%T2" + [(set_attr "type" "bitmanip")]) + +(define_insn "*binv<mode>" + [(set (match_operand:X 0 "register_operand" "=r") + (xor:X (ashift:X (const_int 1) + (match_operand:QI 2 "register_operand" "r")) + (match_operand:X 1 "register_operand" "r")))] + "TARGET_ZBS" + "binv\t%0,%1,%2" + [(set_attr "type" "bitmanip")]) + +(define_insn "*binvi<mode>" + [(set (match_operand:X 0 "register_operand" "=r") + (xor:X (match_operand:X 1 "register_operand" "r") + (match_operand 2 "single_bit_mask_operand" "i")))] + "TARGET_ZBS" + "binvi\t%0,%1,%S2" + [(set_attr "type" "bitmanip")]) + +(define_insn "*bext<mode>" + [(set (match_operand:X 0 "register_operand" "=r") + (zero_extract:X (match_operand:X 1 "register_operand" "r") + (const_int 1) + (zero_extend:X + (match_operand:QI 2 "register_operand" "r"))))] + "TARGET_ZBS" + "bext\t%0,%1,%2" + [(set_attr "type" "bitmanip")]) + +(define_insn "*bexti" + [(set (match_operand:X 0 "register_operand" "=r") + (zero_extract:X (match_operand:X 1 "register_operand" "r") + (const_int 1) + (match_operand 2 "immediate_operand" "i")))] + "TARGET_ZBS" + "bexti\t%0,%1,%2" + [(set_attr "type" "bitmanip")]) diff --git a/gcc/config/riscv/predicates.md b/gcc/config/riscv/predicates.md index 2321151..3da6fd4 100644 --- a/gcc/config/riscv/predicates.md +++ b/gcc/config/riscv/predicates.md @@ -74,6 +74,11 @@ if (GET_MODE_SIZE (mode) > UNITS_PER_WORD) return false; + /* Check whether the constant can be loaded in a single + instruction with zbs extensions. */ + if (TARGET_64BIT && TARGET_ZBS && SINGLE_BIT_MASK_OPERAND (INTVAL (op))) + return false; + /* Otherwise check whether the constant can be loaded in a single instruction. */ return !LUI_OPERAND (INTVAL (op)) && !SMALL_OPERAND (INTVAL (op)); @@ -217,3 +222,20 @@ { return riscv_gpr_save_operation_p (op); }) + +;; Predicates for the ZBS extension. +(define_predicate "single_bit_mask_operand" + (and (match_code "const_int") + (match_test "pow2p_hwi (INTVAL (op))"))) + +(define_predicate "not_single_bit_mask_operand" + (and (match_code "const_int") + (match_test "pow2p_hwi (~INTVAL (op))"))) + +(define_predicate "const31_operand" + (and (match_code "const_int") + (match_test "INTVAL (op) == 31"))) + +(define_predicate "const63_operand" + (and (match_code "const_int") + (match_test "INTVAL (op) == 63"))) diff --git a/gcc/config/riscv/riscv.c b/gcc/config/riscv/riscv.c index 3ed34f2..3943eb4 100644 --- a/gcc/config/riscv/riscv.c +++ b/gcc/config/riscv/riscv.c @@ -410,6 +410,13 @@ riscv_build_integer_1 (struct riscv_integer_op codes[RISCV_MAX_INTEGER_OPS], codes[0].value = value; return 1; } + if (TARGET_ZBS && SINGLE_BIT_MASK_OPERAND (value)) + { + /* Simply BSETI. */ + codes[0].code = UNKNOWN; + codes[0].value = value; + return 1; + } /* End with ADDI. When constructing HImode constants, do not generate any intermediate value that is not itself a valid HImode constant. The @@ -2220,7 +2227,17 @@ riscv_output_move (rtx dest, rtx src) } if (src_code == CONST_INT) - return "li\t%0,%1"; + { + if (SMALL_OPERAND (INTVAL (src)) || LUI_OPERAND (INTVAL (src))) + return "li\t%0,%1"; + + if (TARGET_ZBS + && SINGLE_BIT_MASK_OPERAND (INTVAL (src))) + return "bseti\t%0,zero,%S1"; + + /* Should never reach here. */ + abort (); + } if (src_code == HIGH) return "lui\t%0,%h1"; @@ -3561,7 +3578,9 @@ riscv_memmodel_needs_release_fence (enum memmodel model) 'A' Print the atomic operation suffix for memory model OP. 'F' Print a FENCE if the memory model requires a release. 'z' Print x0 if OP is zero, otherwise print OP normally. - 'i' Print i if the operand is not a register. */ + 'i' Print i if the operand is not a register. + 'S' Print shift-index of single-bit mask OP. + 'T' Print shift-index of inverted single-bit mask OP. */ static void riscv_print_operand (FILE *file, rtx op, int letter) @@ -3601,6 +3620,18 @@ riscv_print_operand (FILE *file, rtx op, int letter) fputs ("i", file); break; + case 'S': + { + rtx newop = GEN_INT (ctz_hwi (INTVAL (op))); + output_addr_const (file, newop); + break; + } + case 'T': + { + rtx newop = GEN_INT (ctz_hwi (~INTVAL (op))); + output_addr_const (file, newop); + break; + } default: switch (code) { diff --git a/gcc/config/riscv/riscv.h b/gcc/config/riscv/riscv.h index f47d5b4..6428712 100644 --- a/gcc/config/riscv/riscv.h +++ b/gcc/config/riscv/riscv.h @@ -526,6 +526,14 @@ enum reg_class (((VALUE) | ((1UL<<31) - IMM_REACH)) == ((1UL<<31) - IMM_REACH) \ || ((VALUE) | ((1UL<<31) - IMM_REACH)) + IMM_REACH == 0) +/* If this is a single bit mask, then we can load it with bseti. But this + is not useful for any of the low 31 bits because we can use addi or lui + to load them. It is wrong for loading SImode 0x80000000 on rv64 because it + needs to be sign-extended. So we restrict this to the upper 32-bits + only. */ +#define SINGLE_BIT_MASK_OPERAND(VALUE) \ + (pow2p_hwi (VALUE) && (ctz_hwi (VALUE) >= 32)) + /* Stack layout; function entry, exit and calling. */ #define STACK_GROWS_DOWNWARD 1 diff --git a/gcc/testsuite/gcc.target/riscv/zba-slliuw.c b/gcc/testsuite/gcc.target/riscv/zba-slliuw.c index 50399f6..a7a3dc7 100644 --- a/gcc/testsuite/gcc.target/riscv/zba-slliuw.c +++ b/gcc/testsuite/gcc.target/riscv/zba-slliuw.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-march=rv64gc_zba -mabi=lp64 -O2" } */ +/* { dg-options "-march=rv64gc_zba_zbs -mabi=lp64 -O2" } */ long foo (long i) @@ -8,4 +8,4 @@ foo (long i) } /* XXX: This pattern need combine improvement or intermediate instruction * from zbs. */ -/* { dg-final { scan-assembler-not "slli.uw" } } */ +/* { dg-final { scan-assembler "slli.uw" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/zbs-bclr.c b/gcc/testsuite/gcc.target/riscv/zbs-bclr.c new file mode 100644 index 0000000..4a3c2f1 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/zbs-bclr.c @@ -0,0 +1,20 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gc_zbs -mabi=lp64 -O2" } */ + +/* bclr */ +long +foo0 (long i, long j) +{ + return i & ~(1L << j); +} + +/* bclri */ +long +foo1 (long i) +{ + return i & ~(1L << 20); +} + +/* { dg-final { scan-assembler-times "bclr\t" 1 } } */ +/* { dg-final { scan-assembler-times "bclri\t" 1 } } */ +/* { dg-final { scan-assembler-not "andi" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/zbs-bext.c b/gcc/testsuite/gcc.target/riscv/zbs-bext.c new file mode 100644 index 0000000..a093cdc --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/zbs-bext.c @@ -0,0 +1,20 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gc_zbs -mabi=lp64 -O2" } */ + +/* bext */ +long +foo0 (long i, long j) +{ + return 1L & (i >> j); +} + +/* bexti */ +long +foo1 (long i) +{ + return 1L & (i >> 20); +} + +/* { dg-final { scan-assembler-times "bexti\t" 1 } } */ +/* { dg-final { scan-assembler-times "bext\t" 1 } } */ +/* { dg-final { scan-assembler-not "andi" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/zbs-binv.c b/gcc/testsuite/gcc.target/riscv/zbs-binv.c new file mode 100644 index 0000000..e4e48b9 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/zbs-binv.c @@ -0,0 +1,20 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gc_zbs -mabi=lp64 -O2" } */ + +/* binv */ +long +foo0 (long i, long j) +{ + return i ^ (1L << j); +} + +/* binvi */ +long +foo1 (long i) +{ + return i ^ (1L << 20); +} + +/* { dg-final { scan-assembler-times "binv\t" 1 } } */ +/* { dg-final { scan-assembler-times "binvi\t" 1 } } */ +/* { dg-final { scan-assembler-not "andi" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/zbs-bset.c b/gcc/testsuite/gcc.target/riscv/zbs-bset.c new file mode 100644 index 0000000..733d427 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/zbs-bset.c @@ -0,0 +1,41 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gc_zbs -mabi=lp64 -O2" } */ + +/* bset */ +long +sub0 (long i, long j) +{ + return i | (1L << j); +} + +/* bset_mask */ +long +sub1 (long i, long j) +{ + return i | (1L << (j & 0x3f)); +} + +/* bset_1 */ +long +sub2 (long i) +{ + return 1L << i; +} + +/* bset_1_mask */ +long +sub3 (long i) +{ + return 1L << (i & 0x3f); +} + +/* bseti */ +long +sub4 (long i) +{ + return i | (1L << 20); +} + +/* { dg-final { scan-assembler-times "bset\t" 4 } } */ +/* { dg-final { scan-assembler-times "bseti\t" 1 } } */ +/* { dg-final { scan-assembler-not "andi" } } */ |