Skip to content

Commit 9b7a809

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 cast), 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 but we have to select between two instructions: one using the normal GPR register class and one using the YGPR register class. The newly added test checks that we select the right instruction (`LW` or `LW_Y`) using --show-inst, since both the encoding and the assembler syntax are the same in both modes. This commit changes the Load_ri and Store_rri tablegen classes into a multiclass that defines the RVI and RVY at the same time to reduce the size of the diff and hopefully improve maintainability. The downstream fork had duplicated definitions which avoids merge conflicts but does mean any refactorings do not make it to the almost identical duplicate definitions. The other advantage is that we also get support for the other load/store instructions that are not explicitly tested in this commit.
1 parent 02a8278 commit 9b7a809

File tree

8 files changed

+148
-31
lines changed

8 files changed

+148
-31
lines changed

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -735,6 +735,9 @@ static constexpr DecoderListEntry DecoderList32[]{
735735
{DecoderTableXAndes32, XAndesGroup, "Andes extensions"},
736736
{DecoderTableXSMT32, XSMTGroup, "SpacemiT extensions"},
737737
// Standard Extensions
738+
{DecoderTableRVY32Only32,
739+
{RISCV::FeatureStdExtY, RISCV::Feature32Bit},
740+
"RVY32-only standard 32-bit instructions"},
738741
{DecoderTableRVYOnly32,
739742
{RISCV::FeatureStdExtY},
740743
"RVY-only standard 32-bit instructions"},

llvm/lib/Target/RISCV/RISCVInstrInfo.td

Lines changed: 41 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,7 @@ def GPRMemZeroOffset : MemOperand<GPR> {
227227
}
228228

229229
def GPRMem : MemOperand<GPR>;
230+
def YGPRMem : MemOperand<YGPR>;
230231

231232
def SPMem : MemOperand<SP>;
232233

@@ -643,9 +644,20 @@ class BranchCC_rri<bits<3> funct3, string opcodestr>
643644
}
644645

645646
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),
648-
opcodestr, "$rd, ${imm12}(${rs1})">;
647+
multiclass Load_ri<bits<3> funct3, string opcodestr, DAGOperand rty = GPR,
648+
RISCVOpcode opcode=OPC_LOAD, list<Predicate> ExtraPreds=[],
649+
string DecoderNS=""> {
650+
let DecoderNamespace = DecoderNS,
651+
Predicates = !listconcat(ExtraPreds, [NotCapMode]) in
652+
def "" : RVInstI<funct3, opcode, (outs rty:$rd),
653+
(ins GPRMem:$rs1, simm12_lo:$imm12), opcodestr,
654+
"$rd, ${imm12}(${rs1})">;
655+
let DecoderNamespace = !if(!eq(DecoderNS, ""), "RVYOnly", !subst("RV", "RVY", DecoderNS)),
656+
Predicates = !listconcat(ExtraPreds, [HasStdExtY, IsCapMode]) in
657+
def _Y : RVInstI<funct3, opcode, (outs rty:$rd),
658+
(ins YGPRMem:$rs1, simm12_lo:$imm12), opcodestr,
659+
"$rd, ${imm12}(${rs1})">;
660+
}
649661

650662
class HLoad_r<bits<7> funct7, bits<5> funct5, string opcodestr>
651663
: RVInstR<funct7, 0b100, OPC_SYSTEM, (outs GPR:$rd),
@@ -658,10 +670,19 @@ class HLoad_r<bits<7> funct7, bits<5> funct5, string opcodestr>
658670
// reflecting the order these fields are specified in the instruction
659671
// encoding.
660672
let hasSideEffects = 0, mayLoad = 0, mayStore = 1 in {
661-
class Store_rri<bits<3> funct3, string opcodestr, DAGOperand rty = GPR>
662-
: RVInstS<funct3, OPC_STORE, (outs),
673+
multiclass Store_rri<bits<3> funct3, string opcodestr, DAGOperand rty = GPR,
674+
list<Predicate> ExtraPreds = [], string DecoderNS = ""> {
675+
let DecoderNamespace = DecoderNS,
676+
Predicates = !listconcat(ExtraPreds, [NotCapMode]) in
677+
def "" : RVInstS<funct3, OPC_STORE, (outs),
663678
(ins rty:$rs2, GPRMem:$rs1, simm12_lo:$imm12),
664679
opcodestr, "$rs2, ${imm12}(${rs1})">;
680+
let DecoderNamespace = !if(!eq(DecoderNS, ""), "RVYOnly", !subst("RV", "RVY", DecoderNS)),
681+
Predicates = !listconcat(ExtraPreds, [HasStdExtY, IsCapMode]) in
682+
def _Y : RVInstS<funct3, OPC_STORE, (outs),
683+
(ins rty:$rs2, YGPRMem:$rs1, simm12_lo:$imm12),
684+
opcodestr, "$rs2, ${imm12}(${rs1})">;
685+
}
665686

666687
class HStore_rr<bits<7> funct7, string opcodestr>
667688
: RVInstR<funct7, 0b100, OPC_SYSTEM, (outs),
@@ -769,16 +790,16 @@ def BLTU : BranchCC_rri<0b110, "bltu">;
769790
def BGEU : BranchCC_rri<0b111, "bgeu">;
770791

771792
let IsSignExtendingOpW = 1 in {
772-
def LB : Load_ri<0b000, "lb">, Sched<[WriteLDB, ReadMemBase]>;
773-
def LH : Load_ri<0b001, "lh">, Sched<[WriteLDH, ReadMemBase]>;
774-
def LW : Load_ri<0b010, "lw">, Sched<[WriteLDW, ReadMemBase]>;
775-
def LBU : Load_ri<0b100, "lbu">, Sched<[WriteLDB, ReadMemBase]>;
776-
def LHU : Load_ri<0b101, "lhu">, Sched<[WriteLDH, ReadMemBase]>;
793+
defm LB : Load_ri<0b000, "lb">, Sched<[WriteLDB, ReadMemBase]>;
794+
defm LH : Load_ri<0b001, "lh">, Sched<[WriteLDH, ReadMemBase]>;
795+
defm LW : Load_ri<0b010, "lw">, Sched<[WriteLDW, ReadMemBase]>;
796+
defm LBU : Load_ri<0b100, "lbu">, Sched<[WriteLDB, ReadMemBase]>;
797+
defm LHU : Load_ri<0b101, "lhu">, Sched<[WriteLDH, ReadMemBase]>;
777798
}
778799

779-
def SB : Store_rri<0b000, "sb">, Sched<[WriteSTB, ReadStoreData, ReadMemBase]>;
780-
def SH : Store_rri<0b001, "sh">, Sched<[WriteSTH, ReadStoreData, ReadMemBase]>;
781-
def SW : Store_rri<0b010, "sw">, Sched<[WriteSTW, ReadStoreData, ReadMemBase]>;
800+
defm SB : Store_rri<0b000, "sb">, Sched<[WriteSTB, ReadStoreData, ReadMemBase]>;
801+
defm SH : Store_rri<0b001, "sh">, Sched<[WriteSTH, ReadStoreData, ReadMemBase]>;
802+
defm SW : Store_rri<0b010, "sw">, Sched<[WriteSTW, ReadStoreData, ReadMemBase]>;
782803

783804
// ADDI isn't always rematerializable, but isReMaterializable will be used as
784805
// a hint which is verified in isReMaterializableImpl.
@@ -888,11 +909,14 @@ def CSRRCI : CSR_ii<0b111, "csrrci">;
888909

889910
/// RV64I instructions
890911

891-
let Predicates = [IsRV64] in {
892-
def LWU : Load_ri<0b110, "lwu">, Sched<[WriteLDW, ReadMemBase]>;
893-
def LD : Load_ri<0b011, "ld">, Sched<[WriteLDD, ReadMemBase]>;
894-
def SD : Store_rri<0b011, "sd">, Sched<[WriteSTD, ReadStoreData, ReadMemBase]>;
912+
defm LWU : Load_ri<0b110, "lwu", ExtraPreds=[IsRV64]>,
913+
Sched<[WriteLDW, ReadMemBase]>;
914+
defm LD : Load_ri<0b011, "ld", ExtraPreds=[IsRV64]>,
915+
Sched<[WriteLDD, ReadMemBase]>;
916+
defm SD : Store_rri<0b011, "sd", ExtraPreds=[IsRV64]>,
917+
Sched<[WriteSTD, ReadStoreData, ReadMemBase]>;
895918

919+
let Predicates = [IsRV64] in {
896920
let IsSignExtendingOpW = 1 in {
897921
let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in
898922
def ADDIW : RVInstI<0b000, OPC_OP_IMM_32, (outs GPR:$rd),

llvm/lib/Target/RISCV/RISCVInstrInfoF.td

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -337,15 +337,16 @@ def FLW : FPLoad_r<0b010, "flw", FPR32, WriteFLD32>;
337337
def FSW : FPStore_r<0b010, "fsw", FPR32, WriteFST32>;
338338
} // Predicates = [HasStdExtF]
339339

340-
let Predicates = [HasStdExtZfinx], isCodeGenOnly = 1 in {
341-
def LW_INX : Load_ri<0b010, "lw", GPRF32>, Sched<[WriteLDW, ReadMemBase]>;
342-
def SW_INX : Store_rri<0b010, "sw", GPRF32>,
340+
let isCodeGenOnly = 1 in {
341+
defm LW_INX : Load_ri<0b010, "lw", GPRF32, ExtraPreds=[HasStdExtZfinx]>,
342+
Sched<[WriteLDW, ReadMemBase]>;
343+
defm SW_INX : Store_rri<0b010, "sw", GPRF32, ExtraPreds=[HasStdExtZfinx]>,
343344
Sched<[WriteSTW, ReadStoreData, ReadMemBase]>;
344345

345346
// ADDI with GPRF32 register class to use for copy. This should not be used as
346347
// general ADDI, so the immediate should always be zero.
347348
let isReMaterializable = 1, isAsCheapAsAMove = 1, isMoveReg = 1,
348-
hasSideEffects = 0, mayLoad = 0, mayStore = 0 in
349+
hasSideEffects = 0, mayLoad = 0, mayStore = 0, Predicates=[HasStdExtZfinx] in
349350
def PseudoMV_FPR32INX : Pseudo<(outs GPRF32:$rd), (ins GPRF32:$rs), []>,
350351
Sched<[WriteIALU, ReadIALU]>;
351352
}

llvm/lib/Target/RISCV/RISCVInstrInfoY.td

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

llvm/lib/Target/RISCV/RISCVInstrInfoZfh.td

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -98,15 +98,17 @@ def FLH : FPLoad_r<0b001, "flh", FPR16, WriteFLD16>;
9898
def FSH : FPStore_r<0b001, "fsh", FPR16, WriteFST16>;
9999
} // Predicates = [HasHalfFPLoadStoreMove]
100100

101-
let Predicates = [HasStdExtZhinxmin], isCodeGenOnly = 1 in {
102-
def LH_INX : Load_ri<0b001, "lh", GPRF16>, Sched<[WriteLDH, ReadMemBase]>;
103-
def SH_INX : Store_rri<0b001, "sh", GPRF16>,
104-
Sched<[WriteSTH, ReadStoreData, ReadMemBase]>;
101+
let isCodeGenOnly = 1 in {
102+
defm LH_INX : Load_ri<0b001, "lh", GPRF16, ExtraPreds=[HasStdExtZfinx]>,
103+
Sched<[WriteLDH, ReadMemBase]>;
104+
defm SH_INX : Store_rri<0b001, "sh", GPRF16, ExtraPreds=[HasStdExtZfinx]>,
105+
Sched<[WriteSTH, ReadStoreData, ReadMemBase]>;
105106

106107
// ADDI with GPRF16 register class to use for copy. This should not be used as
107108
// general ADDI, so the immediate should always be zero.
108109
let isReMaterializable = 1, isAsCheapAsAMove = 1, isMoveReg = 1,
109-
hasSideEffects = 0, mayLoad = 0, mayStore = 0 in
110+
hasSideEffects = 0, mayLoad = 0, mayStore = 0,
111+
Predicates = [HasStdExtZhinxmin] in
110112
def PseudoMV_FPR16INX : Pseudo<(outs GPRF16:$rd), (ins GPRF16:$rs), []>,
111113
Sched<[WriteIALU, ReadIALU]>;
112114
}

llvm/lib/Target/RISCV/RISCVInstrInfoZilsd.td

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,12 @@ def riscv_st_rv32 : RVSDNode<"SD_RV32", SDT_RISCV_SD_RV32,
3333
// Instructions
3434
//===----------------------------------------------------------------------===//
3535

36-
let Predicates = [HasStdExtZilsd, IsRV32], DecoderNamespace = "RV32Only" in {
37-
def LD_RV32 : Load_ri<0b011, "ld", GPRPairRV32>, Sched<[WriteLDD, ReadMemBase]>;
38-
def SD_RV32 : Store_rri<0b011, "sd", GPRPairRV32>,
39-
Sched<[WriteSTD, ReadStoreData, ReadMemBase]>;
40-
} // Predicates = [HasStdExtZilsd, IsRV32], DecoderNamespace = "RV32Only"
36+
defm LD_RV32 : Load_ri<0b011, "ld", GPRPairRV32, DecoderNS="RV32Only",
37+
ExtraPreds=[HasStdExtZilsd, IsRV32]>,
38+
Sched<[WriteLDD, ReadMemBase]>;
39+
defm SD_RV32 : Store_rri<0b011, "sd", GPRPairRV32, DecoderNS="RV32Only",
40+
ExtraPreds=[HasStdExtZilsd, IsRV32]>,
41+
Sched<[WriteSTD, ReadStoreData, ReadMemBase]>;
4142

4243
//===----------------------------------------------------------------------===//
4344
// Assembler Pseudo Instructions

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: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
# RUN: llvm-mc %s --triple=riscv32 -mattr=+experimental-y --riscv-no-aliases --show-encoding --show-inst \
2+
# RUN: | FileCheck --check-prefixes=CHECK-ASM,CHECK-ASM-AND-OBJ -DSUFFIX= %s
3+
# RUN: llvm-mc %s --triple=riscv32 -mattr=+experimental-y,+cap-mode --riscv-no-aliases --show-encoding --show-inst \
4+
# RUN: | FileCheck --check-prefixes=CHECK-ASM,CHECK-ASM-AND-OBJ -DSUFFIX=_Y %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 --show-inst --defsym=RV64=1 \
11+
# RUN: | FileCheck --check-prefixes=CHECK-ASM,CHECK-ASM-64,CHECK-ASM-AND-OBJ,CHECK-ASM-AND-OBJ-64 -DSUFFIX= %s
12+
# RUN: llvm-mc %s --triple=riscv64 --mattr=+experimental-y,+cap-mode --riscv-no-aliases \
13+
# RUN: --show-encoding --show-inst --defsym=RV64=1 \
14+
# RUN: | FileCheck --check-prefixes=CHECK-ASM,CHECK-ASM-64,CHECK-ASM-AND-OBJ,CHECK-ASM-AND-OBJ-64 -DSUFFIX=_Y %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, but we have
21+
## to check that we select the correct MCInst: for +cap-mode we want a _Y suffix
22+
23+
# CHECK-ASM-AND-OBJ: lb a0, 0(a1)
24+
# CHECK-ASM-SAME: # encoding: [0x03,0x85,0x05,0x00]
25+
# CHECK-ASM-NEXT: <MCInst #[[#]] LB[[SUFFIX]]{{$}}
26+
lb a0, 0(a1)
27+
# CHECK-ASM-AND-OBJ: sb a0, 0(a1)
28+
# CHECK-ASM-SAME: # encoding: [0x23,0x80,0xa5,0x00]
29+
# CHECK-ASM-NEXT: <MCInst #[[#]] SB[[SUFFIX]]{{$}}
30+
sb a0, 0(a1)
31+
# CHECK-ASM-AND-OBJ: lbu a0, 0(a1)
32+
# CHECK-ASM-SAME: # encoding: [0x03,0xc5,0x05,0x00]
33+
# CHECK-ASM-NEXT: <MCInst #[[#]] LBU[[SUFFIX]]{{$}}
34+
lbu a0, 0(a1)
35+
# CHECK-ASM-AND-OBJ: lh a0, 0(a1)
36+
# CHECK-ASM-SAME: # encoding: [0x03,0x95,0x05,0x00]
37+
# CHECK-ASM-NEXT: <MCInst #[[#]] LH[[SUFFIX]]{{$}}
38+
lh a0, 0(a1)
39+
# CHECK-ASM-AND-OBJ: sh a0, 0(a1)
40+
# CHECK-ASM-SAME: # encoding: [0x23,0x90,0xa5,0x00]
41+
# CHECK-ASM-NEXT: <MCInst #[[#]] SH[[SUFFIX]]{{$}}
42+
sh a0, 0(a1)
43+
# CHECK-ASM-AND-OBJ: lhu a0, 0(a1)
44+
# CHECK-ASM-SAME: # encoding: [0x03,0xd5,0x05,0x00]
45+
# CHECK-ASM-NEXT: <MCInst #[[#]] LHU[[SUFFIX]]{{$}}
46+
lhu a0, 0(a1)
47+
# CHECK-ASM-AND-OBJ: lw a0, 0(a1)
48+
# CHECK-ASM-SAME: # encoding: [0x03,0xa5,0x05,0x00]
49+
# CHECK-ASM-NEXT: <MCInst #[[#]] LW[[SUFFIX]]{{$}}
50+
lw a0, 0(a1)
51+
# CHECK-ASM-AND-OBJ: sw a0, 0(a1)
52+
# CHECK-ASM-SAME: # encoding: [0x23,0xa0,0xa5,0x00]
53+
# CHECK-ASM-NEXT: <MCInst #[[#]] SW[[SUFFIX]]{{$}}
54+
sw a0, 0(a1)
55+
56+
.ifdef RV64
57+
# CHECK-ASM-AND-OBJ-64: lwu a0, 0(a1)
58+
# CHECK-ASM-64-SAME: # encoding: [0x03,0xe5,0x05,0x00]
59+
# CHECK-ASM-64-NEXT: <MCInst #[[#]] LWU[[SUFFIX]]{{$}}
60+
lwu a0, 0(a1)
61+
# CHECK-ASM-AND-OBJ-64: ld a0, 0(a1)
62+
# CHECK-ASM-64-SAME: # encoding: [0x03,0xb5,0x05,0x00]
63+
# CHECK-ASM-64-NEXT: <MCInst #[[#]] LD[[SUFFIX]]{{$}}
64+
ld a0, 0(a1)
65+
# CHECK-ASM-AND-OBJ-64: sd a0, 0(a1)
66+
# CHECK-ASM-64-SAME: # encoding: [0x23,0xb0,0xa5,0x00]
67+
# CHECK-ASM-64-NEXT: <MCInst #[[#]] SD[[SUFFIX]]{{$}}
68+
sd a0, 0(a1)
69+
.endif
70+
71+
# CHECK-ASM-AND-OBJ: ly a0, 0(a1)
72+
# CHECK-ASM-SAME: # encoding: [0x0f,0xc5,0x05,0x00]
73+
# CHECK-ASM-NEXT: <MCInst #[[#]] LY[[SUFFIX]]{{$}}
74+
ly a0, 0(a1)
75+
# CHECK-ASM-AND-OBJ: sy a0, 0(a1)
76+
# CHECK-ASM-SAME: # encoding: [0x23,0xc0,0xa5,0x00]
77+
# CHECK-ASM-NEXT: <MCInst #[[#]] SY[[SUFFIX]]{{$}}
78+
sy a0, 0(a1)

0 commit comments

Comments
 (0)