Skip to content

Commit a485d97

Browse files
committed
[region-isolation] Allow for unapplied isolated parameter ownership.
Given a function or a partial_apply with an isolated parameter, we do not know immediately what the actual isolation is of the function or partial_apply since we do not know which instance will be applied to the function or partial_apply. In this commit, I introduce a new bit into SILIsolationInfo that tracks this information upon construction and allows for it to merge with ownership that has the appropriate type and a specific instance. Since the values that created the two isolations, will be in the same region this should ensure that the value is only ever in a flow sensitive manner in a region with only one actor instance (since regions with isolations with differing actor instances are illegal). (cherry picked from commit 0c25480)
1 parent e14d3a3 commit a485d97

File tree

3 files changed

+135
-55
lines changed

3 files changed

+135
-55
lines changed

include/swift/SILOptimizer/Utils/SILIsolationInfo.h

Lines changed: 70 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,10 @@ class ActorInstance {
114114
}
115115
};
116116

117+
/// The isolation info inferred for a specific SILValue. Use
118+
/// SILIsolationInfo::get() to compute these. It is intended to be a
119+
/// conservatively correct model that we expand over time with more pattern
120+
/// matching.
117121
class SILIsolationInfo {
118122
public:
119123
/// The lattice is:
@@ -128,6 +132,20 @@ class SILIsolationInfo {
128132
Actor,
129133
};
130134

135+
enum class Flag : uint8_t {
136+
None,
137+
138+
/// If set, this means that the element that we derived this from was marked
139+
/// with nonisolated(unsafe).
140+
UnsafeNonIsolated = 0x1,
141+
142+
/// If set, this means that this actor isolation is from an isolated
143+
/// parameter and should be allowed to merge into a self parameter.
144+
UnappliedIsolatedAnyParameter = 0x2,
145+
};
146+
147+
using Options = OptionSet<Flag>;
148+
131149
private:
132150
/// The actor isolation if this value has one. The default unspecified case
133151
/// otherwise.
@@ -142,13 +160,13 @@ class SILIsolationInfo {
142160
ActorInstance actorInstance;
143161

144162
unsigned kind : 8;
145-
unsigned unsafeNonIsolated : 1;
163+
unsigned options : 8;
146164

147165
SILIsolationInfo(SILValue isolatedValue, SILValue actorInstance,
148-
ActorIsolation actorIsolation, bool isUnsafeNonIsolated)
166+
ActorIsolation actorIsolation, Options options = Options())
149167
: actorIsolation(actorIsolation), isolatedValue(isolatedValue),
150168
actorInstance(ActorInstance::getForValue(actorInstance)), kind(Actor),
151-
unsafeNonIsolated(isUnsafeNonIsolated) {
169+
options(options.toRaw()) {
152170
assert((!actorInstance ||
153171
(actorIsolation.getKind() == ActorIsolation::ActorInstance &&
154172
actorInstance->getType()
@@ -159,24 +177,22 @@ class SILIsolationInfo {
159177
}
160178

161179
SILIsolationInfo(SILValue isolatedValue, ActorInstance actorInstance,
162-
ActorIsolation actorIsolation, bool isUnsafeNonIsolated)
180+
ActorIsolation actorIsolation, Options options = Options())
163181
: actorIsolation(actorIsolation), isolatedValue(isolatedValue),
164-
actorInstance(actorInstance), kind(Actor),
165-
unsafeNonIsolated(isUnsafeNonIsolated) {
182+
actorInstance(actorInstance), kind(Actor), options(options.toRaw()) {
166183
assert(actorInstance);
167184
assert(actorIsolation.getKind() == ActorIsolation::ActorInstance);
168185
}
169186

170187
SILIsolationInfo(Kind kind, SILValue isolatedValue)
171-
: actorIsolation(), isolatedValue(isolatedValue), kind(kind),
172-
unsafeNonIsolated(false) {}
188+
: actorIsolation(), isolatedValue(isolatedValue), kind(kind), options(0) {
189+
}
173190

174-
SILIsolationInfo(Kind kind, bool isUnsafeNonIsolated)
175-
: actorIsolation(), kind(kind), unsafeNonIsolated(isUnsafeNonIsolated) {}
191+
SILIsolationInfo(Kind kind, Options options = Options())
192+
: actorIsolation(), kind(kind), options(options.toRaw()) {}
176193

177194
public:
178-
SILIsolationInfo()
179-
: actorIsolation(), kind(Kind::Unknown), unsafeNonIsolated(false) {}
195+
SILIsolationInfo() : actorIsolation(), kind(Kind::Unknown), options(0) {}
180196

181197
operator bool() const { return kind != Kind::Unknown; }
182198

@@ -188,12 +204,43 @@ class SILIsolationInfo {
188204
bool isActorIsolated() const { return kind == Kind::Actor; }
189205
bool isTaskIsolated() const { return kind == Kind::Task; }
190206

191-
bool isUnsafeNonIsolated() const { return unsafeNonIsolated; }
207+
Options getOptions() const { return Options(options); }
208+
209+
void setOptions(Options newOptions) { options = newOptions.toRaw(); }
210+
211+
bool isUnsafeNonIsolated() const {
212+
return getOptions().contains(Flag::UnsafeNonIsolated);
213+
}
192214

193215
SILIsolationInfo withUnsafeNonIsolated(bool newValue = true) const {
194216
assert(*this && "Cannot be unknown");
195217
auto self = *this;
196-
self.unsafeNonIsolated = newValue;
218+
if (newValue) {
219+
self.options = (self.getOptions() | Flag::UnsafeNonIsolated).toRaw();
220+
} else {
221+
self.options =
222+
self.getOptions().toRaw() & ~Options(Flag::UnsafeNonIsolated).toRaw();
223+
}
224+
return self;
225+
}
226+
227+
/// Returns true if this actor isolation is derived from an unapplied
228+
/// isolation parameter. When merging, we allow for this to be merged with a
229+
/// more specific isolation kind.
230+
bool isUnappliedIsolatedAnyParameter() const {
231+
return getOptions().contains(Flag::UnappliedIsolatedAnyParameter);
232+
}
233+
234+
SILIsolationInfo withUnappliedIsolatedParameter(bool newValue = true) const {
235+
assert(*this && "Cannot be unknown");
236+
auto self = *this;
237+
if (newValue) {
238+
self.options =
239+
(self.getOptions() | Flag::UnappliedIsolatedAnyParameter).toRaw();
240+
} else {
241+
self.options = self.getOptions().toRaw() &
242+
~Options(Flag::UnappliedIsolatedAnyParameter).toRaw();
243+
}
197244
return self;
198245
}
199246

@@ -243,7 +290,8 @@ class SILIsolationInfo {
243290
}
244291

245292
static SILIsolationInfo getDisconnected(bool isUnsafeNonIsolated) {
246-
return {Kind::Disconnected, isUnsafeNonIsolated};
293+
return {Kind::Disconnected,
294+
isUnsafeNonIsolated ? Flag::UnsafeNonIsolated : Flag::None};
247295
}
248296

249297
/// Create an actor isolation for a value that we know is actor isolated to a
@@ -261,7 +309,7 @@ class SILIsolationInfo {
261309
getFlowSensitiveActorIsolated(SILValue isolatedValue,
262310
ActorIsolation actorIsolation) {
263311
return {isolatedValue, SILValue(), actorIsolation,
264-
false /*nonisolated(unsafe)*/};
312+
Flag::UnappliedIsolatedAnyParameter};
265313
}
266314

267315
/// Only use this as a fallback if we cannot find better information.
@@ -270,8 +318,7 @@ class SILIsolationInfo {
270318
if (crossing.getCalleeIsolation().isActorIsolated()) {
271319
// SIL level, just let it through
272320
return SILIsolationInfo(SILValue(), SILValue(),
273-
crossing.getCalleeIsolation(),
274-
false /*nonisolated(unsafe)*/);
321+
crossing.getCalleeIsolation());
275322
}
276323

277324
return {};
@@ -287,8 +334,7 @@ class SILIsolationInfo {
287334
return {};
288335
}
289336
return {isolatedValue, actorInstance,
290-
ActorIsolation::forActorInstanceSelf(typeDecl),
291-
false /*nonisolated(unsafe)*/};
337+
ActorIsolation::forActorInstanceSelf(typeDecl)};
292338
}
293339

294340
static SILIsolationInfo getActorInstanceIsolated(SILValue isolatedValue,
@@ -301,8 +347,7 @@ class SILIsolationInfo {
301347
return {};
302348
}
303349
return {isolatedValue, actorInstance,
304-
ActorIsolation::forActorInstanceSelf(typeDecl),
305-
false /*nonisolated(unsafe)*/};
350+
ActorIsolation::forActorInstanceSelf(typeDecl)};
306351
}
307352

308353
/// A special actor instance isolated for partial apply cases where we do not
@@ -318,14 +363,13 @@ class SILIsolationInfo {
318363
}
319364
return {isolatedValue, SILValue(),
320365
ActorIsolation::forActorInstanceSelf(typeDecl),
321-
false /*nonisolated(unsafe)*/};
366+
Flag::UnappliedIsolatedAnyParameter};
322367
}
323368

324369
static SILIsolationInfo getGlobalActorIsolated(SILValue value,
325370
Type globalActorType) {
326371
return {value, SILValue() /*no actor instance*/,
327-
ActorIsolation::forGlobalActor(globalActorType),
328-
false /*nonisolated(unsafe)*/};
372+
ActorIsolation::forGlobalActor(globalActorType)};
329373
}
330374

331375
static SILIsolationInfo getGlobalActorIsolated(SILValue value,
@@ -395,7 +439,7 @@ class SILDynamicMergedIsolationInfo {
395439

396440
public:
397441
SILDynamicMergedIsolationInfo() : innerInfo() {}
398-
explicit SILDynamicMergedIsolationInfo(SILIsolationInfo innerInfo)
442+
SILDynamicMergedIsolationInfo(SILIsolationInfo innerInfo)
399443
: innerInfo(innerInfo) {}
400444

401445
/// Returns nullptr only if both this isolation info and \p other are actor

lib/SILOptimizer/Analysis/RegionAnalysis.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1633,8 +1633,9 @@ class PartitionOpTranslator {
16331633
if (originalMergedInfo)
16341634
originalMergedInfo->printForDiagnostics(llvm::dbgs());
16351635
else llvm::dbgs() << "nil";
1636-
llvm::dbgs() << "\nValue: "
1636+
llvm::dbgs() << "\nValue Rep: "
16371637
<< value->getRepresentative().getValue();
1638+
llvm::dbgs() << "Original Src: " << src;
16381639
llvm::dbgs() << "Value Info: ";
16391640
value->getIsolationRegionInfo().printForDiagnostics(llvm::dbgs());
16401641
llvm::dbgs() << "\n");

lib/SILOptimizer/Utils/SILIsolationInfo.cpp

Lines changed: 63 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -874,15 +874,38 @@ SILIsolationInfo SILIsolationInfo::get(SILArgument *arg) {
874874
}
875875

876876
void SILIsolationInfo::print(llvm::raw_ostream &os) const {
877+
auto printOptions = [&] {
878+
auto opts = getOptions();
879+
if (!opts)
880+
return;
881+
882+
os << ": ";
883+
884+
std::array<std::pair<Flag, StringLiteral>, 2> data = {
885+
std::make_pair(Flag::UnsafeNonIsolated,
886+
StringLiteral("nonisolated(unsafe)")),
887+
std::make_pair(Flag::UnappliedIsolatedAnyParameter,
888+
StringLiteral("unapplied_isolated_parameter")),
889+
};
890+
891+
llvm::interleave(
892+
data, os,
893+
[&](const std::pair<Flag, StringLiteral> &value) {
894+
opts -= value.first;
895+
os << value.second;
896+
},
897+
", ");
898+
899+
assert(!opts && "Unhandled flag?!");
900+
};
901+
877902
switch (Kind(*this)) {
878903
case Unknown:
879904
os << "unknown";
880905
return;
881906
case Disconnected:
882907
os << "disconnected";
883-
if (unsafeNonIsolated) {
884-
os << ": nonisolated(unsafe)";
885-
}
908+
printOptions();
886909
return;
887910
case Actor:
888911
if (ActorInstance instance = getActorInstance()) {
@@ -891,9 +914,7 @@ void SILIsolationInfo::print(llvm::raw_ostream &os) const {
891914
SILValue value = instance.getValue();
892915
if (auto name = VariableNameInferrer::inferName(value)) {
893916
os << "'" << *name << "'-isolated";
894-
if (unsafeNonIsolated) {
895-
os << ": nonisolated(unsafe)";
896-
}
917+
printOptions();
897918
os << "\n";
898919
os << "instance: " << *value;
899920

@@ -903,9 +924,7 @@ void SILIsolationInfo::print(llvm::raw_ostream &os) const {
903924
}
904925
case ActorInstance::Kind::ActorAccessorInit:
905926
os << "'self'-isolated";
906-
if (unsafeNonIsolated) {
907-
os << ": nonisolated(unsafe)";
908-
}
927+
printOptions();
909928
os << '\n';
910929
os << "instance: actor accessor init\n";
911930
return;
@@ -915,23 +934,17 @@ void SILIsolationInfo::print(llvm::raw_ostream &os) const {
915934
if (getActorIsolation().getKind() == ActorIsolation::ActorInstance) {
916935
if (auto *vd = getActorIsolation().getActorInstance()) {
917936
os << "'" << vd->getBaseIdentifier() << "'-isolated";
918-
if (unsafeNonIsolated) {
919-
os << ": nonisolated(unsafe)";
920-
}
937+
printOptions();
921938
return;
922939
}
923940
}
924941

925942
getActorIsolation().printForDiagnostics(os);
926-
if (unsafeNonIsolated) {
927-
os << ": nonisolated(unsafe)";
928-
}
943+
printOptions();
929944
return;
930945
case Task:
931946
os << "task-isolated";
932-
if (unsafeNonIsolated) {
933-
os << ": nonisolated(unsafe)";
934-
}
947+
printOptions();
935948
os << '\n';
936949
os << "instance: " << *getIsolatedValue();
937950
return;
@@ -958,8 +971,13 @@ bool SILIsolationInfo::hasSameIsolation(const SILIsolationInfo &other) const {
958971
ActorInstance actor1 = getActorInstance();
959972
ActorInstance actor2 = other.getActorInstance();
960973

961-
// If either are non-null, and the actor instance doesn't match, return
962-
// false.
974+
// If either have an actor instance, and the actor instance doesn't match,
975+
// return false.
976+
//
977+
// This ensures that cases like comparing two global actor isolated things
978+
// do not hit this path.
979+
//
980+
// It also catches cases where we have a missing actor instance.
963981
if ((actor1 || actor2) && actor1 != actor2)
964982
return false;
965983

@@ -1053,7 +1071,7 @@ void SILIsolationInfo::printForOneLineLogging(llvm::raw_ostream &os) const {
10531071
return;
10541072
case Disconnected:
10551073
os << "disconnected";
1056-
if (unsafeNonIsolated) {
1074+
if (getOptions().contains(Flag::UnsafeNonIsolated)) {
10571075
os << ": nonisolated(unsafe)";
10581076
}
10591077
return;
@@ -1142,14 +1160,31 @@ std::optional<SILDynamicMergedIsolationInfo>
11421160
SILDynamicMergedIsolationInfo::merge(SILIsolationInfo other) const {
11431161
// If we are greater than the other kind, then we are further along the
11441162
// lattice. We ignore the change.
1145-
if (unsigned(other.getKind()) < unsigned(innerInfo.getKind()))
1163+
if (unsigned(innerInfo.getKind() > unsigned(other.getKind())))
11461164
return {*this};
11471165

1148-
// If we are both actor isolated and our isolations are not
1149-
// compatible... return None.
1150-
if (other.isActorIsolated() && innerInfo.isActorIsolated() &&
1151-
!innerInfo.hasSameIsolation(other))
1166+
// If we are both actor isolated...
1167+
if (innerInfo.isActorIsolated() && other.isActorIsolated()) {
1168+
// If both innerInfo and other have the same isolation, we are obviously
1169+
// done. Just return innerInfo since we could return either.
1170+
if (innerInfo.hasSameIsolation(other))
1171+
return {innerInfo};
1172+
1173+
// Ok, there is some difference in between innerInfo and other. Lets see if
1174+
// they are both actor instance isolated and if either are unapplied
1175+
// isolated any parameter. In such a case, take the one that is further
1176+
// along.
1177+
if (innerInfo.getActorIsolation().isActorInstanceIsolated() &&
1178+
other.getActorIsolation().isActorInstanceIsolated()) {
1179+
if (innerInfo.isUnappliedIsolatedAnyParameter())
1180+
return other;
1181+
if (other.isUnappliedIsolatedAnyParameter())
1182+
return innerInfo;
1183+
}
1184+
1185+
// Otherwise, they do not match... so return None to signal merge failure.
11521186
return {};
1187+
}
11531188

11541189
// If we are both disconnected and other has the unsafeNonIsolated bit set,
11551190
// drop that bit and return that.
@@ -1158,11 +1193,11 @@ SILDynamicMergedIsolationInfo::merge(SILIsolationInfo other) const {
11581193
// merging. These bits should not propagate through merging and should instead
11591194
// always be associated with non-merged infos.
11601195
if (other.isDisconnected() && other.isUnsafeNonIsolated()) {
1161-
return SILDynamicMergedIsolationInfo(other.withUnsafeNonIsolated(false));
1196+
return {other.withUnsafeNonIsolated(false)};
11621197
}
11631198

11641199
// Otherwise, just return other.
1165-
return SILDynamicMergedIsolationInfo(other);
1200+
return {other};
11661201
}
11671202

11681203
//===----------------------------------------------------------------------===//

0 commit comments

Comments
 (0)