15173854fSReshabh Sharma //===-- AMDGPUCtorDtorLowering.cpp - Handle global ctors and dtors --------===//
25173854fSReshabh Sharma //
35173854fSReshabh Sharma // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45173854fSReshabh Sharma // See https://llvm.org/LICENSE.txt for license information.
55173854fSReshabh Sharma // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
65173854fSReshabh Sharma //
75173854fSReshabh Sharma //===----------------------------------------------------------------------===//
85173854fSReshabh Sharma ///
95173854fSReshabh Sharma /// \file
105173854fSReshabh Sharma /// This pass creates a unified init and fini kernel with the required metadata
115173854fSReshabh Sharma //===----------------------------------------------------------------------===//
125173854fSReshabh Sharma 
135173854fSReshabh Sharma #include "AMDGPU.h"
145173854fSReshabh Sharma #include "llvm/IR/Constants.h"
155173854fSReshabh Sharma #include "llvm/IR/Function.h"
165173854fSReshabh Sharma #include "llvm/IR/GlobalVariable.h"
175173854fSReshabh Sharma #include "llvm/IR/IRBuilder.h"
185173854fSReshabh Sharma #include "llvm/IR/Module.h"
195173854fSReshabh Sharma #include "llvm/IR/Value.h"
205173854fSReshabh Sharma #include "llvm/Pass.h"
215173854fSReshabh Sharma #include "llvm/Transforms/Utils/ModuleUtils.h"
225173854fSReshabh Sharma 
235173854fSReshabh Sharma using namespace llvm;
245173854fSReshabh Sharma 
255173854fSReshabh Sharma #define DEBUG_TYPE "amdgpu-lower-ctor-dtor"
265173854fSReshabh Sharma 
275173854fSReshabh Sharma namespace {
285173854fSReshabh Sharma class AMDGPUCtorDtorLowering final : public ModulePass {
295173854fSReshabh Sharma   bool runOnModule(Module &M) override;
305173854fSReshabh Sharma 
315173854fSReshabh Sharma public:
createInitOrFiniKernelFunction(Module & M,bool IsCtor)325173854fSReshabh Sharma   Function *createInitOrFiniKernelFunction(Module &M, bool IsCtor) {
335173854fSReshabh Sharma     StringRef InitOrFiniKernelName = "amdgcn.device.init";
345173854fSReshabh Sharma     if (!IsCtor)
355173854fSReshabh Sharma       InitOrFiniKernelName = "amdgcn.device.fini";
365173854fSReshabh Sharma 
375173854fSReshabh Sharma     Function *InitOrFiniKernel = Function::createWithDefaultAttr(
385173854fSReshabh Sharma         FunctionType::get(Type::getVoidTy(M.getContext()), false),
39e90b512cSPraveen Velliengiri         GlobalValue::ExternalLinkage, 0, InitOrFiniKernelName, &M);
405173854fSReshabh Sharma     BasicBlock *InitOrFiniKernelBB =
415173854fSReshabh Sharma         BasicBlock::Create(M.getContext(), "", InitOrFiniKernel);
425173854fSReshabh Sharma     ReturnInst::Create(M.getContext(), InitOrFiniKernelBB);
435173854fSReshabh Sharma 
445173854fSReshabh Sharma     InitOrFiniKernel->setCallingConv(CallingConv::AMDGPU_KERNEL);
455173854fSReshabh Sharma     if (IsCtor)
465173854fSReshabh Sharma       InitOrFiniKernel->addFnAttr("device-init");
475173854fSReshabh Sharma     else
485173854fSReshabh Sharma       InitOrFiniKernel->addFnAttr("device-fini");
495173854fSReshabh Sharma     return InitOrFiniKernel;
505173854fSReshabh Sharma   }
515173854fSReshabh Sharma 
createInitOrFiniKernel(Module & M,GlobalVariable * GV,bool IsCtor)525173854fSReshabh Sharma   bool createInitOrFiniKernel(Module &M, GlobalVariable *GV, bool IsCtor) {
53*49b8ca3fSRuiling Song     if (!GV || !GV->hasInitializer())
545173854fSReshabh Sharma       return false;
5530b29db7SJon Chesterfield     ConstantArray *GA = dyn_cast<ConstantArray>(GV->getInitializer());
5630b29db7SJon Chesterfield     if (!GA || GA->getNumOperands() == 0)
575173854fSReshabh Sharma       return false;
585173854fSReshabh Sharma     Function *InitOrFiniKernel = createInitOrFiniKernelFunction(M, IsCtor);
595173854fSReshabh Sharma     IRBuilder<> IRB(InitOrFiniKernel->getEntryBlock().getTerminator());
605173854fSReshabh Sharma     for (Value *V : GA->operands()) {
615173854fSReshabh Sharma       auto *CS = cast<ConstantStruct>(V);
625173854fSReshabh Sharma       if (Function *F = dyn_cast<Function>(CS->getOperand(1))) {
635173854fSReshabh Sharma         FunctionCallee Ctor =
645173854fSReshabh Sharma             M.getOrInsertFunction(F->getName(), IRB.getVoidTy());
655173854fSReshabh Sharma         IRB.CreateCall(Ctor);
665173854fSReshabh Sharma       }
675173854fSReshabh Sharma     }
685173854fSReshabh Sharma     appendToUsed(M, {InitOrFiniKernel});
695173854fSReshabh Sharma     return true;
705173854fSReshabh Sharma   }
715173854fSReshabh Sharma 
725173854fSReshabh Sharma   static char ID;
AMDGPUCtorDtorLowering()735173854fSReshabh Sharma   AMDGPUCtorDtorLowering() : ModulePass(ID) {}
745173854fSReshabh Sharma };
755173854fSReshabh Sharma } // End anonymous namespace
765173854fSReshabh Sharma 
775173854fSReshabh Sharma char AMDGPUCtorDtorLowering::ID = 0;
785173854fSReshabh Sharma char &llvm::AMDGPUCtorDtorLoweringID = AMDGPUCtorDtorLowering::ID;
795173854fSReshabh Sharma INITIALIZE_PASS(AMDGPUCtorDtorLowering, DEBUG_TYPE,
805173854fSReshabh Sharma                 "Lower ctors and dtors for AMDGPU", false, false)
815173854fSReshabh Sharma 
createAMDGPUCtorDtorLoweringPass()825173854fSReshabh Sharma ModulePass *llvm::createAMDGPUCtorDtorLoweringPass() {
835173854fSReshabh Sharma   return new AMDGPUCtorDtorLowering();
845173854fSReshabh Sharma }
855173854fSReshabh Sharma 
runOnModule(Module & M)865173854fSReshabh Sharma bool AMDGPUCtorDtorLowering::runOnModule(Module &M) {
875173854fSReshabh Sharma   bool Modified = false;
885173854fSReshabh Sharma   Modified |=
895173854fSReshabh Sharma       createInitOrFiniKernel(M, M.getGlobalVariable("llvm.global_ctors"),
905173854fSReshabh Sharma                              /*IsCtor =*/true);
915173854fSReshabh Sharma   Modified |=
925173854fSReshabh Sharma       createInitOrFiniKernel(M, M.getGlobalVariable("llvm.global_dtors"),
935173854fSReshabh Sharma                              /*IsCtor =*/false);
945173854fSReshabh Sharma   return Modified;
955173854fSReshabh Sharma }
96