[AMDGPU] Lazily init pal metadata on first function

Delay reading global metadata until the first function or the end of
the file is emitted. That way, earlier module passes can set metadata
that is emitted in the ELF.

`emitStartOfAsmFile` gets called when the passes are initialized,
which prevented earlier passes from changing the metadata.

This fixes issues encountered after converting
AMDGPUResourceUsageAnalysis to a Module pass in D117504.

Differential Revision: https://reviews.llvm.org/D118492
This commit is contained in:
Sebastian Neubauer 2022-02-04 18:39:35 +01:00
parent 44cdca37c0
commit 4a02562275
4 changed files with 113 additions and 0 deletions

View File

@ -111,6 +111,12 @@ AMDGPUTargetStreamer* AMDGPUAsmPrinter::getTargetStreamer() const {
} }
void AMDGPUAsmPrinter::emitStartOfAsmFile(Module &M) { void AMDGPUAsmPrinter::emitStartOfAsmFile(Module &M) {
IsTargetStreamerInitialized = false;
}
void AMDGPUAsmPrinter::initTargetStreamer(Module &M) {
IsTargetStreamerInitialized = true;
// TODO: Which one is called first, emitStartOfAsmFile or // TODO: Which one is called first, emitStartOfAsmFile or
// emitFunctionBodyStart? // emitFunctionBodyStart?
if (getTargetStreamer() && !getTargetStreamer()->getTargetID()) if (getTargetStreamer() && !getTargetStreamer()->getTargetID())
@ -143,6 +149,10 @@ void AMDGPUAsmPrinter::emitStartOfAsmFile(Module &M) {
} }
void AMDGPUAsmPrinter::emitEndOfAsmFile(Module &M) { void AMDGPUAsmPrinter::emitEndOfAsmFile(Module &M) {
// Init target streamer if it has not yet happened
if (!IsTargetStreamerInitialized)
initTargetStreamer(M);
// Following code requires TargetStreamer to be present. // Following code requires TargetStreamer to be present.
if (!getTargetStreamer()) if (!getTargetStreamer())
return; return;
@ -437,6 +447,11 @@ amdhsa::kernel_descriptor_t AMDGPUAsmPrinter::getAmdhsaKernelDescriptor(
} }
bool AMDGPUAsmPrinter::runOnMachineFunction(MachineFunction &MF) { bool AMDGPUAsmPrinter::runOnMachineFunction(MachineFunction &MF) {
// Init target streamer lazily on the first function so that previous passes
// can set metadata.
if (!IsTargetStreamerInitialized)
initTargetStreamer(*MF.getFunction().getParent());
ResourceUsage = &getAnalysis<AMDGPUResourceUsageAnalysis>(); ResourceUsage = &getAnalysis<AMDGPUResourceUsageAnalysis>();
CurrentProgramInfo = SIProgramInfo(); CurrentProgramInfo = SIProgramInfo();

View File

@ -77,6 +77,8 @@ private:
const MachineFunction &MF, const MachineFunction &MF,
const SIProgramInfo &PI) const; const SIProgramInfo &PI) const;
void initTargetStreamer(Module &M);
public: public:
explicit AMDGPUAsmPrinter(TargetMachine &TM, explicit AMDGPUAsmPrinter(TargetMachine &TM,
std::unique_ptr<MCStreamer> Streamer); std::unique_ptr<MCStreamer> Streamer);
@ -132,6 +134,7 @@ protected:
std::vector<std::string> DisasmLines, HexLines; std::vector<std::string> DisasmLines, HexLines;
size_t DisasmLineMaxLen; size_t DisasmLineMaxLen;
bool IsTargetStreamerInitialized;
}; };
} // end namespace llvm } // end namespace llvm

View File

@ -0,0 +1,94 @@
//===- llvm/unittest/CodeGen/AMDGPUMetadataTest.cpp -----------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
//
/// \file
/// Test that amdgpu metadata that is added in a pass is read by the asm emitter
/// and stored in the ELF.
//
//===----------------------------------------------------------------------===//
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/MC/TargetRegistry.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Target/TargetMachine.h"
#include "gtest/gtest.h"
namespace llvm {
namespace {
// Pass that adds global metadata
struct AddMetadataPass : public ModulePass {
std::string PalMDString;
public:
static char ID;
AddMetadataPass(std::string PalMDString)
: ModulePass(ID), PalMDString(PalMDString) {}
bool runOnModule(Module &M) override {
auto &Ctx = M.getContext();
auto *MD = M.getOrInsertNamedMetadata("amdgpu.pal.metadata.msgpack");
auto *PalMD = MDString::get(Ctx, PalMDString);
auto *TMD = MDTuple::get(Ctx, {PalMD});
MD->addOperand(TMD);
return true;
}
};
char AddMetadataPass::ID = 0;
} // end anonymous namespace
class AMDGPUSelectionDAGTest : public testing::Test {
protected:
static void SetUpTestCase() {
InitializeAllTargets();
InitializeAllTargetMCs();
}
void SetUp() override {
std::string Error;
const Target *T = TargetRegistry::lookupTarget("amdgcn--amdpal", Error);
if (!T)
GTEST_SKIP();
TargetOptions Options;
TM = std::unique_ptr<LLVMTargetMachine>(
static_cast<LLVMTargetMachine *>(T->createTargetMachine(
"amdgcn--amdpal", "gfx1010", "", Options, None)));
if (!TM)
GTEST_SKIP();
LLVMContext Context;
std::unique_ptr<Module> M(new Module("TestModule", Context));
M->setDataLayout(TM->createDataLayout());
legacy::PassManager PM;
PM.add(new AddMetadataPass(PalMDString));
raw_svector_ostream OutStream(Elf);
if (TM->addPassesToEmitFile(PM, OutStream, nullptr,
CodeGenFileType::CGFT_ObjectFile))
report_fatal_error("Target machine cannot emit a file of this type");
PM.run(*M);
}
static std::string PalMDString;
LLVMContext Context;
std::unique_ptr<LLVMTargetMachine> TM;
std::unique_ptr<Module> M;
SmallString<1024> Elf;
};
std::string AMDGPUSelectionDAGTest::PalMDString =
"\x81\xB0"
"amdpal.pipelines\x91\x81\xA4.api\xA6Vulkan";
TEST_F(AMDGPUSelectionDAGTest, checkMetadata) {
// Check that the string is contained in the ELF
EXPECT_NE(Elf.find("Vulkan"), std::string::npos);
}
} // end namespace llvm

View File

@ -17,6 +17,7 @@ set(LLVM_LINK_COMPONENTS
add_llvm_unittest(CodeGenTests add_llvm_unittest(CodeGenTests
AArch64SelectionDAGTest.cpp AArch64SelectionDAGTest.cpp
AllocationOrderTest.cpp AllocationOrderTest.cpp
AMDGPUMetadataTest.cpp
AsmPrinterDwarfTest.cpp AsmPrinterDwarfTest.cpp
DIEHashTest.cpp DIEHashTest.cpp
DIETest.cpp DIETest.cpp