10b57cec5SDimitry Andric //===- AMDGPUAliasAnalysis ------------------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric /// \file
90b57cec5SDimitry Andric /// This is the AMGPU address space based alias analysis pass.
100b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
110b57cec5SDimitry Andric 
120b57cec5SDimitry Andric #include "AMDGPUAliasAnalysis.h"
130b57cec5SDimitry Andric #include "llvm/Analysis/ValueTracking.h"
14af732203SDimitry Andric #include "llvm/IR/Instructions.h"
150b57cec5SDimitry Andric 
160b57cec5SDimitry Andric using namespace llvm;
170b57cec5SDimitry Andric 
180b57cec5SDimitry Andric #define DEBUG_TYPE "amdgpu-aa"
190b57cec5SDimitry Andric 
20af732203SDimitry Andric AnalysisKey AMDGPUAA::Key;
21af732203SDimitry Andric 
220b57cec5SDimitry Andric // Register this pass...
230b57cec5SDimitry Andric char AMDGPUAAWrapperPass::ID = 0;
240b57cec5SDimitry Andric char AMDGPUExternalAAWrapper::ID = 0;
250b57cec5SDimitry Andric 
260b57cec5SDimitry Andric INITIALIZE_PASS(AMDGPUAAWrapperPass, "amdgpu-aa",
270b57cec5SDimitry Andric                 "AMDGPU Address space based Alias Analysis", false, true)
280b57cec5SDimitry Andric 
290b57cec5SDimitry Andric INITIALIZE_PASS(AMDGPUExternalAAWrapper, "amdgpu-aa-wrapper",
300b57cec5SDimitry Andric                 "AMDGPU Address space based Alias Analysis Wrapper", false, true)
310b57cec5SDimitry Andric 
createAMDGPUAAWrapperPass()320b57cec5SDimitry Andric ImmutablePass *llvm::createAMDGPUAAWrapperPass() {
330b57cec5SDimitry Andric   return new AMDGPUAAWrapperPass();
340b57cec5SDimitry Andric }
350b57cec5SDimitry Andric 
createAMDGPUExternalAAWrapperPass()360b57cec5SDimitry Andric ImmutablePass *llvm::createAMDGPUExternalAAWrapperPass() {
370b57cec5SDimitry Andric   return new AMDGPUExternalAAWrapper();
380b57cec5SDimitry Andric }
390b57cec5SDimitry Andric 
getAnalysisUsage(AnalysisUsage & AU) const400b57cec5SDimitry Andric void AMDGPUAAWrapperPass::getAnalysisUsage(AnalysisUsage &AU) const {
410b57cec5SDimitry Andric   AU.setPreservesAll();
420b57cec5SDimitry Andric }
430b57cec5SDimitry Andric 
getAliasResult(unsigned AS1,unsigned AS2)440b57cec5SDimitry Andric static AliasResult getAliasResult(unsigned AS1, unsigned AS2) {
450b57cec5SDimitry Andric   static_assert(AMDGPUAS::MAX_AMDGPU_ADDRESS <= 7, "Addr space out of range");
460b57cec5SDimitry Andric 
470b57cec5SDimitry Andric   if (AS1 > AMDGPUAS::MAX_AMDGPU_ADDRESS || AS2 > AMDGPUAS::MAX_AMDGPU_ADDRESS)
48*5f7ddb14SDimitry Andric     return AliasResult::MayAlias;
49*5f7ddb14SDimitry Andric 
50*5f7ddb14SDimitry Andric #define ASMay AliasResult::MayAlias
51*5f7ddb14SDimitry Andric #define ASNo AliasResult::NoAlias
52*5f7ddb14SDimitry Andric   // This array is indexed by address space value enum elements 0 ... to 7
53*5f7ddb14SDimitry Andric   static const AliasResult ASAliasRules[8][8] = {
54*5f7ddb14SDimitry Andric     /*                    Flat    Global Region Group  Constant Private Const32 Buf Fat Ptr */
55*5f7ddb14SDimitry Andric     /* Flat     */        {ASMay, ASMay, ASNo,  ASMay, ASMay,   ASMay,  ASMay,  ASMay},
56*5f7ddb14SDimitry Andric     /* Global   */        {ASMay, ASMay, ASNo,  ASNo,  ASMay,   ASNo,   ASMay,  ASMay},
57*5f7ddb14SDimitry Andric     /* Region   */        {ASNo,  ASNo,  ASMay, ASNo,  ASNo,    ASNo,   ASNo,   ASNo},
58*5f7ddb14SDimitry Andric     /* Group    */        {ASMay, ASNo,  ASNo,  ASMay, ASNo,    ASNo,   ASNo,   ASNo},
59*5f7ddb14SDimitry Andric     /* Constant */        {ASMay, ASMay, ASNo,  ASNo,  ASNo,    ASNo,   ASMay,  ASMay},
60*5f7ddb14SDimitry Andric     /* Private  */        {ASMay, ASNo,  ASNo,  ASNo,  ASNo,    ASMay,  ASNo,   ASNo},
61*5f7ddb14SDimitry Andric     /* Constant 32-bit */ {ASMay, ASMay, ASNo,  ASNo,  ASMay,   ASNo,   ASNo,   ASMay},
62*5f7ddb14SDimitry Andric     /* Buffer Fat Ptr  */ {ASMay, ASMay, ASNo,  ASNo,  ASMay,   ASNo,   ASMay,  ASMay}
63*5f7ddb14SDimitry Andric   };
64*5f7ddb14SDimitry Andric #undef ASMay
65*5f7ddb14SDimitry Andric #undef ASNo
660b57cec5SDimitry Andric 
670b57cec5SDimitry Andric   return ASAliasRules[AS1][AS2];
680b57cec5SDimitry Andric }
690b57cec5SDimitry Andric 
alias(const MemoryLocation & LocA,const MemoryLocation & LocB,AAQueryInfo & AAQI)700b57cec5SDimitry Andric AliasResult AMDGPUAAResult::alias(const MemoryLocation &LocA,
710b57cec5SDimitry Andric                                   const MemoryLocation &LocB,
720b57cec5SDimitry Andric                                   AAQueryInfo &AAQI) {
730b57cec5SDimitry Andric   unsigned asA = LocA.Ptr->getType()->getPointerAddressSpace();
740b57cec5SDimitry Andric   unsigned asB = LocB.Ptr->getType()->getPointerAddressSpace();
750b57cec5SDimitry Andric 
760b57cec5SDimitry Andric   AliasResult Result = getAliasResult(asA, asB);
77*5f7ddb14SDimitry Andric   if (Result == AliasResult::NoAlias)
780b57cec5SDimitry Andric     return Result;
790b57cec5SDimitry Andric 
80af732203SDimitry Andric   // In general, FLAT (generic) pointers could be aliased to LOCAL or PRIVATE
81af732203SDimitry Andric   // pointers. However, as LOCAL or PRIVATE pointers point to local objects, in
82af732203SDimitry Andric   // certain cases, it's still viable to check whether a FLAT pointer won't
83af732203SDimitry Andric   // alias to a LOCAL or PRIVATE pointer.
84af732203SDimitry Andric   MemoryLocation A = LocA;
85af732203SDimitry Andric   MemoryLocation B = LocB;
86af732203SDimitry Andric   // Canonicalize the location order to simplify the following alias check.
87af732203SDimitry Andric   if (asA != AMDGPUAS::FLAT_ADDRESS) {
88af732203SDimitry Andric     std::swap(asA, asB);
89af732203SDimitry Andric     std::swap(A, B);
90af732203SDimitry Andric   }
91af732203SDimitry Andric   if (asA == AMDGPUAS::FLAT_ADDRESS &&
92af732203SDimitry Andric       (asB == AMDGPUAS::LOCAL_ADDRESS || asB == AMDGPUAS::PRIVATE_ADDRESS)) {
93af732203SDimitry Andric     const auto *ObjA =
94*5f7ddb14SDimitry Andric         getUnderlyingObject(A.Ptr->stripPointerCastsForAliasAnalysis());
95af732203SDimitry Andric     if (const LoadInst *LI = dyn_cast<LoadInst>(ObjA)) {
96af732203SDimitry Andric       // If a generic pointer is loaded from the constant address space, it
97af732203SDimitry Andric       // could only be a GLOBAL or CONSTANT one as that address space is soley
98af732203SDimitry Andric       // prepared on the host side, where only GLOBAL or CONSTANT variables are
99af732203SDimitry Andric       // visible. Note that this even holds for regular functions.
100af732203SDimitry Andric       if (LI->getPointerAddressSpace() == AMDGPUAS::CONSTANT_ADDRESS)
101*5f7ddb14SDimitry Andric         return AliasResult::NoAlias;
102af732203SDimitry Andric     } else if (const Argument *Arg = dyn_cast<Argument>(ObjA)) {
103af732203SDimitry Andric       const Function *F = Arg->getParent();
104af732203SDimitry Andric       switch (F->getCallingConv()) {
105af732203SDimitry Andric       case CallingConv::AMDGPU_KERNEL:
106af732203SDimitry Andric         // In the kernel function, kernel arguments won't alias to (local)
107af732203SDimitry Andric         // variables in shared or private address space.
108*5f7ddb14SDimitry Andric         return AliasResult::NoAlias;
109af732203SDimitry Andric       default:
110af732203SDimitry Andric         // TODO: In the regular function, if that local variable in the
111af732203SDimitry Andric         // location B is not captured, that argument pointer won't alias to it
112af732203SDimitry Andric         // as well.
113af732203SDimitry Andric         break;
114af732203SDimitry Andric       }
115af732203SDimitry Andric     }
116af732203SDimitry Andric   }
117af732203SDimitry Andric 
1180b57cec5SDimitry Andric   // Forward the query to the next alias analysis.
1190b57cec5SDimitry Andric   return AAResultBase::alias(LocA, LocB, AAQI);
1200b57cec5SDimitry Andric }
1210b57cec5SDimitry Andric 
pointsToConstantMemory(const MemoryLocation & Loc,AAQueryInfo & AAQI,bool OrLocal)1220b57cec5SDimitry Andric bool AMDGPUAAResult::pointsToConstantMemory(const MemoryLocation &Loc,
1230b57cec5SDimitry Andric                                             AAQueryInfo &AAQI, bool OrLocal) {
1245ffd83dbSDimitry Andric   unsigned AS = Loc.Ptr->getType()->getPointerAddressSpace();
1250b57cec5SDimitry Andric   if (AS == AMDGPUAS::CONSTANT_ADDRESS ||
1265ffd83dbSDimitry Andric       AS == AMDGPUAS::CONSTANT_ADDRESS_32BIT)
1270b57cec5SDimitry Andric     return true;
1285ffd83dbSDimitry Andric 
129af732203SDimitry Andric   const Value *Base = getUnderlyingObject(Loc.Ptr);
1305ffd83dbSDimitry Andric   AS = Base->getType()->getPointerAddressSpace();
1315ffd83dbSDimitry Andric   if (AS == AMDGPUAS::CONSTANT_ADDRESS ||
1325ffd83dbSDimitry Andric       AS == AMDGPUAS::CONSTANT_ADDRESS_32BIT)
1335ffd83dbSDimitry Andric     return true;
1340b57cec5SDimitry Andric 
1350b57cec5SDimitry Andric   if (const GlobalVariable *GV = dyn_cast<GlobalVariable>(Base)) {
1360b57cec5SDimitry Andric     if (GV->isConstant())
1370b57cec5SDimitry Andric       return true;
1380b57cec5SDimitry Andric   } else if (const Argument *Arg = dyn_cast<Argument>(Base)) {
1390b57cec5SDimitry Andric     const Function *F = Arg->getParent();
1400b57cec5SDimitry Andric 
1410b57cec5SDimitry Andric     // Only assume constant memory for arguments on kernels.
1420b57cec5SDimitry Andric     switch (F->getCallingConv()) {
1430b57cec5SDimitry Andric     default:
1440b57cec5SDimitry Andric       return AAResultBase::pointsToConstantMemory(Loc, AAQI, OrLocal);
1450b57cec5SDimitry Andric     case CallingConv::AMDGPU_LS:
1460b57cec5SDimitry Andric     case CallingConv::AMDGPU_HS:
1470b57cec5SDimitry Andric     case CallingConv::AMDGPU_ES:
1480b57cec5SDimitry Andric     case CallingConv::AMDGPU_GS:
1490b57cec5SDimitry Andric     case CallingConv::AMDGPU_VS:
1500b57cec5SDimitry Andric     case CallingConv::AMDGPU_PS:
1510b57cec5SDimitry Andric     case CallingConv::AMDGPU_CS:
1520b57cec5SDimitry Andric     case CallingConv::AMDGPU_KERNEL:
1530b57cec5SDimitry Andric     case CallingConv::SPIR_KERNEL:
1540b57cec5SDimitry Andric       break;
1550b57cec5SDimitry Andric     }
1560b57cec5SDimitry Andric 
1570b57cec5SDimitry Andric     unsigned ArgNo = Arg->getArgNo();
1580b57cec5SDimitry Andric     /* On an argument, ReadOnly attribute indicates that the function does
1590b57cec5SDimitry Andric        not write through this pointer argument, even though it may write
1600b57cec5SDimitry Andric        to the memory that the pointer points to.
1610b57cec5SDimitry Andric        On an argument, ReadNone attribute indicates that the function does
1620b57cec5SDimitry Andric        not dereference that pointer argument, even though it may read or write
1630b57cec5SDimitry Andric        the memory that the pointer points to if accessed through other pointers.
1640b57cec5SDimitry Andric      */
1650b57cec5SDimitry Andric     if (F->hasParamAttribute(ArgNo, Attribute::NoAlias) &&
1660b57cec5SDimitry Andric         (F->hasParamAttribute(ArgNo, Attribute::ReadNone) ||
1670b57cec5SDimitry Andric          F->hasParamAttribute(ArgNo, Attribute::ReadOnly))) {
1680b57cec5SDimitry Andric       return true;
1690b57cec5SDimitry Andric     }
1700b57cec5SDimitry Andric   }
1710b57cec5SDimitry Andric   return AAResultBase::pointsToConstantMemory(Loc, AAQI, OrLocal);
1720b57cec5SDimitry Andric }
173