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.
[(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]);
+ })
--- /dev/null
+/* { 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 } } */