10b57cec5SDimitry Andric //===- AMDGPUAliasAnalysis ------------------------------------------------===// 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 /// \file 90b57cec5SDimitry Andric /// This is the AMGPU address space based alias analysis pass. 100b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 110b57cec5SDimitry Andric 120b57cec5SDimitry Andric #include "AMDGPUAliasAnalysis.h" 130b57cec5SDimitry Andric #include "llvm/Analysis/ValueTracking.h" 14e8d8bef9SDimitry Andric #include "llvm/IR/Instructions.h" 150b57cec5SDimitry Andric 160b57cec5SDimitry Andric using namespace llvm; 170b57cec5SDimitry Andric 180b57cec5SDimitry Andric #define DEBUG_TYPE "amdgpu-aa" 190b57cec5SDimitry Andric 20e8d8bef9SDimitry Andric AnalysisKey AMDGPUAA::Key; 21e8d8bef9SDimitry Andric 220b57cec5SDimitry Andric // Register this pass... 230b57cec5SDimitry Andric char AMDGPUAAWrapperPass::ID = 0; 240b57cec5SDimitry Andric char AMDGPUExternalAAWrapper::ID = 0; 250b57cec5SDimitry Andric 260b57cec5SDimitry Andric INITIALIZE_PASS(AMDGPUAAWrapperPass, "amdgpu-aa", 270b57cec5SDimitry Andric "AMDGPU Address space based Alias Analysis", false, true) 280b57cec5SDimitry Andric 290b57cec5SDimitry Andric INITIALIZE_PASS(AMDGPUExternalAAWrapper, "amdgpu-aa-wrapper", 300b57cec5SDimitry Andric "AMDGPU Address space based Alias Analysis Wrapper", false, true) 310b57cec5SDimitry Andric 320b57cec5SDimitry Andric ImmutablePass *llvm::createAMDGPUAAWrapperPass() { 330b57cec5SDimitry Andric return new AMDGPUAAWrapperPass(); 340b57cec5SDimitry Andric } 350b57cec5SDimitry Andric 360b57cec5SDimitry Andric ImmutablePass *llvm::createAMDGPUExternalAAWrapperPass() { 370b57cec5SDimitry Andric return new AMDGPUExternalAAWrapper(); 380b57cec5SDimitry Andric } 390b57cec5SDimitry Andric 400b57cec5SDimitry Andric void AMDGPUAAWrapperPass::getAnalysisUsage(AnalysisUsage &AU) const { 410b57cec5SDimitry Andric AU.setPreservesAll(); 420b57cec5SDimitry Andric } 430b57cec5SDimitry Andric 440b57cec5SDimitry Andric static AliasResult getAliasResult(unsigned AS1, unsigned AS2) { 450b57cec5SDimitry Andric static_assert(AMDGPUAS::MAX_AMDGPU_ADDRESS <= 7, "Addr space out of range"); 460b57cec5SDimitry Andric 470b57cec5SDimitry Andric if (AS1 > AMDGPUAS::MAX_AMDGPU_ADDRESS || AS2 > AMDGPUAS::MAX_AMDGPU_ADDRESS) 48*fe6060f1SDimitry Andric return AliasResult::MayAlias; 49*fe6060f1SDimitry Andric 50*fe6060f1SDimitry Andric #define ASMay AliasResult::MayAlias 51*fe6060f1SDimitry Andric #define ASNo AliasResult::NoAlias 52*fe6060f1SDimitry Andric // This array is indexed by address space value enum elements 0 ... to 7 53*fe6060f1SDimitry Andric static const AliasResult ASAliasRules[8][8] = { 54*fe6060f1SDimitry Andric /* Flat Global Region Group Constant Private Const32 Buf Fat Ptr */ 55*fe6060f1SDimitry Andric /* Flat */ {ASMay, ASMay, ASNo, ASMay, ASMay, ASMay, ASMay, ASMay}, 56*fe6060f1SDimitry Andric /* Global */ {ASMay, ASMay, ASNo, ASNo, ASMay, ASNo, ASMay, ASMay}, 57*fe6060f1SDimitry Andric /* Region */ {ASNo, ASNo, ASMay, ASNo, ASNo, ASNo, ASNo, ASNo}, 58*fe6060f1SDimitry Andric /* Group */ {ASMay, ASNo, ASNo, ASMay, ASNo, ASNo, ASNo, ASNo}, 59*fe6060f1SDimitry Andric /* Constant */ {ASMay, ASMay, ASNo, ASNo, ASNo, ASNo, ASMay, ASMay}, 60*fe6060f1SDimitry Andric /* Private */ {ASMay, ASNo, ASNo, ASNo, ASNo, ASMay, ASNo, ASNo}, 61*fe6060f1SDimitry Andric /* Constant 32-bit */ {ASMay, ASMay, ASNo, ASNo, ASMay, ASNo, ASNo, ASMay}, 62*fe6060f1SDimitry Andric /* Buffer Fat Ptr */ {ASMay, ASMay, ASNo, ASNo, ASMay, ASNo, ASMay, ASMay} 63*fe6060f1SDimitry Andric }; 64*fe6060f1SDimitry Andric #undef ASMay 65*fe6060f1SDimitry Andric #undef ASNo 660b57cec5SDimitry Andric 670b57cec5SDimitry Andric return ASAliasRules[AS1][AS2]; 680b57cec5SDimitry Andric } 690b57cec5SDimitry Andric 700b57cec5SDimitry Andric AliasResult AMDGPUAAResult::alias(const MemoryLocation &LocA, 710b57cec5SDimitry Andric const MemoryLocation &LocB, 720b57cec5SDimitry Andric AAQueryInfo &AAQI) { 730b57cec5SDimitry Andric unsigned asA = LocA.Ptr->getType()->getPointerAddressSpace(); 740b57cec5SDimitry Andric unsigned asB = LocB.Ptr->getType()->getPointerAddressSpace(); 750b57cec5SDimitry Andric 760b57cec5SDimitry Andric AliasResult Result = getAliasResult(asA, asB); 77*fe6060f1SDimitry Andric if (Result == AliasResult::NoAlias) 780b57cec5SDimitry Andric return Result; 790b57cec5SDimitry Andric 80e8d8bef9SDimitry Andric // In general, FLAT (generic) pointers could be aliased to LOCAL or PRIVATE 81e8d8bef9SDimitry Andric // pointers. However, as LOCAL or PRIVATE pointers point to local objects, in 82e8d8bef9SDimitry Andric // certain cases, it's still viable to check whether a FLAT pointer won't 83e8d8bef9SDimitry Andric // alias to a LOCAL or PRIVATE pointer. 84e8d8bef9SDimitry Andric MemoryLocation A = LocA; 85e8d8bef9SDimitry Andric MemoryLocation B = LocB; 86e8d8bef9SDimitry Andric // Canonicalize the location order to simplify the following alias check. 87e8d8bef9SDimitry Andric if (asA != AMDGPUAS::FLAT_ADDRESS) { 88e8d8bef9SDimitry Andric std::swap(asA, asB); 89e8d8bef9SDimitry Andric std::swap(A, B); 90e8d8bef9SDimitry Andric } 91e8d8bef9SDimitry Andric if (asA == AMDGPUAS::FLAT_ADDRESS && 92e8d8bef9SDimitry Andric (asB == AMDGPUAS::LOCAL_ADDRESS || asB == AMDGPUAS::PRIVATE_ADDRESS)) { 93e8d8bef9SDimitry Andric const auto *ObjA = 94*fe6060f1SDimitry Andric getUnderlyingObject(A.Ptr->stripPointerCastsForAliasAnalysis()); 95e8d8bef9SDimitry Andric if (const LoadInst *LI = dyn_cast<LoadInst>(ObjA)) { 96e8d8bef9SDimitry Andric // If a generic pointer is loaded from the constant address space, it 97e8d8bef9SDimitry Andric // could only be a GLOBAL or CONSTANT one as that address space is soley 98e8d8bef9SDimitry Andric // prepared on the host side, where only GLOBAL or CONSTANT variables are 99e8d8bef9SDimitry Andric // visible. Note that this even holds for regular functions. 100e8d8bef9SDimitry Andric if (LI->getPointerAddressSpace() == AMDGPUAS::CONSTANT_ADDRESS) 101*fe6060f1SDimitry Andric return AliasResult::NoAlias; 102e8d8bef9SDimitry Andric } else if (const Argument *Arg = dyn_cast<Argument>(ObjA)) { 103e8d8bef9SDimitry Andric const Function *F = Arg->getParent(); 104e8d8bef9SDimitry Andric switch (F->getCallingConv()) { 105e8d8bef9SDimitry Andric case CallingConv::AMDGPU_KERNEL: 106e8d8bef9SDimitry Andric // In the kernel function, kernel arguments won't alias to (local) 107e8d8bef9SDimitry Andric // variables in shared or private address space. 108*fe6060f1SDimitry Andric return AliasResult::NoAlias; 109e8d8bef9SDimitry Andric default: 110e8d8bef9SDimitry Andric // TODO: In the regular function, if that local variable in the 111e8d8bef9SDimitry Andric // location B is not captured, that argument pointer won't alias to it 112e8d8bef9SDimitry Andric // as well. 113e8d8bef9SDimitry Andric break; 114e8d8bef9SDimitry Andric } 115e8d8bef9SDimitry Andric } 116e8d8bef9SDimitry Andric } 117e8d8bef9SDimitry Andric 1180b57cec5SDimitry Andric // Forward the query to the next alias analysis. 1190b57cec5SDimitry Andric return AAResultBase::alias(LocA, LocB, AAQI); 1200b57cec5SDimitry Andric } 1210b57cec5SDimitry Andric 1220b57cec5SDimitry Andric bool AMDGPUAAResult::pointsToConstantMemory(const MemoryLocation &Loc, 1230b57cec5SDimitry Andric AAQueryInfo &AAQI, bool OrLocal) { 1245ffd83dbSDimitry Andric unsigned AS = Loc.Ptr->getType()->getPointerAddressSpace(); 1250b57cec5SDimitry Andric if (AS == AMDGPUAS::CONSTANT_ADDRESS || 1265ffd83dbSDimitry Andric AS == AMDGPUAS::CONSTANT_ADDRESS_32BIT) 1270b57cec5SDimitry Andric return true; 1285ffd83dbSDimitry Andric 129e8d8bef9SDimitry Andric const Value *Base = getUnderlyingObject(Loc.Ptr); 1305ffd83dbSDimitry Andric AS = Base->getType()->getPointerAddressSpace(); 1315ffd83dbSDimitry Andric if (AS == AMDGPUAS::CONSTANT_ADDRESS || 1325ffd83dbSDimitry Andric AS == AMDGPUAS::CONSTANT_ADDRESS_32BIT) 1335ffd83dbSDimitry Andric return true; 1340b57cec5SDimitry Andric 1350b57cec5SDimitry Andric if (const GlobalVariable *GV = dyn_cast<GlobalVariable>(Base)) { 1360b57cec5SDimitry Andric if (GV->isConstant()) 1370b57cec5SDimitry Andric return true; 1380b57cec5SDimitry Andric } else if (const Argument *Arg = dyn_cast<Argument>(Base)) { 1390b57cec5SDimitry Andric const Function *F = Arg->getParent(); 1400b57cec5SDimitry Andric 1410b57cec5SDimitry Andric // Only assume constant memory for arguments on kernels. 1420b57cec5SDimitry Andric switch (F->getCallingConv()) { 1430b57cec5SDimitry Andric default: 1440b57cec5SDimitry Andric return AAResultBase::pointsToConstantMemory(Loc, AAQI, OrLocal); 1450b57cec5SDimitry Andric case CallingConv::AMDGPU_LS: 1460b57cec5SDimitry Andric case CallingConv::AMDGPU_HS: 1470b57cec5SDimitry Andric case CallingConv::AMDGPU_ES: 1480b57cec5SDimitry Andric case CallingConv::AMDGPU_GS: 1490b57cec5SDimitry Andric case CallingConv::AMDGPU_VS: 1500b57cec5SDimitry Andric case CallingConv::AMDGPU_PS: 1510b57cec5SDimitry Andric case CallingConv::AMDGPU_CS: 1520b57cec5SDimitry Andric case CallingConv::AMDGPU_KERNEL: 1530b57cec5SDimitry Andric case CallingConv::SPIR_KERNEL: 1540b57cec5SDimitry Andric break; 1550b57cec5SDimitry Andric } 1560b57cec5SDimitry Andric 1570b57cec5SDimitry Andric unsigned ArgNo = Arg->getArgNo(); 1580b57cec5SDimitry Andric /* On an argument, ReadOnly attribute indicates that the function does 1590b57cec5SDimitry Andric not write through this pointer argument, even though it may write 1600b57cec5SDimitry Andric to the memory that the pointer points to. 1610b57cec5SDimitry Andric On an argument, ReadNone attribute indicates that the function does 1620b57cec5SDimitry Andric not dereference that pointer argument, even though it may read or write 1630b57cec5SDimitry Andric the memory that the pointer points to if accessed through other pointers. 1640b57cec5SDimitry Andric */ 1650b57cec5SDimitry Andric if (F->hasParamAttribute(ArgNo, Attribute::NoAlias) && 1660b57cec5SDimitry Andric (F->hasParamAttribute(ArgNo, Attribute::ReadNone) || 1670b57cec5SDimitry Andric F->hasParamAttribute(ArgNo, Attribute::ReadOnly))) { 1680b57cec5SDimitry Andric return true; 1690b57cec5SDimitry Andric } 1700b57cec5SDimitry Andric } 1710b57cec5SDimitry Andric return AAResultBase::pointsToConstantMemory(Loc, AAQI, OrLocal); 1720b57cec5SDimitry Andric } 173