@@ -69,10 +69,27 @@ static bool isIsolationBoundaryCrossingApply(SILInstruction *inst) {
6969
7070namespace {
7171
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+
7285struct UseDefChainVisitor
7386 : public AccessUseDefChainVisitor<UseDefChainVisitor, SILValue> {
7487 bool isMerge = false ;
7588
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+
7693 SILValue visitAll (SILValue sourceAddr) {
7794 SILValue result = visit (sourceAddr);
7895 if (!result)
@@ -142,9 +159,21 @@ struct UseDefChainVisitor
142159 // Index is always a merge.
143160 isMerge = true ;
144161 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+ }
147175 break ;
176+ }
148177 case ProjectionKind::Tuple: {
149178 // These are merges if we have multiple fields.
150179 auto *tti = cast<TupleElementAddrInst>(inst);
@@ -163,6 +192,17 @@ struct UseDefChainVisitor
163192 case ProjectionKind::Struct:
164193 auto *sea = cast<StructElementAddrInst>(inst);
165194
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+
166206 // See if our result type is a sendable type. In such a case, we do not
167207 // want to look through the struct_element_addr since we do not want to
168208 // identify the sendable type with the non-sendable operand. These we
@@ -248,8 +288,6 @@ static bool isLookThroughIfResultNonSendable(SILInstruction *inst) {
248288 switch (inst->getKind ()) {
249289 default :
250290 return false ;
251- case SILInstructionKind::TupleElementAddrInst:
252- case SILInstructionKind::StructElementAddrInst:
253291 case SILInstructionKind::RawPointerToRefInst:
254292 return true ;
255293 }
@@ -264,13 +302,16 @@ static bool isLookThroughIfOperandNonSendable(SILInstruction *inst) {
264302 }
265303}
266304
267- static bool isLookThroughIfOperandAndResultSendable (SILInstruction *inst) {
305+ static bool isLookThroughIfOperandAndResultNonSendable (SILInstruction *inst) {
268306 switch (inst->getKind ()) {
269307 default :
270308 return false ;
271309 case SILInstructionKind::UncheckedTrivialBitCastInst:
272310 case SILInstructionKind::UncheckedBitwiseCastInst:
273311 case SILInstructionKind::UncheckedValueCastInst:
312+ case SILInstructionKind::StructElementAddrInst:
313+ case SILInstructionKind::TupleElementAddrInst:
314+ case SILInstructionKind::UncheckedTakeEnumDataAddrInst:
274315 return true ;
275316 }
276317}
@@ -293,7 +334,7 @@ static SILValue getUnderlyingTrackedObjectValue(SILValue value) {
293334
294335 // If we have a cast and our operand and result are non-Sendable, treat it
295336 // as a look through.
296- if (isLookThroughIfOperandAndResultSendable (svi)) {
337+ if (isLookThroughIfOperandAndResultNonSendable (svi)) {
297338 if (isNonSendableType (svi->getType (), fn) &&
298339 isNonSendableType (svi->getOperand (0 )->getType (), fn)) {
299340 temp = svi->getOperand (0 );
@@ -329,21 +370,21 @@ static SILValue getUnderlyingTrackedObjectValue(SILValue value) {
329370 }
330371}
331372
332- static SILValue getUnderlyingTrackedValue (SILValue value) {
373+ static UnderlyingTrackedValueInfo getUnderlyingTrackedValue (SILValue value) {
333374 if (!value->getType ().isAddress ()) {
334- return getUnderlyingTrackedObjectValue (value);
375+ return UnderlyingTrackedValueInfo ( getUnderlyingTrackedObjectValue (value) );
335376 }
336377
337378 UseDefChainVisitor visitor;
338379 SILValue base = visitor.visitAll (value);
339380 assert (base);
340381 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 ()} ;
343384}
344385
345386SILValue RegionAnalysisFunctionInfo::getUnderlyingTrackedValue (SILValue value) {
346- return ::getUnderlyingTrackedValue (value);
387+ return ::getUnderlyingTrackedValue (value). value ;
347388}
348389
349390namespace {
@@ -650,7 +691,7 @@ struct PartialApplyReachabilityDataflow {
650691
651692private:
652693 SILValue getRootValue (SILValue value) const {
653- return getUnderlyingTrackedValue (value);
694+ return getUnderlyingTrackedValue (value). value ;
654695 }
655696
656697 unsigned getBitForValue (SILValue value) const {
@@ -2150,7 +2191,7 @@ class PartitionOpTranslator {
21502191 assert ((isStaticallyLookThroughInst (inst) ||
21512192 isLookThroughIfResultNonSendable (inst) ||
21522193 isLookThroughIfOperandNonSendable (inst) ||
2153- isLookThroughIfOperandAndResultSendable (inst)) &&
2194+ isLookThroughIfOperandAndResultNonSendable (inst)) &&
21542195 " Out of sync... should return true for one of these categories!" );
21552196 return translateSILLookThrough (inst->getResults (), inst->getOperand (0 ));
21562197
@@ -2379,7 +2420,6 @@ CONSTANT_TRANSLATION(EndInitLetRefInst, LookThrough)
23792420CONSTANT_TRANSLATION(InitEnumDataAddrInst, LookThrough)
23802421CONSTANT_TRANSLATION(OpenExistentialAddrInst, LookThrough)
23812422CONSTANT_TRANSLATION(UncheckedRefCastInst, LookThrough)
2382- CONSTANT_TRANSLATION(UncheckedTakeEnumDataAddrInst, LookThrough)
23832423CONSTANT_TRANSLATION(UpcastInst, LookThrough)
23842424CONSTANT_TRANSLATION(MoveValueInst, LookThrough)
23852425CONSTANT_TRANSLATION(MarkUnresolvedNonCopyableValueInst, LookThrough)
@@ -2598,39 +2638,6 @@ CONSTANT_TRANSLATION(VectorInst, Asserting)
25982638
25992639#undef CONSTANT_TRANSLATION
26002640
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-
26342641#define IGNORE_IF_SENDABLE_RESULT_ASSIGN_OTHERWISE (INST ) \
26352642 TranslationSemantics PartitionOpTranslator::visit##INST(INST *inst) { \
26362643 if (!isNonSendableType (inst->getType ())) { \
@@ -2644,14 +2651,14 @@ IGNORE_IF_SENDABLE_RESULT_ASSIGN_OTHERWISE(StructExtractInst)
26442651
26452652#undef IGNORE_IF_SENDABLE_RESULT_ASSIGN_OTHERWISE
26462653
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"
26492656#endif
26502657
2651- #define CAST_WITH_MAYBE_SENDABLE_NONSENDABLE_OP_AND_RESULT (INST ) \
2658+ #define LOOKTHROUGH_IF_NONSENDABLE_RESULT_AND_OPERAND (INST ) \
26522659 \
26532660 TranslationSemantics PartitionOpTranslator::visit##INST(INST *cast) { \
2654- assert (isLookThroughIfOperandAndResultSendable (cast) && " Out of sync" ); \
2661+ assert (isLookThroughIfOperandAndResultNonSendable (cast) && " Out of sync" ); \
26552662 bool isOperandNonSendable = \
26562663 isNonSendableType (cast->getOperand ()->getType ()); \
26572664 bool isResultNonSendable = isNonSendableType (cast->getType ()); \
@@ -2670,11 +2677,14 @@ IGNORE_IF_SENDABLE_RESULT_ASSIGN_OTHERWISE(StructExtractInst)
26702677 return TranslationSemantics::Ignored; \
26712678 }
26722679
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)
26762686
2677- #undef CAST_WITH_MAYBE_SENDABLE_NONSENDABLE_OP_AND_RESULT
2687+ #undef LOOKTHROUGH_IF_NONSENDABLE_RESULT_AND_OPERAND
26782688
26792689// ===---
26802690// Custom Handling
@@ -3146,7 +3156,8 @@ bool RegionAnalysisValueMap::isActorDerived(Element trackableValueID) const {
31463156// / may alias.
31473157TrackableValue RegionAnalysisValueMap::getTrackableValue (
31483158 SILValue value, bool isAddressCapturedByPartialApply) const {
3149- value = getUnderlyingTrackedValue (value);
3159+ auto info = getUnderlyingTrackedValue (value);
3160+ value = info.value ;
31503161
31513162 auto *self = const_cast <RegionAnalysisValueMap *>(this );
31523163 auto iter = self->equivalenceClassValuesToState .try_emplace (
@@ -3163,6 +3174,12 @@ TrackableValue RegionAnalysisValueMap::getTrackableValue(
31633174
31643175 // First for addresses.
31653176 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+
31663183 auto storage = AccessStorageWithBase::compute (value);
31673184 if (storage.storage ) {
31683185 // Check if we have a uniquely identified address that was not captured
@@ -3214,10 +3231,50 @@ TrackableValue RegionAnalysisValueMap::getTrackableValue(
32143231 // mark this value as actor derived.
32153232 if (isa<LoadInst, LoadBorrowInst>(iter.first ->first .getValue ())) {
32163233 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+
32173244 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+ }
32213278 }
32223279 }
32233280 }
@@ -3266,7 +3323,7 @@ TrackableValue RegionAnalysisValueMap::getActorIntroducingRepresentative(
32663323}
32673324
32683325bool RegionAnalysisValueMap::markValueAsActorDerived (SILValue value) {
3269- value = getUnderlyingTrackedValue (value);
3326+ value = getUnderlyingTrackedValue (value). value ;
32703327 auto iter = equivalenceClassValuesToState.find (value);
32713328 if (iter == equivalenceClassValuesToState.end ())
32723329 return false ;
0 commit comments