Skip to content

Commit 902da31

Browse files
authored
Merge pull request #27028 from nate-chandler/update-instruction-worklist
2 parents 681a203 + d2270b9 commit 902da31

File tree

6 files changed

+171
-126
lines changed

6 files changed

+171
-126
lines changed

include/swift/Basic/BlotSetVector.h

Lines changed: 78 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -47,111 +47,132 @@ namespace swift {
4747
template <typename ValueT, typename VectorT = std::vector<Optional<ValueT>>,
4848
typename MapT = llvm::DenseMap<ValueT, unsigned>>
4949
class BlotSetVector {
50-
VectorT Vector;
51-
MapT Map;
50+
VectorT vector;
51+
MapT map;
5252

5353
public:
5454
/// Construct an empty BlotSetVector.
5555
BlotSetVector() {}
5656

57-
bool empty() const { return Vector.empty(); }
57+
bool empty() const { return vector.empty(); }
5858

59-
unsigned size() const { return Vector.size(); }
59+
unsigned size() const { return vector.size(); }
6060

6161
using iterator = typename VectorT::iterator;
6262
using const_iterator = typename VectorT::const_iterator;
63-
iterator begin() { return Vector.begin(); }
64-
iterator end() { return Vector.end(); }
65-
const_iterator begin() const { return Vector.begin(); }
66-
const_iterator end() const { return Vector.end(); }
63+
iterator begin() { return vector.begin(); }
64+
iterator end() { return vector.end(); }
65+
const_iterator begin() const { return vector.begin(); }
66+
const_iterator end() const { return vector.end(); }
6767
llvm::iterator_range<const_iterator> getRange() const {
6868
return {begin(), end()};
6969
}
7070

7171
using const_reverse_iterator = typename VectorT::const_reverse_iterator;
72-
const_reverse_iterator rbegin() const { return Vector.rbegin(); }
73-
const_reverse_iterator rend() const { return Vector.rend(); }
72+
const_reverse_iterator rbegin() const { return vector.rbegin(); }
73+
const_reverse_iterator rend() const { return vector.rend(); }
7474
llvm::iterator_range<const_reverse_iterator> getReverseRange() const {
7575
return {rbegin(), rend()};
7676
}
7777

7878
const Optional<ValueT> &operator[](unsigned n) const {
79-
assert(n < Vector.size() && "Out of range!");
80-
return Vector[n];
79+
assert(n < vector.size() && "Out of range!");
80+
return vector[n];
8181
}
8282

83-
/// Insert \p V into the SetVector if it is not in the array and return the
84-
/// index of \p V in the Set Vector. If \p V is already in the SetVector, just
85-
/// return its index in the array.
86-
unsigned insert(const ValueT &V) {
87-
auto Iter = Map.find(V);
88-
if (Iter != Map.end())
89-
return Iter->second;
90-
91-
unsigned Index = Vector.size();
92-
Map[V] = Index;
93-
Vector.push_back(V);
94-
return Index;
83+
/// Grow the set vector so that it can contain at least \p capacity items
84+
/// before resizing again.
85+
///
86+
/// \param capacity The minimum size that the set vector will be able to grow
87+
/// to before a resize is required to insert additional items.
88+
void reserve(unsigned capacity) {
89+
vector.reserve(capacity);
90+
map.reserve(capacity);
9591
}
9692

97-
/// Replace \p V1 with \p V2 placing \p V2 into the position in the array
98-
/// where V1 used to be. If \p V2 is already in the set, this just erases \p
99-
/// V1.
100-
void replace(const ValueT &V1, const ValueT &V2) {
101-
auto Iter1 = Map.find(V1);
102-
assert(Iter1 != Map.end() && "Cannot replace value that is not in set");
103-
unsigned V1Index = Iter1->second;
104-
Map.erase(V1);
105-
106-
auto Iter2 = Map.find(V2);
107-
if (Iter2 != Map.end()) {
108-
Vector[V1Index] = None;
93+
/// Insert \p value into the SetVector if it is not there already.
94+
///
95+
/// \param value The item to insert if not already present.
96+
///
97+
/// \returns Both the index of the item and whether it was inserted in a pair.
98+
/// If the item was already present, its preexisting index along with
99+
/// false will be returned. If the item was newly added, its new
100+
/// index along with true will be returned.
101+
std::pair<unsigned, bool> insert(const ValueT &value) {
102+
auto iterator = map.find(value);
103+
if (iterator != map.end())
104+
return {iterator->second, false};
105+
106+
unsigned index = vector.size();
107+
map[value] = index;
108+
vector.push_back(value);
109+
return {index, true};
110+
}
111+
112+
/// Replace \p value1 with \p value2 placing \p value2 into the position in
113+
/// the array where value1 used to be. If \p value2 is already in the set,
114+
/// this just erases \p value1.
115+
void replace(const ValueT &value1, const ValueT &value2) {
116+
auto iterator1 = map.find(value1);
117+
assert(iterator1 != map.end() && "Cannot replace value that is not in set");
118+
unsigned index1 = iterator1->second;
119+
map.erase(value1);
120+
121+
auto iterator2 = map.find(value2);
122+
if (iterator2 != map.end()) {
123+
vector[index1] = None;
109124
return;
110125
}
111126

112-
Map[V2] = V1Index;
113-
Vector[V1Index] = V2;
127+
map[value2] = index1;
128+
vector[index1] = value2;
114129
}
115130

116-
/// Erase the value \p V if it is in the set. Returns true if V was
131+
/// Erase the value \p value if it is in the set. Returns true if value was
117132
/// successfully erased and false otherwise.
118-
bool erase(const ValueT &V) {
119-
auto Iter = Map.find(V);
120-
if (Iter == Map.end())
133+
bool erase(const ValueT &value) {
134+
auto iterator = map.find(value);
135+
if (iterator == map.end())
121136
return false;
122-
unsigned Index = Iter->second;
123-
Map.erase(Iter);
124-
Vector[Index] = None;
137+
unsigned index = iterator->second;
138+
map.erase(iterator);
139+
vector[index] = None;
125140
return true;
126141
}
127142

128143
/// Return the last element of the blot map vector. Will be None if blotted.
129144
Optional<ValueT> pop_back_val() {
130-
auto result = Vector.pop_back_val();
145+
auto result = vector.pop_back_val();
131146
if (!result)
132147
return result;
133-
Map.erase(*result);
148+
map.erase(*result);
134149
return result;
135150
}
136151

137-
/// Attempt to lookup the index of \p V. Returns None upon failure and the
152+
/// Attempt to lookup the index of \p value. Returns None upon failure and the
138153
/// value on success.
139-
Optional<unsigned> getIndex(const ValueT &V) {
140-
auto Iter = Map.find(V);
141-
if (Iter == Map.end())
154+
Optional<unsigned> getIndex(const ValueT &value) {
155+
auto iterator = map.find(value);
156+
if (iterator == map.end())
142157
return None;
143-
return Iter->second;
158+
return iterator->second;
159+
}
160+
161+
/// Clear the backing vector and map.
162+
void clear() {
163+
vector.clear();
164+
map.clear();
144165
}
145166
};
146167

147-
template <typename ValueT, unsigned N,
148-
typename VectorT = llvm::SmallVector<Optional<ValueT>, N>,
149-
typename MapT = llvm::SmallDenseMap<ValueT, unsigned, N>>
150-
class SmallBlotSetVector : public BlotSetVector<ValueT, VectorT, MapT> {
168+
template <typename ValueT, unsigned N>
169+
class SmallBlotSetVector
170+
: public BlotSetVector<ValueT, llvm::SmallVector<Optional<ValueT>, N>,
171+
llvm::SmallDenseMap<ValueT, unsigned, N>> {
151172
public:
152173
SmallBlotSetVector() {}
153174
};
154175

155-
} // end swift namespace
176+
} // namespace swift
156177

157178
#endif // SWIFT_BASIC_BLOTSETVECTOR_H

include/swift/SIL/SILInstructionWorklist.h

Lines changed: 73 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -24,92 +24,128 @@
2424
///
2525
//===----------------------------------------------------------------------===//
2626

27+
#include "swift/Basic/BlotSetVector.h"
2728
#include "swift/SIL/SILInstruction.h"
2829
#include "swift/SIL/SILValue.h"
2930
#include "llvm/ADT/DenseMap.h"
3031
#include "llvm/ADT/SmallVector.h"
3132

3233
namespace swift {
3334

35+
class SILInstructionWorklistBase {
36+
const char *loggingName;
37+
38+
protected:
39+
SILInstructionWorklistBase(const char *loggingName)
40+
: loggingName(loggingName){};
41+
void withDebugStream(
42+
std::function<void(llvm::raw_ostream &stream, const char *loggingName)>
43+
perform);
44+
};
45+
3446
/// Manages a list of instructions awaiting visitation.
35-
class SILInstructionWorklist final {
36-
llvm::SmallVector<SILInstruction *, 256> worklist;
37-
llvm::DenseMap<SILInstruction *, unsigned> worklistMap;
38-
StringRef loggingName;
47+
template <typename VectorT = std::vector<SILInstruction *>,
48+
typename MapT = llvm::DenseMap<SILInstruction *, unsigned>>
49+
class SILInstructionWorklist : SILInstructionWorklistBase {
50+
BlotSetVector<SILInstruction *, VectorT, MapT> worklist;
3951

4052
void operator=(const SILInstructionWorklist &rhs) = delete;
4153
SILInstructionWorklist(const SILInstructionWorklist &worklist) = delete;
4254

4355
public:
4456
SILInstructionWorklist(const char *loggingName = "InstructionWorklist")
45-
: loggingName(loggingName) {}
57+
: SILInstructionWorklistBase(loggingName) {}
4658

4759
/// Returns true if the worklist is empty.
4860
bool isEmpty() const { return worklist.empty(); }
4961

5062
/// Add the specified instruction to the worklist if it isn't already in it.
51-
void add(SILInstruction *instruction);
63+
void add(SILInstruction *instruction) {
64+
if (worklist.insert(instruction).second) {
65+
withDebugStream([&](llvm::raw_ostream &stream, StringRef loggingName) {
66+
stream << loggingName << ": ADD: " << *instruction << '\n';
67+
});
68+
}
69+
}
5270

53-
/// If the given ValueBase is a SILInstruction add it to the worklist.
54-
void addValue(ValueBase *value) {
55-
if (auto *instruction = value->getDefiningInstruction())
71+
/// If the given SILValue is a SILInstruction add it to the worklist.
72+
void addValue(SILValue value) {
73+
if (auto *instruction = value->getDefiningInstruction()) {
5674
add(instruction);
75+
}
5776
}
5877

5978
/// Add the given list of instructions in reverse order to the worklist. This
6079
/// routine assumes that the worklist is empty and the given list has no
6180
/// duplicates.
62-
void addInitialGroup(ArrayRef<SILInstruction *> list);
81+
void addInitialGroup(ArrayRef<SILInstruction *> list) {
82+
assert(worklist.empty() && "worklist must be empty to add initial group");
83+
worklist.reserve(list.size() + 16);
84+
withDebugStream([&](llvm::raw_ostream &stream, StringRef loggingName) {
85+
stream << loggingName << ": ADDING: " << list.size()
86+
<< " instrs to worklist\n";
87+
});
88+
while (!list.empty()) {
89+
SILInstruction *instruction = list.back();
90+
list = list.drop_back();
91+
worklist.insert(instruction);
92+
}
93+
}
6394

6495
// If instruction is in the worklist, remove it.
65-
void remove(SILInstruction *instruction) {
66-
auto iterator = worklistMap.find(instruction);
67-
if (iterator == worklistMap.end())
68-
return; // Not in worklist.
69-
70-
// Don't bother moving everything down, just null out the slot. We will
71-
// check before we process any instruction if it is null.
72-
worklist[iterator->second] = nullptr;
73-
worklistMap.erase(iterator);
74-
}
96+
void erase(SILInstruction *instruction) { worklist.erase(instruction); }
7597

7698
/// Remove the top element from the worklist.
77-
SILInstruction *removeOne() {
78-
SILInstruction *instruction = worklist.pop_back_val();
79-
worklistMap.erase(instruction);
80-
return instruction;
99+
SILInstruction *pop_back_val() {
100+
return worklist.pop_back_val().getValueOr(nullptr);
81101
}
82102

83103
/// When an instruction has been simplified, add all of its users to the
84104
/// worklist, since additional simplifications of its users may have been
85105
/// exposed.
86-
void addUsersToWorklist(ValueBase *instruction) {
87-
for (auto *use : instruction->getUses())
88-
add(use->getUser());
89-
}
90-
91106
void addUsersToWorklist(SILValue value) {
92-
for (auto *use : value->getUses())
107+
for (auto *use : value->getUses()) {
93108
add(use->getUser());
109+
}
94110
}
95111

96112
/// When an instruction has been simplified, add all of its users to the
97113
/// worklist, since additional simplifications of its users may have been
98114
/// exposed.
99115
void addUsersOfAllResultsToWorklist(SILInstruction *instruction) {
100116
for (auto result : instruction->getResults()) {
101-
addUsersToWorklist(result);
117+
addUsersToWorklist(&*result);
102118
}
103119
}
104120

105-
/// Check that the worklist is empty and nuke the backing store for the map if
106-
/// it is large.
107-
void zap() {
108-
assert(worklistMap.empty() && "Worklist empty, but the map is not?");
121+
/// Check that the worklist is empty and nuke the backing store if it is
122+
/// large.
123+
void resetChecked() {
124+
assert(worklist.empty() && "Vector empty, but the map is not?");
109125

110-
// Do an explicit clear, this shrinks the map if needed.
111-
worklistMap.clear();
126+
// Do an explicit clear, shrinking the storage if needed.
127+
worklist.clear();
112128
}
113129
};
114130

131+
// TODO: This name is somewhat unpleasant. Once the type is templated over its
132+
// storage and renamed BlottableWorklist, this type will be
133+
// SmallBlottableWorklist which is more reasonable.
134+
template <unsigned N>
135+
class SmallSILInstructionWorklist final
136+
: public SILInstructionWorklist<
137+
llvm::SmallVector<Optional<SILInstruction *>, N>,
138+
// TODO: A DenseMap rather than a SmallDenseMap is used here to avoid
139+
// running into an upstream problem with the handling of grow()
140+
// when it results in rehashing and tombstone removal:
141+
//
142+
// https://reviews.llvm.org/D56455
143+
llvm::DenseMap<SILInstruction *, unsigned>> {
144+
public:
145+
using VectorT = llvm::SmallVector<Optional<SILInstruction *>, N>;
146+
using MapT = llvm::DenseMap<SILInstruction *, unsigned>;
147+
SmallSILInstructionWorklist(const char *loggingName = "InstructionWorklist")
148+
: SILInstructionWorklist<VectorT, MapT>(loggingName) {}
149+
};
150+
115151
} // end namespace swift

include/swift/SILOptimizer/Analysis/LoopRegionAnalysis.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -762,7 +762,7 @@ class LoopRegion {
762762

763763
unsigned addSucc(LoopRegion *Successor) {
764764
assert(!isFunction() && "Functions cannot have successors");
765-
return Succs.insert(SuccessorID(Successor->getID(), false));
765+
return Succs.insert(SuccessorID(Successor->getID(), false)).first;
766766
}
767767

768768
void replacePred(unsigned OldPredID, unsigned NewPredID) {

lib/SIL/SILInstructionWorklist.cpp

Lines changed: 6 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -15,24 +15,10 @@
1515

1616
using namespace swift;
1717

18-
void SILInstructionWorklist::add(SILInstruction *instruction) {
19-
if (!worklistMap.insert(std::make_pair(instruction, worklist.size())).second)
20-
return;
21-
22-
LLVM_DEBUG(llvm::dbgs() << loggingName << ": ADD: " << *instruction << '\n');
23-
worklist.push_back(instruction);
24-
}
25-
26-
void SILInstructionWorklist::addInitialGroup(ArrayRef<SILInstruction *> list) {
27-
assert(worklist.empty() && "worklist must be empty to add initial group");
28-
worklist.reserve(list.size() + 16);
29-
worklistMap.reserve(list.size());
30-
LLVM_DEBUG(llvm::dbgs() << loggingName << ": ADDING: " << list.size()
31-
<< " instrs to worklist\n");
32-
while (!list.empty()) {
33-
SILInstruction *instruction = list.back();
34-
list = list.slice(0, list.size() - 1);
35-
worklistMap.insert(std::make_pair(instruction, worklist.size()));
36-
worklist.push_back(instruction);
37-
}
18+
void SILInstructionWorklistBase::withDebugStream(
19+
std::function<void(llvm::raw_ostream &stream, const char *loggingName)>
20+
perform) {
21+
#ifndef NDEBUG
22+
LLVM_DEBUG(perform(llvm::dbgs(), loggingName));
23+
#endif
3824
}

0 commit comments

Comments
 (0)