diff --git a/gcc/config/riscv/bitmanip.md b/gcc/config/riscv/bitmanip.md index 8769a6b818b..7e716d2d076 100644 --- a/gcc/config/riscv/bitmanip.md +++ b/gcc/config/riscv/bitmanip.md @@ -754,6 +754,18 @@ "operands[1] = gen_lowpart (word_mode, operands[1]);" [(set_attr "type" "bitmanip")]) +;; The logical-and against 0x1 implicitly extends the result. So we can treat +;; an SImode bext as-if it's DImode without any explicit extension. +(define_insn "*bextdisi" + [(set (match_operand:DI 0 "register_operand" "=r") + (and:DI (subreg:DI (lshiftrt:SI + (match_operand:SI 1 "register_operand" "r") + (match_operand:QI 2 "register_operand" "r")) 0) + (const_int 1)))] + "TARGET_64BIT && TARGET_ZBS" + "bext\t%0,%1,%2" + [(set_attr "type" "bitmanip")]) + ;; When performing `(a & (1UL << bitno)) ? 0 : -1` the combiner ;; usually has the `bitno` typed as X-mode (i.e. no further ;; zero-extension is performed around the bitno). diff --git a/gcc/testsuite/gcc.target/riscv/bext-ext.c b/gcc/testsuite/gcc.target/riscv/bext-ext.c new file mode 100644 index 00000000000..eeef07d7013 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/bext-ext.c @@ -0,0 +1,27 @@ +/* { 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 bext1 (int dst, const uint32_t i) +{ + uint64_t checks = 1U; + checks &= dst >> i; + return checks; +} + +int bext2 (int dst, int i_denom) +{ + dst = 1 & (dst >> i_denom); + return dst; +} + +const uint32_t bext3 (uint32_t bit_count, uint32_t symbol) +{ + return (symbol >> bit_count) & 1; +} + +/* { dg-final { scan-assembler-times "bext\t" 3 } } */ +/* { dg-final { scan-assembler-not "sllw\t"} } */ +/* { dg-final { scan-assembler-not "srlw\t"} } */