From 162386693f663b3d0aa5403a45bfbc8edc3a84ed Mon Sep 17 00:00:00 2001 From: Ivan Kosarev Date: Tue, 18 Jun 2024 17:44:14 +0300 Subject: [AMDGPU][MC] Support UC_VERSION_* constants. (#95618) Our other tools support them, so we want them in LLVM assembler/disassembler too. --- llvm/lib/Target/AMDGPU/AMDGPUInstructions.td | 4 +- .../Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp | 62 ++++++++++++---------- .../AMDGPU/Disassembler/AMDGPUDisassembler.cpp | 59 ++++++++++++++++++++ .../AMDGPU/Disassembler/AMDGPUDisassembler.h | 7 +++ .../AMDGPU/MCTargetDesc/AMDGPUInstPrinter.cpp | 8 ++- .../AMDGPU/MCTargetDesc/AMDGPUMCCodeEmitter.cpp | 5 ++ llvm/lib/Target/AMDGPU/SOPInstructions.td | 6 ++- llvm/lib/Target/AMDGPU/Utils/AMDGPUAsmUtils.cpp | 15 ++++++ llvm/lib/Target/AMDGPU/Utils/AMDGPUAsmUtils.h | 11 ++++ llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.h | 4 ++ llvm/test/MC/AMDGPU/gfx12_asm_sopk.s | 15 ++++++ .../MC/Disassembler/AMDGPU/gfx12_dasm_sopk.txt | 15 ++++++ 12 files changed, 179 insertions(+), 32 deletions(-) diff --git a/llvm/lib/Target/AMDGPU/AMDGPUInstructions.td b/llvm/lib/Target/AMDGPU/AMDGPUInstructions.td index 65439f2..ebc6402 100644 --- a/llvm/lib/Target/AMDGPU/AMDGPUInstructions.td +++ b/llvm/lib/Target/AMDGPU/AMDGPUInstructions.td @@ -140,7 +140,9 @@ class ImmOperand; +class S16ImmOperand : ImmOperand; + +def s16imm : S16ImmOperand; def u16imm : ImmOperand; class ValuePredicatedOperand= 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 { @@ -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) { diff --git a/llvm/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.cpp b/llvm/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.cpp index 05063c6c..76a559c 100644 --- a/llvm/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.cpp +++ b/llvm/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.cpp @@ -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" @@ -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) { @@ -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(Decoder); + return addOperand(Inst, DAsm->decodeVersionImm(Imm)); +} + #include "AMDGPUGenDisassemblerTables.inc" //===----------------------------------------------------------------------===// @@ -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; + + 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); } @@ -2312,6 +2362,15 @@ Expected 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 //===----------------------------------------------------------------------===// diff --git a/llvm/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.h b/llvm/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.h index 2061d83..694cd7a 100644 --- a/llvm/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.h +++ b/llvm/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.h @@ -102,6 +102,11 @@ private: mutable bool HasLiteral; mutable std::optional 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, @@ -264,6 +269,8 @@ public: 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(); } diff --git a/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUInstPrinter.cpp b/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUInstPrinter.cpp index 227b738..bb5de36 100644 --- a/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUInstPrinter.cpp +++ b/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUInstPrinter.cpp @@ -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(Imm & 0xffff)); else diff --git a/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUMCCodeEmitter.cpp b/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUMCCodeEmitter.cpp index fb93f45..b3cca91 100644 --- a/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUMCCodeEmitter.cpp +++ b/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUMCCodeEmitter.cpp @@ -662,6 +662,11 @@ void AMDGPUMCCodeEmitter::getMachineOpValueT16Lo128( void AMDGPUMCCodeEmitter::getMachineOpValueCommon( const MCInst &MI, const MCOperand &MO, unsigned OpNo, APInt &Op, SmallVectorImpl &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 diff --git a/llvm/lib/Target/AMDGPU/SOPInstructions.td b/llvm/lib/Target/AMDGPU/SOPInstructions.td index aee5186..e1253d3e 100644 --- a/llvm/lib/Target/AMDGPU/SOPInstructions.td +++ b/llvm/lib/Target/AMDGPU/SOPInstructions.td @@ -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; } diff --git a/llvm/lib/Target/AMDGPU/Utils/AMDGPUAsmUtils.cpp b/llvm/lib/Target/AMDGPU/Utils/AMDGPUAsmUtils.cpp index 2e1db16..3af536d 100644 --- a/llvm/lib/Target/AMDGPU/Utils/AMDGPUAsmUtils.cpp +++ b/llvm/lib/Target/AMDGPU/Utils/AMDGPUAsmUtils.cpp @@ -669,5 +669,20 @@ const char* const IdSymbolic[] = { } // namespace VGPRIndexMode +namespace UCVersion { + +ArrayRef 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 diff --git a/llvm/lib/Target/AMDGPU/Utils/AMDGPUAsmUtils.h b/llvm/lib/Target/AMDGPU/Utils/AMDGPUAsmUtils.h index 069134a..c84c1a7 100644 --- a/llvm/lib/Target/AMDGPU/Utils/AMDGPUAsmUtils.h +++ b/llvm/lib/Target/AMDGPU/Utils/AMDGPUAsmUtils.h @@ -116,6 +116,17 @@ extern const char* const IdSymbolic[]; } // namespace VGPRIndexMode +namespace UCVersion { + +struct GFXVersion { + StringLiteral Symbol; + unsigned Code; +}; + +ArrayRef getGFXVersions(); + +} // namespace UCVersion + } // namespace AMDGPU } // namespace llvm diff --git a/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.h b/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.h index d4729b8..88b449c 100644 --- a/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.h +++ b/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.h @@ -360,6 +360,10 @@ struct EncodingField { static ValueType decode(uint64_t Encoded) { return Encoded; } }; +// Represents a single bit in an encoded value. +template +using EncodingBit = EncodingField; + // A helper for encoding and decoding multiple fields. template struct EncodingFields { static constexpr uint64_t encode(Fields... Values) { diff --git a/llvm/test/MC/AMDGPU/gfx12_asm_sopk.s b/llvm/test/MC/AMDGPU/gfx12_asm_sopk.s index 69566bb..5ce6847 100644 --- a/llvm/test/MC/AMDGPU/gfx12_asm_sopk.s +++ b/llvm/test/MC/AMDGPU/gfx12_asm_sopk.s @@ -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] diff --git a/llvm/test/MC/Disassembler/AMDGPU/gfx12_dasm_sopk.txt b/llvm/test/MC/Disassembler/AMDGPU/gfx12_dasm_sopk.txt index f2b9858..1d56c7b 100644 --- a/llvm/test/MC/Disassembler/AMDGPU/gfx12_dasm_sopk.txt +++ b/llvm/test/MC/Disassembler/AMDGPU/gfx12_dasm_sopk.txt @@ -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 -- cgit v1.1