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