12cab237bSDimitry Andric //===- AMDGPUAliasAnalysis ------------------------------------------------===//
27a7e6055SDimitry Andric //
37a7e6055SDimitry Andric //                     The LLVM Compiler Infrastructure
47a7e6055SDimitry Andric //
57a7e6055SDimitry Andric // This file is distributed under the University of Illinois Open Source
67a7e6055SDimitry Andric // License. See LICENSE.TXT for details.
77a7e6055SDimitry Andric //
87a7e6055SDimitry Andric //===----------------------------------------------------------------------===//
97a7e6055SDimitry Andric /// \file
107a7e6055SDimitry Andric /// This is the AMGPU address space based alias analysis pass.
117a7e6055SDimitry Andric //===----------------------------------------------------------------------===//
127a7e6055SDimitry Andric 
137a7e6055SDimitry Andric #include "AMDGPUAliasAnalysis.h"
14db17bf38SDimitry Andric #include "AMDGPU.h"
152cab237bSDimitry Andric #include "llvm/ADT/Triple.h"
167a7e6055SDimitry Andric #include "llvm/Analysis/AliasAnalysis.h"
172cab237bSDimitry Andric #include "llvm/Analysis/MemoryLocation.h"
18db17bf38SDimitry Andric #include "llvm/Analysis/ValueTracking.h"
192cab237bSDimitry Andric #include "llvm/IR/Argument.h"
202cab237bSDimitry Andric #include "llvm/IR/Attributes.h"
212cab237bSDimitry Andric #include "llvm/IR/CallingConv.h"
227a7e6055SDimitry Andric #include "llvm/IR/Function.h"
232cab237bSDimitry Andric #include "llvm/IR/GlobalVariable.h"
242cab237bSDimitry Andric #include "llvm/IR/Type.h"
252cab237bSDimitry Andric #include "llvm/IR/Value.h"
267a7e6055SDimitry Andric #include "llvm/Pass.h"
272cab237bSDimitry Andric #include "llvm/Support/Casting.h"
282cab237bSDimitry Andric #include "llvm/Support/ErrorHandling.h"
292cab237bSDimitry Andric #include <cassert>
307a7e6055SDimitry Andric 
317a7e6055SDimitry Andric using namespace llvm;
327a7e6055SDimitry Andric 
337a7e6055SDimitry Andric #define DEBUG_TYPE "amdgpu-aa"
347a7e6055SDimitry Andric 
357a7e6055SDimitry Andric // Register this pass...
367a7e6055SDimitry Andric char AMDGPUAAWrapperPass::ID = 0;
37*b5893f02SDimitry Andric char AMDGPUExternalAAWrapper::ID = 0;
382cab237bSDimitry Andric 
397a7e6055SDimitry Andric INITIALIZE_PASS(AMDGPUAAWrapperPass, "amdgpu-aa",
407a7e6055SDimitry Andric                 "AMDGPU Address space based Alias Analysis", false, true)
417a7e6055SDimitry Andric 
42*b5893f02SDimitry Andric INITIALIZE_PASS(AMDGPUExternalAAWrapper, "amdgpu-aa-wrapper",
43*b5893f02SDimitry Andric                 "AMDGPU Address space based Alias Analysis Wrapper", false, true)
44*b5893f02SDimitry Andric 
createAMDGPUAAWrapperPass()457a7e6055SDimitry Andric ImmutablePass *llvm::createAMDGPUAAWrapperPass() {
467a7e6055SDimitry Andric   return new AMDGPUAAWrapperPass();
477a7e6055SDimitry Andric }
487a7e6055SDimitry Andric 
createAMDGPUExternalAAWrapperPass()49*b5893f02SDimitry Andric ImmutablePass *llvm::createAMDGPUExternalAAWrapperPass() {
50*b5893f02SDimitry Andric   return new AMDGPUExternalAAWrapper();
51*b5893f02SDimitry Andric }
52*b5893f02SDimitry Andric 
getAnalysisUsage(AnalysisUsage & AU) const537a7e6055SDimitry Andric void AMDGPUAAWrapperPass::getAnalysisUsage(AnalysisUsage &AU) const {
547a7e6055SDimitry Andric   AU.setPreservesAll();
557a7e6055SDimitry Andric }
567a7e6055SDimitry Andric 
57*b5893f02SDimitry Andric // These arrays are indexed by address space value enum elements 0 ... to 6
58*b5893f02SDimitry Andric static const AliasResult ASAliasRules[7][7] = {
594ba319b5SDimitry Andric   /*                    Flat       Global    Region    Group     Constant  Private   Constant 32-bit */
604ba319b5SDimitry Andric   /* Flat     */        {MayAlias, MayAlias, MayAlias, MayAlias, MayAlias, MayAlias, MayAlias},
614ba319b5SDimitry Andric   /* Global   */        {MayAlias, MayAlias, NoAlias , NoAlias , MayAlias, NoAlias , MayAlias},
624ba319b5SDimitry Andric   /* Region   */        {MayAlias, NoAlias , NoAlias , NoAlias,  MayAlias, NoAlias , MayAlias},
634ba319b5SDimitry Andric   /* Group    */        {MayAlias, NoAlias , NoAlias , MayAlias, NoAlias , NoAlias , NoAlias},
644ba319b5SDimitry Andric   /* Constant */        {MayAlias, MayAlias, MayAlias, NoAlias , NoAlias,  NoAlias , MayAlias},
654ba319b5SDimitry Andric   /* Private  */        {MayAlias, NoAlias , NoAlias , NoAlias , NoAlias , MayAlias, NoAlias},
664ba319b5SDimitry Andric   /* Constant 32-bit */ {MayAlias, MayAlias, MayAlias, NoAlias , MayAlias, NoAlias , NoAlias}
677a7e6055SDimitry Andric };
68*b5893f02SDimitry Andric 
getAliasResult(unsigned AS1,unsigned AS2)69*b5893f02SDimitry Andric static AliasResult getAliasResult(unsigned AS1, unsigned AS2) {
704ba319b5SDimitry Andric   static_assert(AMDGPUAS::MAX_AMDGPU_ADDRESS <= 6, "Addr space out of range");
717a7e6055SDimitry Andric 
72*b5893f02SDimitry Andric   if (AS1 > AMDGPUAS::MAX_AMDGPU_ADDRESS || AS2 > AMDGPUAS::MAX_AMDGPU_ADDRESS)
73*b5893f02SDimitry Andric     return MayAlias;
747a7e6055SDimitry Andric 
75*b5893f02SDimitry Andric   return ASAliasRules[AS1][AS2];
767a7e6055SDimitry Andric }
777a7e6055SDimitry Andric 
alias(const MemoryLocation & LocA,const MemoryLocation & LocB)787a7e6055SDimitry Andric AliasResult AMDGPUAAResult::alias(const MemoryLocation &LocA,
797a7e6055SDimitry Andric                                   const MemoryLocation &LocB) {
807a7e6055SDimitry Andric   unsigned asA = LocA.Ptr->getType()->getPointerAddressSpace();
817a7e6055SDimitry Andric   unsigned asB = LocB.Ptr->getType()->getPointerAddressSpace();
827a7e6055SDimitry Andric 
83*b5893f02SDimitry Andric   AliasResult Result = getAliasResult(asA, asB);
84*b5893f02SDimitry Andric   if (Result == NoAlias)
85*b5893f02SDimitry Andric     return Result;
867a7e6055SDimitry Andric 
877a7e6055SDimitry Andric   // Forward the query to the next alias analysis.
887a7e6055SDimitry Andric   return AAResultBase::alias(LocA, LocB);
897a7e6055SDimitry Andric }
907a7e6055SDimitry Andric 
pointsToConstantMemory(const MemoryLocation & Loc,bool OrLocal)917a7e6055SDimitry Andric bool AMDGPUAAResult::pointsToConstantMemory(const MemoryLocation &Loc,
927a7e6055SDimitry Andric                                             bool OrLocal) {
937a7e6055SDimitry Andric   const Value *Base = GetUnderlyingObject(Loc.Ptr, DL);
94*b5893f02SDimitry Andric   unsigned AS = Base->getType()->getPointerAddressSpace();
95*b5893f02SDimitry Andric   if (AS == AMDGPUAS::CONSTANT_ADDRESS ||
96*b5893f02SDimitry Andric       AS == AMDGPUAS::CONSTANT_ADDRESS_32BIT) {
977a7e6055SDimitry Andric     return true;
987a7e6055SDimitry Andric   }
997a7e6055SDimitry Andric 
1007a7e6055SDimitry Andric   if (const GlobalVariable *GV = dyn_cast<GlobalVariable>(Base)) {
1017a7e6055SDimitry Andric     if (GV->isConstant())
1027a7e6055SDimitry Andric       return true;
1037a7e6055SDimitry Andric   } else if (const Argument *Arg = dyn_cast<Argument>(Base)) {
1047a7e6055SDimitry Andric     const Function *F = Arg->getParent();
1057a7e6055SDimitry Andric 
1067a7e6055SDimitry Andric     // Only assume constant memory for arguments on kernels.
1077a7e6055SDimitry Andric     switch (F->getCallingConv()) {
1087a7e6055SDimitry Andric     default:
1097a7e6055SDimitry Andric       return AAResultBase::pointsToConstantMemory(Loc, OrLocal);
1102cab237bSDimitry Andric     case CallingConv::AMDGPU_LS:
1112cab237bSDimitry Andric     case CallingConv::AMDGPU_HS:
1122cab237bSDimitry Andric     case CallingConv::AMDGPU_ES:
1137a7e6055SDimitry Andric     case CallingConv::AMDGPU_GS:
1142cab237bSDimitry Andric     case CallingConv::AMDGPU_VS:
1157a7e6055SDimitry Andric     case CallingConv::AMDGPU_PS:
1167a7e6055SDimitry Andric     case CallingConv::AMDGPU_CS:
1177a7e6055SDimitry Andric     case CallingConv::AMDGPU_KERNEL:
1187a7e6055SDimitry Andric     case CallingConv::SPIR_KERNEL:
1197a7e6055SDimitry Andric       break;
1207a7e6055SDimitry Andric     }
1217a7e6055SDimitry Andric 
1227a7e6055SDimitry Andric     unsigned ArgNo = Arg->getArgNo();
1237a7e6055SDimitry Andric     /* On an argument, ReadOnly attribute indicates that the function does
1247a7e6055SDimitry Andric        not write through this pointer argument, even though it may write
1257a7e6055SDimitry Andric        to the memory that the pointer points to.
1267a7e6055SDimitry Andric        On an argument, ReadNone attribute indicates that the function does
1277a7e6055SDimitry Andric        not dereference that pointer argument, even though it may read or write
1287a7e6055SDimitry Andric        the memory that the pointer points to if accessed through other pointers.
1297a7e6055SDimitry Andric      */
1307a7e6055SDimitry Andric     if (F->hasParamAttribute(ArgNo, Attribute::NoAlias) &&
1317a7e6055SDimitry Andric         (F->hasParamAttribute(ArgNo, Attribute::ReadNone) ||
1327a7e6055SDimitry Andric          F->hasParamAttribute(ArgNo, Attribute::ReadOnly))) {
1337a7e6055SDimitry Andric       return true;
1347a7e6055SDimitry Andric     }
1357a7e6055SDimitry Andric   }
1367a7e6055SDimitry Andric   return AAResultBase::pointsToConstantMemory(Loc, OrLocal);
1377a7e6055SDimitry Andric }
138