https://gcc.gnu.org/g:45a1038f3ca6ddceb8d159ccba6d99ed61951472
commit r16-28-g45a1038f3ca6ddceb8d159ccba6d99ed61951472 Author: Jeff Law <j...@ventanamicro.com> Date: Fri Apr 18 12:19:30 2025 -0600 [RISC-V] Fix missed bext discovery RISC-V has the ability to extract a single bit out of a register from a fixed or variable position. While looking at 502.gcc a little while ago I realize that we failed to use bext inside bitmap_bit_p for its return value. The core "problem" is that the RISC-V does not define SHIFT_COUNT_TRUNCATED (for good reasons). As a result the target is largely responsible for handling elimination of shift count/bit position masking. There's a follow-up patch I've been working on with an intern to improve detection of bext in more cases. This one stands independently though and is probably the most important of the missed cases. Will push to the trunk assuming pre-commit testing is green. It's already been through my tester as well as Ventana's internal testing. gcc * config/riscv/bitmanip.md (*bext<mode>_mask_pos): New pattern for extracting a single bit at masked bit position. gcc/testsuite * gcc.target/riscv/bext-ext-2.c: New test Diff: --- gcc/config/riscv/bitmanip.md | 18 +++++++ gcc/testsuite/gcc.target/riscv/bext-ext-2.c | 74 +++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+) diff --git a/gcc/config/riscv/bitmanip.md b/gcc/config/riscv/bitmanip.md index 5ed5e18cb36a..2a3884cfde01 100644 --- a/gcc/config/riscv/bitmanip.md +++ b/gcc/config/riscv/bitmanip.md @@ -908,6 +908,24 @@ "bext\t%0,%1,%2" [(set_attr "type" "bitmanip")]) +;; We do not define SHIFT_COUNT_TRUNCATED, so we have to have variants +;; that mask/extend the count if we want to eliminate those ops +;; +;; We could (in theory) use GPR for the various modes, but I haven't +;; seen those cases appear in practice. Without a testcase I've +;; elected to keep the modes X which is easy to reason about. +(define_insn "*bext<mode>_mask_pos" + [(set (match_operand:X 0 "register_operand" "=r") + (zero_extract:X (match_operand:X 1 "register_operand" "r") + (const_int 1) + (and:X + (match_operand:X 2 "register_operand" "r") + (match_operand 3 "const_int_operand"))))] + "(TARGET_ZBS + && INTVAL (operands[3]) + 1 == GET_MODE_BITSIZE (<MODE>mode))" + "bext\t%0,%1,%2" + [(set_attr "type" "bitmanip")]) + ;; This is a bext followed by a seqz. Normally this would be a 3->2 split ;; But the and-not pattern with a constant operand is a define_insn_and_split, ;; so this looks like a 2->2 split, which combine rejects. So implement it diff --git a/gcc/testsuite/gcc.target/riscv/bext-ext-2.c b/gcc/testsuite/gcc.target/riscv/bext-ext-2.c new file mode 100644 index 000000000000..aa170d06d0e7 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/bext-ext-2.c @@ -0,0 +1,74 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcb -mabi=lp64" } */ +/* { dg-skip-if "" { *-*-* } { "-O0" } } */ + +struct obstack; +struct bitmap_head_def; +typedef struct bitmap_head_def *bitmap; +struct obstack +{ + long chunk_size; + struct _obstack_chunk *chunk; + char *object_base; + char *next_free; + char *chunk_limit; + long int temp; + int alignment_mask; + + + + struct _obstack_chunk *(*chunkfun) (void *, long); + void (*freefun) (void *, struct _obstack_chunk *); + void *extra_arg; + unsigned use_extra_arg:1; + unsigned maybe_empty_object:1; + + + + unsigned alloc_failed:1; + + +}; + +typedef unsigned long BITMAP_WORD; +typedef struct bitmap_obstack { + struct bitmap_element_def *elements; + struct bitmap_head_def *heads; + struct obstack obstack; +} bitmap_obstack; +typedef struct bitmap_element_def { + struct bitmap_element_def *next; + struct bitmap_element_def *prev; + unsigned int indx; + BITMAP_WORD bits[((128 + (8 + * 8 * 1u) - 1) / (8 + * 8 * 1u))]; +} bitmap_element; +bitmap_element *bitmap_find_bit (bitmap, unsigned int); + + +int +bitmap_bit_p (bitmap head, int bit) +{ + bitmap_element *ptr; + unsigned bit_num; + unsigned word_num; + + ptr = bitmap_find_bit (head, bit); + if (ptr == 0) + return 0; + + bit_num = bit % (8 + * 8 * 1u); + word_num = bit / (8 + * 8 * 1u) % ((128 + (8 + * 8 * 1u) - 1) / (8 + * 8 * 1u)); + + return (ptr->bits[word_num] >> bit_num) & 1; +} + +/* { dg-final { scan-assembler-times "bext\t" 1 } } */ +/* { dg-final { scan-assembler-not "slr\t"} } */ +/* { dg-final { scan-assembler-not "andi\t"} } */ +