Skip to content

Commit 2de13df

Browse files
committed
[region-isolation] Use SILIsolationInfo::initializeTrackableValue instead of SILIsolationInfo::mergeIsolationRegionInfo to fix last issue
When merging SILIsolationInfo for regions, we want to drop nonisolated(unsafe). This is important since nonisolated(unsafe) should only apply to the specific "value" that it belongs to, not the entire region. This creates a problem since in a few places in the code base we initialize a value (producing a disconnected value) and then initialize it by merging in an actor isolation. This no longer work since we will then always have nonisolated(unsafe) stripped, so no values would ever be considered to be nonisolated(unsafe). After analyzing the use case, I realized that these were just initialization patterns and in this commit, I added a specific initialization operation called SILIsolationInfo::initializeTrackableValue and eliminated those calls to SILIsolationInfo::mergeIsolationRegionInfo. Since SILIsolationInfo no longer has any merge operation on it, I then eliminated that code in this commit. This completes the behavior split that I put into the type system in the last commit. Specifically, I defined a composition type called SILDynamicMergedIsolationInfo. It represents a SILIsolationInfo that has been merged... that is why I called it the DynamicMergedIsolationInfo. It could probably use a better name = (. This fixes one of the last weird test case that I wrote where we were not letting through valid nonisolated(unsafe) code. At the same time, I discovered an additional issue (which can be seen in the TODOs in this commit), where we are being too conservative around a non-Sendable class var field. I am going to fix that in the next commit. rdar://128299305
1 parent 1bef011 commit 2de13df

File tree

6 files changed

+143
-99
lines changed

6 files changed

+143
-99
lines changed

include/swift/SILOptimizer/Analysis/RegionAnalysis.h

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -159,12 +159,6 @@ class regionanalysisimpl::TrackableValueState {
159159
return getIsolationRegionInfo().getActorIsolation();
160160
}
161161

162-
void mergeIsolationRegionInfo(SILIsolationInfo newRegionInfo) {
163-
// TODO: Remove this.
164-
regionInfo =
165-
getIsolationRegionInfo().merge(newRegionInfo).getIsolationInfo();
166-
}
167-
168162
void setDisconnectedNonisolatedUnsafe() {
169163
auto oldRegionInfo = getIsolationRegionInfo();
170164
assert(oldRegionInfo.isDisconnected());
@@ -386,9 +380,17 @@ class RegionAnalysisValueMap {
386380
TrackableValue
387381
getActorIntroducingRepresentative(SILInstruction *introducingInst,
388382
SILIsolationInfo isolation) const;
389-
bool mergeIsolationRegionInfo(SILValue value, SILIsolationInfo isolation);
390383
bool valueHasID(SILValue value, bool dumpIfHasNoID = false);
391384
Element lookupValueID(SILValue value);
385+
386+
/// Initialize a TrackableValue with a SILIsolationInfo that we already know
387+
/// instead of inferring.
388+
///
389+
/// If we successfully initialize \p value with \p info, returns
390+
/// {TrackableValue(), true}. If we already had a TrackableValue, we return
391+
/// {TrackableValue(), false}.
392+
std::pair<TrackableValue, bool>
393+
initializeTrackableValue(SILValue value, SILIsolationInfo info) const;
392394
};
393395

394396
class RegionAnalysisFunctionInfo {

include/swift/SILOptimizer/Utils/PartitionUtils.h

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -938,21 +938,24 @@ struct PartitionOpEvaluator {
938938
///
939939
/// The bool result is if it is captured by a closure element. That only is
940940
/// computed if \p sourceOp is non-null.
941-
std::pair<SILDynamicMergedIsolationInfo, bool>
941+
std::optional<std::pair<SILDynamicMergedIsolationInfo, bool>>
942942
getIsolationRegionInfo(Region region, Operand *sourceOp) const {
943943
bool isClosureCapturedElt = false;
944-
SILDynamicMergedIsolationInfo isolationRegionInfo;
944+
std::optional<SILDynamicMergedIsolationInfo> isolationRegionInfo =
945+
SILDynamicMergedIsolationInfo();
945946

946947
for (const auto &pair : p.range()) {
947948
if (pair.second == region) {
948949
isolationRegionInfo =
949-
isolationRegionInfo.merge(getIsolationRegionInfo(pair.first));
950+
isolationRegionInfo->merge(getIsolationRegionInfo(pair.first));
951+
if (!isolationRegionInfo)
952+
return {};
950953
if (sourceOp)
951954
isClosureCapturedElt |= isClosureCaptured(pair.first, sourceOp);
952955
}
953956
}
954957

955-
return {isolationRegionInfo, isClosureCapturedElt};
958+
return {{isolationRegionInfo.value(), isClosureCapturedElt}};
956959
}
957960

958961
/// Overload of \p getIsolationRegionInfo without an Operand.
@@ -1062,8 +1065,13 @@ struct PartitionOpEvaluator {
10621065
Region transferredRegion = p.getRegion(transferredElement);
10631066
bool isClosureCapturedElt = false;
10641067
SILDynamicMergedIsolationInfo transferredRegionIsolation;
1065-
std::tie(transferredRegionIsolation, isClosureCapturedElt) =
1068+
auto pairOpt =
10661069
getIsolationRegionInfo(transferredRegion, op.getSourceOp());
1070+
if (!pairOpt) {
1071+
handleUnknownCodePattern(op);
1072+
return;
1073+
}
1074+
std::tie(transferredRegionIsolation, isClosureCapturedElt) = *pairOpt;
10671075

10681076
// Before we do anything, see if our dynamic isolation kind is the same as
10691077
// the isolation info for our partition op. If they match, this is not a
@@ -1089,8 +1097,12 @@ struct PartitionOpEvaluator {
10891097
// Mark op.getOpArgs()[0] as transferred.
10901098
TransferringOperandState &state = operandToStateMap.get(op.getSourceOp());
10911099
state.isClosureCaptured |= isClosureCapturedElt;
1092-
state.isolationInfo =
1093-
state.isolationInfo.merge(transferredRegionIsolation);
1100+
if (auto newInfo =
1101+
state.isolationInfo.merge(transferredRegionIsolation)) {
1102+
state.isolationInfo = *newInfo;
1103+
} else {
1104+
handleUnknownCodePattern(op);
1105+
}
10941106
assert(state.isolationInfo && "Cannot have unknown");
10951107
state.isolationHistory.pushCFGHistoryJoin(p.getIsolationHistory());
10961108
auto *ptrSet = ptrSetFactory.get(op.getSourceOp());

include/swift/SILOptimizer/Utils/SILIsolationInfo.h

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

105-
class SILDynamicMergedIsolationInfo;
106-
107105
class SILIsolationInfo {
108106
public:
109107
/// The lattice is:
@@ -232,13 +230,6 @@ class SILIsolationInfo {
232230
return (kind == Task || kind == Actor) && bool(isolatedValue);
233231
}
234232

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;
241-
242233
static SILIsolationInfo getDisconnected(bool isUnsafeNonIsolated) {
243234
return {Kind::Disconnected, isUnsafeNonIsolated};
244235
}
@@ -395,10 +386,12 @@ class SILDynamicMergedIsolationInfo {
395386
SILDynamicMergedIsolationInfo(SILIsolationInfo innerInfo)
396387
: innerInfo(innerInfo) {}
397388

398-
[[nodiscard]] SILDynamicMergedIsolationInfo
389+
/// Returns nullptr only if both this isolation info and \p other are actor
390+
/// isolated to incompatible actors.
391+
[[nodiscard]] std::optional<SILDynamicMergedIsolationInfo>
399392
merge(SILIsolationInfo other) const;
400393

401-
[[nodiscard]] SILDynamicMergedIsolationInfo
394+
[[nodiscard]] std::optional<SILDynamicMergedIsolationInfo>
402395
merge(SILDynamicMergedIsolationInfo other) const {
403396
return merge(other.getIsolationInfo());
404397
}

lib/SILOptimizer/Analysis/RegionAnalysis.cpp

Lines changed: 60 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1500,18 +1500,30 @@ class PartitionOpTranslator {
15001500
return valueMap.tryToTrackValue(value);
15011501
}
15021502

1503+
/// If \p value already has state associated with it, return that. Otherwise
1504+
/// begin tracking \p value and initialize its isolation info to be \p.
1505+
///
1506+
/// This is in contrast to tryToTrackValue which infers isolation
1507+
/// information. This should only be used in exceptional cases when one 100%
1508+
/// knows what the isolation is already. E.x.: a partial_apply.
1509+
std::optional<std::pair<TrackableValue, bool>>
1510+
initializeTrackedValue(SILValue value, SILIsolationInfo info) const {
1511+
auto trackedValuePair = valueMap.initializeTrackableValue(value, info);
1512+
if (trackedValuePair.first.isNonSendable()) {
1513+
assert(trackedValuePair.second);
1514+
return trackedValuePair;
1515+
}
1516+
assert(trackedValuePair.second);
1517+
return {};
1518+
}
1519+
15031520
TrackableValue
15041521
getActorIntroducingRepresentative(SILInstruction *introducingInst,
15051522
SILIsolationInfo actorIsolation) const {
15061523
return valueMap.getActorIntroducingRepresentative(introducingInst,
15071524
actorIsolation);
15081525
}
15091526

1510-
bool mergeIsolationRegionInfo(SILValue value,
1511-
SILIsolationInfo isolationRegion) {
1512-
return valueMap.mergeIsolationRegionInfo(value, isolationRegion);
1513-
}
1514-
15151527
bool valueHasID(SILValue value, bool dumpIfHasNoID = false) {
15161528
return valueMap.valueHasID(value, dumpIfHasNoID);
15171529
}
@@ -1542,9 +1554,6 @@ class PartitionOpTranslator {
15421554
if (tryApplyInst->getErrorBB()->getNumArguments() > 0) {
15431555
foundResults.emplace_back(tryApplyInst->getErrorBB()->getArgument(0));
15441556
}
1545-
for (auto indirectResults : tryApplyInst->getIndirectSILResults()) {
1546-
foundResults.emplace_back(indirectResults);
1547-
}
15481557
return;
15491558
}
15501559

@@ -1568,11 +1577,20 @@ class PartitionOpTranslator {
15681577
}
15691578

15701579
for (SILValue result : resultValues) {
1571-
if (auto value = tryToTrackValue(result)) {
1572-
assignResults.push_back(value->getRepresentative().getValue());
1573-
// TODO: Can we pass back a reference to value perhaps?
1574-
if (isolationInfo) {
1575-
mergeIsolationRegionInfo(result, isolationInfo);
1580+
if (isolationInfo) {
1581+
// We only get back result if it is non-Sendable.
1582+
if (auto nonSendableValue =
1583+
initializeTrackedValue(result, isolationInfo)) {
1584+
if (!nonSendableValue->second) {
1585+
builder.addUnknownPatternError(result);
1586+
continue;
1587+
}
1588+
assignResults.push_back(
1589+
nonSendableValue->first.getRepresentative().getValue());
1590+
}
1591+
} else {
1592+
if (auto value = tryToTrackValue(result)) {
1593+
assignResults.push_back(value->getRepresentative().getValue());
15761594
}
15771595
}
15781596
}
@@ -1741,10 +1759,12 @@ class PartitionOpTranslator {
17411759
if (pai->getFunctionType()->isSendable())
17421760
return;
17431761

1744-
auto paiValue = tryToTrackValue(pai).value();
1745-
SILValue rep = paiValue.getRepresentative().getValue();
1746-
mergeIsolationRegionInfo(rep, actorIsolation);
1747-
translateSILAssignFresh(rep);
1762+
auto trackedValue = initializeTrackedValue(pai, actorIsolation);
1763+
assert(trackedValue && "Should not have happened already");
1764+
assert(
1765+
trackedValue->second &&
1766+
"Insert should have happened since this could not happen before this");
1767+
translateSILAssignFresh(trackedValue->first.getRepresentative().getValue());
17481768
}
17491769

17501770
void translateSILPartialApply(PartialApplyInst *pai) {
@@ -3258,6 +3278,27 @@ RegionAnalysisValueMap::getIsolationRegion(SILValue value) const {
32583278
return iter->getSecond().getIsolationRegionInfo();
32593279
}
32603280

3281+
std::pair<TrackableValue, bool>
3282+
RegionAnalysisValueMap::initializeTrackableValue(
3283+
SILValue value, SILIsolationInfo newInfo) const {
3284+
auto info = getUnderlyingTrackedValue(value);
3285+
value = info.value;
3286+
3287+
auto *self = const_cast<RegionAnalysisValueMap *>(this);
3288+
auto iter = self->equivalenceClassValuesToState.try_emplace(
3289+
value, TrackableValueState(equivalenceClassValuesToState.size()));
3290+
3291+
// If we did not insert, just return the already stored value.
3292+
if (!iter.second) {
3293+
return {{iter.first->first, iter.first->second}, false};
3294+
}
3295+
3296+
self->stateIndexToEquivalenceClass[iter.first->second.getID()] = value;
3297+
iter.first->getSecond().setIsolationRegionInfo(newInfo);
3298+
3299+
return {{iter.first->first, iter.first->second}, true};
3300+
}
3301+
32613302
/// If \p isAddressCapturedByPartialApply is set to true, then this value is
32623303
/// an address that is captured by a partial_apply and we want to treat it as
32633304
/// may alias.
@@ -3275,6 +3316,7 @@ TrackableValue RegionAnalysisValueMap::getTrackableValue(
32753316
return {iter.first->first, iter.first->second};
32763317
}
32773318

3319+
// If we did not insert, just return the already stored value.
32783320
self->stateIndexToEquivalenceClass[iter.first->second.getID()] = value;
32793321

32803322
// Otherwise, we need to compute our flags.
@@ -3409,20 +3451,10 @@ TrackableValue RegionAnalysisValueMap::getActorIntroducingRepresentative(
34093451
// Otherwise, wire up the value.
34103452
self->stateIndexToEquivalenceClass[iter.first->second.getID()] =
34113453
introducingInst;
3412-
iter.first->getSecond().mergeIsolationRegionInfo(actorIsolation);
3454+
iter.first->getSecond().setIsolationRegionInfo(actorIsolation);
34133455
return {iter.first->first, iter.first->second};
34143456
}
34153457

3416-
bool RegionAnalysisValueMap::mergeIsolationRegionInfo(
3417-
SILValue value, SILIsolationInfo actorIsolation) {
3418-
value = getUnderlyingTrackedValue(value).value;
3419-
auto iter = equivalenceClassValuesToState.find(value);
3420-
if (iter == equivalenceClassValuesToState.end())
3421-
return false;
3422-
iter->getSecond().mergeIsolationRegionInfo(actorIsolation);
3423-
return true;
3424-
}
3425-
34263458
bool RegionAnalysisValueMap::valueHasID(SILValue value, bool dumpIfHasNoID) {
34273459
assert(getTrackableValue(value).isNonSendable() &&
34283460
"Can only accept non-Sendable values");

lib/SILOptimizer/Utils/SILIsolationInfo.cpp

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

643-
SILDynamicMergedIsolationInfo
644-
SILIsolationInfo::merge(SILIsolationInfo other) const {
645-
// If we are greater than the other kind, then we are further along the
646-
// lattice. We ignore the change.
647-
if (unsigned(other.kind) < unsigned(kind))
648-
return {*this};
649-
650-
// TODO: Make this failing mean that we emit an unknown SIL error instead of
651-
// asserting.
652-
assert((!other.isActorIsolated() || !isActorIsolated() ||
653-
hasSameIsolation(other)) &&
654-
"Actor can only be merged with the same actor");
655-
656-
// If we are both disconnected and other has the unsafeNonIsolated bit set,
657-
// drop that bit and return that.
658-
//
659-
// DISCUSSION: We do not want to preserve the unsafe non isolated bit after
660-
// merging. These bits should not propagate through merging and should instead
661-
// always be associated with non-merged infos.
662-
//
663-
// TODO: We should really bake the above into the type system by having merged
664-
// and non-merged SILIsolationInfo.
665-
if (other.isDisconnected() && other.isUnsafeNonIsolated()) {
666-
return other.withUnsafeNonIsolated(false);
667-
}
668-
669-
// Otherwise, just return other.
670-
return other;
671-
}
672-
673643
bool SILIsolationInfo::hasSameIsolation(ActorIsolation actorIsolation) const {
674644
if (getKind() != Kind::Actor)
675645
return false;
@@ -846,28 +816,25 @@ bool SILIsolationInfo::isNonSendableType(SILType type, SILFunction *fn) {
846816
// MARK: SILDynamicMergedIsolationInfo
847817
//===----------------------------------------------------------------------===//
848818

849-
SILDynamicMergedIsolationInfo
819+
std::optional<SILDynamicMergedIsolationInfo>
850820
SILDynamicMergedIsolationInfo::merge(SILIsolationInfo other) const {
851821
// If we are greater than the other kind, then we are further along the
852822
// lattice. We ignore the change.
853823
if (unsigned(other.getKind()) < unsigned(innerInfo.getKind()))
854824
return {*this};
855825

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");
826+
// If we are both actor isolated and our isolations are not
827+
// compatible... return None.
828+
if (other.isActorIsolated() && innerInfo.isActorIsolated() &&
829+
!innerInfo.hasSameIsolation(other))
830+
return {};
861831

862832
// If we are both disconnected and other has the unsafeNonIsolated bit set,
863833
// drop that bit and return that.
864834
//
865835
// DISCUSSION: We do not want to preserve the unsafe non isolated bit after
866836
// merging. These bits should not propagate through merging and should instead
867837
// 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.
871838
if (other.isDisconnected() && other.isUnsafeNonIsolated()) {
872839
return other.withUnsafeNonIsolated(false);
873840
}

0 commit comments

Comments
 (0)