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