@@ -69,10 +69,27 @@ static bool isIsolationBoundaryCrossingApply(SILInstruction *inst) {
69
69
70
70
namespace {
71
71
72
+ struct UnderlyingTrackedValueInfo {
73
+ SILValue value;
74
+
75
+ // / Only used for addresses.
76
+ bool isActorIsolated;
77
+
78
+ explicit UnderlyingTrackedValueInfo (SILValue value)
79
+ : value(value), isActorIsolated(false ) {}
80
+
81
+ UnderlyingTrackedValueInfo (SILValue value, bool isActorIsolated)
82
+ : value(value), isActorIsolated(isActorIsolated) {}
83
+ };
84
+
72
85
struct UseDefChainVisitor
73
86
: public AccessUseDefChainVisitor<UseDefChainVisitor, SILValue> {
74
87
bool isMerge = false ;
75
88
89
+ // / The actor isolation that we found while walking from use->def. Always set
90
+ // / to the first one encountered.
91
+ std::optional<ActorIsolation> actorIsolation;
92
+
76
93
SILValue visitAll (SILValue sourceAddr) {
77
94
SILValue result = visit (sourceAddr);
78
95
if (!result)
@@ -142,9 +159,21 @@ struct UseDefChainVisitor
142
159
// Index is always a merge.
143
160
isMerge = true ;
144
161
break ;
145
- case ProjectionKind::Enum:
146
- // Enum is never a merge since it always has a single field.
162
+ case ProjectionKind::Enum: {
163
+ // Enum is never a merge since it always has a single tuple field... but
164
+ // it can be actor isolated.
165
+ if (!bool (actorIsolation)) {
166
+ auto *uedi = cast<UncheckedTakeEnumDataAddrInst>(inst);
167
+ auto i = getActorIsolation (uedi->getEnumDecl ());
168
+ // If our operand decl is actor isolated, then we want to stop looking
169
+ // through since it is Sendable.
170
+ if (i.isActorIsolated ()) {
171
+ actorIsolation = i;
172
+ return SILValue ();
173
+ }
174
+ }
147
175
break ;
176
+ }
148
177
case ProjectionKind::Tuple: {
149
178
// These are merges if we have multiple fields.
150
179
auto *tti = cast<TupleElementAddrInst>(inst);
@@ -163,6 +192,17 @@ struct UseDefChainVisitor
163
192
case ProjectionKind::Struct:
164
193
auto *sea = cast<StructElementAddrInst>(inst);
165
194
195
+ // See if our type is actor isolated.
196
+ if (!bool (actorIsolation)) {
197
+ auto i = getActorIsolation (sea->getStructDecl ());
198
+ // If our parent type is actor isolated then we do not want to keep on
199
+ // walking up from use->def since the value is considered Sendable.
200
+ if (i.isActorIsolated ()) {
201
+ actorIsolation = i;
202
+ return SILValue ();
203
+ }
204
+ }
205
+
166
206
// See if our result type is a sendable type. In such a case, we do not
167
207
// want to look through the struct_element_addr since we do not want to
168
208
// identify the sendable type with the non-sendable operand. These we
@@ -248,8 +288,6 @@ static bool isLookThroughIfResultNonSendable(SILInstruction *inst) {
248
288
switch (inst->getKind ()) {
249
289
default :
250
290
return false ;
251
- case SILInstructionKind::TupleElementAddrInst:
252
- case SILInstructionKind::StructElementAddrInst:
253
291
case SILInstructionKind::RawPointerToRefInst:
254
292
return true ;
255
293
}
@@ -264,13 +302,16 @@ static bool isLookThroughIfOperandNonSendable(SILInstruction *inst) {
264
302
}
265
303
}
266
304
267
- static bool isLookThroughIfOperandAndResultSendable (SILInstruction *inst) {
305
+ static bool isLookThroughIfOperandAndResultNonSendable (SILInstruction *inst) {
268
306
switch (inst->getKind ()) {
269
307
default :
270
308
return false ;
271
309
case SILInstructionKind::UncheckedTrivialBitCastInst:
272
310
case SILInstructionKind::UncheckedBitwiseCastInst:
273
311
case SILInstructionKind::UncheckedValueCastInst:
312
+ case SILInstructionKind::StructElementAddrInst:
313
+ case SILInstructionKind::TupleElementAddrInst:
314
+ case SILInstructionKind::UncheckedTakeEnumDataAddrInst:
274
315
return true ;
275
316
}
276
317
}
@@ -293,7 +334,7 @@ static SILValue getUnderlyingTrackedObjectValue(SILValue value) {
293
334
294
335
// If we have a cast and our operand and result are non-Sendable, treat it
295
336
// as a look through.
296
- if (isLookThroughIfOperandAndResultSendable (svi)) {
337
+ if (isLookThroughIfOperandAndResultNonSendable (svi)) {
297
338
if (isNonSendableType (svi->getType (), fn) &&
298
339
isNonSendableType (svi->getOperand (0 )->getType (), fn)) {
299
340
temp = svi->getOperand (0 );
@@ -329,21 +370,21 @@ static SILValue getUnderlyingTrackedObjectValue(SILValue value) {
329
370
}
330
371
}
331
372
332
- static SILValue getUnderlyingTrackedValue (SILValue value) {
373
+ static UnderlyingTrackedValueInfo getUnderlyingTrackedValue (SILValue value) {
333
374
if (!value->getType ().isAddress ()) {
334
- return getUnderlyingTrackedObjectValue (value);
375
+ return UnderlyingTrackedValueInfo ( getUnderlyingTrackedObjectValue (value) );
335
376
}
336
377
337
378
UseDefChainVisitor visitor;
338
379
SILValue base = visitor.visitAll (value);
339
380
assert (base);
340
381
if (base->getType ().isObject ())
341
- return getUnderlyingObject (base);
342
- return base;
382
+ return { getUnderlyingObject (base), visitor. actorIsolation . has_value ()} ;
383
+ return { base, visitor. actorIsolation . has_value ()} ;
343
384
}
344
385
345
386
SILValue RegionAnalysisFunctionInfo::getUnderlyingTrackedValue (SILValue value) {
346
- return ::getUnderlyingTrackedValue (value);
387
+ return ::getUnderlyingTrackedValue (value). value ;
347
388
}
348
389
349
390
namespace {
@@ -650,7 +691,7 @@ struct PartialApplyReachabilityDataflow {
650
691
651
692
private:
652
693
SILValue getRootValue (SILValue value) const {
653
- return getUnderlyingTrackedValue (value);
694
+ return getUnderlyingTrackedValue (value). value ;
654
695
}
655
696
656
697
unsigned getBitForValue (SILValue value) const {
@@ -2150,7 +2191,7 @@ class PartitionOpTranslator {
2150
2191
assert ((isStaticallyLookThroughInst (inst) ||
2151
2192
isLookThroughIfResultNonSendable (inst) ||
2152
2193
isLookThroughIfOperandNonSendable (inst) ||
2153
- isLookThroughIfOperandAndResultSendable (inst)) &&
2194
+ isLookThroughIfOperandAndResultNonSendable (inst)) &&
2154
2195
" Out of sync... should return true for one of these categories!" );
2155
2196
return translateSILLookThrough (inst->getResults (), inst->getOperand (0 ));
2156
2197
@@ -2379,7 +2420,6 @@ CONSTANT_TRANSLATION(EndInitLetRefInst, LookThrough)
2379
2420
CONSTANT_TRANSLATION(InitEnumDataAddrInst, LookThrough)
2380
2421
CONSTANT_TRANSLATION(OpenExistentialAddrInst, LookThrough)
2381
2422
CONSTANT_TRANSLATION(UncheckedRefCastInst, LookThrough)
2382
- CONSTANT_TRANSLATION(UncheckedTakeEnumDataAddrInst, LookThrough)
2383
2423
CONSTANT_TRANSLATION(UpcastInst, LookThrough)
2384
2424
CONSTANT_TRANSLATION(MoveValueInst, LookThrough)
2385
2425
CONSTANT_TRANSLATION(MarkUnresolvedNonCopyableValueInst, LookThrough)
@@ -2598,39 +2638,6 @@ CONSTANT_TRANSLATION(VectorInst, Asserting)
2598
2638
2599
2639
#undef CONSTANT_TRANSLATION
2600
2640
2601
- #ifdef LOOKTHROUGH_IF_NONSENDABLE_RESULT_REQUIRE_OTHERWISE
2602
- #error "LOOKTHROUGH_IF_NONSENDABLE_RESULT_REQUIRE_OTHERWISE already defined?!"
2603
- #endif
2604
-
2605
- // If our result is non-Sendable, treat this as a lookthrough.
2606
- // Otherwise, we are extracting a sendable field from a non-Sendable base
2607
- // type. We need to track this as an assignment so that if we transferred
2608
- //
2609
- // the value we emit an error. Since we do not track uses of Sendable
2610
- // values this is the best place to emit the error since we do not look
2611
- // further to find the actual use site.
2612
- //
2613
- // TODO: We could do a better job here and attempt to find the actual
2614
- // use
2615
- // of the Sendable addr. That would require adding more logic though.
2616
- #define LOOKTHROUGH_IF_NONSENDABLE_RESULT_REQUIRE_OTHERWISE (INST ) \
2617
- TranslationSemantics PartitionOpTranslator::visit##INST(INST *inst) { \
2618
- assert (isLookThroughIfResultNonSendable (inst) && " Out of sync?!" ); \
2619
- if (isNonSendableType (inst->getType ())) { \
2620
- return TranslationSemantics::LookThrough; \
2621
- } \
2622
- return TranslationSemantics::Require; \
2623
- }
2624
-
2625
- LOOKTHROUGH_IF_NONSENDABLE_RESULT_REQUIRE_OTHERWISE (TupleElementAddrInst)
2626
- LOOKTHROUGH_IF_NONSENDABLE_RESULT_REQUIRE_OTHERWISE(StructElementAddrInst)
2627
-
2628
- #undef LOOKTHROUGH_IF_NONSENDABLE_RESULT_REQUIRE_OTHERWISE
2629
-
2630
- #ifdef IGNORE_IF_SENDABLE_RESULT_ASSIGN_OTHERWISE
2631
- #error IGNORE_IF_SENDABLE_RESULT_ASSIGN_OTHERWISE already defined
2632
- #endif
2633
-
2634
2641
#define IGNORE_IF_SENDABLE_RESULT_ASSIGN_OTHERWISE (INST ) \
2635
2642
TranslationSemantics PartitionOpTranslator::visit##INST(INST *inst) { \
2636
2643
if (!isNonSendableType (inst->getType ())) { \
@@ -2644,14 +2651,14 @@ IGNORE_IF_SENDABLE_RESULT_ASSIGN_OTHERWISE(StructExtractInst)
2644
2651
2645
2652
#undef IGNORE_IF_SENDABLE_RESULT_ASSIGN_OTHERWISE
2646
2653
2647
- #ifdef CAST_WITH_MAYBE_SENDABLE_NONSENDABLE_OP_AND_RESULT
2648
- #error "CAST_WITH_MAYBE_SENDABLE_NONSENDABLE_OP_AND_RESULT already defined"
2654
+ #ifdef LOOKTHROUGH_IF_NONSENDABLE_RESULT_AND_OPERAND
2655
+ #error "LOOKTHROUGH_IF_NONSENDABLE_RESULT_AND_OPERAND already defined"
2649
2656
#endif
2650
2657
2651
- #define CAST_WITH_MAYBE_SENDABLE_NONSENDABLE_OP_AND_RESULT (INST ) \
2658
+ #define LOOKTHROUGH_IF_NONSENDABLE_RESULT_AND_OPERAND (INST ) \
2652
2659
\
2653
2660
TranslationSemantics PartitionOpTranslator::visit##INST(INST *cast) { \
2654
- assert (isLookThroughIfOperandAndResultSendable (cast) && " Out of sync" ); \
2661
+ assert (isLookThroughIfOperandAndResultNonSendable (cast) && " Out of sync" ); \
2655
2662
bool isOperandNonSendable = \
2656
2663
isNonSendableType (cast->getOperand ()->getType ()); \
2657
2664
bool isResultNonSendable = isNonSendableType (cast->getType ()); \
@@ -2670,11 +2677,14 @@ IGNORE_IF_SENDABLE_RESULT_ASSIGN_OTHERWISE(StructExtractInst)
2670
2677
return TranslationSemantics::Ignored; \
2671
2678
}
2672
2679
2673
- CAST_WITH_MAYBE_SENDABLE_NONSENDABLE_OP_AND_RESULT (UncheckedTrivialBitCastInst)
2674
- CAST_WITH_MAYBE_SENDABLE_NONSENDABLE_OP_AND_RESULT(UncheckedBitwiseCastInst)
2675
- CAST_WITH_MAYBE_SENDABLE_NONSENDABLE_OP_AND_RESULT(UncheckedValueCastInst)
2680
+ LOOKTHROUGH_IF_NONSENDABLE_RESULT_AND_OPERAND (UncheckedTrivialBitCastInst)
2681
+ LOOKTHROUGH_IF_NONSENDABLE_RESULT_AND_OPERAND(UncheckedBitwiseCastInst)
2682
+ LOOKTHROUGH_IF_NONSENDABLE_RESULT_AND_OPERAND(UncheckedValueCastInst)
2683
+ LOOKTHROUGH_IF_NONSENDABLE_RESULT_AND_OPERAND(TupleElementAddrInst)
2684
+ LOOKTHROUGH_IF_NONSENDABLE_RESULT_AND_OPERAND(StructElementAddrInst)
2685
+ LOOKTHROUGH_IF_NONSENDABLE_RESULT_AND_OPERAND(UncheckedTakeEnumDataAddrInst)
2676
2686
2677
- #undef CAST_WITH_MAYBE_SENDABLE_NONSENDABLE_OP_AND_RESULT
2687
+ #undef LOOKTHROUGH_IF_NONSENDABLE_RESULT_AND_OPERAND
2678
2688
2679
2689
// ===---
2680
2690
// Custom Handling
@@ -3146,7 +3156,8 @@ bool RegionAnalysisValueMap::isActorDerived(Element trackableValueID) const {
3146
3156
// / may alias.
3147
3157
TrackableValue RegionAnalysisValueMap::getTrackableValue (
3148
3158
SILValue value, bool isAddressCapturedByPartialApply) const {
3149
- value = getUnderlyingTrackedValue (value);
3159
+ auto info = getUnderlyingTrackedValue (value);
3160
+ value = info.value ;
3150
3161
3151
3162
auto *self = const_cast <RegionAnalysisValueMap *>(this );
3152
3163
auto iter = self->equivalenceClassValuesToState .try_emplace (
@@ -3163,6 +3174,12 @@ TrackableValue RegionAnalysisValueMap::getTrackableValue(
3163
3174
3164
3175
// First for addresses.
3165
3176
if (value->getType ().isAddress ()) {
3177
+ // If we were able to find this was actor isolated from finding our
3178
+ // underlying object, use that. It is never wrong.
3179
+ if (info.isActorIsolated ) {
3180
+ iter.first ->getSecond ().addFlag (TrackableValueFlag::isActorDerived);
3181
+ }
3182
+
3166
3183
auto storage = AccessStorageWithBase::compute (value);
3167
3184
if (storage.storage ) {
3168
3185
// Check if we have a uniquely identified address that was not captured
@@ -3214,10 +3231,50 @@ TrackableValue RegionAnalysisValueMap::getTrackableValue(
3214
3231
// mark this value as actor derived.
3215
3232
if (isa<LoadInst, LoadBorrowInst>(iter.first ->first .getValue ())) {
3216
3233
auto *svi = cast<SingleValueInstruction>(iter.first ->first .getValue ());
3234
+
3235
+ // See if we can use get underlying tracked value to find if it is actor
3236
+ // isolated.
3237
+ //
3238
+ // TODO: Instead of using AccessStorageBase, just use our own visitor
3239
+ // everywhere. Just haven't done it due to possible perturbations.
3240
+ auto parentAddrInfo = getUnderlyingTrackedValue (svi);
3241
+ if (parentAddrInfo.isActorIsolated )
3242
+ iter.first ->getSecond ().addFlag (TrackableValueFlag::isActorDerived);
3243
+
3217
3244
auto storage = AccessStorageWithBase::compute (svi->getOperand (0 ));
3218
- if (storage.storage && isa<RefElementAddrInst>(storage.base )) {
3219
- if (storage.storage .getRoot ()->getType ().isActor ()) {
3220
- iter.first ->getSecond ().addFlag (TrackableValueFlag::isActorDerived);
3245
+ if (storage.storage ) {
3246
+ if (isa<RefElementAddrInst>(storage.base )) {
3247
+ if (storage.storage .getRoot ()->getType ().isActor ()) {
3248
+ iter.first ->getSecond ().addFlag (TrackableValueFlag::isActorDerived);
3249
+ }
3250
+ }
3251
+ }
3252
+ }
3253
+
3254
+ // See if we have a struct_extract from a global actor isolated type.
3255
+ if (auto *sei = dyn_cast<StructExtractInst>(iter.first ->first .getValue ())) {
3256
+ if (getActorIsolation (sei->getStructDecl ()).isActorIsolated ()) {
3257
+ iter.first ->getSecond ().addFlag (TrackableValueFlag::isActorDerived);
3258
+ }
3259
+ }
3260
+
3261
+ // See if we have an unchecked_enum_data from a global actor isolated type.
3262
+ if (auto *uedi =
3263
+ dyn_cast<UncheckedEnumDataInst>(iter.first ->first .getValue ())) {
3264
+ if (getActorIsolation (uedi->getEnumDecl ()).isActorIsolated ()) {
3265
+ iter.first ->getSecond ().addFlag (TrackableValueFlag::isActorDerived);
3266
+ }
3267
+ }
3268
+
3269
+ // Handle a switch_enum from a global actor isolated type.
3270
+ if (auto *arg = dyn_cast<SILPhiArgument>(iter.first ->first .getValue ())) {
3271
+ if (auto *singleTerm = arg->getSingleTerminator ()) {
3272
+ if (auto *sei = dyn_cast<SwitchEnumInst>(singleTerm)) {
3273
+ auto enumDecl =
3274
+ sei->getOperand ()->getType ().getEnumOrBoundGenericEnum ();
3275
+ if (getActorIsolation (enumDecl).isActorIsolated ()) {
3276
+ iter.first ->getSecond ().addFlag (TrackableValueFlag::isActorDerived);
3277
+ }
3221
3278
}
3222
3279
}
3223
3280
}
@@ -3266,7 +3323,7 @@ TrackableValue RegionAnalysisValueMap::getActorIntroducingRepresentative(
3266
3323
}
3267
3324
3268
3325
bool RegionAnalysisValueMap::markValueAsActorDerived (SILValue value) {
3269
- value = getUnderlyingTrackedValue (value);
3326
+ value = getUnderlyingTrackedValue (value). value ;
3270
3327
auto iter = equivalenceClassValuesToState.find (value);
3271
3328
if (iter == equivalenceClassValuesToState.end ())
3272
3329
return false ;
0 commit comments