Skip to content

Commit

Permalink
[AMDGPU][MC] Support UC_VERSION_* constants. (llvm#95618)
Browse files Browse the repository at this point in the history
Our other tools support them, so we want them in LLVM
assembler/disassembler too.
  • Loading branch information
kosarev authored Jun 18, 2024
1 parent 8052e94 commit 1623866
Show file tree
Hide file tree
Showing 12 changed files with 179 additions and 32 deletions.
4 changes: 3 additions & 1 deletion llvm/lib/Target/AMDGPU/AMDGPUInstructions.td
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,9 @@ class ImmOperand<ValueType type, string name = NAME, bit optional = 0,
let PrintMethod = printer;
}

def s16imm : ImmOperand<i16, "S16Imm", 0, "printU16ImmOperand">;
class S16ImmOperand : ImmOperand<i16, "S16Imm", 0, "printU16ImmOperand">;

def s16imm : S16ImmOperand;
def u16imm : ImmOperand<i16, "U16Imm", 0, "printU16ImmOperand">;

class ValuePredicatedOperand<CustomOperand op, string valuePredicate,
Expand Down
62 changes: 33 additions & 29 deletions llvm/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1314,6 +1314,8 @@ class AMDGPUAsmParser : public MCTargetAsmParser {
/// }

private:
void createConstantSymbol(StringRef Id, int64_t Val);

bool ParseAsAbsoluteExpression(uint32_t &Ret);
bool OutOfRangeError(SMRange Range);
/// Calculate VGPR/SGPR blocks required for given target, reserved
Expand Down Expand Up @@ -1408,36 +1410,28 @@ class AMDGPUAsmParser : public MCTargetAsmParser {

setAvailableFeatures(ComputeAvailableFeatures(getFeatureBits()));

{
// TODO: make those pre-defined variables read-only.
// Currently there is none suitable machinery in the core llvm-mc for this.
// MCSymbol::isRedefinable is intended for another purpose, and
// AsmParser::parseDirectiveSet() cannot be specialized for specific target.
AMDGPU::IsaVersion ISA = AMDGPU::getIsaVersion(getSTI().getCPU());
MCContext &Ctx = getContext();
if (ISA.Major >= 6 && isHsaAbi(getSTI())) {
MCSymbol *Sym =
Ctx.getOrCreateSymbol(Twine(".amdgcn.gfx_generation_number"));
Sym->setVariableValue(MCConstantExpr::create(ISA.Major, Ctx));
Sym = Ctx.getOrCreateSymbol(Twine(".amdgcn.gfx_generation_minor"));
Sym->setVariableValue(MCConstantExpr::create(ISA.Minor, Ctx));
Sym = Ctx.getOrCreateSymbol(Twine(".amdgcn.gfx_generation_stepping"));
Sym->setVariableValue(MCConstantExpr::create(ISA.Stepping, Ctx));
} else {
MCSymbol *Sym =
Ctx.getOrCreateSymbol(Twine(".option.machine_version_major"));
Sym->setVariableValue(MCConstantExpr::create(ISA.Major, Ctx));
Sym = Ctx.getOrCreateSymbol(Twine(".option.machine_version_minor"));
Sym->setVariableValue(MCConstantExpr::create(ISA.Minor, Ctx));
Sym = Ctx.getOrCreateSymbol(Twine(".option.machine_version_stepping"));
Sym->setVariableValue(MCConstantExpr::create(ISA.Stepping, Ctx));
}
if (ISA.Major >= 6 && isHsaAbi(getSTI())) {
initializeGprCountSymbol(IS_VGPR);
initializeGprCountSymbol(IS_SGPR);
} else
KernelScope.initialize(getContext());
AMDGPU::IsaVersion ISA = AMDGPU::getIsaVersion(getSTI().getCPU());
if (ISA.Major >= 6 && isHsaAbi(getSTI())) {
createConstantSymbol(".amdgcn.gfx_generation_number", ISA.Major);
createConstantSymbol(".amdgcn.gfx_generation_minor", ISA.Minor);
createConstantSymbol(".amdgcn.gfx_generation_stepping", ISA.Stepping);
} else {
createConstantSymbol(".option.machine_version_major", ISA.Major);
createConstantSymbol(".option.machine_version_minor", ISA.Minor);
createConstantSymbol(".option.machine_version_stepping", ISA.Stepping);
}
if (ISA.Major >= 6 && isHsaAbi(getSTI())) {
initializeGprCountSymbol(IS_VGPR);
initializeGprCountSymbol(IS_SGPR);
} else
KernelScope.initialize(getContext());

for (auto [Symbol, Code] : AMDGPU::UCVersion::getGFXVersions())
createConstantSymbol(Symbol, Code);

createConstantSymbol("UC_VERSION_W64_BIT", 0x2000);
createConstantSymbol("UC_VERSION_W32_BIT", 0x4000);
createConstantSymbol("UC_VERSION_MDP_BIT", 0x8000);
}

bool hasMIMG_R128() const {
Expand Down Expand Up @@ -2486,6 +2480,16 @@ bool AMDGPUOperand::isInlineValue() const {
// AsmParser
//===----------------------------------------------------------------------===//

void AMDGPUAsmParser::createConstantSymbol(StringRef Id, int64_t Val) {
// TODO: make those pre-defined variables read-only.
// Currently there is none suitable machinery in the core llvm-mc for this.
// MCSymbol::isRedefinable is intended for another purpose, and
// AsmParser::parseDirectiveSet() cannot be specialized for specific target.
MCContext &Ctx = getContext();
MCSymbol *Sym = Ctx.getOrCreateSymbol(Id);
Sym->setVariableValue(MCConstantExpr::create(Val, Ctx));
}

static int getRegClass(RegisterKind Is, unsigned RegWidth) {
if (Is == IS_VGPR) {
switch (RegWidth) {
Expand Down
59 changes: 59 additions & 0 deletions llvm/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "SIDefines.h"
#include "SIRegisterInfo.h"
#include "TargetInfo/AMDGPUTargetInfo.h"
#include "Utils/AMDGPUAsmUtils.h"
#include "Utils/AMDGPUBaseInfo.h"
#include "llvm-c/DisassemblerTypes.h"
#include "llvm/BinaryFormat/ELF.h"
Expand Down Expand Up @@ -52,6 +53,13 @@ AMDGPUDisassembler::AMDGPUDisassembler(const MCSubtargetInfo &STI,
// ToDo: AMDGPUDisassembler supports only VI ISA.
if (!STI.hasFeature(AMDGPU::FeatureGCN3Encoding) && !isGFX10Plus())
report_fatal_error("Disassembly not yet supported for subtarget");

for (auto [Symbol, Code] : AMDGPU::UCVersion::getGFXVersions())
createConstantSymbolExpr(Symbol, Code);

UCVersionW64Expr = createConstantSymbolExpr("UC_VERSION_W64_BIT", 0x2000);
UCVersionW32Expr = createConstantSymbolExpr("UC_VERSION_W32_BIT", 0x4000);
UCVersionMDPExpr = createConstantSymbolExpr("UC_VERSION_MDP_BIT", 0x8000);
}

void AMDGPUDisassembler::setABIVersion(unsigned Version) {
Expand Down Expand Up @@ -421,6 +429,13 @@ DECODE_SDWA(Src32)
DECODE_SDWA(Src16)
DECODE_SDWA(VopcDst)

static DecodeStatus decodeVersionImm(MCInst &Inst, unsigned Imm,
uint64_t /* Addr */,
const MCDisassembler *Decoder) {
auto DAsm = static_cast<const AMDGPUDisassembler *>(Decoder);
return addOperand(Inst, DAsm->decodeVersionImm(Imm));
}

#include "AMDGPUGenDisassemblerTables.inc"

//===----------------------------------------------------------------------===//
Expand Down Expand Up @@ -1727,6 +1742,41 @@ MCOperand AMDGPUDisassembler::decodeDpp8FI(unsigned Val) const {
return MCOperand::createImm(Val);
}

MCOperand AMDGPUDisassembler::decodeVersionImm(unsigned Imm) const {
using VersionField = AMDGPU::EncodingField<7, 0>;
using W64Bit = AMDGPU::EncodingBit<13>;
using W32Bit = AMDGPU::EncodingBit<14>;
using MDPBit = AMDGPU::EncodingBit<15>;
using Encoding = AMDGPU::EncodingFields<VersionField, W64Bit, W32Bit, MDPBit>;

auto [Version, W64, W32, MDP] = Encoding::decode(Imm);

// Decode into a plain immediate if any unused bits are raised.
if (Encoding::encode(Version, W64, W32, MDP) != Imm)
return MCOperand::createImm(Imm);

const auto &Versions = AMDGPU::UCVersion::getGFXVersions();
auto I = find_if(Versions,
[Version = Version](const AMDGPU::UCVersion::GFXVersion &V) {
return V.Code == Version;
});
MCContext &Ctx = getContext();
const MCExpr *E;
if (I == Versions.end())
E = MCConstantExpr::create(Version, Ctx);
else
E = MCSymbolRefExpr::create(Ctx.getOrCreateSymbol(I->Symbol), Ctx);

if (W64)
E = MCBinaryExpr::createOr(E, UCVersionW64Expr, Ctx);
if (W32)
E = MCBinaryExpr::createOr(E, UCVersionW32Expr, Ctx);
if (MDP)
E = MCBinaryExpr::createOr(E, UCVersionMDPExpr, Ctx);

return MCOperand::createExpr(E);
}

bool AMDGPUDisassembler::isVI() const {
return STI.hasFeature(AMDGPU::FeatureVolcanicIslands);
}
Expand Down Expand Up @@ -2312,6 +2362,15 @@ Expected<bool> AMDGPUDisassembler::onSymbolStart(SymbolInfoTy &Symbol,
return false;
}

const MCExpr *AMDGPUDisassembler::createConstantSymbolExpr(StringRef Id,
int64_t Val) {
MCContext &Ctx = getContext();
MCSymbol *Sym = Ctx.getOrCreateSymbol(Id);
assert(!Sym->isVariable());
Sym->setVariableValue(MCConstantExpr::create(Val, Ctx));
return MCSymbolRefExpr::create(Sym, Ctx);
}

//===----------------------------------------------------------------------===//
// AMDGPUSymbolizer
//===----------------------------------------------------------------------===//
Expand Down
7 changes: 7 additions & 0 deletions llvm/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,11 @@ class AMDGPUDisassembler : public MCDisassembler {
mutable bool HasLiteral;
mutable std::optional<bool> EnableWavefrontSize32;
unsigned CodeObjectVersion;
const MCExpr *UCVersionW64Expr;
const MCExpr *UCVersionW32Expr;
const MCExpr *UCVersionMDPExpr;

const MCExpr *createConstantSymbolExpr(StringRef Id, int64_t Val);

public:
AMDGPUDisassembler(const MCSubtargetInfo &STI, MCContext &Ctx,
Expand Down Expand Up @@ -264,6 +269,8 @@ class AMDGPUDisassembler : public MCDisassembler {
MCOperand decodeSplitBarrier(unsigned Val) const;
MCOperand decodeDpp8FI(unsigned Val) const;

MCOperand decodeVersionImm(unsigned Imm) const;

int getTTmpIdx(unsigned Val) const;

const MCInstrInfo *getMCII() const { return MCII.get(); }
Expand Down
8 changes: 7 additions & 1 deletion llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUInstPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,15 @@ void AMDGPUInstPrinter::printU4ImmOperand(const MCInst *MI, unsigned OpNo,
void AMDGPUInstPrinter::printU16ImmOperand(const MCInst *MI, unsigned OpNo,
const MCSubtargetInfo &STI,
raw_ostream &O) {
const MCOperand &Op = MI->getOperand(OpNo);
if (Op.isExpr()) {
Op.getExpr()->print(O, &MAI);
return;
}

// It's possible to end up with a 32-bit literal used with a 16-bit operand
// with ignored high bits. Print as 32-bit anyway in that case.
int64_t Imm = MI->getOperand(OpNo).getImm();
int64_t Imm = Op.getImm();
if (isInt<16>(Imm) || isUInt<16>(Imm))
O << formatHex(static_cast<uint64_t>(Imm & 0xffff));
else
Expand Down
5 changes: 5 additions & 0 deletions llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUMCCodeEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -662,6 +662,11 @@ void AMDGPUMCCodeEmitter::getMachineOpValueT16Lo128(
void AMDGPUMCCodeEmitter::getMachineOpValueCommon(
const MCInst &MI, const MCOperand &MO, unsigned OpNo, APInt &Op,
SmallVectorImpl<MCFixup> &Fixups, const MCSubtargetInfo &STI) const {
int64_t Val;
if (MO.isExpr() && MO.getExpr()->evaluateAsAbsolute(Val)) {
Op = Val;
return;
}

if (MO.isExpr() && MO.getExpr()->getKind() != MCExpr::Constant) {
// FIXME: If this is expression is PCRel or not should not depend on what
Expand Down
6 changes: 5 additions & 1 deletion llvm/lib/Target/AMDGPU/SOPInstructions.td
Original file line number Diff line number Diff line change
Expand Up @@ -1196,11 +1196,15 @@ let SubtargetPredicate = isGFX9Plus in {
}
} // End SubtargetPredicate = isGFX9Plus

def VersionImm : S16ImmOperand {
let DecoderMethod = "decodeVersionImm";
}

let SubtargetPredicate = isGFX10Plus in {
def S_VERSION : SOPK_Pseudo<
"s_version",
(outs),
(ins s16imm:$simm16),
(ins VersionImm:$simm16),
"$simm16"> {
let has_sdst = 0;
}
Expand Down
15 changes: 15 additions & 0 deletions llvm/lib/Target/AMDGPU/Utils/AMDGPUAsmUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -669,5 +669,20 @@ const char* const IdSymbolic[] = {

} // namespace VGPRIndexMode

namespace UCVersion {

ArrayRef<GFXVersion> getGFXVersions() {
// GFX6, GFX8 and GFX9 don't support s_version and there are no
// UC_VERSION_GFX* codes for them.
static const GFXVersion Versions[] = {{"UC_VERSION_GFX7", 0},
{"UC_VERSION_GFX10", 4},
{"UC_VERSION_GFX11", 6},
{"UC_VERSION_GFX12", 9}};

return Versions;
}

} // namespace UCVersion

} // namespace AMDGPU
} // namespace llvm
11 changes: 11 additions & 0 deletions llvm/lib/Target/AMDGPU/Utils/AMDGPUAsmUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,17 @@ extern const char* const IdSymbolic[];

} // namespace VGPRIndexMode

namespace UCVersion {

struct GFXVersion {
StringLiteral Symbol;
unsigned Code;
};

ArrayRef<GFXVersion> getGFXVersions();

} // namespace UCVersion

} // namespace AMDGPU
} // namespace llvm

Expand Down
4 changes: 4 additions & 0 deletions llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,10 @@ struct EncodingField {
static ValueType decode(uint64_t Encoded) { return Encoded; }
};

// Represents a single bit in an encoded value.
template <unsigned Bit, unsigned D = 0>
using EncodingBit = EncodingField<Bit, Bit, D>;

// A helper for encoding and decoding multiple fields.
template <typename... Fields> struct EncodingFields {
static constexpr uint64_t encode(Fields... Values) {
Expand Down
15 changes: 15 additions & 0 deletions llvm/test/MC/AMDGPU/gfx12_asm_sopk.s
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,21 @@ s_version 0x1234
s_version 0xc1d1
// GFX12: encoding: [0xd1,0xc1,0x80,0xb0]

s_version UC_VERSION_GFX12
// GFX12: encoding: [0x09,0x00,0x80,0xb0]

s_version UC_VERSION_GFX12 | UC_VERSION_W32_BIT
// GFX12: encoding: [0x09,0x40,0x80,0xb0]

s_version UC_VERSION_GFX12 | UC_VERSION_W64_BIT
// GFX12: encoding: [0x09,0x20,0x80,0xb0]

s_version UC_VERSION_GFX12 | UC_VERSION_MDP_BIT
// GFX12: encoding: [0x09,0x80,0x80,0xb0]

s_version UC_VERSION_GFX12 | UC_VERSION_W64_BIT | UC_VERSION_MDP_BIT
// GFX12: encoding: [0x09,0xa0,0x80,0xb0]

s_cmovk_i32 s0, 0x1234
// GFX12: encoding: [0x34,0x12,0x00,0xb1]

Expand Down
15 changes: 15 additions & 0 deletions llvm/test/MC/Disassembler/AMDGPU/gfx12_dasm_sopk.txt
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,21 @@
# GFX12: s_version 0xc1d1 ; encoding: [0xd1,0xc1,0x80,0xb0]
0xd1,0xc1,0x80,0xb0

# GFX12: s_version UC_VERSION_GFX12 ; encoding: [0x09,0x00,0x80,0xb0]
0x09,0x00,0x80,0xb0

# GFX12: s_version UC_VERSION_GFX12|UC_VERSION_W32_BIT ; encoding: [0x09,0x40,0x80,0xb0]
0x09,0x40,0x80,0xb0

# GFX12: s_version UC_VERSION_GFX12|UC_VERSION_W64_BIT ; encoding: [0x09,0x20,0x80,0xb0]
0x09,0x20,0x80,0xb0

# GFX12: s_version UC_VERSION_GFX12|UC_VERSION_MDP_BIT ; encoding: [0x09,0x80,0x80,0xb0]
0x09,0x80,0x80,0xb0

# GFX12: s_version ((128|UC_VERSION_W64_BIT)|UC_VERSION_W32_BIT)|UC_VERSION_MDP_BIT ; encoding: [0x80,0xe0,0x80,0xb0]
0x80,0xe0,0x80,0xb0

# GFX12: s_setreg_imm32_b32 hwreg(HW_REG_MODE), 0xaf123456 ; encoding: [0x01,0xf8,0x80,0xb9,0x56,0x34,0x12,0xaf]
0x01,0xf8,0x80,0xb9,0x56,0x34,0x12,0xaf

Expand Down

0 comments on commit 1623866

Please sign in to comment.