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"
136bda14b3SChandler Carruth #include "llvm/Analysis/ValueTracking.h"
149ed8e0caSdfukalov #include "llvm/IR/Instructions.h"
158e45acfcSStanislav Mekhanoshin 
168e45acfcSStanislav Mekhanoshin using namespace llvm;
178e45acfcSStanislav Mekhanoshin 
188e45acfcSStanislav Mekhanoshin #define DEBUG_TYPE "amdgpu-aa"
198e45acfcSStanislav Mekhanoshin 
2019155234SArthur Eubanks AnalysisKey AMDGPUAA::Key;
2119155234SArthur Eubanks 
228e45acfcSStanislav Mekhanoshin // Register this pass...
238e45acfcSStanislav Mekhanoshin char AMDGPUAAWrapperPass::ID = 0;
248ba740a5SMatt Arsenault char AMDGPUExternalAAWrapper::ID = 0;
25d16eff81SEugene Zelenko 
268e45acfcSStanislav Mekhanoshin INITIALIZE_PASS(AMDGPUAAWrapperPass, "amdgpu-aa",
278e45acfcSStanislav Mekhanoshin                 "AMDGPU Address space based Alias Analysis", false, true)
288e45acfcSStanislav Mekhanoshin 
298ba740a5SMatt Arsenault INITIALIZE_PASS(AMDGPUExternalAAWrapper, "amdgpu-aa-wrapper",
308ba740a5SMatt Arsenault                 "AMDGPU Address space based Alias Analysis Wrapper", false, true)
318ba740a5SMatt Arsenault 
328e45acfcSStanislav Mekhanoshin ImmutablePass *llvm::createAMDGPUAAWrapperPass() {
338e45acfcSStanislav Mekhanoshin   return new AMDGPUAAWrapperPass();
348e45acfcSStanislav Mekhanoshin }
358e45acfcSStanislav Mekhanoshin 
368ba740a5SMatt Arsenault ImmutablePass *llvm::createAMDGPUExternalAAWrapperPass() {
378ba740a5SMatt Arsenault   return new AMDGPUExternalAAWrapper();
388ba740a5SMatt Arsenault }
398ba740a5SMatt Arsenault 
408e45acfcSStanislav Mekhanoshin void AMDGPUAAWrapperPass::getAnalysisUsage(AnalysisUsage &AU) const {
418e45acfcSStanislav Mekhanoshin   AU.setPreservesAll();
428e45acfcSStanislav Mekhanoshin }
438e45acfcSStanislav Mekhanoshin 
44796b0e7aSMatt Arsenault static AliasResult getAliasResult(unsigned AS1, unsigned AS2) {
45523dab07SNeil Henning   static_assert(AMDGPUAS::MAX_AMDGPU_ADDRESS <= 7, "Addr space out of range");
460da6350dSMatt Arsenault 
47796b0e7aSMatt Arsenault   if (AS1 > AMDGPUAS::MAX_AMDGPU_ADDRESS || AS2 > AMDGPUAS::MAX_AMDGPU_ADDRESS)
48d0660797Sdfukalov     return AliasResult::MayAlias;
49d0660797Sdfukalov 
50d0660797Sdfukalov #define ASMay AliasResult::MayAlias
51d0660797Sdfukalov #define ASNo AliasResult::NoAlias
52d0660797Sdfukalov   // This array is indexed by address space value enum elements 0 ... to 7
53d0660797Sdfukalov   static const AliasResult ASAliasRules[8][8] = {
54d0660797Sdfukalov     /*                    Flat    Global Region Group  Constant Private Const32 Buf Fat Ptr */
55d0660797Sdfukalov     /* Flat     */        {ASMay, ASMay, ASNo,  ASMay, ASMay,   ASMay,  ASMay,  ASMay},
56d0660797Sdfukalov     /* Global   */        {ASMay, ASMay, ASNo,  ASNo,  ASMay,   ASNo,   ASMay,  ASMay},
57d0660797Sdfukalov     /* Region   */        {ASNo,  ASNo,  ASMay, ASNo,  ASNo,    ASNo,   ASNo,   ASNo},
58d0660797Sdfukalov     /* Group    */        {ASMay, ASNo,  ASNo,  ASMay, ASNo,    ASNo,   ASNo,   ASNo},
59d0660797Sdfukalov     /* Constant */        {ASMay, ASMay, ASNo,  ASNo,  ASNo,    ASNo,   ASMay,  ASMay},
60d0660797Sdfukalov     /* Private  */        {ASMay, ASNo,  ASNo,  ASNo,  ASNo,    ASMay,  ASNo,   ASNo},
61d0660797Sdfukalov     /* Constant 32-bit */ {ASMay, ASMay, ASNo,  ASNo,  ASMay,   ASNo,   ASNo,   ASMay},
62d0660797Sdfukalov     /* Buffer Fat Ptr  */ {ASMay, ASMay, ASNo,  ASNo,  ASMay,   ASNo,   ASMay,  ASMay}
63d0660797Sdfukalov   };
64d0660797Sdfukalov #undef ASMay
65d0660797Sdfukalov #undef ASNo
661a14bfa0SYaxun Liu 
67796b0e7aSMatt Arsenault   return ASAliasRules[AS1][AS2];
681a14bfa0SYaxun Liu }
691a14bfa0SYaxun Liu 
708e45acfcSStanislav Mekhanoshin AliasResult AMDGPUAAResult::alias(const MemoryLocation &LocA,
71bfc779e4SAlina Sbirlea                                   const MemoryLocation &LocB,
72bfc779e4SAlina Sbirlea                                   AAQueryInfo &AAQI) {
738e45acfcSStanislav Mekhanoshin   unsigned asA = LocA.Ptr->getType()->getPointerAddressSpace();
748e45acfcSStanislav Mekhanoshin   unsigned asB = LocB.Ptr->getType()->getPointerAddressSpace();
758e45acfcSStanislav Mekhanoshin 
76796b0e7aSMatt Arsenault   AliasResult Result = getAliasResult(asA, asB);
77d0660797Sdfukalov   if (Result == AliasResult::NoAlias)
78796b0e7aSMatt Arsenault     return Result;
798e45acfcSStanislav Mekhanoshin 
802a0e4d1cSMichael Liao   // In general, FLAT (generic) pointers could be aliased to LOCAL or PRIVATE
812a0e4d1cSMichael Liao   // pointers. However, as LOCAL or PRIVATE pointers point to local objects, in
822a0e4d1cSMichael Liao   // certain cases, it's still viable to check whether a FLAT pointer won't
832a0e4d1cSMichael Liao   // alias to a LOCAL or PRIVATE pointer.
842a0e4d1cSMichael Liao   MemoryLocation A = LocA;
852a0e4d1cSMichael Liao   MemoryLocation B = LocB;
862a0e4d1cSMichael Liao   // Canonicalize the location order to simplify the following alias check.
872a0e4d1cSMichael Liao   if (asA != AMDGPUAS::FLAT_ADDRESS) {
882a0e4d1cSMichael Liao     std::swap(asA, asB);
892a0e4d1cSMichael Liao     std::swap(A, B);
902a0e4d1cSMichael Liao   }
912a0e4d1cSMichael Liao   if (asA == AMDGPUAS::FLAT_ADDRESS &&
922a0e4d1cSMichael Liao       (asB == AMDGPUAS::LOCAL_ADDRESS || asB == AMDGPUAS::PRIVATE_ADDRESS)) {
932a0e4d1cSMichael Liao     const auto *ObjA =
9470e3c9a8SNikita Popov         getUnderlyingObject(A.Ptr->stripPointerCastsForAliasAnalysis());
952a0e4d1cSMichael Liao     if (const LoadInst *LI = dyn_cast<LoadInst>(ObjA)) {
962a0e4d1cSMichael Liao       // If a generic pointer is loaded from the constant address space, it
97*dc6e8dfdSJacob Lambert       // could only be a GLOBAL or CONSTANT one as that address space is solely
982a0e4d1cSMichael Liao       // prepared on the host side, where only GLOBAL or CONSTANT variables are
992a0e4d1cSMichael Liao       // visible. Note that this even holds for regular functions.
1002a0e4d1cSMichael Liao       if (LI->getPointerAddressSpace() == AMDGPUAS::CONSTANT_ADDRESS)
101d0660797Sdfukalov         return AliasResult::NoAlias;
1022a0e4d1cSMichael Liao     } else if (const Argument *Arg = dyn_cast<Argument>(ObjA)) {
1032a0e4d1cSMichael Liao       const Function *F = Arg->getParent();
1042a0e4d1cSMichael Liao       switch (F->getCallingConv()) {
1052a0e4d1cSMichael Liao       case CallingConv::AMDGPU_KERNEL:
1062a0e4d1cSMichael Liao         // In the kernel function, kernel arguments won't alias to (local)
1072a0e4d1cSMichael Liao         // variables in shared or private address space.
108d0660797Sdfukalov         return AliasResult::NoAlias;
1092a0e4d1cSMichael Liao       default:
1102a0e4d1cSMichael Liao         // TODO: In the regular function, if that local variable in the
1112a0e4d1cSMichael Liao         // location B is not captured, that argument pointer won't alias to it
1122a0e4d1cSMichael Liao         // as well.
1132a0e4d1cSMichael Liao         break;
1142a0e4d1cSMichael Liao       }
1152a0e4d1cSMichael Liao     }
1162a0e4d1cSMichael Liao   }
1172a0e4d1cSMichael Liao 
1188e45acfcSStanislav Mekhanoshin   // Forward the query to the next alias analysis.
119bfc779e4SAlina Sbirlea   return AAResultBase::alias(LocA, LocB, AAQI);
1208e45acfcSStanislav Mekhanoshin }
1218e45acfcSStanislav Mekhanoshin 
1228e45acfcSStanislav Mekhanoshin bool AMDGPUAAResult::pointsToConstantMemory(const MemoryLocation &Loc,
123bfc779e4SAlina Sbirlea                                             AAQueryInfo &AAQI, bool OrLocal) {
124beda9d04SMatt Arsenault   unsigned AS = Loc.Ptr->getType()->getPointerAddressSpace();
1250da6350dSMatt Arsenault   if (AS == AMDGPUAS::CONSTANT_ADDRESS ||
126beda9d04SMatt Arsenault       AS == AMDGPUAS::CONSTANT_ADDRESS_32BIT)
1278e45acfcSStanislav Mekhanoshin     return true;
128beda9d04SMatt Arsenault 
129b0eb40caSVitaly Buka   const Value *Base = getUnderlyingObject(Loc.Ptr);
130beda9d04SMatt Arsenault   AS = Base->getType()->getPointerAddressSpace();
131beda9d04SMatt Arsenault   if (AS == AMDGPUAS::CONSTANT_ADDRESS ||
132beda9d04SMatt Arsenault       AS == AMDGPUAS::CONSTANT_ADDRESS_32BIT)
133beda9d04SMatt Arsenault     return true;
1348e45acfcSStanislav Mekhanoshin 
1358e45acfcSStanislav Mekhanoshin   if (const GlobalVariable *GV = dyn_cast<GlobalVariable>(Base)) {
1368e45acfcSStanislav Mekhanoshin     if (GV->isConstant())
1378e45acfcSStanislav Mekhanoshin       return true;
1388e45acfcSStanislav Mekhanoshin   } else if (const Argument *Arg = dyn_cast<Argument>(Base)) {
1398e45acfcSStanislav Mekhanoshin     const Function *F = Arg->getParent();
1408e45acfcSStanislav Mekhanoshin 
1418e45acfcSStanislav Mekhanoshin     // Only assume constant memory for arguments on kernels.
1428e45acfcSStanislav Mekhanoshin     switch (F->getCallingConv()) {
1438e45acfcSStanislav Mekhanoshin     default:
144bfc779e4SAlina Sbirlea       return AAResultBase::pointsToConstantMemory(Loc, AAQI, OrLocal);
145ef1ae8ffSTim Renouf     case CallingConv::AMDGPU_LS:
146ef1ae8ffSTim Renouf     case CallingConv::AMDGPU_HS:
147ef1ae8ffSTim Renouf     case CallingConv::AMDGPU_ES:
1488e45acfcSStanislav Mekhanoshin     case CallingConv::AMDGPU_GS:
149ef1ae8ffSTim Renouf     case CallingConv::AMDGPU_VS:
1508e45acfcSStanislav Mekhanoshin     case CallingConv::AMDGPU_PS:
1518e45acfcSStanislav Mekhanoshin     case CallingConv::AMDGPU_CS:
1528e45acfcSStanislav Mekhanoshin     case CallingConv::AMDGPU_KERNEL:
1538e45acfcSStanislav Mekhanoshin     case CallingConv::SPIR_KERNEL:
1548e45acfcSStanislav Mekhanoshin       break;
1558e45acfcSStanislav Mekhanoshin     }
1568e45acfcSStanislav Mekhanoshin 
1578e45acfcSStanislav Mekhanoshin     unsigned ArgNo = Arg->getArgNo();
1588e45acfcSStanislav Mekhanoshin     /* On an argument, ReadOnly attribute indicates that the function does
1598e45acfcSStanislav Mekhanoshin        not write through this pointer argument, even though it may write
1608e45acfcSStanislav Mekhanoshin        to the memory that the pointer points to.
1618e45acfcSStanislav Mekhanoshin        On an argument, ReadNone attribute indicates that the function does
1628e45acfcSStanislav Mekhanoshin        not dereference that pointer argument, even though it may read or write
1638e45acfcSStanislav Mekhanoshin        the memory that the pointer points to if accessed through other pointers.
1648e45acfcSStanislav Mekhanoshin      */
165f021fab2SReid Kleckner     if (F->hasParamAttribute(ArgNo, Attribute::NoAlias) &&
166f021fab2SReid Kleckner         (F->hasParamAttribute(ArgNo, Attribute::ReadNone) ||
167f021fab2SReid Kleckner          F->hasParamAttribute(ArgNo, Attribute::ReadOnly))) {
1688e45acfcSStanislav Mekhanoshin       return true;
1698e45acfcSStanislav Mekhanoshin     }
1708e45acfcSStanislav Mekhanoshin   }
171bfc779e4SAlina Sbirlea   return AAResultBase::pointsToConstantMemory(Loc, AAQI, OrLocal);
1728e45acfcSStanislav Mekhanoshin }
173