[gcc r17-2512] [PR target/123883] Inefficient bit manipulation code on RISC-V port

Jeff Law via Gcc-cvs <[email protected]>
Newsgroups gmane.comp.gcc.cvs
Message-ID <[email protected]>
https://gcc.gnu.org/g:c348f5c5e991dd9d4e13d5943485a938cc4342a8

commit r17-2512-gc348f5c5e991dd9d4e13d5943485a938cc4342a8
Author: Dusan Stojkovic <[email protected]>
Date:   Sat Jul 18 10:38:41 2026 -0600

    [PR target/123883] Inefficient bit manipulation code on RISC-V port
    
    With changes to the RISC-V backend, it's possible to get the desired code
    generation for this test with a simple match.pd pattern.
    
    Essentially we have (1 << N) & (1 << N) where each shift is in a different
    type.  With some constraints, we can collapse that down to just (1 << N) in
    the wider type.  That in turn allows collapsing the entire sequence down to
    a single bit set (6 instructions -> 3 instructions on rv64gcb).
    
            PR target/123883
    
    gcc/ChangeLog:
    
            * match.pd ((1<<N) & (1<<N) with different types): New
            pattern.
    
    gcc/testsuite/ChangeLog:
    
            * gcc.target/riscv/pr123883-a.c: New test.
            * gcc.target/riscv/pr123883-b.c: New test.

Diff:
---
 gcc/match.pd                                | 21 ++++++++++
 gcc/testsuite/gcc.target/riscv/pr123883-a.c | 59 +++++++++++++++++++++++++++++
 gcc/testsuite/gcc.target/riscv/pr123883-b.c | 58 ++++++++++++++++++++++++++++
 3 files changed, 138 insertions(+)

diff --git a/gcc/match.pd b/gcc/match.pd
index 07b3f72d73b3..d750438382e9 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -12545,6 +12545,27 @@ and,
         && @0 == @3)
     (bit_xor (rrotate @0 @4) @2)))
 
+
+/* (T0)(1 << x) & (T1)(1 << x) -> (T)(1 << x),
+ *  but keep the shift in the wider type to avoid introducing
+ *  undefined behaviour.  */
+(simplify
+ (bit_and:c
+  (convert? (lshift@2 integer_onep@1 @0))
+  (convert? (lshift@3 integer_onep@4 @0)))
+ (with
+  {
+    tree ltype0 = TREE_TYPE (@2);
+    tree ltype1 = TREE_TYPE (@3);
+  }
+  (if (INTEGRAL_TYPE_P (type)
+       && INTEGRAL_TYPE_P (ltype0)
+       && INTEGRAL_TYPE_P (ltype1)
+       && element_precision (type) <= element_precision (ltype0)
+       && element_precision (ltype0) <= element_precision (ltype1))
+       (convert:type
+	  (lshift:ltype1 { @4; } @0)))))
+
 /* Optimize extraction from a uniform vector to a representative element as
    long as the requested element is within range.  */
 (simplify (IFN_VEC_EXTRACT (vec_duplicate @0) INTEGER_CST@1)
diff --git a/gcc/testsuite/gcc.target/riscv/pr123883-a.c b/gcc/testsuite/gcc.target/riscv/pr123883-a.c
new file mode 100644
index 000000000000..39cc2f5ee09b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/pr123883-a.c
@@ -0,0 +1,59 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcb -mabi=lp64d" { target rv64 } } */
+/* { dg-options "-march=rv32gcb -mabi=ilp32" { target rv32 } } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-O1" "-Og" "-Os" "-Oz" } } */
+
+#define TEST_STORE_NARROW_SHIFT(TYPE, WTYPE, NAME)               \
+void                                                             \
+NAME (TYPE *data, unsigned int lo_bit)                           \
+{                                                                \
+  WTYPE mask = (((WTYPE) 1UL << 1) - 1) << lo_bit;               \
+  *data = (*data & ~mask) | ((1U << lo_bit) & mask);             \
+}
+
+#define TEST_RET_NARROW_SHIFT(TYPE, WTYPE, NAME)                 \
+TYPE                                                             \
+NAME (TYPE data, unsigned int lo_bit)                            \
+{                                                                \
+  WTYPE mask = (((WTYPE) 1 << 1) - 1) << lo_bit;                 \
+  return (data & ~mask) | ((1U << lo_bit) & mask);               \
+}
+
+/* WTYPE = unsigned int */
+TEST_STORE_NARROW_SHIFT(unsigned char,  unsigned int, store_uc_ui_narrow)
+TEST_STORE_NARROW_SHIFT(unsigned short, unsigned int, store_us_ui_narrow)
+
+TEST_RET_NARROW_SHIFT(unsigned char,    unsigned int, ret_uc_ui_narrow)
+TEST_RET_NARROW_SHIFT(unsigned short,   unsigned int, ret_us_ui_narrow)
+
+/* WTYPE = unsigned long */
+TEST_STORE_NARROW_SHIFT(unsigned char,  unsigned long, store_uc_ul_narrow)
+TEST_STORE_NARROW_SHIFT(unsigned short, unsigned long, store_us_ul_narrow)
+TEST_STORE_NARROW_SHIFT(unsigned int,   unsigned long, store_ui_ul_narrow)
+
+TEST_RET_NARROW_SHIFT(unsigned char,    unsigned long, ret_uc_ul_narrow)
+TEST_RET_NARROW_SHIFT(unsigned short,   unsigned long, ret_us_ul_narrow)
+TEST_RET_NARROW_SHIFT(unsigned int,     unsigned long, ret_ui_ul_narrow)
+
+/* WTYPE = unsigned long long */
+TEST_STORE_NARROW_SHIFT(unsigned char,  unsigned long long, store_uc_ull_narrow)
+TEST_STORE_NARROW_SHIFT(unsigned short, unsigned long long, store_us_ull_narrow)
+TEST_STORE_NARROW_SHIFT(unsigned int,   unsigned long long, store_ui_ull_narrow)
+
+TEST_RET_NARROW_SHIFT(unsigned char,    unsigned long long, ret_uc_ull_narrow)
+TEST_RET_NARROW_SHIFT(unsigned short,   unsigned long long, ret_us_ull_narrow)
+TEST_RET_NARROW_SHIFT(unsigned int,     unsigned long long, ret_ui_ull_narrow)
+
+/* { dg-final { scan-assembler-times "\\tbset\\t" 14 { target rv64 } } } */
+/* Current remaining missed SI-mode cases.  */
+/* { dg-final { scan-assembler-times "\\tsllw\\t" 4 { target rv64 } } } */
+/* { dg-final { scan-assembler-times "\\tbinv\\t" 2 { target rv64 } } } */
+/* { dg-final { scan-assembler-times "\\tsext.w\\t" 4 { target rv64 } } } */
+
+
+/* { dg-final { scan-assembler-times "\\tbset\\t" 16 { target rv32 } } } */
+/* Testcases with ULL. */
+/* { dg-final { scan-assembler-times "\\tbinv\\t" 2 { target rv32 } } } */
+/* { dg-final { scan-assembler-times "\\tand\\t" 8 { target rv32 } } } */
+/* { dg-final { scan-assembler-times "\\tsrai\\t" 6 { target rv32 } } } */
+
diff --git a/gcc/testsuite/gcc.target/riscv/pr123883-b.c b/gcc/testsuite/gcc.target/riscv/pr123883-b.c
new file mode 100644
index 000000000000..4e623764228e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/pr123883-b.c
@@ -0,0 +1,58 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcb -mabi=lp64d" { target rv64 } } */
+/* { dg-options "-march=rv32gcb -mabi=ilp32" { target rv32 } } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-O1" "-Og" "-Os" "-Oz" } } */
+
+#define TEST_STORE_NARROW_SHIFT(TYPE, WTYPE, NAME)               \
+void                                                             \
+NAME (TYPE *data, unsigned int lo_bit)                           \
+{                                                                \
+  WTYPE mask = ((1UL << 1) - 1) << lo_bit;                 	  \
+  *data = (*data & ~mask) | (((WTYPE) 1U << lo_bit) & mask);     \
+}
+
+#define TEST_RET_NARROW_SHIFT(TYPE, WTYPE, NAME)                 \
+TYPE                                                             \
+NAME (TYPE data, unsigned int lo_bit)                            \
+{                                                                \
+  WTYPE mask = ((1 << 1) - 1) << lo_bit;                         \
+  return (data & ~mask) | (((WTYPE)1U << lo_bit) & mask);        \
+}
+
+/* WTYPE = unsigned int */
+TEST_STORE_NARROW_SHIFT(unsigned char,  unsigned int, store_uc_ui_narrow)
+TEST_STORE_NARROW_SHIFT(unsigned short, unsigned int, store_us_ui_narrow)
+
+TEST_RET_NARROW_SHIFT(unsigned char,    unsigned int, ret_uc_ui_narrow)
+TEST_RET_NARROW_SHIFT(unsigned short,   unsigned int, ret_us_ui_narrow)
+
+/* WTYPE = unsigned long */
+TEST_STORE_NARROW_SHIFT(unsigned char,  unsigned long, store_uc_ul_narrow)
+TEST_STORE_NARROW_SHIFT(unsigned short, unsigned long, store_us_ul_narrow)
+TEST_STORE_NARROW_SHIFT(unsigned int,   unsigned long, store_ui_ul_narrow)
+
+TEST_RET_NARROW_SHIFT(unsigned char,    unsigned long, ret_uc_ul_narrow)
+TEST_RET_NARROW_SHIFT(unsigned short,   unsigned long, ret_us_ul_narrow)
+TEST_RET_NARROW_SHIFT(unsigned int,     unsigned long, ret_ui_ul_narrow)
+
+/* WTYPE = unsigned long long */
+TEST_STORE_NARROW_SHIFT(unsigned char,  unsigned long long, store_uc_ull_narrow)
+TEST_STORE_NARROW_SHIFT(unsigned short, unsigned long long, store_us_ull_narrow)
+TEST_STORE_NARROW_SHIFT(unsigned int,   unsigned long long, store_ui_ull_narrow)
+
+TEST_RET_NARROW_SHIFT(unsigned char,    unsigned long long, ret_uc_ull_narrow)
+TEST_RET_NARROW_SHIFT(unsigned short,   unsigned long long, ret_us_ull_narrow)
+TEST_RET_NARROW_SHIFT(unsigned int,     unsigned long long, ret_ui_ull_narrow)
+
+/* { dg-final { scan-assembler-times "\\tbset\\t" 16 { target rv64 } } } */
+/* { dg-final { scan-assembler-not "\\tsllw\\t" { target rv64 } } } */
+/* { dg-final { scan-assembler-not "\\tbinv\\t" { target rv64 } } } */
+/* { dg-final { scan-assembler-not "\\txor\\t" { target rv64 } } } */
+/* { dg-final { scan-assembler-not "\\tand\\t" { target rv64 } } } */
+
+/* { dg-final { scan-assembler-times "\\tbset\\t" 16 { target rv32 } } } */
+/* Testcases with ULL. */
+/* { dg-final { scan-assembler-times "\\tand\\t" 7 { target rv32 } } } */
+/* { dg-final { scan-assembler-times "\\tbclr\\t" 5 { target rv32 } } } */
+/* { dg-final { scan-assembler-times "\\tsrai\\t" 6 { target rv32 } } } */
+
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.