[llvm] [RISCV] Add ISel patterns for Xqcilia instructions (PR #135724)

Sudharsan Veeravalli via llvm-commits llvm-commits at lists.llvm.org
Tue Apr 15 00:54:20 PDT 2025


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

>From 5d145820b1032d9d13dcb6650550459873c3a518 Mon Sep 17 00:00:00 2001
From: Sudharsan Veeravalli <quic_svs at quicinc.com>
Date: Tue, 15 Apr 2025 06:49:04 +0530
Subject: [PATCH 1/3] [RISCV] Add ISel patterns for Xqcilia instructions

This patch adds instruction selection patterns for generating the long
immediate arithmetic instructions.
---
 llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td |  41 +++++++-
 llvm/test/CodeGen/RISCV/xqcilia.ll          | 108 ++++++++++++++++++++
 2 files changed, 148 insertions(+), 1 deletion(-)
 create mode 100644 llvm/test/CodeGen/RISCV/xqcilia.ll

diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td b/llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td
index 4ac17c8283866..d915177278828 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td
@@ -125,7 +125,8 @@ class BareSImmNAsmOperand<int width>
 
 // 32-bit Immediate, used by RV32 Instructions in 32-bit operations, so no
 // sign-/zero-extension. This is represented internally as a signed 32-bit value.
-def bare_simm32 : RISCVOp<XLenVT> {
+def bare_simm32 : RISCVOp<XLenVT>,
+                  ImmLeaf<XLenVT, [{return isInt<32>(Imm);}]> {
   let ParserMatchClass = BareSImmNAsmOperand<32>;
   let EncoderMethod = "getImmOpValue";
   let DecoderMethod = "decodeSImmOperand<32>";
@@ -1245,5 +1246,43 @@ def PseudoQC_E_JAL: Pseudo<(outs), (ins pseudo_qc_jump_symbol:$func), [],
 // Code Gen Patterns
 //===----------------------------------------------------------------------===//
 
+/// Generic pattern classes
+
+class PatGprNoX0Simm26<SDPatternOperator OpNode, RVInst48 Inst>
+    : Pat<(i32 (OpNode (i32 GPRNoX0:$rs1), simm26:$imm)),
+          (Inst GPRNoX0:$rs1, simm26:$imm)>;
+
+class PatGprNoX0Imm32<SDPatternOperator OpNode, RVInst48 Inst>
+    : Pat<(i32 (OpNode (i32 GPRNoX0:$rs1), bare_simm32:$imm)),
+          (Inst GPRNoX0:$rs1, bare_simm32:$imm)>;
+
+/// Simple arithmetic operations
+
+let Predicates = [HasVendorXqcilia, IsRV32] in {
+//
+// LLVM sorts by number of covered nodes plus AddedComplexity,
+// highest first. All these patterns cover the same number of
+// nodes (but the immediate leafs are different sizes), so we use
+// AddedComplexity to deprioritise the longer immediate encodings,
+// and achieve the following order for pattern matching:
+// 1. Base RISC-V arithmetic instructions
+// 2. Xqcilia instructions with 26 bit immediate
+// 3. Xqcilia instructions with 32 bit immediate
+//
+let AddedComplexity = -2 in {
+def : PatGprNoX0Imm32<add, QC_E_ADDAI>;
+def : PatGprNoX0Imm32<and, QC_E_ANDAI>;
+def : PatGprNoX0Imm32<or, QC_E_ORAI>;
+def : PatGprNoX0Imm32<xor, QC_E_XORAI>;
+} // AddedComplexity = -2
+
+let AddedComplexity = -1 in {
+def : PatGprNoX0Simm26<add, QC_E_ADDI>;
+def : PatGprNoX0Simm26<and, QC_E_ANDI>;
+def : PatGprNoX0Simm26<or, QC_E_ORI>;
+def : PatGprNoX0Simm26<xor, QC_E_XORI>;
+} // AddedComplexity = -1
+} // Predicates = [HasVendorXqcilia, IsRV32]
+
 let Predicates = [HasVendorXqciint, IsRV32] in
 def : Pat<(riscv_mileaveret_glue), (QC_C_MILEAVERET)>;
diff --git a/llvm/test/CodeGen/RISCV/xqcilia.ll b/llvm/test/CodeGen/RISCV/xqcilia.ll
new file mode 100644
index 0000000000000..0f14044d62dc8
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/xqcilia.ll
@@ -0,0 +1,108 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; Test that we are able to generate the Xqcilia instructions
+; RUN: llc < %s -mtriple=riscv32 | FileCheck %s -check-prefix=RV32I
+; RUN: llc < %s -mtriple=riscv32 -mattr=+experimental-xqcilia | FileCheck %s -check-prefix=RV32XQCILIA
+
+define i32 @add(i32 %a, i32 %b) {
+; RV32I-LABEL: add:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    lui a2, 65536
+; RV32I-NEXT:    add a0, a0, a2
+; RV32I-NEXT:    lui a2, 573
+; RV32I-NEXT:    addi a2, a2, -1330
+; RV32I-NEXT:    add a1, a1, a2
+; RV32I-NEXT:    and a0, a1, a0
+; RV32I-NEXT:    addi a0, a0, 13
+; RV32I-NEXT:    ret
+;
+; RV32XQCILIA-LABEL: add:
+; RV32XQCILIA:       # %bb.0:
+; RV32XQCILIA-NEXT:    qc.e.addi a1, a1, 2345678
+; RV32XQCILIA-NEXT:    qc.e.addai a0, 268435456
+; RV32XQCILIA-NEXT:    and a0, a0, a1
+; RV32XQCILIA-NEXT:    addi a0, a0, 13
+; RV32XQCILIA-NEXT:    ret
+ %addai = add i32 %a, 268435456
+ %add = add i32 %b, 2345678
+ %and = and i32 %add, %addai
+ %res = add i32 %and, 13
+ ret i32 %res
+}
+
+define i32 @and(i32 %a, i32 %b) {
+; RV32I-LABEL: and:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    lui a2, 65536
+; RV32I-NEXT:    and a0, a0, a2
+; RV32I-NEXT:    lui a2, 573
+; RV32I-NEXT:    addi a2, a2, -1330
+; RV32I-NEXT:    and a1, a1, a2
+; RV32I-NEXT:    srl a0, a1, a0
+; RV32I-NEXT:    andi a0, a0, 10
+; RV32I-NEXT:    ret
+;
+; RV32XQCILIA-LABEL: and:
+; RV32XQCILIA:       # %bb.0:
+; RV32XQCILIA-NEXT:    qc.e.andi a1, a1, 2345678
+; RV32XQCILIA-NEXT:    qc.e.andai a0, 268435456
+; RV32XQCILIA-NEXT:    srl a0, a1, a0
+; RV32XQCILIA-NEXT:    andi a0, a0, 10
+; RV32XQCILIA-NEXT:    ret
+ %andai = and i32 %a, 268435456
+ %and = and i32 %b, 2345678
+ %srl = lshr i32 %and, %andai
+ %res = and i32 %srl, 10
+ ret i32 %res
+}
+
+define i32 @or(i32 %a, i32 %b) {
+; RV32I-LABEL: or:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    lui a2, 65536
+; RV32I-NEXT:    or a0, a0, a2
+; RV32I-NEXT:    lui a2, 573
+; RV32I-NEXT:    addi a2, a2, -1330
+; RV32I-NEXT:    or a1, a1, a2
+; RV32I-NEXT:    add a0, a1, a0
+; RV32I-NEXT:    ori a0, a0, 13
+; RV32I-NEXT:    ret
+;
+; RV32XQCILIA-LABEL: or:
+; RV32XQCILIA:       # %bb.0:
+; RV32XQCILIA-NEXT:    qc.e.ori a1, a1, 2345678
+; RV32XQCILIA-NEXT:    qc.e.orai a0, 268435456
+; RV32XQCILIA-NEXT:    add a0, a0, a1
+; RV32XQCILIA-NEXT:    ori a0, a0, 13
+; RV32XQCILIA-NEXT:    ret
+ %orai = or i32 %a, 268435456
+ %or = or i32 %b, 2345678
+ %add = add i32 %or, %orai
+ %res = or i32 %add, 13
+ ret i32 %res
+}
+
+define i32 @xor(i32 %a, i32 %b) {
+; RV32I-LABEL: xor:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    lui a2, 65536
+; RV32I-NEXT:    xor a0, a0, a2
+; RV32I-NEXT:    lui a2, 573
+; RV32I-NEXT:    addi a2, a2, -1330
+; RV32I-NEXT:    xor a1, a1, a2
+; RV32I-NEXT:    add a0, a1, a0
+; RV32I-NEXT:    xori a0, a0, 13
+; RV32I-NEXT:    ret
+;
+; RV32XQCILIA-LABEL: xor:
+; RV32XQCILIA:       # %bb.0:
+; RV32XQCILIA-NEXT:    qc.e.xori a1, a1, 2345678
+; RV32XQCILIA-NEXT:    qc.e.xorai a0, 268435456
+; RV32XQCILIA-NEXT:    add a0, a0, a1
+; RV32XQCILIA-NEXT:    xori a0, a0, 13
+; RV32XQCILIA-NEXT:    ret
+ %xorai = xor i32 %a, 268435456
+ %xor = xor i32 %b, 2345678
+ %add = add i32 %xor, %xorai
+ %res = xor i32 %add, 13
+ ret i32 %res
+}

>From edf14a22d849efcfd02f75c8484c4bed7020706e Mon Sep 17 00:00:00 2001
From: Sudharsan Veeravalli <quic_svs at quicinc.com>
Date: Tue, 15 Apr 2025 13:11:11 +0530
Subject: [PATCH 2/3] Use ImmLeaf

---
 llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td | 46 +++++++++------------
 1 file changed, 19 insertions(+), 27 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td b/llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td
index d915177278828..bc8179862c0e7 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td
@@ -118,6 +118,12 @@ def simm20_li : RISCVOp<XLenVT> {
 
 def simm26 : RISCVSImmLeafOp<26>;
 
+def simm26_nosimm12 : ImmLeaf<XLenVT, [{
+  return isInt<26>(Imm) && !isInt<12>(Imm);}]>;
+
+def simm32_nosimm26 : ImmLeaf<XLenVT, [{
+  return isInt<32>(Imm) && !isInt<26>(Imm);}]>;
+
 class BareSImmNAsmOperand<int width>
     : ImmAsmOperand<"BareS", width, ""> {
   let PredicateMethod = "isBareSimmN<" # width # ">";
@@ -1248,40 +1254,26 @@ def PseudoQC_E_JAL: Pseudo<(outs), (ins pseudo_qc_jump_symbol:$func), [],
 
 /// Generic pattern classes
 
-class PatGprNoX0Simm26<SDPatternOperator OpNode, RVInst48 Inst>
-    : Pat<(i32 (OpNode (i32 GPRNoX0:$rs1), simm26:$imm)),
+class PatGprNoX0Simm26NoSimm12<SDPatternOperator OpNode, RVInst48 Inst>
+    : Pat<(i32 (OpNode (i32 GPRNoX0:$rs1), simm26_nosimm12:$imm)),
           (Inst GPRNoX0:$rs1, simm26:$imm)>;
 
-class PatGprNoX0Imm32<SDPatternOperator OpNode, RVInst48 Inst>
-    : Pat<(i32 (OpNode (i32 GPRNoX0:$rs1), bare_simm32:$imm)),
+class PatGprNoX0Simm32NoSimm26<SDPatternOperator OpNode, RVInst48 Inst>
+    : Pat<(i32 (OpNode (i32 GPRNoX0:$rs1), simm32_nosimm26:$imm)),
           (Inst GPRNoX0:$rs1, bare_simm32:$imm)>;
 
 /// Simple arithmetic operations
 
 let Predicates = [HasVendorXqcilia, IsRV32] in {
-//
-// LLVM sorts by number of covered nodes plus AddedComplexity,
-// highest first. All these patterns cover the same number of
-// nodes (but the immediate leafs are different sizes), so we use
-// AddedComplexity to deprioritise the longer immediate encodings,
-// and achieve the following order for pattern matching:
-// 1. Base RISC-V arithmetic instructions
-// 2. Xqcilia instructions with 26 bit immediate
-// 3. Xqcilia instructions with 32 bit immediate
-//
-let AddedComplexity = -2 in {
-def : PatGprNoX0Imm32<add, QC_E_ADDAI>;
-def : PatGprNoX0Imm32<and, QC_E_ANDAI>;
-def : PatGprNoX0Imm32<or, QC_E_ORAI>;
-def : PatGprNoX0Imm32<xor, QC_E_XORAI>;
-} // AddedComplexity = -2
-
-let AddedComplexity = -1 in {
-def : PatGprNoX0Simm26<add, QC_E_ADDI>;
-def : PatGprNoX0Simm26<and, QC_E_ANDI>;
-def : PatGprNoX0Simm26<or, QC_E_ORI>;
-def : PatGprNoX0Simm26<xor, QC_E_XORI>;
-} // AddedComplexity = -1
+def : PatGprNoX0Simm32NoSimm26<add, QC_E_ADDAI>;
+def : PatGprNoX0Simm32NoSimm26<and, QC_E_ANDAI>;
+def : PatGprNoX0Simm32NoSimm26<or, QC_E_ORAI>;
+def : PatGprNoX0Simm32NoSimm26<xor, QC_E_XORAI>;
+
+def : PatGprNoX0Simm26NoSimm12<add, QC_E_ADDI>;
+def : PatGprNoX0Simm26NoSimm12<and, QC_E_ANDI>;
+def : PatGprNoX0Simm26NoSimm12<or, QC_E_ORI>;
+def : PatGprNoX0Simm26NoSimm12<xor, QC_E_XORI>;
 } // Predicates = [HasVendorXqcilia, IsRV32]
 
 let Predicates = [HasVendorXqciint, IsRV32] in

>From a65f177a0357893b132997978fb9af2bca09db5a Mon Sep 17 00:00:00 2001
From: Sudharsan Veeravalli <quic_svs at quicinc.com>
Date: Tue, 15 Apr 2025 13:23:59 +0530
Subject: [PATCH 3/3] Minor fixes

---
 llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td b/llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td
index bc8179862c0e7..7b17dc8fc94e9 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td
@@ -131,8 +131,7 @@ class BareSImmNAsmOperand<int width>
 
 // 32-bit Immediate, used by RV32 Instructions in 32-bit operations, so no
 // sign-/zero-extension. This is represented internally as a signed 32-bit value.
-def bare_simm32 : RISCVOp<XLenVT>,
-                  ImmLeaf<XLenVT, [{return isInt<32>(Imm);}]> {
+def bare_simm32 : RISCVOp<XLenVT> {
   let ParserMatchClass = BareSImmNAsmOperand<32>;
   let EncoderMethod = "getImmOpValue";
   let DecoderMethod = "decodeSImmOperand<32>";
@@ -1256,11 +1255,11 @@ def PseudoQC_E_JAL: Pseudo<(outs), (ins pseudo_qc_jump_symbol:$func), [],
 
 class PatGprNoX0Simm26NoSimm12<SDPatternOperator OpNode, RVInst48 Inst>
     : Pat<(i32 (OpNode (i32 GPRNoX0:$rs1), simm26_nosimm12:$imm)),
-          (Inst GPRNoX0:$rs1, simm26:$imm)>;
+          (Inst GPRNoX0:$rs1, simm26_nosimm12:$imm)>;
 
 class PatGprNoX0Simm32NoSimm26<SDPatternOperator OpNode, RVInst48 Inst>
     : Pat<(i32 (OpNode (i32 GPRNoX0:$rs1), simm32_nosimm26:$imm)),
-          (Inst GPRNoX0:$rs1, bare_simm32:$imm)>;
+          (Inst GPRNoX0:$rs1, simm32_nosimm26:$imm)>;
 
 /// Simple arithmetic operations
 



More information about the llvm-commits mailing list