xref: /freebsd/contrib/llvm-project/llvm/lib/Target/AMDGPU/AMDGPUAliasAnalysis.cpp (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
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"
13349cc55cSDimitry 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 
41349cc55cSDimitry Andric AMDGPUAAWrapperPass::AMDGPUAAWrapperPass() : ImmutablePass(ID) {
42349cc55cSDimitry Andric   initializeAMDGPUAAWrapperPassPass(*PassRegistry::getPassRegistry());
43349cc55cSDimitry Andric }
44349cc55cSDimitry 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,
76*bdd1243dSDimitry Andric                                   const MemoryLocation &LocB, AAQueryInfo &AAQI,
77*bdd1243dSDimitry Andric                                   const Instruction *) {
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
102349cc55cSDimitry 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.
124*bdd1243dSDimitry Andric   return AAResultBase::alias(LocA, LocB, AAQI, nullptr);
1250b57cec5SDimitry Andric }
1260b57cec5SDimitry Andric 
127*bdd1243dSDimitry Andric ModRefInfo AMDGPUAAResult::getModRefInfoMask(const MemoryLocation &Loc,
128*bdd1243dSDimitry Andric                                              AAQueryInfo &AAQI,
129*bdd1243dSDimitry Andric                                              bool IgnoreLocals) {
1305ffd83dbSDimitry Andric   unsigned AS = Loc.Ptr->getType()->getPointerAddressSpace();
1310b57cec5SDimitry Andric   if (AS == AMDGPUAS::CONSTANT_ADDRESS ||
1325ffd83dbSDimitry Andric       AS == AMDGPUAS::CONSTANT_ADDRESS_32BIT)
133*bdd1243dSDimitry Andric     return ModRefInfo::NoModRef;
1345ffd83dbSDimitry Andric 
135e8d8bef9SDimitry Andric   const Value *Base = getUnderlyingObject(Loc.Ptr);
1365ffd83dbSDimitry Andric   AS = Base->getType()->getPointerAddressSpace();
1375ffd83dbSDimitry Andric   if (AS == AMDGPUAS::CONSTANT_ADDRESS ||
1385ffd83dbSDimitry Andric       AS == AMDGPUAS::CONSTANT_ADDRESS_32BIT)
139*bdd1243dSDimitry Andric     return ModRefInfo::NoModRef;
1400b57cec5SDimitry Andric 
141*bdd1243dSDimitry Andric   return AAResultBase::getModRefInfoMask(Loc, AAQI, IgnoreLocals);
1420b57cec5SDimitry Andric }
143