[llvm] 0ae1506 - [RISCV] Add ISel patterns for Xqciac QC_SHLADD instruction (#148256)

via llvm-commits llvm-commits at lists.llvm.org
Mon Jul 14 04:13:45 PDT 2025


Author: Sudharsan Veeravalli
Date: 2025-07-14T16:43:41+05:30
New Revision: 0ae1506847ee9516630fe08f74d0db516eeaa993

URL: https://github.com/llvm/llvm-project/commit/0ae1506847ee9516630fe08f74d0db516eeaa993
DIFF: https://github.com/llvm/llvm-project/commit/0ae1506847ee9516630fe08f74d0db516eeaa993.diff

LOG: [RISCV] Add ISel patterns for Xqciac QC_SHLADD instruction (#148256)

Add a couple of patterns to generate the Xqciac QC_SHLADD shift left and
add immediate instruction.

Added: 
    

Modified: 
    llvm/lib/Target/RISCV/RISCVISelLowering.cpp
    llvm/lib/Target/RISCV/RISCVInstrInfo.cpp
    llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td
    llvm/test/CodeGen/RISCV/xqciac.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index 7c72d074a35b6..359e529df46f3 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -15032,10 +15032,15 @@ 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())
+  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 (!HasStdExtZba && !HasVendorXAndesPerf && !HasVendorXqciac)
     return SDValue();
 
   // Skip for vector types and larger types.
@@ -15060,14 +15065,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)
+  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/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 4fc98385b4e00..0f222988114b8 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td
@@ -1359,6 +1359,10 @@ class SelectQCbi<CondCode Cond, DAGOperand InTyImm, Pseudo OpNode >
 let Predicates = [HasVendorXqciac, IsRV32] in {
 def : Pat<(i32 (add GPRNoX0:$rd, (mul GPRNoX0:$rs1, simm12:$imm12))),
           (QC_MULIADD GPRNoX0:$rd, GPRNoX0:$rs1, simm12:$imm12)>;
+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 4cee0910608f3..a3b4e7829a51d 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, a0, a1, 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, a0, a1, 5
 ; RV32IZBAMXQCIAC-NEXT:    ret
 entry:
   %mul = mul nsw i32 %b, 32
@@ -269,3 +266,200 @@ 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, a0, a1, 31
+; RV32IMXQCIAC-NEXT:    ret
+;
+; RV32IZBAMXQCIAC-LABEL: shladd:
+; RV32IZBAMXQCIAC:       # %bb.0: # %entry
+; RV32IZBAMXQCIAC-NEXT:    qc.shladd a0, a0, a1, 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, a0, a2, 31
+; RV32IMXQCIAC-NEXT:    slli a2, a2, 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
+; RV32IMXQCIAC-NEXT:    ret
+;
+; RV32IZBAMXQCIAC-LABEL: shladd64:
+; RV32IZBAMXQCIAC:       # %bb.0: # %entry
+; RV32IZBAMXQCIAC-NEXT:    srli a4, a2, 1
+; RV32IZBAMXQCIAC-NEXT:    qc.shladd a0, a0, a2, 31
+; RV32IZBAMXQCIAC-NEXT:    slli a2, a2, 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
+; 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, a0, a1, 22
+; RV32IMXQCIAC-NEXT:    ret
+;
+; RV32IZBAMXQCIAC-LABEL: shladd_ordisjoint:
+; RV32IZBAMXQCIAC:       # %bb.0: # %entry
+; RV32IZBAMXQCIAC-NEXT:    qc.shladd a0, a0, a1, 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, a1, a0, 5
+; RV32IMXQCIAC-NEXT:    slli a0, a0, 26
+; RV32IMXQCIAC-NEXT:    ret
+;
+; RV32IZBAMXQCIAC-LABEL: shladdc1c2:
+; RV32IZBAMXQCIAC:       # %bb.0: # %entry
+; RV32IZBAMXQCIAC-NEXT:    qc.shladd a0, a1, a0, 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 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
+; 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, a1, a3, 20
+; RV32IMXQCIAC-NEXT:    slli a2, a2, 20
+; 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, a1, a3, 20
+; RV32IZBAMXQCIAC-NEXT:    slli a2, a2, 20
+; RV32IZBAMXQCIAC-NEXT:    qc.shladd a1, a1, a0, 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, a1, a0, 12
+; RV32IMXQCIAC-NEXT:    ret
+;
+; RV32IZBAMXQCIAC-LABEL: shladdc1equalc2:
+; RV32IZBAMXQCIAC:       # %bb.0: # %entry
+; RV32IZBAMXQCIAC-NEXT:    slli a1, a1, 12
+; RV32IZBAMXQCIAC-NEXT:    qc.shladd a0, a1, a0, 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
+}


        


More information about the llvm-commits mailing list