20
20
#include " swift/SILOptimizer/Analysis/DominanceAnalysis.h"
21
21
#include " swift/SILOptimizer/PassManager/Passes.h"
22
22
#include " swift/SILOptimizer/PassManager/Transforms.h"
23
+ #include " swift/SILOptimizer/Utils/BasicBlockOptUtils.h"
24
+ #include " swift/SILOptimizer/Utils/CFGOptUtils.h"
23
25
#include " swift/SILOptimizer/Utils/InstOptUtils.h"
24
26
#include " llvm/ADT/DenseMap.h"
25
27
#include " llvm/ADT/SmallPtrSet.h"
@@ -45,6 +47,17 @@ static bool seemsUseful(SILInstruction *I) {
45
47
if (isa<BeginAccessInst>(I))
46
48
return false ;
47
49
50
+ // Even though begin_borrow/destroy_value/copy_value have side-effects, they
51
+ // can be DCE'ed if they do not have useful dependencies/reverse dependencies
52
+ if (isa<BeginBorrowInst>(I))
53
+ return false ;
54
+
55
+ if (isa<DestroyValueInst>(I))
56
+ return false ;
57
+
58
+ if (isa<CopyValueInst>(I))
59
+ return false ;
60
+
48
61
if (I->mayHaveSideEffects ())
49
62
return true ;
50
63
@@ -94,15 +107,16 @@ class DCE : public SILFunctionTransform {
94
107
// Dependencies which go in the reverse direction. Usually for a pair
95
108
// %1 = inst_a
96
109
// inst_b(%1)
97
- // the dependency goes from inst_b to inst_a: if inst_b is alive then also
98
- // inst_a is alive.
110
+ // the dependency goes from inst_b to inst_a: if inst_b is alive then
111
+ // inst_a is also alive.
99
112
// For some instructions the dependency is exactly the other way round, e.g.
100
113
// %1 = inst_which_can_fail
101
114
// cond_fail(%1)
102
115
// In this case cond_fail is alive only if inst_which_can_fail is alive.
103
116
// The key of this map is the source of the dependency (inst_a), the
104
- // value is the destination (inst_b).
105
- llvm::DenseMap<SILInstruction *, SILInstruction *> ReverseDependencies;
117
+ // value is the set of instructions dependent on it (inst_b).
118
+ llvm::DenseMap<SILValue, SmallPtrSet<SILInstruction *, 4 >>
119
+ ReverseDependencies;
106
120
107
121
// / Tracks if the pass changed branches.
108
122
bool BranchesChanged;
@@ -115,11 +129,6 @@ class DCE : public SILFunctionTransform {
115
129
CallsChanged = false ;
116
130
117
131
SILFunction *F = getFunction ();
118
-
119
- // FIXME: Support ownership.
120
- if (F->hasOwnership ())
121
- return ;
122
-
123
132
auto *DA = PM->getAnalysis <PostDominanceAnalysis>();
124
133
PDT = DA->get (F);
125
134
@@ -150,8 +159,12 @@ class DCE : public SILFunctionTransform {
150
159
using InvalidationKind = SILAnalysis::InvalidationKind;
151
160
152
161
unsigned Inv = InvalidationKind::Instructions;
153
- if (CallsChanged) Inv |= (unsigned ) InvalidationKind::Calls;
154
- if (BranchesChanged) Inv |= (unsigned ) InvalidationKind::Branches;
162
+ if (CallsChanged)
163
+ Inv |= (unsigned )InvalidationKind::Calls;
164
+ if (BranchesChanged) {
165
+ removeUnreachableBlocks (*F);
166
+ Inv |= (unsigned )InvalidationKind::Branches;
167
+ }
155
168
156
169
invalidateAnalysis (SILAnalysis::InvalidationKind (Inv));
157
170
}
@@ -164,7 +177,9 @@ class DCE : public SILFunctionTransform {
164
177
165
178
bool precomputeControlInfo (SILFunction &F);
166
179
void markLive (SILFunction &F);
167
- void addReverseDependency (SILInstruction *From, SILInstruction *To);
180
+ // / Record a reverse dependency from \p from to \p to meaning \p to is live
181
+ // / if \p from is also live.
182
+ void addReverseDependency (SILValue from, SILInstruction *to);
168
183
bool removeDead (SILFunction &F);
169
184
170
185
void computeLevelNumbers (PostDomTreeNode *root);
@@ -186,7 +201,9 @@ class DCE : public SILFunctionTransform {
186
201
llvm::SmallPtrSetImpl<SILBasicBlock *> &);
187
202
SILBasicBlock *nearestUsefulPostDominator (SILBasicBlock *Block);
188
203
void replaceBranchWithJump (SILInstruction *Inst, SILBasicBlock *Block);
189
-
204
+ // / If \p value is live, insert a lifetime ending operation in ossa.
205
+ // / destroy_value for @owned value and end_borrow for a @guaranteed value.
206
+ void endLifetimeOfLiveValue (SILValue value, SILInstruction *insertPt);
190
207
};
191
208
192
209
// Keep track of the fact that V is live and add it to our worklist
@@ -220,7 +237,7 @@ void DCE::markValueLive(SILNode *V) {
220
237
// / Gets the producing instruction of a cond_fail condition. Currently these
221
238
// / are overflow builtins but may be extended to other instructions in the
222
239
// / future.
223
- static SILInstruction *getProducer (CondFailInst *CFI) {
240
+ static BuiltinInst *getProducer (CondFailInst *CFI) {
224
241
// Check for the pattern:
225
242
// %1 = builtin "some_operation_with_overflow"
226
243
// %2 = tuple_extract %1
@@ -236,42 +253,47 @@ static SILInstruction *getProducer(CondFailInst *CFI) {
236
253
237
254
// Determine which instructions from this function we need to keep.
238
255
void DCE::markLive (SILFunction &F) {
239
-
240
256
// Find the initial set of instructions in this function that appear
241
257
// to be live in the sense that they are not trivially something we
242
258
// can delete by examining only that instruction.
243
259
for (auto &BB : F) {
244
260
for (auto &I : BB) {
245
- if ( auto *CFI = dyn_cast<CondFailInst>(&I )) {
246
- // A cond_fail is only alive if its (identifiable) producer is alive.
247
- if (SILInstruction *Prod = getProducer (CFI )) {
248
- addReverseDependency (Prod, CFI );
261
+ switch (I. getKind ( )) {
262
+ case SILInstructionKind::CondFailInst: {
263
+ if (auto *Prod = getProducer (cast<CondFailInst>(&I) )) {
264
+ addReverseDependency (Prod, &I );
249
265
} else {
250
- markValueLive (CFI );
266
+ markValueLive (&I );
251
267
}
252
- continue ;
268
+ break ;
253
269
}
254
- if (auto *FLI = dyn_cast<FixLifetimeInst>(&I)) {
255
- // A fix_lifetime (with a non-address type) is only alive if it's
256
- // definition is alive.
257
- SILValue Op = FLI->getOperand ();
258
- auto *OpInst = Op->getDefiningInstruction ();
259
- if (OpInst && !Op->getType ().isAddress ()) {
260
- addReverseDependency (OpInst, FLI);
270
+ case SILInstructionKind::FixLifetimeInst: {
271
+ SILValue Op = I.getOperand (0 );
272
+ if (!Op->getType ().isAddress ()) {
273
+ addReverseDependency (Op, &I);
261
274
} else {
262
- markValueLive (FLI );
275
+ markValueLive (&I );
263
276
}
264
- continue ;
277
+ break ;
265
278
}
266
- if (auto *endAccess = dyn_cast<EndAccessInst>(&I)) {
267
- addReverseDependency (endAccess->getBeginAccess (), &I);
268
- continue ;
279
+ case SILInstructionKind::EndAccessInst: {
280
+ // An end_access is live only if it's begin_access is also live.
281
+ auto *beginAccess = cast<EndAccessInst>(&I)->getBeginAccess ();
282
+ addReverseDependency (beginAccess, &I);
283
+ break ;
284
+ }
285
+ case SILInstructionKind::DestroyValueInst:
286
+ case SILInstructionKind::EndBorrowInst: {
287
+ // The instruction is live only if it's operand value is also live
288
+ addReverseDependency (I.getOperand (0 ), &I);
289
+ break ;
290
+ }
291
+ default :
292
+ if (seemsUseful (&I))
293
+ markValueLive (&I);
269
294
}
270
- if (seemsUseful (&I))
271
- markValueLive (&I);
272
295
}
273
296
}
274
-
275
297
// Now propagate liveness backwards from each instruction in our
276
298
// worklist, adding new instructions to the worklist as we discover
277
299
// more that we need to keep.
@@ -281,17 +303,11 @@ void DCE::markLive(SILFunction &F) {
281
303
}
282
304
}
283
305
284
- // Records a reverse dependency. See DCE::ReverseDependencies.
285
- void DCE::addReverseDependency (SILInstruction *From, SILInstruction *To) {
286
- assert (!ReverseDependencies.lookup (To) &&
287
- " Target of reverse dependency already in map" );
288
- SILInstruction *&Target = ReverseDependencies[From];
289
- SILInstruction *ExistingTarget = Target;
290
- Target = To;
291
- if (ExistingTarget) {
292
- // Create a single linked chain if From has multiple targets.
293
- ReverseDependencies[To] = ExistingTarget;
294
- }
306
+ // Records a reverse dependency if needed. See DCE::ReverseDependencies.
307
+ void DCE::addReverseDependency (SILValue from, SILInstruction *to) {
308
+ LLVM_DEBUG (llvm::dbgs () << " Adding reverse dependency from " << from << " to "
309
+ << to);
310
+ ReverseDependencies[from].insert (to);
295
311
}
296
312
297
313
// Mark as live the terminator argument at index ArgIndex in Pred that
@@ -366,8 +382,10 @@ void DCE::propagateLiveBlockArgument(SILArgument *Arg) {
366
382
for (Operand *DU : getDebugUses (Arg))
367
383
markValueLive (DU->getUser ());
368
384
369
- if (isa<SILFunctionArgument>(Arg))
370
- return ;
385
+ // Mark all reverse dependencies on the Arg live
386
+ for (auto *depInst : ReverseDependencies.lookup (Arg)) {
387
+ markValueLive (depInst);
388
+ }
371
389
372
390
auto *Block = Arg->getParent ();
373
391
auto ArgIndex = Arg->getIndex ();
@@ -390,10 +408,13 @@ void DCE::propagateLiveness(SILInstruction *I) {
390
408
for (Operand *DU : getDebugUses (result))
391
409
markValueLive (DU->getUser ());
392
410
393
- // Handle all other reverse-dependency instructions, like cond_fail and
394
- // fix_lifetime. Only if the definition is alive, the user itself is alive.
395
- if (SILInstruction *DepInst = ReverseDependencies.lookup (I)) {
396
- markValueLive (DepInst);
411
+ // Handle all other reverse-dependency instructions, like cond_fail,
412
+ // fix_lifetime, destroy_value, etc. Only if the definition is alive, the
413
+ // user itself is alive.
414
+ for (auto res : I->getResults ()) {
415
+ for (auto *depInst : ReverseDependencies.lookup (res)) {
416
+ markValueLive (depInst);
417
+ }
397
418
}
398
419
return ;
399
420
}
@@ -471,22 +492,75 @@ void DCE::replaceBranchWithJump(SILInstruction *Inst, SILBasicBlock *Block) {
471
492
(void )Branch;
472
493
}
473
494
495
+ void DCE::endLifetimeOfLiveValue (SILValue value, SILInstruction *insertPt) {
496
+ if (!LiveValues.count (value->getRepresentativeSILNodeInObject ())) {
497
+ return ;
498
+ }
499
+ SILBuilderWithScope builder (insertPt);
500
+ if (value.getOwnershipKind () == OwnershipKind::Owned) {
501
+ builder.emitDestroyOperation (RegularLocation::getAutoGeneratedLocation (),
502
+ value);
503
+ }
504
+ if (value.getOwnershipKind () == OwnershipKind::Guaranteed) {
505
+ builder.emitEndBorrowOperation (RegularLocation::getAutoGeneratedLocation (),
506
+ value);
507
+ }
508
+ }
509
+
474
510
// Remove the instructions that are not potentially useful.
475
511
bool DCE::removeDead (SILFunction &F) {
476
512
bool Changed = false ;
477
513
478
514
for (auto &BB : F) {
479
- for (auto I = BB.args_begin (), E = BB.args_end (); I != E;) {
480
- auto Inst = *I++;
481
- if (LiveValues.count (Inst))
515
+ for (unsigned i = 0 ; i < BB.getArguments ().size ();) {
516
+ auto *arg = BB.getArgument (i);
517
+ if (LiveValues.count (arg)) {
518
+ i++;
482
519
continue ;
520
+ }
483
521
484
522
LLVM_DEBUG (llvm::dbgs () << " Removing dead argument:\n " );
485
- LLVM_DEBUG (Inst->dump ());
523
+ LLVM_DEBUG (arg->dump ());
524
+
525
+ arg->replaceAllUsesWithUndef ();
486
526
487
- Inst->replaceAllUsesWithUndef ();
527
+ if (!F.hasOwnership () || arg->getType ().isTrivial (F)) {
528
+ i++;
529
+ Changed = true ;
530
+ BranchesChanged = true ;
531
+ continue ;
532
+ }
488
533
534
+ if (!arg->isPhiArgument ()) {
535
+ // We cannot delete a non phi arg. If it was @owned, insert a
536
+ // destroy_value, because its consuming user has already been marked
537
+ // dead and will be deleted.
538
+ // We do not have to end lifetime of a @guaranteed non phi arg.
539
+ if (arg->getOwnershipKind () == OwnershipKind::Owned) {
540
+ auto insertPt = getInsertAfterPoint (arg).getValue ();
541
+ SILBuilderWithScope builder (insertPt);
542
+ auto *destroy = builder.createDestroyValue (insertPt->getLoc (), arg);
543
+ LiveValues.insert (destroy->getRepresentativeSILNodeInObject ());
544
+ }
545
+ i++;
546
+ Changed = true ;
547
+ BranchesChanged = true ;
548
+ continue ;
549
+ }
550
+ // In OSSA, we have to delete a dead phi argument and insert destroy or
551
+ // end_borrow at its predecessors if the incoming values are live.
552
+ // This is not necessary in non-OSSA, and will infact be incorrect.
553
+ // Because, passing a value as a phi argument does not imply end of
554
+ // lifetime in non-OSSA.
555
+ BB.eraseArgument (i);
556
+ for (auto *pred : BB.getPredecessorBlocks ()) {
557
+ auto *predTerm = pred->getTerminator ();
558
+ auto predArg = predTerm->getAllOperands ()[i].get ();
559
+ endLifetimeOfLiveValue (predArg, predTerm);
560
+ deleteEdgeValue (pred->getTerminator (), &BB, i);
561
+ }
489
562
Changed = true ;
563
+ BranchesChanged = true ;
490
564
}
491
565
492
566
for (auto I = BB.begin (), E = BB.end (); I != E; ) {
@@ -501,7 +575,11 @@ bool DCE::removeDead(SILFunction &F) {
501
575
SILBasicBlock *postDom = nearestUsefulPostDominator (Inst->getParent ());
502
576
if (!postDom)
503
577
continue ;
504
-
578
+
579
+ LLVM_DEBUG (llvm::dbgs () << " Replacing branch: " );
580
+ LLVM_DEBUG (Inst->dump ());
581
+ LLVM_DEBUG (llvm::dbgs () << " with jump to: BB" << postDom->getDebugID ());
582
+
505
583
replaceBranchWithJump (Inst, postDom);
506
584
Inst->eraseFromParent ();
507
585
BranchesChanged = true ;
@@ -514,6 +592,13 @@ bool DCE::removeDead(SILFunction &F) {
514
592
LLVM_DEBUG (llvm::dbgs () << " Removing dead instruction:\n " );
515
593
LLVM_DEBUG (Inst->dump ());
516
594
595
+ if (F.hasOwnership ()) {
596
+ for (auto &Op : Inst->getAllOperands ()) {
597
+ if (Op.isLifetimeEnding ()) {
598
+ endLifetimeOfLiveValue (Op.get (), Inst);
599
+ }
600
+ }
601
+ }
517
602
Inst->replaceAllUsesOfAllResultsWithUndef ();
518
603
519
604
if (isa<ApplyInst>(Inst))
0 commit comments