diff --git a/gcc/config/riscv/bitmanip.md b/gcc/config/riscv/bitmanip.md index 7e716d2d076..4ee413c143e 100644 --- a/gcc/config/riscv/bitmanip.md +++ b/gcc/config/riscv/bitmanip.md @@ -684,6 +684,23 @@ } [(set_attr "type" "bitmanip")]) +;; An outer AND with a constant where bits 31..63 are 0 can be seen as +;; a virtual zero extension from 31 to 64 bits. +(define_split + [(set (match_operand:DI 0 "register_operand") + (and:DI (not:DI (subreg:DI + (ashift:SI (const_int 1) + (match_operand:QI 1 "register_operand")) 0)) + (match_operand:DI 2 "arith_operand"))) + (clobber (match_operand:DI 3 "register_operand"))] + "TARGET_64BIT && TARGET_ZBS + && clz_hwi (INTVAL (operands[2])) >= 33" + [(set (match_dup 3) + (match_dup 2)) + (set (match_dup 0) + (and:DI (rotate:DI (const_int -2) (match_dup 1)) + (match_dup 3)))]) + (define_insn "*binv" [(set (match_operand:X 0 "register_operand" "=r") (xor:X (ashift:X (const_int 1) diff --git a/gcc/testsuite/gcc.target/riscv/zbs-ext.c b/gcc/testsuite/gcc.target/riscv/zbs-ext.c new file mode 100644 index 00000000000..65f42545b5f --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/zbs-ext.c @@ -0,0 +1,15 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gc_zbs -mabi=lp64" } */ +/* { dg-skip-if "" { *-*-* } { "-O0" "-Og" "-O1" } } */ +typedef unsigned long uint64_t; +typedef unsigned int uint32_t; + +uint64_t bclr (const uint32_t i) +{ + uint64_t checks = 10; + checks &= ~(1U << i); + return checks; +} + +/* { dg-final { scan-assembler-times "bclr\t" 1 } } */ +/* { dg-final { scan-assembler-not "sllw\t"} } */