xref: /freebsd/contrib/llvm-project/llvm/lib/Target/AMDGPU/AMDGPUAliasAnalysis.cpp (revision 0b57cec536236d46e3dba9bd041533462f33dbb7)
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