8
8
9
9
#include " DXILResourceAccess.h"
10
10
#include " DirectX.h"
11
+ #include " llvm/ADT/SetVector.h"
11
12
#include " llvm/Analysis/DXILResource.h"
13
+ #include " llvm/IR/BasicBlock.h"
12
14
#include " llvm/IR/Dominators.h"
13
15
#include " llvm/IR/IRBuilder.h"
16
+ #include " llvm/IR/Instruction.h"
14
17
#include " llvm/IR/Instructions.h"
15
18
#include " llvm/IR/IntrinsicInst.h"
16
19
#include " llvm/IR/Intrinsics.h"
17
20
#include " llvm/IR/IntrinsicsDirectX.h"
21
+ #include " llvm/IR/User.h"
18
22
#include " llvm/InitializePasses.h"
23
+ #include " llvm/Transforms/Utils/ValueMapper.h"
19
24
20
25
#define DEBUG_TYPE " dxil-resource-access"
21
26
@@ -198,6 +203,112 @@ static void createLoadIntrinsic(IntrinsicInst *II, LoadInst *LI, Value *Offset,
198
203
llvm_unreachable (" Unhandled case in switch" );
199
204
}
200
205
206
+ static SmallVector<Instruction *> collectBlockUseDef (Instruction *Start) {
207
+ SmallPtrSet<Instruction *, 32 > Visited;
208
+ SmallVector<Instruction *, 32 > Worklist;
209
+ SmallVector<Instruction *> Out;
210
+ auto *BB = Start->getParent ();
211
+
212
+ // Seed with direct users in this block.
213
+ for (User *U : Start->users ()) {
214
+ if (auto *I = dyn_cast<Instruction>(U)) {
215
+ if (I->getParent () == BB)
216
+ Worklist.push_back (I);
217
+ }
218
+ }
219
+
220
+ // BFS over transitive users, constrained to the same block.
221
+ while (!Worklist.empty ()) {
222
+ Instruction *I = Worklist.pop_back_val ();
223
+ if (!Visited.insert (I).second )
224
+ continue ;
225
+ Out.push_back (I);
226
+
227
+ for (User *U : I->users ()) {
228
+ if (auto *J = dyn_cast<Instruction>(U)) {
229
+ if (J->getParent () == BB)
230
+ Worklist.push_back (J);
231
+ }
232
+ }
233
+ for (Use &V : I->operands ()) {
234
+ if (auto *J = dyn_cast<Instruction>(V)) {
235
+ if (J->getParent () == BB && V != Start)
236
+ Worklist.push_back (J);
237
+ }
238
+ }
239
+ }
240
+
241
+ // Order results in program order.
242
+ DenseMap<const Instruction *, unsigned > Ord;
243
+ unsigned Idx = 0 ;
244
+ for (Instruction &I : *BB)
245
+ Ord[&I] = Idx++;
246
+
247
+ llvm::sort (Out, [&](Instruction *A, Instruction *B) {
248
+ return Ord.lookup (A) < Ord.lookup (B);
249
+ });
250
+
251
+ return Out;
252
+ }
253
+
254
+ static void phiNodeRemapHelper (PHINode *Phi, BasicBlock *BB,
255
+ IRBuilder<> &Builder,
256
+ SmallVector<Instruction *> &UsesInBlock) {
257
+
258
+ ValueToValueMapTy VMap;
259
+ Value *Val = Phi->getIncomingValueForBlock (BB);
260
+ VMap[Phi] = Val;
261
+ Builder.SetInsertPoint (&BB->back ());
262
+ for (Instruction *I : UsesInBlock) {
263
+ // don't clone over the Phi just remap them
264
+ if (auto *PhiNested = dyn_cast<PHINode>(I)) {
265
+ VMap[PhiNested] = PhiNested->getIncomingValueForBlock (BB);
266
+ continue ;
267
+ }
268
+ Instruction *Clone = I->clone ();
269
+ RemapInstruction (Clone, VMap,
270
+ RF_NoModuleLevelChanges | RF_IgnoreMissingLocals);
271
+ Builder.Insert (Clone);
272
+ VMap[I] = Clone;
273
+ }
274
+ }
275
+
276
+ static void phiNodeReplacement (IntrinsicInst *II,
277
+ SmallVectorImpl<Instruction *> &PrevBBDeadInsts,
278
+ SetVector<BasicBlock *> &DeadBB) {
279
+ SmallVector<Instruction *> CurrBBDeadInsts;
280
+ for (User *U : II->users ()) {
281
+ auto *Phi = dyn_cast<PHINode>(U);
282
+ if (!Phi)
283
+ continue ;
284
+
285
+ IRBuilder<> Builder (Phi);
286
+ SmallVector<Instruction *> UsesInBlock = collectBlockUseDef (Phi);
287
+ bool HasReturnUse = isa<ReturnInst>(UsesInBlock.back ());
288
+
289
+ for (unsigned I = 0 , E = Phi->getNumIncomingValues (); I < E; I++) {
290
+ auto *CurrIncomingBB = Phi->getIncomingBlock (I);
291
+ phiNodeRemapHelper (Phi, CurrIncomingBB, Builder, UsesInBlock);
292
+ if (HasReturnUse)
293
+ PrevBBDeadInsts.push_back (&CurrIncomingBB->back ());
294
+ }
295
+
296
+ CurrBBDeadInsts.push_back (Phi);
297
+
298
+ for (Instruction *I : UsesInBlock) {
299
+ CurrBBDeadInsts.push_back (I);
300
+ }
301
+ if (HasReturnUse) {
302
+ BasicBlock *PhiBB = Phi->getParent ();
303
+ DeadBB.insert (PhiBB);
304
+ }
305
+ }
306
+ // Traverse the now-dead instructions in RPO and remove them.
307
+ for (Instruction *Dead : llvm::reverse (CurrBBDeadInsts))
308
+ Dead->eraseFromParent ();
309
+ CurrBBDeadInsts.clear ();
310
+ }
311
+
201
312
static void replaceAccess (IntrinsicInst *II, dxil::ResourceTypeInfo &RTI) {
202
313
// Process users keeping track of indexing accumulated from GEPs.
203
314
struct AccessAndOffset {
@@ -229,7 +340,6 @@ static void replaceAccess(IntrinsicInst *II, dxil::ResourceTypeInfo &RTI) {
229
340
} else if (auto *LI = dyn_cast<LoadInst>(Current.Access )) {
230
341
createLoadIntrinsic (II, LI, Current.Offset , RTI);
231
342
DeadInsts.push_back (LI);
232
-
233
343
} else
234
344
llvm_unreachable (" Unhandled instruction - pointer escaped?" );
235
345
}
@@ -242,13 +352,27 @@ static void replaceAccess(IntrinsicInst *II, dxil::ResourceTypeInfo &RTI) {
242
352
243
353
static bool transformResourcePointers (Function &F, DXILResourceTypeMap &DRTM) {
244
354
SmallVector<std::pair<IntrinsicInst *, dxil::ResourceTypeInfo>> Resources;
245
- for (BasicBlock &BB : F)
355
+ SetVector<BasicBlock *> DeadBB;
356
+ SmallVector<Instruction *> PrevBBDeadInsts;
357
+ for (BasicBlock &BB : make_early_inc_range (F)) {
358
+ for (Instruction &I : make_early_inc_range (BB))
359
+ if (auto *II = dyn_cast<IntrinsicInst>(&I))
360
+ if (II->getIntrinsicID () == Intrinsic::dx_resource_getpointer)
361
+ phiNodeReplacement (II, PrevBBDeadInsts, DeadBB);
362
+
246
363
for (Instruction &I : BB)
247
364
if (auto *II = dyn_cast<IntrinsicInst>(&I))
248
365
if (II->getIntrinsicID () == Intrinsic::dx_resource_getpointer) {
249
366
auto *HandleTy = cast<TargetExtType>(II->getArgOperand (0 )->getType ());
250
367
Resources.emplace_back (II, DRTM[HandleTy]);
251
368
}
369
+ }
370
+ for (auto *Dead : PrevBBDeadInsts)
371
+ Dead->eraseFromParent ();
372
+ PrevBBDeadInsts.clear ();
373
+ for (auto *Dead : DeadBB)
374
+ Dead->eraseFromParent ();
375
+ DeadBB.clear ();
252
376
253
377
for (auto &[II, RI] : Resources)
254
378
replaceAccess (II, RI);
@@ -279,7 +403,6 @@ class DXILResourceAccessLegacy : public FunctionPass {
279
403
bool runOnFunction (Function &F) override {
280
404
DXILResourceTypeMap &DRTM =
281
405
getAnalysis<DXILResourceTypeWrapperPass>().getResourceTypeMap ();
282
-
283
406
return transformResourcePointers (F, DRTM);
284
407
}
285
408
StringRef getPassName () const override { return " DXIL Resource Access" ; }
0 commit comments