]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
[V3][RISC-V][PR target/124760] Promote SI to DI in some cases to encourage shNadd...
authorJeff Law <jeffrey.law@oss.qualcomm.com>
Tue, 28 Apr 2026 22:55:13 +0000 (16:55 -0600)
committerJeff Law <jeffrey.law@oss.qualcomm.com>
Tue, 28 Apr 2026 22:55:13 +0000 (16:55 -0600)
So for this testcase:

int foo (int t)
 {
   return 3 * t - 1;
 }

We currently generate:

    slliw    a5,a0,1
    addw    a0,a5,a0
    addiw    a0,a0,-1
    ret

Intuitively we can see we're doing a 32->64 sign extension at each step and we
could drop the intermediate sign extensions.  In fact, not only can we drop the
intermediate sign extensions, we can safely "promote" the intermediate
operations from SI to DI with a final sign extending add.  Conceptually that
unlocks combining the first shift+add into a shNadd insn resulting in this
code:

    sh1add    a0, a0, a0
    addiw    a0, a0, -1
    ret

The patch, but not the testcase, has been in my tree for a while, so it's been
through bootstrap & regression testing on the BPI and Pioneer as well as
testing on riscv32-elf and riscv64-elf. Obviously I'll wait for pre-commit CI
to do its thing before pushing.

PR target/124760
gcc/
* config/riscv/bitmanip.md (SI->DI promoting shadd pattern): Promote
intermediate SI ops to DI ops when there's a final extending op.

gcc/testsuite

* gcc.target/riscv/pr124760.c: New test.

gcc/config/riscv/bitmanip.md
gcc/testsuite/gcc.target/riscv/pr124760.c [new file with mode: 0644]

index 1ca9f82b363f01f7c881f61285826fec85518002..c9561b0b622805817887655573a58166e426ffd9 100644 (file)
   [(set (match_dup 2) (plus:X (match_dup 1) (const_int -1)))
    (set (match_dup 0) (and:X (not:X (match_dup 1)) (match_dup 2)))])
 
+(define_split
+  [(set (match_operand:DI 0 "register_operand")
+       (sign_extend:DI (plus:SI (plus:SI (ashift:SI (match_operand:SI 1 "register_operand")
+                                                    (match_operand 2 "imm123_operand"))
+                                         (match_operand:SI 3 "register_operand"))
+                                (match_operand:SI 4 "arith_operand"))))
+   (clobber (match_operand:DI 5 "register_operand"))]
+  "TARGET_64BIT && TARGET_ZBA"
+  [(set (match_dup 5) (plus:DI (ashift:DI (match_dup 1) (match_dup 2)) (match_dup 3)))
+   (set (match_dup 0) (sign_extend:DI (plus:SI (match_dup 6) (match_dup 4))))]
+  {
+    operands[1] = gen_lowpart (DImode, operands[1]);
+    operands[3] = gen_lowpart (DImode, operands[3]);
+    operands[6] = gen_lowpart (SImode, operands[5]);
+  })
diff --git a/gcc/testsuite/gcc.target/riscv/pr124760.c b/gcc/testsuite/gcc.target/riscv/pr124760.c
new file mode 100644 (file)
index 0000000..0c4768f
--- /dev/null
@@ -0,0 +1,14 @@
+/* { dg-do compile { target rv64 } } */
+/* { dg-additional-options "-march=rv64gcb_zicond -mabi=lp64d" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Og" "-Os" "-Oz" } } */
+
+
+int foo (int t)
+{
+  return 3 * t - 1;
+}
+
+/* { dg-final { scan-assembler-not "slliw\t" } } */
+/* { dg-final { scan-assembler-not "addw\t" } } */
+/* { dg-final { scan-assembler-times "sh1add\t" 1 } } */
+/* { dg-final { scan-assembler-times "addiw\t" 1 } } */