1 //===-- AMDGPUCtorDtorLowering.cpp - Handle global ctors and dtors --------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
10 /// This pass creates a unified init and fini kernel with the required metadata
11 //===----------------------------------------------------------------------===//
14 #include "llvm/IR/Constants.h"
15 #include "llvm/IR/Function.h"
16 #include "llvm/IR/GlobalVariable.h"
17 #include "llvm/IR/IRBuilder.h"
18 #include "llvm/IR/Module.h"
19 #include "llvm/IR/Value.h"
20 #include "llvm/Pass.h"
21 #include "llvm/Transforms/Utils/ModuleUtils.h"
25 #define DEBUG_TYPE "amdgpu-lower-ctor-dtor"
28 class AMDGPUCtorDtorLowering final
: public ModulePass
{
29 bool runOnModule(Module
&M
) override
;
32 Function
*createInitOrFiniKernelFunction(Module
&M
, bool IsCtor
) {
33 StringRef InitOrFiniKernelName
= "amdgcn.device.init";
35 InitOrFiniKernelName
= "amdgcn.device.fini";
37 Function
*InitOrFiniKernel
= Function::createWithDefaultAttr(
38 FunctionType::get(Type::getVoidTy(M
.getContext()), false),
39 GlobalValue::InternalLinkage
, 0, InitOrFiniKernelName
, &M
);
40 BasicBlock
*InitOrFiniKernelBB
=
41 BasicBlock::Create(M
.getContext(), "", InitOrFiniKernel
);
42 ReturnInst::Create(M
.getContext(), InitOrFiniKernelBB
);
44 InitOrFiniKernel
->setCallingConv(CallingConv::AMDGPU_KERNEL
);
46 InitOrFiniKernel
->addFnAttr("device-init");
48 InitOrFiniKernel
->addFnAttr("device-fini");
49 return InitOrFiniKernel
;
52 bool createInitOrFiniKernel(Module
&M
, GlobalVariable
*GV
, bool IsCtor
) {
55 ConstantArray
*GA
= cast
<ConstantArray
>(GV
->getInitializer());
56 if (GA
->getNumOperands() == 0)
58 Function
*InitOrFiniKernel
= createInitOrFiniKernelFunction(M
, IsCtor
);
59 IRBuilder
<> IRB(InitOrFiniKernel
->getEntryBlock().getTerminator());
60 for (Value
*V
: GA
->operands()) {
61 auto *CS
= cast
<ConstantStruct
>(V
);
62 if (Function
*F
= dyn_cast
<Function
>(CS
->getOperand(1))) {
64 M
.getOrInsertFunction(F
->getName(), IRB
.getVoidTy());
68 appendToUsed(M
, {InitOrFiniKernel
});
73 AMDGPUCtorDtorLowering() : ModulePass(ID
) {}
75 } // End anonymous namespace
77 char AMDGPUCtorDtorLowering::ID
= 0;
78 char &llvm::AMDGPUCtorDtorLoweringID
= AMDGPUCtorDtorLowering::ID
;
79 INITIALIZE_PASS(AMDGPUCtorDtorLowering
, DEBUG_TYPE
,
80 "Lower ctors and dtors for AMDGPU", false, false)
82 ModulePass
*llvm::createAMDGPUCtorDtorLoweringPass() {
83 return new AMDGPUCtorDtorLowering();
86 bool AMDGPUCtorDtorLowering::runOnModule(Module
&M
) {
87 bool Modified
= false;
89 createInitOrFiniKernel(M
, M
.getGlobalVariable("llvm.global_ctors"),
92 createInitOrFiniKernel(M
, M
.getGlobalVariable("llvm.global_dtors"),