Add a split for cases where we can use two bclri (or one bclri and an andi) to clear two bits.
gcc/ChangeLog: * config/riscv/bitmanip.md (*bclri<mode>_nottwobits): New pattern. (*bclridisi_nottwobits): New pattern, handling the sign-bit. * config/riscv/predicates.md (const_nottwobits_operand): New predicate. gcc/testsuite/ChangeLog: * gcc.target/riscv/zbs-bclri.c: New test. Signed-off-by: Philipp Tomsich <philipp.toms...@vrull.eu> --- gcc/config/riscv/bitmanip.md | 38 ++++++++++++++++++++++ gcc/config/riscv/predicates.md | 5 +++ gcc/testsuite/gcc.target/riscv/zbs-bclri.c | 12 +++++++ 3 files changed, 55 insertions(+) create mode 100644 gcc/testsuite/gcc.target/riscv/zbs-bclri.c diff --git a/gcc/config/riscv/bitmanip.md b/gcc/config/riscv/bitmanip.md index 7fa8461bb71..f1d8f24c2d3 100644 --- a/gcc/config/riscv/bitmanip.md +++ b/gcc/config/riscv/bitmanip.md @@ -560,6 +560,44 @@ "bclri\t%0,%1,%T2" [(set_attr "type" "bitmanip")]) +;; In case we have "val & ~IMM" where ~IMM has 2 bits set. +(define_insn_and_split "*bclri<mode>_nottwobits" + [(set (match_operand:X 0 "register_operand" "=r") + (and:X (match_operand:X 1 "register_operand" "r") + (match_operand:X 2 "const_nottwobits_operand" "i")))] + "TARGET_ZBS && !paradoxical_subreg_p (operands[1])" + "#" + "&& reload_completed" + [(set (match_dup 0) (and:X (match_dup 1) (match_dup 3))) + (set (match_dup 0) (and:X (match_dup 0) (match_dup 4)))] +{ + unsigned HOST_WIDE_INT bits = ~UINTVAL (operands[2]); + unsigned HOST_WIDE_INT topbit = HOST_WIDE_INT_1U << floor_log2 (bits); + + operands[3] = GEN_INT (~bits | topbit); + operands[4] = GEN_INT (~topbit); +}) + +;; In case of a paradoxical subreg, the sign bit and the high bits are +;; not allowed to be changed +(define_insn_and_split "*bclridisi_nottwobits" + [(set (match_operand:DI 0 "register_operand" "=r") + (and:DI (match_operand:DI 1 "register_operand" "r") + (match_operand:DI 2 "const_nottwobits_operand" "i")))] + "TARGET_64BIT && TARGET_ZBS + && clz_hwi (~UINTVAL (operands[2])) > 33" + "#" + "&& reload_completed" + [(set (match_dup 0) (and:DI (match_dup 1) (match_dup 3))) + (set (match_dup 0) (and:DI (match_dup 0) (match_dup 4)))] +{ + unsigned HOST_WIDE_INT bits = ~UINTVAL (operands[2]); + unsigned HOST_WIDE_INT topbit = HOST_WIDE_INT_1U << floor_log2 (bits); + + operands[3] = GEN_INT (~bits | topbit); + operands[4] = GEN_INT (~topbit); +}) + (define_insn "*binv<mode>" [(set (match_operand:X 0 "register_operand" "=r") (xor:X (ashift:X (const_int 1) diff --git a/gcc/config/riscv/predicates.md b/gcc/config/riscv/predicates.md index 6de9b39e39b..b368c11c930 100644 --- a/gcc/config/riscv/predicates.md +++ b/gcc/config/riscv/predicates.md @@ -304,6 +304,11 @@ (match_test "ctz_hwi (INTVAL (op)) > 0") (match_test "SMALL_OPERAND (INTVAL (op) >> ctz_hwi (INTVAL (op)))"))) +;; A CONST_INT operand that has exactly two bits cleared. +(define_predicate "const_nottwobits_operand" + (and (match_code "const_int") + (match_test "popcount_hwi (~UINTVAL (op)) == 2"))) + ;; A CONST_INT operand that fits into the unsigned half of a ;; signed-immediate after the top bit has been cleared. (define_predicate "uimm_extra_bit_operand" diff --git a/gcc/testsuite/gcc.target/riscv/zbs-bclri.c b/gcc/testsuite/gcc.target/riscv/zbs-bclri.c new file mode 100644 index 00000000000..12e2063436c --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/zbs-bclri.c @@ -0,0 +1,12 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gc_zbs -mabi=lp64" } */ +/* { dg-skip-if "" { *-*-* } { "-O0" "-Og" } } */ + +/* bclri + bclri */ +long long f5 (long long a) +{ + return a & ~0x11000; +} + +/* { dg-final { scan-assembler-times "bclri\t" 2 } } */ + -- 2.34.1