@@ -190,9 +190,6 @@ class PrunedLiveBlocks {
190190 // / Optional vector of live blocks for clients that deterministically iterate.
191191 SmallVectorImpl<SILBasicBlock *> *discoveredBlocks = nullptr ;
192192
193- // / Only a clean bitfield can be initialized.
194- bool cleanFlag = true ;
195-
196193 // / Once the first def has been initialized, uses can be added.
197194 bool initializedFlag = false ;
198195
@@ -207,7 +204,6 @@ class PrunedLiveBlocks {
207204
208205 void invalidate () {
209206 initializedFlag = false ;
210- cleanFlag = false ;
211207 }
212208
213209 void initializeDiscoveredBlocks (
@@ -229,17 +225,21 @@ class PrunedLiveBlocks {
229225 }
230226
231227 // / Update this liveness result for a single use.
232- IsLive updateForUse (SILInstruction *user) {
228+ // /
229+ // / \p isUseBeforeDef is true if \p user occures before the first def in this
230+ // / block. This indicates "liveness holes" inside the block, causing liveness
231+ // / to propagate to predecessors.
232+ IsLive updateForUse (SILInstruction *user, bool isUseBeforeDef) {
233233 assert (isInitialized () && " at least one definition must be initialized" );
234234
235235 auto *block = user->getParent ();
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 .
240- if (liveness != Dead)
241- return liveness;
242-
236+ if (!isUseBeforeDef) {
237+ auto liveness = getBlockLiveness (block);
238+ // If a block is already marked live, it must either "kill" liveness, or
239+ // liveness was already propagated to its predecessors .
240+ if (liveness != Dead)
241+ return liveness;
242+ }
243243 computeUseBlockLiveness (block);
244244 return getBlockLiveness (block);
245245 }
@@ -348,6 +348,7 @@ struct LiveRangeSummary {
348348// / necessarily include liveness up to destroy_value or end_borrow
349349// / instructions.
350350class PrunedLiveness {
351+ protected:
351352 PrunedLiveBlocks liveBlocks;
352353
353354 // Map all "interesting" user instructions in this def's live range to a flag
@@ -390,27 +391,6 @@ class PrunedLiveness {
390391 liveBlocks.initializeDefBlock (defBB);
391392 }
392393
393- // / For flexibility, \p lifetimeEnding is provided by the
394- // / caller. PrunedLiveness makes no assumptions about the def-use
395- // / relationships that generate liveness. For example, use->isLifetimeEnding()
396- // / cannot distinguish the end of the borrow scope that defines this extended
397- // / live range vs. a nested borrow scope within the extended live range.
398- void updateForUse (SILInstruction *user, bool lifetimeEnding);
399-
400- // / Updates the liveness for a whole borrow scope, beginning at \p op.
401- // / Returns false if this cannot be done. This assumes that nested OSSA
402- // / lifetimes are complete.
403- InnerBorrowKind updateForBorrowingOperand (Operand *operand);
404-
405- // / Update liveness for an interior pointer use. These are normally handled
406- // / like an instantaneous use. But if \p operand "borrows" a value for the
407- // / duration of a scoped address (store_borrow), then update liveness for the
408- // / entire scope. This assumes that nested OSSA lifetimes are complete.
409- AddressUseKind checkAndUpdateInteriorPointer (Operand *operand);
410-
411- // / Update this liveness to extend across the given liveness.
412- void extendAcrossLiveness (PrunedLiveness &otherLiveness);
413-
414394 PrunedLiveBlocks::IsLive getBlockLiveness (SILBasicBlock *bb) const {
415395 return liveBlocks.getBlockLiveness (bb);
416396 }
@@ -565,6 +545,27 @@ class PrunedLiveRange : public PrunedLiveness {
565545 SILValue value);
566546
567547public:
548+ // / For flexibility, \p lifetimeEnding is provided by the
549+ // / caller. PrunedLiveness makes no assumptions about the def-use
550+ // / relationships that generate liveness. For example, use->isLifetimeEnding()
551+ // / cannot distinguish the end of the borrow scope that defines this extended
552+ // / live range vs. a nested borrow scope within the extended live range.
553+ void updateForUse (SILInstruction *user, bool lifetimeEnding);
554+
555+ // / Updates the liveness for a whole borrow scope, beginning at \p op.
556+ // / Returns false if this cannot be done. This assumes that nested OSSA
557+ // / lifetimes are complete.
558+ InnerBorrowKind updateForBorrowingOperand (Operand *operand);
559+
560+ // / Update liveness for an interior pointer use. These are normally handled
561+ // / like an instantaneous use. But if \p operand "borrows" a value for the
562+ // / duration of a scoped address (store_borrow), then update liveness for the
563+ // / entire scope. This assumes that nested OSSA lifetimes are complete.
564+ AddressUseKind checkAndUpdateInteriorPointer (Operand *operand);
565+
566+ // / Update this liveness to extend across the given liveness.
567+ void extendAcrossLiveness (PrunedLiveness &otherLiveness);
568+
568569 // / Update liveness for all direct uses of \p def. Transitively follows
569570 // / guaranteed forwards up to but not including guaranteed phis. If \p def is
570571 // / used by a guaranteed phi return InnerBorrowKind::Reborrowed.
@@ -660,6 +661,9 @@ class SSAPrunedLiveness : public PrunedLiveRange<SSAPrunedLiveness> {
660661 return def->getParentBlock () == block;
661662 }
662663
664+ // / In SSA, uses never occur before the single def.
665+ bool isUserBeforeDef (SILInstruction *user) const { return false ; }
666+
663667 // / SSA implementation of computeBoundary.
664668 void findBoundariesInBlock (SILBasicBlock *block, bool isLiveOut,
665669 PrunedLivenessBoundary &boundary) const ;
@@ -711,7 +715,7 @@ class MultiDefPrunedLiveness : public PrunedLiveRange<MultiDefPrunedLiveness> {
711715 }
712716
713717 void initializeDef (SILInstruction *defInst) {
714- initializeDefNode (defInst-> asSILNode ( ));
718+ initializeDefNode (cast<SILNode>(defInst ));
715719 }
716720
717721 void initializeDef (SILArgument *defArg) { initializeDefNode (defArg); }
@@ -733,10 +737,25 @@ class MultiDefPrunedLiveness : public PrunedLiveRange<MultiDefPrunedLiveness> {
733737 return defs.contains (cast<SILNode>(inst));
734738 }
735739
740+ bool isDef (SILArgument *arg) const {
741+ return defs.contains (arg);
742+ }
743+
736744 bool isDefBlock (SILBasicBlock *block) const {
737745 return defBlocks.contains (block);
738746 }
739747
748+ // / Return true if \p user occurs before the first def in the same basic
749+ // / block. In classical liveness dataflow terms, gen/kill conditions over all
750+ // / users in 'bb' are:
751+ // /
752+ // / Gen(bb) |= !isDefBlock(bb) || isUserBeforeDef(bb)
753+ // / Kill(bb) &= isDefBlock(bb) && !isUserBeforeDef(bb)
754+ // /
755+ // / If 'bb' has no users, it is neither a Gen nor Kill. Otherwise, Gen and
756+ // / Kill are complements.
757+ bool isUserBeforeDef (SILInstruction *user) const ;
758+
740759 // / Multi-Def implementation of computeBoundary.
741760 void findBoundariesInBlock (SILBasicBlock *block, bool isLiveOut,
742761 PrunedLivenessBoundary &boundary) const ;
0 commit comments