1d16eff81SEugene Zelenko //===- AMDGPUAliasAnalysis ------------------------------------------------===//
28e45acfcSStanislav Mekhanoshin //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
68e45acfcSStanislav Mekhanoshin //
78e45acfcSStanislav Mekhanoshin //===----------------------------------------------------------------------===//
88e45acfcSStanislav Mekhanoshin /// \file
98e45acfcSStanislav Mekhanoshin /// This is the AMGPU address space based alias analysis pass.
108e45acfcSStanislav Mekhanoshin //===----------------------------------------------------------------------===//
118e45acfcSStanislav Mekhanoshin 
128e45acfcSStanislav Mekhanoshin #include "AMDGPUAliasAnalysis.h"
13*47d6274dSDaniil Fukalov #include "AMDGPU.h"
146bda14b3SChandler Carruth #include "llvm/Analysis/ValueTracking.h"
159ed8e0caSdfukalov #include "llvm/IR/Instructions.h"
168e45acfcSStanislav Mekhanoshin 
178e45acfcSStanislav Mekhanoshin using namespace llvm;
188e45acfcSStanislav Mekhanoshin 
198e45acfcSStanislav Mekhanoshin #define DEBUG_TYPE "amdgpu-aa"
208e45acfcSStanislav Mekhanoshin 
2119155234SArthur Eubanks AnalysisKey AMDGPUAA::Key;
2219155234SArthur Eubanks 
238e45acfcSStanislav Mekhanoshin // Register this pass...
248e45acfcSStanislav Mekhanoshin char AMDGPUAAWrapperPass::ID = 0;
258ba740a5SMatt Arsenault char AMDGPUExternalAAWrapper::ID = 0;
26d16eff81SEugene Zelenko 
278e45acfcSStanislav Mekhanoshin INITIALIZE_PASS(AMDGPUAAWrapperPass, "amdgpu-aa",
288e45acfcSStanislav Mekhanoshin                 "AMDGPU Address space based Alias Analysis", false, true)
298e45acfcSStanislav Mekhanoshin 
308ba740a5SMatt Arsenault INITIALIZE_PASS(AMDGPUExternalAAWrapper, "amdgpu-aa-wrapper",
318ba740a5SMatt Arsenault                 "AMDGPU Address space based Alias Analysis Wrapper", false, true)
328ba740a5SMatt Arsenault 
createAMDGPUAAWrapperPass()338e45acfcSStanislav Mekhanoshin ImmutablePass *llvm::createAMDGPUAAWrapperPass() {
348e45acfcSStanislav Mekhanoshin   return new AMDGPUAAWrapperPass();
358e45acfcSStanislav Mekhanoshin }
368e45acfcSStanislav Mekhanoshin 
createAMDGPUExternalAAWrapperPass()378ba740a5SMatt Arsenault ImmutablePass *llvm::createAMDGPUExternalAAWrapperPass() {
388ba740a5SMatt Arsenault   return new AMDGPUExternalAAWrapper();
398ba740a5SMatt Arsenault }
408ba740a5SMatt Arsenault 
AMDGPUAAWrapperPass()41*47d6274dSDaniil Fukalov AMDGPUAAWrapperPass::AMDGPUAAWrapperPass() : ImmutablePass(ID) {
42*47d6274dSDaniil Fukalov   initializeAMDGPUAAWrapperPassPass(*PassRegistry::getPassRegistry());
43*47d6274dSDaniil Fukalov }
44*47d6274dSDaniil Fukalov 
getAnalysisUsage(AnalysisUsage & AU) const458e45acfcSStanislav Mekhanoshin void AMDGPUAAWrapperPass::getAnalysisUsage(AnalysisUsage &AU) const {
468e45acfcSStanislav Mekhanoshin   AU.setPreservesAll();
478e45acfcSStanislav Mekhanoshin }
488e45acfcSStanislav Mekhanoshin 
getAliasResult(unsigned AS1,unsigned AS2)49796b0e7aSMatt Arsenault static AliasResult getAliasResult(unsigned AS1, unsigned AS2) {
50523dab07SNeil Henning   static_assert(AMDGPUAS::MAX_AMDGPU_ADDRESS <= 7, "Addr space out of range");
510da6350dSMatt Arsenault 
52796b0e7aSMatt Arsenault   if (AS1 > AMDGPUAS::MAX_AMDGPU_ADDRESS || AS2 > AMDGPUAS::MAX_AMDGPU_ADDRESS)
53d0660797Sdfukalov     return AliasResult::MayAlias;
54d0660797Sdfukalov 
55d0660797Sdfukalov #define ASMay AliasResult::MayAlias
56d0660797Sdfukalov #define ASNo AliasResult::NoAlias
57d0660797Sdfukalov   // This array is indexed by address space value enum elements 0 ... to 7
58d0660797Sdfukalov   static const AliasResult ASAliasRules[8][8] = {
59d0660797Sdfukalov     /*                    Flat    Global Region Group  Constant Private Const32 Buf Fat Ptr */
60d0660797Sdfukalov     /* Flat     */        {ASMay, ASMay, ASNo,  ASMay, ASMay,   ASMay,  ASMay,  ASMay},
61d0660797Sdfukalov     /* Global   */        {ASMay, ASMay, ASNo,  ASNo,  ASMay,   ASNo,   ASMay,  ASMay},
62d0660797Sdfukalov     /* Region   */        {ASNo,  ASNo,  ASMay, ASNo,  ASNo,    ASNo,   ASNo,   ASNo},
63d0660797Sdfukalov     /* Group    */        {ASMay, ASNo,  ASNo,  ASMay, ASNo,    ASNo,   ASNo,   ASNo},
64d0660797Sdfukalov     /* Constant */        {ASMay, ASMay, ASNo,  ASNo,  ASNo,    ASNo,   ASMay,  ASMay},
65d0660797Sdfukalov     /* Private  */        {ASMay, ASNo,  ASNo,  ASNo,  ASNo,    ASMay,  ASNo,   ASNo},
66d0660797Sdfukalov     /* Constant 32-bit */ {ASMay, ASMay, ASNo,  ASNo,  ASMay,   ASNo,   ASNo,   ASMay},
67d0660797Sdfukalov     /* Buffer Fat Ptr  */ {ASMay, ASMay, ASNo,  ASNo,  ASMay,   ASNo,   ASMay,  ASMay}
68d0660797Sdfukalov   };
69d0660797Sdfukalov #undef ASMay
70d0660797Sdfukalov #undef ASNo
711a14bfa0SYaxun Liu 
72796b0e7aSMatt Arsenault   return ASAliasRules[AS1][AS2];
731a14bfa0SYaxun Liu }
741a14bfa0SYaxun Liu 
alias(const MemoryLocation & LocA,const MemoryLocation & LocB,AAQueryInfo & AAQI)758e45acfcSStanislav Mekhanoshin AliasResult AMDGPUAAResult::alias(const MemoryLocation &LocA,
76bfc779e4SAlina Sbirlea                                   const MemoryLocation &LocB,
77bfc779e4SAlina Sbirlea                                   AAQueryInfo &AAQI) {
788e45acfcSStanislav Mekhanoshin   unsigned asA = LocA.Ptr->getType()->getPointerAddressSpace();
798e45acfcSStanislav Mekhanoshin   unsigned asB = LocB.Ptr->getType()->getPointerAddressSpace();
808e45acfcSStanislav Mekhanoshin 
81796b0e7aSMatt Arsenault   AliasResult Result = getAliasResult(asA, asB);
82d0660797Sdfukalov   if (Result == AliasResult::NoAlias)
83796b0e7aSMatt Arsenault     return Result;
848e45acfcSStanislav Mekhanoshin 
852a0e4d1cSMichael Liao   // In general, FLAT (generic) pointers could be aliased to LOCAL or PRIVATE
862a0e4d1cSMichael Liao   // pointers. However, as LOCAL or PRIVATE pointers point to local objects, in
872a0e4d1cSMichael Liao   // certain cases, it's still viable to check whether a FLAT pointer won't
882a0e4d1cSMichael Liao   // alias to a LOCAL or PRIVATE pointer.
892a0e4d1cSMichael Liao   MemoryLocation A = LocA;
902a0e4d1cSMichael Liao   MemoryLocation B = LocB;
912a0e4d1cSMichael Liao   // Canonicalize the location order to simplify the following alias check.
922a0e4d1cSMichael Liao   if (asA != AMDGPUAS::FLAT_ADDRESS) {
932a0e4d1cSMichael Liao     std::swap(asA, asB);
942a0e4d1cSMichael Liao     std::swap(A, B);
952a0e4d1cSMichael Liao   }
962a0e4d1cSMichael Liao   if (asA == AMDGPUAS::FLAT_ADDRESS &&
972a0e4d1cSMichael Liao       (asB == AMDGPUAS::LOCAL_ADDRESS || asB == AMDGPUAS::PRIVATE_ADDRESS)) {
982a0e4d1cSMichael Liao     const auto *ObjA =
9970e3c9a8SNikita Popov         getUnderlyingObject(A.Ptr->stripPointerCastsForAliasAnalysis());
1002a0e4d1cSMichael Liao     if (const LoadInst *LI = dyn_cast<LoadInst>(ObjA)) {
1012a0e4d1cSMichael Liao       // If a generic pointer is loaded from the constant address space, it
102dc6e8dfdSJacob Lambert       // could only be a GLOBAL or CONSTANT one as that address space is solely
1032a0e4d1cSMichael Liao       // prepared on the host side, where only GLOBAL or CONSTANT variables are
1042a0e4d1cSMichael Liao       // visible. Note that this even holds for regular functions.
1052a0e4d1cSMichael Liao       if (LI->getPointerAddressSpace() == AMDGPUAS::CONSTANT_ADDRESS)
106d0660797Sdfukalov         return AliasResult::NoAlias;
1072a0e4d1cSMichael Liao     } else if (const Argument *Arg = dyn_cast<Argument>(ObjA)) {
1082a0e4d1cSMichael Liao       const Function *F = Arg->getParent();
1092a0e4d1cSMichael Liao       switch (F->getCallingConv()) {
1102a0e4d1cSMichael Liao       case CallingConv::AMDGPU_KERNEL:
1112a0e4d1cSMichael Liao         // In the kernel function, kernel arguments won't alias to (local)
1122a0e4d1cSMichael Liao         // variables in shared or private address space.
113d0660797Sdfukalov         return AliasResult::NoAlias;
1142a0e4d1cSMichael Liao       default:
1152a0e4d1cSMichael Liao         // TODO: In the regular function, if that local variable in the
1162a0e4d1cSMichael Liao         // location B is not captured, that argument pointer won't alias to it
1172a0e4d1cSMichael Liao         // as well.
1182a0e4d1cSMichael Liao         break;
1192a0e4d1cSMichael Liao       }
1202a0e4d1cSMichael Liao     }
1212a0e4d1cSMichael Liao   }
1222a0e4d1cSMichael Liao 
1238e45acfcSStanislav Mekhanoshin   // Forward the query to the next alias analysis.
124bfc779e4SAlina Sbirlea   return AAResultBase::alias(LocA, LocB, AAQI);
1258e45acfcSStanislav Mekhanoshin }
1268e45acfcSStanislav Mekhanoshin 
pointsToConstantMemory(const MemoryLocation & Loc,AAQueryInfo & AAQI,bool OrLocal)1278e45acfcSStanislav Mekhanoshin bool AMDGPUAAResult::pointsToConstantMemory(const MemoryLocation &Loc,
128bfc779e4SAlina Sbirlea                                             AAQueryInfo &AAQI, bool OrLocal) {
129beda9d04SMatt Arsenault   unsigned AS = Loc.Ptr->getType()->getPointerAddressSpace();
1300da6350dSMatt Arsenault   if (AS == AMDGPUAS::CONSTANT_ADDRESS ||
131beda9d04SMatt Arsenault       AS == AMDGPUAS::CONSTANT_ADDRESS_32BIT)
1328e45acfcSStanislav Mekhanoshin     return true;
133beda9d04SMatt Arsenault 
134b0eb40caSVitaly Buka   const Value *Base = getUnderlyingObject(Loc.Ptr);
135beda9d04SMatt Arsenault   AS = Base->getType()->getPointerAddressSpace();
136beda9d04SMatt Arsenault   if (AS == AMDGPUAS::CONSTANT_ADDRESS ||
137beda9d04SMatt Arsenault       AS == AMDGPUAS::CONSTANT_ADDRESS_32BIT)
138beda9d04SMatt Arsenault     return true;
1398e45acfcSStanislav Mekhanoshin 
1408e45acfcSStanislav Mekhanoshin   if (const GlobalVariable *GV = dyn_cast<GlobalVariable>(Base)) {
1418e45acfcSStanislav Mekhanoshin     if (GV->isConstant())
1428e45acfcSStanislav Mekhanoshin       return true;
1438e45acfcSStanislav Mekhanoshin   } else if (const Argument *Arg = dyn_cast<Argument>(Base)) {
1448e45acfcSStanislav Mekhanoshin     const Function *F = Arg->getParent();
1458e45acfcSStanislav Mekhanoshin 
1468e45acfcSStanislav Mekhanoshin     // Only assume constant memory for arguments on kernels.
1478e45acfcSStanislav Mekhanoshin     switch (F->getCallingConv()) {
1488e45acfcSStanislav Mekhanoshin     default:
149bfc779e4SAlina Sbirlea       return AAResultBase::pointsToConstantMemory(Loc, AAQI, OrLocal);
150ef1ae8ffSTim Renouf     case CallingConv::AMDGPU_LS:
151ef1ae8ffSTim Renouf     case CallingConv::AMDGPU_HS:
152ef1ae8ffSTim Renouf     case CallingConv::AMDGPU_ES:
1538e45acfcSStanislav Mekhanoshin     case CallingConv::AMDGPU_GS:
154ef1ae8ffSTim Renouf     case CallingConv::AMDGPU_VS:
1558e45acfcSStanislav Mekhanoshin     case CallingConv::AMDGPU_PS:
1568e45acfcSStanislav Mekhanoshin     case CallingConv::AMDGPU_CS:
1578e45acfcSStanislav Mekhanoshin     case CallingConv::AMDGPU_KERNEL:
1588e45acfcSStanislav Mekhanoshin     case CallingConv::SPIR_KERNEL:
1598e45acfcSStanislav Mekhanoshin       break;
1608e45acfcSStanislav Mekhanoshin     }
1618e45acfcSStanislav Mekhanoshin 
1628e45acfcSStanislav Mekhanoshin     unsigned ArgNo = Arg->getArgNo();
1638e45acfcSStanislav Mekhanoshin     /* On an argument, ReadOnly attribute indicates that the function does
1648e45acfcSStanislav Mekhanoshin        not write through this pointer argument, even though it may write
1658e45acfcSStanislav Mekhanoshin        to the memory that the pointer points to.
1668e45acfcSStanislav Mekhanoshin        On an argument, ReadNone attribute indicates that the function does
1678e45acfcSStanislav Mekhanoshin        not dereference that pointer argument, even though it may read or write
1688e45acfcSStanislav Mekhanoshin        the memory that the pointer points to if accessed through other pointers.
1698e45acfcSStanislav Mekhanoshin      */
170f021fab2SReid Kleckner     if (F->hasParamAttribute(ArgNo, Attribute::NoAlias) &&
171f021fab2SReid Kleckner         (F->hasParamAttribute(ArgNo, Attribute::ReadNone) ||
172f021fab2SReid Kleckner          F->hasParamAttribute(ArgNo, Attribute::ReadOnly))) {
1738e45acfcSStanislav Mekhanoshin       return true;
1748e45acfcSStanislav Mekhanoshin     }
1758e45acfcSStanislav Mekhanoshin   }
176bfc779e4SAlina Sbirlea   return AAResultBase::pointsToConstantMemory(Loc, AAQI, OrLocal);
1778e45acfcSStanislav Mekhanoshin }
178