@@ -90,28 +90,21 @@ SILInstruction *ValueLifetimeAnalysis::findLastUserInBlock(SILBasicBlock *bb) {
9090 llvm_unreachable (" Expected to find use of value in block!" );
9191}
9292
93- bool ValueLifetimeAnalysis::computeFrontier (FrontierImpl &frontier, Mode mode,
94- DeadEndBlocks *deBlocks) {
93+ // FIXME: remove the visitBlock callback once DeadEndBlocks is removed.
94+ void ValueLifetimeAnalysis::computeLifetime (
95+ llvm::function_ref<bool (SILBasicBlock *)> visitBlock,
96+ llvm::function_ref<void(SILInstruction *)> visitLastUser,
97+ llvm::function_ref<void(SILBasicBlock *predBB, SILBasicBlock *succBB)>
98+ visitBoundaryEdge) {
9599 assert (!isAliveAtBeginOfBlock (getFunction ()->getEntryBlock ()) &&
96100 " Can't compute frontier for def which does not dominate all uses" );
97101
98- bool noCriticalEdges = true ;
99-
100- // Exit-blocks from the lifetime region. The value is live at the end of
101- // a predecessor block but not in the frontier block itself.
102- BasicBlockSetVector<16 > frontierBlocks (getFunction ());
103-
104- // Blocks where the value is live at the end of the block and which have
105- // a frontier block as successor.
106- BasicBlockSetVector<16 > liveOutBlocks (getFunction ());
107-
108102 // / The lifetime ends if we have a live block and a not-live successor.
109103 for (SILBasicBlock *bb : liveBlocks) {
110- if (deBlocks && deBlocks-> isDeadEnd (bb))
104+ if (! visitBlock (bb))
111105 continue ;
112106
113107 bool liveInSucc = false ;
114- bool deadInSucc = false ;
115108 bool usedAndRedefinedInSucc = false ;
116109 for (const SILSuccessor &succ : bb->getSuccessors ()) {
117110 if (isAliveAtBeginOfBlock (succ)) {
@@ -128,63 +121,120 @@ bool ValueLifetimeAnalysis::computeFrontier(FrontierImpl &frontier, Mode mode,
128121 " blocks" );
129122 usedAndRedefinedInSucc = true ;
130123 }
131- } else if (!deBlocks || !deBlocks->isDeadEnd (succ)) {
132- deadInSucc = true ;
133124 }
134125 }
135126 if (usedAndRedefinedInSucc) {
136127 // Here, the basic block bb uses the value and later redefines the value.
137128 // Therefore, this value's lifetime ends after its last use preceding the
138129 // re-definition of the value.
139- //
140- // We know that we can not have a SILArgument here since the SILArgument
141- // dominates all instructions in the same block.
142130 auto ii = defValue.get <SILInstruction *>()->getReverseIterator ();
143131 for (; ii != bb->rend (); ++ii) {
144132 if (userSet.count (&*ii)) {
145- frontier. push_back (&*std::next (ii) );
133+ visitLastUser (&*ii );
146134 break ;
147135 }
148136 }
149137 assert (ii != bb->rend () &&
150138 " There must be a user in bb before definition" );
151139 }
152- if (!liveInSucc) {
153- // The value is not live in any of the successor blocks. This means the
154- // block contains a last use of the value. The next instruction after
155- // the last use is part of the frontier.
156- SILInstruction *lastUser = findLastUserInBlock (bb);
157- if (!isa<TermInst>(lastUser)) {
158- frontier.push_back (&*std::next (lastUser->getIterator ()));
159- continue ;
160- }
161- // In case the last user is a TermInst there is no further instruction in
162- // the block which can be the frontier. Instead we add all successor
163- // blocks to the frontier (see below).
164- // If the TermInst exits the function (e.g. 'return' or 'throw'), there
165- // are no successors and we have to bail.
166- if (!deadInSucc) {
167- assert (cast<TermInst>(lastUser)->isFunctionExiting () &&
168- " The final using TermInst must have successors" );
169- assert (mode != AllowToModifyCFG &&
170- " Cannot bail if the mode is AllowToModifyCFG" );
171- return false ;
172- }
173- }
174- if (deadInSucc) {
175- if (mode == UsersMustPostDomDef)
176- return false ;
177-
178- // The value is not live in some of the successor blocks.
179- liveOutBlocks.insert (bb);
140+ if (liveInSucc) {
180141 for (const SILSuccessor &succ : bb->getSuccessors ()) {
181- if (!isAliveAtBeginOfBlock (succ)) {
182- // It's an "exit" edge from the lifetime region.
183- frontierBlocks.insert (succ);
184- }
142+ if (!isAliveAtBeginOfBlock (succ))
143+ visitBoundaryEdge (bb, succ);
185144 }
145+ } else {
146+ // The value is not live in any of the successor blocks. This means the
147+ // block contains a last use of the value.
148+ visitLastUser (findLastUserInBlock (bb));
186149 }
187150 }
151+ }
152+
153+ // Compute a LifetimeBoundary.
154+ //
155+ // Precondition: no critical edges.
156+ void ValueLifetimeAnalysis::computeLifetimeBoundary (
157+ ValueLifetimeBoundary &boundary) {
158+ auto visitBlock = [&](SILBasicBlock *) { return true ; };
159+ auto visitLastUser = [&](SILInstruction *lastUser) {
160+ boundary.lastUsers .push_back (lastUser);
161+ };
162+ auto visitBoundaryEdge = [&](SILBasicBlock *, SILBasicBlock *succBB) {
163+ boundary.boundaryEdges .push_back (succBB);
164+ };
165+ computeLifetime (visitBlock, visitLastUser, visitBoundaryEdge);
166+ }
167+
168+ // FIXME: There is no need for a Mode within the algorithm once critical edges
169+ // are universally prohibited.
170+ //
171+ // FIXME: DeadEndBlocks does not affect value lifetime. It
172+ // should be completely removed and handled by the client.
173+ bool ValueLifetimeAnalysis::computeFrontier (FrontierImpl &frontier, Mode mode,
174+ DeadEndBlocks *deBlocks) {
175+ bool noCriticalEdges = true ;
176+
177+ // Exit-blocks from the lifetime region. The value is live at the end of
178+ // a predecessor block but not in the frontier block itself.
179+ BasicBlockSetVector<16 > frontierBlocks (getFunction ());
180+
181+ // Blocks where the value is live at the end of the block and which have
182+ // a frontier block as successor.
183+ BasicBlockSetVector<16 > liveOutBlocks (getFunction ());
184+
185+ auto visitBlock = [&](SILBasicBlock *bb) {
186+ return !deBlocks || !deBlocks->isDeadEnd (bb);
187+ };
188+
189+ bool foundInvalidLastUser = false ;
190+ auto visitLastUser = [&](SILInstruction *lastUser) {
191+ if (!isa<TermInst>(lastUser)) {
192+ // The next instruction after the last use is part of the frontier.
193+ frontier.push_back (&*std::next (lastUser->getIterator ()));
194+ return ;
195+ }
196+ // FIXME: DeadObjectElimination and StackPromotion don't currently handle
197+ // last use terminators, for no good reason. Fix them, then remove the silly
198+ // UsersMustPostDomDef mode.
199+ if (mode == UsersMustPostDomDef) {
200+ foundInvalidLastUser = true ;
201+ return ;
202+ }
203+ // The last user is a TermInst, and the value is not live into any successor
204+ // blocks (the usedAndRedefinedInSucc case is never a terminator). Since
205+ // there is no further instruction in the block which can be the
206+ // frontier, add all successor blocks to the frontier.
207+ auto *termBB = lastUser->getParent ();
208+ for (const SILSuccessor &succ : termBB->getSuccessors ()) {
209+ assert (!isAliveAtBeginOfBlock (succ)
210+ && " out-of-sync with computeLifetime" );
211+
212+ if (deBlocks && deBlocks->isDeadEnd (succ))
213+ continue ;
214+
215+ // The successor's first instruction will be added to the frontier. Fake
216+ // this block as live-out so edge splitting works.
217+ liveOutBlocks.insert (termBB);
218+ frontierBlocks.insert (succ);
219+ }
220+ };
221+ auto visitBoundaryEdge = [&](SILBasicBlock *predBB, SILBasicBlock *succBB) {
222+ if (deBlocks && deBlocks->isDeadEnd (succBB))
223+ return ;
224+
225+ if (mode == UsersMustPostDomDef) {
226+ foundInvalidLastUser = true ;
227+ return ;
228+ }
229+ liveOutBlocks.insert (predBB);
230+ frontierBlocks.insert (succBB);
231+ };
232+
233+ // Populate frontierBlocks and call visitLastUser().
234+ computeLifetime (visitBlock, visitLastUser, visitBoundaryEdge);
235+ if (foundInvalidLastUser)
236+ return false ;
237+
188238 // Handle "exit" edges from the lifetime region.
189239 BasicBlockSet unhandledFrontierBlocks (getFunction ());
190240 bool unhandledFrontierBlocksFound = false ;
0 commit comments