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