@@ -96,7 +96,7 @@ AllocationBasedLivenessAnalysis::LivenessData* AllocationBasedLivenessAnalysis::
9696 }
9797
9898 // figure out the potential accesses to the memory via GEP and bitcasts
99- while (!worklist.empty () && !hasNoLifetimeEnd )
99+ while (!worklist.empty ())
100100 {
101101 auto * use = worklist.pop_back_val ();
102102 auto * II = cast<Instruction>(use->getUser ());
@@ -140,22 +140,44 @@ AllocationBasedLivenessAnalysis::LivenessData* AllocationBasedLivenessAnalysis::
140140 }
141141 }
142142
143- // we add the return instructions to the list of users to express the infinite lifetime
144- if (hasNoLifetimeEnd)
143+ return new LivenessData (I, allUsers, *LI, *DT, commonDominator, hasNoLifetimeEnd);
144+ }
145+
146+ template <typename range>
147+ static inline void doWorkLoop (
148+ SmallVector<BasicBlock*>& worklist,
149+ DenseSet<BasicBlock*>& bbSet1,
150+ DenseSet<BasicBlock*>& bbSet2,
151+ std::function<range(BasicBlock*)> iterate,
152+ std::function<bool(BasicBlock*)> continueCondition
153+ ) {
154+ // perform data flow analysis
155+ while (!worklist.empty ())
145156 {
146- for_each (instructions (*I->getFunction ()),
147- [&](auto & II)
148- {
149- if (isa<ReturnInst>(&II))
150- allUsers.insert (&II);
151- }
152- );
157+ auto * currbb = worklist.pop_back_val ();
158+
159+ if (continueCondition (currbb))
160+ continue ;
161+
162+ bool addToSet1 = false ;
163+
164+ for (auto * pbb : iterate(currbb))
165+ {
166+ addToSet1 = true ;
167+
168+ bool inserted = bbSet2.insert (pbb).second ;
169+
170+ if (inserted)
171+ worklist.push_back (pbb);
172+ }
173+
174+ if (addToSet1)
175+ bbSet1.insert (currbb);
153176 }
154177
155- return new LivenessData (I, allUsers, *LI, commonDominator);
156178}
157179
158- AllocationBasedLivenessAnalysis::LivenessData::LivenessData (Instruction* allocationInstruction, const SetVector<Instruction*>& usersOfAllocation, const LoopInfo& LI, BasicBlock* userDominatorBlock)
180+ AllocationBasedLivenessAnalysis::LivenessData::LivenessData (Instruction* allocationInstruction, const SetVector<Instruction*>& usersOfAllocation, const LoopInfo& LI, const DominatorTree& DT, BasicBlock* userDominatorBlock, bool isLifetimeInfinite )
159181{
160182 if (!userDominatorBlock)
161183 userDominatorBlock = allocationInstruction->getParent ();
@@ -172,38 +194,44 @@ AllocationBasedLivenessAnalysis::LivenessData::LivenessData(Instruction* allocat
172194 // Keep track of loop header of blocks that contain allocation instruction
173195 auto * allocationParent = allocationInstruction->getParent ();
174196 llvm::SmallPtrSet<llvm::BasicBlock*, 4 > containedLoopHeaders;
175- if (const auto * parentLoop = LI.getLoopFor (allocationParent);
176- parentLoop != nullptr ) {
197+ if (const auto * parentLoop = LI.getLoopFor (allocationParent))
198+ {
177199 containedLoopHeaders.insert (parentLoop->getHeader ());
178- while (parentLoop->getParentLoop () != nullptr ) {
200+ while (parentLoop->getParentLoop ()) {
179201 parentLoop = parentLoop->getParentLoop ();
180202 containedLoopHeaders.insert (parentLoop->getHeader ());
181203 }
182204 }
205+
183206 // perform data flow analysis
184- while (!worklist.empty ())
207+ doWorkLoop<llvm::pred_range>(
208+ worklist,
209+ bbIn,
210+ bbOut,
211+ [&](auto * currbb) { return llvm::predecessors (currbb); },
212+ [&](auto * currbb) { return bbIn.contains (currbb) || currbb == userDominatorBlock || containedLoopHeaders.contains (currbb); }
213+ );
214+
215+ // handle infinite lifetime
216+ if (isLifetimeInfinite)
185217 {
186- auto * currbb = worklist.pop_back_val ();
187-
188- if (bbIn.contains (currbb) || currbb == userDominatorBlock)
189- continue ;
190-
191- // If alloca is defined in the loop, we skip loop header
192- // so that we don't escape loop scope.
193- if (containedLoopHeaders.count (currbb) != 0 )
194- {
195- continue ;
196- }
197-
198- if (currbb != allocationParent)
199- {
200- bbIn.insert (currbb);
201- }
202- for (auto * pbb : llvm::predecessors (currbb))
203- {
204- bbOut.insert (pbb);
205- worklist.push_back (pbb);
206- }
218+ // traverse all the successors until there are no left.
219+ auto bbInOnly = bbIn;
220+ set_subtract (bbInOnly, bbOut);
221+
222+ for (auto * bb : bbInOnly)
223+ worklist.push_back (bb);
224+
225+ // in case the only use is the one that causes lifetime escape
226+ worklist.push_back (userDominatorBlock);
227+
228+ doWorkLoop<llvm::succ_range>(
229+ worklist,
230+ bbOut,
231+ bbIn,
232+ [&](auto * currbb) { return llvm::successors (currbb); },
233+ [&](auto * currbb) { return false ; }
234+ );
207235 }
208236
209237 // if the lifetime escapes any loop, we should make sure all the loops blocks are included
@@ -216,12 +244,38 @@ AllocationBasedLivenessAnalysis::LivenessData::LivenessData(Instruction* allocat
216244 {
217245 llvm::for_each (
218246 loop->blocks (),
219- [&](auto * block) {
220- bbOut.insert (block);
221- if (block != loop->getHeader ())
222- bbIn.insert (block);
223- }
247+ [&](auto * block) { bbOut.insert (block); bbIn.insert (block); }
224248 );
249+
250+ if (loop->getLoopPreheader ())
251+ {
252+ bbOut.insert (loop->getLoopPreheader ());
253+ }
254+ else
255+ {
256+ // if the header has multiple predecessors, we need to find the common dominator of all of these
257+ auto * commonDominator = loop->getHeader ();
258+ for (auto * bb : llvm::predecessors (loop->getHeader ()))
259+ {
260+ if (loop->contains (bb))
261+ continue ;
262+
263+ commonDominator = DT.findNearestCommonDominator (commonDominator, bb);
264+ worklist.push_back (bb);
265+ }
266+
267+ // acknowledge lifetime flow out of the common dominator block
268+ bbOut.insert (commonDominator);
269+
270+ // add all blocks inbetween
271+ doWorkLoop<llvm::pred_range>(
272+ worklist,
273+ bbIn,
274+ bbOut,
275+ [&](auto * currbb) { return llvm::predecessors (currbb); },
276+ [&](auto * currbb) { return bbOut.contains (currbb) || currbb == commonDominator; }
277+ );
278+ }
225279 }
226280 }
227281
@@ -265,7 +319,7 @@ AllocationBasedLivenessAnalysis::LivenessData::LivenessData(Instruction* allocat
265319 {
266320 for (auto & I : llvm::reverse (*bb))
267321 {
268- if (usersOfAllocation.contains (&I))
322+ if (usersOfAllocation.contains (&I) || isLifetimeInfinite )
269323 {
270324 lifetimeEnds.push_back (&I);
271325 break ;
@@ -290,12 +344,34 @@ bool AllocationBasedLivenessAnalysis::LivenessData::OverlapsWith(const LivenessD
290344 // check lifetime boundaries
291345 for (auto & [LD1, LD2] : { std::make_pair (*this , LD), std::make_pair (LD, *this ) })
292346 {
293- if (LD1.lifetimeEnds .size () == 1 && *LD1.lifetimeEnds .begin () == LD1.lifetimeStart )
294- continue ;
295-
296347 for (auto * I : LD1.lifetimeEnds )
297348 {
298- if (I->getParent () == LD2.lifetimeStart ->getParent ())
349+ // what if LD1 is contained in a single block
350+ if (I->getParent () == LD1.lifetimeStart ->getParent ())
351+ {
352+ auto * bb = I->getParent ();
353+ bool inflow = LD2.bbIn .contains (bb);
354+ bool outflow = LD2.bbOut .contains (bb);
355+ bool lifetimeStart = LD2.lifetimeStart ->getParent () == bb && LD2.lifetimeStart ->comesBefore (I);
356+
357+ auto * LD1_lifetimeStart = LD1.lifetimeStart ; // we have to copy LD1.lifetimeStart to avoid clang complaining about LD1 being captured by the lambda
358+ bool lifetimeEnd = any_of (LD2.lifetimeEnds , [&](auto * lifetimeEnd) {
359+ return lifetimeEnd->getParent () == bb && LD1_lifetimeStart->comesBefore (lifetimeEnd);
360+ });
361+
362+ if (inflow && outflow)
363+ return true ;
364+
365+ if (inflow && lifetimeEnd)
366+ return true ;
367+
368+ if (outflow && lifetimeStart)
369+ return true ;
370+
371+ if (lifetimeEnd && lifetimeStart)
372+ return true ;
373+ }
374+ else if (I->getParent () == LD2.lifetimeStart ->getParent ())
299375 {
300376 if (LD2.lifetimeStart ->comesBefore (I))
301377 return true ;
0 commit comments