Skip to content

[RISCV] Add ISel patterns for Qualcomm uC Xqcicli extension #148121

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jul 15, 2025

Conversation

hchandel
Copy link
Contributor

Add CodeGen patterns for conditional load immediate instructions

Harsh Chandel added 2 commits July 4, 2025 11:54
Change-Id: I50a62db40ada7bc7f5233992d0d44f2840b1dac4
Change-Id: I4f96ecfbe7164981e543d8964db524990de0feab
@llvmbot
Copy link
Member

llvmbot commented Jul 11, 2025

@llvm/pr-subscribers-backend-risc-v

Author: quic_hchandel (hchandel)

Changes

Add CodeGen patterns for conditional load immediate instructions


Patch is 25.40 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/148121.diff

3 Files Affected:

  • (modified) llvm/lib/Target/RISCV/RISCVFeatures.td (+3)
  • (modified) llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td (+46)
  • (added) llvm/test/CodeGen/RISCV/xqcicli.ll (+717)
diff --git a/llvm/lib/Target/RISCV/RISCVFeatures.td b/llvm/lib/Target/RISCV/RISCVFeatures.td
index bf58226e0bd39..134b6df68bcad 100644
--- a/llvm/lib/Target/RISCV/RISCVFeatures.td
+++ b/llvm/lib/Target/RISCV/RISCVFeatures.td
@@ -1488,6 +1488,9 @@ def HasVendorXqcics
       AssemblerPredicate<(all_of FeatureVendorXqcics),
                          "'Xqcics' (Qualcomm uC Conditional Select Extension)">;
 
+def HasVendorXqcicsOrXqcicm
+    : Predicate<"Subtarget->hasVendorXqcics() || Subtarget->hasVendorXqcicm()">;
+
 def FeatureVendorXqcicsr
     : RISCVExperimentalExtension<0, 4, "Qualcomm uC CSR Extension">;
 def HasVendorXqcicsr
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td b/llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td
index 6a1b8965b4e13..21d1125ed472a 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td
@@ -1336,6 +1336,22 @@ class QCISELECTIICCPat<CondCode Cond, QCISELECTIICC Inst>
     : Pat<(select (XLenVT (setcc (XLenVT GPRNoX0:$rd), (XLenVT GPRNoX0:$rs1), Cond)), simm5:$simm1, simm5:$simm2),
           (Inst GPRNoX0:$rd, GPRNoX0:$rs1, simm5:$simm1, simm5:$simm2)>;
 
+class QCILICCPat<CondCode Cond, QCILICC Inst>
+    : Pat<(select (XLenVT (setcc (XLenVT GPRNoX0:$rs1), (XLenVT GPRNoX0:$rs2), Cond)), simm5:$simm, (XLenVT GPRNoX0:$rd)),
+          (Inst GPRNoX0:$rd, GPRNoX0:$rs1, GPRNoX0:$rs2, simm5:$simm)>;
+
+class QCILICCPatInv<CondCode Cond, QCILICC Inst>
+    : Pat<(select (XLenVT (setcc (XLenVT GPRNoX0:$rs1), (XLenVT GPRNoX0:$rs2), Cond)), (XLenVT GPRNoX0:$rd), simm5:$simm),
+          (Inst GPRNoX0:$rd, GPRNoX0:$rs1, GPRNoX0:$rs2, simm5:$simm)>;
+
+class QCILICCIPat<CondCode Cond, QCILICC Inst, DAGOperand InTyImm>
+    : Pat<(select (XLenVT (setcc (XLenVT GPRNoX0:$rs1), InTyImm:$imm, Cond)), simm5:$simm, (XLenVT GPRNoX0:$rd)),
+          (Inst GPRNoX0:$rd, GPRNoX0:$rs1, InTyImm:$imm, simm5:$simm)>;
+
+class QCILICCIPatInv<CondCode Cond, QCILICC Inst, DAGOperand InTyImm>
+    : Pat<(select (XLenVT (setcc (XLenVT GPRNoX0:$rs1), InTyImm:$imm, Cond)), (XLenVT GPRNoX0:$rd), simm5:$simm),
+          (Inst GPRNoX0:$rd, GPRNoX0:$rs1, InTyImm:$imm, simm5:$simm)>;
+
 // Match `riscv_brcc` and lower to the appropriate XQCIBI branch instruction.
 class BcciPat<CondCode Cond, QCIBranchInst_rii Inst, DAGOperand InTyImm>
     : Pat<(riscv_brcc (XLenVT GPRNoX0:$rs1), InTyImm:$rs2, Cond, bb:$imm12),
@@ -1485,6 +1501,36 @@ def : QCIMVCCIPat <SETLT,  QC_MVLTI, simm5>;
 def : QCIMVCCIPat <SETULT, QC_MVLTUI, uimm5>;
 }
 
+let Predicates = [HasVendorXqcicli, HasVendorXqcicsOrXqcicm, IsRV32] in {
+def : QCILICCPat <SETEQ,  QC_LIEQ>;
+def : QCILICCPat <SETNE,  QC_LINE>;
+def : QCILICCPat <SETLT,  QC_LILT>;
+def : QCILICCPat <SETGE,  QC_LIGE>;
+def : QCILICCPat <SETULT, QC_LILTU>;
+def : QCILICCPat <SETUGE, QC_LIGEU>;
+
+def : QCILICCIPat <SETEQ,  QC_LIEQI, simm5>;
+def : QCILICCIPat <SETNE,  QC_LINEI, simm5>;
+def : QCILICCIPat <SETLT,  QC_LILTI, simm5>;
+def : QCILICCIPat <SETGE,  QC_LIGEI, simm5>;
+def : QCILICCIPat <SETULT, QC_LILTUI, uimm5>;
+def : QCILICCIPat <SETUGE, QC_LIGEUI, uimm5>;
+
+def : QCILICCPatInv <SETNE,  QC_LIEQ>;
+def : QCILICCPatInv <SETEQ,  QC_LINE>;
+def : QCILICCPatInv <SETGE,  QC_LILT>;
+def : QCILICCPatInv <SETLT,  QC_LIGE>;
+def : QCILICCPatInv <SETUGE, QC_LILTU>;
+def : QCILICCPatInv <SETULT, QC_LIGEU>;
+
+def : QCILICCIPatInv <SETNE,  QC_LIEQI, simm5>;
+def : QCILICCIPatInv <SETEQ,  QC_LINEI, simm5>;
+def : QCILICCIPatInv <SETGE,  QC_LILTI, simm5>;
+def : QCILICCIPatInv <SETLT,  QC_LIGEI, simm5>;
+def : QCILICCIPatInv <SETUGE, QC_LILTUI, uimm5>;
+def : QCILICCIPatInv <SETULT, QC_LIGEUI, uimm5>;
+}
+
 let Predicates = [HasVendorXqcics, IsRV32] in {
 def : Pat<(select (XLenVT GPRNoX0:$rd), (XLenVT GPRNoX0:$rs2),(XLenVT GPRNoX0:$rs3)),
           (QC_SELECTNEI GPRNoX0:$rd, (XLenVT 0), GPRNoX0:$rs2, GPRNoX0:$rs3)>;
diff --git a/llvm/test/CodeGen/RISCV/xqcicli.ll b/llvm/test/CodeGen/RISCV/xqcicli.ll
new file mode 100644
index 0000000000000..b0d51429556ef
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/xqcicli.ll
@@ -0,0 +1,717 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; Test that we are able to generate the Xqcicli instructions
+; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s \
+; RUN:   | FileCheck %s --check-prefixes=RV32I
+; RUN: llc -mtriple=riscv32 -mattr=+experimental-xqcicli,+experimental-xqcics -verify-machineinstrs < %s \
+; RUN:   | FileCheck %s --check-prefixes=RV32IXQCICLI
+; RUN: llc -mtriple=riscv32 -mattr=+experimental-xqcicli,+experimental-xqcicm -verify-machineinstrs < %s \
+; RUN:   | FileCheck %s --check-prefixes=RV32IXQCICLI
+
+define i32 @select_cc_example_eq(i32 %a, i32 %b, i32 %x, i32 %y) {
+; RV32I-LABEL: select_cc_example_eq:
+; RV32I:       # %bb.0: # %entry
+; RV32I-NEXT:    bne a1, a2, .LBB0_2
+; RV32I-NEXT:  # %bb.1: # %entry
+; RV32I-NEXT:    li a0, 11
+; RV32I-NEXT:  .LBB0_2: # %entry
+; RV32I-NEXT:    ret
+;
+; RV32IXQCICLI-LABEL: select_cc_example_eq:
+; RV32IXQCICLI:       # %bb.0: # %entry
+; RV32IXQCICLI-NEXT:    qc.lieq a0, a1, a2, 11
+; RV32IXQCICLI-NEXT:    ret
+entry:
+  %cmp = icmp eq i32 %b, %x
+  %sel = select i1 %cmp, i32 11, i32 %a
+  ret i32 %sel
+}
+
+define i32 @select_cc_example_ne(i32 %a, i32 %b, i32 %x, i32 %y) {
+; RV32I-LABEL: select_cc_example_ne:
+; RV32I:       # %bb.0: # %entry
+; RV32I-NEXT:    beq a1, a2, .LBB1_2
+; RV32I-NEXT:  # %bb.1: # %entry
+; RV32I-NEXT:    li a0, 11
+; RV32I-NEXT:  .LBB1_2: # %entry
+; RV32I-NEXT:    ret
+;
+; RV32IXQCICLI-LABEL: select_cc_example_ne:
+; RV32IXQCICLI:       # %bb.0: # %entry
+; RV32IXQCICLI-NEXT:    qc.line a0, a1, a2, 11
+; RV32IXQCICLI-NEXT:    ret
+entry:
+  %cmp = icmp ne i32 %b, %x
+  %sel = select i1 %cmp, i32 11, i32 %a
+  ret i32 %sel
+}
+
+define i32 @select_cc_example_slt(i32 %a, i32 %b, i32 %x, i32 %y) {
+; RV32I-LABEL: select_cc_example_slt:
+; RV32I:       # %bb.0: # %entry
+; RV32I-NEXT:    bge a1, a2, .LBB2_2
+; RV32I-NEXT:  # %bb.1: # %entry
+; RV32I-NEXT:    li a0, 11
+; RV32I-NEXT:  .LBB2_2: # %entry
+; RV32I-NEXT:    ret
+;
+; RV32IXQCICLI-LABEL: select_cc_example_slt:
+; RV32IXQCICLI:       # %bb.0: # %entry
+; RV32IXQCICLI-NEXT:    qc.lilt a0, a1, a2, 11
+; RV32IXQCICLI-NEXT:    ret
+entry:
+  %cmp = icmp slt i32 %b, %x
+  %sel = select i1 %cmp, i32 11, i32 %a
+  ret i32 %sel
+}
+
+define i32 @select_cc_example_sge(i32 %a, i32 %b, i32 %x, i32 %y) {
+; RV32I-LABEL: select_cc_example_sge:
+; RV32I:       # %bb.0: # %entry
+; RV32I-NEXT:    blt a1, a2, .LBB3_2
+; RV32I-NEXT:  # %bb.1: # %entry
+; RV32I-NEXT:    li a0, 11
+; RV32I-NEXT:  .LBB3_2: # %entry
+; RV32I-NEXT:    ret
+;
+; RV32IXQCICLI-LABEL: select_cc_example_sge:
+; RV32IXQCICLI:       # %bb.0: # %entry
+; RV32IXQCICLI-NEXT:    qc.lige a0, a1, a2, 11
+; RV32IXQCICLI-NEXT:    ret
+entry:
+  %cmp = icmp sge i32 %b, %x
+  %sel = select i1 %cmp, i32 11, i32 %a
+  ret i32 %sel
+}
+
+define i32 @select_cc_example_uge(i32 %a, i32 %b, i32 %x, i32 %y) {
+; RV32I-LABEL: select_cc_example_uge:
+; RV32I:       # %bb.0: # %entry
+; RV32I-NEXT:    bltu a1, a2, .LBB4_2
+; RV32I-NEXT:  # %bb.1: # %entry
+; RV32I-NEXT:    li a0, 11
+; RV32I-NEXT:  .LBB4_2: # %entry
+; RV32I-NEXT:    ret
+;
+; RV32IXQCICLI-LABEL: select_cc_example_uge:
+; RV32IXQCICLI:       # %bb.0: # %entry
+; RV32IXQCICLI-NEXT:    qc.ligeu a0, a1, a2, 11
+; RV32IXQCICLI-NEXT:    ret
+entry:
+  %cmp = icmp uge i32 %b, %x
+  %sel = select i1 %cmp, i32 11, i32 %a
+  ret i32 %sel
+}
+
+define i32 @select_cc_example_ult(i32 %a, i32 %b, i32 %x, i32 %y) {
+; RV32I-LABEL: select_cc_example_ult:
+; RV32I:       # %bb.0: # %entry
+; RV32I-NEXT:    bgeu a1, a2, .LBB5_2
+; RV32I-NEXT:  # %bb.1: # %entry
+; RV32I-NEXT:    li a0, 11
+; RV32I-NEXT:  .LBB5_2: # %entry
+; RV32I-NEXT:    ret
+;
+; RV32IXQCICLI-LABEL: select_cc_example_ult:
+; RV32IXQCICLI:       # %bb.0: # %entry
+; RV32IXQCICLI-NEXT:    qc.liltu a0, a1, a2, 11
+; RV32IXQCICLI-NEXT:    ret
+entry:
+  %cmp = icmp ult i32 %b, %x
+  %sel = select i1 %cmp, i32 11, i32 %a
+  ret i32 %sel
+}
+
+define i32 @select_cc_example_eq_c(i32 %a, i32 %b, i32 %x, i32 %y) {
+; RV32I-LABEL: select_cc_example_eq_c:
+; RV32I:       # %bb.0: # %entry
+; RV32I-NEXT:    beq a1, a2, .LBB6_2
+; RV32I-NEXT:  # %bb.1: # %entry
+; RV32I-NEXT:    li a0, 11
+; RV32I-NEXT:  .LBB6_2: # %entry
+; RV32I-NEXT:    ret
+;
+; RV32IXQCICLI-LABEL: select_cc_example_eq_c:
+; RV32IXQCICLI:       # %bb.0: # %entry
+; RV32IXQCICLI-NEXT:    qc.line a0, a1, a2, 11
+; RV32IXQCICLI-NEXT:    ret
+entry:
+  %cmp = icmp eq i32 %b, %x
+  %sel = select i1 %cmp, i32 %a, i32 11
+  ret i32 %sel
+}
+
+define i32 @select_cc_example_ne_c(i32 %a, i32 %b, i32 %x, i32 %y) {
+; RV32I-LABEL: select_cc_example_ne_c:
+; RV32I:       # %bb.0: # %entry
+; RV32I-NEXT:    bne a1, a2, .LBB7_2
+; RV32I-NEXT:  # %bb.1: # %entry
+; RV32I-NEXT:    li a0, 11
+; RV32I-NEXT:  .LBB7_2: # %entry
+; RV32I-NEXT:    ret
+;
+; RV32IXQCICLI-LABEL: select_cc_example_ne_c:
+; RV32IXQCICLI:       # %bb.0: # %entry
+; RV32IXQCICLI-NEXT:    qc.lieq a0, a1, a2, 11
+; RV32IXQCICLI-NEXT:    ret
+entry:
+  %cmp = icmp ne i32 %b, %x
+  %sel = select i1 %cmp, i32 %a, i32 11
+  ret i32 %sel
+}
+
+define i32 @select_cc_example_slt_c(i32 %a, i32 %b, i32 %x, i32 %y) {
+; RV32I-LABEL: select_cc_example_slt_c:
+; RV32I:       # %bb.0: # %entry
+; RV32I-NEXT:    blt a1, a2, .LBB8_2
+; RV32I-NEXT:  # %bb.1: # %entry
+; RV32I-NEXT:    li a0, 11
+; RV32I-NEXT:  .LBB8_2: # %entry
+; RV32I-NEXT:    ret
+;
+; RV32IXQCICLI-LABEL: select_cc_example_slt_c:
+; RV32IXQCICLI:       # %bb.0: # %entry
+; RV32IXQCICLI-NEXT:    qc.lige a0, a1, a2, 11
+; RV32IXQCICLI-NEXT:    ret
+entry:
+  %cmp = icmp slt i32 %b, %x
+  %sel = select i1 %cmp, i32 %a, i32 11
+  ret i32 %sel
+}
+
+define i32 @select_cc_example_sge_c(i32 %a, i32 %b, i32 %x, i32 %y) {
+; RV32I-LABEL: select_cc_example_sge_c:
+; RV32I:       # %bb.0: # %entry
+; RV32I-NEXT:    bge a1, a2, .LBB9_2
+; RV32I-NEXT:  # %bb.1: # %entry
+; RV32I-NEXT:    li a0, 11
+; RV32I-NEXT:  .LBB9_2: # %entry
+; RV32I-NEXT:    ret
+;
+; RV32IXQCICLI-LABEL: select_cc_example_sge_c:
+; RV32IXQCICLI:       # %bb.0: # %entry
+; RV32IXQCICLI-NEXT:    qc.lilt a0, a1, a2, 11
+; RV32IXQCICLI-NEXT:    ret
+entry:
+  %cmp = icmp sge i32 %b, %x
+  %sel = select i1 %cmp, i32 %a, i32 11
+  ret i32 %sel
+}
+
+define i32 @select_cc_example_uge_c(i32 %a, i32 %b, i32 %x, i32 %y) {
+; RV32I-LABEL: select_cc_example_uge_c:
+; RV32I:       # %bb.0: # %entry
+; RV32I-NEXT:    bgeu a1, a2, .LBB10_2
+; RV32I-NEXT:  # %bb.1: # %entry
+; RV32I-NEXT:    li a0, 11
+; RV32I-NEXT:  .LBB10_2: # %entry
+; RV32I-NEXT:    ret
+;
+; RV32IXQCICLI-LABEL: select_cc_example_uge_c:
+; RV32IXQCICLI:       # %bb.0: # %entry
+; RV32IXQCICLI-NEXT:    qc.liltu a0, a1, a2, 11
+; RV32IXQCICLI-NEXT:    ret
+entry:
+  %cmp = icmp uge i32 %b, %x
+  %sel = select i1 %cmp, i32 %a, i32 11
+  ret i32 %sel
+}
+
+define i32 @select_cc_example_ult_c(i32 %a, i32 %b, i32 %x, i32 %y) {
+; RV32I-LABEL: select_cc_example_ult_c:
+; RV32I:       # %bb.0: # %entry
+; RV32I-NEXT:    bltu a1, a2, .LBB11_2
+; RV32I-NEXT:  # %bb.1: # %entry
+; RV32I-NEXT:    li a0, 11
+; RV32I-NEXT:  .LBB11_2: # %entry
+; RV32I-NEXT:    ret
+;
+; RV32IXQCICLI-LABEL: select_cc_example_ult_c:
+; RV32IXQCICLI:       # %bb.0: # %entry
+; RV32IXQCICLI-NEXT:    qc.ligeu a0, a1, a2, 11
+; RV32IXQCICLI-NEXT:    ret
+entry:
+  %cmp = icmp ult i32 %b, %x
+  %sel = select i1 %cmp, i32 %a, i32 11
+  ret i32 %sel
+}
+
+define i32 @select_cc_example_eqi(i32 %a, i32 %b, i32 %x, i32 %y) {
+; RV32I-LABEL: select_cc_example_eqi:
+; RV32I:       # %bb.0: # %entry
+; RV32I-NEXT:    li a2, 12
+; RV32I-NEXT:    bne a1, a2, .LBB12_2
+; RV32I-NEXT:  # %bb.1: # %entry
+; RV32I-NEXT:    li a0, 11
+; RV32I-NEXT:  .LBB12_2: # %entry
+; RV32I-NEXT:    ret
+;
+; RV32IXQCICLI-LABEL: select_cc_example_eqi:
+; RV32IXQCICLI:       # %bb.0: # %entry
+; RV32IXQCICLI-NEXT:    qc.lieqi a0, a1, 12, 11
+; RV32IXQCICLI-NEXT:    ret
+entry:
+  %cmp = icmp eq i32 %b, 12
+  %sel = select i1 %cmp, i32 11, i32 %a
+  ret i32 %sel
+}
+
+define i32 @select_cc_example_nei(i32 %a, i32 %b, i32 %x, i32 %y) {
+; RV32I-LABEL: select_cc_example_nei:
+; RV32I:       # %bb.0: # %entry
+; RV32I-NEXT:    li a2, 12
+; RV32I-NEXT:    beq a1, a2, .LBB13_2
+; RV32I-NEXT:  # %bb.1: # %entry
+; RV32I-NEXT:    li a0, 11
+; RV32I-NEXT:  .LBB13_2: # %entry
+; RV32I-NEXT:    ret
+;
+; RV32IXQCICLI-LABEL: select_cc_example_nei:
+; RV32IXQCICLI:       # %bb.0: # %entry
+; RV32IXQCICLI-NEXT:    qc.linei a0, a1, 12, 11
+; RV32IXQCICLI-NEXT:    ret
+entry:
+  %cmp = icmp ne i32 %b, 12
+  %sel = select i1 %cmp, i32 11, i32 %a
+  ret i32 %sel
+}
+
+define i32 @select_cc_example_slti(i32 %a, i32 %b, i32 %x, i32 %y) {
+; RV32I-LABEL: select_cc_example_slti:
+; RV32I:       # %bb.0: # %entry
+; RV32I-NEXT:    li a2, 12
+; RV32I-NEXT:    bge a1, a2, .LBB14_2
+; RV32I-NEXT:  # %bb.1: # %entry
+; RV32I-NEXT:    li a0, 11
+; RV32I-NEXT:  .LBB14_2: # %entry
+; RV32I-NEXT:    ret
+;
+; RV32IXQCICLI-LABEL: select_cc_example_slti:
+; RV32IXQCICLI:       # %bb.0: # %entry
+; RV32IXQCICLI-NEXT:    qc.lilti a0, a1, 12, 11
+; RV32IXQCICLI-NEXT:    ret
+entry:
+  %cmp = icmp slt i32 %b, 12
+  %sel = select i1 %cmp, i32 11, i32 %a
+  ret i32 %sel
+}
+
+define i32 @select_cc_example_sgei(i32 %a, i32 %b, i32 %x, i32 %y) {
+; RV32I-LABEL: select_cc_example_sgei:
+; RV32I:       # %bb.0: # %entry
+; RV32I-NEXT:    li a2, 11
+; RV32I-NEXT:    bge a2, a1, .LBB15_2
+; RV32I-NEXT:  # %bb.1: # %entry
+; RV32I-NEXT:    li a0, 11
+; RV32I-NEXT:  .LBB15_2: # %entry
+; RV32I-NEXT:    ret
+;
+; RV32IXQCICLI-LABEL: select_cc_example_sgei:
+; RV32IXQCICLI:       # %bb.0: # %entry
+; RV32IXQCICLI-NEXT:    qc.ligei a0, a1, 12, 11
+; RV32IXQCICLI-NEXT:    ret
+entry:
+  %cmp = icmp sge i32 %b, 12
+  %sel = select i1 %cmp, i32 11, i32 %a
+  ret i32 %sel
+}
+
+define i32 @select_cc_example_ulti(i32 %a, i32 %b, i32 %x, i32 %y) {
+; RV32I-LABEL: select_cc_example_ulti:
+; RV32I:       # %bb.0: # %entry
+; RV32I-NEXT:    li a2, 12
+; RV32I-NEXT:    bgeu a1, a2, .LBB16_2
+; RV32I-NEXT:  # %bb.1: # %entry
+; RV32I-NEXT:    li a0, 11
+; RV32I-NEXT:  .LBB16_2: # %entry
+; RV32I-NEXT:    ret
+;
+; RV32IXQCICLI-LABEL: select_cc_example_ulti:
+; RV32IXQCICLI:       # %bb.0: # %entry
+; RV32IXQCICLI-NEXT:    qc.liltui a0, a1, 12, 11
+; RV32IXQCICLI-NEXT:    ret
+entry:
+  %cmp = icmp ult i32 %b, 12
+  %sel = select i1 %cmp, i32 11, i32 %a
+  ret i32 %sel
+}
+
+define i32 @select_cc_example_ugei(i32 %a, i32 %b, i32 %x, i32 %y) {
+; RV32I-LABEL: select_cc_example_ugei:
+; RV32I:       # %bb.0: # %entry
+; RV32I-NEXT:    li a2, 11
+; RV32I-NEXT:    bgeu a2, a1, .LBB17_2
+; RV32I-NEXT:  # %bb.1: # %entry
+; RV32I-NEXT:    li a0, 11
+; RV32I-NEXT:  .LBB17_2: # %entry
+; RV32I-NEXT:    ret
+;
+; RV32IXQCICLI-LABEL: select_cc_example_ugei:
+; RV32IXQCICLI:       # %bb.0: # %entry
+; RV32IXQCICLI-NEXT:    qc.ligeui a0, a1, 12, 11
+; RV32IXQCICLI-NEXT:    ret
+entry:
+  %cmp = icmp uge i32 %b, 12
+  %sel = select i1 %cmp, i32 11, i32 %a
+  ret i32 %sel
+}
+
+define i32 @select_cc_example_eqi_c1(i32 %a, i32 %b, i32 %x, i32 %y) {
+; RV32I-LABEL: select_cc_example_eqi_c1:
+; RV32I:       # %bb.0: # %entry
+; RV32I-NEXT:    li a2, 12
+; RV32I-NEXT:    bne a1, a2, .LBB18_2
+; RV32I-NEXT:  # %bb.1: # %entry
+; RV32I-NEXT:    li a0, 11
+; RV32I-NEXT:  .LBB18_2: # %entry
+; RV32I-NEXT:    ret
+;
+; RV32IXQCICLI-LABEL: select_cc_example_eqi_c1:
+; RV32IXQCICLI:       # %bb.0: # %entry
+; RV32IXQCICLI-NEXT:    qc.lieqi a0, a1, 12, 11
+; RV32IXQCICLI-NEXT:    ret
+entry:
+  %cmp = icmp eq i32 12, %b
+  %sel = select i1 %cmp, i32 11, i32 %a
+  ret i32 %sel
+}
+
+define i32 @select_cc_example_nei_c1(i32 %a, i32 %b, i32 %x, i32 %y) {
+; RV32I-LABEL: select_cc_example_nei_c1:
+; RV32I:       # %bb.0: # %entry
+; RV32I-NEXT:    li a2, 12
+; RV32I-NEXT:    beq a1, a2, .LBB19_2
+; RV32I-NEXT:  # %bb.1: # %entry
+; RV32I-NEXT:    li a0, 11
+; RV32I-NEXT:  .LBB19_2: # %entry
+; RV32I-NEXT:    ret
+;
+; RV32IXQCICLI-LABEL: select_cc_example_nei_c1:
+; RV32IXQCICLI:       # %bb.0: # %entry
+; RV32IXQCICLI-NEXT:    qc.linei a0, a1, 12, 11
+; RV32IXQCICLI-NEXT:    ret
+entry:
+  %cmp = icmp ne i32 12, %b
+  %sel = select i1 %cmp, i32 11, i32 %a
+  ret i32 %sel
+}
+
+define i32 @select_cc_example_slti_c1(i32 %a, i32 %b, i32 %x, i32 %y) {
+; RV32I-LABEL: select_cc_example_slti_c1:
+; RV32I:       # %bb.0: # %entry
+; RV32I-NEXT:    li a2, 12
+; RV32I-NEXT:    bge a2, a1, .LBB20_2
+; RV32I-NEXT:  # %bb.1: # %entry
+; RV32I-NEXT:    li a0, 11
+; RV32I-NEXT:  .LBB20_2: # %entry
+; RV32I-NEXT:    ret
+;
+; RV32IXQCICLI-LABEL: select_cc_example_slti_c1:
+; RV32IXQCICLI:       # %bb.0: # %entry
+; RV32IXQCICLI-NEXT:    qc.ligei a0, a1, 13, 11
+; RV32IXQCICLI-NEXT:    ret
+entry:
+  %cmp = icmp slt i32 12, %b
+  %sel = select i1 %cmp, i32 11, i32 %a
+  ret i32 %sel
+}
+
+define i32 @select_cc_example_sgei_c1(i32 %a, i32 %b, i32 %x, i32 %y) {
+; RV32I-LABEL: select_cc_example_sgei_c1:
+; RV32I:       # %bb.0: # %entry
+; RV32I-NEXT:    li a2, 13
+; RV32I-NEXT:    bge a1, a2, .LBB21_2
+; RV32I-NEXT:  # %bb.1: # %entry
+; RV32I-NEXT:    li a0, 11
+; RV32I-NEXT:  .LBB21_2: # %entry
+; RV32I-NEXT:    ret
+;
+; RV32IXQCICLI-LABEL: select_cc_example_sgei_c1:
+; RV32IXQCICLI:       # %bb.0: # %entry
+; RV32IXQCICLI-NEXT:    qc.lilti a0, a1, 13, 11
+; RV32IXQCICLI-NEXT:    ret
+entry:
+  %cmp = icmp sge i32 12, %b
+  %sel = select i1 %cmp, i32 11, i32 %a
+  ret i32 %sel
+}
+
+define i32 @select_cc_example_ulti_c1(i32 %a, i32 %b, i32 %x, i32 %y) {
+; RV32I-LABEL: select_cc_example_ulti_c1:
+; RV32I:       # %bb.0: # %entry
+; RV32I-NEXT:    li a2, 12
+; RV32I-NEXT:    bgeu a2, a1, .LBB22_2
+; RV32I-NEXT:  # %bb.1: # %entry
+; RV32I-NEXT:    li a0, 11
+; RV32I-NEXT:  .LBB22_2: # %entry
+; RV32I-NEXT:    ret
+;
+; RV32IXQCICLI-LABEL: select_cc_example_ulti_c1:
+; RV32IXQCICLI:       # %bb.0: # %entry
+; RV32IXQCICLI-NEXT:    qc.ligeui a0, a1, 13, 11
+; RV32IXQCICLI-NEXT:    ret
+entry:
+  %cmp = icmp ult i32 12, %b
+  %sel = select i1 %cmp, i32 11, i32 %a
+  ret i32 %sel
+}
+
+define i32 @select_cc_example_ugei_c1(i32 %a, i32 %b, i32 %x, i32 %y) {
+; RV32I-LABEL: select_cc_example_ugei_c1:
+; RV32I:       # %bb.0: # %entry
+; RV32I-NEXT:    li a2, 13
+; RV32I-NEXT:    bgeu a1, a2, .LBB23_2
+; RV32I-NEXT:  # %bb.1: # %entry
+; RV32I-NEXT:    li a0, 11
+; RV32I-NEXT:  .LBB23_2: # %entry
+; RV32I-NEXT:    ret
+;
+; RV32IXQCICLI-LABEL: select_cc_example_ugei_c1:
+; RV32IXQCICLI:       # %bb.0: # %entry
+; RV32IXQCICLI-NEXT:    qc.liltui a0, a1, 13, 11
+; RV32IXQCICLI-NEXT:    ret
+entry:
+  %cmp = icmp uge i32 12, %b
+  %sel = select i1 %cmp, i32 11, i32 %a
+  ret i32 %sel
+}
+
+define i32 @select_cc_example_eqi_c2(i32 %a, i32 %b, i32 %x, i32 %y) {
+; RV32I-LABEL: select_cc_example_eqi_c2:
+; RV32I:       # %bb.0: # %entry
+; RV32I-NEXT:    li a2, 12
+; RV32I-NEXT:    beq a1, a2, .LBB24_2
+; RV32I-NEXT:  # %bb.1: # %entry
+; RV32I-NEXT:    li a0, 11
+; RV32I-NEXT:  .LBB24_2: # %entry
+; RV32I-NEXT:    ret
+;
+; RV32IXQCICLI-LABEL: select_cc_example_eqi_c2:
+; RV32IXQCICLI:       # %bb.0: # %entry
+; RV32IXQCICLI-NEXT:    qc.linei a0, a1, 12, 11
+; RV32IXQCICLI-NEXT:    ret
+entry:
+  %cmp = icmp eq i32 12, %b
+  %sel = select i1 %cmp, i32 %a, i32 11
+  ret i32 %sel
+}
+
+define i32 @select_cc_example_nei_c2(i32 %a, i32 %b, i32 %x, i32 %y) {
+; RV32I-LABEL: select_cc_example_nei_c2:
+; RV32I:       # %bb.0: # %entry
+; RV32I-NEXT:    li a2, 12
+; RV32I-NEXT:    bne a1, a2, .LBB25_2
+; RV32I-NEXT:  # %bb.1: # %entry
+; RV32I-NEXT:    li a0, 11
+; RV32I-NEXT:  .LBB25_2: # %entry
+; RV32I-NEXT:    ret
+;
+; RV32IXQCICLI-LABEL: select_cc_example_nei_c2:
+; RV32IXQCICLI:       # %bb.0: # %entry
+; RV32IXQCICLI-NEXT:    qc.lieqi a0, a1, 12, 11
+; RV32IXQCICLI-NEXT:    ret
+entry:
+  %cmp = icmp ne i32 12, %b
+  %sel = select i1 %cmp, i32 %a, i32 11
+  ret i32 %sel
+}
+
+define i32 @select_cc_example_slti_c2(i32 %a, i32 %b, i32 %x, i32 %y) {
+; RV32I-LABEL: select_cc_example_slti_c2:
+; RV32I:       # %bb.0: # %entry
+; RV32I-NEXT:    li a2, 12
+; RV32I-NEXT:    blt a2, a1, .LBB26_2
+; RV32I-NEXT:  # %bb.1: # %entry
+; RV32I-NEXT:    li a0, 11
+; RV32I-NEXT:  .LBB26_2: # %entry
+; RV32I-NEXT:    ret
+;
+; RV32IXQCICLI-LABEL: select_cc_example_slti_c2:
+; RV32IXQCICLI:       # %bb.0: # %entry
+; RV32IXQCICLI-NEXT:    qc.lilti a0, a1, 13, 11
+; RV32IXQCICLI-NEXT:    ret
+entry:
+  %cmp = icmp slt i32 12, %b
+  %se...
[truncated]

Copy link
Member

@lenary lenary left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

@@ -1485,6 +1501,36 @@ def : QCIMVCCIPat <SETLT, QC_MVLTI, simm5>;
def : QCIMVCCIPat <SETULT, QC_MVLTUI, uimm5>;
}

let Predicates = [HasVendorXqcicli, HasVendorXqcicsOrXqcicm, IsRV32] in {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need this?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's complex and a comment would be helpful, so maybe I'll sketch one out.

These patterns are written using select, which is normally not legal on RISC-V. We cannot mark select as legal when we only have xqcicli, because we cannot isel a select of a condition and two arbitrary xlen values (in registers) when we only have xqcicli (there is no instruction in the extension that can do so).

But we only care about codegen for configs where we have both xqcics/xqcicm and xqcicli - we can sort-of see xqcicli as an optimisation of the other two. If we have either of the other two, then we have marked select as legal and we can lower a select with a condition and two xlen values (in registers).

These patterns would only be used if we have one of the other two extensions, so make that clear with their predicates.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm curious why you want select to be legal for any of the Xqc instructions. It looks like select_cc (either the RISCVISD version or the ISD version) is a better match for the ISA.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I advised towards this way because I felt our best aim was to try to keep to standard nodes (which is why i avoided riscvisd::select_cc), and to try to keep to what was mostly already happening in RISC-V (which is why i avoided isd::select_cc), but evidently that instinct isn't quite right.

I would like to proceed with this approach for this patch, and later we can refactor to riscvisd::select_cc, I think.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would like to proceed with this approach for this patch, and later we can refactor to riscvisd::select_cc, I think.

I'm fine with that.

; Test that we are able to generate the Xqcicli instructions
; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s \
; RUN: | FileCheck %s --check-prefixes=RV32I
; RUN: llc -mtriple=riscv32 -mattr=+experimental-xqcicli,+experimental-xqcics -verify-machineinstrs < %s \
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about a RUN line with only xqcicli enable?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See the other comment above, but the thing here is we need at least one of xqcics or xqcicm, for select to be marked legal and the patterns to be able to apply.

Copy link
Member

@lenary lenary left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Copy link
Collaborator

@topperc topperc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Change-Id: Iecd0bdb4fc58e98154824a726cf51ae5f0606502
@hchandel hchandel merged commit 0be51cf into llvm:main Jul 15, 2025
9 checks passed
@hchandel hchandel deleted the xqcicli branch July 15, 2025 06:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants