@@ -401,17 +401,6 @@ static bool isInOutDefThatNeedsEndOfFunctionLiveness(MarkMustCheckInst *markedAd
401
401
}
402
402
}
403
403
404
- // See if we have an assignable_but_not_consumable from a formal access.
405
- // In this case, the value must be live at the end of the
406
- // access, similar to an inout parameter.
407
- if (markedAddr->getCheckKind () ==
408
- MarkMustCheckInst::CheckKind::AssignableButNotConsumable) {
409
- if (isa<BeginAccessInst>(operand)) {
410
- return true ;
411
- }
412
- }
413
-
414
-
415
404
return false ;
416
405
}
417
406
@@ -529,7 +518,7 @@ struct UseState {
529
518
// / terminator user and so that we can use the set to quickly identify later
530
519
// / while emitting diagnostics that a liveness use is a terminator user and
531
520
// / emit a specific diagnostic message.
532
- SmallSetVector<SILInstruction *, 2 > inoutTermUsers ;
521
+ SmallSetVector<SILInstruction *, 2 > implicitEndOfLifetimeLivenessUses ;
533
522
534
523
// / We add debug_values to liveness late after we diagnose, but before we
535
524
// / hoist destroys to ensure that we do not hoist destroys out of access
@@ -581,11 +570,17 @@ struct UseState {
581
570
setAffectedBits (inst, range, initInsts);
582
571
}
583
572
584
- // / Returns true if this is a terminator instruction that although it doesn't
585
- // / use our inout argument directly is used by the pass to ensure that we
586
- // / reinit said argument if we consumed it in the body of the function.
587
- bool isInOutTermUser (SILInstruction *inst) const {
588
- return inoutTermUsers.count (inst);
573
+ // / Returns true if this is an instruction that is used by the pass to ensure
574
+ // / that we reinit said argument if we consumed it in a region of code.
575
+ // /
576
+ // / Example:
577
+ // /
578
+ // / 1. In the case of an inout argument, this will contain the terminator
579
+ // / instruction.
580
+ // / 2. In the case of a ref_element_addr or a global, this will contain the
581
+ // / end_access.
582
+ bool isImplicitEndOfLifetimeLivenessUses (SILInstruction *inst) const {
583
+ return implicitEndOfLifetimeLivenessUses.count (inst);
589
584
}
590
585
591
586
// / Returns true if the given instruction is within the same block as a reinit
@@ -625,7 +620,7 @@ struct UseState {
625
620
initInsts.clear ();
626
621
reinitInsts.clear ();
627
622
dropDeinitInsts.clear ();
628
- inoutTermUsers .clear ();
623
+ implicitEndOfLifetimeLivenessUses .clear ();
629
624
debugValue = nullptr ;
630
625
}
631
626
@@ -663,8 +658,8 @@ struct UseState {
663
658
for (auto *inst : dropDeinitInsts) {
664
659
llvm::dbgs () << *inst;
665
660
}
666
- llvm::dbgs () << " InOut Term Users:\n " ;
667
- for (auto *inst : inoutTermUsers ) {
661
+ llvm::dbgs () << " Implicit End Of Lifetime Liveness Users:\n " ;
662
+ for (auto *inst : implicitEndOfLifetimeLivenessUses ) {
668
663
llvm::dbgs () << *inst;
669
664
}
670
665
llvm::dbgs () << " Debug Value User:\n " ;
@@ -696,16 +691,28 @@ struct UseState {
696
691
void
697
692
initializeLiveness (FieldSensitiveMultiDefPrunedLiveRange &prunedLiveness);
698
693
699
- void initializeInOutTermUsers () {
700
- if (!isInOutDefThatNeedsEndOfFunctionLiveness (address))
694
+ void initializeImplicitEndOfLifetimeLivenessUses () {
695
+ if (isInOutDefThatNeedsEndOfFunctionLiveness (address)) {
696
+ SmallVector<SILBasicBlock *, 8 > exitBlocks;
697
+ address->getFunction ()->findExitingBlocks (exitBlocks);
698
+ for (auto *block : exitBlocks) {
699
+ LLVM_DEBUG (llvm::dbgs () << " Adding term as liveness user: "
700
+ << *block->getTerminator ());
701
+ implicitEndOfLifetimeLivenessUses.insert (block->getTerminator ());
702
+ }
701
703
return ;
704
+ }
702
705
703
- SmallVector<SILBasicBlock *, 8 > exitBlocks;
704
- address->getFunction ()->findExitingBlocks (exitBlocks);
705
- for (auto *block : exitBlocks) {
706
- LLVM_DEBUG (llvm::dbgs () << " Adding term as liveness user: "
707
- << *block->getTerminator ());
708
- inoutTermUsers.insert (block->getTerminator ());
706
+ if (address->getCheckKind () ==
707
+ MarkMustCheckInst::CheckKind::AssignableButNotConsumable) {
708
+ if (auto *bai = dyn_cast<BeginAccessInst>(address->getOperand ())) {
709
+ for (auto *eai : bai->getEndAccesses ()) {
710
+ LLVM_DEBUG (llvm::dbgs () << " Adding end_access as implicit end of "
711
+ " lifetime liveness user: "
712
+ << *eai);
713
+ implicitEndOfLifetimeLivenessUses.insert (eai);
714
+ }
715
+ }
709
716
}
710
717
}
711
718
@@ -765,7 +772,7 @@ struct UseState {
765
772
// An "inout terminator use" is an implicit liveness use of the entire
766
773
// value. This is because we need to ensure that our inout value is
767
774
// reinitialized along exit paths.
768
- if (inoutTermUsers .count (inst))
775
+ if (implicitEndOfLifetimeLivenessUses .count (inst))
769
776
return true ;
770
777
771
778
return false ;
@@ -1080,13 +1087,11 @@ void UseState::initializeLiveness(
1080
1087
liveness.print (llvm::dbgs ()));
1081
1088
}
1082
1089
1083
- // Finally, if we have an inout argument, add a liveness use of the entire
1084
- // value on terminators in blocks that are exits from the function. This
1085
- // ensures that along all paths, if our inout is not reinitialized before we
1086
- // exit the function, we will get an error. We also stash these users into
1087
- // inoutTermUser so we can quickly recognize them later and emit a better
1088
- // error msg.
1089
- for (auto *inst : inoutTermUsers) {
1090
+ // Finally, if we have an inout argument or an access scope associated with a
1091
+ // ref_element_addr or global_addr, add a liveness use of the entire value on
1092
+ // the implicit end lifetime instruction. For inout this is terminators for
1093
+ // ref_element_addr, global_addr it is the end_access instruction.
1094
+ for (auto *inst : implicitEndOfLifetimeLivenessUses) {
1090
1095
liveness.updateForUse (inst, TypeTreeLeafTypeRange (address),
1091
1096
false /* lifetime ending*/ );
1092
1097
LLVM_DEBUG (llvm::dbgs () << " Added liveness for inoutTermUser: " << *inst;
@@ -2245,7 +2250,7 @@ bool GlobalLivenessChecker::testInstVectorLiveness(
2245
2250
if (addressUseState.isLivenessUse (&*ii, errorSpan)) {
2246
2251
diagnosticEmitter.emitAddressDiagnostic (
2247
2252
addressUseState.address , &*ii, errorUser, false /* is consuming*/ ,
2248
- addressUseState.isInOutTermUser (&*ii));
2253
+ addressUseState.isImplicitEndOfLifetimeLivenessUses (&*ii));
2249
2254
foundSingleBlockError = true ;
2250
2255
emittedDiagnostic = true ;
2251
2256
break ;
@@ -2265,8 +2270,9 @@ bool GlobalLivenessChecker::testInstVectorLiveness(
2265
2270
&*ii, FieldSensitivePrunedLiveness::NonLifetimeEndingUse,
2266
2271
errorSpan)) {
2267
2272
diagnosticEmitter.emitAddressDiagnostic (
2268
- addressUseState.address , &*ii, errorUser, false /* is consuming*/ ,
2269
- addressUseState.isInOutTermUser (&*ii));
2273
+ addressUseState.address , &*ii, errorUser,
2274
+ false /* is consuming*/ ,
2275
+ addressUseState.isImplicitEndOfLifetimeLivenessUses (&*ii));
2270
2276
foundSingleBlockError = true ;
2271
2277
emittedDiagnostic = true ;
2272
2278
break ;
@@ -2356,7 +2362,8 @@ bool GlobalLivenessChecker::testInstVectorLiveness(
2356
2362
diagnosticEmitter.emitAddressDiagnostic (
2357
2363
addressUseState.address , &blockInst, errorUser,
2358
2364
false /* is consuming*/ ,
2359
- addressUseState.isInOutTermUser (&blockInst));
2365
+ addressUseState.isImplicitEndOfLifetimeLivenessUses (
2366
+ &blockInst));
2360
2367
foundSingleBlockError = true ;
2361
2368
emittedDiagnostic = true ;
2362
2369
break ;
@@ -2583,6 +2590,18 @@ void MoveOnlyAddressCheckerPImpl::insertDestroysOnBoundary(
2583
2590
continue ;
2584
2591
}
2585
2592
2593
+ // If we have an implicit end of lifetime use, we do not insert a
2594
+ // destroy_addr. Instead, we insert an undef debug value after the
2595
+ // use. This occurs if we have an end_access associated with a
2596
+ // global_addr or a ref_element_addr field access.
2597
+ if (addressUseState.isImplicitEndOfLifetimeLivenessUses (inst)) {
2598
+ LLVM_DEBUG (
2599
+ llvm::dbgs ()
2600
+ << " Use was an implicit end of lifetime liveness use!\n " );
2601
+ insertUndefDebugValue (inst->getNextInstruction ());
2602
+ continue ;
2603
+ }
2604
+
2586
2605
auto *insertPt = inst->getNextInstruction ();
2587
2606
insertDestroyBeforeInstruction (addressUseState, insertPt,
2588
2607
liveness.getRootValue (), bits, consumes);
@@ -3210,7 +3229,7 @@ bool MoveOnlyAddressCheckerPImpl::performSingleCheck(
3210
3229
// DISCUSSION: For non address only types, this is not an issue since we
3211
3230
// eagerly load
3212
3231
3213
- addressUseState.initializeInOutTermUsers ();
3232
+ addressUseState.initializeImplicitEndOfLifetimeLivenessUses ();
3214
3233
3215
3234
// ===---
3216
3235
// Liveness Checking
0 commit comments