[llvm] [RISCV] Add ISel patterns for Xqciac QC_SHLADD instruction (PR #148256)

Sudharsan Veeravalli via llvm-commits llvm-commits at lists.llvm.org
Mon Jul 14 00:51:04 PDT 2025


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

>From 2df6343497ea6330daec787e8b94eae7178dd98a Mon Sep 17 00:00:00 2001
From: Sudharsan Veeravalli <quic_svs at quicinc.com>
Date: Fri, 11 Jul 2025 21:29:19 +0530
Subject: [PATCH 1/3] [RISCV] Add ISel patterns for Xqciac QC_SHLADD
 instruction

Add a couple of patterns to generate the Xqciac QC_SHLADD shift left accumulate instruction.
---
 llvm/lib/Target/RISCV/RISCVISelLowering.cpp |  12 +-
 llvm/lib/Target/RISCV/RISCVInstrInfo.cpp    |   3 +
 llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td |   6 +
 llvm/test/CodeGen/RISCV/xqciac.ll           | 178 +++++++++++++++++++-
 4 files changed, 191 insertions(+), 8 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index 456f3aedbf034..35658a2632540 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -15025,10 +15025,13 @@ static SDValue combineBinOpToReduce(SDNode *N, SelectionDAG &DAG,
 
 // Optimize (add (shl x, c0), (shl y, c1)) ->
 //          (SLLI (SH*ADD x, y), c0), if c1-c0 equals to [1|2|3].
+// or
+//          (SLLI (QC.SHLADD x, y, c1 - c0), c0), if 4 <= (c1-c0) <=31.
 static SDValue transformAddShlImm(SDNode *N, SelectionDAG &DAG,
                                   const RISCVSubtarget &Subtarget) {
-  // Perform this optimization only in the zba/xandesperf extension.
-  if (!Subtarget.hasStdExtZba() && !Subtarget.hasVendorXAndesPerf())
+  // Perform this optimization only in the zba/xandesperf/xqciac extension.
+  if (!Subtarget.hasStdExtZba() && !Subtarget.hasVendorXAndesPerf() &&
+      !Subtarget.hasVendorXqciac())
     return SDValue();
 
   // Skip for vector types and larger types.
@@ -15056,7 +15059,10 @@ static SDValue transformAddShlImm(SDNode *N, SelectionDAG &DAG,
   // Skip if SH1ADD/SH2ADD/SH3ADD are not applicable.
   int64_t Bits = std::min(C0, C1);
   int64_t Diff = std::abs(C0 - C1);
-  if (Diff != 1 && Diff != 2 && Diff != 3)
+  if (Diff != 1 && Diff != 2 && Diff != 3 && !Subtarget.hasVendorXqciac())
+    return SDValue();
+
+  if (!Diff || Diff > 31)
     return SDValue();
 
   // Build nodes.
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp b/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp
index 2723229859a55..c7019a65ec30c 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp
@@ -2823,6 +2823,9 @@ bool RISCVInstrInfo::verifyInstruction(const MachineInstr &MI,
         case RISCVOp::OPERAND_UIMM5_NONZERO:
           Ok = isUInt<5>(Imm) && (Imm != 0);
           break;
+        case RISCVOp::OPERAND_UIMM5_GT3:
+          Ok = isUInt<5>(Imm) && (Imm > 3);
+          break;
         case RISCVOp::OPERAND_UIMM5_PLUS1:
           Ok = (isUInt<5>(Imm) && (Imm != 0)) || (Imm == 32);
           break;
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td b/llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td
index 9e3eb1c03fb37..6ca8d2737bd5f 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td
@@ -1359,6 +1359,12 @@ class SelectQCbi<CondCode Cond, DAGOperand InTyImm, Pseudo OpNode >
 let Predicates = [HasVendorXqciac, IsRV32] in {
 def : Pat<(XLenVT (add GPRNoX0:$rd, (mul GPRNoX0:$rs1, simm12:$imm12))),
           (QC_MULIADD GPRNoX0:$rd, GPRNoX0:$rs1, simm12:$imm12)>;
+foreach i = 4-31 in {
+  def : Pat<(XLenVT (add_like_non_imm12 (shl GPR:$rs1, (XLenVT i)), GPR:$rs2)),
+            (QC_SHLADD GPR:$rs1, GPR:$rs2, i)>;
+  def : Pat<(XLenVT (riscv_shl_add GPR:$rs1, (XLenVT i), GPR:$rs2)),
+            (QC_SHLADD GPR:$rs1, GPR:$rs2, i)>;
+}
 } // Predicates = [HasVendorXqciac, IsRV32]
 
 /// Simple arithmetic operations
diff --git a/llvm/test/CodeGen/RISCV/xqciac.ll b/llvm/test/CodeGen/RISCV/xqciac.ll
index 4cee0910608f3..807c4ef48a3a3 100644
--- a/llvm/test/CodeGen/RISCV/xqciac.ll
+++ b/llvm/test/CodeGen/RISCV/xqciac.ll
@@ -222,7 +222,6 @@ entry:
   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
@@ -232,14 +231,12 @@ define dso_local i32 @pow2(i32 %a, i32 %b) local_unnamed_addr #0 {
 ;
 ; RV32IMXQCIAC-LABEL: pow2:
 ; RV32IMXQCIAC:       # %bb.0: # %entry
-; RV32IMXQCIAC-NEXT:    slli a1, a1, 5
-; RV32IMXQCIAC-NEXT:    add a0, a0, a1
+; RV32IMXQCIAC-NEXT:    qc.shladd a0, a1, a0, 5
 ; RV32IMXQCIAC-NEXT:    ret
 ;
 ; RV32IZBAMXQCIAC-LABEL: pow2:
 ; RV32IZBAMXQCIAC:       # %bb.0: # %entry
-; RV32IZBAMXQCIAC-NEXT:    slli a1, a1, 5
-; RV32IZBAMXQCIAC-NEXT:    add a0, a0, a1
+; RV32IZBAMXQCIAC-NEXT:    qc.shladd a0, a1, a0, 5
 ; RV32IZBAMXQCIAC-NEXT:    ret
 entry:
   %mul = mul nsw i32 %b, 32
@@ -269,3 +266,174 @@ entry:
   %add = add nsw i32 %mul, %a
   ret i32 %add
 }
+
+define dso_local i32 @shladd(i32 %a, i32 %b) local_unnamed_addr #0 {
+; RV32IM-LABEL: shladd:
+; RV32IM:       # %bb.0: # %entry
+; RV32IM-NEXT:    slli a1, a1, 31
+; RV32IM-NEXT:    add a0, a1, a0
+; RV32IM-NEXT:    ret
+;
+; RV32IMXQCIAC-LABEL: shladd:
+; RV32IMXQCIAC:       # %bb.0: # %entry
+; RV32IMXQCIAC-NEXT:    qc.shladd a0, a1, a0, 31
+; RV32IMXQCIAC-NEXT:    ret
+;
+; RV32IZBAMXQCIAC-LABEL: shladd:
+; RV32IZBAMXQCIAC:       # %bb.0: # %entry
+; RV32IZBAMXQCIAC-NEXT:    qc.shladd a0, a1, a0, 31
+; RV32IZBAMXQCIAC-NEXT:    ret
+entry:
+  %shl = shl nsw i32 %b, 31
+  %add = add nsw i32 %shl, %a
+  ret i32 %add
+}
+
+define dso_local i64 @shladd64(i64 %a, i64 %b) local_unnamed_addr #0 {
+; RV32IM-LABEL: shladd64:
+; RV32IM:       # %bb.0: # %entry
+; RV32IM-NEXT:    srli a4, a2, 1
+; RV32IM-NEXT:    slli a3, a3, 31
+; RV32IM-NEXT:    slli a2, a2, 31
+; RV32IM-NEXT:    or a3, a3, a4
+; RV32IM-NEXT:    add a0, a2, a0
+; RV32IM-NEXT:    sltu a2, a0, a2
+; RV32IM-NEXT:    add a1, a3, a1
+; RV32IM-NEXT:    add a1, a1, a2
+; RV32IM-NEXT:    ret
+;
+; RV32IMXQCIAC-LABEL: shladd64:
+; RV32IMXQCIAC:       # %bb.0: # %entry
+; RV32IMXQCIAC-NEXT:    srli a4, a2, 1
+; RV32IMXQCIAC-NEXT:    qc.shladd a0, a2, a0, 31
+; RV32IMXQCIAC-NEXT:    slli a2, a2, 31
+; RV32IMXQCIAC-NEXT:    qc.shladd a3, a3, a4, 31
+; RV32IMXQCIAC-NEXT:    sltu a2, a0, a2
+; RV32IMXQCIAC-NEXT:    add a1, a1, a3
+; RV32IMXQCIAC-NEXT:    add a1, a1, a2
+; RV32IMXQCIAC-NEXT:    ret
+;
+; RV32IZBAMXQCIAC-LABEL: shladd64:
+; RV32IZBAMXQCIAC:       # %bb.0: # %entry
+; RV32IZBAMXQCIAC-NEXT:    srli a4, a2, 1
+; RV32IZBAMXQCIAC-NEXT:    qc.shladd a0, a2, a0, 31
+; RV32IZBAMXQCIAC-NEXT:    slli a2, a2, 31
+; RV32IZBAMXQCIAC-NEXT:    qc.shladd a3, a3, a4, 31
+; RV32IZBAMXQCIAC-NEXT:    sltu a2, a0, a2
+; RV32IZBAMXQCIAC-NEXT:    add a1, a1, a3
+; RV32IZBAMXQCIAC-NEXT:    add a1, a1, a2
+; RV32IZBAMXQCIAC-NEXT:    ret
+entry:
+  %shl = shl nsw i64 %b, 31
+  %add = add nsw i64 %shl, %a
+  ret i64 %add
+}
+
+define dso_local i32 @shladd_ordisjoint(i32 %a, i32 %b) local_unnamed_addr #0 {
+; RV32IM-LABEL: shladd_ordisjoint:
+; RV32IM:       # %bb.0: # %entry
+; RV32IM-NEXT:    slli a1, a1, 22
+; RV32IM-NEXT:    or a0, a1, a0
+; RV32IM-NEXT:    ret
+;
+; RV32IMXQCIAC-LABEL: shladd_ordisjoint:
+; RV32IMXQCIAC:       # %bb.0: # %entry
+; RV32IMXQCIAC-NEXT:    qc.shladd a0, a1, a0, 22
+; RV32IMXQCIAC-NEXT:    ret
+;
+; RV32IZBAMXQCIAC-LABEL: shladd_ordisjoint:
+; RV32IZBAMXQCIAC:       # %bb.0: # %entry
+; RV32IZBAMXQCIAC-NEXT:    qc.shladd a0, a1, a0, 22
+; RV32IZBAMXQCIAC-NEXT:    ret
+entry:
+  %shl = shl nsw i32 %b, 22
+  %or = or disjoint i32 %shl, %a
+  ret i32 %or
+}
+
+define dso_local i32 @shladdc1c2(i32 %a, i32 %b) local_unnamed_addr #0 {
+; RV32IM-LABEL: shladdc1c2:
+; RV32IM:       # %bb.0: # %entry
+; RV32IM-NEXT:    slli a0, a0, 31
+; RV32IM-NEXT:    slli a1, a1, 26
+; RV32IM-NEXT:    add a0, a0, a1
+; RV32IM-NEXT:    ret
+;
+; RV32IMXQCIAC-LABEL: shladdc1c2:
+; RV32IMXQCIAC:       # %bb.0: # %entry
+; RV32IMXQCIAC-NEXT:    qc.shladd a0, a0, a1, 5
+; RV32IMXQCIAC-NEXT:    slli a0, a0, 26
+; RV32IMXQCIAC-NEXT:    ret
+;
+; RV32IZBAMXQCIAC-LABEL: shladdc1c2:
+; RV32IZBAMXQCIAC:       # %bb.0: # %entry
+; RV32IZBAMXQCIAC-NEXT:    qc.shladd a0, a0, a1, 5
+; RV32IZBAMXQCIAC-NEXT:    slli a0, a0, 26
+; RV32IZBAMXQCIAC-NEXT:    ret
+entry:
+  %shlc1 = shl nsw i32 %a, 31
+  %shlc2 = shl nsw i32 %b, 26
+  %add = add nsw i32 %shlc1, %shlc2
+  ret i32 %add
+}
+
+define dso_local i64 @shladdc1c264(i64 %a, i64 %b) local_unnamed_addr #0 {
+; RV32IM-LABEL: shladdc1c264:
+; RV32IM:       # %bb.0: # %entry
+; RV32IM-NEXT:    slli a1, a0, 23
+; RV32IM-NEXT:    srli a0, a2, 12
+; RV32IM-NEXT:    slli a3, a3, 20
+; RV32IM-NEXT:    or a3, a3, a0
+; RV32IM-NEXT:    slli a0, a2, 20
+; RV32IM-NEXT:    add a1, a1, a3
+; RV32IM-NEXT:    ret
+;
+; RV32IMXQCIAC-LABEL: shladdc1c264:
+; RV32IMXQCIAC:       # %bb.0: # %entry
+; RV32IMXQCIAC-NEXT:    srli a1, a2, 12
+; RV32IMXQCIAC-NEXT:    qc.shladd a1, a3, a1, 20
+; RV32IMXQCIAC-NEXT:    slli a2, a2, 20
+; RV32IMXQCIAC-NEXT:    qc.shladd a1, a0, a1, 23
+; RV32IMXQCIAC-NEXT:    mv a0, a2
+; RV32IMXQCIAC-NEXT:    ret
+;
+; RV32IZBAMXQCIAC-LABEL: shladdc1c264:
+; RV32IZBAMXQCIAC:       # %bb.0: # %entry
+; RV32IZBAMXQCIAC-NEXT:    srli a1, a2, 12
+; RV32IZBAMXQCIAC-NEXT:    qc.shladd a1, a3, a1, 20
+; RV32IZBAMXQCIAC-NEXT:    slli a2, a2, 20
+; RV32IZBAMXQCIAC-NEXT:    qc.shladd a1, a0, a1, 23
+; RV32IZBAMXQCIAC-NEXT:    mv a0, a2
+; RV32IZBAMXQCIAC-NEXT:    ret
+entry:
+  %shlc1 = shl nsw i64 %a, 55
+  %shlc2 = shl nsw i64 %b, 20
+  %add = add nsw i64 %shlc1, %shlc2
+  ret i64 %add
+}
+
+define dso_local i32 @shladdc1equalc2(i32 %a, i32 %b) local_unnamed_addr #0 {
+; RV32IM-LABEL: shladdc1equalc2:
+; RV32IM:       # %bb.0: # %entry
+; RV32IM-NEXT:    slli a0, a0, 12
+; RV32IM-NEXT:    slli a1, a1, 12
+; RV32IM-NEXT:    add a0, a0, a1
+; RV32IM-NEXT:    ret
+;
+; RV32IMXQCIAC-LABEL: shladdc1equalc2:
+; RV32IMXQCIAC:       # %bb.0: # %entry
+; RV32IMXQCIAC-NEXT:    slli a1, a1, 12
+; RV32IMXQCIAC-NEXT:    qc.shladd a0, a0, a1, 12
+; RV32IMXQCIAC-NEXT:    ret
+;
+; RV32IZBAMXQCIAC-LABEL: shladdc1equalc2:
+; RV32IZBAMXQCIAC:       # %bb.0: # %entry
+; RV32IZBAMXQCIAC-NEXT:    slli a1, a1, 12
+; RV32IZBAMXQCIAC-NEXT:    qc.shladd a0, a0, a1, 12
+; RV32IZBAMXQCIAC-NEXT:    ret
+entry:
+  %shlc1 = shl nsw i32 %a, 12
+  %shlc2 = shl nsw i32 %b, 12
+  %add = add nsw i32 %shlc1, %shlc2
+  ret i32 %add
+}

>From 36c06fb2357b01c0bbafe26ea283443d052b306c Mon Sep 17 00:00:00 2001
From: Sudharsan Veeravalli <quic_svs at quicinc.com>
Date: Sat, 12 Jul 2025 08:46:30 +0530
Subject: [PATCH 2/3] Fix tests

---
 llvm/lib/Target/RISCV/RISCVISelLowering.cpp |  2 +-
 llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td |  4 +--
 llvm/test/CodeGen/RISCV/xqciac.ll           | 36 ++++++++++-----------
 3 files changed, 21 insertions(+), 21 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index 35658a2632540..a38723f2b2e17 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -15062,7 +15062,7 @@ static SDValue transformAddShlImm(SDNode *N, SelectionDAG &DAG,
   if (Diff != 1 && Diff != 2 && Diff != 3 && !Subtarget.hasVendorXqciac())
     return SDValue();
 
-  if (!Diff || Diff > 31)
+  if (Diff == 0 || Diff > 31)
     return SDValue();
 
   // Build nodes.
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td b/llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td
index 6ca8d2737bd5f..bfd55e9e57be1 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td
@@ -1361,9 +1361,9 @@ def : Pat<(XLenVT (add GPRNoX0:$rd, (mul GPRNoX0:$rs1, simm12:$imm12))),
           (QC_MULIADD GPRNoX0:$rd, GPRNoX0:$rs1, simm12:$imm12)>;
 foreach i = 4-31 in {
   def : Pat<(XLenVT (add_like_non_imm12 (shl GPR:$rs1, (XLenVT i)), GPR:$rs2)),
-            (QC_SHLADD GPR:$rs1, GPR:$rs2, i)>;
+            (QC_SHLADD GPR:$rs2, GPR:$rs1, i)>;
   def : Pat<(XLenVT (riscv_shl_add GPR:$rs1, (XLenVT i), GPR:$rs2)),
-            (QC_SHLADD GPR:$rs1, GPR:$rs2, i)>;
+            (QC_SHLADD GPR:$rs2, GPR:$rs1, i)>;
 }
 } // Predicates = [HasVendorXqciac, IsRV32]
 
diff --git a/llvm/test/CodeGen/RISCV/xqciac.ll b/llvm/test/CodeGen/RISCV/xqciac.ll
index 807c4ef48a3a3..9a946f0455437 100644
--- a/llvm/test/CodeGen/RISCV/xqciac.ll
+++ b/llvm/test/CodeGen/RISCV/xqciac.ll
@@ -231,12 +231,12 @@ define dso_local i32 @pow2(i32 %a, i32 %b) local_unnamed_addr #0 {
 ;
 ; RV32IMXQCIAC-LABEL: pow2:
 ; RV32IMXQCIAC:       # %bb.0: # %entry
-; RV32IMXQCIAC-NEXT:    qc.shladd a0, a1, a0, 5
+; RV32IMXQCIAC-NEXT:    qc.shladd a0, a0, a1, 5
 ; RV32IMXQCIAC-NEXT:    ret
 ;
 ; RV32IZBAMXQCIAC-LABEL: pow2:
 ; RV32IZBAMXQCIAC:       # %bb.0: # %entry
-; RV32IZBAMXQCIAC-NEXT:    qc.shladd a0, a1, a0, 5
+; RV32IZBAMXQCIAC-NEXT:    qc.shladd a0, a0, a1, 5
 ; RV32IZBAMXQCIAC-NEXT:    ret
 entry:
   %mul = mul nsw i32 %b, 32
@@ -276,12 +276,12 @@ define dso_local i32 @shladd(i32 %a, i32 %b) local_unnamed_addr #0 {
 ;
 ; RV32IMXQCIAC-LABEL: shladd:
 ; RV32IMXQCIAC:       # %bb.0: # %entry
-; RV32IMXQCIAC-NEXT:    qc.shladd a0, a1, a0, 31
+; RV32IMXQCIAC-NEXT:    qc.shladd a0, a0, a1, 31
 ; RV32IMXQCIAC-NEXT:    ret
 ;
 ; RV32IZBAMXQCIAC-LABEL: shladd:
 ; RV32IZBAMXQCIAC:       # %bb.0: # %entry
-; RV32IZBAMXQCIAC-NEXT:    qc.shladd a0, a1, a0, 31
+; RV32IZBAMXQCIAC-NEXT:    qc.shladd a0, a0, a1, 31
 ; RV32IZBAMXQCIAC-NEXT:    ret
 entry:
   %shl = shl nsw i32 %b, 31
@@ -305,9 +305,9 @@ define dso_local i64 @shladd64(i64 %a, i64 %b) local_unnamed_addr #0 {
 ; RV32IMXQCIAC-LABEL: shladd64:
 ; RV32IMXQCIAC:       # %bb.0: # %entry
 ; RV32IMXQCIAC-NEXT:    srli a4, a2, 1
-; RV32IMXQCIAC-NEXT:    qc.shladd a0, a2, a0, 31
+; RV32IMXQCIAC-NEXT:    qc.shladd a0, a0, a2, 31
 ; RV32IMXQCIAC-NEXT:    slli a2, a2, 31
-; RV32IMXQCIAC-NEXT:    qc.shladd a3, a3, a4, 31
+; RV32IMXQCIAC-NEXT:    qc.shladd a3, a4, a3, 31
 ; RV32IMXQCIAC-NEXT:    sltu a2, a0, a2
 ; RV32IMXQCIAC-NEXT:    add a1, a1, a3
 ; RV32IMXQCIAC-NEXT:    add a1, a1, a2
@@ -316,9 +316,9 @@ define dso_local i64 @shladd64(i64 %a, i64 %b) local_unnamed_addr #0 {
 ; RV32IZBAMXQCIAC-LABEL: shladd64:
 ; RV32IZBAMXQCIAC:       # %bb.0: # %entry
 ; RV32IZBAMXQCIAC-NEXT:    srli a4, a2, 1
-; RV32IZBAMXQCIAC-NEXT:    qc.shladd a0, a2, a0, 31
+; RV32IZBAMXQCIAC-NEXT:    qc.shladd a0, a0, a2, 31
 ; RV32IZBAMXQCIAC-NEXT:    slli a2, a2, 31
-; RV32IZBAMXQCIAC-NEXT:    qc.shladd a3, a3, a4, 31
+; RV32IZBAMXQCIAC-NEXT:    qc.shladd a3, a4, a3, 31
 ; RV32IZBAMXQCIAC-NEXT:    sltu a2, a0, a2
 ; RV32IZBAMXQCIAC-NEXT:    add a1, a1, a3
 ; RV32IZBAMXQCIAC-NEXT:    add a1, a1, a2
@@ -338,12 +338,12 @@ define dso_local i32 @shladd_ordisjoint(i32 %a, i32 %b) local_unnamed_addr #0 {
 ;
 ; RV32IMXQCIAC-LABEL: shladd_ordisjoint:
 ; RV32IMXQCIAC:       # %bb.0: # %entry
-; RV32IMXQCIAC-NEXT:    qc.shladd a0, a1, a0, 22
+; RV32IMXQCIAC-NEXT:    qc.shladd a0, a0, a1, 22
 ; RV32IMXQCIAC-NEXT:    ret
 ;
 ; RV32IZBAMXQCIAC-LABEL: shladd_ordisjoint:
 ; RV32IZBAMXQCIAC:       # %bb.0: # %entry
-; RV32IZBAMXQCIAC-NEXT:    qc.shladd a0, a1, a0, 22
+; RV32IZBAMXQCIAC-NEXT:    qc.shladd a0, a0, a1, 22
 ; RV32IZBAMXQCIAC-NEXT:    ret
 entry:
   %shl = shl nsw i32 %b, 22
@@ -361,13 +361,13 @@ define dso_local i32 @shladdc1c2(i32 %a, i32 %b) local_unnamed_addr #0 {
 ;
 ; RV32IMXQCIAC-LABEL: shladdc1c2:
 ; RV32IMXQCIAC:       # %bb.0: # %entry
-; RV32IMXQCIAC-NEXT:    qc.shladd a0, a0, a1, 5
+; RV32IMXQCIAC-NEXT:    qc.shladd a0, a1, a0, 5
 ; RV32IMXQCIAC-NEXT:    slli a0, a0, 26
 ; RV32IMXQCIAC-NEXT:    ret
 ;
 ; RV32IZBAMXQCIAC-LABEL: shladdc1c2:
 ; RV32IZBAMXQCIAC:       # %bb.0: # %entry
-; RV32IZBAMXQCIAC-NEXT:    qc.shladd a0, a0, a1, 5
+; RV32IZBAMXQCIAC-NEXT:    qc.shladd a0, a1, a0, 5
 ; RV32IZBAMXQCIAC-NEXT:    slli a0, a0, 26
 ; RV32IZBAMXQCIAC-NEXT:    ret
 entry:
@@ -391,18 +391,18 @@ define dso_local i64 @shladdc1c264(i64 %a, i64 %b) local_unnamed_addr #0 {
 ; RV32IMXQCIAC-LABEL: shladdc1c264:
 ; RV32IMXQCIAC:       # %bb.0: # %entry
 ; RV32IMXQCIAC-NEXT:    srli a1, a2, 12
-; RV32IMXQCIAC-NEXT:    qc.shladd a1, a3, a1, 20
+; RV32IMXQCIAC-NEXT:    qc.shladd a1, a1, a3, 20
 ; RV32IMXQCIAC-NEXT:    slli a2, a2, 20
-; RV32IMXQCIAC-NEXT:    qc.shladd a1, a0, a1, 23
+; RV32IMXQCIAC-NEXT:    qc.shladd a1, a1, a0, 23
 ; RV32IMXQCIAC-NEXT:    mv a0, a2
 ; RV32IMXQCIAC-NEXT:    ret
 ;
 ; RV32IZBAMXQCIAC-LABEL: shladdc1c264:
 ; RV32IZBAMXQCIAC:       # %bb.0: # %entry
 ; RV32IZBAMXQCIAC-NEXT:    srli a1, a2, 12
-; RV32IZBAMXQCIAC-NEXT:    qc.shladd a1, a3, a1, 20
+; RV32IZBAMXQCIAC-NEXT:    qc.shladd a1, a1, a3, 20
 ; RV32IZBAMXQCIAC-NEXT:    slli a2, a2, 20
-; RV32IZBAMXQCIAC-NEXT:    qc.shladd a1, a0, a1, 23
+; RV32IZBAMXQCIAC-NEXT:    qc.shladd a1, a1, a0, 23
 ; RV32IZBAMXQCIAC-NEXT:    mv a0, a2
 ; RV32IZBAMXQCIAC-NEXT:    ret
 entry:
@@ -423,13 +423,13 @@ define dso_local i32 @shladdc1equalc2(i32 %a, i32 %b) local_unnamed_addr #0 {
 ; RV32IMXQCIAC-LABEL: shladdc1equalc2:
 ; RV32IMXQCIAC:       # %bb.0: # %entry
 ; RV32IMXQCIAC-NEXT:    slli a1, a1, 12
-; RV32IMXQCIAC-NEXT:    qc.shladd a0, a0, a1, 12
+; RV32IMXQCIAC-NEXT:    qc.shladd a0, a1, a0, 12
 ; RV32IMXQCIAC-NEXT:    ret
 ;
 ; RV32IZBAMXQCIAC-LABEL: shladdc1equalc2:
 ; RV32IZBAMXQCIAC:       # %bb.0: # %entry
 ; RV32IZBAMXQCIAC-NEXT:    slli a1, a1, 12
-; RV32IZBAMXQCIAC-NEXT:    qc.shladd a0, a0, a1, 12
+; RV32IZBAMXQCIAC-NEXT:    qc.shladd a0, a1, a0, 12
 ; RV32IZBAMXQCIAC-NEXT:    ret
 entry:
   %shlc1 = shl nsw i32 %a, 12

>From 9b222ff4b28ed57d3f6f8a4f3d4d1e604dca3106 Mon Sep 17 00:00:00 2001
From: Sudharsan Veeravalli <quic_svs at quicinc.com>
Date: Sat, 12 Jul 2025 12:42:21 +0530
Subject: [PATCH 3/3] Fix pattern add test

---
 llvm/lib/Target/RISCV/RISCVISelLowering.cpp | 17 ++++++++++----
 llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td | 10 ++++----
 llvm/test/CodeGen/RISCV/xqciac.ll           | 26 +++++++++++++++++++++
 3 files changed, 42 insertions(+), 11 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index a38723f2b2e17..e74f35ac4c0e8 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -15029,9 +15029,11 @@ static SDValue combineBinOpToReduce(SDNode *N, SelectionDAG &DAG,
 //          (SLLI (QC.SHLADD x, y, c1 - c0), c0), if 4 <= (c1-c0) <=31.
 static SDValue transformAddShlImm(SDNode *N, SelectionDAG &DAG,
                                   const RISCVSubtarget &Subtarget) {
+  const bool HasStdExtZba = Subtarget.hasStdExtZba();
+  const bool HasVendorXAndesPerf = Subtarget.hasVendorXAndesPerf();
+  const bool HasVendorXqciac = Subtarget.hasVendorXqciac();
   // Perform this optimization only in the zba/xandesperf/xqciac extension.
-  if (!Subtarget.hasStdExtZba() && !Subtarget.hasVendorXAndesPerf() &&
-      !Subtarget.hasVendorXqciac())
+  if (!HasStdExtZba && !HasVendorXAndesPerf && !HasVendorXqciac)
     return SDValue();
 
   // Skip for vector types and larger types.
@@ -15056,17 +15058,22 @@ static SDValue transformAddShlImm(SDNode *N, SelectionDAG &DAG,
   if (C0 <= 0 || C1 <= 0)
     return SDValue();
 
-  // Skip if SH1ADD/SH2ADD/SH3ADD are not applicable.
-  int64_t Bits = std::min(C0, C1);
   int64_t Diff = std::abs(C0 - C1);
-  if (Diff != 1 && Diff != 2 && Diff != 3 && !Subtarget.hasVendorXqciac())
+  bool IsShXaddDiff = Diff == 1 || Diff == 2 || Diff == 3;
+  bool HasShXadd = HasStdExtZba || HasVendorXAndesPerf;
+
+  // Skip if SH1ADD/SH2ADD/SH3ADD are not applicable.
+  if ((!IsShXaddDiff && HasShXadd && !HasVendorXqciac) ||
+      (IsShXaddDiff && !HasShXadd && HasVendorXqciac))
     return SDValue();
 
+  // Skip if QC_SHLADD is not applicable.
   if (Diff == 0 || Diff > 31)
     return SDValue();
 
   // Build nodes.
   SDLoc DL(N);
+  int64_t Bits = std::min(C0, C1);
   SDValue NS = (C0 < C1) ? N0->getOperand(0) : N1->getOperand(0);
   SDValue NL = (C0 > C1) ? N0->getOperand(0) : N1->getOperand(0);
   SDValue SHADD = DAG.getNode(RISCVISD::SHL_ADD, DL, VT, NL,
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td b/llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td
index bfd55e9e57be1..84475e1d8961b 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td
@@ -1359,12 +1359,10 @@ class SelectQCbi<CondCode Cond, DAGOperand InTyImm, Pseudo OpNode >
 let Predicates = [HasVendorXqciac, IsRV32] in {
 def : Pat<(XLenVT (add GPRNoX0:$rd, (mul GPRNoX0:$rs1, simm12:$imm12))),
           (QC_MULIADD GPRNoX0:$rd, GPRNoX0:$rs1, simm12:$imm12)>;
-foreach i = 4-31 in {
-  def : Pat<(XLenVT (add_like_non_imm12 (shl GPR:$rs1, (XLenVT i)), GPR:$rs2)),
-            (QC_SHLADD GPR:$rs2, GPR:$rs1, i)>;
-  def : Pat<(XLenVT (riscv_shl_add GPR:$rs1, (XLenVT i), GPR:$rs2)),
-            (QC_SHLADD GPR:$rs2, GPR:$rs1, i)>;
-}
+def : Pat<(i32 (add_like_non_imm12 (shl GPRNoX0:$rs1, uimm5gt3:$imm), GPRNoX0:$rs2)),
+          (QC_SHLADD GPRNoX0:$rs2, GPRNoX0:$rs1, uimm5gt3:$imm)>;
+def : Pat<(i32 (riscv_shl_add GPRNoX0:$rs1, uimm5gt3:$imm, GPRNoX0:$rs2)),
+          (QC_SHLADD GPRNoX0:$rs2, GPRNoX0:$rs1, uimm5gt3:$imm)>;
 } // Predicates = [HasVendorXqciac, IsRV32]
 
 /// Simple arithmetic operations
diff --git a/llvm/test/CodeGen/RISCV/xqciac.ll b/llvm/test/CodeGen/RISCV/xqciac.ll
index 9a946f0455437..a3b4e7829a51d 100644
--- a/llvm/test/CodeGen/RISCV/xqciac.ll
+++ b/llvm/test/CodeGen/RISCV/xqciac.ll
@@ -377,6 +377,32 @@ entry:
   ret i32 %add
 }
 
+define dso_local i32 @shxaddc1c2(i32 %a, i32 %b) local_unnamed_addr #0 {
+; RV32IM-LABEL: shxaddc1c2:
+; RV32IM:       # %bb.0: # %entry
+; RV32IM-NEXT:    slli a0, a0, 31
+; RV32IM-NEXT:    slli a1, a1, 28
+; RV32IM-NEXT:    add a0, a0, a1
+; RV32IM-NEXT:    ret
+;
+; RV32IMXQCIAC-LABEL: shxaddc1c2:
+; RV32IMXQCIAC:       # %bb.0: # %entry
+; RV32IMXQCIAC-NEXT:    slli a1, a1, 28
+; RV32IMXQCIAC-NEXT:    qc.shladd a0, a1, a0, 31
+; RV32IMXQCIAC-NEXT:    ret
+;
+; RV32IZBAMXQCIAC-LABEL: shxaddc1c2:
+; RV32IZBAMXQCIAC:       # %bb.0: # %entry
+; RV32IZBAMXQCIAC-NEXT:    sh3add a0, a0, a1
+; RV32IZBAMXQCIAC-NEXT:    slli a0, a0, 28
+; RV32IZBAMXQCIAC-NEXT:    ret
+entry:
+  %shlc1 = shl nsw i32 %a, 31
+  %shlc2 = shl nsw i32 %b, 28
+  %add = add nsw i32 %shlc1, %shlc2
+  ret i32 %add
+}
+
 define dso_local i64 @shladdc1c264(i64 %a, i64 %b) local_unnamed_addr #0 {
 ; RV32IM-LABEL: shladdc1c264:
 ; RV32IM:       # %bb.0: # %entry



More information about the llvm-commits mailing list