[llvm] [RISCV] Add ISel patterns for Xqciac QC_SHLADD instruction (PR #148256)
via llvm-commits
llvm-commits at lists.llvm.org
Fri Jul 11 09:05:07 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-backend-risc-v
Author: Sudharsan Veeravalli (svs-quic)
<details>
<summary>Changes</summary>
Add a couple of patterns to generate the Xqciac QC_SHLADD shift left and add immediate instruction.
---
Full diff: https://github.com/llvm/llvm-project/pull/148256.diff
4 Files Affected:
- (modified) llvm/lib/Target/RISCV/RISCVISelLowering.cpp (+9-3)
- (modified) llvm/lib/Target/RISCV/RISCVInstrInfo.cpp (+3)
- (modified) llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td (+6)
- (modified) llvm/test/CodeGen/RISCV/xqciac.ll (+173-5)
``````````diff
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
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/148256
More information about the llvm-commits
mailing list