[llvm] [RISCV] Add combines to form WSUBAU on RV32 with P. (PR #181604)
Craig Topper via llvm-commits
llvm-commits at lists.llvm.org
Sun Feb 15 22:51:44 PST 2026
https://github.com/topperc created https://github.com/llvm/llvm-project/pull/181604
None
>From 44e97ea46d85f4eaab7c65d129323c4af3327e82 Mon Sep 17 00:00:00 2001
From: Craig Topper <craig.topper at sifive.com>
Date: Sun, 15 Feb 2026 22:11:49 -0800
Subject: [PATCH 1/2] Pre-commit tests
---
llvm/test/CodeGen/RISCV/rv32p.ll | 44 ++++++++++++++++++++++++++++++++
1 file changed, 44 insertions(+)
diff --git a/llvm/test/CodeGen/RISCV/rv32p.ll b/llvm/test/CodeGen/RISCV/rv32p.ll
index 9f04646b54d75..8a8e5d6bd20fc 100644
--- a/llvm/test/CodeGen/RISCV/rv32p.ll
+++ b/llvm/test/CodeGen/RISCV/rv32p.ll
@@ -1109,3 +1109,47 @@ define i64 @waddau_zext_chain(i64 %acc, i32 %a, i32 %b) nounwind {
%sum2 = add i64 %sum1, %ext_b
ret i64 %sum2
}
+
+; acc - zext(a) -> wsubau acc, 0, a
+define i64 @wsubau_zext(i64 %acc, i32 %a) nounwind {
+; CHECK-LABEL: wsubau_zext:
+; CHECK: # %bb.0:
+; CHECK-NEXT: li a3, 0
+; CHECK-NEXT: subd a0, a0, a2
+; CHECK-NEXT: ret
+ %ext_a = zext i32 %a to i64
+ %sub = sub i64 %acc, %ext_a
+ ret i64 %sub
+}
+
+; (acc + zext(a)) - zext(b) -> wsubau acc, a, b
+define i64 @wsubau_zext_chain(i64 %acc, i32 %a, i32 %b) nounwind {
+; CHECK-LABEL: wsubau_zext_chain:
+; CHECK: # %bb.0:
+; CHECK-NEXT: mv a4, a3
+; CHECK-NEXT: waddau a0, a2, zero
+; CHECK-NEXT: li a5, 0
+; CHECK-NEXT: subd a0, a0, a4
+; CHECK-NEXT: ret
+ %ext_a = zext i32 %a to i64
+ %ext_b = zext i32 %b to i64
+ %sum = add i64 %acc, %ext_a
+ %sub = sub i64 %sum, %ext_b
+ ret i64 %sub
+}
+
+; (acc - zext(a)) + zext(b) -> wsubau acc, b, a
+define i64 @wsubau_zext_chain_rev(i64 %acc, i32 %a, i32 %b) nounwind {
+; CHECK-LABEL: wsubau_zext_chain_rev:
+; CHECK: # %bb.0:
+; CHECK-NEXT: mv a4, a3
+; CHECK-NEXT: li a3, 0
+; CHECK-NEXT: subd a0, a0, a2
+; CHECK-NEXT: waddau a0, a4, zero
+; CHECK-NEXT: ret
+ %ext_a = zext i32 %a to i64
+ %ext_b = zext i32 %b to i64
+ %sub = sub i64 %acc, %ext_a
+ %sum = add i64 %sub, %ext_b
+ ret i64 %sum
+}
>From 13d63cf68c207d3f13b21261154d843c16882828 Mon Sep 17 00:00:00 2001
From: Craig Topper <craig.topper at sifive.com>
Date: Sun, 15 Feb 2026 22:46:26 -0800
Subject: [PATCH 2/2] [RISCV] Add combines to form WSUBAU on RV32 with P.
---
llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp | 16 +++---
llvm/lib/Target/RISCV/RISCVISelLowering.cpp | 59 ++++++++++++++++++---
llvm/lib/Target/RISCV/RISCVInstrInfoP.td | 2 +
llvm/test/CodeGen/RISCV/rv32p.ll | 13 ++---
4 files changed, 66 insertions(+), 24 deletions(-)
diff --git a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
index 7d61ea6332138..bf5057bdc50fb 100644
--- a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
@@ -1990,7 +1990,8 @@ void RISCVDAGToDAGISel::Select(SDNode *Node) {
[[fallthrough]];
case RISCVISD::SUBD:
case RISCVISD::PPAIRE_DB:
- case RISCVISD::WADDAU: {
+ case RISCVISD::WADDAU:
+ case RISCVISD::WSUBAU: {
assert(!Subtarget->is64Bit() && "Unexpected opcode");
assert((Node->getOpcode() != RISCVISD::PPAIRE_DB ||
Subtarget->enablePExtSIMDCodeGen()) &&
@@ -2010,17 +2011,16 @@ void RISCVDAGToDAGISel::Select(SDNode *Node) {
SDValue Op1Hi = Node->getOperand(3);
MachineSDNode *New;
- if (Node->getOpcode() == RISCVISD::WADDAU) {
- // WADDAU: rd = rd + zext(rs1) + zext(rs2)
- // Op0 is the accumulator (GPRPair), Op1Lo and Op1Hi are the two 32-bit
- // values to add.
- New = CurDAG->getMachineNode(RISCV::WADDAU, DL, MVT::Untyped, Op0, Op1Lo,
- Op1Hi);
+ if (Opcode == RISCVISD::WADDAU || Opcode == RISCVISD::WSUBAU) {
+ // WADDAU/WSUBAU: Op0 is the accumulator (GPRPair), Op1Lo and Op1Hi are
+ // the two 32-bit values.
+ unsigned Opc = Opcode == RISCVISD::WADDAU ? RISCV::WADDAU : RISCV::WSUBAU;
+ New = CurDAG->getMachineNode(Opc, DL, MVT::Untyped, Op0, Op1Lo, Op1Hi);
} else {
SDValue Op1 = buildGPRPair(CurDAG, DL, MVT::Untyped, Op1Lo, Op1Hi);
unsigned Opc;
- switch (Node->getOpcode()) {
+ switch (Opcode) {
default:
llvm_unreachable("Unexpected opcode");
case RISCVISD::ADDD:
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index 4d38ee354d86f..221a56427c173 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -21375,25 +21375,72 @@ SDValue RISCVTargetLowering::PerformDAGCombine(SDNode *N,
}
break;
}
+ case RISCVISD::SUBD: {
+ assert(!Subtarget.is64Bit() && Subtarget.hasStdExtP() &&
+ "SUBD is only for RV32 with P extension");
+
+ SDValue Op0Lo = N->getOperand(0);
+ SDValue Op0Hi = N->getOperand(1);
+ SDValue Op1Lo = N->getOperand(2);
+ SDValue Op1Hi = N->getOperand(3);
+
+ // (SUBD lo, hi, x, 0) -> (WSUBAU lo, hi, 0, x)
+ // WSUBAU semantics: rd = rd + zext(rs1) - zext(rs2)
+ if (isNullConstant(Op1Hi)) {
+ SDValue Result =
+ DAG.getNode(RISCVISD::WSUBAU, DL, DAG.getVTList(MVT::i32, MVT::i32),
+ Op0Lo, Op0Hi, DAG.getConstant(0, DL, MVT::i32), Op1Lo);
+ return DCI.CombineTo(N, Result.getValue(0), Result.getValue(1));
+ }
+ break;
+ }
case RISCVISD::WADDAU: {
assert(!Subtarget.is64Bit() && Subtarget.hasStdExtP() &&
"WADDAU is only for RV32 with P extension");
- // (WADDAU (WADDAU lo, hi, x, 0), y, 0) -> (WADDAU lo, hi, x, y)
SDValue Op0Lo = N->getOperand(0);
SDValue Op0Hi = N->getOperand(1);
SDValue Op1 = N->getOperand(2);
SDValue Op2 = N->getOperand(3);
- // Check if this WADDAU has a zero second operand and the accumulator
- // comes from another WADDAU with a zero second operand.
// FIXME: Canonicalize zero Op1 to Op2.
- if (isNullConstant(Op2) && Op0Lo.getOpcode() == RISCVISD::WADDAU &&
+ if (isNullConstant(Op2) && Op0Lo.getNode() == Op0Hi.getNode() &&
+ Op0Lo.getResNo() == 0 && Op0Hi.getResNo() == 1 && Op0Lo.hasOneUse() &&
+ Op0Hi.hasOneUse()) {
+ // (WADDAU (WADDAU lo, hi, x, 0), y, 0) -> (WADDAU lo, hi, x, y)
+ if (Op0Lo.getOpcode() == RISCVISD::WADDAU &&
+ isNullConstant(Op0Lo.getOperand(3))) {
+ SDValue Result = DAG.getNode(
+ RISCVISD::WADDAU, DL, DAG.getVTList(MVT::i32, MVT::i32),
+ Op0Lo.getOperand(0), Op0Lo.getOperand(1), Op0Lo.getOperand(2), Op1);
+ return DCI.CombineTo(N, Result.getValue(0), Result.getValue(1));
+ }
+ // (WADDAU (WSUBAU lo, hi, 0, a), b, 0) -> (WSUBAU lo, hi, b, a)
+ if (Op0Lo.getOpcode() == RISCVISD::WSUBAU &&
+ isNullConstant(Op0Lo.getOperand(2))) {
+ SDValue Result = DAG.getNode(
+ RISCVISD::WSUBAU, DL, DAG.getVTList(MVT::i32, MVT::i32),
+ Op0Lo.getOperand(0), Op0Lo.getOperand(1), Op1, Op0Lo.getOperand(3));
+ return DCI.CombineTo(N, Result.getValue(0), Result.getValue(1));
+ }
+ }
+ break;
+ }
+ case RISCVISD::WSUBAU: {
+ assert(!Subtarget.is64Bit() && Subtarget.hasStdExtP() &&
+ "WSUBAU is only for RV32 with P extension");
+ SDValue Op0Lo = N->getOperand(0);
+ SDValue Op0Hi = N->getOperand(1);
+ SDValue Op1 = N->getOperand(2);
+ SDValue Op2 = N->getOperand(3);
+
+ // (WSUBAU (WADDAU lo, hi, a, 0), 0, b) -> (WSUBAU lo, hi, a, b)
+ if (isNullConstant(Op1) && Op0Lo.getOpcode() == RISCVISD::WADDAU &&
Op0Lo.getNode() == Op0Hi.getNode() && Op0Lo.getResNo() == 0 &&
Op0Hi.getResNo() == 1 && Op0Lo.hasOneUse() && Op0Hi.hasOneUse() &&
isNullConstant(Op0Lo.getOperand(3))) {
SDValue Result = DAG.getNode(
- RISCVISD::WADDAU, DL, DAG.getVTList(MVT::i32, MVT::i32),
- Op0Lo.getOperand(0), Op0Lo.getOperand(1), Op0Lo.getOperand(2), Op1);
+ RISCVISD::WSUBAU, DL, DAG.getVTList(MVT::i32, MVT::i32),
+ Op0Lo.getOperand(0), Op0Lo.getOperand(1), Op0Lo.getOperand(2), Op2);
return DCI.CombineTo(N, Result.getValue(0), Result.getValue(1));
}
break;
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoP.td b/llvm/lib/Target/RISCV/RISCVInstrInfoP.td
index 6de7309dc2deb..2df2d84d6933a 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoP.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoP.td
@@ -1501,6 +1501,8 @@ def SDT_RISCVWideningAddSubAccumulate : SDTypeProfile<2, 4, [SDTCisVT<0, i32>,
SDTCisSameAs<0, 5>]>;
// Widening add accumulate unsigned: rd = rd + zext(rs1) + zext(rs2)
def riscv_waddau : RVSDNode<"WADDAU", SDT_RISCVWideningAddSubAccumulate>;
+// Widening sub accumulate unsigned: rd = rd + zext(rs1) - zext(rs2)
+def riscv_wsubau : RVSDNode<"WSUBAU", SDT_RISCVWideningAddSubAccumulate>;
def riscv_wmulsu : RVSDNode<"WMULSU", SDTIntBinHiLoOp>;
diff --git a/llvm/test/CodeGen/RISCV/rv32p.ll b/llvm/test/CodeGen/RISCV/rv32p.ll
index 8a8e5d6bd20fc..1e0e6b5e9748a 100644
--- a/llvm/test/CodeGen/RISCV/rv32p.ll
+++ b/llvm/test/CodeGen/RISCV/rv32p.ll
@@ -1114,8 +1114,7 @@ define i64 @waddau_zext_chain(i64 %acc, i32 %a, i32 %b) nounwind {
define i64 @wsubau_zext(i64 %acc, i32 %a) nounwind {
; CHECK-LABEL: wsubau_zext:
; CHECK: # %bb.0:
-; CHECK-NEXT: li a3, 0
-; CHECK-NEXT: subd a0, a0, a2
+; CHECK-NEXT: wsubau a0, zero, a2
; CHECK-NEXT: ret
%ext_a = zext i32 %a to i64
%sub = sub i64 %acc, %ext_a
@@ -1126,10 +1125,7 @@ define i64 @wsubau_zext(i64 %acc, i32 %a) nounwind {
define i64 @wsubau_zext_chain(i64 %acc, i32 %a, i32 %b) nounwind {
; CHECK-LABEL: wsubau_zext_chain:
; CHECK: # %bb.0:
-; CHECK-NEXT: mv a4, a3
-; CHECK-NEXT: waddau a0, a2, zero
-; CHECK-NEXT: li a5, 0
-; CHECK-NEXT: subd a0, a0, a4
+; CHECK-NEXT: wsubau a0, a2, a3
; CHECK-NEXT: ret
%ext_a = zext i32 %a to i64
%ext_b = zext i32 %b to i64
@@ -1142,10 +1138,7 @@ define i64 @wsubau_zext_chain(i64 %acc, i32 %a, i32 %b) nounwind {
define i64 @wsubau_zext_chain_rev(i64 %acc, i32 %a, i32 %b) nounwind {
; CHECK-LABEL: wsubau_zext_chain_rev:
; CHECK: # %bb.0:
-; CHECK-NEXT: mv a4, a3
-; CHECK-NEXT: li a3, 0
-; CHECK-NEXT: subd a0, a0, a2
-; CHECK-NEXT: waddau a0, a4, zero
+; CHECK-NEXT: wsubau a0, a3, a2
; CHECK-NEXT: ret
%ext_a = zext i32 %a to i64
%ext_b = zext i32 %b to i64
More information about the llvm-commits
mailing list