blob: c218e2aa4cbf11fa5d0ba57a07a9648d05ab2fba [file] [edit]
//===-- NVPTXMarkKernelPtrsGlobal.cpp - Mark kernel pointers as global ----===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// For CUDA kernels, pointers loaded from byval parameters are known to be in
// global address space. This pass inserts addrspacecast pairs to make that
// explicit, enabling later address-space inference to propagate the global AS.
// It also handles the pattern where a pointer is loaded as an integer and then
// converted via inttoptr.
//
//===----------------------------------------------------------------------===//
#include "NVPTX.h"
#include "NVVMProperties.h"
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/IR/InstIterator.h"
#include "llvm/IR/Instructions.h"
#include "llvm/InitializePasses.h"
#include "llvm/Pass.h"
#include "llvm/Support/NVPTXAddrSpace.h"
using namespace llvm;
using namespace NVPTXAS;
static void markPointerAsAS(Value *Ptr, unsigned AS) {
if (Ptr->getType()->getPointerAddressSpace() != ADDRESS_SPACE_GENERIC)
return;
BasicBlock::iterator InsertPt;
if (auto *Arg = dyn_cast<Argument>(Ptr)) {
InsertPt = Arg->getParent()->getEntryBlock().begin();
} else {
InsertPt = ++cast<Instruction>(Ptr)->getIterator();
assert(InsertPt != InsertPt->getParent()->end() &&
"We don't call this function with Ptr being a terminator.");
}
Instruction *PtrInGlobal = new AddrSpaceCastInst(
Ptr, PointerType::get(Ptr->getContext(), AS), Ptr->getName(), InsertPt);
Value *PtrInGeneric = new AddrSpaceCastInst(PtrInGlobal, Ptr->getType(),
Ptr->getName(), InsertPt);
Ptr->replaceAllUsesWith(PtrInGeneric);
PtrInGlobal->setOperand(0, Ptr);
}
static void markPointerAsGlobal(Value *Ptr) {
markPointerAsAS(Ptr, ADDRESS_SPACE_GLOBAL);
}
static void handleIntToPtr(Value &V) {
if (!all_of(V.users(), [](User *U) { return isa<IntToPtrInst>(U); }))
return;
SmallVector<User *, 16> UsersToUpdate(V.users());
for (User *U : UsersToUpdate)
markPointerAsGlobal(U);
}
static bool markKernelPtrsGlobal(Function &F) {
if (!isKernelFunction(F))
return false;
// Copying of byval aggregates + SROA may result in pointers being loaded as
// integers, followed by inttoptr. We mark those as global too, but only if
// the loaded integer is used exclusively for conversion to a pointer.
for (auto &I : instructions(F)) {
auto *LI = dyn_cast<LoadInst>(&I);
if (!LI)
continue;
if (LI->getType()->isPointerTy() || LI->getType()->isIntegerTy()) {
Value *UO = getUnderlyingObject(LI->getPointerOperand());
if (auto *Arg = dyn_cast<Argument>(UO)) {
if (Arg->hasByValAttr()) {
if (LI->getType()->isPointerTy())
markPointerAsGlobal(LI);
else
handleIntToPtr(*LI);
}
}
}
}
for (Argument &Arg : F.args())
if (Arg.getType()->isIntegerTy())
handleIntToPtr(Arg);
return true;
}
namespace {
class NVPTXMarkKernelPtrsGlobalLegacyPass : public FunctionPass {
public:
static char ID;
NVPTXMarkKernelPtrsGlobalLegacyPass() : FunctionPass(ID) {}
bool runOnFunction(Function &F) override;
};
} // namespace
INITIALIZE_PASS(NVPTXMarkKernelPtrsGlobalLegacyPass,
"nvptx-mark-kernel-ptrs-global",
"NVPTX Mark Kernel Pointers Global", false, false)
bool NVPTXMarkKernelPtrsGlobalLegacyPass::runOnFunction(Function &F) {
return markKernelPtrsGlobal(F);
}
char NVPTXMarkKernelPtrsGlobalLegacyPass::ID = 0;
FunctionPass *llvm::createNVPTXMarkKernelPtrsGlobalPass() {
return new NVPTXMarkKernelPtrsGlobalLegacyPass();
}
PreservedAnalyses
NVPTXMarkKernelPtrsGlobalPass::run(Function &F, FunctionAnalysisManager &) {
return markKernelPtrsGlobal(F) ? PreservedAnalyses::none()
: PreservedAnalyses::all();
}