Skip to content

Commit c5884c5

Browse files
committed
[RISC-V][MC] Add support for RVY loads/stores
This adds supports for all new RVY loads/stores (capability-wide versions: ly/sy instructions). Additionally, for RVY (CHERI), loads and stores are mode-dependent, using either a YLEN register or a XLEN register as the base. In the former case loads/stores are authorized by that register, and in the latter (compatibility mode), the loads/stores keep using an address but are authorized by the DDC CSR. The assembler mnemonics are the same in both cases. Prior to the standardization process CHERI assembly used c-prefixed register names for capabilities, so we had the following syntax: lw x4, 0(c3) # capability mode: use new `CLW` instruction lw x4, 0(x3) # integer mode: use existing `LW` instruction During the standardization this was changed to keep the same register name in both modes, so now we have `lw x4, 0(x3)` in both modes. This allows using the RegClassByHwMode feature to reuse the same MC instruction but with a different operand type depending on the HwMode. The downstream fork had duplicated definitions which meant a lot of switch statements now needed to handle both MCInsts. This approach using HwMode should be much more maintainable and only introduces a minor diff compared to what we had downstream. This will also make it much easier adding support for RVY versions of other extensions such as vector, since we just need to change out the `GPRMem` operand with `PtrMem`.
1 parent a0222b5 commit c5884c5

File tree

8 files changed

+143
-43
lines changed

8 files changed

+143
-43
lines changed

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

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1367,7 +1367,14 @@ unsigned RISCVAsmParser::validateTargetOperandClass(MCParsedAsmOperand &AsmOp,
13671367
bool IsRegFPR64C =
13681368
RISCVMCRegisterClasses[RISCV::FPR64CRegClassID].contains(Reg);
13691369
bool IsRegVR = RISCVMCRegisterClasses[RISCV::VRRegClassID].contains(Reg);
1370-
if (Op.isGPR() && Kind == MCK_YGPR) {
1370+
1371+
// In RVY mode, the MemPtrRC register class should select capability registers
1372+
// for the base pointer operands, otherwise we use GPRs.
1373+
// TODO: Is there any way we could do this in tablegen automatically?
1374+
if (Kind == MCK_RegByHwMode_MemPtrRC)
1375+
Kind = STI->hasFeature(RISCV::FeatureCapMode) ? MCK_YGPR : MCK_GPR;
1376+
1377+
if (Op.isGPR() && (Kind == MCK_YGPR)) {
13711378
// GPR and capability GPR use the same register names, convert if required.
13721379
Op.Reg.Reg = convertGPRToYGPR(Reg);
13731380
return Match_Success;

llvm/lib/Target/RISCV/RISCVFeatures.td

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1774,8 +1774,10 @@ def IsRV32 : Predicate<"!Subtarget->is64Bit()">,
17741774
AssemblerPredicate<(all_of (not Feature64Bit)),
17751775
"RV32I Base Instruction Set">;
17761776

1777-
defvar RV32 = DefaultMode;
1778-
def RV64 : HwMode<[IsRV64]>;
1777+
def RV32I : HwMode<[IsRV32, NotCapMode]>;
1778+
def RV64I : HwMode<[IsRV64, NotCapMode]>;
1779+
def RV32Y : HwMode<[IsRV32, IsCapMode]>;
1780+
def RV64Y : HwMode<[IsRV64, IsCapMode]>;
17791781

17801782
def FeatureRelax
17811783
: SubtargetFeature<"relax", "EnableLinkerRelax", "true",

llvm/lib/Target/RISCV/RISCVInstrInfo.td

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,7 @@ def ZeroOffsetMemOpOperand : AsmOperandClass {
217217
let ParserMethod = "parseZeroOffsetMemOp";
218218
}
219219

220-
class MemOperand<RegisterClass regClass> : RegisterOperand<regClass>{
220+
class MemOperand<RegisterClassLike regClass> : RegisterOperand<regClass> {
221221
let OperandType = "OPERAND_MEMORY";
222222
}
223223

@@ -227,6 +227,14 @@ def GPRMemZeroOffset : MemOperand<GPR> {
227227
}
228228

229229
def GPRMem : MemOperand<GPR>;
230+
def YGPRMem : MemOperand<YGPR>;
231+
232+
def MemPtrRC : RegClassByHwMode<
233+
[RV32I, RV64I, RV32Y, RV64Y],
234+
[GPR, GPR, YGPR, YGPR]>;
235+
236+
def PtrMem : MemOperand<MemPtrRC>;
237+
230238

231239
def SPMem : MemOperand<SP>;
232240

@@ -643,8 +651,9 @@ class BranchCC_rri<bits<3> funct3, string opcodestr>
643651
}
644652

645653
let hasSideEffects = 0, mayLoad = 1, mayStore = 0 in {
646-
class Load_ri<bits<3> funct3, string opcodestr, DAGOperand rty = GPR>
647-
: RVInstI<funct3, OPC_LOAD, (outs rty:$rd), (ins GPRMem:$rs1, simm12_lo:$imm12),
654+
class Load_ri<bits<3> funct3, string opcodestr, DAGOperand rty = GPR,
655+
RISCVOpcode opcode = OPC_LOAD>
656+
: RVInstI<funct3, opcode, (outs rty:$rd), (ins PtrMem:$rs1, simm12_lo:$imm12),
648657
opcodestr, "$rd, ${imm12}(${rs1})">;
649658

650659
class HLoad_r<bits<7> funct7, bits<5> funct5, string opcodestr>
@@ -660,7 +669,7 @@ class HLoad_r<bits<7> funct7, bits<5> funct5, string opcodestr>
660669
let hasSideEffects = 0, mayLoad = 0, mayStore = 1 in {
661670
class Store_rri<bits<3> funct3, string opcodestr, DAGOperand rty = GPR>
662671
: RVInstS<funct3, OPC_STORE, (outs),
663-
(ins rty:$rs2, GPRMem:$rs1, simm12_lo:$imm12),
672+
(ins rty:$rs2, PtrMem:$rs1, simm12_lo:$imm12),
664673
opcodestr, "$rs2, ${imm12}(${rs1})">;
665674

666675
class HStore_rr<bits<7> funct7, string opcodestr>
@@ -1164,22 +1173,22 @@ let Predicates = [HasStdExtZihintntl] in {
11641173

11651174
let EmitPriority = 0 in {
11661175
def : InstAlias<"lb $rd, (${rs1})",
1167-
(LB GPR:$rd, GPR:$rs1, 0)>;
1176+
(LB GPR:$rd, PtrMem:$rs1, 0)>;
11681177
def : InstAlias<"lh $rd, (${rs1})",
1169-
(LH GPR:$rd, GPR:$rs1, 0)>;
1178+
(LH GPR:$rd, PtrMem:$rs1, 0)>;
11701179
def : InstAlias<"lw $rd, (${rs1})",
1171-
(LW GPR:$rd, GPR:$rs1, 0)>;
1180+
(LW GPR:$rd, PtrMem:$rs1, 0)>;
11721181
def : InstAlias<"lbu $rd, (${rs1})",
1173-
(LBU GPR:$rd, GPR:$rs1, 0)>;
1182+
(LBU GPR:$rd, PtrMem:$rs1, 0)>;
11741183
def : InstAlias<"lhu $rd, (${rs1})",
1175-
(LHU GPR:$rd, GPR:$rs1, 0)>;
1184+
(LHU GPR:$rd, PtrMem:$rs1, 0)>;
11761185

11771186
def : InstAlias<"sb $rs2, (${rs1})",
1178-
(SB GPR:$rs2, GPR:$rs1, 0)>;
1187+
(SB GPR:$rs2, PtrMem:$rs1, 0)>;
11791188
def : InstAlias<"sh $rs2, (${rs1})",
1180-
(SH GPR:$rs2, GPR:$rs1, 0)>;
1189+
(SH GPR:$rs2, PtrMem:$rs1, 0)>;
11811190
def : InstAlias<"sw $rs2, (${rs1})",
1182-
(SW GPR:$rs2, GPR:$rs1, 0)>;
1191+
(SW GPR:$rs2, PtrMem:$rs1, 0)>;
11831192

11841193
def : InstAlias<"add $rd, $rs1, $imm12",
11851194
(ADDI GPR:$rd, GPR:$rs1, simm12_lo:$imm12)>;
@@ -1197,11 +1206,11 @@ def : InstAlias<"sra $rd, $rs1, $shamt",
11971206
(SRAI GPR:$rd, GPR:$rs1, uimmlog2xlen:$shamt)>;
11981207
let Predicates = [IsRV64] in {
11991208
def : InstAlias<"lwu $rd, (${rs1})",
1200-
(LWU GPR:$rd, GPR:$rs1, 0)>;
1209+
(LWU GPR:$rd, PtrMem:$rs1, 0)>;
12011210
def : InstAlias<"ld $rd, (${rs1})",
1202-
(LD GPR:$rd, GPR:$rs1, 0)>;
1211+
(LD GPR:$rd, PtrMem:$rs1, 0)>;
12031212
def : InstAlias<"sd $rs2, (${rs1})",
1204-
(SD GPR:$rs2, GPR:$rs1, 0)>;
1213+
(SD GPR:$rs2, PtrMem:$rs1, 0)>;
12051214

12061215
def : InstAlias<"addw $rd, $rs1, $imm12",
12071216
(ADDIW GPR:$rd, GPR:$rs1, simm12_lo:$imm12)>;

llvm/lib/Target/RISCV/RISCVInstrInfoY.td

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,4 +106,11 @@ let Predicates = [HasStdExtY] in {
106106
def SYEQ : RVY_rr<0x6, 0x4, "syeq", GPR, YGPR, YGPR>;
107107
def YLT : RVY_rr<0x6, 0x6, "ylt", GPR, YGPR, YGPR>;
108108
def YAMASK : RVY_r<0x7, "yamask", GPR, GPR>;
109+
110+
// Instructions to Load and Store Capability Data
111+
def LY : Load_ri<0b100, "ly", opcode=OPC_MISC_MEM>,
112+
Sched<[/* TODO: WriteLDY, */ ReadMemBase]>;
113+
def SY : Store_rri<0b100, "sy">,
114+
Sched<[/* TODO: WriteSTY, */ ReadStoreData, ReadMemBase]>;
115+
109116
} // Predicates = [HasStdExtY]

llvm/lib/Target/RISCV/RISCVInstrInfoZilsd.td

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,6 @@ let Predicates = [HasStdExtZilsd, IsRV32] in {
4747
def PseudoLD_RV32 : PseudoLoad<"ld", GPRPairRV32>;
4848
def PseudoSD_RV32 : PseudoStore<"sd", GPRPairRV32>;
4949

50-
def : InstAlias<"ld $rd, (${rs1})", (LD_RV32 GPRPairRV32:$rd, GPR:$rs1, 0), 0>;
51-
def : InstAlias<"sd $rs2, (${rs1})", (SD_RV32 GPRPairRV32:$rs2, GPR:$rs1, 0), 0>;
50+
def : InstAlias<"ld $rd, (${rs1})", (LD_RV32 GPRPairRV32:$rd, PtrMem:$rs1, 0), 0>;
51+
def : InstAlias<"sd $rs2, (${rs1})", (SD_RV32 GPRPairRV32:$rs2, PtrMem:$rs1, 0), 0>;
5252
}

llvm/lib/Target/RISCV/RISCVRegisterInfo.td

Lines changed: 31 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,9 @@ class RISCVReg128<RISCVReg64 subreg>
5555
// A subreg index for the address part of capability registers (this is just the
5656
// default XLEN-wide X<N> register).
5757
def sub_cap_addr : SubRegIndex<32> {
58-
let SubRegRanges =
59-
SubRegRangeByHwMode<[RV32, RV64], [SubRegRange<32>, SubRegRange<64>]>;
58+
let SubRegRanges = SubRegRangeByHwMode<
59+
[RV32I, RV64I, RV32Y, RV64Y],
60+
[SubRegRange<32>, SubRegRange<64>, SubRegRange<32>, SubRegRange<64>]>;
6061
}
6162
class RISCVCapReg<RISCVRegWithSubRegs subreg, string n, list<string> alt = []>
6263
: RISCVRegWithSubRegs<subreg.HWEncoding{4 -0}, n, [subreg], alt> {
@@ -83,12 +84,14 @@ def sub_vrm1_7 : ComposedSubRegIndex<sub_vrm2_3, sub_vrm1_1>;
8384

8485
// GPR sizes change with HwMode.
8586
def sub_gpr_even : SubRegIndex<32> {
86-
let SubRegRanges = SubRegRangeByHwMode<[RV32, RV64],
87-
[SubRegRange<32>, SubRegRange<64>]>;
87+
let SubRegRanges = SubRegRangeByHwMode<
88+
[RV32I, RV64I, RV32Y, RV64Y],
89+
[SubRegRange<32>, SubRegRange<32>, SubRegRange<64>, SubRegRange<64>]>;
8890
}
8991
def sub_gpr_odd : SubRegIndex<32, 32> {
90-
let SubRegRanges = SubRegRangeByHwMode<[RV32, RV64],
91-
[SubRegRange<32, 32>, SubRegRange<64, 64>]>;
92+
let SubRegRanges = SubRegRangeByHwMode<
93+
[RV32I, RV64I, RV32Y, RV64Y],
94+
[SubRegRange<32, 32>, SubRegRange<32, 32>, SubRegRange<64, 64>, SubRegRange<64, 64>]>;
9295
}
9396
} // Namespace = "RISCV"
9497

@@ -264,27 +267,32 @@ let RegAltNameIndices = [ABIRegAltName] in {
264267
}
265268
}
266269

267-
def XLenVT : ValueTypeByHwMode<[RV32, RV64],
268-
[i32, i64]>;
270+
def XLenVT : ValueTypeByHwMode<[RV32I, RV64I, RV32Y, RV64Y],
271+
[i32, i64, i32, i64]>;
269272
defvar XLenPairVT = untyped;
270273

271274
// Allow f64 in GPR for ZDINX on RV64.
272-
def XLenFVT : ValueTypeByHwMode<[RV64],
273-
[f64]>;
274-
def XLenPairFVT : ValueTypeByHwMode<[RV32],
275-
[f64]>;
275+
def XLenFVT : ValueTypeByHwMode<[RV64I, RV64Y],
276+
[f64, f64]>;
277+
def XLenPairFVT : ValueTypeByHwMode<[RV32I, RV32Y],
278+
[f64, f64]>;
276279

277280
// P extension
278-
def XLenVecI8VT : ValueTypeByHwMode<[RV32, RV64],
279-
[v4i8, v8i8]>;
280-
def XLenVecI16VT : ValueTypeByHwMode<[RV32, RV64],
281-
[v2i16, v4i16]>;
281+
def XLenVecI8VT : ValueTypeByHwMode<[RV32I, RV64I, RV32Y, RV64Y],
282+
[v4i8, v8i8, v4i8, v8i8]>;
283+
def XLenVecI16VT : ValueTypeByHwMode<[RV32I, RV64I, RV32Y, RV64Y],
284+
[v2i16, v4i16, v2i16, v4i16]>;
282285
def XLenRI : RegInfoByHwMode<
283-
[RV32, RV64],
284-
[RegInfo<32,32,32>, RegInfo<64,64,64>]>;
285-
def YLenVT : ValueTypeByHwMode<[RV32, RV64], [c64, c128]>;
286-
def YLenRI : RegInfoByHwMode<[RV32, RV64], [RegInfo<64, 64, 64>,
287-
RegInfo<128, 128, 128>]>;
286+
[RV32I, RV64I, RV32Y, RV64Y],
287+
[RegInfo<32,32,32>, RegInfo<64,64,64>, RegInfo<32,32,32>, RegInfo<64,64,64>]>;
288+
def YLenVT : ValueTypeByHwMode<[RV32I, RV64I, RV32Y, RV64Y],
289+
[c64, c128, c64, c128]>;
290+
def YLenRI : RegInfoByHwMode<
291+
[RV32I, RV64I, RV32Y, RV64Y],
292+
[RegInfo<64, 64, 64>, RegInfo<128, 128, 128>, RegInfo<64, 64, 64>, RegInfo<128, 128, 128>]>;
293+
294+
def PtrLenVT : ValueTypeByHwMode<[RV32I, RV64I, RV32Y, RV64Y],
295+
[i32, i64, c64, c128]>;
288296

289297
class RISCVRegisterClass<list<ValueType> regTypes, int align, dag regList>
290298
: RegisterClass<"RISCV", regTypes, align, regList> {
@@ -394,8 +402,8 @@ def GPRNoX31 : GPRRegisterClass<(sub GPR, X31)> {
394402
//===----------------------------------------------------------------------===//
395403

396404
def XLenPairRI : RegInfoByHwMode<
397-
[RV32, RV64],
398-
[RegInfo<64, 64, 32>, RegInfo<128, 128, 64>]>;
405+
[RV32I, RV64I, RV32Y, RV64Y],
406+
[RegInfo<64, 64, 32>, RegInfo<128, 128, 64>, RegInfo<64, 64, 32>, RegInfo<128, 128, 64>]>;
399407

400408
// Dummy zero register for use in the register pair containing X0 (as X1 is
401409
// not read to or written when the X0 register pair is used).

llvm/lib/Target/RISCV/RISCVSchedule.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,13 @@ def WriteLDB : SchedWrite; // Load byte
2727
def WriteLDH : SchedWrite; // Load half-word
2828
def WriteLDW : SchedWrite; // Load word
2929
def WriteLDD : SchedWrite; // Load double-word
30+
// TODO: def WriteLDY : SchedWrite; // Load capability
3031
def WriteCSR : SchedWrite; // CSR instructions
3132
def WriteSTB : SchedWrite; // Store byte
3233
def WriteSTH : SchedWrite; // Store half-word
3334
def WriteSTW : SchedWrite; // Store word
3435
def WriteSTD : SchedWrite; // Store double-word
36+
// TODO: def WriteSTY : SchedWrite; // Store capability
3537
def WriteAtomicB : SchedWrite; //Atomic memory operation byte size
3638
def WriteAtomicH : SchedWrite; //Atomic memory operation halfword size
3739
def WriteAtomicW : SchedWrite; //Atomic memory operation word size
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
# RUN: llvm-mc %s --triple=riscv32 -mattr=+experimental-y --riscv-no-aliases --show-encoding \
2+
# RUN: | FileCheck --check-prefixes=CHECK-ASM,CHECK-ASM-AND-OBJ %s
3+
# RUN: llvm-mc %s --triple=riscv32 -mattr=+experimental-y,+cap-mode --riscv-no-aliases --show-encoding \
4+
# RUN: | FileCheck --check-prefixes=CHECK-ASM,CHECK-ASM-AND-OBJ %s
5+
# RUN: llvm-mc --filetype=obj --triple=riscv32 --mattr=+experimental-y < %s \
6+
# RUN: | llvm-objdump --mattr=+experimental-y -M no-aliases -d --no-print-imm-hex - \
7+
# RUN: | FileCheck --check-prefixes=CHECK-ASM-AND-OBJ %s
8+
#
9+
# RUN: llvm-mc %s --triple=riscv64 --mattr=+experimental-y --riscv-no-aliases \
10+
# RUN: --show-encoding --defsym=RV64=1 \
11+
# RUN: | FileCheck --check-prefixes=CHECK-ASM,CHECK-ASM-64,CHECK-ASM-AND-OBJ,CHECK-ASM-AND-OBJ-64 %s
12+
# RUN: llvm-mc %s --triple=riscv64 --mattr=+experimental-y,+cap-mode --riscv-no-aliases \
13+
# RUN: --show-encoding --defsym=RV64=1 \
14+
# RUN: | FileCheck --check-prefixes=CHECK-ASM,CHECK-ASM-64,CHECK-ASM-AND-OBJ,CHECK-ASM-AND-OBJ-64 %s
15+
# RUN: llvm-mc --filetype=obj --triple=riscv64 --mattr=+experimental-y \
16+
# RUN: --riscv-no-aliases --show-encoding --defsym=RV64=1 < %s \
17+
# RUN: | llvm-objdump --mattr=+experimental-y -M no-aliases -d --no-print-imm-hex - \
18+
# RUN: | FileCheck --check-prefixes=CHECK-ASM-AND-OBJ,CHECK-ASM-AND-OBJ-64 %s
19+
20+
## Both capability & normal RISC-V instruction use the same encoding, and the
21+
## same MCInst as we rely on RegClassByHwMode to select the rigt base pointer.
22+
23+
# CHECK-ASM-AND-OBJ: lb a0, 0(a1)
24+
# CHECK-ASM-SAME: # encoding: [0x03,0x85,0x05,0x00]
25+
lb a0, 0(a1)
26+
# CHECK-ASM-AND-OBJ: sb a0, 0(a1)
27+
# CHECK-ASM-SAME: # encoding: [0x23,0x80,0xa5,0x00]
28+
sb a0, 0(a1)
29+
# CHECK-ASM-AND-OBJ: lbu a0, 0(a1)
30+
# CHECK-ASM-SAME: # encoding: [0x03,0xc5,0x05,0x00]
31+
lbu a0, 0(a1)
32+
# CHECK-ASM-AND-OBJ: lh a0, 0(a1)
33+
# CHECK-ASM-SAME: # encoding: [0x03,0x95,0x05,0x00]
34+
lh a0, 0(a1)
35+
# CHECK-ASM-AND-OBJ: sh a0, 0(a1)
36+
# CHECK-ASM-SAME: # encoding: [0x23,0x90,0xa5,0x00]
37+
sh a0, 0(a1)
38+
# CHECK-ASM-AND-OBJ: lhu a0, 0(a1)
39+
# CHECK-ASM-SAME: # encoding: [0x03,0xd5,0x05,0x00]
40+
lhu a0, 0(a1)
41+
# CHECK-ASM-AND-OBJ: lw a0, 0(a1)
42+
# CHECK-ASM-SAME: # encoding: [0x03,0xa5,0x05,0x00]
43+
lw a0, 0(a1)
44+
# CHECK-ASM-AND-OBJ: sw a0, 0(a1)
45+
# CHECK-ASM-SAME: # encoding: [0x23,0xa0,0xa5,0x00]
46+
sw a0, 0(a1)
47+
48+
.ifdef RV64
49+
# CHECK-ASM-AND-OBJ-64: lwu a0, 0(a1)
50+
# CHECK-ASM-64-SAME: # encoding: [0x03,0xe5,0x05,0x00]
51+
lwu a0, 0(a1)
52+
# CHECK-ASM-AND-OBJ-64: ld a0, 0(a1)
53+
# CHECK-ASM-64-SAME: # encoding: [0x03,0xb5,0x05,0x00]
54+
ld a0, 0(a1)
55+
# CHECK-ASM-AND-OBJ-64: sd a0, 0(a1)
56+
# CHECK-ASM-64-SAME: # encoding: [0x23,0xb0,0xa5,0x00]
57+
sd a0, 0(a1)
58+
.endif
59+
60+
# CHECK-ASM-AND-OBJ: ly a0, 0(a1)
61+
# CHECK-ASM-SAME: # encoding: [0x0f,0xc5,0x05,0x00]
62+
ly a0, 0(a1)
63+
# CHECK-ASM-AND-OBJ: sy a0, 0(a1)
64+
# CHECK-ASM-SAME: # encoding: [0x23,0xc0,0xa5,0x00]
65+
sy a0, 0(a1)

0 commit comments

Comments
 (0)