From: Jim Wilson <j...@sifive.com> 2021-09-23 Jim Wilson <j...@sifive.com> Kito Cheng <kito.ch...@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 cost model for zbb extension. (riscv_output_move): Handle bseti. (riscv_print_operand): Handle new operand type: T and S. * config/riscv/riscv.h (SINGLE_BIT_MASK_OPERAND): New. 2021-09-23 Jia-Wei Chen <jia...@iscas.ac.cn> Shi-Hua Liao <shi...@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.ch...@sifive.com> Co-authored-by: Jia-Wei Chen <jia...@iscas.ac.cn> Co-authored-by: Shi-Hua Liao <shi...@iscas.ac.cn> --- gcc/config/riscv/bitmanip.md | 102 ++++++++++++++++++++ gcc/config/riscv/predicates.md | 22 +++++ gcc/config/riscv/riscv.c | 35 ++++++- gcc/config/riscv/riscv.h | 8 ++ gcc/testsuite/gcc.target/riscv/zba-slliuw.c | 4 +- gcc/testsuite/gcc.target/riscv/zbs-bclr.c | 20 ++++ gcc/testsuite/gcc.target/riscv/zbs-bext.c | 20 ++++ gcc/testsuite/gcc.target/riscv/zbs-binv.c | 20 ++++ gcc/testsuite/gcc.target/riscv/zbs-bset.c | 41 ++++++++ 9 files changed, 268 insertions(+), 4 deletions(-) create mode 100644 gcc/testsuite/gcc.target/riscv/zbs-bclr.c create mode 100644 gcc/testsuite/gcc.target/riscv/zbs-bext.c create mode 100644 gcc/testsuite/gcc.target/riscv/zbs-binv.c create mode 100644 gcc/testsuite/gcc.target/riscv/zbs-bset.c diff --git a/gcc/config/riscv/bitmanip.md b/gcc/config/riscv/bitmanip.md index 4d624514049..59779b48f27 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 23211513554..3da6fd4c049 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 66daebbbc8f..77981d8e818 100644 --- a/gcc/config/riscv/riscv.c +++ b/gcc/config/riscv/riscv.c @@ -409,6 +409,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 @@ -2219,7 +2226,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"; @@ -3560,7 +3577,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) @@ -3600,6 +3619,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 f47d5b40a66..64287124735 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 50399f68e08..a7a3dc77d53 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 00000000000..4a3c2f1cdaf --- /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 00000000000..a093cdc8d1e --- /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 00000000000..e4e48b9cdfd --- /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 00000000000..733d4279d3a --- /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" } } */ -- 2.33.0