10b57cec5SDimitry Andric //===-- AMDGPULowerKernelAttributes.cpp ------------------------------------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric /// \file This pass does attempts to make use of reqd_work_group_size metadata 100b57cec5SDimitry Andric /// to eliminate loads from the dispatch packet and to constant fold OpenCL 110b57cec5SDimitry Andric /// get_local_size-like functions. 120b57cec5SDimitry Andric // 130b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 140b57cec5SDimitry Andric 150b57cec5SDimitry Andric #include "AMDGPU.h" 16bdd1243dSDimitry Andric #include "Utils/AMDGPUBaseInfo.h" 175f757f3fSDimitry Andric #include "llvm/Analysis/ConstantFolding.h" 180b57cec5SDimitry Andric #include "llvm/Analysis/ValueTracking.h" 190b57cec5SDimitry Andric #include "llvm/CodeGen/Passes.h" 200b57cec5SDimitry Andric #include "llvm/CodeGen/TargetPassConfig.h" 210b57cec5SDimitry Andric #include "llvm/IR/Constants.h" 220b57cec5SDimitry Andric #include "llvm/IR/Function.h" 23e8d8bef9SDimitry Andric #include "llvm/IR/InstIterator.h" 240b57cec5SDimitry Andric #include "llvm/IR/Instructions.h" 25e8d8bef9SDimitry Andric #include "llvm/IR/IntrinsicsAMDGPU.h" 260b57cec5SDimitry Andric #include "llvm/IR/PatternMatch.h" 270b57cec5SDimitry Andric #include "llvm/Pass.h" 280b57cec5SDimitry Andric 290b57cec5SDimitry Andric #define DEBUG_TYPE "amdgpu-lower-kernel-attributes" 300b57cec5SDimitry Andric 310b57cec5SDimitry Andric using namespace llvm; 320b57cec5SDimitry Andric 330b57cec5SDimitry Andric namespace { 340b57cec5SDimitry Andric 350b57cec5SDimitry Andric // Field offsets in hsa_kernel_dispatch_packet_t. 360b57cec5SDimitry Andric enum DispatchPackedOffsets { 370b57cec5SDimitry Andric WORKGROUP_SIZE_X = 4, 380b57cec5SDimitry Andric WORKGROUP_SIZE_Y = 6, 390b57cec5SDimitry Andric WORKGROUP_SIZE_Z = 8, 400b57cec5SDimitry Andric 410b57cec5SDimitry Andric GRID_SIZE_X = 12, 420b57cec5SDimitry Andric GRID_SIZE_Y = 16, 430b57cec5SDimitry Andric GRID_SIZE_Z = 20 440b57cec5SDimitry Andric }; 450b57cec5SDimitry Andric 46bdd1243dSDimitry Andric // Field offsets to implicit kernel argument pointer. 47bdd1243dSDimitry Andric enum ImplicitArgOffsets { 48bdd1243dSDimitry Andric HIDDEN_BLOCK_COUNT_X = 0, 49bdd1243dSDimitry Andric HIDDEN_BLOCK_COUNT_Y = 4, 50bdd1243dSDimitry Andric HIDDEN_BLOCK_COUNT_Z = 8, 51bdd1243dSDimitry Andric 52bdd1243dSDimitry Andric HIDDEN_GROUP_SIZE_X = 12, 53bdd1243dSDimitry Andric HIDDEN_GROUP_SIZE_Y = 14, 54bdd1243dSDimitry Andric HIDDEN_GROUP_SIZE_Z = 16, 55bdd1243dSDimitry Andric 56bdd1243dSDimitry Andric HIDDEN_REMAINDER_X = 18, 57bdd1243dSDimitry Andric HIDDEN_REMAINDER_Y = 20, 58bdd1243dSDimitry Andric HIDDEN_REMAINDER_Z = 22, 59bdd1243dSDimitry Andric }; 60bdd1243dSDimitry Andric 610b57cec5SDimitry Andric class AMDGPULowerKernelAttributes : public ModulePass { 620b57cec5SDimitry Andric public: 630b57cec5SDimitry Andric static char ID; 640b57cec5SDimitry Andric 650b57cec5SDimitry Andric AMDGPULowerKernelAttributes() : ModulePass(ID) {} 660b57cec5SDimitry Andric 670b57cec5SDimitry Andric bool runOnModule(Module &M) override; 680b57cec5SDimitry Andric 690b57cec5SDimitry Andric StringRef getPassName() const override { 700b57cec5SDimitry Andric return "AMDGPU Kernel Attributes"; 710b57cec5SDimitry Andric } 720b57cec5SDimitry Andric 730b57cec5SDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override { 740b57cec5SDimitry Andric AU.setPreservesAll(); 750b57cec5SDimitry Andric } 760b57cec5SDimitry Andric }; 770b57cec5SDimitry Andric 78bdd1243dSDimitry Andric Function *getBasePtrIntrinsic(Module &M, bool IsV5OrAbove) { 79bdd1243dSDimitry Andric auto IntrinsicId = IsV5OrAbove ? Intrinsic::amdgcn_implicitarg_ptr 80bdd1243dSDimitry Andric : Intrinsic::amdgcn_dispatch_ptr; 81bdd1243dSDimitry Andric StringRef Name = Intrinsic::getName(IntrinsicId); 82bdd1243dSDimitry Andric return M.getFunction(Name); 83bdd1243dSDimitry Andric } 84bdd1243dSDimitry Andric 850b57cec5SDimitry Andric } // end anonymous namespace 860b57cec5SDimitry Andric 87bdd1243dSDimitry Andric static bool processUse(CallInst *CI, bool IsV5OrAbove) { 880b57cec5SDimitry Andric Function *F = CI->getParent()->getParent(); 890b57cec5SDimitry Andric 900b57cec5SDimitry Andric auto MD = F->getMetadata("reqd_work_group_size"); 910b57cec5SDimitry Andric const bool HasReqdWorkGroupSize = MD && MD->getNumOperands() == 3; 920b57cec5SDimitry Andric 930b57cec5SDimitry Andric const bool HasUniformWorkGroupSize = 94fe6060f1SDimitry Andric F->getFnAttribute("uniform-work-group-size").getValueAsBool(); 950b57cec5SDimitry Andric 960b57cec5SDimitry Andric if (!HasReqdWorkGroupSize && !HasUniformWorkGroupSize) 970b57cec5SDimitry Andric return false; 980b57cec5SDimitry Andric 99bdd1243dSDimitry Andric Value *BlockCounts[3] = {nullptr, nullptr, nullptr}; 100bdd1243dSDimitry Andric Value *GroupSizes[3] = {nullptr, nullptr, nullptr}; 101bdd1243dSDimitry Andric Value *Remainders[3] = {nullptr, nullptr, nullptr}; 102bdd1243dSDimitry Andric Value *GridSizes[3] = {nullptr, nullptr, nullptr}; 1030b57cec5SDimitry Andric 104*0fca6ea1SDimitry Andric const DataLayout &DL = F->getDataLayout(); 1050b57cec5SDimitry Andric 1060b57cec5SDimitry Andric // We expect to see several GEP users, casted to the appropriate type and 1070b57cec5SDimitry Andric // loaded. 1080b57cec5SDimitry Andric for (User *U : CI->users()) { 1090b57cec5SDimitry Andric if (!U->hasOneUse()) 1100b57cec5SDimitry Andric continue; 1110b57cec5SDimitry Andric 1120b57cec5SDimitry Andric int64_t Offset = 0; 113bdd1243dSDimitry Andric auto *Load = dyn_cast<LoadInst>(U); // Load from ImplicitArgPtr/DispatchPtr? 114bdd1243dSDimitry Andric auto *BCI = dyn_cast<BitCastInst>(U); 115bdd1243dSDimitry Andric if (!Load && !BCI) { 1160b57cec5SDimitry Andric if (GetPointerBaseWithConstantOffset(U, Offset, DL) != CI) 1170b57cec5SDimitry Andric continue; 118bdd1243dSDimitry Andric Load = dyn_cast<LoadInst>(*U->user_begin()); // Load from GEP? 119bdd1243dSDimitry Andric BCI = dyn_cast<BitCastInst>(*U->user_begin()); 120bdd1243dSDimitry Andric } 1210b57cec5SDimitry Andric 122bdd1243dSDimitry Andric if (BCI) { 123bdd1243dSDimitry Andric if (!BCI->hasOneUse()) 1240b57cec5SDimitry Andric continue; 125bdd1243dSDimitry Andric Load = dyn_cast<LoadInst>(*BCI->user_begin()); // Load from BCI? 126bdd1243dSDimitry Andric } 1270b57cec5SDimitry Andric 1280b57cec5SDimitry Andric if (!Load || !Load->isSimple()) 1290b57cec5SDimitry Andric continue; 1300b57cec5SDimitry Andric 1310b57cec5SDimitry Andric unsigned LoadSize = DL.getTypeStoreSize(Load->getType()); 1320b57cec5SDimitry Andric 1330b57cec5SDimitry Andric // TODO: Handle merged loads. 134bdd1243dSDimitry Andric if (IsV5OrAbove) { // Base is ImplicitArgPtr. 135bdd1243dSDimitry Andric switch (Offset) { 136bdd1243dSDimitry Andric case HIDDEN_BLOCK_COUNT_X: 137bdd1243dSDimitry Andric if (LoadSize == 4) 138bdd1243dSDimitry Andric BlockCounts[0] = Load; 139bdd1243dSDimitry Andric break; 140bdd1243dSDimitry Andric case HIDDEN_BLOCK_COUNT_Y: 141bdd1243dSDimitry Andric if (LoadSize == 4) 142bdd1243dSDimitry Andric BlockCounts[1] = Load; 143bdd1243dSDimitry Andric break; 144bdd1243dSDimitry Andric case HIDDEN_BLOCK_COUNT_Z: 145bdd1243dSDimitry Andric if (LoadSize == 4) 146bdd1243dSDimitry Andric BlockCounts[2] = Load; 147bdd1243dSDimitry Andric break; 148bdd1243dSDimitry Andric case HIDDEN_GROUP_SIZE_X: 149bdd1243dSDimitry Andric if (LoadSize == 2) 150bdd1243dSDimitry Andric GroupSizes[0] = Load; 151bdd1243dSDimitry Andric break; 152bdd1243dSDimitry Andric case HIDDEN_GROUP_SIZE_Y: 153bdd1243dSDimitry Andric if (LoadSize == 2) 154bdd1243dSDimitry Andric GroupSizes[1] = Load; 155bdd1243dSDimitry Andric break; 156bdd1243dSDimitry Andric case HIDDEN_GROUP_SIZE_Z: 157bdd1243dSDimitry Andric if (LoadSize == 2) 158bdd1243dSDimitry Andric GroupSizes[2] = Load; 159bdd1243dSDimitry Andric break; 160bdd1243dSDimitry Andric case HIDDEN_REMAINDER_X: 161bdd1243dSDimitry Andric if (LoadSize == 2) 162bdd1243dSDimitry Andric Remainders[0] = Load; 163bdd1243dSDimitry Andric break; 164bdd1243dSDimitry Andric case HIDDEN_REMAINDER_Y: 165bdd1243dSDimitry Andric if (LoadSize == 2) 166bdd1243dSDimitry Andric Remainders[1] = Load; 167bdd1243dSDimitry Andric break; 168bdd1243dSDimitry Andric case HIDDEN_REMAINDER_Z: 169bdd1243dSDimitry Andric if (LoadSize == 2) 170bdd1243dSDimitry Andric Remainders[2] = Load; 171bdd1243dSDimitry Andric break; 172bdd1243dSDimitry Andric default: 173bdd1243dSDimitry Andric break; 174bdd1243dSDimitry Andric } 175bdd1243dSDimitry Andric } else { // Base is DispatchPtr. 1760b57cec5SDimitry Andric switch (Offset) { 1770b57cec5SDimitry Andric case WORKGROUP_SIZE_X: 1780b57cec5SDimitry Andric if (LoadSize == 2) 179bdd1243dSDimitry Andric GroupSizes[0] = Load; 1800b57cec5SDimitry Andric break; 1810b57cec5SDimitry Andric case WORKGROUP_SIZE_Y: 1820b57cec5SDimitry Andric if (LoadSize == 2) 183bdd1243dSDimitry Andric GroupSizes[1] = Load; 1840b57cec5SDimitry Andric break; 1850b57cec5SDimitry Andric case WORKGROUP_SIZE_Z: 1860b57cec5SDimitry Andric if (LoadSize == 2) 187bdd1243dSDimitry Andric GroupSizes[2] = Load; 1880b57cec5SDimitry Andric break; 1890b57cec5SDimitry Andric case GRID_SIZE_X: 1900b57cec5SDimitry Andric if (LoadSize == 4) 191bdd1243dSDimitry Andric GridSizes[0] = Load; 1920b57cec5SDimitry Andric break; 1930b57cec5SDimitry Andric case GRID_SIZE_Y: 1940b57cec5SDimitry Andric if (LoadSize == 4) 195bdd1243dSDimitry Andric GridSizes[1] = Load; 1960b57cec5SDimitry Andric break; 1970b57cec5SDimitry Andric case GRID_SIZE_Z: 1980b57cec5SDimitry Andric if (LoadSize == 4) 199bdd1243dSDimitry Andric GridSizes[2] = Load; 2000b57cec5SDimitry Andric break; 2010b57cec5SDimitry Andric default: 2020b57cec5SDimitry Andric break; 2030b57cec5SDimitry Andric } 2040b57cec5SDimitry Andric } 205bdd1243dSDimitry Andric } 2060b57cec5SDimitry Andric 207bdd1243dSDimitry Andric bool MadeChange = false; 208bdd1243dSDimitry Andric if (IsV5OrAbove && HasUniformWorkGroupSize) { 209bdd1243dSDimitry Andric // Under v5 __ockl_get_local_size returns the value computed by the expression: 210bdd1243dSDimitry Andric // 211bdd1243dSDimitry Andric // workgroup_id < hidden_block_count ? hidden_group_size : hidden_remainder 212bdd1243dSDimitry Andric // 213bdd1243dSDimitry Andric // For functions with the attribute uniform-work-group-size=true. we can evaluate 214bdd1243dSDimitry Andric // workgroup_id < hidden_block_count as true, and thus hidden_group_size is returned 215bdd1243dSDimitry Andric // for __ockl_get_local_size. 216bdd1243dSDimitry Andric for (int I = 0; I < 3; ++I) { 217bdd1243dSDimitry Andric Value *BlockCount = BlockCounts[I]; 218bdd1243dSDimitry Andric if (!BlockCount) 219bdd1243dSDimitry Andric continue; 220bdd1243dSDimitry Andric 221bdd1243dSDimitry Andric using namespace llvm::PatternMatch; 222bdd1243dSDimitry Andric auto GroupIDIntrin = 223bdd1243dSDimitry Andric I == 0 ? m_Intrinsic<Intrinsic::amdgcn_workgroup_id_x>() 224bdd1243dSDimitry Andric : (I == 1 ? m_Intrinsic<Intrinsic::amdgcn_workgroup_id_y>() 225bdd1243dSDimitry Andric : m_Intrinsic<Intrinsic::amdgcn_workgroup_id_z>()); 226bdd1243dSDimitry Andric 227bdd1243dSDimitry Andric for (User *ICmp : BlockCount->users()) { 228bdd1243dSDimitry Andric ICmpInst::Predicate Pred; 229bdd1243dSDimitry Andric if (match(ICmp, m_ICmp(Pred, GroupIDIntrin, m_Specific(BlockCount)))) { 230bdd1243dSDimitry Andric if (Pred != ICmpInst::ICMP_ULT) 231bdd1243dSDimitry Andric continue; 232bdd1243dSDimitry Andric ICmp->replaceAllUsesWith(llvm::ConstantInt::getTrue(ICmp->getType())); 233bdd1243dSDimitry Andric MadeChange = true; 234bdd1243dSDimitry Andric } 235bdd1243dSDimitry Andric } 236bdd1243dSDimitry Andric } 237bdd1243dSDimitry Andric 238bdd1243dSDimitry Andric // All remainders should be 0 with uniform work group size. 239bdd1243dSDimitry Andric for (Value *Remainder : Remainders) { 240bdd1243dSDimitry Andric if (!Remainder) 241bdd1243dSDimitry Andric continue; 242bdd1243dSDimitry Andric Remainder->replaceAllUsesWith(Constant::getNullValue(Remainder->getType())); 243bdd1243dSDimitry Andric MadeChange = true; 244bdd1243dSDimitry Andric } 245bdd1243dSDimitry Andric } else if (HasUniformWorkGroupSize) { // Pre-V5. 2460b57cec5SDimitry Andric // Pattern match the code used to handle partial workgroup dispatches in the 2470b57cec5SDimitry Andric // library implementation of get_local_size, so the entire function can be 2480b57cec5SDimitry Andric // constant folded with a known group size. 2490b57cec5SDimitry Andric // 2500b57cec5SDimitry Andric // uint r = grid_size - group_id * group_size; 2510b57cec5SDimitry Andric // get_local_size = (r < group_size) ? r : group_size; 2520b57cec5SDimitry Andric // 2530b57cec5SDimitry Andric // If we have uniform-work-group-size (which is the default in OpenCL 1.2), 2540b57cec5SDimitry Andric // the grid_size is required to be a multiple of group_size). In this case: 2550b57cec5SDimitry Andric // 2560b57cec5SDimitry Andric // grid_size - (group_id * group_size) < group_size 2570b57cec5SDimitry Andric // -> 2580b57cec5SDimitry Andric // grid_size < group_size + (group_id * group_size) 2590b57cec5SDimitry Andric // 2600b57cec5SDimitry Andric // (grid_size / group_size) < 1 + group_id 2610b57cec5SDimitry Andric // 2620b57cec5SDimitry Andric // grid_size / group_size is at least 1, so we can conclude the select 2630b57cec5SDimitry Andric // condition is false (except for group_id == 0, where the select result is 2640b57cec5SDimitry Andric // the same). 265bdd1243dSDimitry Andric for (int I = 0; I < 3; ++I) { 266bdd1243dSDimitry Andric Value *GroupSize = GroupSizes[I]; 2670b57cec5SDimitry Andric Value *GridSize = GridSizes[I]; 2680b57cec5SDimitry Andric if (!GroupSize || !GridSize) 2690b57cec5SDimitry Andric continue; 2700b57cec5SDimitry Andric 27181ad6265SDimitry Andric using namespace llvm::PatternMatch; 27281ad6265SDimitry Andric auto GroupIDIntrin = 27381ad6265SDimitry Andric I == 0 ? m_Intrinsic<Intrinsic::amdgcn_workgroup_id_x>() 27481ad6265SDimitry Andric : (I == 1 ? m_Intrinsic<Intrinsic::amdgcn_workgroup_id_y>() 27581ad6265SDimitry Andric : m_Intrinsic<Intrinsic::amdgcn_workgroup_id_z>()); 27681ad6265SDimitry Andric 2770b57cec5SDimitry Andric for (User *U : GroupSize->users()) { 2780b57cec5SDimitry Andric auto *ZextGroupSize = dyn_cast<ZExtInst>(U); 2790b57cec5SDimitry Andric if (!ZextGroupSize) 2800b57cec5SDimitry Andric continue; 2810b57cec5SDimitry Andric 28281ad6265SDimitry Andric for (User *UMin : ZextGroupSize->users()) { 28381ad6265SDimitry Andric if (match(UMin, 28481ad6265SDimitry Andric m_UMin(m_Sub(m_Specific(GridSize), 28581ad6265SDimitry Andric m_Mul(GroupIDIntrin, m_Specific(ZextGroupSize))), 28681ad6265SDimitry Andric m_Specific(ZextGroupSize)))) { 2870b57cec5SDimitry Andric if (HasReqdWorkGroupSize) { 2880b57cec5SDimitry Andric ConstantInt *KnownSize 2890b57cec5SDimitry Andric = mdconst::extract<ConstantInt>(MD->getOperand(I)); 2905f757f3fSDimitry Andric UMin->replaceAllUsesWith(ConstantFoldIntegerCast( 2915f757f3fSDimitry Andric KnownSize, UMin->getType(), false, DL)); 2920b57cec5SDimitry Andric } else { 29381ad6265SDimitry Andric UMin->replaceAllUsesWith(ZextGroupSize); 2940b57cec5SDimitry Andric } 2950b57cec5SDimitry Andric 2960b57cec5SDimitry Andric MadeChange = true; 2970b57cec5SDimitry Andric } 2980b57cec5SDimitry Andric } 2990b57cec5SDimitry Andric } 3000b57cec5SDimitry Andric } 301bdd1243dSDimitry Andric } 3020b57cec5SDimitry Andric 303bdd1243dSDimitry Andric // If reqd_work_group_size is set, we can replace work group size with it. 3040b57cec5SDimitry Andric if (!HasReqdWorkGroupSize) 3050b57cec5SDimitry Andric return MadeChange; 3060b57cec5SDimitry Andric 307bdd1243dSDimitry Andric for (int I = 0; I < 3; I++) { 308bdd1243dSDimitry Andric Value *GroupSize = GroupSizes[I]; 3090b57cec5SDimitry Andric if (!GroupSize) 3100b57cec5SDimitry Andric continue; 3110b57cec5SDimitry Andric 3120b57cec5SDimitry Andric ConstantInt *KnownSize = mdconst::extract<ConstantInt>(MD->getOperand(I)); 3130b57cec5SDimitry Andric GroupSize->replaceAllUsesWith( 3145f757f3fSDimitry Andric ConstantFoldIntegerCast(KnownSize, GroupSize->getType(), false, DL)); 3150b57cec5SDimitry Andric MadeChange = true; 3160b57cec5SDimitry Andric } 3170b57cec5SDimitry Andric 3180b57cec5SDimitry Andric return MadeChange; 3190b57cec5SDimitry Andric } 3200b57cec5SDimitry Andric 321bdd1243dSDimitry Andric 3220b57cec5SDimitry Andric // TODO: Move makeLIDRangeMetadata usage into here. Seem to not get 3230b57cec5SDimitry Andric // TargetPassConfig for subtarget. 3240b57cec5SDimitry Andric bool AMDGPULowerKernelAttributes::runOnModule(Module &M) { 325bdd1243dSDimitry Andric bool MadeChange = false; 3267a6dacacSDimitry Andric bool IsV5OrAbove = 3277a6dacacSDimitry Andric AMDGPU::getAMDHSACodeObjectVersion(M) >= AMDGPU::AMDHSA_COV5; 328bdd1243dSDimitry Andric Function *BasePtr = getBasePtrIntrinsic(M, IsV5OrAbove); 3290b57cec5SDimitry Andric 330bdd1243dSDimitry Andric if (!BasePtr) // ImplicitArgPtr/DispatchPtr not used. 3310b57cec5SDimitry Andric return false; 3320b57cec5SDimitry Andric 3330b57cec5SDimitry Andric SmallPtrSet<Instruction *, 4> HandledUses; 334bdd1243dSDimitry Andric for (auto *U : BasePtr->users()) { 3350b57cec5SDimitry Andric CallInst *CI = cast<CallInst>(U); 3360b57cec5SDimitry Andric if (HandledUses.insert(CI).second) { 337bdd1243dSDimitry Andric if (processUse(CI, IsV5OrAbove)) 3380b57cec5SDimitry Andric MadeChange = true; 3390b57cec5SDimitry Andric } 3400b57cec5SDimitry Andric } 3410b57cec5SDimitry Andric 3420b57cec5SDimitry Andric return MadeChange; 3430b57cec5SDimitry Andric } 3440b57cec5SDimitry Andric 345bdd1243dSDimitry Andric 3460b57cec5SDimitry Andric INITIALIZE_PASS_BEGIN(AMDGPULowerKernelAttributes, DEBUG_TYPE, 347fe6060f1SDimitry Andric "AMDGPU Kernel Attributes", false, false) 348fe6060f1SDimitry Andric INITIALIZE_PASS_END(AMDGPULowerKernelAttributes, DEBUG_TYPE, 349fe6060f1SDimitry Andric "AMDGPU Kernel Attributes", false, false) 3500b57cec5SDimitry Andric 3510b57cec5SDimitry Andric char AMDGPULowerKernelAttributes::ID = 0; 3520b57cec5SDimitry Andric 3530b57cec5SDimitry Andric ModulePass *llvm::createAMDGPULowerKernelAttributesPass() { 3540b57cec5SDimitry Andric return new AMDGPULowerKernelAttributes(); 3550b57cec5SDimitry Andric } 356e8d8bef9SDimitry Andric 357e8d8bef9SDimitry Andric PreservedAnalyses 358e8d8bef9SDimitry Andric AMDGPULowerKernelAttributesPass::run(Function &F, FunctionAnalysisManager &AM) { 35906c3fb27SDimitry Andric bool IsV5OrAbove = 3607a6dacacSDimitry Andric AMDGPU::getAMDHSACodeObjectVersion(*F.getParent()) >= AMDGPU::AMDHSA_COV5; 361bdd1243dSDimitry Andric Function *BasePtr = getBasePtrIntrinsic(*F.getParent(), IsV5OrAbove); 362e8d8bef9SDimitry Andric 363bdd1243dSDimitry Andric if (!BasePtr) // ImplicitArgPtr/DispatchPtr not used. 364e8d8bef9SDimitry Andric return PreservedAnalyses::all(); 365e8d8bef9SDimitry Andric 366e8d8bef9SDimitry Andric for (Instruction &I : instructions(F)) { 367e8d8bef9SDimitry Andric if (CallInst *CI = dyn_cast<CallInst>(&I)) { 368bdd1243dSDimitry Andric if (CI->getCalledFunction() == BasePtr) 369bdd1243dSDimitry Andric processUse(CI, IsV5OrAbove); 370e8d8bef9SDimitry Andric } 371e8d8bef9SDimitry Andric } 372e8d8bef9SDimitry Andric 373e8d8bef9SDimitry Andric return PreservedAnalyses::all(); 374e8d8bef9SDimitry Andric } 375