blob: 888ba6b00d9e8fd6bcfe9eb83187962088d82521 [file] [log] [blame]
//===- DXILForwardHandleAccesses.cpp - Cleanup Handles --------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
#include "DXILForwardHandleAccesses.h"
#include "DXILShaderFlags.h"
#include "DirectX.h"
#include "llvm/Analysis/DXILResource.h"
#include "llvm/Analysis/Loads.h"
#include "llvm/IR/DiagnosticInfo.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/IntrinsicsDirectX.h"
#include "llvm/IR/Module.h"
#include "llvm/InitializePasses.h"
#include "llvm/Pass.h"
#include "llvm/Transforms/Utils/Local.h"
#define DEBUG_TYPE "dxil-forward-handle-accesses"
using namespace llvm;
static void diagnoseAmbiguousHandle(IntrinsicInst *NewII,
IntrinsicInst *PrevII) {
Function *F = NewII->getFunction();
LLVMContext &Context = F->getParent()->getContext();
Context.diagnose(DiagnosticInfoGeneric(
Twine("Handle at \"") + NewII->getName() + "\" overwrites handle at \"" +
PrevII->getName() + "\""));
}
static void diagnoseHandleNotFound(LoadInst *LI) {
Function *F = LI->getFunction();
LLVMContext &Context = F->getParent()->getContext();
Context.diagnose(DiagnosticInfoGeneric(
LI, Twine("Load of \"") + LI->getPointerOperand()->getName() +
"\" is not a global resource handle"));
}
static void diagnoseUndominatedLoad(LoadInst *LI, IntrinsicInst *Handle) {
Function *F = LI->getFunction();
LLVMContext &Context = F->getParent()->getContext();
Context.diagnose(DiagnosticInfoGeneric(
LI, Twine("Load at \"") + LI->getName() +
"\" is not dominated by handle creation at \"" +
Handle->getName() + "\""));
}
static void
processHandle(IntrinsicInst *II,
DenseMap<GlobalVariable *, IntrinsicInst *> &HandleMap) {
for (User *U : II->users())
if (auto *SI = dyn_cast<StoreInst>(U))
if (auto *GV = dyn_cast<GlobalVariable>(SI->getPointerOperand())) {
auto Entry = HandleMap.try_emplace(GV, II);
if (Entry.second)
LLVM_DEBUG(dbgs() << "Added " << GV->getName() << " to handle map\n");
else
diagnoseAmbiguousHandle(II, Entry.first->second);
}
}
static bool forwardHandleAccesses(Function &F, DominatorTree &DT) {
bool Changed = false;
DenseMap<GlobalVariable *, IntrinsicInst *> HandleMap;
SmallVector<LoadInst *> LoadsToProcess;
for (BasicBlock &BB : F)
for (Instruction &Inst : BB)
if (auto *II = dyn_cast<IntrinsicInst>(&Inst)) {
switch (II->getIntrinsicID()) {
case Intrinsic::dx_resource_handlefrombinding:
processHandle(II, HandleMap);
break;
default:
continue;
}
} else if (auto *LI = dyn_cast<LoadInst>(&Inst))
if (isa<dxil::AnyResourceExtType>(LI->getType()))
LoadsToProcess.push_back(LI);
for (LoadInst *LI : LoadsToProcess) {
Value *V = LI->getPointerOperand();
auto *GV = dyn_cast<GlobalVariable>(LI->getPointerOperand());
// If we didn't find the global, we may need to walk through a level of
// indirection. This generally happens at -O0.
if (!GV)
if (auto *NestedLI = dyn_cast<LoadInst>(V)) {
BasicBlock::iterator BBI(NestedLI);
Value *Loaded = FindAvailableLoadedValue(
NestedLI, NestedLI->getParent(), BBI, 0, nullptr, nullptr);
GV = dyn_cast_or_null<GlobalVariable>(Loaded);
}
auto It = HandleMap.find(GV);
if (It == HandleMap.end()) {
diagnoseHandleNotFound(LI);
continue;
}
Changed = true;
if (!DT.dominates(It->second, LI)) {
diagnoseUndominatedLoad(LI, It->second);
continue;
}
LLVM_DEBUG(dbgs() << "Replacing uses of " << GV->getName() << " at "
<< LI->getName() << " with " << It->second->getName()
<< "\n");
LI->replaceAllUsesWith(It->second);
LI->eraseFromParent();
}
return Changed;
}
PreservedAnalyses DXILForwardHandleAccesses::run(Function &F,
FunctionAnalysisManager &AM) {
PreservedAnalyses PA;
DominatorTree *DT = &AM.getResult<DominatorTreeAnalysis>(F);
bool Changed = forwardHandleAccesses(F, *DT);
if (!Changed)
return PreservedAnalyses::all();
return PA;
}
namespace {
class DXILForwardHandleAccessesLegacy : public FunctionPass {
public:
bool runOnFunction(Function &F) override {
DominatorTree *DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();
return forwardHandleAccesses(F, *DT);
}
StringRef getPassName() const override {
return "DXIL Forward Handle Accesses";
}
void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.addRequired<DominatorTreeWrapperPass>();
}
DXILForwardHandleAccessesLegacy() : FunctionPass(ID) {}
static char ID; // Pass identification.
};
char DXILForwardHandleAccessesLegacy::ID = 0;
} // end anonymous namespace
INITIALIZE_PASS_BEGIN(DXILForwardHandleAccessesLegacy, DEBUG_TYPE,
"DXIL Forward Handle Accesses", false, false)
INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
INITIALIZE_PASS_END(DXILForwardHandleAccessesLegacy, DEBUG_TYPE,
"DXIL Forward Handle Accesses", false, false)
FunctionPass *llvm::createDXILForwardHandleAccessesLegacyPass() {
return new DXILForwardHandleAccessesLegacy();
}