[llvm] [RISCV] In tryWideningMulAcc, check multiple users before checking operand 1. (PR #181321)

Craig Topper via llvm-commits llvm-commits at lists.llvm.org
Fri Feb 13 09:04:22 PST 2026


https://github.com/topperc updated https://github.com/llvm/llvm-project/pull/181321

>From a3c5a081d0305fcc9fad5d4441aa774ac228d9b1 Mon Sep 17 00:00:00 2001
From: Craig Topper <craig.topper at sifive.com>
Date: Thu, 12 Feb 2026 23:02:36 -0800
Subject: [PATCH 1/2] [RISCV] In tryWideningMulAcc, check multiple users before
 checking operand 1.

If both operands are WMUL, we should still consider the second
one if the first one has multiple users.
---
 llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp | 27 ++++++++++-----------
 llvm/test/CodeGen/RISCV/rv32p.ll            | 26 ++++++++++++++++++++
 2 files changed, 39 insertions(+), 14 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
index 021fe05a3d7fd..f879ca80c98b8 100644
--- a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
@@ -918,34 +918,33 @@ bool RISCVDAGToDAGISel::tryWideningMulAcc(SDNode *Node, const SDLoc &DL) {
   SDValue Op1Lo = Node->getOperand(2);
   SDValue Op1Hi = Node->getOperand(3);
 
-  auto IsSupportedMul = [](unsigned Opc) {
-    return Opc == ISD::UMUL_LOHI || Opc == ISD::SMUL_LOHI ||
-           Opc == RISCVISD::WMULSU;
+  auto IsSupportedMulWithOneUse = [](SDValue Lo, SDValue Hi) {
+    unsigned Opc = Lo.getOpcode();
+    if (Opc != ISD::UMUL_LOHI && Opc != ISD::SMUL_LOHI &&
+        Opc != RISCVISD::WMULSU)
+      return false;
+    return Lo.getNode() == Hi.getNode() && Lo.getResNo() == 0 &&
+           Hi.getResNo() == 1 && Lo.hasOneUse() && Hi.hasOneUse();
   };
 
   SDNode *MulNode = nullptr;
   SDValue AddLo, AddHi;
 
-  // Check if first operand pair is a supported multiply.
-  if (IsSupportedMul(Op0Lo.getOpcode()) && Op0Lo.getNode() == Op0Hi.getNode() &&
-      Op0Lo.getResNo() == 0 && Op0Hi.getResNo() == 1) {
+  // Check if first operand pair is a supported multiply with single use.
+  if (IsSupportedMulWithOneUse(Op0Lo, Op0Hi)) {
     MulNode = Op0Lo.getNode();
     AddLo = Op1Lo;
     AddHi = Op1Hi;
   }
-  // ADDD is commutative. Check if second operand pair is a supported multiply.
-  else if (IsSupportedMul(Op1Lo.getOpcode()) &&
-           Op1Lo.getNode() == Op1Hi.getNode() && Op1Lo.getResNo() == 0 &&
-           Op1Hi.getResNo() == 1) {
+  // ADDD is commutative. Check if second operand pair is a supported multiply
+  // with single use.
+  else if (IsSupportedMulWithOneUse(Op1Lo, Op1Hi)) {
     MulNode = Op1Lo.getNode();
     AddLo = Op0Lo;
     AddHi = Op0Hi;
   }
 
-  // Check that we found a multiply and this is the only user.
-  // FIXME: We should check the use count before trying to commuted case.
-  if (!MulNode || !SDValue(MulNode, 0).hasOneUse() ||
-      !SDValue(MulNode, 1).hasOneUse())
+  if (!MulNode)
     return false;
 
   unsigned Opc;
diff --git a/llvm/test/CodeGen/RISCV/rv32p.ll b/llvm/test/CodeGen/RISCV/rv32p.ll
index 3f6b3e8184cf0..b4f13b8eb223b 100644
--- a/llvm/test/CodeGen/RISCV/rv32p.ll
+++ b/llvm/test/CodeGen/RISCV/rv32p.ll
@@ -915,6 +915,32 @@ define void @wmaccu_multiple_uses(i32 %a, i32 %b, i64 %c, ptr %out1, ptr %out2)
   ret void
 }
 
+; First multiply has multiple uses, but second multiply has single use.
+; Make sure we fold the second multiply into wmacc.
+define i64 @wmacc_first_mul_multiple_uses(i32 %a, i32 %b, i32 %c, i32 %d, ptr %out) nounwind {
+; CHECK-LABEL: wmacc_first_mul_multiple_uses:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    wmul a2, a2, a3
+; CHECK-NEXT:    mv a5, a3
+; CHECK-NEXT:    mv a6, a2
+; CHECK-NEXT:    wmacc a2, a0, a1
+; CHECK-NEXT:    sw a6, 0(a4)
+; CHECK-NEXT:    sw a5, 4(a4)
+; CHECK-NEXT:    mv a0, a2
+; CHECK-NEXT:    mv a1, a3
+; CHECK-NEXT:    ret
+  %aext = sext i32 %a to i64
+  %bext = sext i32 %b to i64
+  %cext = sext i32 %c to i64
+  %dext = sext i32 %d to i64
+  %mul1 = mul i64 %aext, %bext
+  %mul2 = mul i64 %cext, %dext
+  ; mul2 is first operand (has multiple uses), mul1 is second (single use)
+  %result = add i64 %mul2, %mul1
+  store i64 %mul2, ptr %out
+  ret i64 %result
+}
+
 ; Test bitwise merge: (mask & b) | (~mask & a)
 define i32 @merge_i32(i32 %mask, i32 %a, i32 %b) nounwind {
 ; CHECK-LABEL: merge_i32:

>From 130361e1e96f3bfa348be426dd926c907796baf0 Mon Sep 17 00:00:00 2001
From: Craig Topper <craig.topper at sifive.com>
Date: Fri, 13 Feb 2026 09:03:57 -0800
Subject: [PATCH 2/2] fixup! address review comment

---
 llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
index f879ca80c98b8..bcc1939605e3b 100644
--- a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
@@ -942,10 +942,9 @@ bool RISCVDAGToDAGISel::tryWideningMulAcc(SDNode *Node, const SDLoc &DL) {
     MulNode = Op1Lo.getNode();
     AddLo = Op0Lo;
     AddHi = Op0Hi;
-  }
-
-  if (!MulNode)
+  } else {
     return false;
+  }
 
   unsigned Opc;
   switch (MulNode->getOpcode()) {



More information about the llvm-commits mailing list