[gcc/devel/jlaw/pr123904] Use shift pair to optimize this case

Jeff Law law@gcc.gnu.org
Wed Mar 11 00:09:48 GMT 2026


https://gcc.gnu.org/g:9b642bb5353528a552bc44440769f64aba965590

commit 9b642bb5353528a552bc44440769f64aba965590
Author: Jeff Law <jeffrey.law@oss.qualcomm.com>
Date:   Tue Mar 10 16:01:44 2026 -0600

    Use shift pair to optimize this case

Diff:
---
 gcc/config/riscv/riscv.md                 | 27 +++++++++++++++++++++++++++
 gcc/testsuite/gcc.target/riscv/pr123904.c |  8 ++++++++
 2 files changed, 35 insertions(+)

diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
index 3fe0ad0ccdf4..7ffbdbbb8700 100644
--- a/gcc/config/riscv/riscv.md
+++ b/gcc/config/riscv/riscv.md
@@ -4960,6 +4960,33 @@
   { operands[3] = GEN_INT (BITS_PER_WORD
 			   - exact_log2 (INTVAL (operands[3]) + 1)); })
 
+;; This is similar using a shift triplet to implement a logical AND when
+;; the mask is a consecutive_bits_operand.
+;;
+;; The difference is we have a left shift in the input RTL and we verify
+;; that clears the appropriate low bits.  So we can get away with just
+;; two shifts.
+(define_split
+  [(set (match_operand:X 0 "register_operand")
+	(and:X (ashift:X (match_operand:X 1 "register_operand")
+			 (match_operand 2 "const_int_operand"))
+		(match_operand 3 "consecutive_bits_operand")))
+   (clobber (match_operand:X 4 "register_operand"))]
+  "ctz_hwi (INTVAL (operands[3]) & GET_MODE_MASK (word_mode)) == INTVAL (operands[2])"
+  [(set (match_dup 4) (ashift:X (match_dup 1) (match_dup 5)))
+   (set (match_dup 0) (lshiftrt:X (match_dup 4) (match_dup 6)))]
+"{
+  /* We want to left shift by the number of leading zeros in the mask,
+     plus the number of bits shifted left by the pattern.  */
+  HOST_WIDE_INT lshift
+    = clz_hwi (UINTVAL (operands[3])) % BITS_PER_WORD + INTVAL (operands[2]);
+  operands[5] = gen_int_mode (lshift, QImode);
+
+  /* And then we right shift things back into position.  */
+  HOST_WIDE_INT rshift = lshift - INTVAL (operands[2]);
+  operands[6] = gen_int_mode (rshift, QImode);
+}")
+
 ;; Standard extensions and pattern for optimization
 (include "bitmanip.md")
 (include "crypto.md")
diff --git a/gcc/testsuite/gcc.target/riscv/pr123904.c b/gcc/testsuite/gcc.target/riscv/pr123904.c
new file mode 100644
index 000000000000..7181c8de46f3
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/pr123904.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Og" } } */
+
+unsigned foo19(unsigned a, unsigned b) { b = (b << 2) >> 2; return a + (b << 1); }
+
+/* { dg-final { scan-assembler-times "slli" 1 } } */
+/* { dg-final { scan-assembler-times "srli" 1 } } */
+/* { dg-final { scan-assembler-times "add" 1 } } */


More information about the Gcc-cvs mailing list