mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Merge pull request #62480 from eeckstein/instruction-iteration
SIL: simplify deleting instructions while iterating over instructions.
This commit is contained in:
@@ -31,6 +31,51 @@ class SILFunction;
|
||||
class SILArgument;
|
||||
class SILPrintContext;
|
||||
|
||||
/// Instruction iterator which allows to "delete" instructions while iterating
|
||||
/// over the instruction list.
|
||||
///
|
||||
/// Iteration with this iterator allows to delete the current, the next or any
|
||||
/// instruction in the list while iterating.
|
||||
/// This works because instruction deletion is deferred (for details see
|
||||
/// `SILModule::scheduledForDeletion`) and removing an instruction from the list
|
||||
/// keeps the prev/next pointers (see `SILInstructionListBase`).
|
||||
template <typename IteratorBase>
|
||||
class DeletableInstructionsIterator {
|
||||
using Self = DeletableInstructionsIterator<IteratorBase>;
|
||||
|
||||
IteratorBase base;
|
||||
IteratorBase end;
|
||||
|
||||
public:
|
||||
using value_type = typename IteratorBase::value_type;
|
||||
using difference_type = ptrdiff_t;
|
||||
using pointer = value_type *;
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
|
||||
DeletableInstructionsIterator(IteratorBase base, IteratorBase end)
|
||||
: base(base), end(end) {}
|
||||
|
||||
value_type &operator*() const { return *base; }
|
||||
|
||||
SILInstruction *operator->() const { return base.operator->(); }
|
||||
|
||||
Self &operator++() {
|
||||
// If the current instruction is "deleted" (which means: removed from the
|
||||
// list), it's prev/next pointers still point to the next instruction which
|
||||
// is still in the list - or "deleted", too.
|
||||
++base;
|
||||
// Skip over all deleted instructions. Eventually we reach an instruction
|
||||
// is still in the list (= not "deleted") or the end iterator.
|
||||
while (base != end && base->isDeleted()) {
|
||||
++base;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator==(const Self &rhs) const { return base == rhs.base; }
|
||||
bool operator!=(const Self &rhs) const { return !(*this == rhs); }
|
||||
};
|
||||
|
||||
class SILBasicBlock :
|
||||
public llvm::ilist_node<SILBasicBlock>, public SILAllocated<SILBasicBlock>,
|
||||
public SwiftObjectHeader {
|
||||
@@ -85,7 +130,7 @@ private:
|
||||
/// DD and EEE are uninitialized
|
||||
///
|
||||
/// See also: SILBitfield::bitfieldID, SILFunction::currentBitfieldID.
|
||||
uint64_t lastInitializedBitfieldID = 0;
|
||||
int64_t lastInitializedBitfieldID = 0;
|
||||
|
||||
// Used by `BasicBlockBitfield`.
|
||||
unsigned getCustomBits() const { return customBits; }
|
||||
@@ -148,9 +193,10 @@ public:
|
||||
|
||||
void push_back(SILInstruction *I);
|
||||
void push_front(SILInstruction *I);
|
||||
void remove(SILInstruction *I);
|
||||
void erase(SILInstruction *I);
|
||||
void erase(SILInstruction *I, SILModule &module);
|
||||
static void moveInstruction(SILInstruction *inst, SILInstruction *beforeInst);
|
||||
void moveInstructionToFront(SILInstruction *inst);
|
||||
|
||||
void eraseAllInstructions(SILModule &module);
|
||||
|
||||
@@ -183,6 +229,20 @@ public:
|
||||
const_reverse_iterator rbegin() const { return InstList.rbegin(); }
|
||||
const_reverse_iterator rend() const { return InstList.rend(); }
|
||||
|
||||
/// Allows deleting instructions while iterating over all instructions of the
|
||||
/// block.
|
||||
///
|
||||
/// For details see `DeletableInstructionsIterator`.
|
||||
llvm::iterator_range<DeletableInstructionsIterator<iterator>>
|
||||
deletableInstructions() { return {{begin(), end()}, {end(), end()}}; }
|
||||
|
||||
/// Allows deleting instructions while iterating over all instructions of the
|
||||
/// block in reverse order.
|
||||
///
|
||||
/// For details see `DeletableInstructionsIterator`.
|
||||
llvm::iterator_range<DeletableInstructionsIterator<reverse_iterator>>
|
||||
reverseDeletableInstructions() { return {{rbegin(), rend()}, {rend(), rend()}}; }
|
||||
|
||||
TermInst *getTerminator() {
|
||||
assert(!InstList.empty() && "Can't get successors for malformed block");
|
||||
return cast<TermInst>(&InstList.back());
|
||||
|
||||
@@ -30,7 +30,7 @@ template <class Impl, class T> class SILBitfield {
|
||||
/// that the bits of that block are not initialized yet.
|
||||
/// See also: SILBasicBlock::lastInitializedBitfieldID,
|
||||
/// SILFunction::currentBitfieldID
|
||||
uint64_t bitfieldID;
|
||||
int64_t bitfieldID;
|
||||
|
||||
short startBit;
|
||||
short endBit;
|
||||
|
||||
@@ -340,6 +340,7 @@ BridgedArgumentConvention SILArgument_getConvention(BridgedArgument argument);
|
||||
OptionalBridgedInstruction SILInstruction_next(BridgedInstruction inst);
|
||||
OptionalBridgedInstruction SILInstruction_previous(BridgedInstruction inst);
|
||||
BridgedBasicBlock SILInstruction_getParent(BridgedInstruction inst);
|
||||
bool SILInstruction_isDeleted(BridgedInstruction inst);
|
||||
BridgedArrayRef SILInstruction_getOperands(BridgedInstruction inst);
|
||||
void SILInstruction_setOperand(BridgedInstruction inst, SwiftInt index,
|
||||
BridgedValue value);
|
||||
@@ -456,6 +457,7 @@ BridgedInstruction SILBuilder_createUncheckedEnumData(BridgedBuilder builder,
|
||||
BridgedInstruction SILBuilder_createBranch(
|
||||
BridgedBuilder builder, BridgedBasicBlock destBlock,
|
||||
BridgedValueArray arguments);
|
||||
BridgedInstruction SILBuilder_createUnreachable(BridgedBuilder builder);
|
||||
|
||||
SWIFT_END_NULLABILITY_ANNOTATIONS
|
||||
|
||||
|
||||
@@ -266,7 +266,7 @@ private:
|
||||
/// A monotonically increasing ID which is incremented whenever a
|
||||
/// BasicBlockBitfield or NodeBitfield is constructed.
|
||||
/// For details see SILBitfield::bitfieldID;
|
||||
uint64_t currentBitfieldID = 1;
|
||||
int64_t currentBitfieldID = 1;
|
||||
|
||||
/// Unique identifier for vector indexing and deterministic sorting.
|
||||
/// May be reused when zombie functions are recovered.
|
||||
|
||||
@@ -49,6 +49,58 @@
|
||||
#include "llvm/Support/TrailingObjects.h"
|
||||
#include <array>
|
||||
|
||||
namespace llvm {
|
||||
namespace ilist_detail {
|
||||
|
||||
/// The base class of the instruction list in SILBasicBlock.
|
||||
///
|
||||
/// We need a custom base class to not clear the prev/next pointers when
|
||||
/// removing an instruction from the list.
|
||||
class SILInstructionListBase : public ilist_base<false> {
|
||||
public:
|
||||
/// Remove an instruction from the list.
|
||||
///
|
||||
/// In contrast to the default implementation, it does not clear the prev/
|
||||
/// next pointers in the node. This is needed to being able to remove
|
||||
/// instructions from the list while iterating over the list.
|
||||
/// For details see `DeletableInstructionsIterator`.
|
||||
template <class T> static void remove(T &N) {
|
||||
node_base_type *Prev = N.getPrev();
|
||||
node_base_type *Next = N.getNext();
|
||||
Next->setPrev(Prev);
|
||||
Prev->setNext(Next);
|
||||
}
|
||||
|
||||
template <class T> static void insertBefore(T &Next, T &N) {
|
||||
insertBeforeImpl(Next, N);
|
||||
}
|
||||
|
||||
template <class T> static void transferBefore(T &Next, T &First, T &Last) {
|
||||
transferBeforeImpl(Next, First, Last);
|
||||
}
|
||||
};
|
||||
|
||||
// This template specialization is needed to replace the default instruction
|
||||
// list base class with `SILInstructionListBase`.
|
||||
template <> struct compute_node_options<::swift::SILInstruction> {
|
||||
struct type {
|
||||
typedef ::swift::SILInstruction value_type;
|
||||
typedef value_type *pointer;
|
||||
typedef value_type &reference;
|
||||
typedef const value_type *const_pointer;
|
||||
typedef const value_type &const_reference;
|
||||
|
||||
static const bool enable_sentinel_tracking = false;
|
||||
static const bool is_sentinel_tracking_explicit = false;
|
||||
typedef void tag;
|
||||
typedef ilist_node_base<enable_sentinel_tracking> node_base_type;
|
||||
typedef SILInstructionListBase list_base_type;
|
||||
};
|
||||
};
|
||||
|
||||
} // end namespace ilist_detail
|
||||
} // end llvm namespace
|
||||
|
||||
namespace swift {
|
||||
|
||||
class AllocationInst;
|
||||
@@ -376,9 +428,6 @@ protected:
|
||||
NumCreatedInstructions++;
|
||||
}
|
||||
|
||||
/// This method unlinks 'self' from the containing basic block.
|
||||
void removeFromParent();
|
||||
|
||||
~SILInstruction() {
|
||||
NumDeletedInstructions++;
|
||||
}
|
||||
@@ -394,7 +443,7 @@ public:
|
||||
|
||||
/// Returns true if this instruction is removed from its function and
|
||||
/// scheduled to be deleted.
|
||||
bool isDeleted() const { return !ParentBB; }
|
||||
bool isDeleted() const { return asSILNode()->isMarkedAsDeleted(); }
|
||||
|
||||
enum class MemoryBehavior {
|
||||
None,
|
||||
@@ -10175,7 +10224,6 @@ public:
|
||||
}
|
||||
|
||||
void addNodeToList(SILInstruction *I);
|
||||
void removeNodeFromList(SILInstruction *I);
|
||||
void transferNodesFromList(ilist_traits<SILInstruction> &L2,
|
||||
instr_iterator first, instr_iterator last);
|
||||
|
||||
|
||||
@@ -217,7 +217,7 @@ private:
|
||||
/// This avoids dangling instruction pointers within the run of a pass and in
|
||||
/// analysis caches. Note that the analysis invalidation mechanism ensures
|
||||
/// that analysis caches are invalidated before flushDeletedInsts().
|
||||
llvm::iplist<SILInstruction> scheduledForDeletion;
|
||||
std::vector<SILInstruction*> scheduledForDeletion;
|
||||
|
||||
/// The swift Module associated with this SILModule.
|
||||
ModuleDecl *TheSwiftModule;
|
||||
|
||||
@@ -330,8 +330,13 @@ protected:
|
||||
/// -> AAA, BB and C are initialized,
|
||||
/// DD and EEE are uninitialized
|
||||
///
|
||||
/// If the ID is negative, it means that the node (in case it's an instruction)
|
||||
/// is deleted, i.e. it does not belong to the function anymore. Conceptually
|
||||
/// this results in setting all bitfields to zero, which e.g. "removes" the
|
||||
/// node from all NodeSets.
|
||||
///
|
||||
/// See also: SILBitfield::bitfieldID, SILFunction::currentBitfieldID.
|
||||
uint64_t lastInitializedBitfieldID = 0;
|
||||
int64_t lastInitializedBitfieldID = 0;
|
||||
|
||||
private:
|
||||
SwiftMetatype getSILNodeMetatype(SILNodeKind kind);
|
||||
@@ -389,6 +394,12 @@ public:
|
||||
lastInitializedBitfieldID = 0;
|
||||
}
|
||||
|
||||
void markAsDeleted() {
|
||||
lastInitializedBitfieldID = -1;
|
||||
}
|
||||
|
||||
bool isMarkedAsDeleted() const { return lastInitializedBitfieldID < 0; }
|
||||
|
||||
static SILNode *instAsNode(SILInstruction *inst);
|
||||
static const SILNode *instAsNode(const SILInstruction *inst);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user