220 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9#include "DXILForwardHandleAccesses.h"10#include "DXILShaderFlags.h"11#include "DirectX.h"12#include "llvm/ADT/STLExtras.h"13#include "llvm/Analysis/DXILResource.h"14#include "llvm/Analysis/Loads.h"15#include "llvm/IR/DiagnosticInfo.h"16#include "llvm/IR/Dominators.h"17#include "llvm/IR/InstrTypes.h"18#include "llvm/IR/Instructions.h"19#include "llvm/IR/IntrinsicInst.h"20#include "llvm/IR/Intrinsics.h"21#include "llvm/IR/IntrinsicsDirectX.h"22#include "llvm/IR/Module.h"23#include "llvm/InitializePasses.h"24#include "llvm/Pass.h"25#include "llvm/Transforms/Utils/Local.h"26 27#define DEBUG_TYPE "dxil-forward-handle-accesses"28 29using namespace llvm;30 31static void diagnoseAmbiguousHandle(IntrinsicInst *NewII,32 IntrinsicInst *PrevII) {33 Function *F = NewII->getFunction();34 LLVMContext &Context = F->getParent()->getContext();35 Context.diagnose(DiagnosticInfoGeneric(36 Twine("Handle at \"") + NewII->getName() + "\" overwrites handle at \"" +37 PrevII->getName() + "\""));38}39 40static void diagnoseHandleNotFound(LoadInst *LI) {41 Function *F = LI->getFunction();42 LLVMContext &Context = F->getParent()->getContext();43 Context.diagnose(DiagnosticInfoGeneric(44 LI, Twine("Load of \"") + LI->getPointerOperand()->getName() +45 "\" is not a global resource handle"));46}47 48static void diagnoseUndominatedLoad(LoadInst *LI, IntrinsicInst *Handle) {49 Function *F = LI->getFunction();50 LLVMContext &Context = F->getParent()->getContext();51 Context.diagnose(DiagnosticInfoGeneric(52 LI, Twine("Load at \"") + LI->getName() +53 "\" is not dominated by handle creation at \"" +54 Handle->getName() + "\""));55}56 57static void58processHandle(IntrinsicInst *II,59 DenseMap<GlobalVariable *, IntrinsicInst *> &HandleMap) {60 for (User *U : II->users())61 if (auto *SI = dyn_cast<StoreInst>(U))62 if (auto *GV = dyn_cast<GlobalVariable>(SI->getPointerOperand())) {63 auto Entry = HandleMap.try_emplace(GV, II);64 if (Entry.second)65 LLVM_DEBUG(dbgs() << "Added " << GV->getName() << " to handle map\n");66 else67 diagnoseAmbiguousHandle(II, Entry.first->second);68 }69}70 71static bool forwardHandleAccesses(Function &F, DominatorTree &DT) {72 bool Changed = false;73 74 DenseMap<GlobalVariable *, IntrinsicInst *> HandleMap;75 SmallVector<LoadInst *> LoadsToProcess;76 DenseMap<AllocaInst *, SmallVector<IntrinsicInst *>> LifeTimeIntrinsicMap;77 for (BasicBlock &BB : F)78 for (Instruction &Inst : BB)79 if (auto *II = dyn_cast<IntrinsicInst>(&Inst)) {80 switch (II->getIntrinsicID()) {81 case Intrinsic::dx_resource_handlefrombinding:82 case Intrinsic::dx_resource_handlefromimplicitbinding:83 processHandle(II, HandleMap);84 break;85 case Intrinsic::lifetime_start:86 case Intrinsic::lifetime_end:87 if (II->arg_size() >= 1) {88 Value *Ptr = II->getArgOperand(0);89 if (auto *Alloca = dyn_cast<AllocaInst>(Ptr))90 LifeTimeIntrinsicMap[Alloca].push_back(II);91 }92 break;93 default:94 continue;95 }96 } else if (auto *LI = dyn_cast<LoadInst>(&Inst))97 if (isa<dxil::AnyResourceExtType>(LI->getType()))98 LoadsToProcess.push_back(LI);99 100 for (LoadInst *LI : LoadsToProcess) {101 Value *V = LI->getPointerOperand();102 auto *GV = dyn_cast<GlobalVariable>(V);103 104 // If we didn't find the global, we may need to walk through a level of105 // indirection. This generally happens at -O0.106 if (!GV) {107 if (auto *NestedLI = dyn_cast<LoadInst>(V)) {108 BasicBlock::iterator BBI(NestedLI);109 Value *Loaded = FindAvailableLoadedValue(110 NestedLI, NestedLI->getParent(), BBI, 0, nullptr, nullptr);111 GV = dyn_cast_or_null<GlobalVariable>(Loaded);112 } else if (auto *NestedAlloca = dyn_cast<AllocaInst>(V)) {113 114 if (auto It = LifeTimeIntrinsicMap.find(NestedAlloca);115 It != LifeTimeIntrinsicMap.end()) {116 llvm::for_each(It->second,117 [](IntrinsicInst *II) { II->eraseFromParent(); });118 LifeTimeIntrinsicMap.erase(It);119 }120 121 for (auto *User : NestedAlloca->users()) {122 auto *Store = dyn_cast<StoreInst>(User);123 if (!Store)124 continue;125 126 Value *StoredVal = Store->getValueOperand();127 if (!StoredVal)128 continue;129 130 // Try direct global match131 GV = dyn_cast<GlobalVariable>(StoredVal);132 if (GV)133 break;134 135 // If it's a load, check its source136 if (auto *Load = dyn_cast<LoadInst>(StoredVal)) {137 GV = dyn_cast<GlobalVariable>(Load->getPointerOperand());138 if (GV)139 break;140 141 // If loading from an unmodified stack copy of the global, reuse the142 // global's value. Note: we are just repeating what we are doing for143 // the load case for the alloca store pattern.144 BasicBlock::iterator BBI(Load);145 Value *Loaded = FindAvailableLoadedValue(Load, Load->getParent(),146 BBI, 0, nullptr, nullptr);147 GV = dyn_cast<GlobalVariable>(Loaded);148 if (GV)149 break;150 }151 }152 }153 }154 155 auto It = HandleMap.find(GV);156 if (It == HandleMap.end()) {157 diagnoseHandleNotFound(LI);158 continue;159 }160 Changed = true;161 162 if (!DT.dominates(It->second, LI)) {163 diagnoseUndominatedLoad(LI, It->second);164 continue;165 }166 167 LLVM_DEBUG(dbgs() << "Replacing uses of " << GV->getName() << " at "168 << LI->getName() << " with " << It->second->getName()169 << "\n");170 LI->replaceAllUsesWith(It->second);171 LI->eraseFromParent();172 }173 174 return Changed;175}176 177PreservedAnalyses DXILForwardHandleAccesses::run(Function &F,178 FunctionAnalysisManager &AM) {179 PreservedAnalyses PA;180 181 DominatorTree *DT = &AM.getResult<DominatorTreeAnalysis>(F);182 bool Changed = forwardHandleAccesses(F, *DT);183 184 if (!Changed)185 return PreservedAnalyses::all();186 return PA;187}188 189namespace {190class DXILForwardHandleAccessesLegacy : public FunctionPass {191public:192 bool runOnFunction(Function &F) override {193 DominatorTree *DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();194 return forwardHandleAccesses(F, *DT);195 }196 StringRef getPassName() const override {197 return "DXIL Forward Handle Accesses";198 }199 200 void getAnalysisUsage(AnalysisUsage &AU) const override {201 AU.addRequired<DominatorTreeWrapperPass>();202 }203 204 DXILForwardHandleAccessesLegacy() : FunctionPass(ID) {}205 206 static char ID; // Pass identification.207};208char DXILForwardHandleAccessesLegacy::ID = 0;209} // end anonymous namespace210 211INITIALIZE_PASS_BEGIN(DXILForwardHandleAccessesLegacy, DEBUG_TYPE,212 "DXIL Forward Handle Accesses", false, false)213INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)214INITIALIZE_PASS_END(DXILForwardHandleAccessesLegacy, DEBUG_TYPE,215 "DXIL Forward Handle Accesses", false, false)216 217FunctionPass *llvm::createDXILForwardHandleAccessesLegacyPass() {218 return new DXILForwardHandleAccessesLegacy();219}220