LLVM 24.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
9#include "DXILShaderFlags.h"
10#include "DirectX.h"
11#include "llvm/ADT/STLExtras.h"
13#include "llvm/Analysis/Loads.h"
15#include "llvm/IR/Dominators.h"
16#include "llvm/IR/InstrTypes.h"
19#include "llvm/IR/Intrinsics.h"
20#include "llvm/IR/IntrinsicsDirectX.h"
21#include "llvm/IR/Module.h"
23#include "llvm/Pass.h"
25
26#define DEBUG_TYPE "dxil-forward-handle-accesses"
27
28using namespace llvm;
29
31 IntrinsicInst *PrevII) {
32 Function *F = NewII->getFunction();
33 LLVMContext &Context = F->getParent()->getContext();
34 Context.diagnose(DiagnosticInfoGeneric(
35 Twine("Handle at \"") + NewII->getName() + "\" overwrites handle at \"" +
36 PrevII->getName() + "\""));
37}
38
40 Function *F = LI->getFunction();
41 LLVMContext &Context = F->getParent()->getContext();
42 Context.diagnose(DiagnosticInfoGeneric(
43 LI, Twine("Load of \"") + LI->getPointerOperand()->getName() +
44 "\" is not a global resource handle"));
45}
46
48 Function *F = LI->getFunction();
49 LLVMContext &Context = F->getParent()->getContext();
50 Context.diagnose(DiagnosticInfoGeneric(
51 LI, Twine("Load at \"") + LI->getName() +
52 "\" is not dominated by handle creation at \"" +
53 Handle->getName() + "\""));
54}
55
56static void
59 for (User *U : II->users())
60 if (auto *SI = dyn_cast<StoreInst>(U))
61 if (auto *GV = dyn_cast<GlobalVariable>(SI->getPointerOperand())) {
62 auto Entry = HandleMap.try_emplace(GV, II);
63 if (Entry.second)
64 LLVM_DEBUG(dbgs() << "Added " << GV->getName() << " to handle map\n");
65 else
66 diagnoseAmbiguousHandle(II, Entry.first->second);
67 }
68}
69
71 bool Changed = false;
72
74 SmallVector<LoadInst *> LoadsToProcess;
76 for (BasicBlock &BB : F)
77 for (Instruction &Inst : BB)
78 if (auto *II = dyn_cast<IntrinsicInst>(&Inst)) {
79 switch (II->getIntrinsicID()) {
80 case Intrinsic::dx_resource_handlefrombinding:
81 case Intrinsic::dx_resource_handlefromimplicitbinding:
82 processHandle(II, HandleMap);
83 break;
84 case Intrinsic::lifetime_start:
85 case Intrinsic::lifetime_end:
86 if (II->arg_size() >= 1) {
87 Value *Ptr = II->getArgOperand(0);
88 if (auto *Alloca = dyn_cast<AllocaInst>(Ptr))
89 LifeTimeIntrinsicMap[Alloca].push_back(II);
90 }
91 break;
92 default:
93 continue;
94 }
95 } else if (auto *LI = dyn_cast<LoadInst>(&Inst))
96 if (isa<dxil::AnyResourceExtType>(LI->getType()))
97 LoadsToProcess.push_back(LI);
98
99 for (LoadInst *LI : LoadsToProcess) {
100 Value *V = LI->getPointerOperand();
101 auto *GV = dyn_cast<GlobalVariable>(V);
102
103 // If we didn't find the global, we may need to walk through a level of
104 // indirection. This generally happens at -O0.
105 if (!GV) {
106 if (auto *NestedLI = dyn_cast<LoadInst>(V)) {
107 BasicBlock::iterator BBI(NestedLI);
109 NestedLI, NestedLI->getParent(), BBI, 0, nullptr, nullptr);
111 } else if (auto *NestedAlloca = dyn_cast<AllocaInst>(V)) {
112
113 if (auto It = LifeTimeIntrinsicMap.find(NestedAlloca);
114 It != LifeTimeIntrinsicMap.end()) {
115 llvm::for_each(It->second,
116 [](IntrinsicInst *II) { II->eraseFromParent(); });
117 LifeTimeIntrinsicMap.erase(It);
118 }
119
120 for (auto *User : NestedAlloca->users()) {
122 if (!Store)
123 continue;
124
125 Value *StoredVal = Store->getValueOperand();
126 if (!StoredVal)
127 continue;
128
129 // Try direct global match
130 GV = dyn_cast<GlobalVariable>(StoredVal);
131 if (GV)
132 break;
133
134 // If it's a load, check its source
135 if (auto *Load = dyn_cast<LoadInst>(StoredVal)) {
136 GV = dyn_cast<GlobalVariable>(Load->getPointerOperand());
137 if (GV)
138 break;
139
140 // If loading from an unmodified stack copy of the global, reuse the
141 // global's value. Note: we are just repeating what we are doing for
142 // the load case for the alloca store pattern.
144 Value *Loaded = FindAvailableLoadedValue(Load, Load->getParent(),
145 BBI, 0, nullptr, nullptr);
146 GV = dyn_cast<GlobalVariable>(Loaded);
147 if (GV)
148 break;
149 }
150 }
151 }
152 }
153
154 auto It = HandleMap.find(GV);
155 if (It == HandleMap.end()) {
157 continue;
158 }
159 Changed = true;
160
161 if (!DT.dominates(It->second, LI)) {
162 diagnoseUndominatedLoad(LI, It->second);
163 continue;
164 }
165
166 LLVM_DEBUG(dbgs() << "Replacing uses of " << GV->getName() << " at "
167 << LI->getName() << " with " << It->second->getName()
168 << "\n");
169 LI->replaceAllUsesWith(It->second);
170 LI->eraseFromParent();
171 }
172
173 return Changed;
174}
175
187
188namespace {
189class DXILForwardHandleAccessesLegacy : public FunctionPass {
190public:
191 bool runOnFunction(Function &F) override {
192 DominatorTree *DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();
193 return forwardHandleAccesses(F, *DT);
194 }
195 StringRef getPassName() const override {
196 return "DXIL Forward Handle Accesses";
197 }
198
199 void getAnalysisUsage(AnalysisUsage &AU) const override {
200 AU.addRequired<DominatorTreeWrapperPass>();
201 }
202
203 DXILForwardHandleAccessesLegacy() : FunctionPass(ID) {}
204
205 static char ID; // Pass identification.
206};
207char DXILForwardHandleAccessesLegacy::ID = 0;
208} // end anonymous namespace
209
210INITIALIZE_PASS_BEGIN(DXILForwardHandleAccessesLegacy, DEBUG_TYPE,
211 "DXIL Forward Handle Accesses", false, false)
213INITIALIZE_PASS_END(DXILForwardHandleAccessesLegacy, DEBUG_TYPE,
214 "DXIL Forward Handle Accesses", false, false)
215
217 return new DXILForwardHandleAccessesLegacy();
218}
static void diagnoseHandleNotFound(LoadInst *LI)
static void diagnoseUndominatedLoad(LoadInst *LI, IntrinsicInst *Handle)
static void diagnoseAmbiguousHandle(IntrinsicInst *NewII, IntrinsicInst *PrevII)
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:54
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
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
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:766
iterator end()
Definition DenseMap.h:686
bool erase(const KeyT &Val)
Definition DenseMap.h:930
std::pair< iterator, bool > try_emplace(KeyT &&Key, Ts &&...Args)
Definition DenseMap.h:856
Analysis pass which computes a DominatorTree.
Definition Dominators.h:241
Legacy analysis pass which computes a DominatorTree.
Definition Dominators.h:277
Concrete subclass of DominatorTreeBase that is used to compute a normal dominator tree.
Definition Dominators.h:122
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.
FunctionPass class - This class is used to implement most global optimizations.
Definition Pass.h:312
LLVM_ABI const Function * getFunction() const
Return the function this instruction belongs to.
A wrapper class for inspecting calls to intrinsic functions.
This is an important class for using LLVM in a threaded context.
Definition LLVMContext.h:76
An instruction for reading from memory.
Value * getPointerOperand()
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)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
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:428
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
Definition Value.cpp:315
This is an optimization pass for GlobalISel generic memory operations.
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:1748
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
@ Load
The value being inserted comes from a load (InsertElement only).
@ Store
The extracted value is stored (ExtractElement only).
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:554
auto dyn_cast_or_null(const Y &Val)
Definition Casting.h:753
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
Definition Casting.h:547
AnalysisManager< Function > FunctionAnalysisManager
Convenience typedef for the Function analysis manager.
FunctionPass * createDXILForwardHandleAccessesLegacyPass()