Skip to content

Commit 4789cc7

Browse files
authored
Merge pull request #73556 from gottesmm/rdar127295657_127844737
[region-isolation] When inferring isolation for an argument, handle non-self isolated parameters as well as self parameters that are actor isolated.
2 parents 15cab3a + 4aea60c commit 4789cc7

19 files changed

+737
-205
lines changed

docs/SIL.rst

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -692,6 +692,18 @@ autorelease in the callee.
692692
type behaves like a non-generic type, as if the substitutions were
693693
actually applied to the underlying function type.
694694

695+
- SIL functions may optionally mark a function parameter as
696+
``@sil_isolated``. An ``@sil_isolated`` parameter must be one of:
697+
698+
- An actor or any actor type.
699+
- A generic type that conforms to Actor or AnyActor.
700+
701+
and must be the actor instance that a function is isolated to. Importantly
702+
this means that global actor isolated nominal types are never
703+
``@sil_isolated``. Only one parameter can ever be marked as ``@sil_isolated``
704+
since a function cannot be isolated to multiple actors at the same time.
705+
706+
695707
Async Functions
696708
```````````````
697709

include/swift/AST/ActorIsolation.h

Lines changed: 6 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,8 @@ class ActorIsolation {
205205
return getKind() == GlobalActor;
206206
}
207207

208+
bool isActorInstanceIsolated() const { return getKind() == ActorInstance; }
209+
208210
bool isMainActor() const;
209211

210212
bool isDistributedActor() const;
@@ -262,37 +264,14 @@ class ActorIsolation {
262264
state.parameterIndex);
263265
}
264266

265-
void print(llvm::raw_ostream &os) const {
266-
switch (getKind()) {
267-
case Unspecified:
268-
os << "unspecified";
269-
return;
270-
case ActorInstance:
271-
os << "actor_instance";
272-
return;
273-
case Nonisolated:
274-
os << "nonisolated";
275-
return;
276-
case NonisolatedUnsafe:
277-
os << "nonisolated_unsafe";
278-
return;
279-
case GlobalActor:
280-
os << "global_actor";
281-
return;
282-
case Erased:
283-
os << "erased";
284-
return;
285-
}
286-
llvm_unreachable("Covered switch isn't covered?!");
287-
}
267+
void print(llvm::raw_ostream &os) const;
268+
269+
void printForSIL(llvm::raw_ostream &os) const;
288270

289271
void printForDiagnostics(llvm::raw_ostream &os,
290272
StringRef openingQuotationMark = "'") const;
291273

292-
SWIFT_DEBUG_DUMP {
293-
print(llvm::dbgs());
294-
llvm::dbgs() << '\n';
295-
}
274+
SWIFT_DEBUG_DUMPER(dump());
296275

297276
// Defined out of line to prevent linker errors since libswiftBasic would
298277
// include this header exascerbating a layering violation where libswiftBasic

include/swift/SIL/SILFunction.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1551,6 +1551,17 @@ class SILFunction
15511551
return getArguments().back();
15521552
}
15531553

1554+
/// If we have an isolated argument, return that. Returns nullptr otherwise.
1555+
const SILArgument *maybeGetIsolatedArgument() const {
1556+
for (auto *arg : getArgumentsWithoutIndirectResults()) {
1557+
if (cast<SILFunctionArgument>(arg)->getKnownParameterInfo().hasOption(
1558+
SILParameterInfo::Isolated))
1559+
return arg;
1560+
}
1561+
1562+
return nullptr;
1563+
}
1564+
15541565
const SILArgument *getDynamicSelfMetadata() const {
15551566
assert(hasDynamicSelfMetadata() && "This method can only be called if the "
15561567
"SILFunction has a self-metadata parameter");

include/swift/SILOptimizer/Analysis/RegionAnalysis.h

Lines changed: 4 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -31,27 +31,6 @@ using TransferringOperandSetFactory = Partition::TransferringOperandSetFactory;
3131
using Element = PartitionPrimitives::Element;
3232
using Region = PartitionPrimitives::Region;
3333

34-
/// Check if the passed in type is NonSendable.
35-
///
36-
/// NOTE: We special case RawPointer and NativeObject to ensure they are
37-
/// treated as non-Sendable and strict checking is applied to it.
38-
inline bool isNonSendableType(SILType type, SILFunction *fn) {
39-
// Treat Builtin.NativeObject and Builtin.RawPointer as non-Sendable.
40-
if (type.getASTType()->is<BuiltinNativeObjectType>() ||
41-
type.getASTType()->is<BuiltinRawPointerType>()) {
42-
return true;
43-
}
44-
45-
// Treat Builtin.SILToken as Sendable. It cannot escape from the current
46-
// function. We should change isSendable to hardwire this.
47-
if (type.getASTType()->is<SILTokenType>()) {
48-
return false;
49-
}
50-
51-
// Otherwise, delegate to seeing if type conforms to the Sendable protocol.
52-
return !type.isSendable(fn);
53-
}
54-
5534
/// Return the ApplyIsolationCrossing for a specific \p inst if it
5635
/// exists. Returns std::nullopt otherwise.
5736
std::optional<ApplyIsolationCrossing>
@@ -305,7 +284,10 @@ class regionanalysisimpl::TrackableValue {
305284
os << "\n Rep Value: " << getRepresentative();
306285
}
307286

308-
SWIFT_DEBUG_DUMP { print(llvm::dbgs()); }
287+
SWIFT_DEBUG_DUMP {
288+
print(llvm::dbgs());
289+
llvm::dbgs() << '\n';
290+
}
309291
};
310292

311293
class RegionAnalysis;

include/swift/SILOptimizer/Utils/PartitionUtils.h

Lines changed: 165 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,65 @@ struct DenseMapInfo<swift::PartitionPrimitives::Region> {
9595

9696
namespace swift {
9797

98+
class ActorInstance {
99+
public:
100+
enum class Kind : uint8_t {
101+
Value,
102+
ActorAccessorInit = 0x1,
103+
};
104+
105+
llvm::PointerIntPair<SILValue, 1> value;
106+
107+
ActorInstance(SILValue value, Kind kind)
108+
: value(value, std::underlying_type<Kind>::type(kind)) {}
109+
110+
public:
111+
ActorInstance() : ActorInstance(SILValue(), Kind::Value) {}
112+
113+
static ActorInstance getForValue(SILValue value) {
114+
return ActorInstance(value, Kind::Value);
115+
}
116+
117+
static ActorInstance getForActorAccessorInit() {
118+
return ActorInstance(SILValue(), Kind::ActorAccessorInit);
119+
}
120+
121+
explicit operator bool() const { return bool(value.getOpaqueValue()); }
122+
123+
Kind getKind() const { return Kind(value.getInt()); }
124+
125+
SILValue getValue() const {
126+
assert(getKind() == Kind::Value);
127+
return value.getPointer();
128+
}
129+
130+
bool isValue() const { return getKind() == Kind::Value; }
131+
132+
bool isAccessorInit() const { return getKind() == Kind::ActorAccessorInit; }
133+
134+
bool operator==(const ActorInstance &other) const {
135+
// If both are null, return true.
136+
if (!bool(*this) && !bool(other))
137+
return true;
138+
139+
// Otherwise, check if the kinds match.
140+
if (getKind() != other.getKind())
141+
return false;
142+
143+
// Now that we know that the kinds match, perform the kind specific check.
144+
switch (getKind()) {
145+
case Kind::Value:
146+
return getValue() == other.getValue();
147+
case Kind::ActorAccessorInit:
148+
return true;
149+
}
150+
}
151+
152+
bool operator!=(const ActorInstance &other) const {
153+
return !(*this == other);
154+
}
155+
};
156+
98157
class SILIsolationInfo {
99158
public:
100159
/// The lattice is:
@@ -122,18 +181,29 @@ class SILIsolationInfo {
122181

123182
/// If set this is the SILValue that represents the actor instance that we
124183
/// derived isolatedValue from.
125-
SILValue actorInstance;
184+
///
185+
/// If set to (SILValue(), 1), then we are in an
186+
ActorInstance actorInstance;
126187

127-
SILIsolationInfo(ActorIsolation actorIsolation, SILValue isolatedValue,
128-
SILValue actorInstance)
188+
SILIsolationInfo(SILValue isolatedValue, SILValue actorInstance,
189+
ActorIsolation actorIsolation)
129190
: kind(Actor), actorIsolation(actorIsolation),
130-
isolatedValue(isolatedValue), actorInstance(actorInstance) {
191+
isolatedValue(isolatedValue),
192+
actorInstance(ActorInstance::getForValue(actorInstance)) {
131193
assert((!actorInstance ||
132194
(actorIsolation.getKind() == ActorIsolation::ActorInstance &&
133195
actorInstance->getType().isAnyActor())) &&
134196
"actorInstance must be an actor if it is non-empty");
135197
}
136198

199+
SILIsolationInfo(SILValue isolatedValue, ActorInstance actorInstance,
200+
ActorIsolation actorIsolation)
201+
: kind(Actor), actorIsolation(actorIsolation),
202+
isolatedValue(isolatedValue), actorInstance(actorInstance) {
203+
assert(actorInstance);
204+
assert(actorIsolation.getKind() == ActorIsolation::ActorInstance);
205+
}
206+
137207
SILIsolationInfo(Kind kind, SILValue isolatedValue)
138208
: kind(kind), actorIsolation(), isolatedValue(isolatedValue) {}
139209

@@ -180,7 +250,7 @@ class SILIsolationInfo {
180250

181251
/// Return the specific SILValue for the actor that our isolated value is
182252
/// isolated to if one exists.
183-
SILValue getActorInstance() const {
253+
ActorInstance getActorInstance() const {
184254
assert(kind == Actor);
185255
return actorInstance;
186256
}
@@ -193,37 +263,91 @@ class SILIsolationInfo {
193263

194264
[[nodiscard]] SILIsolationInfo merge(SILIsolationInfo other) const;
195265

196-
SILIsolationInfo withActorIsolated(SILValue isolatedValue,
197-
SILValue actorInstance,
198-
ActorIsolation isolation) {
199-
return SILIsolationInfo::getActorIsolated(isolatedValue, actorInstance,
200-
isolation);
201-
}
202-
203266
static SILIsolationInfo getDisconnected() { return {Kind::Disconnected}; }
204267

205-
static SILIsolationInfo getActorIsolated(SILValue isolatedValue,
206-
SILValue actorInstance,
207-
ActorIsolation actorIsolation) {
208-
return {actorIsolation, isolatedValue, actorInstance};
209-
}
210-
211-
static SILIsolationInfo getActorIsolated(SILValue isolatedValue,
212-
SILValue actorInstance,
213-
NominalTypeDecl *typeDecl) {
214-
if (typeDecl->isAnyActor())
215-
return {ActorIsolation::forActorInstanceSelf(typeDecl), isolatedValue,
216-
actorInstance};
217-
auto isolation = swift::getActorIsolation(typeDecl);
218-
if (isolation.isGlobalActor())
219-
return {isolation, isolatedValue, actorInstance};
268+
/// Create an actor isolation for a value that we know is actor isolated to a
269+
/// specific actor, but we do not know the specific instance yet.
270+
///
271+
/// This can occur when closing over a closure with an isolated parameter or
272+
/// if we are determining isolation of a function_ref that takes an isolated
273+
/// parameter. In both cases, we cannot know what the actual isolation is
274+
/// until we invoke the closure or function.
275+
///
276+
/// TODO: This is just a stub currently until I implement the flow sensitive
277+
/// part. We just treat all instances the same. There are tests that validate
278+
/// this behavior.
279+
static SILIsolationInfo
280+
getFlowSensitiveActorIsolated(SILValue isolatedValue,
281+
ActorIsolation actorIsolation) {
282+
return {isolatedValue, SILValue(), actorIsolation};
283+
}
284+
285+
/// Only use this as a fallback if we cannot find better information.
286+
static SILIsolationInfo
287+
getWithIsolationCrossing(ApplyIsolationCrossing crossing) {
288+
if (crossing.getCalleeIsolation().isActorIsolated()) {
289+
// SIL level, just let it through
290+
return SILIsolationInfo(SILValue(), SILValue(),
291+
crossing.getCalleeIsolation());
292+
}
293+
220294
return {};
221295
}
222296

297+
static SILIsolationInfo getActorInstanceIsolated(SILValue isolatedValue,
298+
SILValue actorInstance,
299+
NominalTypeDecl *typeDecl) {
300+
assert(actorInstance);
301+
if (!typeDecl->isAnyActor()) {
302+
assert(!swift::getActorIsolation(typeDecl).isGlobalActor() &&
303+
"Should have called getGlobalActorIsolated");
304+
return {};
305+
}
306+
return {isolatedValue, actorInstance,
307+
ActorIsolation::forActorInstanceSelf(typeDecl)};
308+
}
309+
310+
static SILIsolationInfo getActorInstanceIsolated(SILValue isolatedValue,
311+
ActorInstance actorInstance,
312+
NominalTypeDecl *typeDecl) {
313+
assert(actorInstance);
314+
if (!typeDecl->isAnyActor()) {
315+
assert(!swift::getActorIsolation(typeDecl).isGlobalActor() &&
316+
"Should have called getGlobalActorIsolated");
317+
return {};
318+
}
319+
return {isolatedValue, actorInstance,
320+
ActorIsolation::forActorInstanceSelf(typeDecl)};
321+
}
322+
323+
/// A special actor instance isolated for partial apply cases where we do not
324+
/// close over the isolated parameter and thus do not know the actual actor
325+
/// instance that we are going to use.
326+
static SILIsolationInfo
327+
getPartialApplyActorInstanceIsolated(SILValue isolatedValue,
328+
NominalTypeDecl *typeDecl) {
329+
if (!typeDecl->isAnyActor()) {
330+
assert(!swift::getActorIsolation(typeDecl).isGlobalActor() &&
331+
"Should have called getGlobalActorIsolated");
332+
return {};
333+
}
334+
return {isolatedValue, SILValue(),
335+
ActorIsolation::forActorInstanceSelf(typeDecl)};
336+
}
337+
223338
static SILIsolationInfo getGlobalActorIsolated(SILValue value,
224339
Type globalActorType) {
225-
return getActorIsolated(value, SILValue() /*no actor instance*/,
226-
ActorIsolation::forGlobalActor(globalActorType));
340+
return {value, SILValue() /*no actor instance*/,
341+
ActorIsolation::forGlobalActor(globalActorType)};
342+
}
343+
344+
static SILIsolationInfo getGlobalActorIsolated(SILValue value,
345+
ValueDecl *decl) {
346+
auto isolation = swift::getActorIsolation(decl);
347+
if (!isolation.isGlobalActor())
348+
return {};
349+
return SILIsolationInfo::getGlobalActorIsolated(value,
350+
isolation.getGlobalActor());
227351
}
228352

229353
static SILIsolationInfo getTaskIsolated(SILValue value) {
@@ -244,6 +368,18 @@ class SILIsolationInfo {
244368
return {};
245369
}
246370

371+
/// A helper that is used to ensure that we treat certain builtin values as
372+
/// non-Sendable that the AST level otherwise thinks are non-Sendable.
373+
///
374+
/// E.x.: Builtin.RawPointer and Builtin.NativeObject
375+
///
376+
/// TODO: Fix the type checker.
377+
static bool isNonSendableType(SILType type, SILFunction *fn);
378+
379+
static bool isNonSendableType(SILValue value) {
380+
return isNonSendableType(value->getType(), value->getFunction());
381+
}
382+
247383
bool hasSameIsolation(ActorIsolation actorIsolation) const;
248384

249385
/// Returns true if \p this and \p other have the same isolation. It allows

0 commit comments

Comments
 (0)