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"} } */
+

Reply via email to