[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