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 "AMDGPUCtorDtorLowering.h" 14 #include "AMDGPU.h" 15 #include "llvm/IR/Constants.h" 16 #include "llvm/IR/Function.h" 17 #include "llvm/IR/GlobalVariable.h" 18 #include "llvm/IR/IRBuilder.h" 19 #include "llvm/IR/Module.h" 20 #include "llvm/IR/Value.h" 21 #include "llvm/Pass.h" 22 #include "llvm/Transforms/Utils/ModuleUtils.h" 23 24 using namespace llvm; 25 26 #define DEBUG_TYPE "amdgpu-lower-ctor-dtor" 27 28 namespace { 29 30 static Function *createInitOrFiniKernelFunction(Module &M, bool IsCtor) { 31 StringRef InitOrFiniKernelName = "amdgcn.device.init"; 32 if (!IsCtor) 33 InitOrFiniKernelName = "amdgcn.device.fini"; 34 35 Function *InitOrFiniKernel = Function::createWithDefaultAttr( 36 FunctionType::get(Type::getVoidTy(M.getContext()), false), 37 GlobalValue::ExternalLinkage, 0, InitOrFiniKernelName, &M); 38 BasicBlock *InitOrFiniKernelBB = 39 BasicBlock::Create(M.getContext(), "", InitOrFiniKernel); 40 ReturnInst::Create(M.getContext(), InitOrFiniKernelBB); 41 42 InitOrFiniKernel->setCallingConv(CallingConv::AMDGPU_KERNEL); 43 if (IsCtor) 44 InitOrFiniKernel->addFnAttr("device-init"); 45 else 46 InitOrFiniKernel->addFnAttr("device-fini"); 47 return InitOrFiniKernel; 48 } 49 50 static bool createInitOrFiniKernel(Module &M, StringRef GlobalName, 51 bool IsCtor) { 52 GlobalVariable *GV = M.getGlobalVariable(GlobalName); 53 if (!GV || !GV->hasInitializer()) 54 return false; 55 ConstantArray *GA = dyn_cast<ConstantArray>(GV->getInitializer()); 56 if (!GA || GA->getNumOperands() == 0) 57 return false; 58 59 Function *InitOrFiniKernel = createInitOrFiniKernelFunction(M, IsCtor); 60 IRBuilder<> IRB(InitOrFiniKernel->getEntryBlock().getTerminator()); 61 62 FunctionType *ConstructorTy = InitOrFiniKernel->getFunctionType(); 63 64 for (Value *V : GA->operands()) { 65 auto *CS = cast<ConstantStruct>(V); 66 IRB.CreateCall(ConstructorTy, CS->getOperand(1)); 67 } 68 69 appendToUsed(M, {InitOrFiniKernel}); 70 71 GV->eraseFromParent(); 72 return true; 73 } 74 75 static bool lowerCtorsAndDtors(Module &M) { 76 bool Modified = false; 77 Modified |= createInitOrFiniKernel(M, "llvm.global_ctors", /*IsCtor =*/true); 78 Modified |= createInitOrFiniKernel(M, "llvm.global_dtors", /*IsCtor =*/false); 79 return Modified; 80 } 81 82 class AMDGPUCtorDtorLoweringLegacy final : public ModulePass { 83 public: 84 static char ID; 85 AMDGPUCtorDtorLoweringLegacy() : ModulePass(ID) {} 86 bool runOnModule(Module &M) override { 87 return lowerCtorsAndDtors(M); 88 } 89 }; 90 91 } // End anonymous namespace 92 93 PreservedAnalyses AMDGPUCtorDtorLoweringPass::run(Module &M, 94 ModuleAnalysisManager &AM) { 95 lowerCtorsAndDtors(M); 96 return PreservedAnalyses::all(); 97 } 98 99 char AMDGPUCtorDtorLoweringLegacy::ID = 0; 100 char &llvm::AMDGPUCtorDtorLoweringLegacyPassID = 101 AMDGPUCtorDtorLoweringLegacy::ID; 102 INITIALIZE_PASS(AMDGPUCtorDtorLoweringLegacy, DEBUG_TYPE, 103 "Lower ctors and dtors for AMDGPU", false, false) 104 105 ModulePass *llvm::createAMDGPUCtorDtorLoweringLegacyPass() { 106 return new AMDGPUCtorDtorLoweringLegacy(); 107 } 108