]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
[RISC-V] Fix missed bext discovery
authorJeff Law <jlaw@ventanamicro.com>
Fri, 18 Apr 2025 18:19:30 +0000 (12:19 -0600)
committerJeff Law <jlaw@ventanamicro.com>
Fri, 18 Apr 2025 18:21:23 +0000 (12:21 -0600)
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

gcc/config/riscv/bitmanip.md
gcc/testsuite/gcc.target/riscv/bext-ext-2.c [new file with mode: 0644]

index 5ed5e18cb36a898000ef888eb3a7303ae75f7a0b..2a3884cfde015cbfd2e5b263dab21a1f2939d69d 100644 (file)
   "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 (file)
index 0000000..aa170d0
--- /dev/null
@@ -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"} } */
+