Repository navigation
[RISC-V][MC] Introduce initial support for RVY (CHERI) - #176871
arichardson wants to merge 10000 commits into
Conversation
|
@llvm/pr-subscribers-backend-risc-v Author: Alexander Richardson (arichardson) ChangesThis adds MC-level support for most of the base Y extension instructions, Co-authored-by: Jessica Clarke <jrtc27@jrtc27.com> Patch is 33.07 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/176871.diff 9 Files Affected:
diff --git a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
index e9d72aceb0e88..6edc942cdb280 100644
--- a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
+++ b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
@@ -488,6 +488,11 @@ struct RISCVOperand final : public MCParsedAsmOperand {
RISCVMCRegisterClasses[RISCV::GPRRegClassID].contains(Reg.Reg);
}
+ bool isYGPR() const {
+ return Kind == KindTy::Register &&
+ RISCVMCRegisterClasses[RISCV::YGPRRegClassID].contains(Reg.Reg);
+ }
+
bool isGPRPair() const {
return Kind == KindTy::Register &&
RISCVMCRegisterClasses[RISCV::GPRPairRegClassID].contains(Reg.Reg);
@@ -762,6 +767,11 @@ struct RISCVOperand final : public MCParsedAsmOperand {
});
}
+ bool isUImm7Srliy() const {
+ return isUImmPred(
+ [this](int64_t Imm) { return isRV64Expr() ? Imm == 64 : Imm == 32; });
+ }
+
bool isUImm8GE32() const {
return isUImmPred([](int64_t Imm) { return isUInt<8>(Imm) && Imm >= 32; });
}
@@ -794,6 +804,29 @@ struct RISCVOperand final : public MCParsedAsmOperand {
return IsConstantImm && isInt<N>(fixImmediateForRV32(Imm, isRV64Expr()));
}
+ bool isYBNDSWImm() const {
+ if (!isExpr())
+ return false;
+
+ int64_t Imm;
+ bool IsConstantImm = evaluateConstantExpr(getExpr(), Imm);
+ if (!IsConstantImm)
+ return false;
+ // The immediate is encoded using `((imm[7:0] + 257) << imm[9:8]) - 256`
+ // which gives the following valid ranges:
+ if (Imm < 1)
+ return false;
+ if (Imm <= 256)
+ return true;
+ if (Imm <= 768)
+ return (Imm % 2) == 0;
+ if (Imm <= 1792)
+ return (Imm % 4) == 0;
+ if (Imm <= 3840)
+ return (Imm % 8) == 0;
+ return false;
+ }
+
template <class Pred> bool isSImmPred(Pred p) const {
int64_t Imm;
if (!isExpr())
@@ -1301,6 +1334,11 @@ static MCRegister convertFPR64ToFPR128(MCRegister Reg) {
return Reg - RISCV::F0_D + RISCV::F0_Q;
}
+static MCRegister convertGPRToYGPR(MCRegister Reg) {
+ assert(Reg >= RISCV::X0 && Reg <= RISCV::X31 && "Invalid register");
+ return Reg - RISCV::X0 + RISCV::X0_Y;
+}
+
static MCRegister convertVRToVRMx(const MCRegisterInfo &RI, MCRegister Reg,
unsigned Kind) {
unsigned RegClassID;
@@ -1334,6 +1372,11 @@ unsigned RISCVAsmParser::validateTargetOperandClass(MCParsedAsmOperand &AsmOp,
RISCVMCRegisterClasses[RISCV::FPR64CRegClassID].contains(Reg);
bool IsRegVR = RISCVMCRegisterClasses[RISCV::VRRegClassID].contains(Reg);
+ if (Op.isGPR() && Kind == MCK_YGPR) {
+ // GPR and capability GPR use the same register names, convert if required.
+ Op.Reg.Reg = convertGPRToYGPR(Reg);
+ return Match_Success;
+ }
if (IsRegFPR64 && Kind == MCK_FPR256) {
Op.Reg.Reg = convertFPR64ToFPR256(Reg);
return Match_Success;
@@ -1712,6 +1755,18 @@ bool RISCVAsmParser::matchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
ErrorLoc,
"stack adjustment is invalid for this instruction and register list");
}
+ case Match_InvalidYBNDSWImm: {
+ const SMLoc ErrorLoc = ((RISCVOperand &)*Operands[ErrorInfo]).getStartLoc();
+ return Error(ErrorLoc, "immediate must be an integer in the range "
+ "[1, 256], a multiple of 2 in the range [258, 768], "
+ "a multiple of 4 in the range [772, 1792], or "
+ "a multiple of 8 in the range [1800, 3840]");
+ }
+ case Match_InvalidUImm7Srliy: {
+ const SMLoc ErrorLoc = ((RISCVOperand &)*Operands[ErrorInfo]).getStartLoc();
+ return Error(ErrorLoc, "immediate must be an integer equal to XLEN (" +
+ Twine(isRV64() ? "64" : "32") + ")");
+ }
}
if (const char *MatchDiag = getMatchKindDiag((RISCVMatchResultTy)Result)) {
diff --git a/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp b/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp
index cacb07fb65501..d894714b03773 100644
--- a/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp
+++ b/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp
@@ -91,6 +91,19 @@ static DecodeStatus DecodeGPRRegisterClass(MCInst &Inst, uint32_t RegNo,
return MCDisassembler::Success;
}
+static DecodeStatus DecodeYGPRRegisterClass(MCInst &Inst, uint32_t RegNo,
+ uint64_t Address,
+ const MCDisassembler *Decoder) {
+ bool IsRVE = Decoder->getSubtargetInfo().hasFeature(RISCV::FeatureStdExtE);
+
+ if (RegNo >= 32 || (IsRVE && RegNo >= 16))
+ return MCDisassembler::Fail;
+
+ MCRegister Reg = RISCV::X0_Y + RegNo;
+ Inst.addOperand(MCOperand::createReg(Reg));
+ return MCDisassembler::Success;
+}
+
static DecodeStatus DecodeGPRF16RegisterClass(MCInst &Inst, uint32_t RegNo,
uint64_t Address,
const MCDisassembler *Decoder) {
@@ -438,6 +451,15 @@ static DecodeStatus DecodeTRM4RegisterClass(MCInst &Inst, uint32_t RegNo,
return MCDisassembler::Success;
}
+static DecodeStatus DecodeYBNDSWImm(MCInst &Inst, uint64_t Imm, int64_t Address,
+ const MCDisassembler *Decoder) {
+ assert(isUInt<10>(Imm) && "Invalid immediate");
+ const uint32_t Shift = Imm >> 8;
+ uint64_t Result = (((Imm & maxUIntN(8)) + 257) << Shift) - 256;
+ Inst.addOperand(MCOperand::createImm(Result));
+ return MCDisassembler::Success;
+}
+
static DecodeStatus decodeVMaskReg(MCInst &Inst, uint32_t RegNo,
uint64_t Address,
const MCDisassembler *Decoder) {
@@ -519,6 +541,20 @@ static DecodeStatus decodeUImmLog2XLenOperand(MCInst &Inst, uint32_t Imm,
return MCDisassembler::Success;
}
+static DecodeStatus decodeUImm7SrliyOperand(MCInst &Inst, uint32_t Imm,
+ int64_t Address,
+ const MCDisassembler *Decoder) {
+ assert(isUInt<7>(Imm) && "Invalid immediate");
+
+ uint32_t ExpectedValue =
+ Decoder->getSubtargetInfo().hasFeature(RISCV::Feature64Bit) ? 64 : 32;
+ if (Imm != ExpectedValue)
+ return MCDisassembler::Fail;
+
+ Inst.addOperand(MCOperand::createImm(Imm));
+ return MCDisassembler::Success;
+}
+
template <unsigned N>
static DecodeStatus decodeUImmNonZeroOperand(MCInst &Inst, uint32_t Imm,
int64_t Address,
@@ -727,6 +763,9 @@ static constexpr DecoderListEntry DecoderList32[]{
{DecoderTableXSMT32, XSMTGroup, "SpacemiT extensions"},
{DecoderTableXAIF32, XAIFGroup, "AI Foundry extensions"},
// Standard Extensions
+ {DecoderTableRVYOnly32,
+ {RISCV::FeatureStdExtY},
+ "RVY-only standard 32-bit instructions"},
{DecoderTable32, {}, "standard 32-bit instructions"},
{DecoderTableRV32Only32, {}, "RV32-only standard 32-bit instructions"},
{DecoderTableZfinx32, {}, "Zfinx (Float in Integer)"},
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h
index cda2f95bbef78..e2b6df1e8c1d5 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h
@@ -380,6 +380,7 @@ enum OperandType : unsigned {
OPERAND_UIMM7,
OPERAND_UIMM7_LSB00,
OPERAND_UIMM7_LSB000,
+ OPERAND_UIMM7_SRLIY,
OPERAND_UIMM8_LSB00,
OPERAND_UIMM8,
OPERAND_UIMM8_LSB000,
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp
index 5cf1f296d4f72..ef40b8b203ca2 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp
@@ -105,6 +105,10 @@ class RISCVMCCodeEmitter : public MCCodeEmitter {
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const;
+ unsigned getYBNDSWImmOpValue(const MCInst &MI, unsigned OpNo,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const;
+
unsigned getVMaskReg(const MCInst &MI, unsigned OpNo,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const;
@@ -730,6 +734,31 @@ uint64_t RISCVMCCodeEmitter::getImmOpValue(const MCInst &MI, unsigned OpNo,
return 0;
}
+unsigned
+RISCVMCCodeEmitter::getYBNDSWImmOpValue(const MCInst &MI, unsigned OpNo,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const {
+ unsigned Imm = getImmOpValue(MI, OpNo, Fixups, STI);
+ // The 10-bit immediate is encoded as `((imm[7:0] + 257) << imm[9:8]) - 256`.
+ if (Imm <= 256) {
+ assert(Imm > 0); // 1, 2, ..., 255, 256
+ return Imm - 1;
+ }
+ if (Imm <= 768) {
+ assert(Imm % 2 == 0); // 258, 260, ..., 766, 768
+ return ((Imm - 258) >> 1) | (1 << 8);
+ }
+ if (Imm <= 1792) {
+ assert(Imm % 4 == 0); // 772, 776, ..., 1788, 1792
+ return ((Imm - 772) >> 2) | (2 << 8);
+ }
+ if (Imm <= 3840) {
+ assert(Imm % 8 == 0); // 1800, 1808, ..., 3832, 3840
+ return ((Imm - 1800) >> 3) | (3 << 8);
+ }
+ llvm_unreachable("Invalid immediate for YBNDSWI");
+}
+
unsigned RISCVMCCodeEmitter::getVMaskReg(const MCInst &MI, unsigned OpNo,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const {
diff --git a/llvm/lib/Target/RISCV/RISCVInstrFormatsY.td b/llvm/lib/Target/RISCV/RISCVInstrFormatsY.td
new file mode 100644
index 0000000000000..cc32d124f515d
--- /dev/null
+++ b/llvm/lib/Target/RISCV/RISCVInstrFormatsY.td
@@ -0,0 +1,77 @@
+//===-- RISCVInstrFormatsY.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 the RISC-V Y extension instruction formats.
+//
+//===----------------------------------------------------------------------===//
+
+//===----------------------------------------------------------------------===//
+// Operand definitions.
+//===----------------------------------------------------------------------===//
+
+def YBNDSWImmOperand : AsmOperandClass {
+ let Name = "YBNDSWImm";
+ let RenderMethod = "addImmOperands";
+ let DiagnosticType = "InvalidYBNDSWImm";
+}
+
+def ybndsw_imm : Operand<XLenVT>, ImmLeaf<XLenVT, [{
+ return (Imm >= 1 && Imm <= 256) ||
+ (Imm >= 258 && Imm <= 768 && (Imm % 2) == 0) ||
+ (Imm >= 772 && Imm <= 1792 && (Imm % 4) == 0) ||
+ (Imm >= 1800 && Imm <= 3840 && (Imm % 8) == 0);
+}]> {
+ let EncoderMethod = "getYBNDSWImmOpValue";
+ let ParserMatchClass = YBNDSWImmOperand;
+ let DecoderMethod = "DecodeYBNDSWImm";
+ let MIOperandInfo = (ops i32imm);
+}
+
+def uimm7_srliy : RISCVUImmOp<7>, ImmLeaf<XLenVT, [{
+ return Subtarget->is64Bit() ? Imm == 64 : Imm == 32;
+}]> {
+ let ParserMatchClass = UImmAsmOperand<7, "Srliy">;
+ let DecoderMethod = "decodeUImm7SrliyOperand";
+ let MCOperandPredicate = [{
+ int64_t Imm;
+ if (!MCOp.evaluateAsConstantImm(Imm))
+ return false;
+ return Subtarget->is64Bit() ? Imm == 64 : Imm == 32;
+ }];
+ let OperandType = "OPERAND_UIMM7_SRLIY";
+}
+
+//===----------------------------------------------------------------------===//
+// Instruction Formats
+//===----------------------------------------------------------------------===//
+
+// Like an RVInstR, except rs2 is now an additional function code.
+class RVYInstSrcDst<bits<7> funct7, bits<5> funct5, bits<3> funct3,
+ RISCVOpcode opcode, dag outs, dag ins, string opcodestr,
+ string argstr>
+ : RVInst<outs, ins, opcodestr, argstr, [], InstFormatR> {
+ bits<5> rs1;
+ bits<5> rd;
+
+ let Inst{31 -25} = funct7;
+ let Inst{24 -20} = funct5;
+ let Inst{19 -15} = rs1;
+ let Inst{14 -12} = funct3;
+ let Inst{11 -7} = rd;
+ let Inst{6 -0} = opcode.Value;
+}
+
+class RVYInstSetBoundsImmFmt<dag outs, dag ins, string opcodestr, string argstr>
+ : RVInstIBase<0b011, OPC_OP_IMM_32, outs, ins, opcodestr, argstr> {
+ bits<5> rd;
+ bits<5> rs1;
+ bits<10> imm;
+
+ let Inst{31 -30} = 0b00;
+ let Inst{29 -20} = imm;
+}
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.td b/llvm/lib/Target/RISCV/RISCVInstrInfo.td
index c7be5b07c33cc..e8e3691564744 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfo.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.td
@@ -2369,6 +2369,9 @@ include "RISCVInstrInfoZicfiss.td"
// Short Forward Branch
include "RISCVInstrInfoSFB.td"
+// CHERI
+include "RISCVInstrInfoY.td"
+
//===----------------------------------------------------------------------===//
// Vendor extensions
//===----------------------------------------------------------------------===//
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoY.td b/llvm/lib/Target/RISCV/RISCVInstrInfoY.td
new file mode 100644
index 0000000000000..08565a6f906e8
--- /dev/null
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoY.td
@@ -0,0 +1,108 @@
+//===-- RISCVInstrInfoY.td - RISCV instructions -------------*- tblgen-*---===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+//===----------------------------------------------------------------------===//
+// Instruction Formats
+//===----------------------------------------------------------------------===//
+
+include "RISCVInstrFormatsY.td"
+
+//===----------------------------------------------------------------------===//
+// Instruction Class Templates
+//===----------------------------------------------------------------------===//
+
+let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in {
+ class RVY_r<bits<5> funct5, string opcodestr, DAGOperand rdOp = GPR,
+ DAGOperand rs1Op = YGPR>
+ : RVYInstSrcDst<0x8, funct5, 0x0, OPC_OP, (outs rdOp:$rd),
+ (ins rs1Op:$rs1), opcodestr, "$rd, $rs1">;
+ class RVY_rr<bits<7> funct7, bits<3> funct3, string opcodestr,
+ DAGOperand rdOp = YGPR, DAGOperand rs1Op = YGPR,
+ DAGOperand rs2Op = GPR>
+ : RVInstR<funct7, funct3, OPC_OP, (outs rdOp:$rd),
+ (ins rs1Op:$rs1, rs2Op:$rs2), opcodestr, "$rd, $rs1, $rs2">;
+ class RVY_ri<bits<3> funct3, RISCVOpcode opcode, string opcodestr,
+ DAGOperand rdOp = YGPR, DAGOperand rs1Op = YGPR>
+ : RVInstI<funct3, opcode, (outs rdOp:$rd),
+ (ins rs1Op:$rs1, simm12_lo:$imm12), opcodestr,
+ "$rd, $rs1, $imm12">;
+ class RVY_setboundsimm<string opcodestr>
+ : RVYInstSetBoundsImmFmt<(outs YGPR:$rd),
+ (ins YGPR:$rs1, ybndsw_imm:$imm), opcodestr,
+ "$rd, $rs1, $imm">;
+} // hasSideEffects = 0, mayLoad = 0, mayStore = 0
+
+let Predicates = [HasStdExtY] in {
+ //
+ // Instructions to Update The Capability Pointer
+ //
+ let isReMaterializable = true, isAsCheapAsAMove = true in {
+ def ADDY : RVY_rr<0x6, 0x0, "addy", YGPR, YGPR, GPRNoX0>;
+ def ADDIY : RVY_ri<0x2, OPC_OP_IMM_32, "addiy">;
+ }
+ def : InstAlias<"addy $rd, $rs1, $imm12",
+ (ADDIY YGPR:$rd, YGPR:$rs1, simm12_lo:$imm12), 0>;
+ def YADDRW : RVY_rr<0x6, 0x1, "yaddrw", YGPR, YGPR, GPR>;
+
+ //
+ // Instructions to Manipulate Capabilities
+ //
+ // TODO: should we support acperm/candperm aliases with inverted mask?
+ def YPERMC : RVY_rr<0x6, 0x2, "ypermc", YGPR, YGPR, GPR>;
+ let hasSideEffects = 0, mayLoad = 0, mayStore = 0, isReMaterializable = true,
+ isAsCheapAsAMove = true, isMoveReg = true in {
+ def YMV : RVYInstSrcDst<0x6, 0x0, 0x0, OPC_OP, (outs YGPR:$rd),
+ (ins YGPR:$rs1), "ymv", "$rd, $rs1">;
+ }
+ def PACKY : RVY_rr<0x6, 0x3, "packy", YGPR, YGPR, GPR>;
+ def : InstAlias<"yhiw $rd, $rs1, $rs2", (PACKY YGPR:$rd, YGPR:$rs1, GPR:$rs2),
+ 0>;
+ def YBNDSW : RVY_rr<0x7, 0x0, "ybndsw", YGPR, YGPR, GPR>;
+ def YBNDSWI : RVY_setboundsimm<"ybndswi">;
+ def : InstAlias<"ybndsw $rd, $rs1, $imm",
+ (YBNDSWI YGPR:$rd, YGPR:$rs1, ybndsw_imm:$imm), 0>;
+ def YBNDSRW : RVY_rr<0x7, 0x1, "ybndsrw", YGPR, YGPR, GPR>;
+ def YSUNSEAL : RVY_rr<0x7, 0x2, "ysunseal", YGPR, YGPR, YGPR>;
+ //
+ // Instructions to Decode Capability Bounds
+ //
+ def YBASER : RVY_r<0x5, "ybaser", GPR, YGPR>;
+ def YLENR : RVY_r<0x6, "ylenr", GPR, YGPR>;
+
+ //
+ // Instructions to Extract Capability Fields
+ //
+ def YTAGR : RVY_r<0x0, "ytagr", GPR, YGPR>;
+ def YPERMR : RVY_r<0x1, "ypermr", GPR, YGPR>;
+ def YTYPER : RVY_r<0x2, "ytyper", GPR, YGPR>;
+ // The SRLIY instruction uses the encoding of SRLI with shamt==XLEN, other
+ // values are not supported. YHIR is a pseudo that expands to the correct
+ // shift value depending on RV32/RV64.
+ let DecoderNamespace = "RVYOnly", hasSideEffects = 0, mayLoad = 0,
+ mayStore = 0 in {
+ def SRLIY : RVInstIBase<0b101, OPC_OP_IMM, (outs GPR:$rd),
+ (ins YGPR:$rs1, uimm7_srliy:$shamt), "srliy",
+ "$rd, $rs1, $shamt"> {
+ bits<7> shamt;
+ let Inst{31 -27} = 0b00000;
+ let Inst{26 -20} = shamt;
+ }
+ }
+ let Predicates = [HasStdExtY, IsRV64] in {
+ def : InstAlias<"yhir $rd, $rs1", (SRLIY GPR:$rd, YGPR:$rs1, 64)>;
+ }
+ let Predicates = [HasStdExtY, IsRV32] in {
+ def : InstAlias<"yhir $rd, $rs1", (SRLIY GPR:$rd, YGPR:$rs1, 32)>;
+ }
+ //
+ // Miscellaneous Instructions to Handle Capability Data
+ //
+ 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>;
+} // Predicates = [HasStdExtY]
diff --git a/llvm/test/MC/RISCV/rvy/rvy-invalid-mode-independent.s b/llvm/test/MC/RISCV/rvy/rvy-invalid-mode-independent.s
new file mode 100644
index 0000000000000..608becf94983e
--- /dev/null
+++ b/llvm/test/MC/RISCV/rvy/rvy-invalid-mode-independent.s
@@ -0,0 +1,42 @@
+# RUN: not llvm-mc --triple riscv32 --mattr=+experimental-y <%s 2>&1 \
+# RUN: | FileCheck %s --check-prefixes=CHECK,CHECK-32 '--implicit-check-not=error:'
+# RUN: not llvm-mc --triple riscv64 --mattr=+experimental-y <%s 2>&1 \
+# RUN: | FileCheck %s --check-prefixes=CHECK,CHECK-64 '--implicit-check-not=error:'
+
+addy a0, a1, zero
+# CHECK: <stdin>:[[#@LINE-1]]:14: error: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo specifier or an integer in the range [-2048, 2047]
+addy a0, a1, x0
+# CHECK: <stdin>:[[#@LINE-1]]:14: error: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo specifier or an integer in the range [-2048, 2047]
+srliy a0, a1, 65
+# CHECK-32: <stdin>:[[#@LINE-1]]:15: error: immediate must be an integer equal to XLEN (32)
+# CHECK-64: <stdin>:[[#@LINE-2]]:15: error: immediate must be an integer equal to XLEN (64)
+srliy a0, a1, 64
+# CHECK-32: <stdin>:[[#@LINE-1]]:15: error: immediate must be an integer equal to XLEN (32)
+srliy a0, a1, 32
+# CHECK-64: <stdin>:[[#@LINE-1]]:15: error: immediate must be an integer equal to XLEN (64)
+ybndswi a0, a0, 0
+# CHECK: <stdin>:[[#@LINE-1]]:17: error: immediate must be an integer in the range [1, 256], a multiple of 2 in the range [258, 768], a multiple of 4 in the range [772, 1792], or a multiple of 8 in the range [1800, 3840]
+ybndswi a0, a0, 257
+# CHECK: <stdin>:[[#@LINE-1]]:17: error: immediate must be an integer in the range [1, 256], a multiple of 2 in the range [258, 768], a multiple of 4 in the range [772, 1792], or a multiple of 8 in the range [1800, 3840]
+ybndswi a0, a0, 259
+# CHECK: <stdin>:[[#@LINE-1]]:17: error: immediate must be an integer in the range [1, 256], a multiple of 2 in the range [258, 768], a multiple of 4 in the range [772, 1792], or a multiple of 8 i...
[truncated]
|
| // Standard Extensions | ||
| {DecoderTableRVYOnly32, | ||
| {RISCV::FeatureStdExtY}, | ||
| "RVY-only standard 32-bit instructions"}, |
There was a problem hiding this comment.
Why do we need a decoder namespace? They shouldn't conflict with other standard extensions.
There was a problem hiding this comment.
I agree we should not conflict with anything, but it was needed for SRLIY (aka YHIR) which technically overlaps with RV64-SRLI for RV32Y. Not sure if there is a more elegant way to solve this?
// The SRLIY instruction uses the encoding of SRLI with shamt==XLEN, other
// values are not supported. YHIR is a pseudo that expands to the correct
// shift value depending on RV32/RV64.
let DecoderNamespace = "RVYOnly", hasSideEffects = 0, mayLoad = 0,
mayStore = 0 in {
def SRLIY : RVInstIBase<0b101, OPC_OP_IMM, (outs GPR:$rd),
(ins YGPR:$rs1, uimm7_srliy:$shamt), "srliy",
"$rd, $rs1, $shamt"> {
bits<7> shamt;
let Inst{31 -27} = 0b00000;
let Inst{26 -20} = shamt;
}
}
let Predicates = [HasStdExtY, IsRV64] in {
def : InstAlias<"yhir $rd, $rs1", (SRLIY GPR:$rd, YGPR:$rs1, 64)>;
}
let Predicates = [HasStdExtY, IsRV32] in {
def : InstAlias<"yhir $rd, $rs1", (SRLIY GPR:$rd, YGPR:$rs1, 32)>;
}
There was a problem hiding this comment.
There's the RV32Only32 namespace already
There was a problem hiding this comment.
Unfortunately RV32Only32 one won't work since SRLI claims the full immediate field for both 32 and 64-bit. I guess we could do something like use EncodingByHwMode for SRLI and SRLIY so that SRLIY claims immediates > XLEN, but I'm not sure if that is better or worse than the namespace?
There was a problem hiding this comment.
Did you try it? I don't think we check for RV32 before using RV32Only32.
As far as I know, EncodingByHwMode duplicates the entire disassembler table for every HwMode which sounds expensive for 1 instruction.
There was a problem hiding this comment.
It looks like this namespace is no longer needed. I started working on this probably around 3-4 months ago, so it's possible it predates the recent tablegen decoder changes.
There was a problem hiding this comment.
Seems like I spoke too soon. Tablegen no longer complains, but we are now unable to disassemble the instruction. Will try to debug this a bit more today.
There was a problem hiding this comment.
New workaround: split it into SRLIY64 and SRLIY32 which now has fixed bits in these positions so the decoder checks them before checking SRLI:
5, 132, 1, // 2089: case 0x5: {
OPC_SwitchField, 26, 6, // 2092: switch Inst[31:26] {
0, 16, // 2095: case 0x0: {
OPC_Scope, 10, // 2097: try {
OPC_CheckField, 20, 6, 32, // 2099: check Inst[25:20] == 0x20
OPC_CheckPredicate, 41, // 2103: check predicate 41
OPC_Decode, 244, 123, 18, // 2105: decode to SRLIY32 using decoder 18
// 2105: } else try {
OPC_Decode, 242, 123, 15, // 2109: decode to SRLI using decoder 15
// 2109: }
// 2109: }
1, 10, // 2113: case 0x1: {
OPC_CheckPredicate, 42, // 2115: check predicate 42
OPC_CheckField, 20, 6, 0, // 2117: check Inst[25:20] == 0x0
OPC_Decode, 245, 123, 19, // 2121: decode to SRLIY64 using decoder 19
// 2121: }
| def ADDY : RVY_rr<0x6, 0x0, "addy", YGPR, YGPR, GPRNoX0>; | ||
| def ADDIY : RVY_ri<0x2, OPC_OP_IMM_32, "addiy">; | ||
| } | ||
| def : InstAlias<"addy $rd, $rs1, $imm12", |
There was a problem hiding this comment.
Can we group the aliases separately from the actual instructions?
There was a problem hiding this comment.
Sure happy to make that change, I just thought keeping them grouped together would make sense since they all share the same Predicate.
| // | ||
| let isReMaterializable = true, isAsCheapAsAMove = true in { | ||
| def ADDY : RVY_rr<0x6, 0x0, "addy", YGPR, YGPR, GPRNoX0>; | ||
| def ADDIY : RVY_ri<0x2, OPC_OP_IMM_32, "addiy">; |
There was a problem hiding this comment.
According to the spec this conflicts with P. Is tablegen just not catching this because P also specifies specific values in some of bits 31-20?
There was a problem hiding this comment.
I don't understand why tablegen is not complaining about this one.
CADDI use OP-IMM-32 encoding space with [14:12] == 010, which based on looking at https://www.jhauser.us/RISCV/ext-P/RVP-instrEncodings-018.pdf should definitely overlap with all uses of RVPUnary_ri.
There was a problem hiding this comment.
This encoding will change for 1.0 (or RVP is moved), so it will only be a temporary encoding conflict.
There was a problem hiding this comment.
I don't understand why tablegen is not complaining about this one. CADDI use OP-IMM-32 encoding space with [14:12] == 010, which based on looking at https://www.jhauser.us/RISCV/ext-P/RVP-instrEncodings-018.pdf should definitely overlap with all uses of RVPUnary_ri.
Tablegen may be conservatively assuming that not all values of the 12-bit immediate for ADDIY are legal. Since P instructions specifies fixed values for some of those bits, I think it just orders the P extension instructions first. Not sure if it will fallthrough to decode ADDIY if the P predicate check fails. Or if the P predicate check will fail the decode. I'll check if you're testing a conflicting case.
There was a problem hiding this comment.
I just looked at the generated table and it looks like we now check all instructions with some bit positions fixed first and the fall back to one with a wildcard. So if you mix P and Y you would get some P instructions in the disassembly stream. Is this okay for the initial version or should I mark P as conflicting?
There was a problem hiding this comment.
I just looked at the generated table and it looks like we now check all instructions with some bit positions fixed first and the fall back to one with a wildcard. So if you mix P and Y you would get some P instructions in the disassembly stream. Is this okay for the initial version or should I mark P as conflicting?
I think it's ok for the initial version.
There was a problem hiding this comment.
I think conflicts are only detected when two instructions have a wildcard bit at the same position, not when one has a fixed bit and the other has a wildcard bit (it's assumed the one with the fixed bit is the more specific decode and used).
We rely on this behaviour in a bunch of places, where we have GPRNoX0 fields (5 bits, all wildcard), and reuse the 0b00000 encoding for another instruction. In these cases, we are getting the correct behaviour.
For more complex cases, we should be setting hasCompleteDecoder = false, so that the decoder can try several operand/instruction decoders and the failure of the first decoder is not treated as a failure of decoding, it will continue trying the rest.
There was a problem hiding this comment.
(It's not clear, however, that this is a case where hasCompleteDecoder = false would actually "fix" something. There are more notes on the comment about hasCompleteDecoder in Target.td)
|
This is a stacked pull request managed by spr. The following pull requests must be merged before this one: |
🐧 Linux x64 Test Results
✅ The build succeeded and all tests passed. |
🪟 Windows x64 Test Results
✅ The build succeeded and all tests passed. |
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
Cmake does not properly parse IN_LIST within the if condition, and treats it as a token. This is not desired behavior. The CMP0057 policy supports the new [if() IN_LIST ](https://cmake.org/cmake/help/latest/command/if.html#command:if) operator. Enable this policy and resolve the build error. Fixes #199282 Assisted by: Github Copilot
In the GFX950 documentation, some instructions that should have the _sdwa suffix were incorrectly given the _dpp suffix.
…ertAll*/) (#197289) In the context of nested checkpoints the tracker's API was somewhat inconsistent. Tracker::revert() would revert to the last checkpoint but accept() would accept all changes. This patch fixes this, and introduces `accept(bool AcceptAll)` and `revert(bool RevertAll)`.
When tryToVectorize is called with AllowFMACandidates=true, falling through to tryToVectorizeList vectorizes the fmul operands of an FMA-candidate fadd without accounting for the lost FMA opportunity. canConvertToFMA requires those fmuls to have one use, so vectorizing them always breaks FMA formation. The cost model for tryToVectorizeList omits the fadd from the tree and compares "2 fmuls vs 1 vfmul", missing the scalar FMA savings entirely. Block tryToVectorizeList when AllowFMACandidates=true. TryToReduce is safe because computeReductionCost accounts for FMA in the scalar baseline via canConvertToFMA on the fadd user. Fixes a 4.5% regression in SPEC17 imagemagick on AArch64 introduced by Reviewers: sushgokh, bababuck Pull Request: #199706
…7620) The second argument to `__builtin_arm_irg()` and `__builtin_arm_gmi()` is expected to be 64-bit. When a wider type is passed, the compiler still generates a `zext` instruction, leading to a backend error: ``` > cat test.c unsigned test(void* a, unsigned __int128 m) { return __builtin_arm_gmi(a, m); } > clang -target aarch64 -march=armv9+memtag -S test.c fatal error: error in backend: Cannot select: ... i64,ch = load<... zext from i128> ``` This is fixed by applying the required implicit conversions to the argument in Sema.
This does not implement CSR spills other than those AMDGPU handles during PEI. The remaining spills are handled in a subsequent patch. Change-Id: I5e3a9a62cf9189245011a82a129790d813d49373 Co-authored-by: Scott Linder <scott.linder@amd.com> Co-authored-by: Venkata Ramanaiah Nalamothu <VenkataRamanaiah.Nalamothu@amd.com>
This adds MC-level support for most of the base Y extension instructions using version 0.9.8.1 of the specification. This initial pull request is restricted to the execution-mode-independent subset. The Y extension (CHERI for RISC-V) also introduces an execution mode that determines whether certain register operands use the full extended register or only the address subset (the current XLEN registers). The instructions that depend on execution mode (loads/stores/jumps + AUIPC) will be added in the following commits in this stack of changes. Specification: https://github.com/riscv/riscv-cheri/releases/tag/v0.9.8.1 Co-authored-by: Jessica Clarke <jrtc27@jrtc27.com> Co-authored-by: Alexander Richardson <alexrichardson@google.com> Co-authored-by: Petr Vesely <petr.vesely@codasip.com> Pull Request: llvm#176871
Created using spr 1.3.8-beta.1
| timeout-minutes: 60 | ||
| runs-on: ${{ matrix.os }} | ||
| container: | ||
| image: ${{ (startsWith(matrix.os, 'ubuntu-24.04-arm') && 'ghcr.io/llvm/arm64v8/libc-ubuntu-24.04') || 'ghcr.io/llvm/libc-ubuntu-24.04'}} |
| timeout-minutes: 60 | ||
| runs-on: ${{ matrix.os }} | ||
| container: | ||
| image: ${{ (startsWith(matrix.os, 'ubuntu-24.04-arm') && 'ghcr.io/llvm/arm64v8/libc-ubuntu-24.04') || 'ghcr.io/llvm/libc-ubuntu-24.04'}} |
| git config user.name "llvmbot" | ||
| git commit -a -m "Add ${{ inputs.release-version }} documentation" | ||
| git push --force "https://$GH_TOKEN@github.com/llvmbot/www-releases.git" HEAD:refs/heads/${{ inputs.release-version }} | ||
| git push --force "https://$PUSH_TOKEN@github.com/llvmbot/www-releases.git" HEAD:refs/heads/${{ inputs.release-version }} |
| git config user.name "llvmbot" | ||
| git commit -a -m "Add ${{ inputs.release-version }} documentation" | ||
| git push --force "https://$GH_TOKEN@github.com/llvmbot/www-releases.git" HEAD:refs/heads/${{ inputs.release-version }} | ||
| git push --force "https://$PUSH_TOKEN@github.com/llvmbot/www-releases.git" HEAD:refs/heads/${{ inputs.release-version }} |
| fi | ||
|
|
||
| cmake \ | ||
| --build ${{ steps.strings.outputs.build-output-dir }} \ |
| repo = github.Github(auth=github.Auth.Token("${{ github.token }}")).get_repo("${{ github.repository }}") | ||
| pr = repo.get_pull(${{ github.event.issue.number }}) | ||
| comment = pr.get_issue_comment(${{ github.event.comment.id }}) | ||
| add_text = "> _Running benchmarks in ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}/job/${{ job.check_run_id }}_" |
| source .venv/bin/activate && cd repo | ||
| ./libcxx/utils/test-at-commit --commit ${{ steps.vars.outputs.pr_head }} -B build/candidate -- -sv -j1 --param optimization=speed "$BENCHMARKS" | ||
| ./libcxx/utils/consolidate-benchmarks build/candidate | tee candidate.lnt | ||
| ./libcxx/utils/build-at-commit --commit ${{ steps.vars.outputs.pr_head }} --install-dir install/candidate -- -DCMAKE_BUILD_TYPE=RelWithDebInfo |
|
Apologies for the spam here, it seems like SPR got confused by the branch being deleted. I'll create a new PR. |
This adds MC-level support for most of the base Y extension instructions
using version 0.9.8.2 of the specification. This initial pull request is
restricted to the execution-mode-independent subset. The Y extension
(CHERI for RISC-V) also introduces an execution mode that determines
whether certain register operands use the full extended register or only
the address subset (the current XLEN registers). The instructions that
depend on execution mode (loads/stores/jumps + AUIPC) will be added in
the following commits in this stack of changes.
Specification: https://github.com/riscv/riscv-cheri/releases/tag/v0.9.8.1
Co-authored-by: Jessica Clarke jrtc27@jrtc27.com
Co-authored-by: Alexander Richardson alexrichardson@google.com
Co-authored-by: Petr Vesely petr.vesely@codasip.com