xref: /freebsd/contrib/llvm-project/llvm/lib/Target/AMDGPU/AMDGPUAliasAnalysis.cpp (revision e8d8bef961a50d4dc22501cde4fb9fb0be1b2532)
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"
14*e8d8bef9SDimitry Andric #include "llvm/IR/Instructions.h"
150b57cec5SDimitry Andric 
160b57cec5SDimitry Andric using namespace llvm;
170b57cec5SDimitry Andric 
180b57cec5SDimitry Andric #define DEBUG_TYPE "amdgpu-aa"
190b57cec5SDimitry Andric 
20*e8d8bef9SDimitry Andric AnalysisKey AMDGPUAA::Key;
21*e8d8bef9SDimitry 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 
320b57cec5SDimitry Andric ImmutablePass *llvm::createAMDGPUAAWrapperPass() {
330b57cec5SDimitry Andric   return new AMDGPUAAWrapperPass();
340b57cec5SDimitry Andric }
350b57cec5SDimitry Andric 
360b57cec5SDimitry Andric ImmutablePass *llvm::createAMDGPUExternalAAWrapperPass() {
370b57cec5SDimitry Andric   return new AMDGPUExternalAAWrapper();
380b57cec5SDimitry Andric }
390b57cec5SDimitry Andric 
400b57cec5SDimitry Andric void AMDGPUAAWrapperPass::getAnalysisUsage(AnalysisUsage &AU) const {
410b57cec5SDimitry Andric   AU.setPreservesAll();
420b57cec5SDimitry Andric }
430b57cec5SDimitry Andric 
440b57cec5SDimitry Andric // These arrays are indexed by address space value enum elements 0 ... to 7
450b57cec5SDimitry Andric static const AliasResult ASAliasRules[8][8] = {
460b57cec5SDimitry Andric   /*                    Flat       Global    Region    Group     Constant  Private   Constant 32-bit  Buffer Fat Ptr */
470b57cec5SDimitry Andric   /* Flat     */        {MayAlias, MayAlias, NoAlias,  MayAlias, MayAlias, MayAlias, MayAlias,        MayAlias},
480b57cec5SDimitry Andric   /* Global   */        {MayAlias, MayAlias, NoAlias , NoAlias , MayAlias, NoAlias , MayAlias,        MayAlias},
490b57cec5SDimitry Andric   /* Region   */        {NoAlias,  NoAlias , MayAlias, NoAlias , NoAlias,  NoAlias , NoAlias,         NoAlias},
500b57cec5SDimitry Andric   /* Group    */        {MayAlias, NoAlias , NoAlias , MayAlias, NoAlias , NoAlias , NoAlias ,        NoAlias},
510b57cec5SDimitry Andric   /* Constant */        {MayAlias, MayAlias, NoAlias,  NoAlias , NoAlias , NoAlias , MayAlias,        MayAlias},
520b57cec5SDimitry Andric   /* Private  */        {MayAlias, NoAlias , NoAlias , NoAlias , NoAlias , MayAlias, NoAlias ,        NoAlias},
530b57cec5SDimitry Andric   /* Constant 32-bit */ {MayAlias, MayAlias, NoAlias,  NoAlias , MayAlias, NoAlias , NoAlias ,        MayAlias},
540b57cec5SDimitry Andric   /* Buffer Fat Ptr  */ {MayAlias, MayAlias, NoAlias , NoAlias , MayAlias, NoAlias , MayAlias,        MayAlias}
550b57cec5SDimitry Andric };
560b57cec5SDimitry Andric 
570b57cec5SDimitry Andric static AliasResult getAliasResult(unsigned AS1, unsigned AS2) {
580b57cec5SDimitry Andric   static_assert(AMDGPUAS::MAX_AMDGPU_ADDRESS <= 7, "Addr space out of range");
590b57cec5SDimitry Andric 
600b57cec5SDimitry Andric   if (AS1 > AMDGPUAS::MAX_AMDGPU_ADDRESS || AS2 > AMDGPUAS::MAX_AMDGPU_ADDRESS)
610b57cec5SDimitry Andric     return MayAlias;
620b57cec5SDimitry Andric 
630b57cec5SDimitry Andric   return ASAliasRules[AS1][AS2];
640b57cec5SDimitry Andric }
650b57cec5SDimitry Andric 
660b57cec5SDimitry Andric AliasResult AMDGPUAAResult::alias(const MemoryLocation &LocA,
670b57cec5SDimitry Andric                                   const MemoryLocation &LocB,
680b57cec5SDimitry Andric                                   AAQueryInfo &AAQI) {
690b57cec5SDimitry Andric   unsigned asA = LocA.Ptr->getType()->getPointerAddressSpace();
700b57cec5SDimitry Andric   unsigned asB = LocB.Ptr->getType()->getPointerAddressSpace();
710b57cec5SDimitry Andric 
720b57cec5SDimitry Andric   AliasResult Result = getAliasResult(asA, asB);
730b57cec5SDimitry Andric   if (Result == NoAlias)
740b57cec5SDimitry Andric     return Result;
750b57cec5SDimitry Andric 
76*e8d8bef9SDimitry Andric   // In general, FLAT (generic) pointers could be aliased to LOCAL or PRIVATE
77*e8d8bef9SDimitry Andric   // pointers. However, as LOCAL or PRIVATE pointers point to local objects, in
78*e8d8bef9SDimitry Andric   // certain cases, it's still viable to check whether a FLAT pointer won't
79*e8d8bef9SDimitry Andric   // alias to a LOCAL or PRIVATE pointer.
80*e8d8bef9SDimitry Andric   MemoryLocation A = LocA;
81*e8d8bef9SDimitry Andric   MemoryLocation B = LocB;
82*e8d8bef9SDimitry Andric   // Canonicalize the location order to simplify the following alias check.
83*e8d8bef9SDimitry Andric   if (asA != AMDGPUAS::FLAT_ADDRESS) {
84*e8d8bef9SDimitry Andric     std::swap(asA, asB);
85*e8d8bef9SDimitry Andric     std::swap(A, B);
86*e8d8bef9SDimitry Andric   }
87*e8d8bef9SDimitry Andric   if (asA == AMDGPUAS::FLAT_ADDRESS &&
88*e8d8bef9SDimitry Andric       (asB == AMDGPUAS::LOCAL_ADDRESS || asB == AMDGPUAS::PRIVATE_ADDRESS)) {
89*e8d8bef9SDimitry Andric     const auto *ObjA =
90*e8d8bef9SDimitry Andric         getUnderlyingObject(A.Ptr->stripPointerCastsAndInvariantGroups());
91*e8d8bef9SDimitry Andric     if (const LoadInst *LI = dyn_cast<LoadInst>(ObjA)) {
92*e8d8bef9SDimitry Andric       // If a generic pointer is loaded from the constant address space, it
93*e8d8bef9SDimitry Andric       // could only be a GLOBAL or CONSTANT one as that address space is soley
94*e8d8bef9SDimitry Andric       // prepared on the host side, where only GLOBAL or CONSTANT variables are
95*e8d8bef9SDimitry Andric       // visible. Note that this even holds for regular functions.
96*e8d8bef9SDimitry Andric       if (LI->getPointerAddressSpace() == AMDGPUAS::CONSTANT_ADDRESS)
97*e8d8bef9SDimitry Andric         return NoAlias;
98*e8d8bef9SDimitry Andric     } else if (const Argument *Arg = dyn_cast<Argument>(ObjA)) {
99*e8d8bef9SDimitry Andric       const Function *F = Arg->getParent();
100*e8d8bef9SDimitry Andric       switch (F->getCallingConv()) {
101*e8d8bef9SDimitry Andric       case CallingConv::AMDGPU_KERNEL:
102*e8d8bef9SDimitry Andric         // In the kernel function, kernel arguments won't alias to (local)
103*e8d8bef9SDimitry Andric         // variables in shared or private address space.
104*e8d8bef9SDimitry Andric         return NoAlias;
105*e8d8bef9SDimitry Andric       default:
106*e8d8bef9SDimitry Andric         // TODO: In the regular function, if that local variable in the
107*e8d8bef9SDimitry Andric         // location B is not captured, that argument pointer won't alias to it
108*e8d8bef9SDimitry Andric         // as well.
109*e8d8bef9SDimitry Andric         break;
110*e8d8bef9SDimitry Andric       }
111*e8d8bef9SDimitry Andric     }
112*e8d8bef9SDimitry Andric   }
113*e8d8bef9SDimitry Andric 
1140b57cec5SDimitry Andric   // Forward the query to the next alias analysis.
1150b57cec5SDimitry Andric   return AAResultBase::alias(LocA, LocB, AAQI);
1160b57cec5SDimitry Andric }
1170b57cec5SDimitry Andric 
1180b57cec5SDimitry Andric bool AMDGPUAAResult::pointsToConstantMemory(const MemoryLocation &Loc,
1190b57cec5SDimitry Andric                                             AAQueryInfo &AAQI, bool OrLocal) {
1205ffd83dbSDimitry Andric   unsigned AS = Loc.Ptr->getType()->getPointerAddressSpace();
1210b57cec5SDimitry Andric   if (AS == AMDGPUAS::CONSTANT_ADDRESS ||
1225ffd83dbSDimitry Andric       AS == AMDGPUAS::CONSTANT_ADDRESS_32BIT)
1230b57cec5SDimitry Andric     return true;
1245ffd83dbSDimitry Andric 
125*e8d8bef9SDimitry Andric   const Value *Base = getUnderlyingObject(Loc.Ptr);
1265ffd83dbSDimitry Andric   AS = Base->getType()->getPointerAddressSpace();
1275ffd83dbSDimitry Andric   if (AS == AMDGPUAS::CONSTANT_ADDRESS ||
1285ffd83dbSDimitry Andric       AS == AMDGPUAS::CONSTANT_ADDRESS_32BIT)
1295ffd83dbSDimitry Andric     return true;
1300b57cec5SDimitry Andric 
1310b57cec5SDimitry Andric   if (const GlobalVariable *GV = dyn_cast<GlobalVariable>(Base)) {
1320b57cec5SDimitry Andric     if (GV->isConstant())
1330b57cec5SDimitry Andric       return true;
1340b57cec5SDimitry Andric   } else if (const Argument *Arg = dyn_cast<Argument>(Base)) {
1350b57cec5SDimitry Andric     const Function *F = Arg->getParent();
1360b57cec5SDimitry Andric 
1370b57cec5SDimitry Andric     // Only assume constant memory for arguments on kernels.
1380b57cec5SDimitry Andric     switch (F->getCallingConv()) {
1390b57cec5SDimitry Andric     default:
1400b57cec5SDimitry Andric       return AAResultBase::pointsToConstantMemory(Loc, AAQI, OrLocal);
1410b57cec5SDimitry Andric     case CallingConv::AMDGPU_LS:
1420b57cec5SDimitry Andric     case CallingConv::AMDGPU_HS:
1430b57cec5SDimitry Andric     case CallingConv::AMDGPU_ES:
1440b57cec5SDimitry Andric     case CallingConv::AMDGPU_GS:
1450b57cec5SDimitry Andric     case CallingConv::AMDGPU_VS:
1460b57cec5SDimitry Andric     case CallingConv::AMDGPU_PS:
1470b57cec5SDimitry Andric     case CallingConv::AMDGPU_CS:
1480b57cec5SDimitry Andric     case CallingConv::AMDGPU_KERNEL:
1490b57cec5SDimitry Andric     case CallingConv::SPIR_KERNEL:
1500b57cec5SDimitry Andric       break;
1510b57cec5SDimitry Andric     }
1520b57cec5SDimitry Andric 
1530b57cec5SDimitry Andric     unsigned ArgNo = Arg->getArgNo();
1540b57cec5SDimitry Andric     /* On an argument, ReadOnly attribute indicates that the function does
1550b57cec5SDimitry Andric        not write through this pointer argument, even though it may write
1560b57cec5SDimitry Andric        to the memory that the pointer points to.
1570b57cec5SDimitry Andric        On an argument, ReadNone attribute indicates that the function does
1580b57cec5SDimitry Andric        not dereference that pointer argument, even though it may read or write
1590b57cec5SDimitry Andric        the memory that the pointer points to if accessed through other pointers.
1600b57cec5SDimitry Andric      */
1610b57cec5SDimitry Andric     if (F->hasParamAttribute(ArgNo, Attribute::NoAlias) &&
1620b57cec5SDimitry Andric         (F->hasParamAttribute(ArgNo, Attribute::ReadNone) ||
1630b57cec5SDimitry Andric          F->hasParamAttribute(ArgNo, Attribute::ReadOnly))) {
1640b57cec5SDimitry Andric       return true;
1650b57cec5SDimitry Andric     }
1660b57cec5SDimitry Andric   }
1670b57cec5SDimitry Andric   return AAResultBase::pointsToConstantMemory(Loc, AAQI, OrLocal);
1680b57cec5SDimitry Andric }
169