1 //===-- AMDGPUCtorDtorLowering.cpp - Handle global ctors and dtors --------===// 2 // 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 6 // 7 //===----------------------------------------------------------------------===// 8 /// 9 /// \file 10 /// This pass creates a unified init and fini kernel with the required metadata 11 //===----------------------------------------------------------------------===// 12 13 #include "AMDGPU.h" 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" 22 23 using namespace llvm; 24 25 #define DEBUG_TYPE "amdgpu-lower-ctor-dtor" 26 27 namespace { 28 class AMDGPUCtorDtorLowering final : public ModulePass { 29 bool runOnModule(Module &M) override; 30 31 public: 32 Function *createInitOrFiniKernelFunction(Module &M, bool IsCtor) { 33 StringRef InitOrFiniKernelName = "amdgcn.device.init"; 34 if (!IsCtor) 35 InitOrFiniKernelName = "amdgcn.device.fini"; 36 37 Function *InitOrFiniKernel = Function::createWithDefaultAttr( 38 FunctionType::get(Type::getVoidTy(M.getContext()), false), 39 GlobalValue::ExternalLinkage, 0, InitOrFiniKernelName, &M); 40 BasicBlock *InitOrFiniKernelBB = 41 BasicBlock::Create(M.getContext(), "", InitOrFiniKernel); 42 ReturnInst::Create(M.getContext(), InitOrFiniKernelBB); 43 44 InitOrFiniKernel->setCallingConv(CallingConv::AMDGPU_KERNEL); 45 if (IsCtor) 46 InitOrFiniKernel->addFnAttr("device-init"); 47 else 48 InitOrFiniKernel->addFnAttr("device-fini"); 49 return InitOrFiniKernel; 50 } 51 52 bool createInitOrFiniKernel(Module &M, GlobalVariable *GV, bool IsCtor) { 53 if (!GV) 54 return false; 55 ConstantArray *GA = dyn_cast<ConstantArray>(GV->getInitializer()); 56 if (!GA || GA->getNumOperands() == 0) 57 return false; 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))) { 63 FunctionCallee Ctor = 64 M.getOrInsertFunction(F->getName(), IRB.getVoidTy()); 65 IRB.CreateCall(Ctor); 66 } 67 } 68 appendToUsed(M, {InitOrFiniKernel}); 69 return true; 70 } 71 72 static char ID; 73 AMDGPUCtorDtorLowering() : ModulePass(ID) {} 74 }; 75 } // End anonymous namespace 76 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) 81 82 ModulePass *llvm::createAMDGPUCtorDtorLoweringPass() { 83 return new AMDGPUCtorDtorLowering(); 84 } 85 86 bool AMDGPUCtorDtorLowering::runOnModule(Module &M) { 87 bool Modified = false; 88 Modified |= 89 createInitOrFiniKernel(M, M.getGlobalVariable("llvm.global_ctors"), 90 /*IsCtor =*/true); 91 Modified |= 92 createInitOrFiniKernel(M, M.getGlobalVariable("llvm.global_dtors"), 93 /*IsCtor =*/false); 94 return Modified; 95 } 96