Skip to content

Commit 741244e

Browse files
committed
[region-isolation] Split in the type system SILIsolationInfo that has been merged and those that haven't.
Specifically, I introduced a new composition type called SILDynamicMergedIsolationInfo that just contains a SILIsolationInfo. Importantly, whenever one merges a SILIsolationInfo with another SILIsolationInfo, one gets back a SILDynamicMergedIsolationInfo. The reason why I am doing this is that we drop nonisolated(unsafe) when merging so I want to ensure that parts of the code that use merging (where the dropping occurs) and normal SILIsolationInfo where we do not want to merge is distinguished.
1 parent 3a1f58a commit 741244e

File tree

5 files changed

+124
-42
lines changed

5 files changed

+124
-42
lines changed

include/swift/SILOptimizer/Analysis/RegionAnalysis.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,9 @@ class regionanalysisimpl::TrackableValueState {
160160
}
161161

162162
void mergeIsolationRegionInfo(SILIsolationInfo newRegionInfo) {
163-
regionInfo = getIsolationRegionInfo().merge(newRegionInfo);
163+
// TODO: Remove this.
164+
regionInfo =
165+
getIsolationRegionInfo().merge(newRegionInfo).getIsolationInfo();
164166
}
165167

166168
void setDisconnectedNonisolatedUnsafe() {

include/swift/SILOptimizer/Utils/PartitionUtils.h

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,7 @@ struct TransferringOperandState {
342342
/// The dynamic isolation info of the region of value when we transferred.
343343
///
344344
/// This will contain the isolated value if we found one.
345-
SILIsolationInfo isolationInfo;
345+
SILDynamicMergedIsolationInfo isolationInfo;
346346

347347
/// The dynamic isolation history at this point.
348348
IsolationHistory isolationHistory;
@@ -888,17 +888,16 @@ struct PartitionOpEvaluator {
888888
}
889889

890890
/// Call handleTransferNonTransferrable on our CRTP subclass.
891-
void
892-
handleTransferNonTransferrable(const PartitionOp &op, Element elt,
893-
SILIsolationInfo isolationRegionInfo) const {
891+
void handleTransferNonTransferrable(
892+
const PartitionOp &op, Element elt,
893+
SILDynamicMergedIsolationInfo isolationRegionInfo) const {
894894
return asImpl().handleTransferNonTransferrable(op, elt,
895895
isolationRegionInfo);
896896
}
897897
/// Just call our CRTP subclass.
898-
void
899-
handleTransferNonTransferrable(const PartitionOp &op, Element elt,
900-
Element otherElement,
901-
SILIsolationInfo isolationRegionInfo) const {
898+
void handleTransferNonTransferrable(
899+
const PartitionOp &op, Element elt, Element otherElement,
900+
SILDynamicMergedIsolationInfo isolationRegionInfo) const {
902901
return asImpl().handleTransferNonTransferrable(op, elt, otherElement,
903902
isolationRegionInfo);
904903
}
@@ -916,10 +915,10 @@ struct PartitionOpEvaluator {
916915
///
917916
/// The bool result is if it is captured by a closure element. That only is
918917
/// computed if \p sourceOp is non-null.
919-
std::pair<SILIsolationInfo, bool>
918+
std::pair<SILDynamicMergedIsolationInfo, bool>
920919
getIsolationRegionInfo(Region region, Operand *sourceOp) const {
921920
bool isClosureCapturedElt = false;
922-
SILIsolationInfo isolationRegionInfo;
921+
SILDynamicMergedIsolationInfo isolationRegionInfo;
923922

924923
for (const auto &pair : p.range()) {
925924
if (pair.second == region) {
@@ -1039,7 +1038,7 @@ struct PartitionOpEvaluator {
10391038
// dynamic isolation region info found by the dataflow.
10401039
Region transferredRegion = p.getRegion(transferredElement);
10411040
bool isClosureCapturedElt = false;
1042-
SILIsolationInfo transferredRegionIsolation;
1041+
SILDynamicMergedIsolationInfo transferredRegionIsolation;
10431042
std::tie(transferredRegionIsolation, isClosureCapturedElt) =
10441043
getIsolationRegionInfo(transferredRegion, op.getSourceOp());
10451044

@@ -1189,7 +1188,7 @@ struct PartitionOpEvaluator {
11891188
// use have the same isolation.
11901189
void handleTransferNonTransferrableHelper(
11911190
const PartitionOp &op, Element elt,
1192-
SILIsolationInfo dynamicMergedIsolationInfo) const {
1191+
SILDynamicMergedIsolationInfo dynamicMergedIsolationInfo) const {
11931192
if (shouldTryToSquelchErrors()) {
11941193
// If we have a temporary that is initialized with an unsafe nonisolated
11951194
// value... squelch the error like if we were that value.
@@ -1252,13 +1251,13 @@ struct PartitionOpEvaluatorBaseImpl : PartitionOpEvaluator<Subclass> {
12521251

12531252
/// This is called if we detect a never transferred element that was passed to
12541253
/// a transfer instruction.
1255-
void handleTransferNonTransferrable(const PartitionOp &op, Element elt,
1256-
SILIsolationInfo regionInfo) const {}
1254+
void handleTransferNonTransferrable(
1255+
const PartitionOp &op, Element elt,
1256+
SILDynamicMergedIsolationInfo regionInfo) const {}
12571257

1258-
void
1259-
handleTransferNonTransferrable(const PartitionOp &op, Element elt,
1260-
Element otherElement,
1261-
SILIsolationInfo isolationRegionInfo) const {}
1258+
void handleTransferNonTransferrable(
1259+
const PartitionOp &op, Element elt, Element otherElement,
1260+
SILDynamicMergedIsolationInfo isolationRegionInfo) const {}
12621261

12631262
/// This is used to determine if an element is actor derived. If we determine
12641263
/// that a region containing such an element is transferred, we emit an error

include/swift/SILOptimizer/Utils/SILIsolationInfo.h

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,8 @@ class ActorInstance {
102102
}
103103
};
104104

105+
class SILDynamicMergedIsolationInfo;
106+
105107
class SILIsolationInfo {
106108
public:
107109
/// The lattice is:
@@ -230,7 +232,12 @@ class SILIsolationInfo {
230232
return (kind == Task || kind == Actor) && bool(isolatedValue);
231233
}
232234

233-
[[nodiscard]] SILIsolationInfo merge(SILIsolationInfo other) const;
235+
/// Merge this SILIsolationInfo with \p other and produce a
236+
/// SILDynamicMergedIsolationInfo that represents the dynamic isolation of a
237+
/// value found by merging the value's region's isolation info. This causes
238+
/// nonisolated(unsafe) to be dropped.
239+
[[nodiscard]] SILDynamicMergedIsolationInfo
240+
merge(SILIsolationInfo other) const;
234241

235242
static SILIsolationInfo getDisconnected(bool isUnsafeNonIsolated) {
236243
return {Kind::Disconnected, isUnsafeNonIsolated};
@@ -374,6 +381,45 @@ class SILIsolationInfo {
374381
void Profile(llvm::FoldingSetNodeID &id) const;
375382
};
376383

384+
/// A SILIsolationInfo that has gone through merging and represents the dynamic
385+
/// isolation info of a value found by merging its isolation at a region
386+
/// point. This means that nonisolated(unsafe) has been removed. It is used so
387+
/// that in the type system we can distinguish in between isolation info that is
388+
/// static isolation info associated with a value and dynamic isolation info
389+
/// that can just be used for dataflow.
390+
class SILDynamicMergedIsolationInfo {
391+
SILIsolationInfo innerInfo;
392+
393+
public:
394+
SILDynamicMergedIsolationInfo() : innerInfo() {}
395+
SILDynamicMergedIsolationInfo(SILIsolationInfo innerInfo)
396+
: innerInfo(innerInfo) {}
397+
398+
[[nodiscard]] SILDynamicMergedIsolationInfo
399+
merge(SILIsolationInfo other) const;
400+
401+
[[nodiscard]] SILDynamicMergedIsolationInfo
402+
merge(SILDynamicMergedIsolationInfo other) const {
403+
return merge(other.getIsolationInfo());
404+
}
405+
406+
operator bool() const { return bool(innerInfo); }
407+
408+
SILIsolationInfo getIsolationInfo() const { return innerInfo; }
409+
410+
bool isDisconnected() const { return innerInfo.isDisconnected(); }
411+
412+
bool hasSameIsolation(SILIsolationInfo other) const {
413+
return innerInfo.hasSameIsolation(other);
414+
}
415+
416+
SWIFT_DEBUG_DUMP { innerInfo.dump(); }
417+
418+
void printForDiagnostics(llvm::raw_ostream &os) const {
419+
innerInfo.printForDiagnostics(os);
420+
}
421+
};
422+
377423
} // namespace swift
378424

379425
#endif

lib/SILOptimizer/Mandatory/TransferNonSendable.cpp

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -438,17 +438,17 @@ struct TransferredNonTransferrableInfo {
438438
///
439439
/// This is equal to the merge of the IsolationRegionInfo from all elements in
440440
/// nonTransferrable's region when the error was diagnosed.
441-
SILIsolationInfo isolationRegionInfo;
441+
SILDynamicMergedIsolationInfo isolationRegionInfo;
442442

443-
TransferredNonTransferrableInfo(Operand *transferredOperand,
444-
SILValue nonTransferrableValue,
445-
SILIsolationInfo isolationRegionInfo)
443+
TransferredNonTransferrableInfo(
444+
Operand *transferredOperand, SILValue nonTransferrableValue,
445+
SILDynamicMergedIsolationInfo isolationRegionInfo)
446446
: transferredOperand(transferredOperand),
447447
nonTransferrable(nonTransferrableValue),
448448
isolationRegionInfo(isolationRegionInfo) {}
449-
TransferredNonTransferrableInfo(Operand *transferredOperand,
450-
SILInstruction *nonTransferrableInst,
451-
SILIsolationInfo isolationRegionInfo)
449+
TransferredNonTransferrableInfo(
450+
Operand *transferredOperand, SILInstruction *nonTransferrableInst,
451+
SILDynamicMergedIsolationInfo isolationRegionInfo)
452452
: transferredOperand(transferredOperand),
453453
nonTransferrable(nonTransferrableInst),
454454
isolationRegionInfo(isolationRegionInfo) {}
@@ -794,7 +794,7 @@ bool UseAfterTransferDiagnosticInferrer::initForIsolatedPartialApply(
794794
VariableNameInferrer::inferNameAndRoot(transferOp->get())) {
795795
diagnosticEmitter.emitNamedIsolationCrossingDueToCapture(
796796
RegularLocation(std::get<0>(p).getLoc()), rootValueAndName->first,
797-
state.isolationInfo, std::get<2>(p));
797+
state.isolationInfo.getIsolationInfo(), std::get<2>(p));
798798
continue;
799799
}
800800

@@ -975,7 +975,8 @@ void UseAfterTransferDiagnosticInferrer::infer() {
975975
VariableNameInferrer::inferNameAndRoot(transferOp->get())) {
976976
auto &state = transferringOpToStateMap.get(transferOp);
977977
return diagnosticEmitter.emitNamedIsolationCrossingError(
978-
baseLoc, rootValueAndName->first, state.isolationInfo,
978+
baseLoc, rootValueAndName->first,
979+
state.isolationInfo.getIsolationInfo(),
979980
*sourceApply->getIsolationCrossing());
980981
}
981982

@@ -1003,7 +1004,8 @@ void UseAfterTransferDiagnosticInferrer::infer() {
10031004
auto captureInfo =
10041005
autoClosureExpr->getCaptureInfo().getCaptures()[captureIndex];
10051006
auto *captureDecl = captureInfo.getDecl();
1006-
AutoClosureWalker walker(*this, captureDecl, state.isolationInfo);
1007+
AutoClosureWalker walker(*this, captureDecl,
1008+
state.isolationInfo.getIsolationInfo());
10071009
autoClosureExpr->walk(walker);
10081010
}
10091011

@@ -1109,7 +1111,7 @@ class TransferNonTransferrableDiagnosticEmitter {
11091111
}
11101112

11111113
/// Return the isolation region info for \p getNonTransferrableValue().
1112-
SILIsolationInfo getIsolationRegionInfo() const {
1114+
SILDynamicMergedIsolationInfo getIsolationRegionInfo() const {
11131115
return info.isolationRegionInfo;
11141116
}
11151117

@@ -1536,10 +1538,9 @@ struct DiagnosticEvaluator final
15361538
partitionOp.getSourceInst());
15371539
}
15381540

1539-
void
1540-
handleTransferNonTransferrable(const PartitionOp &partitionOp,
1541-
Element transferredVal,
1542-
SILIsolationInfo isolationRegionInfo) const {
1541+
void handleTransferNonTransferrable(
1542+
const PartitionOp &partitionOp, Element transferredVal,
1543+
SILDynamicMergedIsolationInfo isolationRegionInfo) const {
15431544
LLVM_DEBUG(llvm::dbgs()
15441545
<< " Emitting TransferNonTransferrable Error!\n"
15451546
<< " ID: %%" << transferredVal << "\n"
@@ -1556,11 +1557,10 @@ struct DiagnosticEvaluator final
15561557
partitionOp.getSourceOp(), nonTransferrableValue, isolationRegionInfo);
15571558
}
15581559

1559-
void
1560-
handleTransferNonTransferrable(const PartitionOp &partitionOp,
1561-
Element transferredVal,
1562-
Element actualNonTransferrableValue,
1563-
SILIsolationInfo isolationRegionInfo) const {
1560+
void handleTransferNonTransferrable(
1561+
const PartitionOp &partitionOp, Element transferredVal,
1562+
Element actualNonTransferrableValue,
1563+
SILDynamicMergedIsolationInfo isolationRegionInfo) const {
15641564
LLVM_DEBUG(llvm::dbgs()
15651565
<< " Emitting TransferNonTransferrable Error!\n"
15661566
<< " ID: %%" << transferredVal << "\n"

lib/SILOptimizer/Utils/SILIsolationInfo.cpp

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -640,11 +640,12 @@ void SILIsolationInfo::print(llvm::raw_ostream &os) const {
640640
}
641641
}
642642

643-
SILIsolationInfo SILIsolationInfo::merge(SILIsolationInfo other) const {
643+
SILDynamicMergedIsolationInfo
644+
SILIsolationInfo::merge(SILIsolationInfo other) const {
644645
// If we are greater than the other kind, then we are further along the
645646
// lattice. We ignore the change.
646647
if (unsigned(other.kind) < unsigned(kind))
647-
return *this;
648+
return {*this};
648649

649650
// TODO: Make this failing mean that we emit an unknown SIL error instead of
650651
// asserting.
@@ -840,3 +841,37 @@ bool SILIsolationInfo::isNonSendableType(SILType type, SILFunction *fn) {
840841
// Otherwise, delegate to seeing if type conforms to the Sendable protocol.
841842
return !type.isSendable(fn);
842843
}
844+
845+
//===----------------------------------------------------------------------===//
846+
// MARK: SILDynamicMergedIsolationInfo
847+
//===----------------------------------------------------------------------===//
848+
849+
SILDynamicMergedIsolationInfo
850+
SILDynamicMergedIsolationInfo::merge(SILIsolationInfo other) const {
851+
// If we are greater than the other kind, then we are further along the
852+
// lattice. We ignore the change.
853+
if (unsigned(other.getKind()) < unsigned(innerInfo.getKind()))
854+
return {*this};
855+
856+
// TODO: Make this failing mean that we emit an unknown SIL error instead of
857+
// asserting.
858+
assert((!other.isActorIsolated() || !innerInfo.isActorIsolated() ||
859+
innerInfo.hasSameIsolation(other)) &&
860+
"Actor can only be merged with the same actor");
861+
862+
// If we are both disconnected and other has the unsafeNonIsolated bit set,
863+
// drop that bit and return that.
864+
//
865+
// DISCUSSION: We do not want to preserve the unsafe non isolated bit after
866+
// merging. These bits should not propagate through merging and should instead
867+
// always be associated with non-merged infos.
868+
//
869+
// TODO: We should really bake the above into the type system by having merged
870+
// and non-merged SILIsolationInfo.
871+
if (other.isDisconnected() && other.isUnsafeNonIsolated()) {
872+
return other.withUnsafeNonIsolated(false);
873+
}
874+
875+
// Otherwise, just return other.
876+
return other;
877+
}

0 commit comments

Comments
 (0)