[llvm] [RISCV] Add ISel patterns for Xqciac QC.MULIADD instruction (PR #147661)

Sudharsan Veeravalli via llvm-commits llvm-commits at lists.llvm.org
Thu Jul 10 22:04:10 PDT 2025


https://github.com/svs-quic updated https://github.com/llvm/llvm-project/pull/147661

>From 8e748ac033539f8e9523c7c09398856444bbb1a8 Mon Sep 17 00:00:00 2001
From: Sudharsan Veeravalli <quic_svs at quicinc.com>
Date: Wed, 9 Jul 2025 11:57:31 +0530
Subject: [PATCH 1/5] [RISCV] Add ISel patterns for Xqciac QC.MULIADD
 instruction

Add basic isel patterns for the multiple accumulate QC.MULIADD instruction.
---
 llvm/lib/Target/RISCV/RISCVISelLowering.cpp |  11 ++
 llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td |   5 +
 llvm/test/CodeGen/RISCV/xqciac.ll           | 177 ++++++++++++++++++++
 3 files changed, 193 insertions(+)
 create mode 100644 llvm/test/CodeGen/RISCV/xqciac.ll

diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index 98b613d9cc856..f586ff609ca16 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -15895,6 +15895,13 @@ static SDValue expandMulToNAFSequence(SDNode *N, SelectionDAG &DAG,
 // X * (2^N +/- 2^M) -> (add/sub (shl X, C1), (shl X, C2))
 static SDValue expandMulToAddOrSubOfShl(SDNode *N, SelectionDAG &DAG,
                                         uint64_t MulAmt) {
+  // Don't do this is if the Xqciac extension is enabled and the MulAmt is
+  // simm12.
+  const RISCVSubtarget &Subtarget =
+      DAG.getMachineFunction().getSubtarget<RISCVSubtarget>();
+  if (Subtarget.hasVendorXqciac() && isInt<12>(MulAmt))
+    return SDValue();
+
   uint64_t MulAmtLowBit = MulAmt & (-MulAmt);
   ISD::NodeType Op;
   uint64_t ShiftAmt1;
@@ -23700,6 +23707,10 @@ bool RISCVTargetLowering::decomposeMulByConstant(LLVMContext &Context, EVT VT,
   auto *ConstNode = cast<ConstantSDNode>(C);
   const APInt &Imm = ConstNode->getAPIntValue();
 
+  // Don't do this if the Xqciac extension is enabled and the Imm in simm12.
+  if (Subtarget.hasVendorXqciac() && Imm.isSignedIntN(12))
+    return false;
+
   // Break the MUL to a SLLI and an ADD/SUB.
   if ((Imm + 1).isPowerOf2() || (Imm - 1).isPowerOf2() ||
       (1 - Imm).isPowerOf2() || (-1 - Imm).isPowerOf2())
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td b/llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td
index b2bf09028bc40..3d0712baf6940 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td
@@ -1332,6 +1332,11 @@ class SelectQCbi<CondCode Cond, DAGOperand InTyImm, Pseudo OpNode >
           (OpNode GPRNoX0:$lhs, InTyImm:$Constant,
            (IntCCtoRISCVCC $cc), GPRNoX0:$truev, GPRNoX0:$falsev)>;
 
+let Predicates = [HasVendorXqciac, IsRV32] in {
+def : Pat<(XLenVT (add GPRNoX0:$rd, (mul GPRNoX0:$rs1, simm12:$imm12))),
+          (QC_MULIADD GPRNoX0:$rd, GPRNoX0:$rs1, simm12:$imm12)>;
+} // Predicates = [HasVendorXqciac, IsRV32]
+
 /// Simple arithmetic operations
 
 let Predicates = [HasVendorXqcilia, IsRV32] in {
diff --git a/llvm/test/CodeGen/RISCV/xqciac.ll b/llvm/test/CodeGen/RISCV/xqciac.ll
new file mode 100644
index 0000000000000..2822d1a98afea
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/xqciac.ll
@@ -0,0 +1,177 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc -mtriple=riscv32 -mattr=+m -verify-machineinstrs < %s \
+; RUN: | FileCheck %s -check-prefix=RV32IM
+; RUN: llc -mtriple=riscv32 -mattr=+m,+experimental-xqciac -verify-machineinstrs < %s \
+; RUN: | FileCheck %s -check-prefix=RV32IMXQCIAC
+; RUN: llc -mtriple=riscv32 -mattr=+m,+experimental-xqciac,+zba -verify-machineinstrs < %s \
+; RUN: | FileCheck %s -check-prefix=RV32IZBAMXQCIAC
+
+define dso_local i32 @mul(i32 %a, i32 %b) local_unnamed_addr #0 {
+; RV32IM-LABEL: mul:
+; RV32IM:       # %bb.0: # %entry
+; RV32IM-NEXT:    slli a0, a1, 5
+; RV32IM-NEXT:    add a0, a0, a1
+; RV32IM-NEXT:    ret
+;
+; RV32IMXQCIAC-LABEL: mul:
+; RV32IMXQCIAC:       # %bb.0: # %entry
+; RV32IMXQCIAC-NEXT:    li a0, 33
+; RV32IMXQCIAC-NEXT:    mul a0, a1, a0
+; RV32IMXQCIAC-NEXT:    ret
+;
+; RV32IZBAMXQCIAC-LABEL: mul:
+; RV32IZBAMXQCIAC:       # %bb.0: # %entry
+; RV32IZBAMXQCIAC-NEXT:    li a0, 33
+; RV32IZBAMXQCIAC-NEXT:    mul a0, a1, a0
+; RV32IZBAMXQCIAC-NEXT:    ret
+entry:
+  %mul = mul nsw i32 %b, 33
+  ret i32 %mul
+}
+
+define dso_local i32 @muliadd(i32 %a, i32 %b) local_unnamed_addr #0 {
+; RV32IM-LABEL: muliadd:
+; RV32IM:       # %bb.0: # %entry
+; RV32IM-NEXT:    li a2, 165
+; RV32IM-NEXT:    mul a1, a1, a2
+; RV32IM-NEXT:    add a0, a1, a0
+; RV32IM-NEXT:    ret
+;
+; RV32IMXQCIAC-LABEL: muliadd:
+; RV32IMXQCIAC:       # %bb.0: # %entry
+; RV32IMXQCIAC-NEXT:    qc.muliadd a0, a1, 165
+; RV32IMXQCIAC-NEXT:    ret
+;
+; RV32IZBAMXQCIAC-LABEL: muliadd:
+; RV32IZBAMXQCIAC:       # %bb.0: # %entry
+; RV32IZBAMXQCIAC-NEXT:    qc.muliadd a0, a1, 165
+; RV32IZBAMXQCIAC-NEXT:    ret
+entry:
+  %mul = mul nsw i32 %b, 165
+  %add = add nsw i32 %mul, %a
+  ret i32 %add
+}
+
+define dso_local i32 @muliadd_neg(i32 %a, i32 %b) local_unnamed_addr #0 {
+; RV32IM-LABEL: muliadd_neg:
+; RV32IM:       # %bb.0: # %entry
+; RV32IM-NEXT:    li a2, -165
+; RV32IM-NEXT:    mul a1, a1, a2
+; RV32IM-NEXT:    add a0, a1, a0
+; RV32IM-NEXT:    ret
+;
+; RV32IMXQCIAC-LABEL: muliadd_neg:
+; RV32IMXQCIAC:       # %bb.0: # %entry
+; RV32IMXQCIAC-NEXT:    qc.muliadd a0, a1, -165
+; RV32IMXQCIAC-NEXT:    ret
+;
+; RV32IZBAMXQCIAC-LABEL: muliadd_neg:
+; RV32IZBAMXQCIAC:       # %bb.0: # %entry
+; RV32IZBAMXQCIAC-NEXT:    qc.muliadd a0, a1, -165
+; RV32IZBAMXQCIAC-NEXT:    ret
+entry:
+  %mul = mul nsw i32 %b, -165
+  %add = add nsw i32 %mul, %a
+  ret i32 %add
+}
+
+define dso_local i32 @pow2immplus1(i32 %a, i32 %b) local_unnamed_addr #0 {
+; RV32IM-LABEL: pow2immplus1:
+; RV32IM:       # %bb.0: # %entry
+; RV32IM-NEXT:    slli a2, a1, 5
+; RV32IM-NEXT:    add a0, a1, a0
+; RV32IM-NEXT:    add a0, a2, a0
+; RV32IM-NEXT:    ret
+;
+; RV32IMXQCIAC-LABEL: pow2immplus1:
+; RV32IMXQCIAC:       # %bb.0: # %entry
+; RV32IMXQCIAC-NEXT:    qc.muliadd a0, a1, 33
+; RV32IMXQCIAC-NEXT:    ret
+;
+; RV32IZBAMXQCIAC-LABEL: pow2immplus1:
+; RV32IZBAMXQCIAC:       # %bb.0: # %entry
+; RV32IZBAMXQCIAC-NEXT:    qc.muliadd a0, a1, 33
+; RV32IZBAMXQCIAC-NEXT:    ret
+entry:
+  %mul = mul nsw i32 %b, 33
+  %add = add nsw i32 %mul, %a
+  ret i32 %add
+}
+
+define dso_local i32 @gtsimm12(i32 %a, i32 %b) local_unnamed_addr #0 {
+; RV32IM-LABEL: gtsimm12:
+; RV32IM:       # %bb.0: # %entry
+; RV32IM-NEXT:    lui a2, 1
+; RV32IM-NEXT:    addi a2, a2, 477
+; RV32IM-NEXT:    mul a1, a1, a2
+; RV32IM-NEXT:    add a0, a1, a0
+; RV32IM-NEXT:    ret
+;
+; RV32IMXQCIAC-LABEL: gtsimm12:
+; RV32IMXQCIAC:       # %bb.0: # %entry
+; RV32IMXQCIAC-NEXT:    lui a2, 1
+; RV32IMXQCIAC-NEXT:    addi a2, a2, 477
+; RV32IMXQCIAC-NEXT:    mul a1, a1, a2
+; RV32IMXQCIAC-NEXT:    add a0, a0, a1
+; RV32IMXQCIAC-NEXT:    ret
+;
+; RV32IZBAMXQCIAC-LABEL: gtsimm12:
+; RV32IZBAMXQCIAC:       # %bb.0: # %entry
+; RV32IZBAMXQCIAC-NEXT:    lui a2, 1
+; RV32IZBAMXQCIAC-NEXT:    addi a2, a2, 477
+; RV32IZBAMXQCIAC-NEXT:    mul a1, a1, a2
+; RV32IZBAMXQCIAC-NEXT:    add a0, a0, a1
+; RV32IZBAMXQCIAC-NEXT:    ret
+entry:
+  %mul = mul nsw i32 %b, 4573
+  %add = add nsw i32 %mul, %a
+  ret i32 %add
+}
+
+; NOTE: This will become qc.shladd once support is added
+define dso_local i32 @pow2(i32 %a, i32 %b) local_unnamed_addr #0 {
+; RV32IM-LABEL: pow2:
+; RV32IM:       # %bb.0: # %entry
+; RV32IM-NEXT:    slli a1, a1, 5
+; RV32IM-NEXT:    add a0, a1, a0
+; RV32IM-NEXT:    ret
+;
+; RV32IMXQCIAC-LABEL: pow2:
+; RV32IMXQCIAC:       # %bb.0: # %entry
+; RV32IMXQCIAC-NEXT:    slli a1, a1, 5
+; RV32IMXQCIAC-NEXT:    add a0, a0, a1
+; RV32IMXQCIAC-NEXT:    ret
+;
+; RV32IZBAMXQCIAC-LABEL: pow2:
+; RV32IZBAMXQCIAC:       # %bb.0: # %entry
+; RV32IZBAMXQCIAC-NEXT:    slli a1, a1, 5
+; RV32IZBAMXQCIAC-NEXT:    add a0, a0, a1
+; RV32IZBAMXQCIAC-NEXT:    ret
+entry:
+  %mul = mul nsw i32 %b, 32
+  %add = add nsw i32 %mul, %a
+  ret i32 %add
+}
+
+define dso_local i32 @shxadd(i32 %a, i32 %b) local_unnamed_addr #0 {
+; RV32IM-LABEL: shxadd:
+; RV32IM:       # %bb.0: # %entry
+; RV32IM-NEXT:    slli a1, a1, 1
+; RV32IM-NEXT:    add a0, a1, a0
+; RV32IM-NEXT:    ret
+;
+; RV32IMXQCIAC-LABEL: shxadd:
+; RV32IMXQCIAC:       # %bb.0: # %entry
+; RV32IMXQCIAC-NEXT:    slli a1, a1, 1
+; RV32IMXQCIAC-NEXT:    add a0, a0, a1
+; RV32IMXQCIAC-NEXT:    ret
+;
+; RV32IZBAMXQCIAC-LABEL: shxadd:
+; RV32IZBAMXQCIAC:       # %bb.0: # %entry
+; RV32IZBAMXQCIAC-NEXT:    sh1add a0, a1, a0
+; RV32IZBAMXQCIAC-NEXT:    ret
+entry:
+  %mul = mul nsw i32 %b, 2
+  %add = add nsw i32 %mul, %a
+  ret i32 %add
+}

>From 0201aea0adcfc0d8c44b46a0c582497b6d9b07e3 Mon Sep 17 00:00:00 2001
From: Sudharsan Veeravalli <quic_svs at quicinc.com>
Date: Wed, 9 Jul 2025 15:49:49 +0530
Subject: [PATCH 2/5] getSubtarget

---
 llvm/lib/Target/RISCV/RISCVISelLowering.cpp | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index f586ff609ca16..da329a8047a42 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -15897,8 +15897,7 @@ static SDValue expandMulToAddOrSubOfShl(SDNode *N, SelectionDAG &DAG,
                                         uint64_t MulAmt) {
   // Don't do this is if the Xqciac extension is enabled and the MulAmt is
   // simm12.
-  const RISCVSubtarget &Subtarget =
-      DAG.getMachineFunction().getSubtarget<RISCVSubtarget>();
+  auto &Subtarget = DAG.getSubtarget<RISCVSubtarget>();
   if (Subtarget.hasVendorXqciac() && isInt<12>(MulAmt))
     return SDValue();
 

>From bf0aca9748717ff551fe5d50e6195c0b91829b15 Mon Sep 17 00:00:00 2001
From: Sudharsan Veeravalli <quic_svs at quicinc.com>
Date: Thu, 10 Jul 2025 06:40:48 +0530
Subject: [PATCH 3/5] Pass subtarget from caller

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

diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index da329a8047a42..8a4e8f967cfcf 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -15894,10 +15894,8 @@ static SDValue expandMulToNAFSequence(SDNode *N, SelectionDAG &DAG,
 
 // X * (2^N +/- 2^M) -> (add/sub (shl X, C1), (shl X, C2))
 static SDValue expandMulToAddOrSubOfShl(SDNode *N, SelectionDAG &DAG,
-                                        uint64_t MulAmt) {
-  // Don't do this is if the Xqciac extension is enabled and the MulAmt is
-  // simm12.
-  auto &Subtarget = DAG.getSubtarget<RISCVSubtarget>();
+                                        uint64_t MulAmt,
+                                        const RISCVSubtarget &Subtarget) {
   if (Subtarget.hasVendorXqciac() && isInt<12>(MulAmt))
     return SDValue();
 
@@ -16085,7 +16083,7 @@ static SDValue expandMul(SDNode *N, SelectionDAG &DAG,
     }
   }
 
-  if (SDValue V = expandMulToAddOrSubOfShl(N, DAG, MulAmt))
+  if (SDValue V = expandMulToAddOrSubOfShl(N, DAG, MulAmt, Subtarget))
     return V;
 
   if (!Subtarget.hasStdExtZmmul())

>From 04a6a401242475de40cd105299683d6f554d8341 Mon Sep 17 00:00:00 2001
From: Sudharsan Veeravalli <quic_svs at quicinc.com>
Date: Fri, 11 Jul 2025 10:16:11 +0530
Subject: [PATCH 4/5] Tests without ISelLowering changes

---
 llvm/lib/Target/RISCV/RISCVISelLowering.cpp |  11 +-
 llvm/test/CodeGen/RISCV/xqciac.ll           | 121 +++++++++++++++++++-
 2 files changed, 117 insertions(+), 15 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index ea2e6de4e8b59..ce28fdb43bf50 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -15946,10 +15946,7 @@ static SDValue expandMulToNAFSequence(SDNode *N, SelectionDAG &DAG,
 
 // X * (2^N +/- 2^M) -> (add/sub (shl X, C1), (shl X, C2))
 static SDValue expandMulToAddOrSubOfShl(SDNode *N, SelectionDAG &DAG,
-                                        uint64_t MulAmt,
-                                        const RISCVSubtarget &Subtarget) {
-  if (Subtarget.hasVendorXqciac() && isInt<12>(MulAmt))
-    return SDValue();
+                                        uint64_t MulAmt) {
 
   uint64_t MulAmtLowBit = MulAmt & (-MulAmt);
   ISD::NodeType Op;
@@ -16135,7 +16132,7 @@ static SDValue expandMul(SDNode *N, SelectionDAG &DAG,
     }
   }
 
-  if (SDValue V = expandMulToAddOrSubOfShl(N, DAG, MulAmt, Subtarget))
+  if (SDValue V = expandMulToAddOrSubOfShl(N, DAG, MulAmt))
     return V;
 
   if (!Subtarget.hasStdExtZmmul())
@@ -23756,10 +23753,6 @@ bool RISCVTargetLowering::decomposeMulByConstant(LLVMContext &Context, EVT VT,
   auto *ConstNode = cast<ConstantSDNode>(C);
   const APInt &Imm = ConstNode->getAPIntValue();
 
-  // Don't do this if the Xqciac extension is enabled and the Imm in simm12.
-  if (Subtarget.hasVendorXqciac() && Imm.isSignedIntN(12))
-    return false;
-
   // Break the MUL to a SLLI and an ADD/SUB.
   if ((Imm + 1).isPowerOf2() || (Imm - 1).isPowerOf2() ||
       (1 - Imm).isPowerOf2() || (-1 - Imm).isPowerOf2())
diff --git a/llvm/test/CodeGen/RISCV/xqciac.ll b/llvm/test/CodeGen/RISCV/xqciac.ll
index 2822d1a98afea..3f36d79119ddd 100644
--- a/llvm/test/CodeGen/RISCV/xqciac.ll
+++ b/llvm/test/CodeGen/RISCV/xqciac.ll
@@ -15,14 +15,14 @@ define dso_local i32 @mul(i32 %a, i32 %b) local_unnamed_addr #0 {
 ;
 ; RV32IMXQCIAC-LABEL: mul:
 ; RV32IMXQCIAC:       # %bb.0: # %entry
-; RV32IMXQCIAC-NEXT:    li a0, 33
-; RV32IMXQCIAC-NEXT:    mul a0, a1, a0
+; RV32IMXQCIAC-NEXT:    slli a0, a1, 5
+; RV32IMXQCIAC-NEXT:    add a0, a0, a1
 ; RV32IMXQCIAC-NEXT:    ret
 ;
 ; RV32IZBAMXQCIAC-LABEL: mul:
 ; RV32IZBAMXQCIAC:       # %bb.0: # %entry
-; RV32IZBAMXQCIAC-NEXT:    li a0, 33
-; RV32IZBAMXQCIAC-NEXT:    mul a0, a1, a0
+; RV32IZBAMXQCIAC-NEXT:    slli a0, a1, 5
+; RV32IZBAMXQCIAC-NEXT:    add a0, a0, a1
 ; RV32IZBAMXQCIAC-NEXT:    ret
 entry:
   %mul = mul nsw i32 %b, 33
@@ -52,6 +52,29 @@ entry:
   ret i32 %add
 }
 
+define dso_local i32 @muliadd2(i32 %a, i32 %b) local_unnamed_addr #0 {
+; RV32IM-LABEL: muliadd2:
+; RV32IM:       # %bb.0: # %entry
+; RV32IM-NEXT:    li a2, 1111
+; RV32IM-NEXT:    mul a1, a1, a2
+; RV32IM-NEXT:    add a0, a1, a0
+; RV32IM-NEXT:    ret
+;
+; RV32IMXQCIAC-LABEL: muliadd2:
+; RV32IMXQCIAC:       # %bb.0: # %entry
+; RV32IMXQCIAC-NEXT:    qc.muliadd a0, a1, 1111
+; RV32IMXQCIAC-NEXT:    ret
+;
+; RV32IZBAMXQCIAC-LABEL: muliadd2:
+; RV32IZBAMXQCIAC:       # %bb.0: # %entry
+; RV32IZBAMXQCIAC-NEXT:    qc.muliadd a0, a1, 1111
+; RV32IZBAMXQCIAC-NEXT:    ret
+entry:
+  %mul = mul nsw i32 %b, 1111
+  %add = add nsw i32 %mul, %a
+  ret i32 %add
+}
+
 define dso_local i32 @muliadd_neg(i32 %a, i32 %b) local_unnamed_addr #0 {
 ; RV32IM-LABEL: muliadd_neg:
 ; RV32IM:       # %bb.0: # %entry
@@ -75,6 +98,29 @@ entry:
   ret i32 %add
 }
 
+define dso_local i32 @muliadd_neg2(i32 %a, i32 %b) local_unnamed_addr #0 {
+; RV32IM-LABEL: muliadd_neg2:
+; RV32IM:       # %bb.0: # %entry
+; RV32IM-NEXT:    li a2, -2045
+; RV32IM-NEXT:    mul a1, a1, a2
+; RV32IM-NEXT:    add a0, a1, a0
+; RV32IM-NEXT:    ret
+;
+; RV32IMXQCIAC-LABEL: muliadd_neg2:
+; RV32IMXQCIAC:       # %bb.0: # %entry
+; RV32IMXQCIAC-NEXT:    qc.muliadd a0, a1, -2045
+; RV32IMXQCIAC-NEXT:    ret
+;
+; RV32IZBAMXQCIAC-LABEL: muliadd_neg2:
+; RV32IZBAMXQCIAC:       # %bb.0: # %entry
+; RV32IZBAMXQCIAC-NEXT:    qc.muliadd a0, a1, -2045
+; RV32IZBAMXQCIAC-NEXT:    ret
+entry:
+  %mul = mul nsw i32 %b, -2045
+  %add = add nsw i32 %mul, %a
+  ret i32 %add
+}
+
 define dso_local i32 @pow2immplus1(i32 %a, i32 %b) local_unnamed_addr #0 {
 ; RV32IM-LABEL: pow2immplus1:
 ; RV32IM:       # %bb.0: # %entry
@@ -85,12 +131,16 @@ define dso_local i32 @pow2immplus1(i32 %a, i32 %b) local_unnamed_addr #0 {
 ;
 ; RV32IMXQCIAC-LABEL: pow2immplus1:
 ; RV32IMXQCIAC:       # %bb.0: # %entry
-; RV32IMXQCIAC-NEXT:    qc.muliadd a0, a1, 33
+; RV32IMXQCIAC-NEXT:    slli a2, a1, 5
+; RV32IMXQCIAC-NEXT:    add a0, a0, a1
+; RV32IMXQCIAC-NEXT:    add a0, a0, a2
 ; RV32IMXQCIAC-NEXT:    ret
 ;
 ; RV32IZBAMXQCIAC-LABEL: pow2immplus1:
 ; RV32IZBAMXQCIAC:       # %bb.0: # %entry
-; RV32IZBAMXQCIAC-NEXT:    qc.muliadd a0, a1, 33
+; RV32IZBAMXQCIAC-NEXT:    slli a2, a1, 5
+; RV32IZBAMXQCIAC-NEXT:    add a0, a0, a1
+; RV32IZBAMXQCIAC-NEXT:    add a0, a0, a2
 ; RV32IZBAMXQCIAC-NEXT:    ret
 entry:
   %mul = mul nsw i32 %b, 33
@@ -98,6 +148,65 @@ entry:
   ret i32 %add
 }
 
+define dso_local i32 @pow2immminus2(i32 %a, i32 %b) local_unnamed_addr #0 {
+; RV32IM-LABEL: pow2immminus2:
+; RV32IM:       # %bb.0: # %entry
+; RV32IM-NEXT:    slli a2, a1, 1
+; RV32IM-NEXT:    slli a1, a1, 7
+; RV32IM-NEXT:    sub a1, a1, a2
+; RV32IM-NEXT:    add a0, a1, a0
+; RV32IM-NEXT:    ret
+;
+; RV32IMXQCIAC-LABEL: pow2immminus2:
+; RV32IMXQCIAC:       # %bb.0: # %entry
+; RV32IMXQCIAC-NEXT:    slli a2, a1, 1
+; RV32IMXQCIAC-NEXT:    slli a1, a1, 7
+; RV32IMXQCIAC-NEXT:    sub a1, a1, a2
+; RV32IMXQCIAC-NEXT:    add a0, a0, a1
+; RV32IMXQCIAC-NEXT:    ret
+;
+; RV32IZBAMXQCIAC-LABEL: pow2immminus2:
+; RV32IZBAMXQCIAC:       # %bb.0: # %entry
+; RV32IZBAMXQCIAC-NEXT:    slli a2, a1, 1
+; RV32IZBAMXQCIAC-NEXT:    slli a1, a1, 7
+; RV32IZBAMXQCIAC-NEXT:    sub a1, a1, a2
+; RV32IZBAMXQCIAC-NEXT:    add a0, a0, a1
+; RV32IZBAMXQCIAC-NEXT:    ret
+entry:
+  %mul = mul nsw i32 %b, 126
+  %add = add nsw i32 %mul, %a
+  ret i32 %add
+}
+
+define dso_local i32 @pow2minuspow2(i32 %a, i32 %b) local_unnamed_addr #0 {
+; RV32IM-LABEL: pow2minuspow2:
+; RV32IM:       # %bb.0: # %entry
+; RV32IM-NEXT:    slli a2, a1, 7
+; RV32IM-NEXT:    slli a1, a1, 9
+; RV32IM-NEXT:    sub a1, a1, a2
+; RV32IM-NEXT:    add a0, a1, a0
+; RV32IM-NEXT:    ret
+;
+; RV32IMXQCIAC-LABEL: pow2minuspow2:
+; RV32IMXQCIAC:       # %bb.0: # %entry
+; RV32IMXQCIAC-NEXT:    slli a2, a1, 7
+; RV32IMXQCIAC-NEXT:    slli a1, a1, 9
+; RV32IMXQCIAC-NEXT:    sub a1, a1, a2
+; RV32IMXQCIAC-NEXT:    add a0, a0, a1
+; RV32IMXQCIAC-NEXT:    ret
+;
+; RV32IZBAMXQCIAC-LABEL: pow2minuspow2:
+; RV32IZBAMXQCIAC:       # %bb.0: # %entry
+; RV32IZBAMXQCIAC-NEXT:    sh1add a1, a1, a1
+; RV32IZBAMXQCIAC-NEXT:    slli a1, a1, 7
+; RV32IZBAMXQCIAC-NEXT:    add a0, a0, a1
+; RV32IZBAMXQCIAC-NEXT:    ret
+entry:
+  %mul = mul nsw i32 %b, 384
+  %add = add nsw i32 %mul, %a
+  ret i32 %add
+}
+
 define dso_local i32 @gtsimm12(i32 %a, i32 %b) local_unnamed_addr #0 {
 ; RV32IM-LABEL: gtsimm12:
 ; RV32IM:       # %bb.0: # %entry

>From 49ecc01a51a2b7eb2b75bd1a4adf1ab2aced77fe Mon Sep 17 00:00:00 2001
From: Sudharsan Veeravalli <quic_svs at quicinc.com>
Date: Fri, 11 Jul 2025 10:33:34 +0530
Subject: [PATCH 5/5] ISel changes for corner cases

---
 llvm/lib/Target/RISCV/RISCVISelLowering.cpp |  9 +++++-
 llvm/test/CodeGen/RISCV/xqciac.ll           | 35 ++++++---------------
 2 files changed, 18 insertions(+), 26 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index ce28fdb43bf50..778cf369d756e 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -15947,7 +15947,6 @@ static SDValue expandMulToNAFSequence(SDNode *N, SelectionDAG &DAG,
 // X * (2^N +/- 2^M) -> (add/sub (shl X, C1), (shl X, C2))
 static SDValue expandMulToAddOrSubOfShl(SDNode *N, SelectionDAG &DAG,
                                         uint64_t MulAmt) {
-
   uint64_t MulAmtLowBit = MulAmt & (-MulAmt);
   ISD::NodeType Op;
   uint64_t ShiftAmt1;
@@ -15994,6 +15993,10 @@ static SDValue expandMul(SDNode *N, SelectionDAG &DAG,
     return SDValue();
   uint64_t MulAmt = CNode->getZExtValue();
 
+  // Don't do this if the Xqciac extension is enabled and the MulAmt in simm12.
+  if (Subtarget.hasVendorXqciac() && isInt<12>(MulAmt))
+    return SDValue();
+
   const bool HasShlAdd = Subtarget.hasStdExtZba() ||
                          Subtarget.hasVendorXTHeadBa() ||
                          Subtarget.hasVendorXAndesPerf();
@@ -23753,6 +23756,10 @@ bool RISCVTargetLowering::decomposeMulByConstant(LLVMContext &Context, EVT VT,
   auto *ConstNode = cast<ConstantSDNode>(C);
   const APInt &Imm = ConstNode->getAPIntValue();
 
+  // Don't do this if the Xqciac extension is enabled and the Imm in simm12.
+  if (Subtarget.hasVendorXqciac() && Imm.isSignedIntN(12))
+    return false;
+
   // Break the MUL to a SLLI and an ADD/SUB.
   if ((Imm + 1).isPowerOf2() || (Imm - 1).isPowerOf2() ||
       (1 - Imm).isPowerOf2() || (-1 - Imm).isPowerOf2())
diff --git a/llvm/test/CodeGen/RISCV/xqciac.ll b/llvm/test/CodeGen/RISCV/xqciac.ll
index 3f36d79119ddd..4cee0910608f3 100644
--- a/llvm/test/CodeGen/RISCV/xqciac.ll
+++ b/llvm/test/CodeGen/RISCV/xqciac.ll
@@ -15,14 +15,14 @@ define dso_local i32 @mul(i32 %a, i32 %b) local_unnamed_addr #0 {
 ;
 ; RV32IMXQCIAC-LABEL: mul:
 ; RV32IMXQCIAC:       # %bb.0: # %entry
-; RV32IMXQCIAC-NEXT:    slli a0, a1, 5
-; RV32IMXQCIAC-NEXT:    add a0, a0, a1
+; RV32IMXQCIAC-NEXT:    li a0, 33
+; RV32IMXQCIAC-NEXT:    mul a0, a1, a0
 ; RV32IMXQCIAC-NEXT:    ret
 ;
 ; RV32IZBAMXQCIAC-LABEL: mul:
 ; RV32IZBAMXQCIAC:       # %bb.0: # %entry
-; RV32IZBAMXQCIAC-NEXT:    slli a0, a1, 5
-; RV32IZBAMXQCIAC-NEXT:    add a0, a0, a1
+; RV32IZBAMXQCIAC-NEXT:    li a0, 33
+; RV32IZBAMXQCIAC-NEXT:    mul a0, a1, a0
 ; RV32IZBAMXQCIAC-NEXT:    ret
 entry:
   %mul = mul nsw i32 %b, 33
@@ -131,16 +131,12 @@ define dso_local i32 @pow2immplus1(i32 %a, i32 %b) local_unnamed_addr #0 {
 ;
 ; RV32IMXQCIAC-LABEL: pow2immplus1:
 ; RV32IMXQCIAC:       # %bb.0: # %entry
-; RV32IMXQCIAC-NEXT:    slli a2, a1, 5
-; RV32IMXQCIAC-NEXT:    add a0, a0, a1
-; RV32IMXQCIAC-NEXT:    add a0, a0, a2
+; RV32IMXQCIAC-NEXT:    qc.muliadd a0, a1, 33
 ; RV32IMXQCIAC-NEXT:    ret
 ;
 ; RV32IZBAMXQCIAC-LABEL: pow2immplus1:
 ; RV32IZBAMXQCIAC:       # %bb.0: # %entry
-; RV32IZBAMXQCIAC-NEXT:    slli a2, a1, 5
-; RV32IZBAMXQCIAC-NEXT:    add a0, a0, a1
-; RV32IZBAMXQCIAC-NEXT:    add a0, a0, a2
+; RV32IZBAMXQCIAC-NEXT:    qc.muliadd a0, a1, 33
 ; RV32IZBAMXQCIAC-NEXT:    ret
 entry:
   %mul = mul nsw i32 %b, 33
@@ -159,18 +155,12 @@ define dso_local i32 @pow2immminus2(i32 %a, i32 %b) local_unnamed_addr #0 {
 ;
 ; RV32IMXQCIAC-LABEL: pow2immminus2:
 ; RV32IMXQCIAC:       # %bb.0: # %entry
-; RV32IMXQCIAC-NEXT:    slli a2, a1, 1
-; RV32IMXQCIAC-NEXT:    slli a1, a1, 7
-; RV32IMXQCIAC-NEXT:    sub a1, a1, a2
-; RV32IMXQCIAC-NEXT:    add a0, a0, a1
+; RV32IMXQCIAC-NEXT:    qc.muliadd a0, a1, 126
 ; RV32IMXQCIAC-NEXT:    ret
 ;
 ; RV32IZBAMXQCIAC-LABEL: pow2immminus2:
 ; RV32IZBAMXQCIAC:       # %bb.0: # %entry
-; RV32IZBAMXQCIAC-NEXT:    slli a2, a1, 1
-; RV32IZBAMXQCIAC-NEXT:    slli a1, a1, 7
-; RV32IZBAMXQCIAC-NEXT:    sub a1, a1, a2
-; RV32IZBAMXQCIAC-NEXT:    add a0, a0, a1
+; RV32IZBAMXQCIAC-NEXT:    qc.muliadd a0, a1, 126
 ; RV32IZBAMXQCIAC-NEXT:    ret
 entry:
   %mul = mul nsw i32 %b, 126
@@ -189,17 +179,12 @@ define dso_local i32 @pow2minuspow2(i32 %a, i32 %b) local_unnamed_addr #0 {
 ;
 ; RV32IMXQCIAC-LABEL: pow2minuspow2:
 ; RV32IMXQCIAC:       # %bb.0: # %entry
-; RV32IMXQCIAC-NEXT:    slli a2, a1, 7
-; RV32IMXQCIAC-NEXT:    slli a1, a1, 9
-; RV32IMXQCIAC-NEXT:    sub a1, a1, a2
-; RV32IMXQCIAC-NEXT:    add a0, a0, a1
+; RV32IMXQCIAC-NEXT:    qc.muliadd a0, a1, 384
 ; RV32IMXQCIAC-NEXT:    ret
 ;
 ; RV32IZBAMXQCIAC-LABEL: pow2minuspow2:
 ; RV32IZBAMXQCIAC:       # %bb.0: # %entry
-; RV32IZBAMXQCIAC-NEXT:    sh1add a1, a1, a1
-; RV32IZBAMXQCIAC-NEXT:    slli a1, a1, 7
-; RV32IZBAMXQCIAC-NEXT:    add a0, a0, a1
+; RV32IZBAMXQCIAC-NEXT:    qc.muliadd a0, a1, 384
 ; RV32IZBAMXQCIAC-NEXT:    ret
 entry:
   %mul = mul nsw i32 %b, 384



More information about the llvm-commits mailing list