Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[region-isolation] Look through actor isolated, non-Sendable struct_element_addr geps. #73304

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
49 changes: 15 additions & 34 deletions lib/SILOptimizer/Analysis/RegionAnalysis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -156,59 +156,38 @@ struct UseDefChainVisitor
isMerge = true;
break;
case ProjectionKind::Enum: {
// Enum is never a merge since it always has a single tuple field... but
// it can be actor isolated.
if (!bool(actorIsolation)) {
auto *uedi = cast<UncheckedTakeEnumDataAddrInst>(inst);
auto i = getActorIsolation(uedi->getEnumDecl());
// If our operand decl is actor isolated, then we want to stop looking
// through since it is Sendable.
if (i.isActorIsolated()) {
actorIsolation = i;
return SILValue();
}
}
auto op = cast<UncheckedTakeEnumDataAddrInst>(inst)->getOperand();

// See if our operand type is a sendable type. In such a case, we do not
// want to look through our operand.
if (!isNonSendableType(op->getType(), op->getFunction()))
return SILValue();

break;
}
case ProjectionKind::Tuple: {
// These are merges if we have multiple fields.
auto *tti = cast<TupleElementAddrInst>(inst);
auto op = cast<TupleElementAddrInst>(inst)->getOperand();

// See if our result type is a sendable type. In such a case, we do not
// want to look through the tuple_element_addr since we do not want to
// identify the sendable type with the non-sendable operand. These we
// are always going to ignore anyways since a sendable let/var field of
// a struct can always be used.
if (!isNonSendableType(tti->getType(), tti->getFunction()))
if (!isNonSendableType(op->getType(), op->getFunction()))
return SILValue();

isMerge |= tti->getOperand()->getType().getNumTupleElements() > 1;
isMerge |= op->getType().getNumTupleElements() > 1;
break;
}
case ProjectionKind::Struct:
auto *sea = cast<StructElementAddrInst>(inst);

// See if our type is actor isolated.
if (!bool(actorIsolation)) {
auto i = getActorIsolation(sea->getStructDecl());
// If our parent type is actor isolated then we do not want to keep on
// walking up from use->def since the value is considered Sendable.
if (i.isActorIsolated()) {
actorIsolation = i;
return SILValue();
}
}
auto op = cast<StructElementAddrInst>(inst)->getOperand();

// See if our result type is a sendable type. In such a case, we do not
// want to look through the struct_element_addr since we do not want to
// identify the sendable type with the non-sendable operand. These we
// are always going to ignore anyways since a sendable let/var field of
// a struct can always be used.
if (!isNonSendableType(sea->getType(), sea->getFunction()))
if (!isNonSendableType(op->getType(), op->getFunction()))
return SILValue();

// These are merges if we have multiple fields.
isMerge |= sea->getOperand()->getType().getNumNominalFields() > 1;
isMerge |= op->getType().getNumNominalFields() > 1;
break;
}
}
Expand Down Expand Up @@ -1457,6 +1436,8 @@ class PartitionOpTranslator {
LLVM_DEBUG(llvm::dbgs() << " %%" << state->getID() << ": ";
state->print(llvm::dbgs()); llvm::dbgs() << *arg);
nonSendableJoinedIndices.push_back(state->getID());
} else {
LLVM_DEBUG(llvm::dbgs() << " Sendable: " << *arg);
}
}

Expand Down
11 changes: 11 additions & 0 deletions lib/SILOptimizer/Utils/PartitionUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -243,12 +243,23 @@ SILIsolationInfo SILIsolationInfo::get(SILInstruction *inst) {
sei->getStructDecl());
}

if (auto *seai = dyn_cast<StructElementAddrInst>(inst)) {
return SILIsolationInfo::getActorIsolated(seai, SILValue(),
seai->getStructDecl());
}

// See if we have an unchecked_enum_data from a global actor isolated type.
if (auto *uedi = dyn_cast<UncheckedEnumDataInst>(inst)) {
return SILIsolationInfo::getActorIsolated(uedi, SILValue(),
uedi->getEnumDecl());
}

// See if we have an unchecked_enum_data from a global actor isolated type.
if (auto *utedi = dyn_cast<UncheckedTakeEnumDataAddrInst>(inst)) {
return SILIsolationInfo::getActorIsolated(utedi, SILValue(),
utedi->getEnumDecl());
}

// Check if we have an unsafeMutableAddressor from a global actor, mark the
// returned value as being actor derived.
if (auto applySite = dyn_cast<ApplyInst>(inst)) {
Expand Down
25 changes: 25 additions & 0 deletions test/Concurrency/transfernonsendable_global_actor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,31 @@ var booleanFlag: Bool { false }
@MainActor var mainActorIsolatedGlobal = NonSendableKlass()
@CustomActor var customActorIsolatedGlobal = NonSendableKlass()

@MainActor
class NonSendableGlobalActorIsolatedKlass {}

@available(*, unavailable)
extension NonSendableGlobalActorIsolatedKlass: Sendable {}

@MainActor
struct NonSendableGlobalActorIsolatedStruct {
var k = NonSendableKlass()
}

@available(*, unavailable)
extension NonSendableGlobalActorIsolatedStruct: Sendable {}

@MainActor
enum NonSendableGlobalActorIsolatedEnum {
case first
case second(NonSendableKlass)
case third(SendableKlass)
}

@available(*, unavailable)
extension NonSendableGlobalActorIsolatedEnum: Sendable {}


/////////////////
// MARK: Tests //
/////////////////
Expand Down