@@ -59,39 +59,53 @@ class InstModCallbacks {
5959 // /
6060 // / NOTE: It is assumed that this operation will never invalidate instruction
6161 // / iterators.
62+ // /
63+ // / This can have compile-time implications and should be avoided
64+ // / whenever possible in favor of more structured optimization passes.
6265 std::function<void (Operand *use, SILValue newValue)> setUseValueFunc;
6366
6467 // / A function that takes in an instruction and deletes the inst.
6568 // /
66- // / Default implementation is instToDelete->eraseFromParent();
69+ // / This is used to invalidate dangling instruction pointers. The SIL will be
70+ // / invalid when it is invoked. The callback is only allowed to inspect the
71+ // / inline fields of \p instToDelete and iterate over the results. It is not
72+ // / allowed to dereference operands or iterate uses.
73+ // /
74+ // / See comments for notifyWillBeDeletedFunc.
75+ // /
76+ // / The default implementation is:
77+ // /
78+ // / instToDelete->eraseFromParent();
79+ // /
80+ // / The reason this callback is reponsible for deleting the instruction is to
81+ // / interoperate more easily with
82+ // / CanonicalizeInstruction::killInstruction(). This allows updates to choose
83+ // / whether to happen before or after deleting the instruction and possibly
84+ // / keep it around as a zombie object. All implementations must at least
85+ // / immediately remove all references to the instruction, including the parent
86+ // / block list.
6787 // /
68- // / NOTE: The reason why we have deleteInstFunc and notifyWillBeDeletedFunc is
69- // / InstModCallback supports 2 stage deletion where a callee passed
70- // / InstModCallback is allowed to drop all references to the instruction
71- // / before calling deleteInstFunc. In contrast, notifyWillBeDeletedFunc
72- // / assumes that the IR is in a good form before being called so that the
73- // / caller can via the callback gather state about the instruction that will
74- // / be deleted. As an example, see InstructionDeleter::deleteInstruction() in
75- // / InstOptUtils.cpp.
88+ // / TODO: When zombie instructions are implemented at the module level, we
89+ // / should move the eraseFromParent() functionality out of the callback.
7690 std::function<void (SILInstruction *instToDelete)> deleteInstFunc;
7791
78- // / If non-null, called before an instruction is deleted or has its references
79- // / dropped. If null, no-op.
92+ // / If non-null, called before a salient instruction is deleted or has its
93+ // / references dropped. If null, no-op.
8094 // /
81- // / NOTE: The reason why we have deleteInstFunc and notifyWillBeDeletedFunc is
82- // / InstModCallback supports 2 stage deletion where a callee passed
83- // / InstModCallback is allowed to drop all references to the instruction
84- // / before calling deleteInstFunc. In contrast, notifyWillBeDeletedFunc
85- // / assumes that the IR is in a good form before being called so that the
86- // / caller can via the callback gather state about the instruction that will
87- // / be deleted. As an example, see InstructionDeleter::deleteInstruction() in
88- // / InstOptUtils.cpp.
95+ // / This can be used to respond to dead instructions that will be deleted in
96+ // / the future. Unlike deleteInstFunc, the SIL will be in a valid
97+ // / state. However, arbitrary SIL transformations may happen between this
98+ // / invocation and actual instruction deletion.
8999 // /
90- // / NOTE: This is called in InstModCallback::deleteInst() if one does not use
91- // / a default bool argument to disable the notification. In general that
92- // / should only be done when one is writing custom handling and is performing
93- // / the notification ones self. It is assumed that the notification will be
94- // / called with a valid instruction.
100+ // / This callback is not guaranteed to be called for every deleted
101+ // / instruction. It cannot be used to invalidate dangling pointers. It is only
102+ // / called for "salient" instructions that likely create additional
103+ // / optimization opportunities when deleted. If a dead def-use chain is
104+ // / deleted, notification only occurs for the initial def.
105+ // /
106+ // / This is used in rare circumstances to update an optimization worklist. It
107+ // / should be avoided whenever possible in favor of more structured
108+ // / optimization passes.
95109 std::function<void (SILInstruction *instThatWillBeDeleted)>
96110 notifyWillBeDeletedFunc;
97111
@@ -265,6 +279,9 @@ void recursivelyDeleteTriviallyDeadInstructions(
265279 SILInstruction *inst, bool force = false ,
266280 InstModCallbacks callbacks = InstModCallbacks());
267281
282+ // / True if this instruction can be deleted if all its uses can also be deleted.
283+ bool isInstructionTriviallyDeletable (SILInstruction *inst);
284+
268285// / Perform a fast local check to see if the instruction is dead.
269286// /
270287// / This routine only examines the state of the instruction at hand.
@@ -279,11 +296,6 @@ bool isIntermediateRelease(SILInstruction *inst, EpilogueARCFunctionInfo *erfi);
279296void collectUsesOfValue (SILValue V,
280297 llvm::SmallPtrSetImpl<SILInstruction *> &Insts);
281298
282- // / Recursively erase all of the uses of the instruction (but not the
283- // / instruction itself)
284- void eraseUsesOfInstruction (SILInstruction *inst,
285- InstModCallbacks callbacks = InstModCallbacks());
286-
287299// / Recursively erase all of the uses of the value (but not the
288300// / value itself)
289301void eraseUsesOfValue (SILValue value);
@@ -375,7 +387,42 @@ bool tryCheckedCastBrJumpThreading(
375387// / cleaning up any dead code resulting from deleting those instructions. Use
376388// / this utility instead of
377389// / \c recursivelyDeleteTriviallyDeadInstruction.
390+ // /
391+ // / This is designed to be used with a single 'onDelete' callback, which is
392+ // / invoked consistently just before deleting each instruction. It's usually
393+ // / used to avoid iterator invalidation (see the updatingIterator() factory
394+ // / method). The other InstModCallbacks should generally be handled at a higher
395+ // / level, and avoided altogether if possible. The following two are supported
396+ // / for flexibility:
397+ // /
398+ // / callbacks.createdNewInst() is invoked incrementally when it fixes lifetimes
399+ // / while deleting a set of instructions, but the SIL may still be invalid
400+ // / relative to the new instruction.
401+ // /
402+ // / callbacks.notifyWillBeDeletedFunc() is invoked when a dead instruction is
403+ // / first recognized and was not already passed in by the client. During the
404+ // / callback, the to-be-deleted instruction has valid SIL. It's operands and
405+ // / uses can be inspected and cached. It will be deleted later during
406+ // / cleanupDeadInstructions().
407+ // /
408+ // / Note that the forceDelete* APIs only invoke notifyWillBeDeletedFunc() when
409+ // / an operand's definition will become dead after force-deleting the specified
410+ // / instruction. Some clients force-delete related instructions one at a
411+ // / time. They may not force-deleted. It's the client's responsiblity to invoke
412+ // / notifyWillBeDeletedFunc() on those explicitly deleted instructions if
413+ // / needed.
414+ // /
378415class InstructionDeleter {
416+ public:
417+ static InstructionDeleter updatingIterator (SILBasicBlock::iterator &iter) {
418+ auto onDelete = InstModCallbacks ().onDelete ([&](SILInstruction *deadInst) {
419+ if (deadInst->getIterator () == iter)
420+ ++iter;
421+ deadInst->eraseFromParent ();
422+ });
423+ return InstructionDeleter (onDelete);
424+ }
425+
379426private:
380427 // / A set vector of instructions that are found to be dead. The ordering of
381428 // / instructions in this set is important as when a dead instruction is
@@ -384,20 +431,33 @@ class InstructionDeleter {
384431 SmallSetVector<SILInstruction *, 8 > deadInstructions;
385432
386433 // / Callbacks used when adding/deleting instructions.
387- InstModCallbacks instModCallbacks ;
434+ InstModCallbacks callbacks ;
388435
389436public:
390- InstructionDeleter () : deadInstructions(), instModCallbacks() {}
391- InstructionDeleter (InstModCallbacks inputCallbacks)
392- : deadInstructions(), instModCallbacks(inputCallbacks) {}
437+ InstructionDeleter () : deadInstructions(), callbacks() {}
438+ InstructionDeleter (InstModCallbacks callbacks)
439+ : deadInstructions(), callbacks(callbacks) {}
440+
441+ InstModCallbacks &getCallbacks () { return callbacks; }
393442
394443 // / If the instruction \p inst is dead, record it so that it can be cleaned
395444 // / up.
396- void trackIfDead (SILInstruction *inst);
445+ // /
446+ // / Calls callbacks.notifyWillBeDeleted().
447+ bool trackIfDead (SILInstruction *inst);
448+
449+ // / Force track this instruction as dead. Used to enable the deletion of a
450+ // / bunch of instructions at the same time.
451+ // /
452+ // / Calls callbacks.notifyWillBeDeleted().
453+ void forceTrackAsDead (SILInstruction *inst);
397454
398- // / If the instruction \p inst is dead, delete it immediately and record
399- // / its operands so that they can be cleaned up later.
400- void deleteIfDead (SILInstruction *inst);
455+ // / If the instruction \p inst is dead, delete it immediately along with its
456+ // / destroys and scope-ending uses, and record its operands so that they can
457+ // / be cleaned up later.
458+ // /
459+ // / Calls callbacks.notifyWillBeDeleted().
460+ bool deleteIfDead (SILInstruction *inst);
401461
402462 // / Delete the instruction \p inst and record instructions that may become
403463 // / dead because of the removal of \c inst. This function will add necessary
@@ -411,10 +471,8 @@ class InstructionDeleter {
411471 // / \pre the instruction to be deleted must not have any use other than
412472 // / incidental uses.
413473 // /
414- // / \p callback is called on each deleted instruction before deleting any
415- // / instructions. This way, the SIL is valid in the callback. However, the
416- // / callback cannot be used to update instruction iterators since other
417- // / instructions to be deleted remain in the instruction list.
474+ // / callbacks.notifyWillBeDeleted will not be called for \p inst but will be
475+ // / called for any other instructions that become dead as a result.
418476 void forceDeleteAndFixLifetimes (SILInstruction *inst);
419477
420478 // / Delete the instruction \p inst and record instructions that may become
@@ -429,11 +487,19 @@ class InstructionDeleter {
429487 // /
430488 // / \pre the instruction to be deleted must not have any use other than
431489 // / incidental uses.
490+ // /
491+ // / callbacks.notifyWillBeDeleted will not be called for \p inst but will be
492+ // / called for any other instructions that become dead as a result.
432493 void forceDelete (SILInstruction *inst);
433494
434- // / Force track this instruction as dead. Used to enable the deletion of a
435- // / bunch of instructions at the same time.
436- void forceTrackAsDead (SILInstruction *inst);
495+ // / Recursively delete all of the uses of the instruction before deleting the
496+ // / instruction itself. Does not fix lifetimes.
497+ // /
498+ // / callbacks.notifyWillBeDeleted will not be called for \p inst but will
499+ // / be called for any other instructions that become dead as a result.
500+ void forceDeleteWithUsers (SILInstruction *inst) {
501+ deleteWithUses (inst, /* fixLifetimes*/ false , /* forceDeleteUsers*/ true );
502+ }
437503
438504 // / Clean up dead instructions that are tracked by this instance and all
439505 // / instructions that transitively become dead.
@@ -442,19 +508,30 @@ class InstructionDeleter {
442508 // / under or over releases). Note that if \c forceDelete call leaves the
443509 // / function body in an inconsistent state, it needs to be made consistent
444510 // / before this method is invoked.
445- void cleanUpDeadInstructions ();
511+ // /
512+ // / callbacks.notifyWillBeDeletedFunc will only be called for instructions
513+ // / that become dead during cleanup but were not already tracked.
514+ void cleanupDeadInstructions ();
446515
447- // / Recursively visit users of \c inst (including \c inst)and delete
448- // / instructions that are dead (including \c inst).
516+ // / Recursively visit users of \p inst and delete instructions that are dead
517+ // / including \p inst.
518+ // /
519+ // / callbacks.notifyWillBeDeletedFunc will be called for any dead
520+ // / instructions.
449521 void recursivelyDeleteUsersIfDead (SILInstruction *inst);
450522
451- // / Recursively visit users of \c inst (including \c inst) and force delete
452- // / them . Also, destroy the consumed operands of the deleted instructions
523+ // / Recursively visit users of \p inst and force delete them including \p
524+ // / inst . Also, destroy the consumed operands of the deleted instructions
453525 // / whenever necessary.
526+ // /
527+ // / callbacks.notifyWillBeDeletedFunc will not be called for \p inst or its
528+ // / users but will be called for any other instructions that become dead as a
529+ // / result.
454530 void recursivelyForceDeleteUsersAndFixLifetimes (SILInstruction *inst);
455531
456532private:
457- void deleteInstruction (SILInstruction *inst, bool fixOperandLifetimes);
533+ void deleteWithUses (SILInstruction *inst, bool fixLifetimes,
534+ bool forceDeleteUsers = false );
458535};
459536
460537// / If \c inst is dead, delete it and recursively eliminate all code that
0 commit comments