https://github.com/svs-quic created https://github.com/llvm/llvm-project/pull/225119
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. >From be3d928597767c8a1abd6937fddf43e5ce1526b8 Mon Sep 17 00:00:00 2001 From: Sudharsan Veeravalli <[email protected]> Date: Tue, 1 Sep 2026 20:37:02 +0530 Subject: [PATCH] [RISCV] Add assembler support for the Qualcomm Xqccmi vendor extension --- .../Driver/print-supported-extensions-riscv.c | 1 + llvm/docs/RISCVUsage.md | 4 +++ llvm/docs/ReleaseNotes.md | 1 + .../RISCV/Disassembler/RISCVDisassembler.cpp | 3 ++ llvm/lib/Target/RISCV/RISCVFeatures.td | 9 ++++++ llvm/lib/Target/RISCV/RISCVInstrInfo.td | 1 + llvm/lib/Target/RISCV/RISCVInstrInfoXqccmi.td | 30 +++++++++++++++++++ llvm/lib/Target/RISCV/RISCVSystemOperands.td | 6 ++++ llvm/lib/TargetParser/RISCVISAInfo.cpp | 13 ++++---- llvm/test/CodeGen/RISCV/features-info.ll | 1 + llvm/test/MC/RISCV/attribute-arch.s | 3 ++ llvm/test/MC/RISCV/xqccmi-invalid.s | 8 +++++ llvm/test/MC/RISCV/xqccmi-valid.s | 23 ++++++++++++++ .../TargetParser/RISCVISAInfoTest.cpp | 6 ++++ 14 files changed, 103 insertions(+), 6 deletions(-) create mode 100644 llvm/lib/Target/RISCV/RISCVInstrInfoXqccmi.td create mode 100644 llvm/test/MC/RISCV/xqccmi-invalid.s create mode 100644 llvm/test/MC/RISCV/xqccmi-valid.s 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 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
