Skip to content

Commit 65cc95e

Browse files
Merge pull request #61325 from nate-chandler/more-node-datastructures
Add a few more node data structures.
2 parents 0dc768a + cc6d97a commit 65cc95e

File tree

1 file changed

+165
-3
lines changed

1 file changed

+165
-3
lines changed

include/swift/SIL/NodeDatastructures.h

Lines changed: 165 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,6 @@
1212
//
1313
// This file defines efficient data structures for working with Nodes.
1414
//
15-
// TODO: Add an InstructionWorklist similar to BasicBlockWorklist.
16-
//
1715
//===----------------------------------------------------------------------===//
1816

1917
#ifndef SWIFT_SIL_NODEDATASTRUCTURES_H
@@ -29,7 +27,7 @@ namespace swift {
2927
/// NodeSet>`.
3028
///
3129
/// Unfortunately it's not possible to use `llvm::SetVector` directly because
32-
/// the ValueSet and StackList constructors needs a `SILFunction` argument.
30+
/// the NodeSet and StackList constructors needs a `SILFunction` argument.
3331
///
3432
/// Note: This class does not provide a `remove` method intentionally, because
3533
/// it would have a O(n) complexity.
@@ -63,6 +61,112 @@ class NodeSetVector {
6361
}
6462
};
6563

64+
/// An implementation of `llvm::SetVector<SILInstruction *,
65+
/// StackList<SILInstruction *>,
66+
/// InstructionSet>`.
67+
///
68+
/// Unfortunately it's not possible to use `llvm::SetVector` directly because
69+
/// the InstructionSet and StackList constructors needs a `SILFunction`
70+
/// argument.
71+
///
72+
/// Note: This class does not provide a `remove` method intentionally, because
73+
/// it would have a O(n) complexity.
74+
class InstructionSetVector {
75+
StackList<SILInstruction *> vector;
76+
InstructionSet set;
77+
78+
public:
79+
using iterator = typename StackList<SILInstruction *>::iterator;
80+
81+
InstructionSetVector(SILFunction *function)
82+
: vector(function), set(function) {}
83+
84+
iterator begin() const { return vector.begin(); }
85+
iterator end() const { return vector.end(); }
86+
87+
llvm::iterator_range<iterator> getRange() const {
88+
return llvm::make_range(begin(), end());
89+
}
90+
91+
bool empty() const { return vector.empty(); }
92+
93+
bool contains(SILInstruction *instruction) const {
94+
return set.contains(instruction);
95+
}
96+
97+
/// Returns true if \p instruction was not contained in the set before
98+
/// inserting.
99+
bool insert(SILInstruction *instruction) {
100+
if (set.insert(instruction)) {
101+
vector.push_back(instruction);
102+
return true;
103+
}
104+
return false;
105+
}
106+
};
107+
108+
/// A utility for processing instructions in a worklist.
109+
///
110+
/// It is basically a combination of an instruction vector and an instruction
111+
/// set. It can be used for typical worklist-processing algorithms.
112+
class InstructionWorklist {
113+
StackList<SILInstruction *> worklist;
114+
InstructionSet visited;
115+
116+
public:
117+
/// Construct an empty worklist.
118+
InstructionWorklist(SILFunction *function)
119+
: worklist(function), visited(function) {}
120+
121+
/// Initialize the worklist with \p initialBlock.
122+
InstructionWorklist(SILInstruction *initialInstruction)
123+
: InstructionWorklist(initialInstruction->getFunction()) {
124+
push(initialInstruction);
125+
}
126+
127+
/// Pops the last added element from the worklist or returns null, if the
128+
/// worklist is empty.
129+
SILInstruction *pop() {
130+
if (worklist.empty())
131+
return nullptr;
132+
return worklist.pop_back_val();
133+
}
134+
135+
/// Pushes \p instruction onto the worklist if \p instruction has never been
136+
/// push before.
137+
bool pushIfNotVisited(SILInstruction *instruction) {
138+
if (visited.insert(instruction)) {
139+
worklist.push_back(instruction);
140+
return true;
141+
}
142+
return false;
143+
}
144+
145+
/// Like `pushIfNotVisited`, but requires that \p instruction has never been
146+
/// on the worklist before.
147+
void push(SILInstruction *instruction) {
148+
assert(!visited.contains(instruction));
149+
visited.insert(instruction);
150+
worklist.push_back(instruction);
151+
}
152+
153+
/// Like `pop`, but marks the returned instruction as "unvisited". This means,
154+
/// that the instruction can be pushed onto the worklist again.
155+
SILInstruction *popAndForget() {
156+
if (worklist.empty())
157+
return nullptr;
158+
SILInstruction *instruction = worklist.pop_back_val();
159+
visited.erase(instruction);
160+
return instruction;
161+
}
162+
163+
/// Returns true if \p instruction was visited, i.e. has been added to the
164+
/// worklist.
165+
bool isVisited(SILInstruction *instruction) const {
166+
return visited.contains(instruction);
167+
}
168+
};
169+
66170
/// An implementation of `llvm::SetVector<SILValue,
67171
/// StackList<SILValue>,
68172
/// ValueSet>`.
@@ -102,6 +206,64 @@ class ValueSetVector {
102206
}
103207
};
104208

209+
/// A utility for processing values in a worklist.
210+
///
211+
/// It is basically a combination of a value vector and a value set. It can be
212+
/// used for typical worklist-processing algorithms.
213+
class ValueWorklist {
214+
StackList<SILValue> worklist;
215+
ValueSet visited;
216+
217+
public:
218+
/// Construct an empty worklist.
219+
ValueWorklist(SILFunction *function)
220+
: worklist(function), visited(function) {}
221+
222+
/// Initialize the worklist with \p initialValue.
223+
ValueWorklist(SILValue initialValue)
224+
: ValueWorklist(initialValue->getFunction()) {
225+
push(initialValue);
226+
}
227+
228+
/// Pops the last added element from the worklist or returns null, if the
229+
/// worklist is empty.
230+
SILValue pop() {
231+
if (worklist.empty())
232+
return nullptr;
233+
return worklist.pop_back_val();
234+
}
235+
236+
/// Pushes \p value onto the worklist if \p value has never been push before.
237+
bool pushIfNotVisited(SILValue value) {
238+
if (visited.insert(value)) {
239+
worklist.push_back(value);
240+
return true;
241+
}
242+
return false;
243+
}
244+
245+
/// Like `pushIfNotVisited`, but requires that \p value has never been on the
246+
/// worklist before.
247+
void push(SILValue value) {
248+
assert(!visited.contains(value));
249+
visited.insert(value);
250+
worklist.push_back(value);
251+
}
252+
253+
/// Like `pop`, but marks the returned value as "unvisited". This means, that
254+
/// the value can be pushed onto the worklist again.
255+
SILValue popAndForget() {
256+
if (worklist.empty())
257+
return nullptr;
258+
SILValue value = worklist.pop_back_val();
259+
visited.erase(value);
260+
return value;
261+
}
262+
263+
/// Returns true if \p value was visited, i.e. has been added to the worklist.
264+
bool isVisited(SILValue value) const { return visited.contains(value); }
265+
};
266+
105267
} // namespace swift
106268

107269
#endif

0 commit comments

Comments
 (0)