1*0b57cec5SDimitry Andric //===- AMDGPUAliasAnalysis ------------------------------------------------===// 2*0b57cec5SDimitry Andric // 3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0b57cec5SDimitry Andric // 7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 8*0b57cec5SDimitry Andric /// \file 9*0b57cec5SDimitry Andric /// This is the AMGPU address space based alias analysis pass. 10*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 11*0b57cec5SDimitry Andric 12*0b57cec5SDimitry Andric #include "AMDGPUAliasAnalysis.h" 13*0b57cec5SDimitry Andric #include "AMDGPU.h" 14*0b57cec5SDimitry Andric #include "llvm/ADT/Triple.h" 15*0b57cec5SDimitry Andric #include "llvm/Analysis/AliasAnalysis.h" 16*0b57cec5SDimitry Andric #include "llvm/Analysis/MemoryLocation.h" 17*0b57cec5SDimitry Andric #include "llvm/Analysis/ValueTracking.h" 18*0b57cec5SDimitry Andric #include "llvm/IR/Argument.h" 19*0b57cec5SDimitry Andric #include "llvm/IR/Attributes.h" 20*0b57cec5SDimitry Andric #include "llvm/IR/CallingConv.h" 21*0b57cec5SDimitry Andric #include "llvm/IR/Function.h" 22*0b57cec5SDimitry Andric #include "llvm/IR/GlobalVariable.h" 23*0b57cec5SDimitry Andric #include "llvm/IR/Type.h" 24*0b57cec5SDimitry Andric #include "llvm/IR/Value.h" 25*0b57cec5SDimitry Andric #include "llvm/Pass.h" 26*0b57cec5SDimitry Andric #include "llvm/Support/Casting.h" 27*0b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h" 28*0b57cec5SDimitry Andric #include <cassert> 29*0b57cec5SDimitry Andric 30*0b57cec5SDimitry Andric using namespace llvm; 31*0b57cec5SDimitry Andric 32*0b57cec5SDimitry Andric #define DEBUG_TYPE "amdgpu-aa" 33*0b57cec5SDimitry Andric 34*0b57cec5SDimitry Andric // Register this pass... 35*0b57cec5SDimitry Andric char AMDGPUAAWrapperPass::ID = 0; 36*0b57cec5SDimitry Andric char AMDGPUExternalAAWrapper::ID = 0; 37*0b57cec5SDimitry Andric 38*0b57cec5SDimitry Andric INITIALIZE_PASS(AMDGPUAAWrapperPass, "amdgpu-aa", 39*0b57cec5SDimitry Andric "AMDGPU Address space based Alias Analysis", false, true) 40*0b57cec5SDimitry Andric 41*0b57cec5SDimitry Andric INITIALIZE_PASS(AMDGPUExternalAAWrapper, "amdgpu-aa-wrapper", 42*0b57cec5SDimitry Andric "AMDGPU Address space based Alias Analysis Wrapper", false, true) 43*0b57cec5SDimitry Andric 44*0b57cec5SDimitry Andric ImmutablePass *llvm::createAMDGPUAAWrapperPass() { 45*0b57cec5SDimitry Andric return new AMDGPUAAWrapperPass(); 46*0b57cec5SDimitry Andric } 47*0b57cec5SDimitry Andric 48*0b57cec5SDimitry Andric ImmutablePass *llvm::createAMDGPUExternalAAWrapperPass() { 49*0b57cec5SDimitry Andric return new AMDGPUExternalAAWrapper(); 50*0b57cec5SDimitry Andric } 51*0b57cec5SDimitry Andric 52*0b57cec5SDimitry Andric void AMDGPUAAWrapperPass::getAnalysisUsage(AnalysisUsage &AU) const { 53*0b57cec5SDimitry Andric AU.setPreservesAll(); 54*0b57cec5SDimitry Andric } 55*0b57cec5SDimitry Andric 56*0b57cec5SDimitry Andric // These arrays are indexed by address space value enum elements 0 ... to 7 57*0b57cec5SDimitry Andric static const AliasResult ASAliasRules[8][8] = { 58*0b57cec5SDimitry Andric /* Flat Global Region Group Constant Private Constant 32-bit Buffer Fat Ptr */ 59*0b57cec5SDimitry Andric /* Flat */ {MayAlias, MayAlias, NoAlias, MayAlias, MayAlias, MayAlias, MayAlias, MayAlias}, 60*0b57cec5SDimitry Andric /* Global */ {MayAlias, MayAlias, NoAlias , NoAlias , MayAlias, NoAlias , MayAlias, MayAlias}, 61*0b57cec5SDimitry Andric /* Region */ {NoAlias, NoAlias , MayAlias, NoAlias , NoAlias, NoAlias , NoAlias, NoAlias}, 62*0b57cec5SDimitry Andric /* Group */ {MayAlias, NoAlias , NoAlias , MayAlias, NoAlias , NoAlias , NoAlias , NoAlias}, 63*0b57cec5SDimitry Andric /* Constant */ {MayAlias, MayAlias, NoAlias, NoAlias , NoAlias , NoAlias , MayAlias, MayAlias}, 64*0b57cec5SDimitry Andric /* Private */ {MayAlias, NoAlias , NoAlias , NoAlias , NoAlias , MayAlias, NoAlias , NoAlias}, 65*0b57cec5SDimitry Andric /* Constant 32-bit */ {MayAlias, MayAlias, NoAlias, NoAlias , MayAlias, NoAlias , NoAlias , MayAlias}, 66*0b57cec5SDimitry Andric /* Buffer Fat Ptr */ {MayAlias, MayAlias, NoAlias , NoAlias , MayAlias, NoAlias , MayAlias, MayAlias} 67*0b57cec5SDimitry Andric }; 68*0b57cec5SDimitry Andric 69*0b57cec5SDimitry Andric static AliasResult getAliasResult(unsigned AS1, unsigned AS2) { 70*0b57cec5SDimitry Andric static_assert(AMDGPUAS::MAX_AMDGPU_ADDRESS <= 7, "Addr space out of range"); 71*0b57cec5SDimitry Andric 72*0b57cec5SDimitry Andric if (AS1 > AMDGPUAS::MAX_AMDGPU_ADDRESS || AS2 > AMDGPUAS::MAX_AMDGPU_ADDRESS) 73*0b57cec5SDimitry Andric return MayAlias; 74*0b57cec5SDimitry Andric 75*0b57cec5SDimitry Andric return ASAliasRules[AS1][AS2]; 76*0b57cec5SDimitry Andric } 77*0b57cec5SDimitry Andric 78*0b57cec5SDimitry Andric AliasResult AMDGPUAAResult::alias(const MemoryLocation &LocA, 79*0b57cec5SDimitry Andric const MemoryLocation &LocB, 80*0b57cec5SDimitry Andric AAQueryInfo &AAQI) { 81*0b57cec5SDimitry Andric unsigned asA = LocA.Ptr->getType()->getPointerAddressSpace(); 82*0b57cec5SDimitry Andric unsigned asB = LocB.Ptr->getType()->getPointerAddressSpace(); 83*0b57cec5SDimitry Andric 84*0b57cec5SDimitry Andric AliasResult Result = getAliasResult(asA, asB); 85*0b57cec5SDimitry Andric if (Result == NoAlias) 86*0b57cec5SDimitry Andric return Result; 87*0b57cec5SDimitry Andric 88*0b57cec5SDimitry Andric // Forward the query to the next alias analysis. 89*0b57cec5SDimitry Andric return AAResultBase::alias(LocA, LocB, AAQI); 90*0b57cec5SDimitry Andric } 91*0b57cec5SDimitry Andric 92*0b57cec5SDimitry Andric bool AMDGPUAAResult::pointsToConstantMemory(const MemoryLocation &Loc, 93*0b57cec5SDimitry Andric AAQueryInfo &AAQI, bool OrLocal) { 94*0b57cec5SDimitry Andric const Value *Base = GetUnderlyingObject(Loc.Ptr, DL); 95*0b57cec5SDimitry Andric unsigned AS = Base->getType()->getPointerAddressSpace(); 96*0b57cec5SDimitry Andric if (AS == AMDGPUAS::CONSTANT_ADDRESS || 97*0b57cec5SDimitry Andric AS == AMDGPUAS::CONSTANT_ADDRESS_32BIT) { 98*0b57cec5SDimitry Andric return true; 99*0b57cec5SDimitry Andric } 100*0b57cec5SDimitry Andric 101*0b57cec5SDimitry Andric if (const GlobalVariable *GV = dyn_cast<GlobalVariable>(Base)) { 102*0b57cec5SDimitry Andric if (GV->isConstant()) 103*0b57cec5SDimitry Andric return true; 104*0b57cec5SDimitry Andric } else if (const Argument *Arg = dyn_cast<Argument>(Base)) { 105*0b57cec5SDimitry Andric const Function *F = Arg->getParent(); 106*0b57cec5SDimitry Andric 107*0b57cec5SDimitry Andric // Only assume constant memory for arguments on kernels. 108*0b57cec5SDimitry Andric switch (F->getCallingConv()) { 109*0b57cec5SDimitry Andric default: 110*0b57cec5SDimitry Andric return AAResultBase::pointsToConstantMemory(Loc, AAQI, OrLocal); 111*0b57cec5SDimitry Andric case CallingConv::AMDGPU_LS: 112*0b57cec5SDimitry Andric case CallingConv::AMDGPU_HS: 113*0b57cec5SDimitry Andric case CallingConv::AMDGPU_ES: 114*0b57cec5SDimitry Andric case CallingConv::AMDGPU_GS: 115*0b57cec5SDimitry Andric case CallingConv::AMDGPU_VS: 116*0b57cec5SDimitry Andric case CallingConv::AMDGPU_PS: 117*0b57cec5SDimitry Andric case CallingConv::AMDGPU_CS: 118*0b57cec5SDimitry Andric case CallingConv::AMDGPU_KERNEL: 119*0b57cec5SDimitry Andric case CallingConv::SPIR_KERNEL: 120*0b57cec5SDimitry Andric break; 121*0b57cec5SDimitry Andric } 122*0b57cec5SDimitry Andric 123*0b57cec5SDimitry Andric unsigned ArgNo = Arg->getArgNo(); 124*0b57cec5SDimitry Andric /* On an argument, ReadOnly attribute indicates that the function does 125*0b57cec5SDimitry Andric not write through this pointer argument, even though it may write 126*0b57cec5SDimitry Andric to the memory that the pointer points to. 127*0b57cec5SDimitry Andric On an argument, ReadNone attribute indicates that the function does 128*0b57cec5SDimitry Andric not dereference that pointer argument, even though it may read or write 129*0b57cec5SDimitry Andric the memory that the pointer points to if accessed through other pointers. 130*0b57cec5SDimitry Andric */ 131*0b57cec5SDimitry Andric if (F->hasParamAttribute(ArgNo, Attribute::NoAlias) && 132*0b57cec5SDimitry Andric (F->hasParamAttribute(ArgNo, Attribute::ReadNone) || 133*0b57cec5SDimitry Andric F->hasParamAttribute(ArgNo, Attribute::ReadOnly))) { 134*0b57cec5SDimitry Andric return true; 135*0b57cec5SDimitry Andric } 136*0b57cec5SDimitry Andric } 137*0b57cec5SDimitry Andric return AAResultBase::pointsToConstantMemory(Loc, AAQI, OrLocal); 138*0b57cec5SDimitry Andric } 139