Skip to content

Commit 8baf40a

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. (cherry picked from commit 741244e)
1 parent 51e59d3 commit 8baf40a

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)