1 //===- AMDGPUAliasAnalysis ------------------------------------------------===// 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 /// \file 9 /// This is the AMGPU address space based alias analysis pass. 10 //===----------------------------------------------------------------------===// 11 12 #include "AMDGPUAliasAnalysis.h" 13 #include "AMDGPU.h" 14 #include "llvm/Analysis/ValueTracking.h" 15 #include "llvm/IR/Instructions.h" 16 17 using namespace llvm; 18 19 #define DEBUG_TYPE "amdgpu-aa" 20 21 AnalysisKey AMDGPUAA::Key; 22 23 // Register this pass... 24 char AMDGPUAAWrapperPass::ID = 0; 25 char AMDGPUExternalAAWrapper::ID = 0; 26 27 INITIALIZE_PASS(AMDGPUAAWrapperPass, "amdgpu-aa", 28 "AMDGPU Address space based Alias Analysis", false, true) 29 30 INITIALIZE_PASS(AMDGPUExternalAAWrapper, "amdgpu-aa-wrapper", 31 "AMDGPU Address space based Alias Analysis Wrapper", false, true) 32 33 ImmutablePass *llvm::createAMDGPUAAWrapperPass() { 34 return new AMDGPUAAWrapperPass(); 35 } 36 37 ImmutablePass *llvm::createAMDGPUExternalAAWrapperPass() { 38 return new AMDGPUExternalAAWrapper(); 39 } 40 41 AMDGPUAAWrapperPass::AMDGPUAAWrapperPass() : ImmutablePass(ID) { 42 initializeAMDGPUAAWrapperPassPass(*PassRegistry::getPassRegistry()); 43 } 44 45 void AMDGPUAAWrapperPass::getAnalysisUsage(AnalysisUsage &AU) const { 46 AU.setPreservesAll(); 47 } 48 49 static AliasResult getAliasResult(unsigned AS1, unsigned AS2) { 50 static_assert(AMDGPUAS::MAX_AMDGPU_ADDRESS <= 7, "Addr space out of range"); 51 52 if (AS1 > AMDGPUAS::MAX_AMDGPU_ADDRESS || AS2 > AMDGPUAS::MAX_AMDGPU_ADDRESS) 53 return AliasResult::MayAlias; 54 55 #define ASMay AliasResult::MayAlias 56 #define ASNo AliasResult::NoAlias 57 // This array is indexed by address space value enum elements 0 ... to 7 58 static const AliasResult ASAliasRules[8][8] = { 59 /* Flat Global Region Group Constant Private Const32 Buf Fat Ptr */ 60 /* Flat */ {ASMay, ASMay, ASNo, ASMay, ASMay, ASMay, ASMay, ASMay}, 61 /* Global */ {ASMay, ASMay, ASNo, ASNo, ASMay, ASNo, ASMay, ASMay}, 62 /* Region */ {ASNo, ASNo, ASMay, ASNo, ASNo, ASNo, ASNo, ASNo}, 63 /* Group */ {ASMay, ASNo, ASNo, ASMay, ASNo, ASNo, ASNo, ASNo}, 64 /* Constant */ {ASMay, ASMay, ASNo, ASNo, ASNo, ASNo, ASMay, ASMay}, 65 /* Private */ {ASMay, ASNo, ASNo, ASNo, ASNo, ASMay, ASNo, ASNo}, 66 /* Constant 32-bit */ {ASMay, ASMay, ASNo, ASNo, ASMay, ASNo, ASNo, ASMay}, 67 /* Buffer Fat Ptr */ {ASMay, ASMay, ASNo, ASNo, ASMay, ASNo, ASMay, ASMay} 68 }; 69 #undef ASMay 70 #undef ASNo 71 72 return ASAliasRules[AS1][AS2]; 73 } 74 75 AliasResult AMDGPUAAResult::alias(const MemoryLocation &LocA, 76 const MemoryLocation &LocB, AAQueryInfo &AAQI, 77 const Instruction *) { 78 unsigned asA = LocA.Ptr->getType()->getPointerAddressSpace(); 79 unsigned asB = LocB.Ptr->getType()->getPointerAddressSpace(); 80 81 AliasResult Result = getAliasResult(asA, asB); 82 if (Result == AliasResult::NoAlias) 83 return Result; 84 85 // In general, FLAT (generic) pointers could be aliased to LOCAL or PRIVATE 86 // pointers. However, as LOCAL or PRIVATE pointers point to local objects, in 87 // certain cases, it's still viable to check whether a FLAT pointer won't 88 // alias to a LOCAL or PRIVATE pointer. 89 MemoryLocation A = LocA; 90 MemoryLocation B = LocB; 91 // Canonicalize the location order to simplify the following alias check. 92 if (asA != AMDGPUAS::FLAT_ADDRESS) { 93 std::swap(asA, asB); 94 std::swap(A, B); 95 } 96 if (asA == AMDGPUAS::FLAT_ADDRESS && 97 (asB == AMDGPUAS::LOCAL_ADDRESS || asB == AMDGPUAS::PRIVATE_ADDRESS)) { 98 const auto *ObjA = 99 getUnderlyingObject(A.Ptr->stripPointerCastsForAliasAnalysis()); 100 if (const LoadInst *LI = dyn_cast<LoadInst>(ObjA)) { 101 // If a generic pointer is loaded from the constant address space, it 102 // could only be a GLOBAL or CONSTANT one as that address space is solely 103 // prepared on the host side, where only GLOBAL or CONSTANT variables are 104 // visible. Note that this even holds for regular functions. 105 if (LI->getPointerAddressSpace() == AMDGPUAS::CONSTANT_ADDRESS) 106 return AliasResult::NoAlias; 107 } else if (const Argument *Arg = dyn_cast<Argument>(ObjA)) { 108 const Function *F = Arg->getParent(); 109 switch (F->getCallingConv()) { 110 case CallingConv::AMDGPU_KERNEL: 111 // In the kernel function, kernel arguments won't alias to (local) 112 // variables in shared or private address space. 113 return AliasResult::NoAlias; 114 default: 115 // TODO: In the regular function, if that local variable in the 116 // location B is not captured, that argument pointer won't alias to it 117 // as well. 118 break; 119 } 120 } 121 } 122 123 // Forward the query to the next alias analysis. 124 return AAResultBase::alias(LocA, LocB, AAQI, nullptr); 125 } 126 127 ModRefInfo AMDGPUAAResult::getModRefInfoMask(const MemoryLocation &Loc, 128 AAQueryInfo &AAQI, 129 bool IgnoreLocals) { 130 unsigned AS = Loc.Ptr->getType()->getPointerAddressSpace(); 131 if (AS == AMDGPUAS::CONSTANT_ADDRESS || 132 AS == AMDGPUAS::CONSTANT_ADDRESS_32BIT) 133 return ModRefInfo::NoModRef; 134 135 const Value *Base = getUnderlyingObject(Loc.Ptr); 136 AS = Base->getType()->getPointerAddressSpace(); 137 if (AS == AMDGPUAS::CONSTANT_ADDRESS || 138 AS == AMDGPUAS::CONSTANT_ADDRESS_32BIT) 139 return ModRefInfo::NoModRef; 140 141 return AAResultBase::getModRefInfoMask(Loc, AAQI, IgnoreLocals); 142 } 143