Repository navigation
[RISC-V][MC][RVY] Add support for RVY loads/stores - #177073
arichardson wants to merge 3 commits into
Conversation
|
@llvm/pr-subscribers-clang-driver @llvm/pr-subscribers-backend-risc-v Author: Alexander Richardson (arichardson) ChangesThis adds supports for all new RVY loads/stores (capability-wide lw x4, 0(c3) # capability mode: use new During the standardization this was changed to keep the same register This allows using the RegClassByHwMode feature to reuse the same MC Patch is 27.04 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/177073.diff 11 Files Affected:
diff --git a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
index 6edc942cdb280..556c78dcc5617 100644
--- a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
+++ b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
@@ -1372,9 +1372,17 @@ unsigned RISCVAsmParser::validateTargetOperandClass(MCParsedAsmOperand &AsmOp,
RISCVMCRegisterClasses[RISCV::FPR64CRegClassID].contains(Reg);
bool IsRegVR = RISCVMCRegisterClasses[RISCV::VRRegClassID].contains(Reg);
- if (Op.isGPR() && Kind == MCK_YGPR) {
+ // In RVY mode, the BasePtrRC register class should select capability
+ // registers for the base pointer operands, otherwise we use GPRs.
+ // TODO: Is there any way we could do this in tablegen automatically?
+ if (Kind == MCK_RegByHwMode_BasePtrRC)
+ Kind = STI->hasFeature(RISCV::FeatureCapMode) ? MCK_YGPRNoX0 : MCK_GPR;
+
+ if (Op.isGPR() && (Kind == MCK_YGPR || Kind == MCK_YGPRNoX0)) {
// GPR and capability GPR use the same register names, convert if required.
Op.Reg.Reg = convertGPRToYGPR(Reg);
+ if (Kind == MCK_YGPRNoX0 && Op.Reg.Reg == RISCV::X0_Y)
+ return Match_InvalidRegClassYGPRNoNull;
return Match_Success;
}
if (IsRegFPR64 && Kind == MCK_FPR256) {
diff --git a/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp b/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp
index d894714b03773..9094ef64c7162 100644
--- a/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp
+++ b/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp
@@ -264,6 +264,15 @@ static DecodeStatus DecodeGPRNoX0RegisterClass(MCInst &Inst, uint32_t RegNo,
return DecodeGPRRegisterClass(Inst, RegNo, Address, Decoder);
}
+static DecodeStatus DecodeYGPRNoX0RegisterClass(MCInst &Inst, uint32_t RegNo,
+ uint64_t Address,
+ const MCDisassembler *Decoder) {
+ if (RegNo == 0)
+ return MCDisassembler::Fail;
+
+ return DecodeYGPRRegisterClass(Inst, RegNo, Address, Decoder);
+}
+
static DecodeStatus DecodeGPRNoX2RegisterClass(MCInst &Inst, uint64_t RegNo,
uint32_t Address,
const MCDisassembler *Decoder) {
diff --git a/llvm/lib/Target/RISCV/RISCVFeatures.td b/llvm/lib/Target/RISCV/RISCVFeatures.td
index b533dfd090ed0..b683662fcf0e2 100644
--- a/llvm/lib/Target/RISCV/RISCVFeatures.td
+++ b/llvm/lib/Target/RISCV/RISCVFeatures.td
@@ -1778,8 +1778,10 @@ def IsRV32 : Predicate<"!Subtarget->is64Bit()">,
AssemblerPredicate<(all_of (not Feature64Bit)),
"RV32I Base Instruction Set">;
-defvar RV32 = DefaultMode;
-def RV64 : HwMode<[IsRV64]>;
+defvar RV32I = DefaultMode;
+def RV64I : HwMode<[IsRV64, NotCapMode]>;
+def RV32Y : HwMode<[IsRV32, IsCapMode]>;
+def RV64Y : HwMode<[IsRV64, IsCapMode]>;
def FeatureRelax
: SubtargetFeature<"relax", "EnableLinkerRelax", "true",
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.td b/llvm/lib/Target/RISCV/RISCVInstrInfo.td
index e8e3691564744..36fe4dfa66610 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfo.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.td
@@ -217,7 +217,7 @@ def ZeroOffsetMemOpOperand : AsmOperandClass {
let ParserMethod = "parseZeroOffsetMemOp";
}
-class MemOperand<RegisterClass regClass> : RegisterOperand<regClass>{
+class MemOperand<RegisterClassLike regClass> : RegisterOperand<regClass> {
let OperandType = "OPERAND_MEMORY";
}
@@ -227,6 +227,15 @@ def GPRMemZeroOffset : MemOperand<GPR> {
}
def GPRMem : MemOperand<GPR>;
+// Note: For RVY, the encodings using x0/zero (a null capability) as the base
+// are reserved. Therefore, we use YGPRNoX0 to reject them in the assembler
+// while allowing the encodings for RVI mode.
+def BasePtrRC : RegClassByHwMode<
+ [RV32I, RV64I, RV32Y, RV64Y],
+ [GPR, GPR, YGPRNoX0, YGPRNoX0]>;
+
+def BasePtr : MemOperand<BasePtrRC>;
+
def SPMem : MemOperand<SP>;
@@ -644,8 +653,9 @@ class BranchCC_rri<bits<3> funct3, string opcodestr>
}
let hasSideEffects = 0, mayLoad = 1, mayStore = 0 in {
-class Load_ri<bits<3> funct3, string opcodestr, DAGOperand rty = GPR>
- : RVInstI<funct3, OPC_LOAD, (outs rty:$rd), (ins GPRMem:$rs1, simm12_lo:$imm12),
+class Load_ri<bits<3> funct3, string opcodestr, DAGOperand rty = GPR,
+ RISCVOpcode opcode = OPC_LOAD>
+ : RVInstI<funct3, opcode, (outs rty:$rd), (ins BasePtr:$rs1, simm12_lo:$imm12),
opcodestr, "$rd, ${imm12}(${rs1})">;
class HLoad_r<bits<7> funct7, bits<5> funct5, string opcodestr>
@@ -661,7 +671,7 @@ class HLoad_r<bits<7> funct7, bits<5> funct5, string opcodestr>
let hasSideEffects = 0, mayLoad = 0, mayStore = 1 in {
class Store_rri<bits<3> funct3, string opcodestr, DAGOperand rty = GPR>
: RVInstS<funct3, OPC_STORE, (outs),
- (ins rty:$rs2, GPRMem:$rs1, simm12_lo:$imm12),
+ (ins rty:$rs2, BasePtr:$rs1, simm12_lo:$imm12),
opcodestr, "$rs2, ${imm12}(${rs1})">;
class HStore_rr<bits<7> funct7, string opcodestr>
@@ -1165,22 +1175,22 @@ let Predicates = [HasStdExtZihintntl] in {
let EmitPriority = 0 in {
def : InstAlias<"lb $rd, (${rs1})",
- (LB GPR:$rd, GPR:$rs1, 0)>;
+ (LB GPR:$rd, BasePtr:$rs1, 0)>;
def : InstAlias<"lh $rd, (${rs1})",
- (LH GPR:$rd, GPR:$rs1, 0)>;
+ (LH GPR:$rd, BasePtr:$rs1, 0)>;
def : InstAlias<"lw $rd, (${rs1})",
- (LW GPR:$rd, GPR:$rs1, 0)>;
+ (LW GPR:$rd, BasePtr:$rs1, 0)>;
def : InstAlias<"lbu $rd, (${rs1})",
- (LBU GPR:$rd, GPR:$rs1, 0)>;
+ (LBU GPR:$rd, BasePtr:$rs1, 0)>;
def : InstAlias<"lhu $rd, (${rs1})",
- (LHU GPR:$rd, GPR:$rs1, 0)>;
+ (LHU GPR:$rd, BasePtr:$rs1, 0)>;
def : InstAlias<"sb $rs2, (${rs1})",
- (SB GPR:$rs2, GPR:$rs1, 0)>;
+ (SB GPR:$rs2, BasePtr:$rs1, 0)>;
def : InstAlias<"sh $rs2, (${rs1})",
- (SH GPR:$rs2, GPR:$rs1, 0)>;
+ (SH GPR:$rs2, BasePtr:$rs1, 0)>;
def : InstAlias<"sw $rs2, (${rs1})",
- (SW GPR:$rs2, GPR:$rs1, 0)>;
+ (SW GPR:$rs2, BasePtr:$rs1, 0)>;
def : InstAlias<"add $rd, $rs1, $imm12",
(ADDI GPR:$rd, GPR:$rs1, simm12_lo:$imm12)>;
@@ -1198,11 +1208,11 @@ def : InstAlias<"sra $rd, $rs1, $shamt",
(SRAI GPR:$rd, GPR:$rs1, uimmlog2xlen:$shamt)>;
let Predicates = [IsRV64] in {
def : InstAlias<"lwu $rd, (${rs1})",
- (LWU GPR:$rd, GPR:$rs1, 0)>;
+ (LWU GPR:$rd, BasePtr:$rs1, 0)>;
def : InstAlias<"ld $rd, (${rs1})",
- (LD GPR:$rd, GPR:$rs1, 0)>;
+ (LD GPR:$rd, BasePtr:$rs1, 0)>;
def : InstAlias<"sd $rs2, (${rs1})",
- (SD GPR:$rs2, GPR:$rs1, 0)>;
+ (SD GPR:$rs2, BasePtr:$rs1, 0)>;
def : InstAlias<"addw $rd, $rs1, $imm12",
(ADDIW GPR:$rd, GPR:$rs1, simm12_lo:$imm12)>;
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoY.td b/llvm/lib/Target/RISCV/RISCVInstrInfoY.td
index 08565a6f906e8..bb9b252367b4a 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoY.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoY.td
@@ -105,4 +105,11 @@ let Predicates = [HasStdExtY] in {
def SYEQ : RVY_rr<0x6, 0x4, "syeq", GPR, YGPR, YGPR>;
def YLT : RVY_rr<0x6, 0x6, "ylt", GPR, YGPR, YGPR>;
def YAMASK : RVY_r<0x7, "yamask", GPR, GPR>;
+
+ // Instructions to Load and Store Capability Data
+ def LY : Load_ri<0b100, "ly", YGPR, opcode=OPC_MISC_MEM>,
+ Sched<[/* TODO: WriteLDY, */ ReadMemBase]>;
+ def SY : Store_rri<0b100, "sy", YGPR>,
+ Sched<[/* TODO: WriteSTY, */ ReadStoreData, ReadMemBase]>;
+
} // Predicates = [HasStdExtY]
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoZilsd.td b/llvm/lib/Target/RISCV/RISCVInstrInfoZilsd.td
index 4fc859f2547c1..0438ff4af6d8d 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoZilsd.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoZilsd.td
@@ -64,6 +64,6 @@ def PseudoSD_RV32_OPT :
let mayStore = 1;
}
-def : InstAlias<"ld $rd, (${rs1})", (LD_RV32 GPRPairRV32:$rd, GPR:$rs1, 0), 0>;
-def : InstAlias<"sd $rs2, (${rs1})", (SD_RV32 GPRPairRV32:$rs2, GPR:$rs1, 0), 0>;
+def : InstAlias<"ld $rd, (${rs1})", (LD_RV32 GPRPairRV32:$rd, BasePtr:$rs1, 0), 0>;
+def : InstAlias<"sd $rs2, (${rs1})", (SD_RV32 GPRPairRV32:$rs2, BasePtr:$rs1, 0), 0>;
}
diff --git a/llvm/lib/Target/RISCV/RISCVRegisterInfo.td b/llvm/lib/Target/RISCV/RISCVRegisterInfo.td
index c6be45b8dfaa6..5fb69d7bcf80d 100644
--- a/llvm/lib/Target/RISCV/RISCVRegisterInfo.td
+++ b/llvm/lib/Target/RISCV/RISCVRegisterInfo.td
@@ -55,8 +55,9 @@ class RISCVReg128<RISCVReg64 subreg>
// A subreg index for the address part of capability registers (this is just the
// default XLEN-wide X<N> register).
def sub_cap_addr : SubRegIndex<32> {
- let SubRegRanges =
- SubRegRangeByHwMode<[RV32, RV64], [SubRegRange<32>, SubRegRange<64>]>;
+ let SubRegRanges = SubRegRangeByHwMode<
+ [RV32I, RV64I, RV32Y, RV64Y],
+ [SubRegRange<32>, SubRegRange<64>, SubRegRange<32>, SubRegRange<64>]>;
}
class RISCVCapReg<RISCVRegWithSubRegs subreg, string n, list<string> alt = []>
: RISCVRegWithSubRegs<subreg.HWEncoding{4 -0}, n, [subreg], alt> {
@@ -83,12 +84,14 @@ def sub_vrm1_7 : ComposedSubRegIndex<sub_vrm2_3, sub_vrm1_1>;
// GPR sizes change with HwMode.
def sub_gpr_even : SubRegIndex<32> {
- let SubRegRanges = SubRegRangeByHwMode<[RV32, RV64],
- [SubRegRange<32>, SubRegRange<64>]>;
+ let SubRegRanges = SubRegRangeByHwMode<
+ [RV32I, RV64I, RV32Y, RV64Y],
+ [SubRegRange<32>, SubRegRange<32>, SubRegRange<64>, SubRegRange<64>]>;
}
def sub_gpr_odd : SubRegIndex<32, 32> {
- let SubRegRanges = SubRegRangeByHwMode<[RV32, RV64],
- [SubRegRange<32, 32>, SubRegRange<64, 64>]>;
+ let SubRegRanges = SubRegRangeByHwMode<
+ [RV32I, RV64I, RV32Y, RV64Y],
+ [SubRegRange<32, 32>, SubRegRange<32, 32>, SubRegRange<64, 64>, SubRegRange<64, 64>]>;
}
} // Namespace = "RISCV"
@@ -264,29 +267,34 @@ let RegAltNameIndices = [ABIRegAltName] in {
}
}
-def XLenVT : ValueTypeByHwMode<[RV32, RV64],
- [i32, i64]>;
+def XLenVT : ValueTypeByHwMode<[RV32I, RV64I, RV32Y, RV64Y],
+ [i32, i64, i32, i64]>;
defvar XLenPairVT = untyped;
// Allow f64 in GPR for ZDINX on RV64.
-def XLenFVT : ValueTypeByHwMode<[RV64],
- [f64]>;
-def XLenPairFVT : ValueTypeByHwMode<[RV32],
- [f64]>;
+def XLenFVT : ValueTypeByHwMode<[RV64I, RV64Y],
+ [f64, f64]>;
+def XLenPairFVT : ValueTypeByHwMode<[RV32I, RV32Y],
+ [f64, f64]>;
// P extension
-def XLenVecI8VT : ValueTypeByHwMode<[RV32, RV64],
- [v4i8, v8i8]>;
-def XLenVecI16VT : ValueTypeByHwMode<[RV32, RV64],
- [v2i16, v4i16]>;
-def XLenVecI32VT : ValueTypeByHwMode<[RV64],
- [v2i32]>;
+def XLenVecI8VT : ValueTypeByHwMode<[RV32I, RV64I, RV32Y, RV64Y],
+ [v4i8, v8i8, v4i8, v8i8]>;
+def XLenVecI16VT : ValueTypeByHwMode<[RV32I, RV64I, RV32Y, RV64Y],
+ [v2i16, v4i16, v2i16, v4i16]>;
+def XLenVecI32VT : ValueTypeByHwMode<[RV64I, RV64Y],
+ [v2i32, v2i32]>;
def XLenRI : RegInfoByHwMode<
- [RV32, RV64],
- [RegInfo<32,32,32>, RegInfo<64,64,64>]>;
-def YLenVT : ValueTypeByHwMode<[RV32, RV64], [c64, c128]>;
-def YLenRI : RegInfoByHwMode<[RV32, RV64], [RegInfo<64, 64, 64>,
- RegInfo<128, 128, 128>]>;
+ [RV32I, RV64I, RV32Y, RV64Y],
+ [RegInfo<32,32,32>, RegInfo<64,64,64>, RegInfo<32,32,32>, RegInfo<64,64,64>]>;
+def YLenVT : ValueTypeByHwMode<[RV32I, RV64I, RV32Y, RV64Y],
+ [c64, c128, c64, c128]>;
+def YLenRI : RegInfoByHwMode<
+ [RV32I, RV64I, RV32Y, RV64Y],
+ [RegInfo<64, 64, 64>, RegInfo<128, 128, 128>, RegInfo<64, 64, 64>, RegInfo<128, 128, 128>]>;
+
+def PtrLenVT : ValueTypeByHwMode<[RV32I, RV64I, RV32Y, RV64Y],
+ [i32, i64, c64, c128]>;
class RISCVRegisterClass<list<ValueType> regTypes, int align, dag regList>
: RegisterClass<"RISCV", regTypes, align, regList> {
@@ -341,6 +349,10 @@ def GPRNoX0 : GPRRegisterClass<(sub GPR, X0)> {
let DiagnosticType = "InvalidRegClassGPRNoX0";
let DiagnosticString = "register must be a GPR excluding zero (x0)";
}
+def YGPRNoX0 : GPRRegisterClass<(sub YGPR, X0_Y)> {
+ let DiagnosticType = "InvalidRegClassYGPRNoNull";
+ let DiagnosticString = GPRNoX0.DiagnosticString;
+}
def GPRNoX2 : GPRRegisterClass<(sub GPR, X2)> {
let DiagnosticType = "InvalidRegClassGPRNoX2";
@@ -398,8 +410,8 @@ def GPRNoX31 : GPRRegisterClass<(sub GPR, X31)> {
//===----------------------------------------------------------------------===//
def XLenPairRI : RegInfoByHwMode<
- [RV32, RV64],
- [RegInfo<64, 64, 32>, RegInfo<128, 128, 64>]>;
+ [RV32I, RV64I, RV32Y, RV64Y],
+ [RegInfo<64, 64, 32>, RegInfo<128, 128, 64>, RegInfo<64, 64, 32>, RegInfo<128, 128, 64>]>;
// Dummy zero register for use in the register pair containing X0 (as X1 is
// not read to or written when the X0 register pair is used).
diff --git a/llvm/lib/Target/RISCV/RISCVSchedule.td b/llvm/lib/Target/RISCV/RISCVSchedule.td
index dfb4bade9d59c..459e06db6c4a4 100644
--- a/llvm/lib/Target/RISCV/RISCVSchedule.td
+++ b/llvm/lib/Target/RISCV/RISCVSchedule.td
@@ -33,11 +33,13 @@ def WriteLDB : SchedWrite; // Load byte
def WriteLDH : SchedWrite; // Load half-word
def WriteLDW : SchedWrite; // Load word
def WriteLDD : SchedWrite; // Load double-word
+// TODO: def WriteLDY : SchedWrite; // Load capability
def WriteCSR : SchedWrite; // CSR instructions
def WriteSTB : SchedWrite; // Store byte
def WriteSTH : SchedWrite; // Store half-word
def WriteSTW : SchedWrite; // Store word
def WriteSTD : SchedWrite; // Store double-word
+// TODO: def WriteSTY : SchedWrite; // Store capability
def WriteAtomicB : SchedWrite; //Atomic memory operation byte size
def WriteAtomicH : SchedWrite; //Atomic memory operation halfword size
def WriteAtomicW : SchedWrite; //Atomic memory operation word size
diff --git a/llvm/test/MC/RISCV/rvy/rvy-invalid-load-store.s b/llvm/test/MC/RISCV/rvy/rvy-invalid-load-store.s
new file mode 100644
index 0000000000000..32914c5a556d0
--- /dev/null
+++ b/llvm/test/MC/RISCV/rvy/rvy-invalid-load-store.s
@@ -0,0 +1,93 @@
+## For RVY, the loads and stores with the zero register as the base are reserved
+## since this is an always-trapping encoding that may be reused in the future.
+## 1) Check that the assembler rejects zero reg base for capmode but allows it in integer mode.
+## 2) Check that the disassembler with +cap-mode decodes zero reg base as invalid instructions
+# RUN: llvm-mc --triple=riscv32 -mattr=+experimental-y --riscv-no-aliases --show-encoding < %s \
+# RUN: | FileCheck --check-prefixes=CHECK-ASM,CHECK %s
+# RUN: not llvm-mc --triple=riscv32 -mattr=+experimental-y,+cap-mode --riscv-no-aliases --show-encoding < %s 2>&1 \
+# RUN: | FileCheck --check-prefixes=ERR-RVY --implicit-check-not=error: %s
+# RUN: llvm-mc --filetype=obj --triple=riscv32 --mattr=+experimental-y -o %t.rv32i.o < %s
+# RUN: llvm-objdump --mattr=+experimental-y -M no-aliases -d --no-print-imm-hex %t.rv32i.o \
+# RUN: | FileCheck --check-prefixes=CHECK %s
+# RUN: llvm-objdump --mattr=+experimental-y,+cap-mode -M no-aliases -d --no-print-imm-hex %t.rv32i.o \
+# RUN: | FileCheck --check-prefixes=CHECK-CAP-MODE-DISASM %s
+
+# RUN: llvm-mc --triple=riscv64 --mattr=+experimental-y --riscv-no-aliases --show-encoding --defsym=RV64=1 < %s \
+# RUN: | FileCheck --check-prefixes=CHECK-ASM,CHECK-ASM-64,CHECK,CHECK-64 %s
+# RUN: not llvm-mc --triple=riscv64 --mattr=+experimental-y,+cap-mode --riscv-no-aliases --show-encoding --defsym=RV64=1 < %s 2>&1 \
+# RUN: | FileCheck --check-prefixes=ERR-RVY,ERR-RVY-64 --implicit-check-not=error: %s
+# RUN: llvm-mc --filetype=obj --triple=riscv64 --mattr=+experimental-y --riscv-no-aliases --show-encoding --defsym=RV64=1 -o %t.rv64i.o < %s
+# RUN: llvm-objdump --mattr=+experimental-y -M no-aliases -d --no-print-imm-hex %t.rv64i.o \
+# RUN: | FileCheck --check-prefixes=CHECK,CHECK-64 %s
+# RUN: llvm-objdump --mattr=+experimental-y,+cap-mode -M no-aliases -d --no-print-imm-hex %t.rv64i.o \
+# RUN: | FileCheck --check-prefixes=CHECK-CAP-MODE-DISASM,CHECK-CAP-MODE-DISASM-64 %s
+
+# CHECK: lb a0, 16(zero)
+# CHECK-ASM-SAME: # encoding: [0x03,0x05,0x00,0x01]
+# CHECK-CAP-MODE-DISASM: 01000503 <unknown>
+# ERR-RVY: :[[#@LINE+1]]:11: error: register must be a GPR excluding zero (x0)
+lb a0, 16(zero)
+# CHECK-NEXT: sb a0, 16(zero)
+# CHECK-ASM-SAME: # encoding: [0x23,0x08,0xa0,0x00]
+# CHECK-CAP-MODE-DISASM-NEXT: 00a00823 <unknown>
+# ERR-RVY: :[[#@LINE+1]]:11: error: register must be a GPR excluding zero (x0)
+sb a0, 16(zero)
+# CHECK-NEXT: lbu a0, 16(zero)
+# CHECK-ASM-SAME: # encoding: [0x03,0x45,0x00,0x01]
+# CHECK-CAP-MODE-DISASM-NEXT: 01004503 <unknown>
+# ERR-RVY: :[[#@LINE+1]]:12: error: register must be a GPR excluding zero (x0)
+lbu a0, 16(zero)
+# CHECK-NEXT: lh a0, 16(zero)
+# CHECK-ASM-SAME: # encoding: [0x03,0x15,0x00,0x01]
+# CHECK-CAP-MODE-DISASM-NEXT: 01001503 <unknown>
+# ERR-RVY: :[[#@LINE+1]]:11: error: register must be a GPR excluding zero (x0)
+lh a0, 16(zero)
+# CHECK-NEXT: sh a0, 16(zero)
+# CHECK-ASM-SAME: # encoding: [0x23,0x18,0xa0,0x00]
+# CHECK-CAP-MODE-DISASM-NEXT: 00a01823 <unknown>
+# ERR-RVY: :[[#@LINE+1]]:11: error: register must be a GPR excluding zero (x0)
+sh a0, 16(zero)
+# CHECK-NEXT: lhu a0, 16(zero)
+# CHECK-ASM-SAME: # encoding: [0x03,0x55,0x00,0x01]
+# CHECK-CAP-MODE-DISASM-NEXT: 01005503 <unknown>
+# ERR-RVY: :[[#@LINE+1]]:12: error: register must be a GPR excluding zero (x0)
+lhu a0, 16(zero)
+# CHECK-NEXT: lw a0, 16(zero)
+# CHECK-ASM-SAME: # encoding: [0x03,0x25,0x00,0x01]
+# CHECK-CAP-MODE-DISASM-NEXT: 01002503 <unknown>
+# ERR-RVY: :[[#@LINE+1]]:11: error: register must be a GPR excluding zero (x0)
+lw a0, 16(zero)
+# CHECK-NEXT: sw a0, 16(zero)
+# CHECK-ASM-SAME: # encoding: [0x23,0x28,0xa0,0x00]
+# CHECK-CAP-MODE-DISASM-NEXT: 00a02823 <unknown>
+# ERR-RVY: :[[#@LINE+1]]:11: error: register must be a GPR excluding zero (x0)
+sw a0, 16(zero)
+#
+.ifdef RV64
+# CHECK-64: lwu a0, 16(zero)
+# CHECK-ASM-64-SAME: # encoding: [0x03,0x65,0x00,0x01]
+# CHECK-CAP-MODE-DISASM-64-NEXT: 01006503 <unknown>
+# ERR-RVY-64: :[[#@LINE+1]]:12: error: register must be a GPR excluding zero (x0)
+lwu a0, 16(zero)
+# CHECK-64: ld a0, 16(zero)
+# CHECK-ASM-64-SAME: # encoding: [0x03,0x35,0x00,0x01]
+# CHECK-CAP-MODE-DISASM-64-NEXT: 01003503 <unknown>
+# ERR-RVY-64: :[[#@LINE+1]]:11: error: register must be a GPR excluding zero (x0)
+ld a0, 16(zero)
+# CHECK-64: sd a0, 16(zero)
+# CHECK-ASM-64-SAME: # encoding: [0x23,0x38,0xa0,0x00]
+# CHECK-CAP-MODE-DISASM-64-NEXT: 00a03823 <unknown>
+# ERR-RVY-64: :[[#@LINE+1]]:11: error: register must be a GPR excluding zero (x0)
+sd a0, 16(zero)
+.endif
+#
+# CHECK-NEXT: ly a0, 16(zero)
+# CHECK-ASM-SAME: # encoding: [0x0f,0x45,0x00,0x01]
+# CHECK-CAP-MODE-DISASM-NEXT: 0100450f <unknown>
+# ERR-RVY: :[[#@LINE+1]]:11: error: register must be a GPR excluding zero (x0)
+ly a0, 16(zero)
+# CHECK-NEXT: sy a0, 16(zero)
+# CHECK-ASM-SAME: # encoding: [0x23,0x48,0xa0,0x00]
+# CHECK-CAP-MODE-DISASM-NEXT: 00a04823 <unknown>
+# ERR-RVY: :[[#@LINE+1]]:11: error: register must be a GPR excluding zero (x0)
+sy a0, 16(zero)
diff --git a/llvm/test/MC/RISCV/rvy/rvy-valid-load-store-64.s b/llvm/test/MC/RISCV/rvy/rvy-valid-load-store-64.s
new file mode 100644
index 0000000000000..5567f2b503fe7
--- /dev/null
+++ b/llvm/test/MC/RISCV/rvy/rvy-valid-load-store-64.s
@@ -0,0 +1,45 @@
+# RUN: ...
[truncated]
|
🐧 Linux x64 Test Results
✅ The build succeeded and all tests passed. |
🪟 Windows x64 Test Results
✅ The build succeeded and all tests passed. |
|
Looks like I need to pull some fixes from later in the stack into this pull request first to resolve the VT error. I think I must have accidentally moved them into another commit. |
|
What about the compressed load/store instructions? Are FP and vector loads/store and atomics going to be separate PRs? |
Yes, I wanted to do one PR per extension to keep the changes smaller. I have a follow-up change for atomics, and will start working on F/D and C shortly. That said, I could definitely include the compressed versions in this PR if you prefer? |
Let's do the compressed versions of the integer load/stores in this PR so they are in sync. Why is the CompressEmitter letting them be out of sync anyway? |
This adds supports for all new RVY loads/stores (capability-wide versions: ly/sy instructions). Additionally, existing I and Zc* loads and stores are updated to be 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 use `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`. Pull Request: llvm#177073
Updated to include the compressed instructions. |
…r GPRSize Map GPRPair register classes to the GPRB register bank during GlobalISel instruction selection. This is required because the introduction of HwMode-dependent base pointer register classes (e.g. via PtrRegClassByHwMode) causes TableGen to emit register bank checks for GPRPair variants in RISCVGenGlobalISel.inc. Without this mapping, instruction selection crashes on unsupported classes. To avoid assertion failures when GPRB's maximum size increases to 128-bit on RV64 due to the register pairs, update RISCVRegisterBankInfo::getInstrMapping to query Subtarget.getXLen() for the scalar register width instead of relying on the bank's getMaximumSize(). This matches AArch64's design pattern of mapping register pairs (XSeqPairsClass) to GPR and resolving scalar register sizes dynamically. This was fine previously but was exposed by the HwMode changes in #177073. Pull Request: #200510
…etXLen() for GPRSize Map GPRPair register classes to the GPRB register bank during GlobalISel instruction selection. This is required because the introduction of HwMode-dependent base pointer register classes (e.g. via PtrRegClassByHwMode) causes TableGen to emit register bank checks for GPRPair variants in RISCVGenGlobalISel.inc. Without this mapping, instruction selection crashes on unsupported classes. To avoid assertion failures when GPRB's maximum size increases to 128-bit on RV64 due to the register pairs, update RISCVRegisterBankInfo::getInstrMapping to query Subtarget.getXLen() for the scalar register width instead of relying on the bank's getMaximumSize(). This matches AArch64's design pattern of mapping register pairs (XSeqPairsClass) to GPR and resolving scalar register sizes dynamically. This was fine previously but was exposed by the HwMode changes in llvm/llvm-project#177073. Pull Request: llvm/llvm-project#200510
…etXLen() for GPRSize Map GPRPair register classes to the GPRB register bank during GlobalISel instruction selection. This is required because the introduction of HwMode-dependent base pointer register classes (e.g. via PtrRegClassByHwMode) causes TableGen to emit register bank checks for GPRPair variants in RISCVGenGlobalISel.inc. Without this mapping, instruction selection crashes on unsupported classes. To avoid assertion failures when GPRB's maximum size increases to 128-bit on RV64 due to the register pairs, update RISCVRegisterBankInfo::getInstrMapping to query Subtarget.getXLen() for the scalar register width instead of relying on the bank's getMaximumSize(). This matches AArch64's design pattern of mapping register pairs (XSeqPairsClass) to GPR and resolving scalar register sizes dynamically. This was fine previously but was exposed by the HwMode changes in llvm/llvm-project#177073. Pull Request: llvm/llvm-project#200510
…n::create This resolves the TODO for LookupRegClassByHwMode support in llvm-exegesis by passing the MCSubtargetInfo to Instruction::create and calling getOpRegClassID with the active HwMode. This also updates MemoryUse test expectations for Mips, as the target now correctly resolve HwMode-dependent memory register operands (MSA128F16 in Mips and post-#177073 BasePtrRegClass for RISC-V). Pull Request: #200525
|
Now supports Floating point and compressed instructions as well. |
… DecodeSPRegisterClass and similar. (#223889) This can avoid adding more explicitly written decode functions for llvm/llvm-project#177073
This is useful to map from a ByHwMode MCK_* value to the actual resolved MCK_* type. This is needed for llvm#177073 where we would otherwise have to add the manual logic to do this remapping (which is the approach I previously used). Move RegClassByHwModeMatchTable to file scope and provide a remapRegClassByHwMode() helper function in the generated AsmMatcher. Currently only used for RISC-V, but I assume other targets could also make use of this in the future. But even if not, I think it's cleaner to have this as a helper rather than an inline array inside the matcher function. This change was created with the help of AI tools. Reviewed By: arsenm Pull Request: llvm#223302
|
Apologies for the delay in getting back to this. I think the latest version has a much cleaner diff and is hopefully okay now. |
…gisterClass and similar. (#223889) This can avoid adding more explicitly written decode functions for llvm/llvm-project#177073 Signed-off-by: Hafidz Muzakky <ais.muzakky@gmail.com>
This adds support for all new RVY loads/stores (capability-wide versions: ly/sy instructions). Additionally, existing I/Zc* loads and stores are updated to be 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 (RVI 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 use `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 `BasePtr` to use `BasePtrRegClass`. Pull Request: llvm#177073
ccf2bd8 to
62df10e
Compare
62df10e to
fe4aa38
Compare
fe4aa38 to
b0f29d8
Compare
This comment was marked as outdated.
This comment was marked as outdated.
|
With #238648 this change has almost zero impact on the size of the generated tables despite doubling the HwModes. Thanks @topperc! Updated table-size numbers for this PR rebased on top of #238648### 1. `RISCVGenGlobalISel.inc` With #238648 applied,
2.
|
| File / Table | main |
This PR | Delta |
|---|---|---|---|
RISCVGenDAGISel.inc MatcherTable |
1,224,786 B | 1,227,296 B | +2,510 B (+0.20%) |
RISCVGenDAGISel.inc OperandLists |
1,002 B | 1,002 B | +0 B |
RISCVGenAsmMatcher.inc MatchTable0 |
99,456 B (3,552 entries) | 99,736 B (3,562 entries) | +280 B (+10 entries, +0.28%) |
RISCVGenAsmMatcher.inc OperandMatchTable |
12,756 B (2,126 entries) | 12,756 B (2,126 entries) | +0 B |
This adds supports for all new RVY loads/stores (capability-wide
versions: ly/sy instructions). Additionally, existing I/Zc* loads and
stores are updated to be 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:
During the standardization this was changed to keep the same register
name in both modes, so now we use
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
GPRMemoperand withPtrMem.This commit also adds assembler-level support for the RVI-compatible
mode of RVY where all base pointers are interpreted as XLEN values
instead of YLEN values. As noted when introducing Zyhybrid support, this
mode selection is as follows:
no longer reserved for vendor extension).