aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeff Law <jlaw@ventanamicro.com>2025-04-18 12:19:30 -0600
committerJeff Law <jlaw@ventanamicro.com>2025-04-18 12:21:23 -0600
commit45a1038f3ca6ddceb8d159ccba6d99ed61951472 (patch)
treee696df4f328b8894b91d1bb4dc96b2cef962d1ba
parentb986ed16c2546674256b8c892541a8fdb6a97202 (diff)
downloadgcc-45a1038f3ca6ddceb8d159ccba6d99ed61951472.zip
gcc-45a1038f3ca6ddceb8d159ccba6d99ed61951472.tar.gz
gcc-45a1038f3ca6ddceb8d159ccba6d99ed61951472.tar.bz2
[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
-rw-r--r--gcc/config/riscv/bitmanip.md18
-rw-r--r--gcc/testsuite/gcc.target/riscv/bext-ext-2.c74
2 files changed, 92 insertions, 0 deletions
diff --git a/gcc/config/riscv/bitmanip.md b/gcc/config/riscv/bitmanip.md
index 5ed5e18..2a3884c 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 0000000..aa170d0
--- /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"} } */
+