Skip to content

Commit 3c5f929

Browse files
authored
[RISCV] Add QingKe "XW" compressed opcode extension (#97925)
This extension consists of 8 additional 16-bit compressed forms for existing standard load/store opcodes. These opcodes are found in some RISC-V microcontrollers from WCH / Nanjing Qinheng Microelectronics. As discussed in the Discourse forums, this uses incompatible extension and opcode names vs the vendor binary toolchain. The chosen names instead follow the conventions for other vendor extensions listed on the "riscv-non-isa" project.
1 parent c5e5088 commit 3c5f929

File tree

16 files changed

+635
-2
lines changed

16 files changed

+635
-2
lines changed

clang/test/Driver/print-supported-extensions-riscv.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,7 @@
166166
// CHECK-NEXT: xtheadsync 1.0 'xtheadsync' (T-Head multicore synchronization instructions)
167167
// CHECK-NEXT: xtheadvdot 1.0 'xtheadvdot' (T-Head Vector Extensions for Dot)
168168
// CHECK-NEXT: xventanacondops 1.0 'XVentanaCondOps' (Ventana Conditional Ops)
169+
// CHECK-NEXT: xwchc 2.2 'Xwchc' (WCH/QingKe additional compressed opcodes)
169170
// CHECK-EMPTY:
170171
// CHECK-NEXT: Experimental extensions
171172
// CHECK-NEXT: zicfilp 0.4 'Zicfilp' (Landing pad)

llvm/docs/RISCVUsage.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -396,6 +396,9 @@ The current vendor extensions supported are:
396396
``XSfcease``
397397
LLVM implements `the SiFive sf.cease instruction specified in <https://sifive.cdn.prismic.io/sifive/767804da-53b2-4893-97d5-b7c030ae0a94_s76mc_core_complex_manual_21G3.pdf>`_ by SiFive.
398398

399+
``Xwchc``
400+
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".
401+
399402
Experimental C Intrinsics
400403
=========================
401404

llvm/docs/ReleaseNotes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,8 @@ Changes to the RISC-V Backend
197197
fully compatible with objects produced prior to this change. The mapping
198198
(ABI) used is recorded as an ELF attribute.
199199
* Ztso is no longer experimental.
200+
* The WCH / Nanjing Qinheng Microelectronics QingKe "XW" compressed opcodes are
201+
supported under the name "Xwchc".
200202

201203
Changes to the WebAssembly Backend
202204
----------------------------------

llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -809,6 +809,26 @@ struct RISCVOperand final : public MCParsedAsmOperand {
809809
VK == RISCVMCExpr::VK_RISCV_None;
810810
}
811811

812+
bool isUImm5Lsb0() const {
813+
if (!isImm())
814+
return false;
815+
int64_t Imm;
816+
RISCVMCExpr::VariantKind VK = RISCVMCExpr::VK_RISCV_None;
817+
bool IsConstantImm = evaluateConstantImm(getImm(), Imm, VK);
818+
return IsConstantImm && isShiftedUInt<4, 1>(Imm) &&
819+
VK == RISCVMCExpr::VK_RISCV_None;
820+
}
821+
822+
bool isUImm6Lsb0() const {
823+
if (!isImm())
824+
return false;
825+
int64_t Imm;
826+
RISCVMCExpr::VariantKind VK = RISCVMCExpr::VK_RISCV_None;
827+
bool IsConstantImm = evaluateConstantImm(getImm(), Imm, VK);
828+
return IsConstantImm && isShiftedUInt<5, 1>(Imm) &&
829+
VK == RISCVMCExpr::VK_RISCV_None;
830+
}
831+
812832
bool isUImm7Lsb00() const {
813833
if (!isImm())
814834
return false;
@@ -1502,6 +1522,14 @@ bool RISCVAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
15021522
return generateImmOutOfRangeError(
15031523
Operands, ErrorInfo, 1, (1 << 5) - 1,
15041524
"immediate must be in [0xfffe0, 0xfffff] or");
1525+
case Match_InvalidUImm5Lsb0:
1526+
return generateImmOutOfRangeError(
1527+
Operands, ErrorInfo, 0, (1 << 5) - 2,
1528+
"immediate must be a multiple of 2 bytes in the range");
1529+
case Match_InvalidUImm6Lsb0:
1530+
return generateImmOutOfRangeError(
1531+
Operands, ErrorInfo, 0, (1 << 6) - 2,
1532+
"immediate must be a multiple of 2 bytes in the range");
15051533
case Match_InvalidUImm7Lsb00:
15061534
return generateImmOutOfRangeError(
15071535
Operands, ErrorInfo, 0, (1 << 7) - 4,

llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -646,6 +646,9 @@ DecodeStatus RISCVDisassembler::getInstruction16(MCInst &MI, uint64_t &Size,
646646
TRY_TO_DECODE_FEATURE(
647647
RISCV::FeatureStdExtZcmp, DecoderTableRVZcmp16,
648648
"Zcmp table (16-bit Push/Pop & Double Move Instructions)");
649+
TRY_TO_DECODE_AND_ADD_SP(STI.hasFeature(RISCV::FeatureVendorXwchc),
650+
DecoderTableXwchc16,
651+
"WCH QingKe XW custom opcode table");
649652
TRY_TO_DECODE_AND_ADD_SP(true, DecoderTable16,
650653
"RISCV_C table (16-bit Instruction)");
651654

llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,9 @@ enum OperandType : unsigned {
269269
OPERAND_UIMM3,
270270
OPERAND_UIMM4,
271271
OPERAND_UIMM5,
272+
OPERAND_UIMM5_LSB0,
272273
OPERAND_UIMM6,
274+
OPERAND_UIMM6_LSB0,
273275
OPERAND_UIMM7,
274276
OPERAND_UIMM7_LSB00,
275277
OPERAND_UIMM8_LSB00,

llvm/lib/Target/RISCV/RISCVFeatures.td

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1210,6 +1210,16 @@ def HasVendorXCVbi
12101210
AssemblerPredicate<(all_of FeatureVendorXCVbi),
12111211
"'XCVbi' (CORE-V Immediate Branching)">;
12121212

1213+
// WCH / Nanjing Qinheng Microelectronics Extension(s)
1214+
1215+
def FeatureVendorXwchc
1216+
: RISCVExtension<"xwchc", 2, 2,
1217+
"'Xwchc' (WCH/QingKe additional compressed opcodes)">;
1218+
def HasVendorXwchc
1219+
: Predicate<"Subtarget->hasVendorXwchc()">,
1220+
AssemblerPredicate<(all_of FeatureVendorXwchc),
1221+
"'Xwchc' (WCH/QingKe additional compressed opcodes)">;
1222+
12131223
//===----------------------------------------------------------------------===//
12141224
// LLVM specific features and extensions
12151225
//===----------------------------------------------------------------------===//

llvm/lib/Target/RISCV/RISCVInstrInfo.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2386,6 +2386,12 @@ bool RISCVInstrInfo::verifyInstruction(const MachineInstr &MI,
23862386
case RISCVOp::OPERAND_UIMM2_LSB0:
23872387
Ok = isShiftedUInt<1, 1>(Imm);
23882388
break;
2389+
case RISCVOp::OPERAND_UIMM5_LSB0:
2390+
Ok = isShiftedUInt<4, 1>(Imm);
2391+
break;
2392+
case RISCVOp::OPERAND_UIMM6_LSB0:
2393+
Ok = isShiftedUInt<5, 1>(Imm);
2394+
break;
23892395
case RISCVOp::OPERAND_UIMM7_LSB00:
23902396
Ok = isShiftedUInt<5, 2>(Imm);
23912397
break;

llvm/lib/Target/RISCV/RISCVInstrInfo.td

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2080,6 +2080,7 @@ include "RISCVInstrInfoXTHead.td"
20802080
include "RISCVInstrInfoXSf.td"
20812081
include "RISCVInstrInfoSFB.td"
20822082
include "RISCVInstrInfoXCV.td"
2083+
include "RISCVInstrInfoXwch.td"
20832084

20842085
//===----------------------------------------------------------------------===//
20852086
// Global ISel
Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
//===-- RISCVInstrInfoXwch.td ------------------------------*- tablegen -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// This file describes the vendor extension(s) defined by WCH.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
class QKStackInst<bits<2> funct2, dag outs, dag ins,
14+
string opcodestr, string argstr>
15+
: RVInst16<outs, ins, opcodestr, argstr, [], InstFormatOther> {
16+
bits<3> rd_rs2;
17+
18+
let Inst{15-11} = 0b10000;
19+
let Inst{6-5} = funct2;
20+
let Inst{4-2} = rd_rs2;
21+
let Inst{1-0} = 0b00;
22+
}
23+
24+
//===----------------------------------------------------------------------===//
25+
// Operand definitions.
26+
//===----------------------------------------------------------------------===//
27+
28+
def uimm4_with_predicate : RISCVUImmLeafOp<4> {
29+
let MCOperandPredicate = [{
30+
int64_t Imm;
31+
if (!MCOp.evaluateAsConstantImm(Imm))
32+
return false;
33+
return isUInt<4>(Imm);
34+
}];
35+
}
36+
37+
def uimm5_with_predicate : RISCVUImmLeafOp<5> {
38+
let MCOperandPredicate = [{
39+
int64_t Imm;
40+
if (!MCOp.evaluateAsConstantImm(Imm))
41+
return false;
42+
return isUInt<5>(Imm);
43+
}];
44+
}
45+
46+
// A 5-bit unsigned immediate where the least significant bit is zero.
47+
def uimm5_lsb0 : RISCVOp,
48+
ImmLeaf<XLenVT, [{return isShiftedUInt<4, 1>(Imm);}]> {
49+
let ParserMatchClass = UImmAsmOperand<5, "Lsb0">;
50+
let EncoderMethod = "getImmOpValue";
51+
let DecoderMethod = "decodeUImmOperand<5>";
52+
let OperandType = "OPERAND_UIMM5_LSB0";
53+
let MCOperandPredicate = [{
54+
int64_t Imm;
55+
if (!MCOp.evaluateAsConstantImm(Imm))
56+
return false;
57+
return isShiftedUInt<4, 1>(Imm);
58+
}];
59+
}
60+
61+
// A 6-bit unsigned immediate where the least significant bit is zero.
62+
def uimm6_lsb0 : RISCVOp,
63+
ImmLeaf<XLenVT, [{return isShiftedUInt<5, 1>(Imm);}]> {
64+
let ParserMatchClass = UImmAsmOperand<6, "Lsb0">;
65+
let EncoderMethod = "getImmOpValue";
66+
let DecoderMethod = "decodeUImmOperand<6>";
67+
let OperandType = "OPERAND_UIMM6_LSB0";
68+
let MCOperandPredicate = [{
69+
int64_t Imm;
70+
if (!MCOp.evaluateAsConstantImm(Imm))
71+
return false;
72+
return isShiftedUInt<5, 1>(Imm);
73+
}];
74+
}
75+
76+
//===----------------------------------------------------------------------===//
77+
// Instructions
78+
//===----------------------------------------------------------------------===//
79+
let Predicates = [HasVendorXwchc], DecoderNamespace = "Xwchc" in {
80+
81+
let hasSideEffects = 0, mayLoad = 1, mayStore = 0 in
82+
def QK_C_LBU : RVInst16CL<0b001, 0b00, (outs GPRC:$rd),
83+
(ins GPRCMem:$rs1, uimm5_with_predicate:$imm),
84+
"qk.c.lbu", "$rd, ${imm}(${rs1})">,
85+
Sched<[WriteLDB, ReadMemBase]> {
86+
bits<5> imm;
87+
let Inst{12} = imm{0};
88+
let Inst{11-10} = imm{4-3};
89+
let Inst{6-5} = imm{2-1};
90+
}
91+
let hasSideEffects = 0, mayLoad = 0, mayStore = 1 in
92+
def QK_C_SB : RVInst16CS<0b101, 0b00, (outs),
93+
(ins GPRC:$rs2, GPRCMem:$rs1,
94+
uimm5_with_predicate:$imm),
95+
"qk.c.sb", "$rs2, ${imm}(${rs1})">,
96+
Sched<[WriteSTB, ReadStoreData, ReadMemBase]> {
97+
bits<5> imm;
98+
let Inst{12} = imm{0};
99+
let Inst{11-10} = imm{4-3};
100+
let Inst{6-5} = imm{2-1};
101+
}
102+
103+
let hasSideEffects = 0, mayLoad = 1, mayStore = 0 in
104+
def QK_C_LHU : RVInst16CL<0b001, 0b10, (outs GPRC:$rd),
105+
(ins GPRCMem:$rs1, uimm6_lsb0:$imm),
106+
"qk.c.lhu", "$rd, ${imm}(${rs1})">,
107+
Sched<[WriteLDH, ReadMemBase]> {
108+
bits<6> imm;
109+
let Inst{12-10} = imm{5-3};
110+
let Inst{6-5} = imm{2-1};
111+
}
112+
let hasSideEffects = 0, mayLoad = 0, mayStore = 1 in
113+
def QK_C_SH : RVInst16CS<0b101, 0b10, (outs),
114+
(ins GPRC:$rs2, GPRCMem:$rs1, uimm6_lsb0:$imm),
115+
"qk.c.sh", "$rs2, ${imm}(${rs1})">,
116+
Sched<[WriteSTH, ReadStoreData, ReadMemBase]> {
117+
bits<6> imm;
118+
let Inst{12-10} = imm{5-3};
119+
let Inst{6-5} = imm{2-1};
120+
}
121+
122+
let hasSideEffects = 0, mayLoad = 1, mayStore = 0 in
123+
def QK_C_LBUSP : QKStackInst<0b00, (outs GPRC:$rd_rs2),
124+
(ins SPMem:$rs1, uimm4_with_predicate:$imm),
125+
"qk.c.lbusp", "$rd_rs2, ${imm}(${rs1})">,
126+
Sched<[WriteLDB, ReadMemBase]> {
127+
bits<4> imm;
128+
let Inst{10-7} = imm;
129+
}
130+
let hasSideEffects = 0, mayLoad = 0, mayStore = 1 in
131+
def QK_C_SBSP : QKStackInst<0b10, (outs),
132+
(ins GPRC:$rd_rs2, SPMem:$rs1,
133+
uimm4_with_predicate:$imm),
134+
"qk.c.sbsp", "$rd_rs2, ${imm}(${rs1})">,
135+
Sched<[WriteSTB, ReadStoreData, ReadMemBase]> {
136+
bits<4> imm;
137+
let Inst{10-7} = imm;
138+
}
139+
140+
let hasSideEffects = 0, mayLoad = 1, mayStore = 0 in
141+
def QK_C_LHUSP : QKStackInst<0b01, (outs GPRC:$rd_rs2),
142+
(ins SPMem:$rs1, uimm5_lsb0:$imm),
143+
"qk.c.lhusp", "$rd_rs2, ${imm}(${rs1})">,
144+
Sched<[WriteLDH, ReadMemBase]> {
145+
bits<5> imm;
146+
let Inst{10-8} = imm{3-1};
147+
let Inst{7} = imm{4};
148+
}
149+
let hasSideEffects = 0, mayLoad = 0, mayStore = 1 in
150+
def QK_C_SHSP : QKStackInst<0b11, (outs),
151+
(ins GPRC:$rd_rs2, SPMem:$rs1, uimm5_lsb0:$imm),
152+
"qk.c.shsp", "$rd_rs2, ${imm}(${rs1})">,
153+
Sched<[WriteSTH, ReadStoreData, ReadMemBase]> {
154+
bits<5> imm;
155+
let Inst{10-8} = imm{3-1};
156+
let Inst{7} = imm{4};
157+
}
158+
159+
} // Predicates = [HasVendorXwchc], DecoderNamespace = "Xwchc"
160+
161+
//===----------------------------------------------------------------------===//
162+
// Assembler Pseudo Instructions
163+
//===----------------------------------------------------------------------===//
164+
165+
let EmitPriority = 0 in {
166+
let Predicates = [HasVendorXwchc] in {
167+
def : InstAlias<"qk.c.lbu $rd, (${rs1})", (QK_C_LBU GPRC:$rd, GPRCMem:$rs1, 0)>;
168+
def : InstAlias<"qk.c.sb $rs2, (${rs1})", (QK_C_SB GPRC:$rs2, GPRCMem:$rs1, 0)>;
169+
def : InstAlias<"qk.c.lhu $rd, (${rs1})", (QK_C_LHU GPRC:$rd, GPRCMem:$rs1, 0)>;
170+
def : InstAlias<"qk.c.sh $rs2, (${rs1})", (QK_C_SH GPRC:$rs2, GPRCMem:$rs1, 0)>;
171+
def : InstAlias<"qk.c.lbusp $rd, (${rs1})", (QK_C_LBUSP GPRC:$rd, SPMem:$rs1, 0)>;
172+
def : InstAlias<"qk.c.sbsp $rs2, (${rs1})", (QK_C_SBSP GPRC:$rs2, SPMem:$rs1, 0)>;
173+
def : InstAlias<"qk.c.lhusp $rd, (${rs1})", (QK_C_LHUSP GPRC:$rd, SPMem:$rs1, 0)>;
174+
def : InstAlias<"qk.c.shsp $rs2, (${rs1})", (QK_C_SHSP GPRC:$rs2, SPMem:$rs1, 0)>;
175+
}
176+
}
177+
178+
//===----------------------------------------------------------------------===/
179+
// Compress Instruction tablegen backend.
180+
//===----------------------------------------------------------------------===//
181+
182+
let Predicates = [HasVendorXwchc] in {
183+
def : CompressPat<(LBU GPRC:$rd, GPRCMem:$rs1, uimm5_with_predicate:$imm),
184+
(QK_C_LBU GPRC:$rd, GPRCMem:$rs1, uimm5_with_predicate:$imm)>;
185+
def : CompressPat<(SB GPRC:$rs2, GPRCMem:$rs1, uimm5_with_predicate:$imm),
186+
(QK_C_SB GPRC:$rs2, GPRCMem:$rs1, uimm5_with_predicate:$imm)>;
187+
def : CompressPat<(LHU GPRC:$rd, GPRCMem:$rs1, uimm6_lsb0:$imm),
188+
(QK_C_LHU GPRC:$rd, GPRCMem:$rs1, uimm6_lsb0:$imm)>;
189+
def : CompressPat<(SH GPRC:$rs2, GPRCMem:$rs1, uimm6_lsb0:$imm),
190+
(QK_C_SH GPRC:$rs2, GPRCMem:$rs1, uimm6_lsb0:$imm)>;
191+
def : CompressPat<(LBU GPRC:$rd, SPMem:$rs1, uimm4_with_predicate:$imm),
192+
(QK_C_LBUSP GPRC:$rd, SPMem:$rs1, uimm4_with_predicate:$imm)>;
193+
def : CompressPat<(SB GPRC:$rs2, SPMem:$rs1, uimm4_with_predicate:$imm),
194+
(QK_C_SBSP GPRC:$rs2, SPMem:$rs1, uimm4_with_predicate:$imm)>;
195+
def : CompressPat<(LHU GPRC:$rd, SPMem:$rs1, uimm5_lsb0:$imm),
196+
(QK_C_LHUSP GPRC:$rd, SPMem:$rs1, uimm5_lsb0:$imm)>;
197+
def : CompressPat<(SH GPRC:$rs2, SPMem:$rs1, uimm5_lsb0:$imm),
198+
(QK_C_SHSP GPRC:$rs2, SPMem:$rs1, uimm5_lsb0:$imm)>;
199+
}

0 commit comments

Comments
 (0)