2020#include " swift/SILOptimizer/Analysis/DominanceAnalysis.h"
2121#include " swift/SILOptimizer/PassManager/Passes.h"
2222#include " swift/SILOptimizer/PassManager/Transforms.h"
23+ #include " swift/SILOptimizer/Utils/BasicBlockOptUtils.h"
24+ #include " swift/SILOptimizer/Utils/CFGOptUtils.h"
2325#include " swift/SILOptimizer/Utils/InstOptUtils.h"
2426#include " llvm/ADT/DenseMap.h"
2527#include " llvm/ADT/SmallPtrSet.h"
@@ -45,6 +47,17 @@ static bool seemsUseful(SILInstruction *I) {
4547 if (isa<BeginAccessInst>(I))
4648 return false ;
4749
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+
4861 if (I->mayHaveSideEffects ())
4962 return true ;
5063
@@ -94,15 +107,16 @@ class DCE : public SILFunctionTransform {
94107 // Dependencies which go in the reverse direction. Usually for a pair
95108 // %1 = inst_a
96109 // 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.
99112 // For some instructions the dependency is exactly the other way round, e.g.
100113 // %1 = inst_which_can_fail
101114 // cond_fail(%1)
102115 // In this case cond_fail is alive only if inst_which_can_fail is alive.
103116 // 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;
106120
107121 // / Tracks if the pass changed branches.
108122 bool BranchesChanged;
@@ -115,11 +129,6 @@ class DCE : public SILFunctionTransform {
115129 CallsChanged = false ;
116130
117131 SILFunction *F = getFunction ();
118-
119- // FIXME: Support ownership.
120- if (F->hasOwnership ())
121- return ;
122-
123132 auto *DA = PM->getAnalysis <PostDominanceAnalysis>();
124133 PDT = DA->get (F);
125134
@@ -150,8 +159,12 @@ class DCE : public SILFunctionTransform {
150159 using InvalidationKind = SILAnalysis::InvalidationKind;
151160
152161 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+ }
155168
156169 invalidateAnalysis (SILAnalysis::InvalidationKind (Inv));
157170 }
@@ -164,7 +177,9 @@ class DCE : public SILFunctionTransform {
164177
165178 bool precomputeControlInfo (SILFunction &F);
166179 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);
168183 bool removeDead (SILFunction &F);
169184
170185 void computeLevelNumbers (PostDomTreeNode *root);
@@ -186,7 +201,9 @@ class DCE : public SILFunctionTransform {
186201 llvm::SmallPtrSetImpl<SILBasicBlock *> &);
187202 SILBasicBlock *nearestUsefulPostDominator (SILBasicBlock *Block);
188203 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);
190207};
191208
192209// Keep track of the fact that V is live and add it to our worklist
@@ -220,7 +237,7 @@ void DCE::markValueLive(SILNode *V) {
220237// / Gets the producing instruction of a cond_fail condition. Currently these
221238// / are overflow builtins but may be extended to other instructions in the
222239// / future.
223- static SILInstruction *getProducer (CondFailInst *CFI) {
240+ static BuiltinInst *getProducer (CondFailInst *CFI) {
224241 // Check for the pattern:
225242 // %1 = builtin "some_operation_with_overflow"
226243 // %2 = tuple_extract %1
@@ -236,42 +253,47 @@ static SILInstruction *getProducer(CondFailInst *CFI) {
236253
237254// Determine which instructions from this function we need to keep.
238255void DCE::markLive (SILFunction &F) {
239-
240256 // Find the initial set of instructions in this function that appear
241257 // to be live in the sense that they are not trivially something we
242258 // can delete by examining only that instruction.
243259 for (auto &BB : F) {
244260 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 );
249265 } else {
250- markValueLive (CFI );
266+ markValueLive (&I );
251267 }
252- continue ;
268+ break ;
253269 }
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);
261274 } else {
262- markValueLive (FLI );
275+ markValueLive (&I );
263276 }
264- continue ;
277+ break ;
265278 }
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);
269294 }
270- if (seemsUseful (&I))
271- markValueLive (&I);
272295 }
273296 }
274-
275297 // Now propagate liveness backwards from each instruction in our
276298 // worklist, adding new instructions to the worklist as we discover
277299 // more that we need to keep.
@@ -281,17 +303,11 @@ void DCE::markLive(SILFunction &F) {
281303 }
282304}
283305
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);
295311}
296312
297313// Mark as live the terminator argument at index ArgIndex in Pred that
@@ -366,8 +382,10 @@ void DCE::propagateLiveBlockArgument(SILArgument *Arg) {
366382 for (Operand *DU : getDebugUses (Arg))
367383 markValueLive (DU->getUser ());
368384
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+ }
371389
372390 auto *Block = Arg->getParent ();
373391 auto ArgIndex = Arg->getIndex ();
@@ -390,10 +408,13 @@ void DCE::propagateLiveness(SILInstruction *I) {
390408 for (Operand *DU : getDebugUses (result))
391409 markValueLive (DU->getUser ());
392410
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+ }
397418 }
398419 return ;
399420 }
@@ -471,22 +492,75 @@ void DCE::replaceBranchWithJump(SILInstruction *Inst, SILBasicBlock *Block) {
471492 (void )Branch;
472493}
473494
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+
474510// Remove the instructions that are not potentially useful.
475511bool DCE::removeDead (SILFunction &F) {
476512 bool Changed = false ;
477513
478514 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++;
482519 continue ;
520+ }
483521
484522 LLVM_DEBUG (llvm::dbgs () << " Removing dead argument:\n " );
485- LLVM_DEBUG (Inst->dump ());
523+ LLVM_DEBUG (arg->dump ());
524+
525+ arg->replaceAllUsesWithUndef ();
486526
487- Inst->replaceAllUsesWithUndef ();
527+ if (!F.hasOwnership () || arg->getType ().isTrivial (F)) {
528+ i++;
529+ Changed = true ;
530+ BranchesChanged = true ;
531+ continue ;
532+ }
488533
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+ }
489562 Changed = true ;
563+ BranchesChanged = true ;
490564 }
491565
492566 for (auto I = BB.begin (), E = BB.end (); I != E; ) {
@@ -501,7 +575,11 @@ bool DCE::removeDead(SILFunction &F) {
501575 SILBasicBlock *postDom = nearestUsefulPostDominator (Inst->getParent ());
502576 if (!postDom)
503577 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+
505583 replaceBranchWithJump (Inst, postDom);
506584 Inst->eraseFromParent ();
507585 BranchesChanged = true ;
@@ -514,6 +592,13 @@ bool DCE::removeDead(SILFunction &F) {
514592 LLVM_DEBUG (llvm::dbgs () << " Removing dead instruction:\n " );
515593 LLVM_DEBUG (Inst->dump ());
516594
595+ if (F.hasOwnership ()) {
596+ for (auto &Op : Inst->getAllOperands ()) {
597+ if (Op.isLifetimeEnding ()) {
598+ endLifetimeOfLiveValue (Op.get (), Inst);
599+ }
600+ }
601+ }
517602 Inst->replaceAllUsesOfAllResultsWithUndef ();
518603
519604 if (isa<ApplyInst>(Inst))
0 commit comments