xref: /freebsd/contrib/llvm-project/llvm/lib/Target/AMDGPU/AMDGPUAliasAnalysis.cpp (revision 349cc55c9796c4596a5b9904cd3281af295f878f)
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"
13*349cc55cSDimitry Andric #include "AMDGPU.h"
140b57cec5SDimitry Andric #include "llvm/Analysis/ValueTracking.h"
15e8d8bef9SDimitry Andric #include "llvm/IR/Instructions.h"
160b57cec5SDimitry Andric 
170b57cec5SDimitry Andric using namespace llvm;
180b57cec5SDimitry Andric 
190b57cec5SDimitry Andric #define DEBUG_TYPE "amdgpu-aa"
200b57cec5SDimitry Andric 
21e8d8bef9SDimitry Andric AnalysisKey AMDGPUAA::Key;
22e8d8bef9SDimitry Andric 
230b57cec5SDimitry Andric // Register this pass...
240b57cec5SDimitry Andric char AMDGPUAAWrapperPass::ID = 0;
250b57cec5SDimitry Andric char AMDGPUExternalAAWrapper::ID = 0;
260b57cec5SDimitry Andric 
270b57cec5SDimitry Andric INITIALIZE_PASS(AMDGPUAAWrapperPass, "amdgpu-aa",
280b57cec5SDimitry Andric                 "AMDGPU Address space based Alias Analysis", false, true)
290b57cec5SDimitry Andric 
300b57cec5SDimitry Andric INITIALIZE_PASS(AMDGPUExternalAAWrapper, "amdgpu-aa-wrapper",
310b57cec5SDimitry Andric                 "AMDGPU Address space based Alias Analysis Wrapper", false, true)
320b57cec5SDimitry Andric 
330b57cec5SDimitry Andric ImmutablePass *llvm::createAMDGPUAAWrapperPass() {
340b57cec5SDimitry Andric   return new AMDGPUAAWrapperPass();
350b57cec5SDimitry Andric }
360b57cec5SDimitry Andric 
370b57cec5SDimitry Andric ImmutablePass *llvm::createAMDGPUExternalAAWrapperPass() {
380b57cec5SDimitry Andric   return new AMDGPUExternalAAWrapper();
390b57cec5SDimitry Andric }
400b57cec5SDimitry Andric 
41*349cc55cSDimitry Andric AMDGPUAAWrapperPass::AMDGPUAAWrapperPass() : ImmutablePass(ID) {
42*349cc55cSDimitry Andric   initializeAMDGPUAAWrapperPassPass(*PassRegistry::getPassRegistry());
43*349cc55cSDimitry Andric }
44*349cc55cSDimitry Andric 
450b57cec5SDimitry Andric void AMDGPUAAWrapperPass::getAnalysisUsage(AnalysisUsage &AU) const {
460b57cec5SDimitry Andric   AU.setPreservesAll();
470b57cec5SDimitry Andric }
480b57cec5SDimitry Andric 
490b57cec5SDimitry Andric static AliasResult getAliasResult(unsigned AS1, unsigned AS2) {
500b57cec5SDimitry Andric   static_assert(AMDGPUAS::MAX_AMDGPU_ADDRESS <= 7, "Addr space out of range");
510b57cec5SDimitry Andric 
520b57cec5SDimitry Andric   if (AS1 > AMDGPUAS::MAX_AMDGPU_ADDRESS || AS2 > AMDGPUAS::MAX_AMDGPU_ADDRESS)
53fe6060f1SDimitry Andric     return AliasResult::MayAlias;
54fe6060f1SDimitry Andric 
55fe6060f1SDimitry Andric #define ASMay AliasResult::MayAlias
56fe6060f1SDimitry Andric #define ASNo AliasResult::NoAlias
57fe6060f1SDimitry Andric   // This array is indexed by address space value enum elements 0 ... to 7
58fe6060f1SDimitry Andric   static const AliasResult ASAliasRules[8][8] = {
59fe6060f1SDimitry Andric     /*                    Flat    Global Region Group  Constant Private Const32 Buf Fat Ptr */
60fe6060f1SDimitry Andric     /* Flat     */        {ASMay, ASMay, ASNo,  ASMay, ASMay,   ASMay,  ASMay,  ASMay},
61fe6060f1SDimitry Andric     /* Global   */        {ASMay, ASMay, ASNo,  ASNo,  ASMay,   ASNo,   ASMay,  ASMay},
62fe6060f1SDimitry Andric     /* Region   */        {ASNo,  ASNo,  ASMay, ASNo,  ASNo,    ASNo,   ASNo,   ASNo},
63fe6060f1SDimitry Andric     /* Group    */        {ASMay, ASNo,  ASNo,  ASMay, ASNo,    ASNo,   ASNo,   ASNo},
64fe6060f1SDimitry Andric     /* Constant */        {ASMay, ASMay, ASNo,  ASNo,  ASNo,    ASNo,   ASMay,  ASMay},
65fe6060f1SDimitry Andric     /* Private  */        {ASMay, ASNo,  ASNo,  ASNo,  ASNo,    ASMay,  ASNo,   ASNo},
66fe6060f1SDimitry Andric     /* Constant 32-bit */ {ASMay, ASMay, ASNo,  ASNo,  ASMay,   ASNo,   ASNo,   ASMay},
67fe6060f1SDimitry Andric     /* Buffer Fat Ptr  */ {ASMay, ASMay, ASNo,  ASNo,  ASMay,   ASNo,   ASMay,  ASMay}
68fe6060f1SDimitry Andric   };
69fe6060f1SDimitry Andric #undef ASMay
70fe6060f1SDimitry Andric #undef ASNo
710b57cec5SDimitry Andric 
720b57cec5SDimitry Andric   return ASAliasRules[AS1][AS2];
730b57cec5SDimitry Andric }
740b57cec5SDimitry Andric 
750b57cec5SDimitry Andric AliasResult AMDGPUAAResult::alias(const MemoryLocation &LocA,
760b57cec5SDimitry Andric                                   const MemoryLocation &LocB,
770b57cec5SDimitry Andric                                   AAQueryInfo &AAQI) {
780b57cec5SDimitry Andric   unsigned asA = LocA.Ptr->getType()->getPointerAddressSpace();
790b57cec5SDimitry Andric   unsigned asB = LocB.Ptr->getType()->getPointerAddressSpace();
800b57cec5SDimitry Andric 
810b57cec5SDimitry Andric   AliasResult Result = getAliasResult(asA, asB);
82fe6060f1SDimitry Andric   if (Result == AliasResult::NoAlias)
830b57cec5SDimitry Andric     return Result;
840b57cec5SDimitry Andric 
85e8d8bef9SDimitry Andric   // In general, FLAT (generic) pointers could be aliased to LOCAL or PRIVATE
86e8d8bef9SDimitry Andric   // pointers. However, as LOCAL or PRIVATE pointers point to local objects, in
87e8d8bef9SDimitry Andric   // certain cases, it's still viable to check whether a FLAT pointer won't
88e8d8bef9SDimitry Andric   // alias to a LOCAL or PRIVATE pointer.
89e8d8bef9SDimitry Andric   MemoryLocation A = LocA;
90e8d8bef9SDimitry Andric   MemoryLocation B = LocB;
91e8d8bef9SDimitry Andric   // Canonicalize the location order to simplify the following alias check.
92e8d8bef9SDimitry Andric   if (asA != AMDGPUAS::FLAT_ADDRESS) {
93e8d8bef9SDimitry Andric     std::swap(asA, asB);
94e8d8bef9SDimitry Andric     std::swap(A, B);
95e8d8bef9SDimitry Andric   }
96e8d8bef9SDimitry Andric   if (asA == AMDGPUAS::FLAT_ADDRESS &&
97e8d8bef9SDimitry Andric       (asB == AMDGPUAS::LOCAL_ADDRESS || asB == AMDGPUAS::PRIVATE_ADDRESS)) {
98e8d8bef9SDimitry Andric     const auto *ObjA =
99fe6060f1SDimitry Andric         getUnderlyingObject(A.Ptr->stripPointerCastsForAliasAnalysis());
100e8d8bef9SDimitry Andric     if (const LoadInst *LI = dyn_cast<LoadInst>(ObjA)) {
101e8d8bef9SDimitry Andric       // If a generic pointer is loaded from the constant address space, it
102*349cc55cSDimitry Andric       // could only be a GLOBAL or CONSTANT one as that address space is solely
103e8d8bef9SDimitry Andric       // prepared on the host side, where only GLOBAL or CONSTANT variables are
104e8d8bef9SDimitry Andric       // visible. Note that this even holds for regular functions.
105e8d8bef9SDimitry Andric       if (LI->getPointerAddressSpace() == AMDGPUAS::CONSTANT_ADDRESS)
106fe6060f1SDimitry Andric         return AliasResult::NoAlias;
107e8d8bef9SDimitry Andric     } else if (const Argument *Arg = dyn_cast<Argument>(ObjA)) {
108e8d8bef9SDimitry Andric       const Function *F = Arg->getParent();
109e8d8bef9SDimitry Andric       switch (F->getCallingConv()) {
110e8d8bef9SDimitry Andric       case CallingConv::AMDGPU_KERNEL:
111e8d8bef9SDimitry Andric         // In the kernel function, kernel arguments won't alias to (local)
112e8d8bef9SDimitry Andric         // variables in shared or private address space.
113fe6060f1SDimitry Andric         return AliasResult::NoAlias;
114e8d8bef9SDimitry Andric       default:
115e8d8bef9SDimitry Andric         // TODO: In the regular function, if that local variable in the
116e8d8bef9SDimitry Andric         // location B is not captured, that argument pointer won't alias to it
117e8d8bef9SDimitry Andric         // as well.
118e8d8bef9SDimitry Andric         break;
119e8d8bef9SDimitry Andric       }
120e8d8bef9SDimitry Andric     }
121e8d8bef9SDimitry Andric   }
122e8d8bef9SDimitry Andric 
1230b57cec5SDimitry Andric   // Forward the query to the next alias analysis.
1240b57cec5SDimitry Andric   return AAResultBase::alias(LocA, LocB, AAQI);
1250b57cec5SDimitry Andric }
1260b57cec5SDimitry Andric 
1270b57cec5SDimitry Andric bool AMDGPUAAResult::pointsToConstantMemory(const MemoryLocation &Loc,
1280b57cec5SDimitry Andric                                             AAQueryInfo &AAQI, bool OrLocal) {
1295ffd83dbSDimitry Andric   unsigned AS = Loc.Ptr->getType()->getPointerAddressSpace();
1300b57cec5SDimitry Andric   if (AS == AMDGPUAS::CONSTANT_ADDRESS ||
1315ffd83dbSDimitry Andric       AS == AMDGPUAS::CONSTANT_ADDRESS_32BIT)
1320b57cec5SDimitry Andric     return true;
1335ffd83dbSDimitry Andric 
134e8d8bef9SDimitry Andric   const Value *Base = getUnderlyingObject(Loc.Ptr);
1355ffd83dbSDimitry Andric   AS = Base->getType()->getPointerAddressSpace();
1365ffd83dbSDimitry Andric   if (AS == AMDGPUAS::CONSTANT_ADDRESS ||
1375ffd83dbSDimitry Andric       AS == AMDGPUAS::CONSTANT_ADDRESS_32BIT)
1385ffd83dbSDimitry Andric     return true;
1390b57cec5SDimitry Andric 
1400b57cec5SDimitry Andric   if (const GlobalVariable *GV = dyn_cast<GlobalVariable>(Base)) {
1410b57cec5SDimitry Andric     if (GV->isConstant())
1420b57cec5SDimitry Andric       return true;
1430b57cec5SDimitry Andric   } else if (const Argument *Arg = dyn_cast<Argument>(Base)) {
1440b57cec5SDimitry Andric     const Function *F = Arg->getParent();
1450b57cec5SDimitry Andric 
1460b57cec5SDimitry Andric     // Only assume constant memory for arguments on kernels.
1470b57cec5SDimitry Andric     switch (F->getCallingConv()) {
1480b57cec5SDimitry Andric     default:
1490b57cec5SDimitry Andric       return AAResultBase::pointsToConstantMemory(Loc, AAQI, OrLocal);
1500b57cec5SDimitry Andric     case CallingConv::AMDGPU_LS:
1510b57cec5SDimitry Andric     case CallingConv::AMDGPU_HS:
1520b57cec5SDimitry Andric     case CallingConv::AMDGPU_ES:
1530b57cec5SDimitry Andric     case CallingConv::AMDGPU_GS:
1540b57cec5SDimitry Andric     case CallingConv::AMDGPU_VS:
1550b57cec5SDimitry Andric     case CallingConv::AMDGPU_PS:
1560b57cec5SDimitry Andric     case CallingConv::AMDGPU_CS:
1570b57cec5SDimitry Andric     case CallingConv::AMDGPU_KERNEL:
1580b57cec5SDimitry Andric     case CallingConv::SPIR_KERNEL:
1590b57cec5SDimitry Andric       break;
1600b57cec5SDimitry Andric     }
1610b57cec5SDimitry Andric 
1620b57cec5SDimitry Andric     unsigned ArgNo = Arg->getArgNo();
1630b57cec5SDimitry Andric     /* On an argument, ReadOnly attribute indicates that the function does
1640b57cec5SDimitry Andric        not write through this pointer argument, even though it may write
1650b57cec5SDimitry Andric        to the memory that the pointer points to.
1660b57cec5SDimitry Andric        On an argument, ReadNone attribute indicates that the function does
1670b57cec5SDimitry Andric        not dereference that pointer argument, even though it may read or write
1680b57cec5SDimitry Andric        the memory that the pointer points to if accessed through other pointers.
1690b57cec5SDimitry Andric      */
1700b57cec5SDimitry Andric     if (F->hasParamAttribute(ArgNo, Attribute::NoAlias) &&
1710b57cec5SDimitry Andric         (F->hasParamAttribute(ArgNo, Attribute::ReadNone) ||
1720b57cec5SDimitry Andric          F->hasParamAttribute(ArgNo, Attribute::ReadOnly))) {
1730b57cec5SDimitry Andric       return true;
1740b57cec5SDimitry Andric     }
1750b57cec5SDimitry Andric   }
1760b57cec5SDimitry Andric   return AAResultBase::pointsToConstantMemory(Loc, AAQI, OrLocal);
1770b57cec5SDimitry Andric }
178