[llvm] [RISCV] Fold (WADDAU -C, -1, rs1, 0) -> (WSUBU rs1, C) where C > 0 (PR #186638)

Craig Topper via llvm-commits llvm-commits at lists.llvm.org
Sat Mar 14 20:27:23 PDT 2026


https://github.com/topperc created https://github.com/llvm/llvm-project/pull/186638

Stacked on #186635

>From 2310bf692dfbbd410c0a25c9dba48e927837302f Mon Sep 17 00:00:00 2001
From: Craig Topper <craig.topper at sifive.com>
Date: Sat, 14 Mar 2026 18:27:07 -0700
Subject: [PATCH 1/4] Pre-commit tests

---
 llvm/test/CodeGen/RISCV/rv32p.ll | 26 ++++++++++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/llvm/test/CodeGen/RISCV/rv32p.ll b/llvm/test/CodeGen/RISCV/rv32p.ll
index fdc7d98e5d833..7b66d5e81f6d0 100644
--- a/llvm/test/CodeGen/RISCV/rv32p.ll
+++ b/llvm/test/CodeGen/RISCV/rv32p.ll
@@ -1210,3 +1210,29 @@ define i64 @wsubau_zext_chain_rev(i64 %acc, i32 %a, i32 %b) nounwind {
   %sum = add i64 %sub, %ext_b
   ret i64 %sum
 }
+
+define i64 @waddu(i32 %a, i32 %b) nounwind {
+; CHECK-LABEL: waddu:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    mv a2, a1
+; CHECK-NEXT:    li a1, 0
+; CHECK-NEXT:    waddau a0, a2, zero
+; CHECK-NEXT:    ret
+  %ext_a = zext i32 %a to i64
+  %ext_b = zext i32 %b to i64
+  %sum = add i64 %ext_a, %ext_b
+  ret i64 %sum
+}
+
+define i64 @wsubu(i32 %a, i32 %b) nounwind {
+; CHECK-LABEL: wsubu:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    mv a2, a1
+; CHECK-NEXT:    li a1, 0
+; CHECK-NEXT:    wsubau a0, zero, a2
+; CHECK-NEXT:    ret
+  %ext_a = zext i32 %a to i64
+  %ext_b = zext i32 %b to i64
+  %diff = sub i64 %ext_a, %ext_b
+  ret i64 %diff
+}

>From a49f5709691bf174ae554adc536591b1f1875ab8 Mon Sep 17 00:00:00 2001
From: Craig Topper <craig.topper at sifive.com>
Date: Sat, 14 Mar 2026 19:04:39 -0700
Subject: [PATCH 2/4] [RISCV] Fold waddau/wsubau to waddu/wsubu when possible

If the wide input is zero extended and only one narrow input is
used, we can fold to waddu/wsubu.
---
 llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp | 15 +++++++++++----
 llvm/lib/Target/RISCV/RISCVISelLowering.cpp | 14 ++++++++++++++
 llvm/lib/Target/RISCV/RISCVInstrInfoP.td    |  3 +++
 llvm/test/CodeGen/RISCV/rv32p.ll            |  8 ++------
 4 files changed, 30 insertions(+), 10 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
index 76ecd4fccfd85..4a81f87153ff2 100644
--- a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
@@ -1842,8 +1842,9 @@ void RISCVDAGToDAGISel::Select(SDNode *Node) {
   }
   case ISD::SMUL_LOHI:
   case ISD::UMUL_LOHI:
-  case RISCVISD::WMULSU: {
-    // Custom select (S/U)MUL_LOHI to WMUL(U) for RV32P.
+  case RISCVISD::WMULSU:
+  case RISCVISD::WADDU:
+  case RISCVISD::WSUBU: {
     assert(Subtarget->hasStdExtP() && !Subtarget->is64Bit() && VT == MVT::i32 &&
            "Unexpected opcode");
 
@@ -1860,12 +1861,18 @@ void RISCVDAGToDAGISel::Select(SDNode *Node) {
     case RISCVISD::WMULSU:
       Opc = RISCV::WMULSU;
       break;
+    case RISCVISD::WADDU:
+      Opc = RISCV::WADDU;
+      break;
+    case RISCVISD::WSUBU:
+      Opc = RISCV::WSUBU;
+      break;
     }
 
-    SDNode *WMUL = CurDAG->getMachineNode(
+    SDNode *Result = CurDAG->getMachineNode(
         Opc, DL, MVT::Untyped, Node->getOperand(0), Node->getOperand(1));
 
-    auto [Lo, Hi] = extractGPRPair(CurDAG, DL, SDValue(WMUL, 0));
+    auto [Lo, Hi] = extractGPRPair(CurDAG, DL, SDValue(Result, 0));
     ReplaceUses(SDValue(Node, 0), Lo);
     ReplaceUses(SDValue(Node, 1), Hi);
     CurDAG->RemoveDeadNode(Node);
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index 5156145e35aa2..0dd14aae4b6fa 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -21613,6 +21613,13 @@ SDValue RISCVTargetLowering::PerformDAGCombine(SDNode *N,
     SDValue Op1 = N->getOperand(2);
     SDValue Op2 = N->getOperand(3);
 
+    // (WADDAU lo, 0, rs1, 0) -> (WADDU lo, rs1)
+    if (isNullConstant(Op0Hi) && isNullConstant(Op2)) {
+      SDValue Result = DAG.getNode(
+          RISCVISD::WADDU, DL, DAG.getVTList(MVT::i32, MVT::i32), Op0Lo, Op1);
+      return DCI.CombineTo(N, Result.getValue(0), Result.getValue(1));
+    }
+
     // FIXME: Canonicalize zero Op1 to Op2.
     if (isNullConstant(Op2) && Op0Lo.getNode() == Op0Hi.getNode() &&
         Op0Lo.getResNo() == 0 && Op0Hi.getResNo() == 1 && Op0Lo.hasOneUse() &&
@@ -21644,6 +21651,13 @@ SDValue RISCVTargetLowering::PerformDAGCombine(SDNode *N,
     SDValue Op1 = N->getOperand(2);
     SDValue Op2 = N->getOperand(3);
 
+    // (WSUBAU lo, 0, 0, rs2) -> (WSUBU lo, rs2)
+    if (isNullConstant(Op0Hi) && isNullConstant(Op1)) {
+      SDValue Result = DAG.getNode(
+          RISCVISD::WSUBU, DL, DAG.getVTList(MVT::i32, MVT::i32), Op0Lo, Op2);
+      return DCI.CombineTo(N, Result.getValue(0), Result.getValue(1));
+    }
+
     // (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 &&
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoP.td b/llvm/lib/Target/RISCV/RISCVInstrInfoP.td
index 23950c4478a1b..788ecda2a1df1 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoP.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoP.td
@@ -1631,6 +1631,9 @@ 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_waddu : RVSDNode<"WADDU", SDTIntBinHiLoOp, [SDNPCommutative]>;
+def riscv_wsubu : RVSDNode<"WSUBU", SDTIntBinHiLoOp>;
+
 def riscv_wmulsu : RVSDNode<"WMULSU", SDTIntBinHiLoOp>;
 
 def SDT_RISCVWideningShiftLeft : SDTypeProfile<2, 2, [SDTCisVT<0, i32>,
diff --git a/llvm/test/CodeGen/RISCV/rv32p.ll b/llvm/test/CodeGen/RISCV/rv32p.ll
index 7b66d5e81f6d0..d47cb57b84c41 100644
--- a/llvm/test/CodeGen/RISCV/rv32p.ll
+++ b/llvm/test/CodeGen/RISCV/rv32p.ll
@@ -1214,9 +1214,7 @@ define i64 @wsubau_zext_chain_rev(i64 %acc, i32 %a, i32 %b) nounwind {
 define i64 @waddu(i32 %a, i32 %b) nounwind {
 ; CHECK-LABEL: waddu:
 ; CHECK:       # %bb.0:
-; CHECK-NEXT:    mv a2, a1
-; CHECK-NEXT:    li a1, 0
-; CHECK-NEXT:    waddau a0, a2, zero
+; CHECK-NEXT:    waddu a0, a0, a1
 ; CHECK-NEXT:    ret
   %ext_a = zext i32 %a to i64
   %ext_b = zext i32 %b to i64
@@ -1227,9 +1225,7 @@ define i64 @waddu(i32 %a, i32 %b) nounwind {
 define i64 @wsubu(i32 %a, i32 %b) nounwind {
 ; CHECK-LABEL: wsubu:
 ; CHECK:       # %bb.0:
-; CHECK-NEXT:    mv a2, a1
-; CHECK-NEXT:    li a1, 0
-; CHECK-NEXT:    wsubau a0, zero, a2
+; CHECK-NEXT:    wsubu a0, a0, a1
 ; CHECK-NEXT:    ret
   %ext_a = zext i32 %a to i64
   %ext_b = zext i32 %b to i64

>From 6713782dfb6f1e1563a24938b1c8eadf1d169f9f Mon Sep 17 00:00:00 2001
From: Craig Topper <craig.topper at sifive.com>
Date: Sat, 14 Mar 2026 20:15:11 -0700
Subject: [PATCH 3/4] Precommit test

---
 llvm/test/CodeGen/RISCV/rv32p.ll | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/llvm/test/CodeGen/RISCV/rv32p.ll b/llvm/test/CodeGen/RISCV/rv32p.ll
index d47cb57b84c41..3f53a271f2873 100644
--- a/llvm/test/CodeGen/RISCV/rv32p.ll
+++ b/llvm/test/CodeGen/RISCV/rv32p.ll
@@ -1232,3 +1232,16 @@ define i64 @wsubu(i32 %a, i32 %b) nounwind {
   %diff = sub i64 %ext_a, %ext_b
   ret i64 %diff
 }
+
+define i64 @wsub_from_neg_const(i32 %a) nounwind {
+; CHECK-LABEL: wsub_from_neg_const:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    mv a2, a0
+; CHECK-NEXT:    li a1, -1
+; CHECK-NEXT:    li a0, -42
+; CHECK-NEXT:    waddau a0, a2, zero
+; CHECK-NEXT:    ret
+  %ext_a = zext i32 %a to i64
+  %sum = add i64 %ext_a, -42
+  ret i64 %sum
+}

>From b0ecb93a49bed9f1598defd78a32b18181706c5a Mon Sep 17 00:00:00 2001
From: Craig Topper <craig.topper at sifive.com>
Date: Sat, 14 Mar 2026 20:25:36 -0700
Subject: [PATCH 4/4] [RISCV] Fold (WADDAU -C, -1, rs1, 0) -> (WSUBU rs1, C)
 where C > 0

---
 llvm/lib/Target/RISCV/RISCVISelLowering.cpp | 14 ++++++++++++++
 llvm/test/CodeGen/RISCV/rv32p.ll            | 15 ++++++---------
 2 files changed, 20 insertions(+), 9 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index 0dd14aae4b6fa..eb253052a0b2a 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -21620,6 +21620,20 @@ SDValue RISCVTargetLowering::PerformDAGCombine(SDNode *N,
       return DCI.CombineTo(N, Result.getValue(0), Result.getValue(1));
     }
 
+    // (WADDAU -C, -1, rs1, 0) -> (WSUBU rs1, C) where C > 0
+    if (isNullConstant(Op2) && isAllOnesConstant(Op0Hi)) {
+      if (auto *C0 = dyn_cast<ConstantSDNode>(Op0Lo)) {
+        int64_t Val = C0->getSExtValue();
+        if (Val < 0) {
+          SDValue PosConst = DAG.getConstant(-Val, DL, MVT::i32);
+          SDValue Result =
+              DAG.getNode(RISCVISD::WSUBU, DL,
+                          DAG.getVTList(MVT::i32, MVT::i32), Op1, PosConst);
+          return DCI.CombineTo(N, Result.getValue(0), Result.getValue(1));
+        }
+      }
+    }
+
     // FIXME: Canonicalize zero Op1 to Op2.
     if (isNullConstant(Op2) && Op0Lo.getNode() == Op0Hi.getNode() &&
         Op0Lo.getResNo() == 0 && Op0Hi.getResNo() == 1 && Op0Lo.hasOneUse() &&
diff --git a/llvm/test/CodeGen/RISCV/rv32p.ll b/llvm/test/CodeGen/RISCV/rv32p.ll
index 3f53a271f2873..4d009ef9ca76b 100644
--- a/llvm/test/CodeGen/RISCV/rv32p.ll
+++ b/llvm/test/CodeGen/RISCV/rv32p.ll
@@ -186,15 +186,14 @@ define i64 @cls_i64(i64 %x) {
 ; CHECK-NEXT:  # %bb.1:
 ; CHECK-NEXT:    xor a0, a0, a2
 ; CHECK-NEXT:    clz a0, a0
-; CHECK-NEXT:    addi a2, a0, 32
+; CHECK-NEXT:    addi a0, a0, 32
 ; CHECK-NEXT:    j .LBB15_3
 ; CHECK-NEXT:  .LBB15_2:
 ; CHECK-NEXT:    xor a1, a1, a2
-; CHECK-NEXT:    clz a2, a1
+; CHECK-NEXT:    clz a0, a1
 ; CHECK-NEXT:  .LBB15_3:
-; CHECK-NEXT:    li a0, -1
-; CHECK-NEXT:    mv a1, a0
-; CHECK-NEXT:    waddau a0, a2, zero
+; CHECK-NEXT:    li a1, 1
+; CHECK-NEXT:    wsubu a0, a0, a1
 ; CHECK-NEXT:    ret
   %a = ashr i64 %x, 63
   %b = xor i64 %x, %a
@@ -1236,10 +1235,8 @@ define i64 @wsubu(i32 %a, i32 %b) nounwind {
 define i64 @wsub_from_neg_const(i32 %a) nounwind {
 ; CHECK-LABEL: wsub_from_neg_const:
 ; CHECK:       # %bb.0:
-; CHECK-NEXT:    mv a2, a0
-; CHECK-NEXT:    li a1, -1
-; CHECK-NEXT:    li a0, -42
-; CHECK-NEXT:    waddau a0, a2, zero
+; CHECK-NEXT:    li a1, 42
+; CHECK-NEXT:    wsubu a0, a0, a1
 ; CHECK-NEXT:    ret
   %ext_a = zext i32 %a to i64
   %sum = add i64 %ext_a, -42



More information about the llvm-commits mailing list