LLVM 22.0.0git
DXILForwardHandleAccesses.cpp
Go to the documentation of this file.
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
10#include "DXILShaderFlags.h"
11#include "DirectX.h"
12#include "llvm/ADT/STLExtras.h"
14#include "llvm/Analysis/Loads.h"
16#include "llvm/IR/Dominators.h"
17#include "llvm/IR/InstrTypes.h"
20#include "llvm/IR/Intrinsics.h"
21#include "llvm/IR/IntrinsicsDirectX.h"
22#include "llvm/IR/Module.h"
24#include "llvm/Pass.h"
26
27#define DEBUG_TYPE "dxil-forward-handle-accesses"
28
29using namespace llvm;
30
32 IntrinsicInst *PrevII) {
33 Function *F = NewII->getFunction();
34 LLVMContext &Context = F->getParent()->getContext();
36 Twine("Handle at \"") + NewII->getName() + "\" overwrites handle at \"" +
37 PrevII->getName() + "\""));
38}
39
41 Function *F = LI->getFunction();
42 LLVMContext &Context = F->getParent()->getContext();
44 LI, Twine("Load of \"") + LI->getPointerOperand()->getName() +
45 "\" is not a global resource handle"));
46}
47
49 Function *F = LI->getFunction();
50 LLVMContext &Context = F->getParent()->getContext();
52 LI, Twine("Load at \"") + LI->getName() +
53 "\" is not dominated by handle creation at \"" +
54 Handle->getName() + "\""));
55}
56
57static void
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 else
67 diagnoseAmbiguousHandle(II, Entry.first->second);
68 }
69}
70
72 bool Changed = false;
73
75 SmallVector<LoadInst *> LoadsToProcess;
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 of
105 // indirection. This generally happens at -O0.
106 if (!GV) {
107 if (auto *NestedLI = dyn_cast<LoadInst>(V)) {
108 BasicBlock::iterator BBI(NestedLI);
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 match
131 GV = dyn_cast<GlobalVariable>(StoredVal);
132 if (GV)
133 break;
134
135 // If it's a load, check its source
136 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 the
142 // global's value. Note: we are just repeating what we are doing for
143 // 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()) {
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
180
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 {
202 }
203
204 DXILForwardHandleAccessesLegacy() : FunctionPass(ID) {}
205
206 static char ID; // Pass identification.
207};
208char DXILForwardHandleAccessesLegacy::ID = 0;
209} // end anonymous namespace
210
211INITIALIZE_PASS_BEGIN(DXILForwardHandleAccessesLegacy, DEBUG_TYPE,
212 "DXIL Forward Handle Accesses", false, false)
214INITIALIZE_PASS_END(DXILForwardHandleAccessesLegacy, DEBUG_TYPE,
215 "DXIL Forward Handle Accesses", false, false)
216
218 return new DXILForwardHandleAccessesLegacy();
219}
static void diagnoseHandleNotFound(LoadInst *LI)
static void diagnoseUndominatedLoad(LoadInst *LI, IntrinsicInst *Handle)
static void diagnoseAmbiguousHandle(IntrinsicInst *NewII, IntrinsicInst *PrevII)
DXIL Forward Handle Accesses
static bool forwardHandleAccesses(Function &F, DominatorTree &DT)
static void processHandle(IntrinsicInst *II, DenseMap< GlobalVariable *, IntrinsicInst * > &HandleMap)
static bool runOnFunction(Function &F, bool PostInlining)
#define DEBUG_TYPE
Module.h This file contains the declarations for the Module class.
#define F(x, y, z)
Definition: MD5.cpp:55
uint64_t IntrinsicInst * II
#define INITIALIZE_PASS_DEPENDENCY(depName)
Definition: PassSupport.h:42
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
Definition: PassSupport.h:44
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
Definition: PassSupport.h:39
This file contains some templates that are useful if you are working with the STL at all.
#define LLVM_DEBUG(...)
Definition: Debug.h:119
A container for analyses that lazily runs them and caches their results.
Definition: PassManager.h:255
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
Definition: PassManager.h:412
Represent the analysis usage information of a pass.
AnalysisUsage & addRequired()
LLVM Basic Block Representation.
Definition: BasicBlock.h:62
InstListType::iterator iterator
Instruction iterators...
Definition: BasicBlock.h:170
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM)
iterator find(const_arg_type_t< KeyT > Val)
Definition: DenseMap.h:177
std::pair< iterator, bool > try_emplace(KeyT &&Key, Ts &&...Args)
Definition: DenseMap.h:245
bool erase(const KeyT &Val)
Definition: DenseMap.h:319
iterator end()
Definition: DenseMap.h:87
Analysis pass which computes a DominatorTree.
Definition: Dominators.h:284
Legacy analysis pass which computes a DominatorTree.
Definition: Dominators.h:322
Concrete subclass of DominatorTreeBase that is used to compute a normal dominator tree.
Definition: Dominators.h:165
LLVM_ABI bool dominates(const BasicBlock *BB, const Use &U) const
Return true if the (end of the) basic block BB dominates the use U.
Definition: Dominators.cpp:135
FunctionPass class - This class is used to implement most global optimizations.
Definition: Pass.h:314
LLVM_ABI const Function * getFunction() const
Return the function this instruction belongs to.
Definition: Instruction.cpp:82
A wrapper class for inspecting calls to intrinsic functions.
Definition: IntrinsicInst.h:49
This is an important class for using LLVM in a threaded context.
Definition: LLVMContext.h:68
An instruction for reading from memory.
Definition: Instructions.h:180
Value * getPointerOperand()
Definition: Instructions.h:259
A set of analyses that are preserved following a run of a transformation pass.
Definition: Analysis.h:112
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition: Analysis.h:118
void push_back(const T &Elt)
Definition: SmallVector.h:414
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1197
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:55
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition: Twine.h:82
LLVM Value Representation.
Definition: Value.h:75
iterator_range< user_iterator > users()
Definition: Value.h:426
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
Definition: Value.cpp:322
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition: CallingConv.h:24
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
UnaryFunction for_each(R &&Range, UnaryFunction F)
Provide wrappers to std::for_each which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1737
LLVM_ABI Value * FindAvailableLoadedValue(LoadInst *Load, BasicBlock *ScanBB, BasicBlock::iterator &ScanFrom, unsigned MaxInstsToScan=DefMaxInstsToScan, BatchAAResults *AA=nullptr, bool *IsLoadCSE=nullptr, unsigned *NumScanedInst=nullptr)
Scan backwards to see if we have the value of the given load available locally within a small number ...
Definition: Loads.cpp:538
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:207
FunctionPass * createDXILForwardHandleAccessesLegacyPass()
Pass to eliminate redundant stores and loads from handle globals.