[llvm] 0d14772 - [RISCV][P-ext] Add isel patterns for for macc*.h00/macc*.w00. (#190444)

via llvm-commits llvm-commits at lists.llvm.org
Mon Apr 6 09:57:33 PDT 2026


Author: Craig Topper
Date: 2026-04-06T09:57:29-07:00
New Revision: 0d14772a91a5c0bbefb59d6dd5a6c0f54f8ed4ea

URL: https://github.com/llvm/llvm-project/commit/0d14772a91a5c0bbefb59d6dd5a6c0f54f8ed4ea
DIFF: https://github.com/llvm/llvm-project/commit/0d14772a91a5c0bbefb59d6dd5a6c0f54f8ed4ea.diff

LOG: [RISCV][P-ext] Add isel patterns for for macc*.h00/macc*.w00. (#190444)

The RV32 macc*.h00 instructions take the lower half words from rs1 and
rs2, compute the full word product by extending the inputs, and
add to rd. The RV64 macc*.w00 is similar but operates on words
and produces a double word result.

I've restricted this to case where the multiply has a single use.
We don't have a general macc that multiplies the full xlen bits
of rs1 and rs2, so I'm allowing the input to be sext_inreg/and or
have sufficient sign/zero bits according to
ComputeNumSignBits/computeKnownBits.

We should also add mul*.h00/mul.*w00 patterns, but those we should
restrict to at least one input being sext_inreg/and and prefer
regular mul when there are no sext_inreg/and.

Added: 
    

Modified: 
    llvm/lib/Target/RISCV/RISCVInstrInfoP.td
    llvm/test/CodeGen/RISCV/rv32p.ll
    llvm/test/CodeGen/RISCV/rv64p.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Target/RISCV/RISCVInstrInfoP.td b/llvm/lib/Target/RISCV/RISCVInstrInfoP.td
index 426fc332debc5..651c8e8608f5c 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoP.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoP.td
@@ -1952,6 +1952,13 @@ let Predicates = [HasStdExtP, IsRV32] in {
   def : PatGprGpr<avgfloors, AADD, i32>;
   def : PatGprGpr<avgflooru, AADDU, i32>;
 
+  def : Pat<(i32 (add GPR:$rd, (mul_oneuse sexti16:$rs1, sexti16:$rs2))),
+            (MACC_H00 GPR:$rd, sexti16:$rs1, sexti16:$rs2)>;
+  def : Pat<(i32 (add GPR:$rd, (mul_oneuse zexti16:$rs1, zexti16:$rs2))),
+            (MACCU_H00 GPR:$rd, zexti16:$rs1, zexti16:$rs2)>;
+  def : Pat<(i32 (add GPR:$rd, (mul_oneuse sexti16:$rs1, zexti16:$rs2))),
+            (MACCSU_H00 GPR:$rd, sexti16:$rs1, zexti16:$rs2)>;
+
   // Narrowing shift patterns (NSRL/NSRA)
   // Immediate shift amount patterns
   def : Pat<(riscv_nsrl GPR:$lo, GPR:$hi, uimm6:$shamt),
@@ -2002,6 +2009,13 @@ let Predicates = [HasStdExtP, IsRV64] in {
   def : Pat<(XLenVT (riscv_usati GPR:$rs1, timm:$imm)),
             (USATI_RV64 GPR:$rs1, timm:$imm)>;
 
+  def : Pat<(i64 (add GPR:$rd, (mul_oneuse sexti32:$rs1, sexti32:$rs2))),
+            (MACC_W00 GPR:$rd, sexti32:$rs1, sexti32:$rs2)>;
+  def : Pat<(i64 (add GPR:$rd, (mul_oneuse zexti32:$rs1, zexti32:$rs2))),
+            (MACCU_W00 GPR:$rd, zexti32:$rs1, zexti32:$rs2)>;
+  def : Pat<(i64 (add GPR:$rd, (mul_oneuse sexti32:$rs1, zexti32:$rs2))),
+            (MACCSU_W00 GPR:$rd, sexti32:$rs1, zexti32:$rs2)>;
+
   // Match a pattern of 2 bytes being inserted into bits [31:16], with bits
   // bits [15:0] coming from a zero extended value, and bits [63:32] being
   // ignored. We can use ppaire.h with ppaire.b for bits [31:16]. If bits [15:0]

diff  --git a/llvm/test/CodeGen/RISCV/rv32p.ll b/llvm/test/CodeGen/RISCV/rv32p.ll
index d2bf1c581e900..a4c39e08f7465 100644
--- a/llvm/test/CodeGen/RISCV/rv32p.ll
+++ b/llvm/test/CodeGen/RISCV/rv32p.ll
@@ -1075,6 +1075,120 @@ define i64 @wmaccsu_commute(i32 %a, i32 %b, i64 %c) nounwind {
   ret i64 %result
 }
 
+define i32 @macc_h00(i32 %rd, i16 %a, i16 %b) nounwind {
+; CHECK-LABEL: macc_h00:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    macc.h00 a0, a1, a2
+; CHECK-NEXT:    ret
+  %aext = sext i16 %a to i32
+  %bext = sext i16 %b to i32
+  %mul = mul i32 %aext, %bext
+  %result = add i32 %rd, %mul
+  ret i32 %result
+}
+
+define i32 @macc_h00_commute(i32 %rd, i16 %a, i16 %b) nounwind {
+; CHECK-LABEL: macc_h00_commute:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    macc.h00 a0, a1, a2
+; CHECK-NEXT:    ret
+  %aext = sext i16 %a to i32
+  %bext = sext i16 %b to i32
+  %mul = mul i32 %aext, %bext
+  %result = add i32 %mul, %rd
+  ret i32 %result
+}
+
+define i32 @maccu_h00(i32 %rd, i16 %a, i16 %b) nounwind {
+; CHECK-LABEL: maccu_h00:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    maccu.h00 a0, a1, a2
+; CHECK-NEXT:    ret
+  %aext = zext i16 %a to i32
+  %bext = zext i16 %b to i32
+  %mul = mul i32 %aext, %bext
+  %result = add i32 %rd, %mul
+  ret i32 %result
+}
+
+define i32 @maccu_h00_commute(i32 %rd, i16 %a, i16 %b) nounwind {
+; CHECK-LABEL: maccu_h00_commute:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    maccu.h00 a0, a1, a2
+; CHECK-NEXT:    ret
+  %aext = zext i16 %a to i32
+  %bext = zext i16 %b to i32
+  %mul = mul i32 %aext, %bext
+  %result = add i32 %mul, %rd
+  ret i32 %result
+}
+
+define i32 @maccsu_h00(i32 %rd, i16 %a, i16 %b) nounwind {
+; CHECK-LABEL: maccsu_h00:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    maccsu.h00 a0, a1, a2
+; CHECK-NEXT:    ret
+  %aext = sext i16 %a to i32
+  %bext = zext i16 %b to i32
+  %mul = mul i32 %aext, %bext
+  %result = add i32 %rd, %mul
+  ret i32 %result
+}
+
+define i32 @maccsu_h00_commute(i32 %rd, i16 %a, i16 %b) nounwind {
+; CHECK-LABEL: maccsu_h00_commute:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    maccsu.h00 a0, a1, a2
+; CHECK-NEXT:    ret
+  %aext = sext i16 %a to i32
+  %bext = zext i16 %b to i32
+  %mul = mul i32 %aext, %bext
+  %result = add i32 %mul, %rd
+  ret i32 %result
+}
+
+define i32 @maccsu_h00_swap_operands(i32 %rd, i16 %a, i16 %b) nounwind {
+; CHECK-LABEL: maccsu_h00_swap_operands:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    maccsu.h00 a0, a2, a1
+; CHECK-NEXT:    ret
+  %aext = zext i16 %a to i32
+  %bext = sext i16 %b to i32
+  %mul = mul i32 %aext, %bext
+  %result = add i32 %rd, %mul
+  ret i32 %result
+}
+
+define i32 @maccsu_h00_swap_operands_commute(i32 %rd, i16 %a, i16 %b) nounwind {
+; CHECK-LABEL: maccsu_h00_swap_operands_commute:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    maccsu.h00 a0, a2, a1
+; CHECK-NEXT:    ret
+  %aext = zext i16 %a to i32
+  %bext = sext i16 %b to i32
+  %mul = mul i32 %aext, %bext
+  %result = add i32 %mul, %rd
+  ret i32 %result
+}
+
+; Negative test: multiply result has multiple uses, should not combine to macc
+define i32 @macc_h00_multiple_uses(i16 %a, i16 %b, i32 %c, ptr %out) nounwind {
+; CHECK-LABEL: macc_h00_multiple_uses:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    sext.h a0, a0
+; CHECK-NEXT:    sext.h a1, a1
+; CHECK-NEXT:    mul a1, a0, a1
+; CHECK-NEXT:    add a0, a2, a1
+; CHECK-NEXT:    sw a1, 0(a3)
+; CHECK-NEXT:    ret
+  %aext = sext i16 %a to i32
+  %bext = sext i16 %b to i32
+  %mul = mul i32 %aext, %bext
+  %result = add i32 %c, %mul
+  store i32 %mul, ptr %out
+  ret i32 %result
+}
+
 ; Negative test: multiply result has multiple uses, should not combine
 define void @wmaccu_multiple_uses(i32 %a, i32 %b, i64 %c, ptr %out1, ptr %out2) nounwind {
 ; CHECK-LABEL: wmaccu_multiple_uses:

diff  --git a/llvm/test/CodeGen/RISCV/rv64p.ll b/llvm/test/CodeGen/RISCV/rv64p.ll
index 1d626611b736a..a05e454a1b5dd 100644
--- a/llvm/test/CodeGen/RISCV/rv64p.ll
+++ b/llvm/test/CodeGen/RISCV/rv64p.ll
@@ -1031,3 +1031,117 @@ entry:
   %3 = or i64 %1, %2
   ret i64 %3
 }
+
+define i64 @macc_w00(i64 %rd, i32 %a, i32 %b) nounwind {
+; CHECK-LABEL: macc_w00:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    macc.w00 a0, a1, a2
+; CHECK-NEXT:    ret
+  %aext = sext i32 %a to i64
+  %bext = sext i32 %b to i64
+  %mul = mul i64 %aext, %bext
+  %result = add i64 %rd, %mul
+  ret i64 %result
+}
+
+define i64 @macc_w00_commute(i64 %rd, i32 %a, i32 %b) nounwind {
+; CHECK-LABEL: macc_w00_commute:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    macc.w00 a0, a1, a2
+; CHECK-NEXT:    ret
+  %aext = sext i32 %a to i64
+  %bext = sext i32 %b to i64
+  %mul = mul i64 %aext, %bext
+  %result = add i64 %mul, %rd
+  ret i64 %result
+}
+
+define i64 @maccu_w00(i64 %rd, i32 %a, i32 %b) nounwind {
+; CHECK-LABEL: maccu_w00:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    maccu.w00 a0, a1, a2
+; CHECK-NEXT:    ret
+  %aext = zext i32 %a to i64
+  %bext = zext i32 %b to i64
+  %mul = mul i64 %aext, %bext
+  %result = add i64 %rd, %mul
+  ret i64 %result
+}
+
+define i64 @maccu_w00_commute(i64 %rd, i32 %a, i32 %b) nounwind {
+; CHECK-LABEL: maccu_w00_commute:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    maccu.w00 a0, a1, a2
+; CHECK-NEXT:    ret
+  %aext = zext i32 %a to i64
+  %bext = zext i32 %b to i64
+  %mul = mul i64 %aext, %bext
+  %result = add i64 %mul, %rd
+  ret i64 %result
+}
+
+define i64 @maccsu_w00(i64 %rd, i32 %a, i32 %b) nounwind {
+; CHECK-LABEL: maccsu_w00:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    maccsu.w00 a0, a1, a2
+; CHECK-NEXT:    ret
+  %aext = sext i32 %a to i64
+  %bext = zext i32 %b to i64
+  %mul = mul i64 %aext, %bext
+  %result = add i64 %rd, %mul
+  ret i64 %result
+}
+
+define i64 @maccsu_w00_commute(i64 %rd, i32 %a, i32 %b) nounwind {
+; CHECK-LABEL: maccsu_w00_commute:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    maccsu.w00 a0, a1, a2
+; CHECK-NEXT:    ret
+  %aext = sext i32 %a to i64
+  %bext = zext i32 %b to i64
+  %mul = mul i64 %aext, %bext
+  %result = add i64 %mul, %rd
+  ret i64 %result
+}
+
+define i64 @maccsu_w00_swap_operands(i64 %rd, i32 %a, i32 %b) nounwind {
+; CHECK-LABEL: maccsu_w00_swap_operands:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    maccsu.w00 a0, a2, a1
+; CHECK-NEXT:    ret
+  %aext = zext i32 %a to i64
+  %bext = sext i32 %b to i64
+  %mul = mul i64 %aext, %bext
+  %result = add i64 %rd, %mul
+  ret i64 %result
+}
+
+define i64 @maccsu_w00_swap_operands_commute(i64 %rd, i32 %a, i32 %b) nounwind {
+; CHECK-LABEL: maccsu_w00_swap_operands_commute:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    maccsu.w00 a0, a2, a1
+; CHECK-NEXT:    ret
+  %aext = zext i32 %a to i64
+  %bext = sext i32 %b to i64
+  %mul = mul i64 %aext, %bext
+  %result = add i64 %mul, %rd
+  ret i64 %result
+}
+
+; Negative test: multiply result has multiple uses, should not combine to macc
+define i64 @macc_w00_multiple_uses(i32 %a, i32 %b, i64 %c, ptr %out) nounwind {
+; CHECK-LABEL: macc_w00_multiple_uses:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    sext.w a0, a0
+; CHECK-NEXT:    sext.w a1, a1
+; CHECK-NEXT:    mul a1, a0, a1
+; CHECK-NEXT:    add a0, a2, a1
+; CHECK-NEXT:    sd a1, 0(a3)
+; CHECK-NEXT:    ret
+  %aext = sext i32 %a to i64
+  %bext = sext i32 %b to i64
+  %mul = mul i64 %aext, %bext
+  %result = add i64 %c, %mul
+  store i64 %mul, ptr %out
+  ret i64 %result
+}


        


More information about the llvm-commits mailing list