xref: /freebsd/contrib/llvm-project/llvm/lib/Target/DirectX/DXILForwardHandleAccesses.cpp (revision 1342eb5a832fa10e689a29faab3acb6054e4778c)
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 
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 
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 
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
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 
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 
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:
139   bool runOnFunction(Function &F) override {
140     DominatorTree *DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();
141     return forwardHandleAccesses(F, *DT);
142   }
143   StringRef getPassName() const override {
144     return "DXIL Forward Handle Accesses";
145   }
146 
147   void getAnalysisUsage(AnalysisUsage &AU) const override {
148     AU.addRequired<DominatorTreeWrapperPass>();
149   }
150 
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)
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