Move InstructionDeleter into its own header.

Add file-level comments on the utility's purpose and intended API
usage.

Cleanup API comments.
This commit is contained in:
Andrew Trick
2021-11-18 11:34:15 -08:00
parent c569b39802
commit b517cce16f
5 changed files with 664 additions and 555 deletions

View File

@@ -28,7 +28,6 @@
#include "swift/SILOptimizer/Analysis/EpilogueARCAnalysis.h"
#include "swift/SILOptimizer/Analysis/SimplifyInstruction.h"
#include "swift/SILOptimizer/Utils/InstModCallbacks.h"
#include "swift/SILOptimizer/Utils/UpdatingInstructionIterator.h"
#include "llvm/ADT/SmallPtrSet.h"
namespace swift {
@@ -76,6 +75,20 @@ bool hasOnlyEndOfScopeOrEndOfLifetimeUses(SILInstruction *inst);
/// Return the number of @inout arguments passed to the given apply site.
unsigned getNumInOutArguments(FullApplySite applySite);
/// If \c inst is dead, delete it and recursively eliminate all code that
/// becomes dead because of that. If more than one instruction must
/// be checked/deleted use the \c InstructionDeleter utility.
///
/// This function will add necessary compensation code to fix the lifetimes of
/// the operands of the deleted instructions.
///
/// \pre the SIL function containing the instruction is assumed to be
/// consistent, i.e., does not have under or over releases.
///
/// \p callbacks.onDelete() is invoked to delete each instruction.
void eliminateDeadInstruction(SILInstruction *inst,
InstModCallbacks callbacks = InstModCallbacks());
/// For each of the given instructions, if they are dead delete them
/// along with their dead operands. Note this utility must be phased out and
/// replaced by \c eliminateDeadInstruction and
@@ -85,6 +98,8 @@ unsigned getNumInOutArguments(FullApplySite applySite);
/// \param force If Force is set, don't check if the top level instructions
/// are considered dead - delete them regardless.
/// \param callbacks The inst mod callbacks used to delete instructions.
///
/// Deprecated: Use InstructionDeleter instead.
void recursivelyDeleteTriviallyDeadInstructions(
ArrayRef<SILInstruction *> inst, bool force = false,
InstModCallbacks callbacks = InstModCallbacks());
@@ -98,6 +113,8 @@ void recursivelyDeleteTriviallyDeadInstructions(
/// \param force If Force is set, don't check if the top level instruction is
/// considered dead - delete it regardless.
/// \param callbacks InstModCallback used to delete instructions.
///
/// Deprecated: Use InstructionDeleter instead.
void recursivelyDeleteTriviallyDeadInstructions(
SILInstruction *inst, bool force = false,
InstModCallbacks callbacks = InstModCallbacks());
@@ -207,181 +224,6 @@ bool tryCheckedCastBrJumpThreading(
SmallVectorImpl<SILBasicBlock *> &blocksForWorklist,
bool EnableOSSARewriteTerminator);
/// A utility for deleting one or more instructions belonging to a function, and
/// cleaning up any dead code resulting from deleting those instructions. Use
/// this utility instead of \p recursivelyDeleteTriviallyDeadInstruction
/// as follows:
/// InstructionDeleter deleter;
/// deleter.deleteIfDead(instruction);
/// deleter.cleanupDeadInstructions();
///
/// This is designed to be used with a single 'onDelete' callback, which is
/// invoked consistently just before deleting each instruction. It's usually
/// used to avoid iterator invalidation (see the updatingIterator() factory
/// method). The other InstModCallbacks should generally be handled at a higher
/// level, and avoided altogether if possible. The following two are supported
/// for flexibility:
///
/// callbacks.createdNewInst() is invoked incrementally when it fixes lifetimes
/// while deleting a set of instructions, but the SIL may still be invalid
/// relative to the new instruction.
///
/// callbacks.notifyWillBeDeletedFunc() is invoked when a dead instruction is
/// first recognized and was not already passed in by the client. During the
/// callback, the to-be-deleted instruction has valid SIL. It's operands and
/// uses can be inspected and cached. It will be deleted later during
/// cleanupDeadInstructions().
///
/// Note that the forceDelete* APIs only invoke notifyWillBeDeletedFunc() when
/// an operand's definition will become dead after force-deleting the specified
/// instruction. Some clients force-delete related instructions one at a
/// time. It is the client's responsiblity to invoke notifyWillBeDeletedFunc()
/// on those explicitly deleted instructions if needed.
class InstructionDeleter {
/// A set vector of instructions that are found to be dead. The ordering of
/// instructions in this set is important as when a dead instruction is
/// removed, new instructions will be generated to fix the lifetime of the
/// instruction's operands. This has to be deterministic.
SmallSetVector<SILInstruction *, 8> deadInstructions;
UpdatingInstructionIteratorRegistry iteratorRegistry;
public:
InstructionDeleter(InstModCallbacks chainedCallbacks = InstModCallbacks())
: deadInstructions(), iteratorRegistry(chainedCallbacks) {}
UpdatingInstructionIteratorRegistry &getIteratorRegistry() {
return iteratorRegistry;
}
InstModCallbacks &getCallbacks() { return iteratorRegistry.getCallbacks(); }
llvm::iterator_range<UpdatingInstructionIterator>
updatingRange(SILBasicBlock *bb) {
return iteratorRegistry.makeIteratorRange(bb);
}
llvm::iterator_range<UpdatingReverseInstructionIterator>
updatingReverseRange(SILBasicBlock *bb) {
return iteratorRegistry.makeReverseIteratorRange(bb);
}
bool hadCallbackInvocation() const {
return const_cast<InstructionDeleter *>(this)
->getCallbacks()
.hadCallbackInvocation();
}
/// If the instruction \p inst is dead, record it so that it can be cleaned
/// up.
///
/// Calls callbacks.notifyWillBeDeleted().
bool trackIfDead(SILInstruction *inst);
/// Track this instruction as dead even if it has side effects. Used to enable
/// the deletion of a bunch of instructions at the same time.
///
/// Calls callbacks.notifyWillBeDeleted().
void forceTrackAsDead(SILInstruction *inst);
/// If the instruction \p inst is dead, delete it immediately along with its
/// destroys and scope-ending uses. If any operand definitions will become
/// dead after deleting this instruction, track them so they can be deleted
/// later during cleanUpDeadInstructions().
///
/// Calls callbacks.notifyWillBeDeleted().
bool deleteIfDead(SILInstruction *inst);
/// Delete the instruction \p inst, ignoring its side effects. If any operand
/// definitions will become dead after deleting this instruction, track them
/// so they can be deleted later during cleanUpDeadInstructions(). This
/// function will add necessary ownership instructions to fix the lifetimes of
/// the operands of \p inst to compensate for its deletion.
///
/// \pre the function containing \p inst must be using ownership SIL.
/// \pre the instruction to be deleted must not have any use other than
/// incidental uses.
///
/// callbacks.notifyWillBeDeleted will not be called for \p inst but will be
/// called for any other instructions that become dead as a result.
void forceDeleteAndFixLifetimes(SILInstruction *inst);
/// Delete the instruction \p inst and record instructions that may become
/// dead because of the removal of \c inst. If in ownership SIL, use the
/// \c forceDeleteAndFixLifetimes function instead, unless under special
/// circumstances where the client must handle fixing lifetimes of the
/// operands of the deleted instructions. This function will not fix the
/// lifetimes of the operands of \c inst once it is deleted. This function
/// will not clean up dead code resulting from the instruction's removal. To
/// do so, invoke the method \c cleanupDeadCode of this instance, once the SIL
/// of the contaning function is made consistent.
///
/// \pre the instruction to be deleted must not have any use other than
/// incidental uses.
///
/// callbacks.notifyWillBeDeleted will not be called for \p inst but will be
/// called for any other instructions that become dead as a result.
void forceDelete(SILInstruction *inst);
/// Recursively delete all of the uses of the instruction before deleting the
/// instruction itself. Does not fix lifetimes.
///
/// callbacks.notifyWillBeDeleted will not be called for \p inst but will
/// be called for any other instructions that become dead as a result.
void forceDeleteWithUsers(SILInstruction *inst) {
deleteWithUses(inst, /*fixLifetimes*/ false, /*forceDeleteUsers*/ true);
}
/// Clean up dead instructions that are tracked by this instance and all
/// instructions that transitively become dead.
///
/// \pre the function contaning dead instructions must be consistent (i.e., no
/// under or over releases). Note that if \c forceDelete call leaves the
/// function body in an inconsistent state, it needs to be made consistent
/// before this method is invoked.
///
/// callbacks.notifyWillBeDeletedFunc will only be called for instructions
/// that become dead during cleanup but were not already tracked.
void cleanupDeadInstructions();
/// Recursively visit users of \p inst and delete instructions that are dead
/// including \p inst.
///
/// callbacks.notifyWillBeDeletedFunc will be called for any dead
/// instructions.
void recursivelyDeleteUsersIfDead(SILInstruction *inst);
/// Recursively visit users of \p inst and force delete them including \p
/// inst. Also, destroy the consumed operands of the deleted instructions
/// whenever necessary.
///
/// callbacks.notifyWillBeDeletedFunc will not be called for \p inst or its
/// users but will be called for any other instructions that become dead as a
/// result.
void recursivelyForceDeleteUsersAndFixLifetimes(SILInstruction *inst);
private:
void deleteWithUses(SILInstruction *inst, bool fixLifetimes,
bool forceDeleteUsers = false);
};
/// If \c inst is dead, delete it and recursively eliminate all code that
/// becomes dead because of that. If more than one instruction must
/// be checked/deleted use the \c InstructionDeleter utility.
///
/// This function will add necessary compensation code to fix the lifetimes of
/// the operands of the deleted instructions.
///
/// \pre the SIL function containing the instruction is assumed to be
/// consistent, i.e., does not have under or over releases.
///
/// \p callbacks is used to delete each instruction. However, the callback
/// cannot be used to update instruction iterators since other instructions to
/// be deleted remain in the instruction list. If set to nullptr, we use the
/// default instruction modification callback structure.
void eliminateDeadInstruction(SILInstruction *inst,
InstModCallbacks callbacks = InstModCallbacks());
/// Get all consumed arguments of a partial_apply.
///
/// These are basically all arguments, except inout arguments and arguments
@@ -731,4 +573,4 @@ bool eliminateDeadAllocations(SILFunction &fn);
} // end namespace swift
#endif
#endif // SWIFT_SILOPTIMIZER_UTILS_INSTOPTUTILS_H