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 "AMDGPU.h" 140b57cec5SDimitry Andric #include "llvm/ADT/Triple.h" 150b57cec5SDimitry Andric #include "llvm/Analysis/AliasAnalysis.h" 160b57cec5SDimitry Andric #include "llvm/Analysis/MemoryLocation.h" 170b57cec5SDimitry Andric #include "llvm/Analysis/ValueTracking.h" 180b57cec5SDimitry Andric #include "llvm/IR/Argument.h" 190b57cec5SDimitry Andric #include "llvm/IR/Attributes.h" 200b57cec5SDimitry Andric #include "llvm/IR/CallingConv.h" 210b57cec5SDimitry Andric #include "llvm/IR/Function.h" 220b57cec5SDimitry Andric #include "llvm/IR/GlobalVariable.h" 230b57cec5SDimitry Andric #include "llvm/IR/Type.h" 240b57cec5SDimitry Andric #include "llvm/IR/Value.h" 250b57cec5SDimitry Andric #include "llvm/Pass.h" 260b57cec5SDimitry Andric #include "llvm/Support/Casting.h" 270b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h" 280b57cec5SDimitry Andric #include <cassert> 290b57cec5SDimitry Andric 300b57cec5SDimitry Andric using namespace llvm; 310b57cec5SDimitry Andric 320b57cec5SDimitry Andric #define DEBUG_TYPE "amdgpu-aa" 330b57cec5SDimitry Andric 340b57cec5SDimitry Andric // Register this pass... 350b57cec5SDimitry Andric char AMDGPUAAWrapperPass::ID = 0; 360b57cec5SDimitry Andric char AMDGPUExternalAAWrapper::ID = 0; 370b57cec5SDimitry Andric 380b57cec5SDimitry Andric INITIALIZE_PASS(AMDGPUAAWrapperPass, "amdgpu-aa", 390b57cec5SDimitry Andric "AMDGPU Address space based Alias Analysis", false, true) 400b57cec5SDimitry Andric 410b57cec5SDimitry Andric INITIALIZE_PASS(AMDGPUExternalAAWrapper, "amdgpu-aa-wrapper", 420b57cec5SDimitry Andric "AMDGPU Address space based Alias Analysis Wrapper", false, true) 430b57cec5SDimitry Andric 440b57cec5SDimitry Andric ImmutablePass *llvm::createAMDGPUAAWrapperPass() { 450b57cec5SDimitry Andric return new AMDGPUAAWrapperPass(); 460b57cec5SDimitry Andric } 470b57cec5SDimitry Andric 480b57cec5SDimitry Andric ImmutablePass *llvm::createAMDGPUExternalAAWrapperPass() { 490b57cec5SDimitry Andric return new AMDGPUExternalAAWrapper(); 500b57cec5SDimitry Andric } 510b57cec5SDimitry Andric 520b57cec5SDimitry Andric void AMDGPUAAWrapperPass::getAnalysisUsage(AnalysisUsage &AU) const { 530b57cec5SDimitry Andric AU.setPreservesAll(); 540b57cec5SDimitry Andric } 550b57cec5SDimitry Andric 560b57cec5SDimitry Andric // These arrays are indexed by address space value enum elements 0 ... to 7 570b57cec5SDimitry Andric static const AliasResult ASAliasRules[8][8] = { 580b57cec5SDimitry Andric /* Flat Global Region Group Constant Private Constant 32-bit Buffer Fat Ptr */ 590b57cec5SDimitry Andric /* Flat */ {MayAlias, MayAlias, NoAlias, MayAlias, MayAlias, MayAlias, MayAlias, MayAlias}, 600b57cec5SDimitry Andric /* Global */ {MayAlias, MayAlias, NoAlias , NoAlias , MayAlias, NoAlias , MayAlias, MayAlias}, 610b57cec5SDimitry Andric /* Region */ {NoAlias, NoAlias , MayAlias, NoAlias , NoAlias, NoAlias , NoAlias, NoAlias}, 620b57cec5SDimitry Andric /* Group */ {MayAlias, NoAlias , NoAlias , MayAlias, NoAlias , NoAlias , NoAlias , NoAlias}, 630b57cec5SDimitry Andric /* Constant */ {MayAlias, MayAlias, NoAlias, NoAlias , NoAlias , NoAlias , MayAlias, MayAlias}, 640b57cec5SDimitry Andric /* Private */ {MayAlias, NoAlias , NoAlias , NoAlias , NoAlias , MayAlias, NoAlias , NoAlias}, 650b57cec5SDimitry Andric /* Constant 32-bit */ {MayAlias, MayAlias, NoAlias, NoAlias , MayAlias, NoAlias , NoAlias , MayAlias}, 660b57cec5SDimitry Andric /* Buffer Fat Ptr */ {MayAlias, MayAlias, NoAlias , NoAlias , MayAlias, NoAlias , MayAlias, MayAlias} 670b57cec5SDimitry Andric }; 680b57cec5SDimitry Andric 690b57cec5SDimitry Andric static AliasResult getAliasResult(unsigned AS1, unsigned AS2) { 700b57cec5SDimitry Andric static_assert(AMDGPUAS::MAX_AMDGPU_ADDRESS <= 7, "Addr space out of range"); 710b57cec5SDimitry Andric 720b57cec5SDimitry Andric if (AS1 > AMDGPUAS::MAX_AMDGPU_ADDRESS || AS2 > AMDGPUAS::MAX_AMDGPU_ADDRESS) 730b57cec5SDimitry Andric return MayAlias; 740b57cec5SDimitry Andric 750b57cec5SDimitry Andric return ASAliasRules[AS1][AS2]; 760b57cec5SDimitry Andric } 770b57cec5SDimitry Andric 780b57cec5SDimitry Andric AliasResult AMDGPUAAResult::alias(const MemoryLocation &LocA, 790b57cec5SDimitry Andric const MemoryLocation &LocB, 800b57cec5SDimitry Andric AAQueryInfo &AAQI) { 810b57cec5SDimitry Andric unsigned asA = LocA.Ptr->getType()->getPointerAddressSpace(); 820b57cec5SDimitry Andric unsigned asB = LocB.Ptr->getType()->getPointerAddressSpace(); 830b57cec5SDimitry Andric 840b57cec5SDimitry Andric AliasResult Result = getAliasResult(asA, asB); 850b57cec5SDimitry Andric if (Result == NoAlias) 860b57cec5SDimitry Andric return Result; 870b57cec5SDimitry Andric 880b57cec5SDimitry Andric // Forward the query to the next alias analysis. 890b57cec5SDimitry Andric return AAResultBase::alias(LocA, LocB, AAQI); 900b57cec5SDimitry Andric } 910b57cec5SDimitry Andric 920b57cec5SDimitry Andric bool AMDGPUAAResult::pointsToConstantMemory(const MemoryLocation &Loc, 930b57cec5SDimitry Andric AAQueryInfo &AAQI, bool OrLocal) { 94*5ffd83dbSDimitry Andric unsigned AS = Loc.Ptr->getType()->getPointerAddressSpace(); 950b57cec5SDimitry Andric if (AS == AMDGPUAS::CONSTANT_ADDRESS || 96*5ffd83dbSDimitry Andric AS == AMDGPUAS::CONSTANT_ADDRESS_32BIT) 970b57cec5SDimitry Andric return true; 98*5ffd83dbSDimitry Andric 99*5ffd83dbSDimitry Andric const Value *Base = GetUnderlyingObject(Loc.Ptr, DL); 100*5ffd83dbSDimitry Andric AS = Base->getType()->getPointerAddressSpace(); 101*5ffd83dbSDimitry Andric if (AS == AMDGPUAS::CONSTANT_ADDRESS || 102*5ffd83dbSDimitry Andric AS == AMDGPUAS::CONSTANT_ADDRESS_32BIT) 103*5ffd83dbSDimitry Andric return true; 1040b57cec5SDimitry Andric 1050b57cec5SDimitry Andric if (const GlobalVariable *GV = dyn_cast<GlobalVariable>(Base)) { 1060b57cec5SDimitry Andric if (GV->isConstant()) 1070b57cec5SDimitry Andric return true; 1080b57cec5SDimitry Andric } else if (const Argument *Arg = dyn_cast<Argument>(Base)) { 1090b57cec5SDimitry Andric const Function *F = Arg->getParent(); 1100b57cec5SDimitry Andric 1110b57cec5SDimitry Andric // Only assume constant memory for arguments on kernels. 1120b57cec5SDimitry Andric switch (F->getCallingConv()) { 1130b57cec5SDimitry Andric default: 1140b57cec5SDimitry Andric return AAResultBase::pointsToConstantMemory(Loc, AAQI, OrLocal); 1150b57cec5SDimitry Andric case CallingConv::AMDGPU_LS: 1160b57cec5SDimitry Andric case CallingConv::AMDGPU_HS: 1170b57cec5SDimitry Andric case CallingConv::AMDGPU_ES: 1180b57cec5SDimitry Andric case CallingConv::AMDGPU_GS: 1190b57cec5SDimitry Andric case CallingConv::AMDGPU_VS: 1200b57cec5SDimitry Andric case CallingConv::AMDGPU_PS: 1210b57cec5SDimitry Andric case CallingConv::AMDGPU_CS: 1220b57cec5SDimitry Andric case CallingConv::AMDGPU_KERNEL: 1230b57cec5SDimitry Andric case CallingConv::SPIR_KERNEL: 1240b57cec5SDimitry Andric break; 1250b57cec5SDimitry Andric } 1260b57cec5SDimitry Andric 1270b57cec5SDimitry Andric unsigned ArgNo = Arg->getArgNo(); 1280b57cec5SDimitry Andric /* On an argument, ReadOnly attribute indicates that the function does 1290b57cec5SDimitry Andric not write through this pointer argument, even though it may write 1300b57cec5SDimitry Andric to the memory that the pointer points to. 1310b57cec5SDimitry Andric On an argument, ReadNone attribute indicates that the function does 1320b57cec5SDimitry Andric not dereference that pointer argument, even though it may read or write 1330b57cec5SDimitry Andric the memory that the pointer points to if accessed through other pointers. 1340b57cec5SDimitry Andric */ 1350b57cec5SDimitry Andric if (F->hasParamAttribute(ArgNo, Attribute::NoAlias) && 1360b57cec5SDimitry Andric (F->hasParamAttribute(ArgNo, Attribute::ReadNone) || 1370b57cec5SDimitry Andric F->hasParamAttribute(ArgNo, Attribute::ReadOnly))) { 1380b57cec5SDimitry Andric return true; 1390b57cec5SDimitry Andric } 1400b57cec5SDimitry Andric } 1410b57cec5SDimitry Andric return AAResultBase::pointsToConstantMemory(Loc, AAQI, OrLocal); 1420b57cec5SDimitry Andric } 143