@@ -99,6 +99,12 @@ class SILValueOwnershipChecker {
99
99
// / successful.
100
100
SmallVector<Operand *, 16 > lifetimeEndingUsers;
101
101
102
+ // / extend_lifetime users of `value`.
103
+ // /
104
+ // / Collected separately because such users do "end the lifetime" but are not
105
+ // / consuming users.
106
+ SmallVector<Operand *, 16 > extendLifetimeUses;
107
+
102
108
// / The list of non lifetime ending users that we found. Only valid if check
103
109
// / is successful.
104
110
SmallVector<Operand *, 16 > regularUsers;
@@ -129,16 +135,26 @@ class SILValueOwnershipChecker {
129
135
bool isCompatibleDefUse (Operand *op, ValueOwnershipKind ownershipKind);
130
136
131
137
bool gatherUsers (SmallVectorImpl<Operand *> &lifetimeEndingUsers,
138
+ SmallVectorImpl<Operand *> &extendLifetimeUses,
132
139
SmallVectorImpl<Operand *> ®ularUsers);
133
140
134
141
bool gatherNonGuaranteedUsers (SmallVectorImpl<Operand *> &lifetimeEndingUsers,
142
+ SmallVectorImpl<Operand *> &extendLifetimeUses,
135
143
SmallVectorImpl<Operand *> ®ularUsers);
136
144
137
- bool checkValueWithoutLifetimeEndingUses (ArrayRef<Operand *> regularUsers);
145
+ bool
146
+ checkValueWithoutLifetimeEndingUses (ArrayRef<Operand *> regularUsers,
147
+ ArrayRef<Operand *> extendLifetimeUses);
138
148
139
- bool checkFunctionArgWithoutLifetimeEndingUses (SILFunctionArgument *arg);
140
- bool checkYieldWithoutLifetimeEndingUses (MultipleValueInstructionResult *yield,
141
- ArrayRef<Operand *> regularUsers);
149
+ bool checkFunctionArgWithoutLifetimeEndingUses (
150
+ SILFunctionArgument *arg, ArrayRef<Operand *> regularUsers,
151
+ ArrayRef<Operand *> extendLifetimeUses);
152
+ bool
153
+ checkYieldWithoutLifetimeEndingUses (MultipleValueInstructionResult *yield,
154
+ ArrayRef<Operand *> regularUsers,
155
+ ArrayRef<Operand *> extendLifetimeUses);
156
+ bool checkDeadEnds (SILBasicBlock *block, ArrayRef<Operand *> regularUsers,
157
+ ArrayRef<Operand *> extendLifetimeUses);
142
158
143
159
bool isGuaranteedFunctionArgWithLifetimeEndingUses (
144
160
SILFunctionArgument *arg,
@@ -166,6 +182,7 @@ bool SILValueOwnershipChecker::check() {
166
182
llvm::copy (lifetimeEndingUsers, std::back_inserter (allLifetimeEndingUsers));
167
183
SmallVector<Operand *, 32 > allRegularUsers;
168
184
llvm::copy (regularUsers, std::back_inserter (allRegularUsers));
185
+ llvm::copy (extendLifetimeUses, std::back_inserter (allRegularUsers));
169
186
170
187
LinearLifetimeChecker checker (deadEndBlocks);
171
188
auto linearLifetimeResult = checker.checkValue (value, allLifetimeEndingUsers,
@@ -199,6 +216,7 @@ bool SILValueOwnershipChecker::isCompatibleDefUse(
199
216
200
217
bool SILValueOwnershipChecker::gatherNonGuaranteedUsers (
201
218
SmallVectorImpl<Operand *> &lifetimeEndingUsers,
219
+ SmallVectorImpl<Operand *> &extendLifetimeUses,
202
220
SmallVectorImpl<Operand *> &nonLifetimeEndingUsers) {
203
221
bool foundError = false ;
204
222
@@ -209,6 +227,11 @@ bool SILValueOwnershipChecker::gatherNonGuaranteedUsers(
209
227
for (auto *op : value->getUses ()) {
210
228
auto *user = op->getUser ();
211
229
230
+ if (isa<ExtendLifetimeInst>(user)) {
231
+ extendLifetimeUses.push_back (op);
232
+ continue ;
233
+ }
234
+
212
235
// For example, type dependent operands are non-use. It is not interesting
213
236
// from an ownership perspective.
214
237
if (op->getOperandOwnership () == OperandOwnership::NonUse)
@@ -268,14 +291,15 @@ bool SILValueOwnershipChecker::gatherNonGuaranteedUsers(
268
291
269
292
bool SILValueOwnershipChecker::gatherUsers (
270
293
SmallVectorImpl<Operand *> &lifetimeEndingUsers,
294
+ SmallVectorImpl<Operand *> &extendLifetimeUses,
271
295
SmallVectorImpl<Operand *> &nonLifetimeEndingUsers) {
272
296
273
297
// See if Value is guaranteed. If we are guaranteed and not forwarding, then
274
298
// we need to look through subobject uses for more uses. Otherwise, if we are
275
299
// forwarding, we do not create any lifetime ending users/non lifetime ending
276
300
// users since we verify against our base.
277
301
if (value->getOwnershipKind () != OwnershipKind::Guaranteed) {
278
- return !gatherNonGuaranteedUsers (lifetimeEndingUsers,
302
+ return !gatherNonGuaranteedUsers (lifetimeEndingUsers, extendLifetimeUses,
279
303
nonLifetimeEndingUsers);
280
304
}
281
305
@@ -474,8 +498,39 @@ bool SILValueOwnershipChecker::gatherUsers(
474
498
return !foundError;
475
499
}
476
500
501
+ // / Precondition: value has no lifetimeEndingUsers
502
+ bool SILValueOwnershipChecker::checkDeadEnds (
503
+ SILBasicBlock *block, ArrayRef<Operand *> regularUses,
504
+ ArrayRef<Operand *> extendedLifetimeUses) {
505
+ if (deadEndBlocks && deadEndBlocks->isDeadEnd (block))
506
+ return true ;
507
+
508
+ if (extendLifetimeUses.size () == 0 )
509
+ return false ;
510
+
511
+ SSAPrunedLiveness liveness (value->getFunction ());
512
+ liveness.initializeDef (value);
513
+ for (auto *use : extendedLifetimeUses) {
514
+ liveness.updateForUse (use->getUser (), /* lifetimeEnding=*/ true );
515
+ }
516
+ auto allWithinBoundary = true ;
517
+ for (auto *use : regularUses) {
518
+ if (!liveness.isWithinBoundary (use->getUser ())) {
519
+ allWithinBoundary |= errorBuilder.handleMalformedSIL ([&] {
520
+ llvm::errs ()
521
+ << " Owned value without lifetime ending uses whose regular use "
522
+ " isn't enclosed within extend_lifetime instructions:\n "
523
+ << " Value: " << value << ' \n '
524
+ << " User: " << use->getUser () << ' \n ' ;
525
+ });
526
+ }
527
+ }
528
+ return allWithinBoundary;
529
+ }
530
+
477
531
bool SILValueOwnershipChecker::checkFunctionArgWithoutLifetimeEndingUses (
478
- SILFunctionArgument *arg) {
532
+ SILFunctionArgument *arg, ArrayRef<Operand *> regularUses,
533
+ ArrayRef<Operand *> extendLifetimeUses) {
479
534
switch (arg->getOwnershipKind ()) {
480
535
case OwnershipKind::Any:
481
536
llvm_unreachable (" Value can not have any ownership kind?!" );
@@ -487,7 +542,7 @@ bool SILValueOwnershipChecker::checkFunctionArgWithoutLifetimeEndingUses(
487
542
break ;
488
543
}
489
544
490
- if (deadEndBlocks && deadEndBlocks-> isDeadEnd (arg->getParent ()))
545
+ if (checkDeadEnds (arg->getParent (), regularUses, extendLifetimeUses ))
491
546
return true ;
492
547
493
548
return !errorBuilder.handleMalformedSIL ([&] {
@@ -497,16 +552,17 @@ bool SILValueOwnershipChecker::checkFunctionArgWithoutLifetimeEndingUses(
497
552
}
498
553
499
554
bool SILValueOwnershipChecker::checkYieldWithoutLifetimeEndingUses (
500
- MultipleValueInstructionResult *yield, ArrayRef<Operand *> regularUses) {
555
+ MultipleValueInstructionResult *yield, ArrayRef<Operand *> regularUses,
556
+ ArrayRef<Operand *> extendLifetimeUses) {
501
557
switch (yield->getOwnershipKind ()) {
502
558
case OwnershipKind::Any:
503
559
llvm_unreachable (" value with any ownership kind?!" );
504
560
case OwnershipKind::Unowned:
505
561
case OwnershipKind::None:
506
562
return true ;
507
563
case OwnershipKind::Owned:
508
- if (deadEndBlocks
509
- && deadEndBlocks-> isDeadEnd (yield-> getParent ()-> getParent () )) {
564
+ if (checkDeadEnds (yield-> getParent ()-> getParent (), regularUses,
565
+ extendLifetimeUses )) {
510
566
return true ;
511
567
}
512
568
return !errorBuilder.handleMalformedSIL ([&] {
@@ -549,16 +605,21 @@ bool SILValueOwnershipChecker::checkYieldWithoutLifetimeEndingUses(
549
605
}
550
606
551
607
bool SILValueOwnershipChecker::checkValueWithoutLifetimeEndingUses (
552
- ArrayRef<Operand *> regularUses) {
608
+ ArrayRef<Operand *> regularUses, ArrayRef<Operand *> extendLifetimeUses) {
609
+ if (extendLifetimeUses.size ()) {
610
+ }
611
+
553
612
LLVM_DEBUG (llvm::dbgs () << " No lifetime ending users?! Bailing early.\n " );
554
613
if (auto *arg = dyn_cast<SILFunctionArgument>(value)) {
555
- if (checkFunctionArgWithoutLifetimeEndingUses (arg)) {
614
+ if (checkFunctionArgWithoutLifetimeEndingUses (arg, regularUses,
615
+ extendLifetimeUses)) {
556
616
return true ;
557
617
}
558
618
}
559
619
560
620
if (auto *yield = isaResultOf<BeginApplyInst>(value)) {
561
- return checkYieldWithoutLifetimeEndingUses (yield, regularUses);
621
+ return checkYieldWithoutLifetimeEndingUses (yield, regularUses,
622
+ extendLifetimeUses);
562
623
}
563
624
564
625
// Check if we are a guaranteed subobject. In such a case, we should never
@@ -575,7 +636,7 @@ bool SILValueOwnershipChecker::checkValueWithoutLifetimeEndingUses(
575
636
return true ;
576
637
577
638
if (auto *parentBlock = value->getParentBlock ()) {
578
- if (deadEndBlocks && deadEndBlocks-> isDeadEnd (parentBlock)) {
639
+ if (checkDeadEnds (parentBlock, regularUses, extendLifetimeUses )) {
579
640
LLVM_DEBUG (llvm::dbgs () << " Ignoring transitively unreachable value "
580
641
<< " without users!\n "
581
642
<< " Value: " << *value << ' \n ' );
@@ -673,7 +734,7 @@ bool SILValueOwnershipChecker::checkUses() {
673
734
// 1. Verify that none of the uses are in the same block. This would be an
674
735
// overconsume so in this case we assert.
675
736
// 2. Verify that the uses are compatible with our ownership convention.
676
- if (!gatherUsers (lifetimeEndingUsers, regularUsers)) {
737
+ if (!gatherUsers (lifetimeEndingUsers, extendLifetimeUses, regularUsers)) {
677
738
// Silently return false if this fails.
678
739
//
679
740
// If the user pass in a ErrorBehaviorKind that will assert, we
@@ -701,7 +762,7 @@ bool SILValueOwnershipChecker::checkUses() {
701
762
// In the case of a yielded guaranteed value, we need to validate that all
702
763
// regular uses of the value are within the coroutine.
703
764
if (lifetimeEndingUsers.empty ()) {
704
- if (checkValueWithoutLifetimeEndingUses (regularUsers))
765
+ if (checkValueWithoutLifetimeEndingUses (regularUsers, extendLifetimeUses ))
705
766
return false ;
706
767
return true ;
707
768
}
0 commit comments