@@ -155,14 +155,6 @@ class DeadEndBlocks;
155155// / not dominated by a def block, then liveness will include the entry block,
156156// / as if defined by a function argument
157157// /
158- // / We allow for multiple bits of liveness information to be tracked by
159- // / internally using a SmallBitVector. The multiple bit tracking is useful when
160- // / tracking state for multiple fields of the same root value. To do this, we
161- // / actually track 2 bits per actual needed bit so we can represent 3 Dead,
162- // / LiveOut, LiveWithin. This was previously unnecessary since we could just
163- // / represent dead by not having liveness state for a block. With multiple bits
164- // / possible this is no longer true.
165- // /
166158// / TODO: For efficiency, use BasicBlockBitfield rather than SmallDenseMap.
167159class PrunedLiveBlocks {
168160public:
@@ -181,210 +173,101 @@ class PrunedLiveBlocks {
181173 // / LiveOut blocks are live on at least one successor path. LiveOut blocks may
182174 // / or may not contain defs or uses.
183175 // /
184- // / NOTE: The values below for Dead, LiveWithin, LiveOut were picked to ensure
185- // / that given a 2 bit representation of the value, a value is Dead if the
186- // / first bit is 0 and is LiveOut if the second bit is set.
176+ // / NOTE: The values below for Dead, LiveWithin, LiveOut were picked to
177+ // / establish a lattice such that:
178+ // / - Dead is the initial state (zero bitfield)
179+ // / - Merging liveness information is a bitwise-or
187180 enum IsLive {
188181 Dead = 0 ,
189182 LiveWithin = 1 ,
190183 LiveOut = 3 ,
191184 };
192185
193- // / A bit vector that stores information about liveness. This is composed
194- // / with SmallBitVector since it contains two bits per liveness so that it
195- // / can represent 3 states, Dead, LiveWithin, LiveOut. We take advantage of
196- // / their numeric values to make testing easier \see documentation on IsLive.
197- class LivenessSmallBitVector {
198- SmallBitVector bits;
199-
200- public:
201- LivenessSmallBitVector () : bits() {}
202-
203- void init (unsigned numBits) {
204- assert (bits.size () == 0 );
205- assert (numBits != 0 );
206- bits.resize (numBits * 2 );
207- }
208-
209- unsigned size () const { return bits.size () / 2 ; }
210-
211- IsLive getLiveness (unsigned bitNo) const {
212- if (!bits[bitNo * 2 ])
213- return IsLive::Dead;
214- return bits[bitNo * 2 + 1 ] ? LiveOut : LiveWithin;
215- }
216-
217- // / Returns the liveness in \p resultingFoundLiveness. We only return the
218- // / bits for endBitNo - startBitNo.
219- void getLiveness (unsigned startBitNo, unsigned endBitNo,
220- SmallVectorImpl<IsLive> &resultingFoundLiveness) const {
221- unsigned actualStartBitNo = startBitNo * 2 ;
222- unsigned actualEndBitNo = endBitNo * 2 ;
223-
224- for (unsigned i = actualStartBitNo, e = actualEndBitNo; i != e; i += 2 ) {
225- if (!bits[i]) {
226- resultingFoundLiveness.push_back (Dead);
227- continue ;
228- }
229-
230- resultingFoundLiveness.push_back (bits[i + 1 ] ? LiveOut : LiveWithin);
231- }
232- }
233-
234- void setLiveness (unsigned startBitNo, unsigned endBitNo, IsLive isLive) {
235- for (unsigned i = startBitNo * 2 , e = endBitNo * 2 ; i != e; i += 2 ) {
236- bits[i] = isLive & 1 ;
237- bits[i + 1 ] = isLive & 2 ;
238- }
239- }
240-
241- void setLiveness (unsigned bitNo, IsLive isLive) {
242- setLiveness (bitNo, bitNo + 1 , isLive);
243- }
244- };
245-
246186private:
247- // / Map all blocks in which current def is live to a SmallBitVector indicating
248- // / whether the value represented by said bit is also liveout of the block.
249- llvm::SmallDenseMap<SILBasicBlock *, LivenessSmallBitVector, 4 > liveBlocks;
250-
251- // / Number of bits of liveness to track. By default 1. Used to track multiple
252- // / liveness bits.
253- unsigned numBitsToTrack;
187+ // / Map all blocks to an IsLive state.
188+ BasicBlockBitfield liveBlocks;
254189
255190 // / Optional vector of live blocks for clients that deterministically iterate.
256- SmallVectorImpl<SILBasicBlock *> *discoveredBlocks;
191+ SmallVectorImpl<SILBasicBlock *> *discoveredBlocks = nullptr ;
192+
193+ // / Only a clean bitfield can be initialized.
194+ SWIFT_ASSERT_ONLY_DECL (bool cleanFlag = true );
257195
258- // / Once the first use has been seen, no definitions can be added.
259- SWIFT_ASSERT_ONLY_DECL (bool seenUse = false );
196+ // / Once the first def has been initialized, uses can be added.
197+ SWIFT_ASSERT_ONLY_DECL (bool initializedFlag = false );
260198
261199public:
262- PrunedLiveBlocks (unsigned numBitsToTrack ,
200+ PrunedLiveBlocks (SILFunction *function ,
263201 SmallVectorImpl<SILBasicBlock *> *discoveredBlocks = nullptr )
264- : numBitsToTrack(numBitsToTrack ), discoveredBlocks(discoveredBlocks) {
202+ : liveBlocks(function, 2 ), discoveredBlocks(discoveredBlocks) {
265203 assert (!discoveredBlocks || discoveredBlocks->empty ());
266204 }
267205
268- unsigned getNumBitsToTrack () const { return numBitsToTrack; }
269-
270- bool empty () const { return liveBlocks.empty (); }
206+ bool isInitialized () const { return initializedFlag; }
271207
272- void clear () {
273- liveBlocks. clear () ;
274- SWIFT_ASSERT_ONLY (seenUse = false ) ;
208+ void invalidate () {
209+ initializedFlag = false ;
210+ cleanFlag = false ;
275211 }
276212
277- unsigned numLiveBlocks () const { return liveBlocks.size (); }
213+ void initializeDiscoveredBlocks (
214+ SmallVectorImpl<SILBasicBlock *> *discoveredBlocks) {
215+ assert (!isInitialized () && " cannot reinitialize after blocks are live" );
216+
217+ this ->discoveredBlocks = discoveredBlocks;
218+ }
278219
279220 // / If the constructor was provided with a vector to populate, then this
280221 // / returns the list of all live blocks with no duplicates.
281222 ArrayRef<SILBasicBlock *> getDiscoveredBlocks () const {
282223 return *discoveredBlocks;
283224 }
284225
285- void initializeDefBlock (SILBasicBlock *defBB, unsigned bitNo) {
286- markBlockLive (defBB, bitNo, LiveWithin);
287- }
288-
289- void initializeDefBlock (SILBasicBlock *defBB, unsigned startBitNo,
290- unsigned endBitNo) {
291- markBlockLive (defBB, startBitNo, endBitNo, LiveWithin);
226+ void initializeDefBlock (SILBasicBlock *defBB) {
227+ initializedFlag = true ;
228+ markBlockLive (defBB, LiveWithin);
292229 }
293230
294231 // / Update this liveness result for a single use.
295- IsLive updateForUse (SILInstruction *user, unsigned bitNo) {
232+ IsLive updateForUse (SILInstruction *user) {
233+ assert (isInitialized () && " at least one definition must be initialized" );
234+
296235 auto *block = user->getParent ();
297- auto liveness = getBlockLiveness (block, bitNo);
236+ auto liveness = getBlockLiveness (block);
237+ // If a block is already marked live, assume that liveness was propagated to
238+ // its predecessors. This assumes that uses will never be added above a def
239+ // in the same block.
298240 if (liveness != Dead)
299241 return liveness;
300- computeScalarUseBlockLiveness (block, bitNo);
301- return getBlockLiveness (block, bitNo);
302- }
303242
304- // / Update this range of liveness results for a single use.
305- void updateForUse (SILInstruction *user, unsigned startBitNo,
306- unsigned endBitNo,
307- SmallVectorImpl<IsLive> &resultingLiveness);
308-
309- IsLive getBlockLiveness (SILBasicBlock *bb, unsigned bitNo) const {
310- auto liveBlockIter = liveBlocks.find (bb);
311- if (liveBlockIter == liveBlocks.end ()) {
312- return Dead;
313- }
314-
315- return liveBlockIter->second .getLiveness (bitNo);
243+ computeUseBlockLiveness (block);
244+ return getBlockLiveness (block);
316245 }
317246
318- // / FIXME: This API should directly return the live bitset. The live bitset
319- // / type should have an api for querying and iterating over the live fields.
320- void getBlockLiveness (SILBasicBlock *bb, unsigned startBitNo,
321- unsigned endBitNo,
322- SmallVectorImpl<IsLive> &foundLivenessInfo) const {
323- auto liveBlockIter = liveBlocks.find (bb);
324- if (liveBlockIter == liveBlocks.end ()) {
325- for (unsigned i : range (endBitNo - startBitNo)) {
326- (void )i;
327- foundLivenessInfo.push_back (Dead);
328- }
329- return ;
330- }
331-
332- liveBlockIter->second .getLiveness (startBitNo, endBitNo, foundLivenessInfo);
247+ IsLive getBlockLiveness (SILBasicBlock *bb) const {
248+ assert (isInitialized ());
249+ return (IsLive)liveBlocks.get (bb);
333250 }
334251
335252 llvm::StringRef getStringRef (IsLive isLive) const ;
253+
336254 void print (llvm::raw_ostream &OS) const ;
255+
337256 void dump () const ;
338257
339258protected:
340- void markBlockLive (SILBasicBlock *bb, unsigned bitNo, IsLive isLive) {
259+ void markBlockLive (SILBasicBlock *bb, IsLive isLive) {
341260 assert (isLive != Dead && " erasing live blocks isn't implemented." );
342- auto iterAndInserted =
343- liveBlocks.insert (std::make_pair (bb, LivenessSmallBitVector ()));
344- if (iterAndInserted.second ) {
345- // We initialize the size of the small bit vector here rather than in
346- // liveBlocks.insert above to prevent us from allocating upon failure if
347- // we have more than SmallBitVector's small size number of bits.
348- auto &insertedBV = iterAndInserted.first ->getSecond ();
349- insertedBV.init (numBitsToTrack);
350- insertedBV.setLiveness (bitNo, bitNo + 1 , isLive);
261+ auto state = (IsLive)liveBlocks.get (bb);
262+ liveBlocks.set (bb, state | isLive);
263+ if (state == IsLive::Dead) {
351264 if (discoveredBlocks)
352265 discoveredBlocks->push_back (bb);
353- } else {
354- // If we are dead, always update to the new liveness.
355- switch (iterAndInserted.first ->getSecond ().getLiveness (bitNo)) {
356- case Dead:
357- iterAndInserted.first ->getSecond ().setLiveness (bitNo, bitNo + 1 ,
358- isLive);
359- break ;
360- case LiveWithin:
361- if (isLive == LiveOut) {
362- // Update the existing entry to be live-out.
363- iterAndInserted.first ->getSecond ().setLiveness (bitNo, bitNo + 1 ,
364- LiveOut);
365- }
366- break ;
367- case LiveOut:
368- break ;
369- }
370- }
371- }
372-
373- void markBlockLive (SILBasicBlock *bb, unsigned startBitNo, unsigned endBitNo,
374- IsLive isLive) {
375- for (unsigned index : range (startBitNo, endBitNo)) {
376- markBlockLive (bb, index, isLive);
377266 }
378267 }
379268
380269private:
381- // / A helper routine that as a fast path handles the scalar case. We do not
382- // / handle the mult-bit case today since the way the code is written today
383- // / assumes we process a bit at a time.
384- // /
385- // / TODO: Make a multi-bit query for efficiency reasons.
386- void computeScalarUseBlockLiveness (SILBasicBlock *userBB,
387- unsigned startBitNo);
270+ void computeUseBlockLiveness (SILBasicBlock *userBB);
388271};
389272
390273// / If inner borrows are 'Contained', then liveness is fully described by the
@@ -483,17 +366,19 @@ class PrunedLiveness {
483366 SmallVectorImpl<SILBasicBlock *> *discoveredBlocks = nullptr )
484367 : liveBlocks(function, discoveredBlocks) {}
485368
486- bool empty () const {
487- assert (!liveBlocks.empty () || users.empty ());
488- return liveBlocks.empty ();
489- }
369+ bool isInitialized () const { return liveBlocks.isInitialized (); }
370+
371+ bool empty () const { return users.empty (); }
490372
491373 void invalidate () {
492374 liveBlocks.invalidate ();
493375 users.clear ();
494376 }
495377
496- unsigned numLiveBlocks () const { return liveBlocks.numLiveBlocks (); }
378+ void initializeDiscoveredBlocks (
379+ SmallVectorImpl<SILBasicBlock *> *discoveredBlocks) {
380+ liveBlocks.initializeDiscoveredBlocks (discoveredBlocks);
381+ }
497382
498383 // / If the constructor was provided with a vector to populate, then this
499384 // / returns the list of all live blocks with no duplicates.
@@ -502,7 +387,7 @@ class PrunedLiveness {
502387 }
503388
504389 void initializeDefBlock (SILBasicBlock *defBB) {
505- liveBlocks.initializeDefBlock (defBB, 0 );
390+ liveBlocks.initializeDefBlock (defBB);
506391 }
507392
508393 // / For flexibility, \p lifetimeEnding is provided by the
@@ -527,7 +412,7 @@ class PrunedLiveness {
527412 void extendAcrossLiveness (PrunedLiveness &otherLiveness);
528413
529414 PrunedLiveBlocks::IsLive getBlockLiveness (SILBasicBlock *bb) const {
530- return liveBlocks.getBlockLiveness (bb, 0 );
415+ return liveBlocks.getBlockLiveness (bb);
531416 }
532417
533418 enum IsInterestingUser {
@@ -671,8 +556,9 @@ class PrunedLiveRange : public PrunedLiveness {
671556 return static_cast <const LivenessWithDefs &>(*this );
672557 }
673558
674- PrunedLiveRange (SmallVectorImpl<SILBasicBlock *> *discoveredBlocks = nullptr )
675- : PrunedLiveness(discoveredBlocks) {}
559+ PrunedLiveRange (SILFunction *function,
560+ SmallVectorImpl<SILBasicBlock *> *discoveredBlocks = nullptr )
561+ : PrunedLiveness(function, discoveredBlocks) {}
676562
677563 LiveRangeSummary recursivelyUpdateForDef (SILValue initialDef,
678564 ValueSet &visited,
@@ -821,8 +707,6 @@ class MultiDefPrunedLiveness : public PrunedLiveRange<MultiDefPrunedLiveness> {
821707 defBlocks (function) {}
822708
823709 void invalidate () {
824- defs.invalidate ();
825- defBlocks.invalidate ();
826710 PrunedLiveRange::invalidate ();
827711 }
828712
0 commit comments