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