88
99#include " DXILResourceAccess.h"
1010#include " DirectX.h"
11+ #include " llvm/ADT/SetVector.h"
1112#include " llvm/Analysis/DXILResource.h"
13+ #include " llvm/IR/BasicBlock.h"
1214#include " llvm/IR/Dominators.h"
1315#include " llvm/IR/IRBuilder.h"
16+ #include " llvm/IR/Instruction.h"
1417#include " llvm/IR/Instructions.h"
1518#include " llvm/IR/IntrinsicInst.h"
1619#include " llvm/IR/Intrinsics.h"
1720#include " llvm/IR/IntrinsicsDirectX.h"
21+ #include " llvm/IR/User.h"
1822#include " llvm/InitializePasses.h"
23+ #include " llvm/Transforms/Utils/ValueMapper.h"
1924
2025#define DEBUG_TYPE " dxil-resource-access"
2126
@@ -198,6 +203,112 @@ static void createLoadIntrinsic(IntrinsicInst *II, LoadInst *LI, Value *Offset,
198203 llvm_unreachable (" Unhandled case in switch" );
199204}
200205
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+
201312static void replaceAccess (IntrinsicInst *II, dxil::ResourceTypeInfo &RTI) {
202313 // Process users keeping track of indexing accumulated from GEPs.
203314 struct AccessAndOffset {
@@ -229,7 +340,6 @@ static void replaceAccess(IntrinsicInst *II, dxil::ResourceTypeInfo &RTI) {
229340 } else if (auto *LI = dyn_cast<LoadInst>(Current.Access )) {
230341 createLoadIntrinsic (II, LI, Current.Offset , RTI);
231342 DeadInsts.push_back (LI);
232-
233343 } else
234344 llvm_unreachable (" Unhandled instruction - pointer escaped?" );
235345 }
@@ -242,13 +352,27 @@ static void replaceAccess(IntrinsicInst *II, dxil::ResourceTypeInfo &RTI) {
242352
243353static bool transformResourcePointers (Function &F, DXILResourceTypeMap &DRTM) {
244354 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+
246363 for (Instruction &I : BB)
247364 if (auto *II = dyn_cast<IntrinsicInst>(&I))
248365 if (II->getIntrinsicID () == Intrinsic::dx_resource_getpointer) {
249366 auto *HandleTy = cast<TargetExtType>(II->getArgOperand (0 )->getType ());
250367 Resources.emplace_back (II, DRTM[HandleTy]);
251368 }
369+ }
370+ for (auto *Dead : PrevBBDeadInsts)
371+ Dead->eraseFromParent ();
372+ PrevBBDeadInsts.clear ();
373+ for (auto *Dead : DeadBB)
374+ Dead->eraseFromParent ();
375+ DeadBB.clear ();
252376
253377 for (auto &[II, RI] : Resources)
254378 replaceAccess (II, RI);
@@ -279,7 +403,6 @@ class DXILResourceAccessLegacy : public FunctionPass {
279403 bool runOnFunction (Function &F) override {
280404 DXILResourceTypeMap &DRTM =
281405 getAnalysis<DXILResourceTypeWrapperPass>().getResourceTypeMap ();
282-
283406 return transformResourcePointers (F, DRTM);
284407 }
285408 StringRef getPassName () const override { return " DXIL Resource Access" ; }
0 commit comments