]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
[RISC-V] Improve (x << C1) + C2 split code
authorJeff Law <jlaw@ventanamicro.com>
Wed, 21 May 2025 22:04:58 +0000 (16:04 -0600)
committerJeff Law <jlaw@ventanamicro.com>
Wed, 21 May 2025 22:04:58 +0000 (16:04 -0600)
I wrote this a couple months ago to fix an instruction count regression in
505.mcf on risc-v, but I don't have a trivial little testcase to add to the
suite.

There were two problems with the pattern.

First, the code was generating a shift followed by an add after reload.
Naturally combine doesn't run after reload and the code stayed in that form
rather than using shadd when available.

Second the splitter was just over-active.  We need to make sure that the
shifted form of the constant operand has a cost > 1 to synthesize.  It's
useless to split if the shifted constant can be synthesized in a single
instruction.

This has been in my tester since March.  So it's been through numerous
riscv64-elf and riscv32-elf test cycles as well as multiple rv64 bootstrap
tests.  Waiting on the upstream CI system to render a verdict before moving
forward.

Looking further out I'm hoping this pattern will transform into a simpler and
always active define_split.

gcc/
* config/riscv/riscv.md ((x << C1) + C2): Tighten split condition
and generate more efficient code when splitting.

gcc/config/riscv/riscv.md

index 7e35d7877ed90ab6175902ad79947dbbfe65c080..a5b3abbe5d452a25453eeca418b75c9302b44cd6 100644 (file)
                            (match_operand 2 "const_int_operand" "n"))
                 (match_operand 3 "const_int_operand" "n")))
    (clobber (match_scratch:DI 4 "=&r"))]
-  "(TARGET_64BIT && riscv_const_insns (operands[3], false) == 1)"
+  "(TARGET_64BIT
+    && riscv_const_insns (operands[3], false) == 1
+    && riscv_const_insns (GEN_INT (INTVAL (operands[3])
+                         << INTVAL (operands[2])), false) != 1)"
   "#"
   "&& reload_completed"
   [(const_int 0)]
   "{
-     rtx x = gen_rtx_ASHIFT (DImode, operands[1], operands[2]);
-     emit_insn (gen_rtx_SET (operands[0], x));
-
-     /* If the constant fits in a simm12, use it directly as we do not
-       get another good chance to optimize things again.  */
-     if (!SMALL_OPERAND (INTVAL (operands[3])))
+     /* Prefer to generate shNadd when we can, even over using an
+       immediate form.  If we're not going to be able to generate
+       a shNadd, then use the constant directly if it fits in a
+       simm12 field since we won't get another chance to optimize this.  */
+     if ((TARGET_ZBA && imm123_operand (operands[2], word_mode))
+        || !SMALL_OPERAND (INTVAL (operands[3])))
        emit_move_insn (operands[4], operands[3]);
      else
        operands[4] = operands[3];
 
-     x = gen_rtx_PLUS (DImode, operands[0], operands[4]);
-     emit_insn (gen_rtx_SET (operands[0], x));
+     if (TARGET_ZBA && imm123_operand (operands[2], word_mode))
+       {
+        rtx x = gen_rtx_ASHIFT (DImode, operands[1], operands[2]);
+        x = gen_rtx_PLUS (DImode, x, operands[4]);
+        emit_insn (gen_rtx_SET (operands[0], x));
+       }
+     else
+       {
+        rtx x = gen_rtx_ASHIFT (DImode, operands[1], operands[2]);
+        emit_insn (gen_rtx_SET (operands[0], x));
+        x = gen_rtx_PLUS (DImode, operands[0], operands[4]);
+        emit_insn (gen_rtx_SET (operands[0], x));
+       }
+
      DONE;
    }"
   [(set_attr "type" "arith")])