[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