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/ADT/Triple.h"
15 #include "llvm/Analysis/AliasAnalysis.h"
16 #include "llvm/Analysis/MemoryLocation.h"
17 #include "llvm/Analysis/ValueTracking.h"
18 #include "llvm/IR/Argument.h"
19 #include "llvm/IR/Attributes.h"
20 #include "llvm/IR/CallingConv.h"
21 #include "llvm/IR/Function.h"
22 #include "llvm/IR/GlobalVariable.h"
23 #include "llvm/IR/Type.h"
24 #include "llvm/IR/Value.h"
25 #include "llvm/Pass.h"
26 #include "llvm/Support/Casting.h"
27 #include "llvm/Support/ErrorHandling.h"
28 #include <cassert>
29 
30 using namespace llvm;
31 
32 #define DEBUG_TYPE "amdgpu-aa"
33 
34 // Register this pass...
35 char AMDGPUAAWrapperPass::ID = 0;
36 char AMDGPUExternalAAWrapper::ID = 0;
37 
38 INITIALIZE_PASS(AMDGPUAAWrapperPass, "amdgpu-aa",
39                 "AMDGPU Address space based Alias Analysis", false, true)
40 
41 INITIALIZE_PASS(AMDGPUExternalAAWrapper, "amdgpu-aa-wrapper",
42                 "AMDGPU Address space based Alias Analysis Wrapper", false, true)
43 
createAMDGPUAAWrapperPass()44 ImmutablePass *llvm::createAMDGPUAAWrapperPass() {
45   return new AMDGPUAAWrapperPass();
46 }
47 
createAMDGPUExternalAAWrapperPass()48 ImmutablePass *llvm::createAMDGPUExternalAAWrapperPass() {
49   return new AMDGPUExternalAAWrapper();
50 }
51 
getAnalysisUsage(AnalysisUsage & AU) const52 void AMDGPUAAWrapperPass::getAnalysisUsage(AnalysisUsage &AU) const {
53   AU.setPreservesAll();
54 }
55 
56 // These arrays are indexed by address space value enum elements 0 ... to 7
57 static const AliasResult ASAliasRules[8][8] = {
58   /*                    Flat       Global    Region    Group     Constant  Private   Constant 32-bit  Buffer Fat Ptr */
59   /* Flat     */        {MayAlias, MayAlias, NoAlias,  MayAlias, MayAlias, MayAlias, MayAlias,        MayAlias},
60   /* Global   */        {MayAlias, MayAlias, NoAlias , NoAlias , MayAlias, NoAlias , MayAlias,        MayAlias},
61   /* Region   */        {NoAlias,  NoAlias , MayAlias, NoAlias , NoAlias,  NoAlias , NoAlias,         NoAlias},
62   /* Group    */        {MayAlias, NoAlias , NoAlias , MayAlias, NoAlias , NoAlias , NoAlias ,        NoAlias},
63   /* Constant */        {MayAlias, MayAlias, NoAlias,  NoAlias , NoAlias , NoAlias , MayAlias,        MayAlias},
64   /* Private  */        {MayAlias, NoAlias , NoAlias , NoAlias , NoAlias , MayAlias, NoAlias ,        NoAlias},
65   /* Constant 32-bit */ {MayAlias, MayAlias, NoAlias,  NoAlias , MayAlias, NoAlias , NoAlias ,        MayAlias},
66   /* Buffer Fat Ptr  */ {MayAlias, MayAlias, NoAlias , NoAlias , MayAlias, NoAlias , MayAlias,        MayAlias}
67 };
68 
getAliasResult(unsigned AS1,unsigned AS2)69 static AliasResult getAliasResult(unsigned AS1, unsigned AS2) {
70   static_assert(AMDGPUAS::MAX_AMDGPU_ADDRESS <= 7, "Addr space out of range");
71 
72   if (AS1 > AMDGPUAS::MAX_AMDGPU_ADDRESS || AS2 > AMDGPUAS::MAX_AMDGPU_ADDRESS)
73     return MayAlias;
74 
75   return ASAliasRules[AS1][AS2];
76 }
77 
alias(const MemoryLocation & LocA,const MemoryLocation & LocB,AAQueryInfo & AAQI)78 AliasResult AMDGPUAAResult::alias(const MemoryLocation &LocA,
79                                   const MemoryLocation &LocB,
80                                   AAQueryInfo &AAQI) {
81   unsigned asA = LocA.Ptr->getType()->getPointerAddressSpace();
82   unsigned asB = LocB.Ptr->getType()->getPointerAddressSpace();
83 
84   AliasResult Result = getAliasResult(asA, asB);
85   if (Result == NoAlias)
86     return Result;
87 
88   // In general, FLAT (generic) pointers could be aliased to LOCAL or PRIVATE
89   // pointers. However, as LOCAL or PRIVATE pointers point to local objects, in
90   // certain cases, it's still viable to check whether a FLAT pointer won't
91   // alias to a LOCAL or PRIVATE pointer.
92   MemoryLocation A = LocA;
93   MemoryLocation B = LocB;
94   // Canonicalize the location order to simplify the following alias check.
95   if (asA != AMDGPUAS::FLAT_ADDRESS) {
96     std::swap(asA, asB);
97     std::swap(A, B);
98   }
99   if (asA == AMDGPUAS::FLAT_ADDRESS &&
100       (asB == AMDGPUAS::LOCAL_ADDRESS || asB == AMDGPUAS::PRIVATE_ADDRESS)) {
101     const auto *ObjA =
102         getUnderlyingObject(A.Ptr->stripPointerCastsAndInvariantGroups());
103     if (const LoadInst *LI = dyn_cast<LoadInst>(ObjA)) {
104       // If a generic pointer is loaded from the constant address space, it
105       // could only be a GLOBAL or CONSTANT one as that address space is soley
106       // prepared on the host side, where only GLOBAL or CONSTANT variables are
107       // visible. Note that this even holds for regular functions.
108       if (LI->getPointerAddressSpace() == AMDGPUAS::CONSTANT_ADDRESS)
109         return NoAlias;
110     } else if (const Argument *Arg = dyn_cast<Argument>(ObjA)) {
111       const Function *F = Arg->getParent();
112       switch (F->getCallingConv()) {
113       case CallingConv::AMDGPU_KERNEL:
114         // In the kernel function, kernel arguments won't alias to (local)
115         // variables in shared or private address space.
116         return NoAlias;
117       default:
118         // TODO: In the regular function, if that local variable in the
119         // location B is not captured, that argument pointer won't alias to it
120         // as well.
121         break;
122       }
123     }
124   }
125 
126   // Forward the query to the next alias analysis.
127   return AAResultBase::alias(LocA, LocB, AAQI);
128 }
129 
pointsToConstantMemory(const MemoryLocation & Loc,AAQueryInfo & AAQI,bool OrLocal)130 bool AMDGPUAAResult::pointsToConstantMemory(const MemoryLocation &Loc,
131                                             AAQueryInfo &AAQI, bool OrLocal) {
132   unsigned AS = Loc.Ptr->getType()->getPointerAddressSpace();
133   if (AS == AMDGPUAS::CONSTANT_ADDRESS ||
134       AS == AMDGPUAS::CONSTANT_ADDRESS_32BIT)
135     return true;
136 
137   const Value *Base = getUnderlyingObject(Loc.Ptr);
138   AS = Base->getType()->getPointerAddressSpace();
139   if (AS == AMDGPUAS::CONSTANT_ADDRESS ||
140       AS == AMDGPUAS::CONSTANT_ADDRESS_32BIT)
141     return true;
142 
143   if (const GlobalVariable *GV = dyn_cast<GlobalVariable>(Base)) {
144     if (GV->isConstant())
145       return true;
146   } else if (const Argument *Arg = dyn_cast<Argument>(Base)) {
147     const Function *F = Arg->getParent();
148 
149     // Only assume constant memory for arguments on kernels.
150     switch (F->getCallingConv()) {
151     default:
152       return AAResultBase::pointsToConstantMemory(Loc, AAQI, OrLocal);
153     case CallingConv::AMDGPU_LS:
154     case CallingConv::AMDGPU_HS:
155     case CallingConv::AMDGPU_ES:
156     case CallingConv::AMDGPU_GS:
157     case CallingConv::AMDGPU_VS:
158     case CallingConv::AMDGPU_PS:
159     case CallingConv::AMDGPU_CS:
160     case CallingConv::AMDGPU_KERNEL:
161     case CallingConv::SPIR_KERNEL:
162       break;
163     }
164 
165     unsigned ArgNo = Arg->getArgNo();
166     /* On an argument, ReadOnly attribute indicates that the function does
167        not write through this pointer argument, even though it may write
168        to the memory that the pointer points to.
169        On an argument, ReadNone attribute indicates that the function does
170        not dereference that pointer argument, even though it may read or write
171        the memory that the pointer points to if accessed through other pointers.
172      */
173     if (F->hasParamAttribute(ArgNo, Attribute::NoAlias) &&
174         (F->hasParamAttribute(ArgNo, Attribute::ReadNone) ||
175          F->hasParamAttribute(ArgNo, Attribute::ReadOnly))) {
176       return true;
177     }
178   }
179   return AAResultBase::pointsToConstantMemory(Loc, AAQI, OrLocal);
180 }
181