Skip to content

Commit

Permalink
Merge pull request #73304 from gottesmm/pr-0f53738606af56510a700d55db…
Browse files Browse the repository at this point in the history
…d3a83360da595e

[region-isolation] Look through actor isolated, non-Sendable struct_element_addr geps.
  • Loading branch information
gottesmm committed May 1, 2024
2 parents bbd7863 + 077f62c commit f1539f1
Show file tree
Hide file tree
Showing 4 changed files with 321 additions and 34 deletions.
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

0 comments on commit f1539f1

Please sign in to comment.