[llvm] 28475c2 - [RISCV][P-ext] Select signed widening add/sub accumulate to wadda/wsuba (#205475)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Jun 25 07:34:35 PDT 2026
Author: SiHuaN
Date: 2026-06-25T22:34:22+08:00
New Revision: 28475c218ebcbf81d581d1953e7a1cb4e91fba60
URL: https://github.com/llvm/llvm-project/commit/28475c218ebcbf81d581d1953e7a1cb4e91fba60
DIFF: https://github.com/llvm/llvm-project/commit/28475c218ebcbf81d581d1953e7a1cb4e91fba60.diff
LOG: [RISCV][P-ext] Select signed widening add/sub accumulate to wadda/wsuba (#205475)
WADDA is rd += sext(rs1) + sext(rs2) and WSUBA is rd += sext(rs1) - sext(rs2),
the signed counterparts of WADDAU/WSUBAU added in #181396.
Add the WADDA/WSUBA SelectionDAG nodes, fold ADDD/SUBD whose addend is a
sign-extended i32 (high half == sra(lo, 31)) into them, collapse chained
accumulates into the free source slot, and select them to the wadda/wsuba
instructions.
Added:
Modified:
llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
llvm/lib/Target/RISCV/RISCVISelLowering.cpp
llvm/lib/Target/RISCV/RISCVInstrInfoP.td
llvm/test/CodeGen/RISCV/rv32p.ll
Removed:
################################################################################
diff --git a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
index 5611410469384..df0a34ea27685 100644
--- a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
@@ -2076,7 +2076,9 @@ void RISCVDAGToDAGISel::Select(SDNode *Node) {
case RISCVISD::SUBD:
case RISCVISD::PPAIRE_DB:
case RISCVISD::WADDAU:
- case RISCVISD::WSUBAU: {
+ case RISCVISD::WSUBAU:
+ case RISCVISD::WADDA:
+ case RISCVISD::WSUBA: {
assert(!Subtarget->is64Bit() && "Unexpected opcode");
assert(
(Node->getOpcode() != RISCVISD::PPAIRE_DB || Subtarget->hasStdExtP()) &&
@@ -2096,10 +2098,27 @@ void RISCVDAGToDAGISel::Select(SDNode *Node) {
SDValue Op1Hi = Node->getOperand(3);
MachineSDNode *New;
- 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;
+ if (Opcode == RISCVISD::WADDAU || Opcode == RISCVISD::WSUBAU ||
+ Opcode == RISCVISD::WADDA || Opcode == RISCVISD::WSUBA) {
+ // Widening accumulate: Op0 is the accumulator (GPRPair), Op1Lo and Op1Hi
+ // are the two 32-bit values.
+ unsigned Opc;
+ switch (Opcode) {
+ default:
+ llvm_unreachable("Unexpected opcode");
+ case RISCVISD::WADDAU:
+ Opc = RISCV::WADDAU;
+ break;
+ case RISCVISD::WSUBAU:
+ Opc = RISCV::WSUBAU;
+ break;
+ case RISCVISD::WADDA:
+ Opc = RISCV::WADDA;
+ break;
+ case RISCVISD::WSUBA:
+ Opc = RISCV::WSUBA;
+ break;
+ }
New = CurDAG->getMachineNode(Opc, DL, MVT::Untyped, Op0, Op1Lo, Op1Hi);
} else {
SDValue Op1 = buildGPRPair(CurDAG, DL, MVT::Untyped, Op1Lo, Op1Hi);
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index 7a2b9611683c6..a0e53d2e69c1f 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -21550,6 +21550,15 @@ static SDValue combineMinMaxToSat(SDNode *N,
return SDValue();
}
+// Returns true if the i32 pair (Lo, Hi) is the 64-bit sign-extension of the
+// i32 value Lo, i.e. Hi == (sra Lo, 31). Used to fold ADDD/SUBD of a
+// sign-extended operand into the WADDA/WSUBA widening accumulate nodes.
+static bool isI32SignExtended(SDValue Lo, SDValue Hi) {
+ return Hi.getOpcode() == ISD::SRA && Hi.getOperand(0) == Lo &&
+ isa<ConstantSDNode>(Hi.getOperand(1)) &&
+ Hi.getConstantOperandVal(1) == 31;
+}
+
SDValue RISCVTargetLowering::PerformDAGCombine(SDNode *N,
DAGCombinerInfo &DCI) const {
SelectionDAG &DAG = DCI.DAG;
@@ -21736,6 +21745,21 @@ SDValue RISCVTargetLowering::PerformDAGCombine(SDNode *N,
Op1Lo, Op1Hi, Op0Lo, DAG.getConstant(0, DL, MVT::i32));
return DCI.CombineTo(N, Result.getValue(0), Result.getValue(1));
}
+
+ // (ADDD lo, hi, x, sra(x, 31)) -> (WADDA lo, hi, x, 0)
+ if (isI32SignExtended(Op1Lo, Op1Hi)) {
+ SDValue Result =
+ DAG.getNode(RISCVISD::WADDA, DL, DAG.getVTList(MVT::i32, MVT::i32),
+ Op0Lo, Op0Hi, Op1Lo, DAG.getConstant(0, DL, MVT::i32));
+ return DCI.CombineTo(N, Result.getValue(0), Result.getValue(1));
+ }
+ // (ADDD x, sra(x, 31), lo, hi) -> (WADDA lo, hi, x, 0)
+ if (isI32SignExtended(Op0Lo, Op0Hi)) {
+ SDValue Result =
+ DAG.getNode(RISCVISD::WADDA, DL, DAG.getVTList(MVT::i32, MVT::i32),
+ Op1Lo, Op1Hi, Op0Lo, DAG.getConstant(0, DL, MVT::i32));
+ return DCI.CombineTo(N, Result.getValue(0), Result.getValue(1));
+ }
break;
}
case RISCVISD::SUBD: {
@@ -21755,6 +21779,15 @@ SDValue RISCVTargetLowering::PerformDAGCombine(SDNode *N,
Op0Lo, Op0Hi, DAG.getConstant(0, DL, MVT::i32), Op1Lo);
return DCI.CombineTo(N, Result.getValue(0), Result.getValue(1));
}
+
+ // (SUBD lo, hi, x, sra(x, 31)) -> (WSUBA lo, hi, 0, x)
+ // WSUBA semantics: rd = rd + sext(rs1) - sext(rs2)
+ if (isI32SignExtended(Op1Lo, Op1Hi)) {
+ SDValue Result =
+ DAG.getNode(RISCVISD::WSUBA, 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: {
@@ -21836,6 +21869,57 @@ SDValue RISCVTargetLowering::PerformDAGCombine(SDNode *N,
}
break;
}
+ case RISCVISD::WADDA: {
+ assert(!Subtarget.is64Bit() && Subtarget.hasStdExtP() &&
+ "WADDA 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);
+
+ // Fold a chained accumulate into the free second source slot.
+ if (isNullConstant(Op2) && Op0Lo.getNode() == Op0Hi.getNode() &&
+ Op0Lo.getResNo() == 0 && Op0Hi.getResNo() == 1 && Op0Lo.hasOneUse() &&
+ Op0Hi.hasOneUse()) {
+ // (WADDA (WADDA lo, hi, x, 0), y, 0) -> (WADDA lo, hi, x, y)
+ if (Op0Lo.getOpcode() == RISCVISD::WADDA &&
+ isNullConstant(Op0Lo.getOperand(3))) {
+ SDValue Result = DAG.getNode(
+ RISCVISD::WADDA, 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));
+ }
+ // (WADDA (WSUBA lo, hi, 0, a), b, 0) -> (WSUBA lo, hi, b, a)
+ if (Op0Lo.getOpcode() == RISCVISD::WSUBA &&
+ isNullConstant(Op0Lo.getOperand(2))) {
+ SDValue Result = DAG.getNode(
+ RISCVISD::WSUBA, 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::WSUBA: {
+ assert(!Subtarget.is64Bit() && Subtarget.hasStdExtP() &&
+ "WSUBA 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);
+
+ // (WSUBA (WADDA lo, hi, a, 0), 0, b) -> (WSUBA lo, hi, a, b)
+ if (isNullConstant(Op1) && Op0Lo.getOpcode() == RISCVISD::WADDA &&
+ Op0Lo.getNode() == Op0Hi.getNode() && Op0Lo.getResNo() == 0 &&
+ Op0Hi.getResNo() == 1 && Op0Lo.hasOneUse() && Op0Hi.hasOneUse() &&
+ isNullConstant(Op0Lo.getOperand(3))) {
+ SDValue Result = DAG.getNode(
+ RISCVISD::WSUBA, 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;
+ }
case RISCVISD::FMV_W_X_RV64: {
// If the input to FMV_W_X_RV64 is just FMV_X_ANYEXTW_RV64 the the
// conversion is unnecessary and can be replaced with the
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoP.td b/llvm/lib/Target/RISCV/RISCVInstrInfoP.td
index 60cdc9a3d2539..83095ae1985b4 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoP.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoP.td
@@ -1799,6 +1799,10 @@ def SDT_RISCVWideningAddSubAccumulate : SDTypeProfile<2, 4, [SDTCisVT<0, i32>,
def riscv_waddau : RVSDNode<"WADDAU", SDT_RISCVWideningAddSubAccumulate>;
// Widening sub accumulate unsigned: rd = rd + zext(rs1) - zext(rs2)
def riscv_wsubau : RVSDNode<"WSUBAU", SDT_RISCVWideningAddSubAccumulate>;
+// Widening add accumulate signed: rd = rd + sext(rs1) + sext(rs2)
+def riscv_wadda : RVSDNode<"WADDA", SDT_RISCVWideningAddSubAccumulate>;
+// Widening sub accumulate signed: rd = rd + sext(rs1) - sext(rs2)
+def riscv_wsuba : RVSDNode<"WSUBA", SDT_RISCVWideningAddSubAccumulate>;
def riscv_waddu : RVSDNode<"WADDU", SDTIntBinHiLoOp, [SDNPCommutative]>;
def riscv_wsubu : RVSDNode<"WSUBU", SDTIntBinHiLoOp>;
diff --git a/llvm/test/CodeGen/RISCV/rv32p.ll b/llvm/test/CodeGen/RISCV/rv32p.ll
index aca224c397ad2..63cdf8ee0ded1 100644
--- a/llvm/test/CodeGen/RISCV/rv32p.ll
+++ b/llvm/test/CodeGen/RISCV/rv32p.ll
@@ -1690,6 +1690,78 @@ define i64 @wsubau_zext_chain_rev(i64 %acc, i32 %a, i32 %b) nounwind {
ret i64 %sum
}
+; acc + sext(a) -> wadda acc, a, 0
+define i64 @wadda_sext(i64 %acc, i32 %a) nounwind {
+; CHECK-LABEL: wadda_sext:
+; CHECK: # %bb.0:
+; CHECK-NEXT: wadda a0, a2, zero
+; CHECK-NEXT: ret
+ %ext_a = sext i32 %a to i64
+ %sum = add i64 %acc, %ext_a
+ ret i64 %sum
+}
+
+; sext(a) + acc -> wadda acc, a, 0
+define i64 @wadda_sext_commuted(i64 %acc, i32 %a) nounwind {
+; CHECK-LABEL: wadda_sext_commuted:
+; CHECK: # %bb.0:
+; CHECK-NEXT: wadda a0, a2, zero
+; CHECK-NEXT: ret
+ %ext_a = sext i32 %a to i64
+ %sum = add i64 %ext_a, %acc
+ ret i64 %sum
+}
+
+; acc + sext(a) + sext(b) -> wadda acc, a, b
+define i64 @wadda_sext_chain(i64 %acc, i32 %a, i32 %b) nounwind {
+; CHECK-LABEL: wadda_sext_chain:
+; CHECK: # %bb.0:
+; CHECK-NEXT: wadda a0, a2, a3
+; CHECK-NEXT: ret
+ %ext_a = sext i32 %a to i64
+ %ext_b = sext i32 %b to i64
+ %sum1 = add i64 %acc, %ext_a
+ %sum2 = add i64 %sum1, %ext_b
+ ret i64 %sum2
+}
+
+; acc - sext(a) -> wsuba acc, 0, a
+define i64 @wsuba_sext(i64 %acc, i32 %a) nounwind {
+; CHECK-LABEL: wsuba_sext:
+; CHECK: # %bb.0:
+; CHECK-NEXT: wsuba a0, zero, a2
+; CHECK-NEXT: ret
+ %ext_a = sext i32 %a to i64
+ %sub = sub i64 %acc, %ext_a
+ ret i64 %sub
+}
+
+; (acc + sext(a)) - sext(b) -> wsuba acc, a, b
+define i64 @wsuba_sext_chain(i64 %acc, i32 %a, i32 %b) nounwind {
+; CHECK-LABEL: wsuba_sext_chain:
+; CHECK: # %bb.0:
+; CHECK-NEXT: wsuba a0, a2, a3
+; CHECK-NEXT: ret
+ %ext_a = sext i32 %a to i64
+ %ext_b = sext i32 %b to i64
+ %sum = add i64 %acc, %ext_a
+ %sub = sub i64 %sum, %ext_b
+ ret i64 %sub
+}
+
+; (acc - sext(a)) + sext(b) -> wsuba acc, b, a
+define i64 @wsuba_sext_chain_rev(i64 %acc, i32 %a, i32 %b) nounwind {
+; CHECK-LABEL: wsuba_sext_chain_rev:
+; CHECK: # %bb.0:
+; CHECK-NEXT: wsuba a0, a3, a2
+; CHECK-NEXT: ret
+ %ext_a = sext i32 %a to i64
+ %ext_b = sext i32 %b to i64
+ %sub = sub i64 %acc, %ext_a
+ %sum = add i64 %sub, %ext_b
+ ret i64 %sum
+}
+
define i64 @waddu(i32 %a, i32 %b) nounwind {
; CHECK-LABEL: waddu:
; CHECK: # %bb.0:
More information about the llvm-commits
mailing list