@@ -190,9 +190,6 @@ class PrunedLiveBlocks {
190
190
// / Optional vector of live blocks for clients that deterministically iterate.
191
191
SmallVectorImpl<SILBasicBlock *> *discoveredBlocks = nullptr ;
192
192
193
- // / Only a clean bitfield can be initialized.
194
- bool cleanFlag = true ;
195
-
196
193
// / Once the first def has been initialized, uses can be added.
197
194
bool initializedFlag = false ;
198
195
@@ -207,7 +204,6 @@ class PrunedLiveBlocks {
207
204
208
205
void invalidate () {
209
206
initializedFlag = false ;
210
- cleanFlag = false ;
211
207
}
212
208
213
209
void initializeDiscoveredBlocks (
@@ -229,17 +225,21 @@ class PrunedLiveBlocks {
229
225
}
230
226
231
227
// / 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) {
233
233
assert (isInitialized () && " at least one definition must be initialized" );
234
234
235
235
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
+ }
243
243
computeUseBlockLiveness (block);
244
244
return getBlockLiveness (block);
245
245
}
@@ -348,6 +348,7 @@ struct LiveRangeSummary {
348
348
// / necessarily include liveness up to destroy_value or end_borrow
349
349
// / instructions.
350
350
class PrunedLiveness {
351
+ protected:
351
352
PrunedLiveBlocks liveBlocks;
352
353
353
354
// Map all "interesting" user instructions in this def's live range to a flag
@@ -390,27 +391,6 @@ class PrunedLiveness {
390
391
liveBlocks.initializeDefBlock (defBB);
391
392
}
392
393
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
-
414
394
PrunedLiveBlocks::IsLive getBlockLiveness (SILBasicBlock *bb) const {
415
395
return liveBlocks.getBlockLiveness (bb);
416
396
}
@@ -565,6 +545,27 @@ class PrunedLiveRange : public PrunedLiveness {
565
545
SILValue value);
566
546
567
547
public:
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
+
568
569
// / Update liveness for all direct uses of \p def. Transitively follows
569
570
// / guaranteed forwards up to but not including guaranteed phis. If \p def is
570
571
// / used by a guaranteed phi return InnerBorrowKind::Reborrowed.
@@ -660,6 +661,9 @@ class SSAPrunedLiveness : public PrunedLiveRange<SSAPrunedLiveness> {
660
661
return def->getParentBlock () == block;
661
662
}
662
663
664
+ // / In SSA, uses never occur before the single def.
665
+ bool isUserBeforeDef (SILInstruction *user) const { return false ; }
666
+
663
667
// / SSA implementation of computeBoundary.
664
668
void findBoundariesInBlock (SILBasicBlock *block, bool isLiveOut,
665
669
PrunedLivenessBoundary &boundary) const ;
@@ -711,7 +715,7 @@ class MultiDefPrunedLiveness : public PrunedLiveRange<MultiDefPrunedLiveness> {
711
715
}
712
716
713
717
void initializeDef (SILInstruction *defInst) {
714
- initializeDefNode (defInst-> asSILNode ( ));
718
+ initializeDefNode (cast<SILNode>(defInst ));
715
719
}
716
720
717
721
void initializeDef (SILArgument *defArg) { initializeDefNode (defArg); }
@@ -733,10 +737,25 @@ class MultiDefPrunedLiveness : public PrunedLiveRange<MultiDefPrunedLiveness> {
733
737
return defs.contains (cast<SILNode>(inst));
734
738
}
735
739
740
+ bool isDef (SILArgument *arg) const {
741
+ return defs.contains (arg);
742
+ }
743
+
736
744
bool isDefBlock (SILBasicBlock *block) const {
737
745
return defBlocks.contains (block);
738
746
}
739
747
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
+
740
759
// / Multi-Def implementation of computeBoundary.
741
760
void findBoundariesInBlock (SILBasicBlock *block, bool isLiveOut,
742
761
PrunedLivenessBoundary &boundary) const ;
0 commit comments