[clang] [llvm] [RISCV] Add assembler support for the Qualcomm Xqccmi vendor extension (PR #225119)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Sep 21 08:49:28 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang-driver
Author: Sudharsan Veeravalli (svs-quic)
<details>
<summary>Changes</summary>
This patch adds support for assembling and disassembling the Qualcomm Xqccmi 16-bit Instruction Lookup Table vendor extension. The extension has a single `qc.cm.ilut` instruction which executes one or two instructions from an instruction lookup table. The encoding overlaps with `c.fld`, making `Xqccmi` and `Zcd` mutually exclusive.
The extension also adds two CSR's `qc.itba` and `qc.itdec` that contain the lookup table base address and the leading double entries count respectively.
Spec: https://github.com/qualcomm/riscv-unified-db/releases#release-Xqccmi-0.2.0
Assisted by gpt-5.6-luna.
---
Full diff: https://github.com/llvm/llvm-project/pull/225119.diff
14 Files Affected:
- (modified) clang/test/Driver/print-supported-extensions-riscv.c (+1)
- (modified) llvm/docs/RISCVUsage.md (+4)
- (modified) llvm/docs/ReleaseNotes.md (+1)
- (modified) llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp (+3)
- (modified) llvm/lib/Target/RISCV/RISCVFeatures.td (+9)
- (modified) llvm/lib/Target/RISCV/RISCVInstrInfo.td (+1)
- (added) llvm/lib/Target/RISCV/RISCVInstrInfoXqccmi.td (+30)
- (modified) llvm/lib/Target/RISCV/RISCVSystemOperands.td (+6)
- (modified) llvm/lib/TargetParser/RISCVISAInfo.cpp (+7-6)
- (modified) llvm/test/CodeGen/RISCV/features-info.ll (+1)
- (modified) llvm/test/MC/RISCV/attribute-arch.s (+3)
- (added) llvm/test/MC/RISCV/xqccmi-invalid.s (+8)
- (added) llvm/test/MC/RISCV/xqccmi-valid.s (+23)
- (modified) llvm/unittests/TargetParser/RISCVISAInfoTest.cpp (+6)
``````````diff
diff --git a/clang/test/Driver/print-supported-extensions-riscv.c b/clang/test/Driver/print-supported-extensions-riscv.c
index 545cc3673fa32..b08b93545ebb3 100644
--- a/clang/test/Driver/print-supported-extensions-riscv.c
+++ b/clang/test/Driver/print-supported-extensions-riscv.c
@@ -280,6 +280,7 @@
// CHECK-NEXT: ssijt 0.20 'Ssijt' (Interrupt Jump Table at Supervisor Level)
// CHECK-NEXT: ssip 0.20 'Ssip' (Support for Interrupt Handler Push/Pop at Supervisor Level)
// CHECK-NEXT: svukte 1.0 'Svukte' (Address-Independent Latency of User-Mode Faults to Supervisor Addresses)
+// CHECK-NEXT: xqccmi 0.2 'Xqccmi' (Qualcomm 16-bit Instruction Lookup Table)
// CHECK-NEXT: xqccmt 0.1 'Xqccmt' (Qualcomm 16-bit Table Jump)
// CHECK-NEXT: xsfmclic 0.1 'XSfmclic' (SiFive CLIC Machine-mode CSRs)
// CHECK-NEXT: xsfsclic 0.1 'XSfsclic' (SiFive CLIC Supervisor-mode CSRs)
diff --git a/llvm/docs/RISCVUsage.md b/llvm/docs/RISCVUsage.md
index 1e89c8d7d82bd..94214fa2e3c51 100644
--- a/llvm/docs/RISCVUsage.md
+++ b/llvm/docs/RISCVUsage.md
@@ -538,6 +538,10 @@ The current vendor extensions supported are:
: LLVM implements `the custom compressed opcodes present in some QingKe cores` by WCH / Nanjing Qinheng Microelectronics. The vendor refers to these opcodes by the name "XW".
+`experimental-Xqccmi`
+
+: LLVM implements [version 0.2 of the Qualcomm 16-bit Instruction Lookup Table extension specification](https://github.com/qualcomm/riscv-unified-db/releases#release-Xqccmi-0.2.0) by Qualcomm. All instructions are prefixed with `qc.` as described in the specification.
+
`Xqccmp`
: LLVM implements [version 0.3 of the 16-bit Push/Pop instructions and double-moves extension specification](https://github.com/quic/riscv-unified-db/releases/tag/Xqccmp_extension-0.3.0) by Qualcomm. All instructions are prefixed with `qc.` as described in the specification.
diff --git a/llvm/docs/ReleaseNotes.md b/llvm/docs/ReleaseNotes.md
index e616c0581b87b..32331608e9afe 100644
--- a/llvm/docs/ReleaseNotes.md
+++ b/llvm/docs/ReleaseNotes.md
@@ -210,6 +210,7 @@ Makes programs 10x faster by doing Special New Thing.
push/pop extensions.
* Bump Svukte extension to 1.0.
* Remove experimental from Zicfiss.
+* Adds experimental assembler support for the `Xqccmi` (Qualcomm 16-bit Instruction Lookup Table) vendor extension
### Changes to the WebAssembly Backend
diff --git a/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp b/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp
index 99066346f0411..057117200df4d 100644
--- a/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp
+++ b/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp
@@ -646,6 +646,9 @@ static constexpr DecoderListEntry DecoderList16[]{
{DecoderTableXqccmp16,
{RISCV::FeatureVendorXqccmp},
"Xqccmp (Qualcomm 16-bit Push/Pop & Double Move Instructions)"},
+ {DecoderTableXqccmi16,
+ {RISCV::FeatureVendorXqccmi},
+ "Xqccmi (Qualcomm 16-bit Instruction Lookup Table)"},
{DecoderTableXqccmt16,
{RISCV::FeatureVendorXqccmt},
"Xqccmt (Qualcomm 16-bit Table Jump Instructions)"},
diff --git a/llvm/lib/Target/RISCV/RISCVFeatures.td b/llvm/lib/Target/RISCV/RISCVFeatures.td
index d388e0ea81c19..19599b62ffbd5 100644
--- a/llvm/lib/Target/RISCV/RISCVFeatures.td
+++ b/llvm/lib/Target/RISCV/RISCVFeatures.td
@@ -1682,6 +1682,15 @@ def HasVendorXqccmp
AssemblerPredicate<(all_of FeatureVendorXqccmp),
"'Xqccmp' (Qualcomm 16-bit Push/Pop and Double Moves)">;
+def FeatureVendorXqccmi
+ : RISCVExperimentalExtension<0, 2,
+ "Qualcomm 16-bit Instruction Lookup Table",
+ [FeatureStdExtZca, FeatureStdExtZicsr]>;
+def HasVendorXqccmi
+ : Predicate<"Subtarget->hasVendorXqccmi()">,
+ AssemblerPredicate<(all_of FeatureVendorXqccmi),
+ "'Xqccmi' (Qualcomm 16-bit Instruction Lookup Table)">;
+
def FeatureVendorXqccmt
: RISCVExperimentalExtension<0, 1, "Qualcomm 16-bit Table Jump",
[FeatureStdExtZca, FeatureStdExtZicsr]>;
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.td b/llvm/lib/Target/RISCV/RISCVInstrInfo.td
index 1a0f85271a9b1..ae897710af1c2 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfo.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.td
@@ -2478,6 +2478,7 @@ include "RISCVInstrInfoXSfmm.td"
include "RISCVInstrInfoXCV.td"
include "RISCVInstrInfoXwch.td"
include "RISCVInstrInfoXqci.td"
+include "RISCVInstrInfoXqccmi.td"
include "RISCVInstrInfoXqccmp.td"
include "RISCVInstrInfoXqccmt.td"
include "RISCVInstrInfoXMips.td"
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoXqccmi.td b/llvm/lib/Target/RISCV/RISCVInstrInfoXqccmi.td
new file mode 100644
index 0000000000000..74ae261e2cedd
--- /dev/null
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoXqccmi.td
@@ -0,0 +1,30 @@
+//===-- RISCVInstrInfoXqccmi.td ---------------------------*- tablegen -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file describes Qualcomm's Xqccmi extension.
+//
+// Xqccmi provides qc.cm.ilut, a compressed instruction which executes one or two
+// instructions from an instruction lookup table. The encoding overlaps with
+// c.fld, so Xqccmi and Zcd are mutually exclusive.
+//
+//===----------------------------------------------------------------------===//
+
+let DecoderNamespace = "Xqccmi", Predicates = [HasVendorXqccmi, IsRV32],
+ hasSideEffects = 1, mayLoad = 1, mayStore = 0 in {
+
+def QC_CM_ILUT : RVInst16<(outs), (ins uimm11:$ilut_index),
+ "qc.cm.ilut", "$ilut_index", [],
+ InstFormatOther> {
+ bits<11> ilut_index;
+
+ let Inst{15-13} = 0b001;
+ let Inst{12-2} = ilut_index;
+ let Inst{1-0} = 0b00;
+}
+
+} // DecoderNamespace = "Xqccmi", Predicates = [HasVendorXqccmi, IsRV32]
diff --git a/llvm/lib/Target/RISCV/RISCVSystemOperands.td b/llvm/lib/Target/RISCV/RISCVSystemOperands.td
index 421a3ae37338d..7dd8bdfb950a5 100644
--- a/llvm/lib/Target/RISCV/RISCVSystemOperands.td
+++ b/llvm/lib/Target/RISCV/RISCVSystemOperands.td
@@ -564,6 +564,12 @@ foreach i = 0 - 3 in {
}
} // FeatureVendorXqciint
+// Xqccmi
+let FeaturesRequired = [{ {RISCV::FeatureVendorXqccmi} }] in {
+def : SysReg<"qc.itba", 0x800, RV32Only=true>;
+def : SysReg<"qc.itdec", 0x801, RV32Only=true>;
+}
+
// XAIFET
let FeaturesRequired = [{ {RISCV::FeatureVendorXAIFET} }] in {
def : SysReg<"aif.cache_invalidate", 0x7d0>;
diff --git a/llvm/lib/TargetParser/RISCVISAInfo.cpp b/llvm/lib/TargetParser/RISCVISAInfo.cpp
index 9d4ce85efe187..ea304a7631e6c 100644
--- a/llvm/lib/TargetParser/RISCVISAInfo.cpp
+++ b/llvm/lib/TargetParser/RISCVISAInfo.cpp
@@ -769,14 +769,15 @@ Error RISCVISAInfo::checkDependency() {
bool HasXqccmt = Exts.count("xqccmt") != 0;
static constexpr StringLiteral ZcdOverlaps[] = {
- {"zcmt"}, {"zcmp"}, {"xqccmp"}, {"xqccmt"}, {"xqciac"}, {"xqcicm"},
+ {"zcmt"}, {"zcmp"}, {"xqccmi"}, {"xqccmp"},
+ {"xqccmt"}, {"xqciac"}, {"xqcicm"},
};
static constexpr StringLiteral RV32Only[] = {
- {"zcf"}, {"zclsd"}, {"zilsd"}, {"xwchc"}, {"xqci"},
- {"xqcia"}, {"xqciac"}, {"xqcibi"}, {"xqcibm"}, {"xqcicli"},
- {"xqcicm"}, {"xqcics"}, {"xqcicsr"}, {"xqciint"}, {"xqciio"},
- {"xqcilb"}, {"xqcili"}, {"xqcilia"}, {"xqcilo"}, {"xqcilsm"},
- {"xqcisim"}, {"xqcisls"}, {"xqcisync"},
+ {"zcf"}, {"zclsd"}, {"zilsd"}, {"xwchc"}, {"xqccmi"},
+ {"xqci"}, {"xqcia"}, {"xqciac"}, {"xqcibi"}, {"xqcibm"},
+ {"xqcicli"}, {"xqcicm"}, {"xqcics"}, {"xqcicsr"}, {"xqciint"},
+ {"xqciio"}, {"xqcilb"}, {"xqcili"}, {"xqcilia"}, {"xqcilo"},
+ {"xqcilsm"}, {"xqcisim"}, {"xqcisls"}, {"xqcisync"},
};
if (HasI && HasE)
diff --git a/llvm/test/CodeGen/RISCV/features-info.ll b/llvm/test/CodeGen/RISCV/features-info.ll
index b756a2f862b7d..b39adc7ecf316 100644
--- a/llvm/test/CodeGen/RISCV/features-info.ll
+++ b/llvm/test/CodeGen/RISCV/features-info.ll
@@ -34,6 +34,7 @@
; CHECK-NEXT: experimental-ssijt - 'Ssijt' (Interrupt Jump Table at Supervisor Level).
; CHECK-NEXT: experimental-ssip - 'Ssip' (Support for Interrupt Handler Push/Pop at Supervisor Level).
; CHECK-NEXT: experimental-svukte - 'Svukte' (Address-Independent Latency of User-Mode Faults to Supervisor Addresses).
+; CHECK-NEXT: experimental-xqccmi - 'Xqccmi' (Qualcomm 16-bit Instruction Lookup Table).
; CHECK-NEXT: experimental-xqccmt - 'Xqccmt' (Qualcomm 16-bit Table Jump).
; CHECK-NEXT: experimental-xsfmclic - 'XSfmclic' (SiFive CLIC Machine-mode CSRs).
; CHECK-NEXT: experimental-xsfsclic - 'XSfsclic' (SiFive CLIC Supervisor-mode CSRs).
diff --git a/llvm/test/MC/RISCV/attribute-arch.s b/llvm/test/MC/RISCV/attribute-arch.s
index f802e91b312b4..71fa80037645a 100644
--- a/llvm/test/MC/RISCV/attribute-arch.s
+++ b/llvm/test/MC/RISCV/attribute-arch.s
@@ -276,6 +276,9 @@
.attribute arch, "rv32izcmt1p0"
# CHECK: attribute 5, "rv32i2p1_c2p0_zicsr2p0_zca1p0_zcmt1p0"
+.attribute arch, "rv32i_xqccmi0p2"
+# CHECK: attribute 5, "rv32i2p1_c2p0_zicsr2p0_zca1p0_xqccmi0p2"
+
.attribute arch, "rv32i_xqccmt0p1"
# CHECK: attribute 5, "rv32i2p1_c2p0_zicsr2p0_zca1p0_xqccmt0p1"
diff --git a/llvm/test/MC/RISCV/xqccmi-invalid.s b/llvm/test/MC/RISCV/xqccmi-invalid.s
new file mode 100644
index 0000000000000..2249bbbf2d4b4
--- /dev/null
+++ b/llvm/test/MC/RISCV/xqccmi-invalid.s
@@ -0,0 +1,8 @@
+# Xqccmi - Qualcomm 16-bit Instruction Lookup Table
+# RUN: not llvm-mc -triple=riscv32 -mattr=+experimental-xqccmi -M no-aliases -show-encoding < %s 2>&1 | FileCheck -check-prefix=CHECK-ERROR %s
+
+# CHECK-ERROR: error: immediate must be an integer in the range [0, 2047]
+qc.cm.ilut 2048
+
+# CHECK-ERROR: error: immediate must be an integer in the range [0, 2047]
+qc.cm.ilut -1
diff --git a/llvm/test/MC/RISCV/xqccmi-valid.s b/llvm/test/MC/RISCV/xqccmi-valid.s
new file mode 100644
index 0000000000000..c47e7737d3926
--- /dev/null
+++ b/llvm/test/MC/RISCV/xqccmi-valid.s
@@ -0,0 +1,23 @@
+# Xqccmi - Qualcomm 16-bit Instruction Lookup Table
+# RUN: llvm-mc %s -triple=riscv32 -mattr=+experimental-xqccmi -M no-aliases -show-encoding | FileCheck -check-prefixes=CHECK-ASM,CHECK-ASM-AND-OBJ %s
+# RUN: llvm-mc -filetype=obj -triple=riscv32 -mattr=+experimental-xqccmi < %s | llvm-objdump --mattr=-c,+experimental-xqccmi --no-print-imm-hex -M no-aliases -d -r - | FileCheck --check-prefixes=CHECK-ASM-AND-OBJ %s
+
+# CHECK-ASM-AND-OBJ: qc.cm.ilut 0
+# CHECK-ASM: encoding: [0x00,0x20]
+qc.cm.ilut 0
+
+# CHECK-ASM-AND-OBJ: qc.cm.ilut 1
+# CHECK-ASM: encoding: [0x04,0x20]
+qc.cm.ilut 1
+
+# CHECK-ASM-AND-OBJ: qc.cm.ilut 2047
+# CHECK-ASM: encoding: [0xfc,0x3f]
+qc.cm.ilut 2047
+
+# CHECK-ASM-AND-OBJ: csrrs t2, qc.itba, zero
+# CHECK-ASM: encoding: [0xf3,0x23,0x00,0x80]
+csrrs t2, qc.itba, zero
+
+# CHECK-ASM-AND-OBJ: csrrs t2, qc.itdec, zero
+# CHECK-ASM: encoding: [0xf3,0x23,0x10,0x80]
+csrrs t2, qc.itdec, zero
diff --git a/llvm/unittests/TargetParser/RISCVISAInfoTest.cpp b/llvm/unittests/TargetParser/RISCVISAInfoTest.cpp
index 60a464d1bce2f..ea9af84be5244 100644
--- a/llvm/unittests/TargetParser/RISCVISAInfoTest.cpp
+++ b/llvm/unittests/TargetParser/RISCVISAInfoTest.cpp
@@ -815,6 +815,11 @@ TEST(ParseArchString, RejectsConflictingExtensions) {
EXPECT_THAT(Error, ::testing::HasSubstr(ConflictingExt));
}
+ for (StringRef Input : {"rv32idc_xqccmi0p2", "rv32i_zcd_xqccmi0p2"}) {
+ EXPECT_EQ(toString(RISCVISAInfo::parseArchString(Input, true).takeError()),
+ "'xqccmi' and 'zcd' extensions are incompatible");
+ }
+
for (StringRef Input : {"rv32i_zcmp_xqccmp0p3", "rv64i_zcmp_xqccmp0p3"}) {
EXPECT_EQ(toString(RISCVISAInfo::parseArchString(Input, true).takeError()),
"'zcmp' and 'xqccmp' extensions are incompatible");
@@ -1670,6 +1675,7 @@ Experimental extensions
ssijt 0.20
ssip 0.20
svukte 1.0
+ xqccmi 0.2
xqccmt 0.1
xsfmclic 0.1
xsfsclic 0.1
``````````
</details>
https://github.com/llvm/llvm-project/pull/225119
More information about the llvm-commits
mailing list