17
17
#define DEBUG_TYPE " cow-opts"
18
18
#include " swift/SILOptimizer/PassManager/Transforms.h"
19
19
#include " swift/SILOptimizer/Analysis/AliasAnalysis.h"
20
+ #include " swift/SIL/NodeBits.h"
20
21
#include " swift/SIL/SILFunction.h"
21
22
#include " swift/SIL/SILBasicBlock.h"
22
23
#include " swift/SIL/SILArgument.h"
23
24
#include " swift/SIL/SILBuilder.h"
25
+ #include " swift/SIL/StackList.h"
24
26
#include " llvm/Support/Debug.h"
25
27
26
28
using namespace swift ;
@@ -65,16 +67,13 @@ class COWOptsPass : public SILFunctionTransform {
65
67
void run () override ;
66
68
67
69
private:
68
- using InstructionSet = SmallPtrSet<SILInstruction *, 8 >;
69
- using VoidPointerSet = SmallPtrSet<void *, 8 >;
70
-
71
70
AliasAnalysis *AA = nullptr ;
72
71
73
72
bool optimizeBeginCOW (BeginCOWMutationInst *BCM);
74
73
75
74
static void collectEscapePoints (SILValue v,
76
- InstructionSet &escapePoints,
77
- VoidPointerSet &handled);
75
+ InstructionSetWithSize &escapePoints,
76
+ ValueSet &handled);
78
77
};
79
78
80
79
void COWOptsPass::run () {
@@ -120,37 +119,44 @@ static SILValue skipStructAndExtract(SILValue value) {
120
119
}
121
120
122
121
bool COWOptsPass::optimizeBeginCOW (BeginCOWMutationInst *BCM) {
123
- VoidPointerSet handled ;
124
- SmallVector<SILValue, 8 > workList ;
125
- SmallPtrSet<EndCOWMutationInst *, 4 > endCOWMutationInsts ;
122
+ SILFunction *function = BCM-> getFunction () ;
123
+ StackList<EndCOWMutationInst *> endCOWMutationInsts (function) ;
124
+ InstructionSet endCOWMutationsFound (function) ;
126
125
127
- // Collect all end_cow_mutation instructions, used by the begin_cow_mutation,
128
- // looking through block phi-arguments.
129
- workList.push_back (BCM->getOperand ());
130
- while (!workList.empty ()) {
131
- SILValue v = skipStructAndExtract (workList.pop_back_val ());
132
- if (SILPhiArgument *arg = dyn_cast<SILPhiArgument>(v)) {
133
- if (handled.insert (arg).second ) {
134
- SmallVector<SILValue, 4 > incomingVals;
135
- if (!arg->getIncomingPhiValues (incomingVals))
136
- return false ;
137
- for (SILValue incomingVal : incomingVals) {
138
- workList.push_back (incomingVal);
126
+ {
127
+ // Collect all end_cow_mutation instructions, used by the begin_cow_mutation,
128
+ // looking through block phi-arguments.
129
+ StackList<SILValue> workList (function);
130
+ ValueSet handled (function);
131
+ workList.push_back (BCM->getOperand ());
132
+ while (!workList.empty ()) {
133
+ SILValue v = skipStructAndExtract (workList.pop_back_val ());
134
+ if (SILPhiArgument *arg = dyn_cast<SILPhiArgument>(v)) {
135
+ if (handled.insert (arg)) {
136
+ SmallVector<SILValue, 4 > incomingVals;
137
+ if (!arg->getIncomingPhiValues (incomingVals))
138
+ return false ;
139
+ for (SILValue incomingVal : incomingVals) {
140
+ workList.push_back (incomingVal);
141
+ }
139
142
}
143
+ } else if (auto *ECM = dyn_cast<EndCOWMutationInst>(v)) {
144
+ if (endCOWMutationsFound.insert (ECM))
145
+ endCOWMutationInsts.push_back (ECM);
146
+ } else {
147
+ return false ;
140
148
}
141
- } else if (auto *ECM = dyn_cast<EndCOWMutationInst>(v)) {
142
- endCOWMutationInsts.insert (ECM);
143
- } else {
144
- return false ;
145
149
}
146
150
}
147
151
148
152
// Collect all uses of the end_cow_instructions, where the buffer can
149
153
// potentially escape.
150
- handled.clear ();
151
- InstructionSet potentialEscapePoints;
152
- for (EndCOWMutationInst *ECM : endCOWMutationInsts) {
153
- collectEscapePoints (ECM, potentialEscapePoints, handled);
154
+ InstructionSetWithSize potentialEscapePoints (function);
155
+ {
156
+ ValueSet handled (function);
157
+ for (EndCOWMutationInst *ECM : endCOWMutationInsts) {
158
+ collectEscapePoints (ECM, potentialEscapePoints, handled);
159
+ }
154
160
}
155
161
156
162
if (!potentialEscapePoints.empty ()) {
@@ -161,10 +167,13 @@ bool COWOptsPass::optimizeBeginCOW(BeginCOWMutationInst *BCM) {
161
167
// For store instructions we do a little bit more: only count a store as an
162
168
// escape if there is a (potential) load from the same address within the
163
169
// liverange.
164
- handled.clear ();
165
- SmallVector<SILInstruction *, 8 > instWorkList;
166
- SmallVector<SILInstruction *, 8 > potentialLoadInsts;
167
- llvm::DenseSet<SILValue> storeAddrs;
170
+ StackList<SILInstruction *> instWorkList (function);
171
+ StackList<SILInstruction *> potentialLoadInsts (function);
172
+ StackList<SILValue> storeAddrs (function);
173
+ ValueSet storeAddrsFound (function);
174
+ BasicBlockSet handled (function);
175
+ int numStoresFound = 0 ;
176
+ int numLoadsFound = 0 ;
168
177
169
178
// This is a simple worklist-based backward dataflow analysis.
170
179
// Start at the initial begin_cow_mutation and go backward.
@@ -173,27 +182,32 @@ bool COWOptsPass::optimizeBeginCOW(BeginCOWMutationInst *BCM) {
173
182
while (!instWorkList.empty ()) {
174
183
SILInstruction *inst = instWorkList.pop_back_val ();
175
184
for (;;) {
176
- if (potentialEscapePoints.count (inst) != 0 ) {
185
+ if (potentialEscapePoints.contains (inst)) {
177
186
if (auto *store = dyn_cast<StoreInst>(inst)) {
178
187
// Don't immediately bail on a store instruction. Instead, remember
179
188
// it and check if it interfers with any (potential) load.
180
- storeAddrs.insert (store->getDest ());
189
+ if (storeAddrsFound.insert (store->getDest ())) {
190
+ storeAddrs.push_back (store->getDest ());
191
+ numStoresFound += 1 ;
192
+ }
181
193
} else {
182
194
return false ;
183
195
}
184
196
}
185
- if (inst->mayReadFromMemory ())
197
+ if (inst->mayReadFromMemory ()) {
186
198
potentialLoadInsts.push_back (inst);
199
+ numLoadsFound += 1 ;
200
+ }
187
201
188
202
// An end_cow_mutation marks the begin of the liverange. It's the end
189
203
// point of the dataflow analysis.
190
204
auto *ECM = dyn_cast<EndCOWMutationInst>(inst);
191
- if (ECM && endCOWMutationInsts. count (ECM) != 0 )
205
+ if (ECM && endCOWMutationsFound. contains (ECM))
192
206
break ;
193
207
194
208
if (inst == &inst->getParent ()->front ()) {
195
209
for (SILBasicBlock *pred : inst->getParent ()->getPredecessorBlocks ()) {
196
- if (handled.insert (pred). second )
210
+ if (handled.insert (pred))
197
211
instWorkList.push_back (pred->getTerminator ());
198
212
}
199
213
break ;
@@ -205,9 +219,9 @@ bool COWOptsPass::optimizeBeginCOW(BeginCOWMutationInst *BCM) {
205
219
206
220
// Check if there is any (potential) load from a memory location where the
207
221
// buffer is stored to.
208
- if (!storeAddrs. empty () ) {
222
+ if (numStoresFound != 0 ) {
209
223
// Avoid quadratic behavior. Usually this limit is not exceeded.
210
- if (storeAddrs. size () * potentialLoadInsts. size () > 128 )
224
+ if (numStoresFound * numLoadsFound > 128 )
211
225
return false ;
212
226
for (SILInstruction *load : potentialLoadInsts) {
213
227
for (SILValue storeAddr : storeAddrs) {
@@ -235,9 +249,9 @@ bool COWOptsPass::optimizeBeginCOW(BeginCOWMutationInst *BCM) {
235
249
}
236
250
237
251
void COWOptsPass::collectEscapePoints (SILValue v,
238
- InstructionSet &escapePoints,
239
- VoidPointerSet &handled) {
240
- if (!handled.insert (v. getOpaqueValue ()). second )
252
+ InstructionSetWithSize &escapePoints,
253
+ ValueSet &handled) {
254
+ if (!handled.insert (v) )
241
255
return ;
242
256
243
257
for (Operand *use : v->getUses ()) {
0 commit comments