@@ -145,12 +145,18 @@ namespace {
145
145
// / the worklist before we delete them.
146
146
struct SemanticARCOptVisitor
147
147
: SILInstructionVisitor<SemanticARCOptVisitor, bool > {
148
+ // / Our main worklist. We use this after an initial run through.
148
149
SmallBlotSetVector<SILValue, 32 > worklist;
150
+
151
+ // / A secondary work list that we use to store dead trivial instructions to
152
+ // / delete after we are done processing the worklist.
153
+ SmallBlotSetVector<SILInstruction *, 32 > deadTrivialInsts;
154
+
149
155
SILFunction &F;
150
156
Optional<DeadEndBlocks> TheDeadEndBlocks;
151
-
157
+
152
158
explicit SemanticARCOptVisitor (SILFunction &F) : F(F) {}
153
-
159
+
154
160
DeadEndBlocks &getDeadEndBlocks () {
155
161
if (!TheDeadEndBlocks)
156
162
TheDeadEndBlocks.emplace (&F);
@@ -167,7 +173,7 @@ struct SemanticARCOptVisitor
167
173
168
174
// / Add all operands of i to the worklist and then call eraseInstruction on
169
175
// / i. Assumes that the instruction doesnt have users.
170
- void eraseInstructionAndAddOptsToWorklist (SILInstruction *i) {
176
+ void eraseInstructionAndAddOperandsToWorklist (SILInstruction *i) {
171
177
// Then copy all operands into the worklist for future processing.
172
178
for (SILValue v : i->getOperandValues ()) {
173
179
worklist.insert (v);
@@ -184,6 +190,7 @@ struct SemanticARCOptVisitor
184
190
for (SILValue result : i->getResults ()) {
185
191
worklist.erase (result);
186
192
}
193
+ deadTrivialInsts.erase (i);
187
194
i->eraseFromParent ();
188
195
}
189
196
@@ -227,18 +234,7 @@ bool SemanticARCOptVisitor::processWorklist() {
227
234
// the instruction).
228
235
if (auto *defInst = next->getDefiningInstruction ()) {
229
236
if (isInstructionTriviallyDead (defInst)) {
230
- madeChange = true ;
231
- recursivelyDeleteTriviallyDeadInstructions (
232
- defInst, true /* force*/ ,
233
- [&](SILInstruction *i) {
234
- for (SILValue operand : i->getOperandValues ()) {
235
- worklist.insert (operand);
236
- }
237
- for (SILValue result : i->getResults ()) {
238
- worklist.erase (result);
239
- }
240
- ++NumEliminatedInsts;
241
- });
237
+ deadTrivialInsts.insert (defInst);
242
238
continue ;
243
239
}
244
240
}
@@ -251,6 +247,23 @@ bool SemanticARCOptVisitor::processWorklist() {
251
247
}
252
248
}
253
249
250
+ // Then eliminate the rest of the dead trivial insts.
251
+ //
252
+ // NOTE: We do not need to touch the worklist here since it is guaranteed to
253
+ // be empty due to the loop above. We enforce this programatically with the
254
+ // assert.
255
+ assert (worklist.empty () && " Expected drained worklist so we don't have to "
256
+ " remove dead insts form it" );
257
+ while (!deadTrivialInsts.empty ()) {
258
+ auto val = deadTrivialInsts.pop_back_val ();
259
+ if (!val)
260
+ continue ;
261
+ recursivelyDeleteTriviallyDeadInstructions (
262
+ *val, true /* force*/ ,
263
+ [&](SILInstruction *i) { deadTrivialInsts.erase (i); });
264
+ madeChange = true ;
265
+ }
266
+
254
267
return madeChange;
255
268
}
256
269
@@ -504,7 +517,7 @@ bool SemanticARCOptVisitor::eliminateDeadLiveRangeCopyValue(CopyValueInst *cvi)
504
517
if (auto *op = cvi->getSingleUse ()) {
505
518
if (auto *dvi = dyn_cast<DestroyValueInst>(op->getUser ())) {
506
519
eraseInstruction (dvi);
507
- eraseInstructionAndAddOptsToWorklist (cvi);
520
+ eraseInstructionAndAddOperandsToWorklist (cvi);
508
521
NumEliminatedInsts += 2 ;
509
522
return true ;
510
523
}
@@ -531,7 +544,7 @@ bool SemanticARCOptVisitor::eliminateDeadLiveRangeCopyValue(CopyValueInst *cvi)
531
544
eraseInstruction (destroys.pop_back_val ());
532
545
++NumEliminatedInsts;
533
546
}
534
- eraseInstructionAndAddOptsToWorklist (cvi);
547
+ eraseInstructionAndAddOperandsToWorklist (cvi);
535
548
++NumEliminatedInsts;
536
549
return true ;
537
550
}
0 commit comments