19
19
#include " swift/AST/Module.h"
20
20
#include " swift/AST/Types.h"
21
21
#include " swift/Basic/Range.h"
22
+ #include " swift/Basic/STLExtras.h"
22
23
#include " swift/ClangImporter/ClangModule.h"
23
24
#include " swift/SIL/Dominance.h"
24
25
#include " swift/SIL/DynamicCasts.h"
25
26
#include " swift/SIL/PrettyStackTrace.h"
27
+ #include " swift/SIL/Projection.h"
26
28
#include " swift/SIL/SILDebugScope.h"
27
29
#include " swift/SIL/SILFunction.h"
28
30
#include " swift/SIL/SILModule.h"
@@ -72,8 +74,37 @@ static bool isValueAddressOrTrivial(SILValue V, SILModule &M) {
72
74
return V->getType ().isAddress () || V->getType ().isTrivial (M);
73
75
}
74
76
77
+ static bool isOwnershipForwardingValueKind (ValueKind K) {
78
+ switch (K) {
79
+ case ValueKind::TupleInst:
80
+ case ValueKind::StructInst:
81
+ case ValueKind::EnumInst:
82
+ case ValueKind::OpenExistentialRefInst:
83
+ case ValueKind::UpcastInst:
84
+ case ValueKind::UncheckedRefCastInst:
85
+ case ValueKind::ConvertFunctionInst:
86
+ case ValueKind::RefToBridgeObjectInst:
87
+ case ValueKind::BridgeObjectToRefInst:
88
+ case ValueKind::UnconditionalCheckedCastInst:
89
+ case ValueKind::TupleExtractInst:
90
+ case ValueKind::StructExtractInst:
91
+ case ValueKind::UncheckedEnumDataInst:
92
+ return true ;
93
+ default :
94
+ return false ;
95
+ }
96
+ }
97
+
98
+ static bool isOwnershipForwardingValue (SILValue V) {
99
+ return isOwnershipForwardingValueKind (V->getKind ());
100
+ }
101
+
102
+ static bool isOwnershipForwardingInst (SILInstruction *I) {
103
+ return isOwnershipForwardingValueKind (I->getKind ());
104
+ }
105
+
75
106
// ===----------------------------------------------------------------------===//
76
- // OwnershipCompatibilityCheckerVisitor
107
+ // OwnershipCompatibilityUseChecker
77
108
// ===----------------------------------------------------------------------===//
78
109
79
110
namespace {
@@ -88,14 +119,34 @@ class OwnershipCompatibilityUseChecker
88
119
OwnershipUseCheckerResult> {
89
120
SILModule &Mod;
90
121
const Operand &Op;
122
+ SILValue BaseValue;
91
123
92
124
public:
93
- OwnershipCompatibilityUseChecker (SILModule &M, const Operand &Op)
94
- : Mod(M), Op(Op) {}
125
+ // / Create a new OwnershipCompatibilityUseChecker.
126
+ // /
127
+ // / In most cases, one should only pass in \p Op and \p BaseValue will be set
128
+ // / to Op.get(). In cases where one is trying to verify subobjects, Op.get()
129
+ // / should be the subobject and Value should be the parent object. An example
130
+ // / of where one would want to do this is in the case of value projections
131
+ // / like struct_extract.
132
+ OwnershipCompatibilityUseChecker (SILModule &M, const Operand &Op,
133
+ SILValue BaseValue)
134
+ : Mod(M), Op(Op), BaseValue(BaseValue) {
135
+ assert ((BaseValue == Op.get () ||
136
+ BaseValue.getOwnershipKind () == ValueOwnershipKind::Guaranteed) &&
137
+ " Guaranteed values are the only values allowed to have subobject" );
138
+ // We only support subobjects on objects.
139
+ assert ((BaseValue->getType ().isObject () || !isCheckingSubObject ()) &&
140
+ " Checking a subobject, but do not have an object base value?!" );
141
+ }
142
+
143
+ bool isCheckingSubObject () const { return Op.get () != BaseValue; }
95
144
96
145
SILValue getValue () const { return Op.get (); }
97
146
98
147
ValueOwnershipKind getOwnershipKind () const {
148
+ assert (getValue ().getOwnershipKind () == Op.get ().getOwnershipKind () &&
149
+ " Expected ownership kind of parent value and operand" );
99
150
return getValue ().getOwnershipKind ();
100
151
}
101
152
@@ -125,8 +176,9 @@ class OwnershipCompatibilityUseChecker
125
176
if (!Result.HasCompatibleOwnership ) {
126
177
llvm::errs () << " Function: '" << User->getFunction ()->getName () << " '\n "
127
178
<< " Have operand with incompatible ownership?!\n "
128
- << " Value: " << *getValue () << " User: " << *User
129
- << " Conv: " << getOwnershipKind () << " \n\n " ;
179
+ << " Value: " << *getValue () << " BaseValue: " << *BaseValue
180
+ << " User: " << *User << " Conv: " << getOwnershipKind ()
181
+ << " \n\n " ;
130
182
if (IsSILOwnershipVerifierTestingEnabled)
131
183
return false ;
132
184
llvm_unreachable (" triggering standard assertion failure routine" );
@@ -212,10 +264,9 @@ CONSTANT_OWNERSHIP_INST(Owned, true, ReleaseValue)
212
264
CONSTANT_OWNERSHIP_INST(Owned, true , StrongRelease)
213
265
CONSTANT_OWNERSHIP_INST(Owned, true , StrongUnpin)
214
266
CONSTANT_OWNERSHIP_INST(Owned, true , SwitchEnum)
267
+ CONSTANT_OWNERSHIP_INST(Owned, true , CheckedCastBranch)
215
268
CONSTANT_OWNERSHIP_INST(Owned, true , UnownedRelease)
216
269
CONSTANT_OWNERSHIP_INST(Owned, true , InitExistentialRef)
217
- CONSTANT_OWNERSHIP_INST(Guaranteed, true ,
218
- OpenExistentialRef) // We may need a take here.
219
270
CONSTANT_OWNERSHIP_INST(Trivial, false , AddressToPointer)
220
271
CONSTANT_OWNERSHIP_INST(Trivial, false , BindMemory)
221
272
CONSTANT_OWNERSHIP_INST(Trivial, false , CheckedCastAddrBranch)
@@ -271,30 +322,6 @@ CONSTANT_OWNERSHIP_INST(Trivial, false, UnconditionalCheckedCastAddr)
271
322
CONSTANT_OWNERSHIP_INST(Trivial, false , UnmanagedToRef)
272
323
#undef CONSTANT_OWNERSHIP_INST
273
324
274
- #define CONSTANT_OR_TRIVIAL_OWNERSHIP_INST ( \
275
- OWNERSHIP, SHOULD_CHECK_FOR_DATAFLOW_VIOLATIONS, INST) \
276
- OwnershipUseCheckerResult \
277
- OwnershipCompatibilityUseChecker::visit##INST##Inst(INST##Inst *I) { \
278
- assert (I->getNumOperands () && " Expected to have non-zero operands" ); \
279
- if (ValueOwnershipKind::OWNERSHIP != ValueOwnershipKind::Trivial && \
280
- getOwnershipKind () == ValueOwnershipKind::Trivial) { \
281
- assert (isAddressOrTrivialType () && \
282
- " Trivial ownership requires a trivial type or an address" ); \
283
- return {true , false }; \
284
- } \
285
- if (ValueOwnershipKind::OWNERSHIP == ValueOwnershipKind::Trivial) { \
286
- assert (isAddressOrTrivialType () && \
287
- " Trivial ownership requires a trivial type or an address" ); \
288
- } \
289
- \
290
- return {compatibleWithOwnership (ValueOwnershipKind::OWNERSHIP), \
291
- SHOULD_CHECK_FOR_DATAFLOW_VIOLATIONS}; \
292
- }
293
- CONSTANT_OR_TRIVIAL_OWNERSHIP_INST (Guaranteed, false , TupleExtract)
294
- CONSTANT_OR_TRIVIAL_OWNERSHIP_INST(Guaranteed, false , StructExtract)
295
- CONSTANT_OR_TRIVIAL_OWNERSHIP_INST(Guaranteed, false , UncheckedEnumData)
296
- #undef CONSTANT_OR_TRIVIAL_OWNERSHIP_INST
297
-
298
325
#define ACCEPTS_ANY_OWNERSHIP_INST (INST ) \
299
326
OwnershipUseCheckerResult \
300
327
OwnershipCompatibilityUseChecker::visit##INST##Inst(INST##Inst *I) { \
@@ -347,6 +374,8 @@ ACCEPTS_ANY_NONTRIVIAL_OWNERSHIP(false, CopyUnownedValue)
347
374
OwnershipUseCheckerResult
348
375
OwnershipCompatibilityUseChecker::visitForwardingInst (SILInstruction *I) {
349
376
assert (I->getNumOperands () && " Expected to have non-zero operands" );
377
+ assert (isOwnershipForwardingInst (I) &&
378
+ " Expected to have an ownership forwarding inst" );
350
379
ArrayRef<Operand> Ops = I->getAllOperands ();
351
380
ValueOwnershipKind Base = getOwnershipKind ();
352
381
for (const Operand &Op : Ops) {
@@ -358,27 +387,73 @@ OwnershipCompatibilityUseChecker::visitForwardingInst(SILInstruction *I) {
358
387
return {true , !isAddressOrTrivialType ()};
359
388
}
360
389
361
- #define FORWARD_OWNERSHIP_INST (INST ) \
390
+ #define FORWARD_ANY_OWNERSHIP_INST (INST ) \
362
391
OwnershipUseCheckerResult \
363
392
OwnershipCompatibilityUseChecker::visit##INST##Inst(INST##Inst *I) { \
364
393
return visitForwardingInst (I); \
365
394
}
395
+ FORWARD_ANY_OWNERSHIP_INST (Tuple)
396
+ FORWARD_ANY_OWNERSHIP_INST(Struct)
397
+ FORWARD_ANY_OWNERSHIP_INST(Enum)
398
+ FORWARD_ANY_OWNERSHIP_INST(OpenExistentialRef)
399
+ FORWARD_ANY_OWNERSHIP_INST(Upcast)
400
+ FORWARD_ANY_OWNERSHIP_INST(UncheckedRefCast)
401
+ FORWARD_ANY_OWNERSHIP_INST(ConvertFunction)
402
+ FORWARD_ANY_OWNERSHIP_INST(RefToBridgeObject)
403
+ FORWARD_ANY_OWNERSHIP_INST(BridgeObjectToRef)
404
+ FORWARD_ANY_OWNERSHIP_INST(UnconditionalCheckedCast)
405
+ FORWARD_ANY_OWNERSHIP_INST(Branch)
406
+ #undef FORWARD_ANY_OWNERSHIP_INST
407
+
408
+ // An instruction that forwards a constant ownership or trivial ownership.
409
+ #define FORWARD_CONSTANT_OR_TRIVIAL_OWNERSHIP_INST ( \
410
+ OWNERSHIP, SHOULD_CHECK_FOR_DATAFLOW_VIOLATIONS, INST) \
411
+ OwnershipUseCheckerResult \
412
+ OwnershipCompatibilityUseChecker::visit##INST##Inst(INST##Inst *I) { \
413
+ assert (I->getNumOperands () && " Expected to have non-zero operands" ); \
414
+ assert (isOwnershipForwardingInst (I) && \
415
+ " Expected an ownership forwarding inst" ); \
416
+ if (ValueOwnershipKind::OWNERSHIP != ValueOwnershipKind::Trivial && \
417
+ getOwnershipKind () == ValueOwnershipKind::Trivial) { \
418
+ assert (isAddressOrTrivialType () && \
419
+ " Trivial ownership requires a trivial type or an address" ); \
420
+ return {true , false }; \
421
+ } \
422
+ if (ValueOwnershipKind::OWNERSHIP == ValueOwnershipKind::Trivial) { \
423
+ assert (isAddressOrTrivialType () && \
424
+ " Trivial ownership requires a trivial type or an address" ); \
425
+ } \
426
+ \
427
+ return {compatibleWithOwnership (ValueOwnershipKind::OWNERSHIP), \
428
+ SHOULD_CHECK_FOR_DATAFLOW_VIOLATIONS}; \
429
+ }
430
+ FORWARD_CONSTANT_OR_TRIVIAL_OWNERSHIP_INST (Guaranteed, false , TupleExtract)
431
+ FORWARD_CONSTANT_OR_TRIVIAL_OWNERSHIP_INST(Guaranteed, false , StructExtract)
432
+ FORWARD_CONSTANT_OR_TRIVIAL_OWNERSHIP_INST(Guaranteed, false , UncheckedEnumData)
433
+ #undef CONSTANT_OR_TRIVIAL_OWNERSHIP_INST
434
+
435
+ // This ANY_should be based off of the argument.
436
+
437
+ OwnershipUseCheckerResult
438
+ OwnershipCompatibilityUseChecker::visitCondBranchInst (CondBranchInst *CBI) {
439
+ ValueOwnershipKind Base = getOwnershipKind ();
440
+
441
+ for (SILValue TrueArg : CBI->getTrueArgs ()) {
442
+ auto MergedValue = Base.merge (TrueArg.getOwnershipKind ());
443
+ if (!MergedValue.hasValue ())
444
+ return {false , true };
445
+ Base = MergedValue.getValue ();
446
+ }
366
447
367
- FORWARD_OWNERSHIP_INST (Tuple)
368
- FORWARD_OWNERSHIP_INST(Struct)
369
- FORWARD_OWNERSHIP_INST(Enum)
370
- // All of these should really have take falgs and be guaranteed otherwise.
371
- FORWARD_OWNERSHIP_INST(Upcast)
372
- FORWARD_OWNERSHIP_INST(UncheckedRefCast)
373
- FORWARD_OWNERSHIP_INST(ConvertFunction)
374
- FORWARD_OWNERSHIP_INST(RefToBridgeObject)
375
- FORWARD_OWNERSHIP_INST(BridgeObjectToRef)
376
- FORWARD_OWNERSHIP_INST(UnconditionalCheckedCast)
377
- // This should be based off of the argument.
378
- FORWARD_OWNERSHIP_INST(Branch)
379
- FORWARD_OWNERSHIP_INST(CondBranch)
380
- FORWARD_OWNERSHIP_INST(CheckedCastBranch)
381
- #undef FORWARD_OWNERSHIP_INST
448
+ for (SILValue FalseArg : CBI->getFalseArgs ()) {
449
+ auto MergedValue = Base.merge (FalseArg.getOwnershipKind ());
450
+ if (!MergedValue.hasValue ())
451
+ return {false , true };
452
+ Base = MergedValue.getValue ();
453
+ }
454
+
455
+ return {true , !isAddressOrTrivialType ()};
456
+ }
382
457
383
458
OwnershipUseCheckerResult
384
459
OwnershipCompatibilityUseChecker::visitReturnInst (ReturnInst *RI) {
@@ -678,7 +753,7 @@ bool SILValueOwnershipChecker::doesBlockContainUseAfterFree(
678
753
<< " Value: " << *Value
679
754
<< " Consuming User: " << *LifetimeEndingUser
680
755
<< " Non Consuming User: " << *Iter->second << " Block: bb"
681
- << UserBlock->getDebugID () << " \n " ;
756
+ << UserBlock->getDebugID () << " \n\n " ;
682
757
return true ;
683
758
}
684
759
@@ -707,15 +782,55 @@ bool SILValueOwnershipChecker::doesBlockDoubleConsume(
707
782
void SILValueOwnershipChecker::gatherUsers (
708
783
llvm::SmallVectorImpl<SILInstruction *> &LifetimeEndingUsers,
709
784
llvm::SmallVectorImpl<SILInstruction *> &NonLifetimeEndingUsers) {
710
- for (Operand *Op : Value->getUses ()) {
785
+
786
+ // See if Value is guaranteed. If we are guaranteed and not forwarding, then
787
+ // we need to look through subobject uses for more uses. Otherwise, if we are
788
+ // forwarding, we do not create any lifetime ending users/non lifetime ending
789
+ // users since we verify against our base.
790
+ bool IsGuaranteed =
791
+ Value.getOwnershipKind () == ValueOwnershipKind::Guaranteed;
792
+
793
+ if (IsGuaranteed && isOwnershipForwardingValue (Value))
794
+ return ;
795
+
796
+ // Then gather up our initial list of users.
797
+ llvm::SmallVector<Operand *, 8 > Users;
798
+ std::copy (Value->use_begin (), Value->use_end (), std::back_inserter (Users));
799
+
800
+ while (!Users.empty ()) {
801
+ Operand *Op = Users.pop_back_val ();
802
+
711
803
auto *User = Op->getUser ();
712
- if (OwnershipCompatibilityUseChecker (Mod, *Op).check (User)) {
804
+ if (OwnershipCompatibilityUseChecker (Mod, *Op, Value ).check (User)) {
713
805
DEBUG (llvm::dbgs () << " Lifetime Ending User: " << *User);
714
806
LifetimeEndingUsers.push_back (User);
715
807
} else {
716
808
DEBUG (llvm::dbgs () << " Regular User: " << *User);
717
809
NonLifetimeEndingUsers.push_back (User);
718
810
}
811
+
812
+ // If our base value is not guaranteed or our intermediate value is not an
813
+ // ownership forwarding inst, continue. We do not want to visit any
814
+ // subobjects recursively.
815
+ if (!IsGuaranteed || !isOwnershipForwardingInst (User)) {
816
+ continue ;
817
+ }
818
+
819
+ // At this point, we know that we must have a forwarded subobject. Since the
820
+ // base type is guaranteed, we know that the subobject is either guaranteed
821
+ // or trivial. The trivial case is not interesting for ARC verification, so
822
+ // if the user has a trivial ownership kind, continue.
823
+ if (SILValue (User).getOwnershipKind () == ValueOwnershipKind::Trivial) {
824
+ continue ;
825
+ }
826
+
827
+ // Now, we /must/ have a guaranteed subobject, so lets assert that the user
828
+ // is actually guaranteed and add the subobject's users to our worklist.
829
+ assert (SILValue (User).getOwnershipKind () ==
830
+ ValueOwnershipKind::Guaranteed &&
831
+ " Our value is guaranteed and this is a forwarding instruction. "
832
+ " Should have guaranteed ownership as well." );
833
+ std::copy (User->use_begin (), User->use_end (), std::back_inserter (Users));
719
834
}
720
835
}
721
836
@@ -784,6 +899,13 @@ bool SILValueOwnershipChecker::checkValueWithoutLifetimeEndingUses() {
784
899
}
785
900
}
786
901
902
+ // Check if we are a guaranteed subobject. In such a case, we should never
903
+ // have lifetime ending uses, since our lifetime is guaranteed by our
904
+ // operand, so there is nothing further to do. So just return true.
905
+ if (isOwnershipForwardingValue (Value) &&
906
+ Value.getOwnershipKind () == ValueOwnershipKind::Guaranteed)
907
+ return true ;
908
+
787
909
if (!isValueAddressOrTrivial (Value, Mod)) {
788
910
llvm::errs () << " Function: '" << Value->getFunction ()->getName () << " '\n "
789
911
<< " Non trivial values, non address values, and non "
@@ -816,6 +938,21 @@ static bool isGuaranteedFunctionArgWithLifetimeEndingUses(
816
938
llvm_unreachable (" triggering standard assertion failure routine" );
817
939
}
818
940
941
+ static bool isSubobjectProjectionWithLifetimeEndingUses (
942
+ SILValue Value,
943
+ const llvm::SmallVectorImpl<SILInstruction *> &LifetimeEndingUsers) {
944
+ llvm::errs () << " Function: '" << Value->getFunction ()->getName () << " '\n "
945
+ << " Subobject projection with life ending uses!\n "
946
+ << " Value: " << *Value;
947
+ for (auto *U : LifetimeEndingUsers) {
948
+ llvm::errs () << " Lifetime Ending User: " << *U;
949
+ }
950
+ llvm::errs () << ' \n ' ;
951
+ if (IsSILOwnershipVerifierTestingEnabled)
952
+ return false ;
953
+ llvm_unreachable (" triggering standard assertion failure routine" );
954
+ }
955
+
819
956
bool SILValueOwnershipChecker::checkUses () {
820
957
DEBUG (llvm::dbgs () << " Gathering and classifying uses!\n " );
821
958
@@ -857,6 +994,17 @@ bool SILValueOwnershipChecker::checkUses() {
857
994
}
858
995
}
859
996
997
+ // Check if we are an instruction that forwards ownership that forwards
998
+ // guaranteed ownership. In such a case, we are a subobject projection. We
999
+ // should not have any lifetime ending uses.
1000
+ if (isOwnershipForwardingValue (Value) &&
1001
+ Value.getOwnershipKind () == ValueOwnershipKind::Guaranteed) {
1002
+ if (!isSubobjectProjectionWithLifetimeEndingUses (Value,
1003
+ LifetimeEndingUsers)) {
1004
+ return false ;
1005
+ }
1006
+ }
1007
+
860
1008
// Then add our non lifetime ending users and their blocks to the
861
1009
// BlocksWithNonLifetimeEndingUses map. While we do this, if we have multiple
862
1010
// uses in the same block, we only accept the last use since from a liveness
@@ -1015,8 +1163,9 @@ void SILValueOwnershipChecker::checkDataflow() {
1015
1163
<< " Value: " << *Value << " Remaining Users:\n " ;
1016
1164
for (auto &Pair : BlocksWithNonLifetimeEndingUses) {
1017
1165
llvm::errs () << " User:" << *Pair.second << " Block: bb"
1018
- << Pair.first ->getDebugID () << " \n\n " ;
1166
+ << Pair.first ->getDebugID () << " \n " ;
1019
1167
}
1168
+ llvm::errs () << " \n " ;
1020
1169
if (IsSILOwnershipVerifierTestingEnabled)
1021
1170
return ;
1022
1171
llvm_unreachable (" triggering standard assertion failure routine" );
@@ -1040,7 +1189,7 @@ void SILInstruction::verifyOperandOwnership() const {
1040
1189
return ;
1041
1190
auto *Self = const_cast <SILInstruction *>(this );
1042
1191
for (const Operand &Op : getAllOperands ()) {
1043
- OwnershipCompatibilityUseChecker (getModule (), Op).check (Self);
1192
+ OwnershipCompatibilityUseChecker (getModule (), Op, Op. get () ).check (Self);
1044
1193
}
1045
1194
#endif
1046
1195
}
0 commit comments