Files
clang-p2996/llvm/lib/Target/AMDGPU/AMDGPUCtorDtorLowering.cpp
Matt Arsenault 9cc0779c4e AMDGPU: Erase llvm.global_ctors/global_dtors after lowering
We should be able to run the pass multiple times without breaking
anything. If we still need to track these for some reason, we could
replace with new entries for the kernels.
2022-12-09 14:25:32 -05:00

108 lines
3.5 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 "AMDGPUCtorDtorLowering.h"
#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 {
static 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::ExternalLinkage, 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;
}
static bool createInitOrFiniKernel(Module &M, StringRef GlobalName,
bool IsCtor) {
GlobalVariable *GV = M.getGlobalVariable(GlobalName);
if (!GV || !GV->hasInitializer())
return false;
ConstantArray *GA = dyn_cast<ConstantArray>(GV->getInitializer());
if (!GA || GA->getNumOperands() == 0)
return false;
Function *InitOrFiniKernel = createInitOrFiniKernelFunction(M, IsCtor);
IRBuilder<> IRB(InitOrFiniKernel->getEntryBlock().getTerminator());
FunctionType *ConstructorTy = InitOrFiniKernel->getFunctionType();
for (Value *V : GA->operands()) {
auto *CS = cast<ConstantStruct>(V);
IRB.CreateCall(ConstructorTy, CS->getOperand(1));
}
appendToUsed(M, {InitOrFiniKernel});
GV->eraseFromParent();
return true;
}
static bool lowerCtorsAndDtors(Module &M) {
bool Modified = false;
Modified |= createInitOrFiniKernel(M, "llvm.global_ctors", /*IsCtor =*/true);
Modified |= createInitOrFiniKernel(M, "llvm.global_dtors", /*IsCtor =*/false);
return Modified;
}
class AMDGPUCtorDtorLoweringLegacy final : public ModulePass {
public:
static char ID;
AMDGPUCtorDtorLoweringLegacy() : ModulePass(ID) {}
bool runOnModule(Module &M) override {
return lowerCtorsAndDtors(M);
}
};
} // End anonymous namespace
PreservedAnalyses AMDGPUCtorDtorLoweringPass::run(Module &M,
ModuleAnalysisManager &AM) {
lowerCtorsAndDtors(M);
return PreservedAnalyses::all();
}
char AMDGPUCtorDtorLoweringLegacy::ID = 0;
char &llvm::AMDGPUCtorDtorLoweringLegacyPassID =
AMDGPUCtorDtorLoweringLegacy::ID;
INITIALIZE_PASS(AMDGPUCtorDtorLoweringLegacy, DEBUG_TYPE,
"Lower ctors and dtors for AMDGPU", false, false)
ModulePass *llvm::createAMDGPUCtorDtorLoweringLegacyPass() {
return new AMDGPUCtorDtorLoweringLegacy();
}