@@ -385,17 +385,6 @@ static bool isInOutDefThatNeedsEndOfFunctionLiveness(MarkMustCheckInst *markedAd
385
385
}
386
386
}
387
387
388
- // See if we have an assignable_but_not_consumable from a formal access.
389
- // In this case, the value must be live at the end of the
390
- // access, similar to an inout parameter.
391
- if (markedAddr->getCheckKind () ==
392
- MarkMustCheckInst::CheckKind::AssignableButNotConsumable) {
393
- if (isa<BeginAccessInst>(operand)) {
394
- return true ;
395
- }
396
- }
397
-
398
-
399
388
return false ;
400
389
}
401
390
@@ -513,7 +502,7 @@ struct UseState {
513
502
// / terminator user and so that we can use the set to quickly identify later
514
503
// / while emitting diagnostics that a liveness use is a terminator user and
515
504
// / emit a specific diagnostic message.
516
- SmallSetVector<SILInstruction *, 2 > inoutTermUsers ;
505
+ SmallSetVector<SILInstruction *, 2 > implicitEndOfLifetimeLivenessUses ;
517
506
518
507
// / We add debug_values to liveness late after we diagnose, but before we
519
508
// / hoist destroys to ensure that we do not hoist destroys out of access
@@ -565,11 +554,17 @@ struct UseState {
565
554
setAffectedBits (inst, range, initInsts);
566
555
}
567
556
568
- // / Returns true if this is a terminator instruction that although it doesn't
569
- // / use our inout argument directly is used by the pass to ensure that we
570
- // / reinit said argument if we consumed it in the body of the function.
571
- bool isInOutTermUser (SILInstruction *inst) const {
572
- return inoutTermUsers.count (inst);
557
+ // / Returns true if this is an instruction that is used by the pass to ensure
558
+ // / that we reinit said argument if we consumed it in a region of code.
559
+ // /
560
+ // / Example:
561
+ // /
562
+ // / 1. In the case of an inout argument, this will contain the terminator
563
+ // / instruction.
564
+ // / 2. In the case of a ref_element_addr or a global, this will contain the
565
+ // / end_access.
566
+ bool isImplicitEndOfLifetimeLivenessUses (SILInstruction *inst) const {
567
+ return implicitEndOfLifetimeLivenessUses.count (inst);
573
568
}
574
569
575
570
// / Returns true if the given instruction is within the same block as a reinit
@@ -609,7 +604,7 @@ struct UseState {
609
604
initInsts.clear ();
610
605
reinitInsts.clear ();
611
606
dropDeinitInsts.clear ();
612
- inoutTermUsers .clear ();
607
+ implicitEndOfLifetimeLivenessUses .clear ();
613
608
debugValue = nullptr ;
614
609
}
615
610
@@ -647,8 +642,8 @@ struct UseState {
647
642
for (auto *inst : dropDeinitInsts) {
648
643
llvm::dbgs () << *inst;
649
644
}
650
- llvm::dbgs () << " InOut Term Users:\n " ;
651
- for (auto *inst : inoutTermUsers ) {
645
+ llvm::dbgs () << " Implicit End Of Lifetime Liveness Users:\n " ;
646
+ for (auto *inst : implicitEndOfLifetimeLivenessUses ) {
652
647
llvm::dbgs () << *inst;
653
648
}
654
649
llvm::dbgs () << " Debug Value User:\n " ;
@@ -680,16 +675,28 @@ struct UseState {
680
675
void
681
676
initializeLiveness (FieldSensitiveMultiDefPrunedLiveRange &prunedLiveness);
682
677
683
- void initializeInOutTermUsers () {
684
- if (!isInOutDefThatNeedsEndOfFunctionLiveness (address))
678
+ void initializeImplicitEndOfLifetimeLivenessUses () {
679
+ if (isInOutDefThatNeedsEndOfFunctionLiveness (address)) {
680
+ SmallVector<SILBasicBlock *, 8 > exitBlocks;
681
+ address->getFunction ()->findExitingBlocks (exitBlocks);
682
+ for (auto *block : exitBlocks) {
683
+ LLVM_DEBUG (llvm::dbgs () << " Adding term as liveness user: "
684
+ << *block->getTerminator ());
685
+ implicitEndOfLifetimeLivenessUses.insert (block->getTerminator ());
686
+ }
685
687
return ;
688
+ }
686
689
687
- SmallVector<SILBasicBlock *, 8 > exitBlocks;
688
- address->getFunction ()->findExitingBlocks (exitBlocks);
689
- for (auto *block : exitBlocks) {
690
- LLVM_DEBUG (llvm::dbgs () << " Adding term as liveness user: "
691
- << *block->getTerminator ());
692
- inoutTermUsers.insert (block->getTerminator ());
690
+ if (address->getCheckKind () ==
691
+ MarkMustCheckInst::CheckKind::AssignableButNotConsumable) {
692
+ if (auto *bai = dyn_cast<BeginAccessInst>(address->getOperand ())) {
693
+ for (auto *eai : bai->getEndAccesses ()) {
694
+ LLVM_DEBUG (llvm::dbgs () << " Adding end_access as implicit end of "
695
+ " lifetime liveness user: "
696
+ << *eai);
697
+ implicitEndOfLifetimeLivenessUses.insert (eai);
698
+ }
699
+ }
693
700
}
694
701
}
695
702
@@ -749,7 +756,7 @@ struct UseState {
749
756
// An "inout terminator use" is an implicit liveness use of the entire
750
757
// value. This is because we need to ensure that our inout value is
751
758
// reinitialized along exit paths.
752
- if (inoutTermUsers .count (inst))
759
+ if (implicitEndOfLifetimeLivenessUses .count (inst))
753
760
return true ;
754
761
755
762
return false ;
@@ -1064,13 +1071,11 @@ void UseState::initializeLiveness(
1064
1071
liveness.print (llvm::dbgs ()));
1065
1072
}
1066
1073
1067
- // Finally, if we have an inout argument, add a liveness use of the entire
1068
- // value on terminators in blocks that are exits from the function. This
1069
- // ensures that along all paths, if our inout is not reinitialized before we
1070
- // exit the function, we will get an error. We also stash these users into
1071
- // inoutTermUser so we can quickly recognize them later and emit a better
1072
- // error msg.
1073
- for (auto *inst : inoutTermUsers) {
1074
+ // Finally, if we have an inout argument or an access scope associated with a
1075
+ // ref_element_addr or global_addr, add a liveness use of the entire value on
1076
+ // the implicit end lifetime instruction. For inout this is terminators for
1077
+ // ref_element_addr, global_addr it is the end_access instruction.
1078
+ for (auto *inst : implicitEndOfLifetimeLivenessUses) {
1074
1079
liveness.updateForUse (inst, TypeTreeLeafTypeRange (address),
1075
1080
false /* lifetime ending*/ );
1076
1081
LLVM_DEBUG (llvm::dbgs () << " Added liveness for inoutTermUser: " << *inst;
@@ -2229,7 +2234,7 @@ bool GlobalLivenessChecker::testInstVectorLiveness(
2229
2234
if (addressUseState.isLivenessUse (&*ii, errorSpan)) {
2230
2235
diagnosticEmitter.emitAddressDiagnostic (
2231
2236
addressUseState.address , &*ii, errorUser, false /* is consuming*/ ,
2232
- addressUseState.isInOutTermUser (&*ii));
2237
+ addressUseState.isImplicitEndOfLifetimeLivenessUses (&*ii));
2233
2238
foundSingleBlockError = true ;
2234
2239
emittedDiagnostic = true ;
2235
2240
break ;
@@ -2249,8 +2254,9 @@ bool GlobalLivenessChecker::testInstVectorLiveness(
2249
2254
&*ii, FieldSensitivePrunedLiveness::NonLifetimeEndingUse,
2250
2255
errorSpan)) {
2251
2256
diagnosticEmitter.emitAddressDiagnostic (
2252
- addressUseState.address , &*ii, errorUser, false /* is consuming*/ ,
2253
- addressUseState.isInOutTermUser (&*ii));
2257
+ addressUseState.address , &*ii, errorUser,
2258
+ false /* is consuming*/ ,
2259
+ addressUseState.isImplicitEndOfLifetimeLivenessUses (&*ii));
2254
2260
foundSingleBlockError = true ;
2255
2261
emittedDiagnostic = true ;
2256
2262
break ;
@@ -2340,7 +2346,8 @@ bool GlobalLivenessChecker::testInstVectorLiveness(
2340
2346
diagnosticEmitter.emitAddressDiagnostic (
2341
2347
addressUseState.address , &blockInst, errorUser,
2342
2348
false /* is consuming*/ ,
2343
- addressUseState.isInOutTermUser (&blockInst));
2349
+ addressUseState.isImplicitEndOfLifetimeLivenessUses (
2350
+ &blockInst));
2344
2351
foundSingleBlockError = true ;
2345
2352
emittedDiagnostic = true ;
2346
2353
break ;
@@ -2567,6 +2574,18 @@ void MoveOnlyAddressCheckerPImpl::insertDestroysOnBoundary(
2567
2574
continue ;
2568
2575
}
2569
2576
2577
+ // If we have an implicit end of lifetime use, we do not insert a
2578
+ // destroy_addr. Instead, we insert an undef debug value after the
2579
+ // use. This occurs if we have an end_access associated with a
2580
+ // global_addr or a ref_element_addr field access.
2581
+ if (addressUseState.isImplicitEndOfLifetimeLivenessUses (inst)) {
2582
+ LLVM_DEBUG (
2583
+ llvm::dbgs ()
2584
+ << " Use was an implicit end of lifetime liveness use!\n " );
2585
+ insertUndefDebugValue (inst->getNextInstruction ());
2586
+ continue ;
2587
+ }
2588
+
2570
2589
auto *insertPt = inst->getNextInstruction ();
2571
2590
insertDestroyBeforeInstruction (addressUseState, insertPt,
2572
2591
liveness.getRootValue (), bits, consumes);
@@ -3207,7 +3226,7 @@ bool MoveOnlyAddressCheckerPImpl::performSingleCheck(
3207
3226
// DISCUSSION: For non address only types, this is not an issue since we
3208
3227
// eagerly load
3209
3228
3210
- addressUseState.initializeInOutTermUsers ();
3229
+ addressUseState.initializeImplicitEndOfLifetimeLivenessUses ();
3211
3230
3212
3231
// ===---
3213
3232
// Liveness Checking
0 commit comments