1 //===- DXILForwardHandleAccesses.cpp - Cleanup Handles --------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "DXILForwardHandleAccesses.h"
10 #include "DXILShaderFlags.h"
11 #include "DirectX.h"
12 #include "llvm/Analysis/DXILResource.h"
13 #include "llvm/Analysis/Loads.h"
14 #include "llvm/IR/DiagnosticInfo.h"
15 #include "llvm/IR/Dominators.h"
16 #include "llvm/IR/IntrinsicInst.h"
17 #include "llvm/IR/Intrinsics.h"
18 #include "llvm/IR/IntrinsicsDirectX.h"
19 #include "llvm/IR/Module.h"
20 #include "llvm/InitializePasses.h"
21 #include "llvm/Pass.h"
22 #include "llvm/Transforms/Utils/Local.h"
23
24 #define DEBUG_TYPE "dxil-forward-handle-accesses"
25
26 using namespace llvm;
27
diagnoseAmbiguousHandle(IntrinsicInst * NewII,IntrinsicInst * PrevII)28 static void diagnoseAmbiguousHandle(IntrinsicInst *NewII,
29 IntrinsicInst *PrevII) {
30 Function *F = NewII->getFunction();
31 LLVMContext &Context = F->getParent()->getContext();
32 Context.diagnose(DiagnosticInfoGeneric(
33 Twine("Handle at \"") + NewII->getName() + "\" overwrites handle at \"" +
34 PrevII->getName() + "\""));
35 }
36
diagnoseHandleNotFound(LoadInst * LI)37 static void diagnoseHandleNotFound(LoadInst *LI) {
38 Function *F = LI->getFunction();
39 LLVMContext &Context = F->getParent()->getContext();
40 Context.diagnose(DiagnosticInfoGeneric(
41 LI, Twine("Load of \"") + LI->getPointerOperand()->getName() +
42 "\" is not a global resource handle"));
43 }
44
diagnoseUndominatedLoad(LoadInst * LI,IntrinsicInst * Handle)45 static void diagnoseUndominatedLoad(LoadInst *LI, IntrinsicInst *Handle) {
46 Function *F = LI->getFunction();
47 LLVMContext &Context = F->getParent()->getContext();
48 Context.diagnose(DiagnosticInfoGeneric(
49 LI, Twine("Load at \"") + LI->getName() +
50 "\" is not dominated by handle creation at \"" +
51 Handle->getName() + "\""));
52 }
53
54 static void
processHandle(IntrinsicInst * II,DenseMap<GlobalVariable *,IntrinsicInst * > & HandleMap)55 processHandle(IntrinsicInst *II,
56 DenseMap<GlobalVariable *, IntrinsicInst *> &HandleMap) {
57 for (User *U : II->users())
58 if (auto *SI = dyn_cast<StoreInst>(U))
59 if (auto *GV = dyn_cast<GlobalVariable>(SI->getPointerOperand())) {
60 auto Entry = HandleMap.try_emplace(GV, II);
61 if (Entry.second)
62 LLVM_DEBUG(dbgs() << "Added " << GV->getName() << " to handle map\n");
63 else
64 diagnoseAmbiguousHandle(II, Entry.first->second);
65 }
66 }
67
forwardHandleAccesses(Function & F,DominatorTree & DT)68 static bool forwardHandleAccesses(Function &F, DominatorTree &DT) {
69 bool Changed = false;
70
71 DenseMap<GlobalVariable *, IntrinsicInst *> HandleMap;
72 SmallVector<LoadInst *> LoadsToProcess;
73 for (BasicBlock &BB : F)
74 for (Instruction &Inst : BB)
75 if (auto *II = dyn_cast<IntrinsicInst>(&Inst)) {
76 switch (II->getIntrinsicID()) {
77 case Intrinsic::dx_resource_handlefrombinding:
78 case Intrinsic::dx_resource_handlefromimplicitbinding:
79 processHandle(II, HandleMap);
80 break;
81 default:
82 continue;
83 }
84 } else if (auto *LI = dyn_cast<LoadInst>(&Inst))
85 if (isa<dxil::AnyResourceExtType>(LI->getType()))
86 LoadsToProcess.push_back(LI);
87
88 for (LoadInst *LI : LoadsToProcess) {
89 Value *V = LI->getPointerOperand();
90 auto *GV = dyn_cast<GlobalVariable>(LI->getPointerOperand());
91
92 // If we didn't find the global, we may need to walk through a level of
93 // indirection. This generally happens at -O0.
94 if (!GV)
95 if (auto *NestedLI = dyn_cast<LoadInst>(V)) {
96 BasicBlock::iterator BBI(NestedLI);
97 Value *Loaded = FindAvailableLoadedValue(
98 NestedLI, NestedLI->getParent(), BBI, 0, nullptr, nullptr);
99 GV = dyn_cast_or_null<GlobalVariable>(Loaded);
100 }
101
102 auto It = HandleMap.find(GV);
103 if (It == HandleMap.end()) {
104 diagnoseHandleNotFound(LI);
105 continue;
106 }
107 Changed = true;
108
109 if (!DT.dominates(It->second, LI)) {
110 diagnoseUndominatedLoad(LI, It->second);
111 continue;
112 }
113
114 LLVM_DEBUG(dbgs() << "Replacing uses of " << GV->getName() << " at "
115 << LI->getName() << " with " << It->second->getName()
116 << "\n");
117 LI->replaceAllUsesWith(It->second);
118 LI->eraseFromParent();
119 }
120
121 return Changed;
122 }
123
run(Function & F,FunctionAnalysisManager & AM)124 PreservedAnalyses DXILForwardHandleAccesses::run(Function &F,
125 FunctionAnalysisManager &AM) {
126 PreservedAnalyses PA;
127
128 DominatorTree *DT = &AM.getResult<DominatorTreeAnalysis>(F);
129 bool Changed = forwardHandleAccesses(F, *DT);
130
131 if (!Changed)
132 return PreservedAnalyses::all();
133 return PA;
134 }
135
136 namespace {
137 class DXILForwardHandleAccessesLegacy : public FunctionPass {
138 public:
runOnFunction(Function & F)139 bool runOnFunction(Function &F) override {
140 DominatorTree *DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();
141 return forwardHandleAccesses(F, *DT);
142 }
getPassName() const143 StringRef getPassName() const override {
144 return "DXIL Forward Handle Accesses";
145 }
146
getAnalysisUsage(AnalysisUsage & AU) const147 void getAnalysisUsage(AnalysisUsage &AU) const override {
148 AU.addRequired<DominatorTreeWrapperPass>();
149 }
150
DXILForwardHandleAccessesLegacy()151 DXILForwardHandleAccessesLegacy() : FunctionPass(ID) {}
152
153 static char ID; // Pass identification.
154 };
155 char DXILForwardHandleAccessesLegacy::ID = 0;
156 } // end anonymous namespace
157
158 INITIALIZE_PASS_BEGIN(DXILForwardHandleAccessesLegacy, DEBUG_TYPE,
159 "DXIL Forward Handle Accesses", false, false)
INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)160 INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
161 INITIALIZE_PASS_END(DXILForwardHandleAccessesLegacy, DEBUG_TYPE,
162 "DXIL Forward Handle Accesses", false, false)
163
164 FunctionPass *llvm::createDXILForwardHandleAccessesLegacyPass() {
165 return new DXILForwardHandleAccessesLegacy();
166 }
167