This patch introduces a new code object metadata field, ".kind" which is used to add support for init and fini kernels. HSAStreamer will use function attributes, "device-init" and "device-fini" to distinguish between init and fini kernels from the regular kernels and will emit metadata with ".kind" set to "init" and "fini" respectively. To reduce the number of init and fini kernels, the ctors and dtors present in the llvm's global.ctors and global.dtors lists are called from a single init and fini kernel respectively. Reviewed by: yaxunl Differential Revision: https://reviews.llvm.org/D105682
96 lines
3.2 KiB
C++
96 lines
3.2 KiB
C++
//===-- AMDGPUCtorDtorLowering.cpp - Handle global ctors and dtors --------===//
|
|
//
|
|
// 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
|
|
/// This pass creates a unified init and fini kernel with the required metadata
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "AMDGPU.h"
|
|
#include "llvm/IR/Constants.h"
|
|
#include "llvm/IR/Function.h"
|
|
#include "llvm/IR/GlobalVariable.h"
|
|
#include "llvm/IR/IRBuilder.h"
|
|
#include "llvm/IR/Module.h"
|
|
#include "llvm/IR/Value.h"
|
|
#include "llvm/Pass.h"
|
|
#include "llvm/Transforms/Utils/ModuleUtils.h"
|
|
|
|
using namespace llvm;
|
|
|
|
#define DEBUG_TYPE "amdgpu-lower-ctor-dtor"
|
|
|
|
namespace {
|
|
class AMDGPUCtorDtorLowering final : public ModulePass {
|
|
bool runOnModule(Module &M) override;
|
|
|
|
public:
|
|
Function *createInitOrFiniKernelFunction(Module &M, bool IsCtor) {
|
|
StringRef InitOrFiniKernelName = "amdgcn.device.init";
|
|
if (!IsCtor)
|
|
InitOrFiniKernelName = "amdgcn.device.fini";
|
|
|
|
Function *InitOrFiniKernel = Function::createWithDefaultAttr(
|
|
FunctionType::get(Type::getVoidTy(M.getContext()), false),
|
|
GlobalValue::InternalLinkage, 0, InitOrFiniKernelName, &M);
|
|
BasicBlock *InitOrFiniKernelBB =
|
|
BasicBlock::Create(M.getContext(), "", InitOrFiniKernel);
|
|
ReturnInst::Create(M.getContext(), InitOrFiniKernelBB);
|
|
|
|
InitOrFiniKernel->setCallingConv(CallingConv::AMDGPU_KERNEL);
|
|
if (IsCtor)
|
|
InitOrFiniKernel->addFnAttr("device-init");
|
|
else
|
|
InitOrFiniKernel->addFnAttr("device-fini");
|
|
return InitOrFiniKernel;
|
|
}
|
|
|
|
bool createInitOrFiniKernel(Module &M, GlobalVariable *GV, bool IsCtor) {
|
|
if (!GV)
|
|
return false;
|
|
ConstantArray *GA = cast<ConstantArray>(GV->getInitializer());
|
|
if (GA->getNumOperands() == 0)
|
|
return false;
|
|
Function *InitOrFiniKernel = createInitOrFiniKernelFunction(M, IsCtor);
|
|
IRBuilder<> IRB(InitOrFiniKernel->getEntryBlock().getTerminator());
|
|
for (Value *V : GA->operands()) {
|
|
auto *CS = cast<ConstantStruct>(V);
|
|
if (Function *F = dyn_cast<Function>(CS->getOperand(1))) {
|
|
FunctionCallee Ctor =
|
|
M.getOrInsertFunction(F->getName(), IRB.getVoidTy());
|
|
IRB.CreateCall(Ctor);
|
|
}
|
|
}
|
|
appendToUsed(M, {InitOrFiniKernel});
|
|
return true;
|
|
}
|
|
|
|
static char ID;
|
|
AMDGPUCtorDtorLowering() : ModulePass(ID) {}
|
|
};
|
|
} // End anonymous namespace
|
|
|
|
char AMDGPUCtorDtorLowering::ID = 0;
|
|
char &llvm::AMDGPUCtorDtorLoweringID = AMDGPUCtorDtorLowering::ID;
|
|
INITIALIZE_PASS(AMDGPUCtorDtorLowering, DEBUG_TYPE,
|
|
"Lower ctors and dtors for AMDGPU", false, false)
|
|
|
|
ModulePass *llvm::createAMDGPUCtorDtorLoweringPass() {
|
|
return new AMDGPUCtorDtorLowering();
|
|
}
|
|
|
|
bool AMDGPUCtorDtorLowering::runOnModule(Module &M) {
|
|
bool Modified = false;
|
|
Modified |=
|
|
createInitOrFiniKernel(M, M.getGlobalVariable("llvm.global_ctors"),
|
|
/*IsCtor =*/true);
|
|
Modified |=
|
|
createInitOrFiniKernel(M, M.getGlobalVariable("llvm.global_dtors"),
|
|
/*IsCtor =*/false);
|
|
return Modified;
|
|
}
|