Skip to content

Commit 41609ff

Browse files
committed
[region-isolation] When inferring isolation for an argument, handle non-self isolated parameters as well as self parameters that are actor isolated.
As part of this I went through how we handled inference and rather than using a grab-bag getActorIsolation that was confusing to use, I created split APIs for specific use cases (actor instance, global actor, just an apply expr crossing) that makes it clearer inside the SILIsolationInfo::get* APIs what we are actually trying to model. I found a few issues as a result and fixed most of them if they were small. I also fixed one bigger one around computed property initializers in the next commit. There is a larger change I didn't fix around allowing function ref/partial_apply with isolated self parameters have a delayed flow sensitive actor isolation... this will be fixed in a subsequent commit. This also fixes a bunch of cases where we were printing actor-isolated instead of 'self' isolated. rdar://127295657 (cherry picked from commit 50c2d67)
1 parent e241344 commit 41609ff

12 files changed

+387
-147
lines changed

include/swift/SILOptimizer/Analysis/RegionAnalysis.h

Lines changed: 0 additions & 21 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>

include/swift/SILOptimizer/Utils/PartitionUtils.h

Lines changed: 79 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -124,8 +124,8 @@ class SILIsolationInfo {
124124
/// derived isolatedValue from.
125125
SILValue actorInstance;
126126

127-
SILIsolationInfo(ActorIsolation actorIsolation, SILValue isolatedValue,
128-
SILValue actorInstance)
127+
SILIsolationInfo(SILValue isolatedValue, SILValue actorInstance,
128+
ActorIsolation actorIsolation)
129129
: kind(Actor), actorIsolation(actorIsolation),
130130
isolatedValue(isolatedValue), actorInstance(actorInstance) {
131131
assert((!actorInstance ||
@@ -193,37 +193,78 @@ class SILIsolationInfo {
193193

194194
[[nodiscard]] SILIsolationInfo merge(SILIsolationInfo other) const;
195195

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

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};
198+
/// Create an actor isolation for a value that we know is actor isolated to a
199+
/// specific actor, but we do not know the specific instance yet.
200+
///
201+
/// This can occur when closing over a closure with an isolated parameter or
202+
/// if we are determining isolation of a function_ref that takes an isolated
203+
/// parameter. In both cases, we cannot know what the actual isolation is
204+
/// until we invoke the closure or function.
205+
///
206+
/// TODO: This is just a stub currently until I implement the flow sensitive
207+
/// part. We just treat all instances the same. There are tests that validate
208+
/// this behavior.
209+
static SILIsolationInfo
210+
getFlowSensitiveActorIsolated(SILValue isolatedValue,
211+
ActorIsolation actorIsolation) {
212+
return {isolatedValue, SILValue(), actorIsolation};
213+
}
214+
215+
/// Only use this as a fallback if we cannot find better information.
216+
static SILIsolationInfo
217+
getWithIsolationCrossing(ApplyIsolationCrossing crossing) {
218+
if (crossing.getCalleeIsolation().isActorIsolated()) {
219+
// SIL level, just let it through
220+
return SILIsolationInfo(SILValue(), SILValue(),
221+
crossing.getCalleeIsolation());
222+
}
223+
220224
return {};
221225
}
222226

227+
static SILIsolationInfo getActorInstanceIsolated(SILValue isolatedValue,
228+
SILValue actorInstance,
229+
NominalTypeDecl *typeDecl) {
230+
assert(actorInstance);
231+
if (!typeDecl->isAnyActor()) {
232+
assert(!swift::getActorIsolation(typeDecl).isGlobalActor() &&
233+
"Should have called getGlobalActorIsolated");
234+
return {};
235+
}
236+
return {isolatedValue, actorInstance,
237+
ActorIsolation::forActorInstanceSelf(typeDecl)};
238+
}
239+
240+
/// A special actor instance isolated for partial apply cases where we do not
241+
/// close over the isolated parameter and thus do not know the actual actor
242+
/// instance that we are going to use.
243+
static SILIsolationInfo
244+
getPartialApplyActorInstanceIsolated(SILValue isolatedValue,
245+
NominalTypeDecl *typeDecl) {
246+
if (!typeDecl->isAnyActor()) {
247+
assert(!swift::getActorIsolation(typeDecl).isGlobalActor() &&
248+
"Should have called getGlobalActorIsolated");
249+
return {};
250+
}
251+
return {isolatedValue, SILValue(),
252+
ActorIsolation::forActorInstanceSelf(typeDecl)};
253+
}
254+
223255
static SILIsolationInfo getGlobalActorIsolated(SILValue value,
224256
Type globalActorType) {
225-
return getActorIsolated(value, SILValue() /*no actor instance*/,
226-
ActorIsolation::forGlobalActor(globalActorType));
257+
return {value, SILValue() /*no actor instance*/,
258+
ActorIsolation::forGlobalActor(globalActorType)};
259+
}
260+
261+
static SILIsolationInfo getGlobalActorIsolated(SILValue value,
262+
ValueDecl *decl) {
263+
auto isolation = swift::getActorIsolation(decl);
264+
if (!isolation.isGlobalActor())
265+
return {};
266+
return SILIsolationInfo::getGlobalActorIsolated(value,
267+
isolation.getGlobalActor());
227268
}
228269

229270
static SILIsolationInfo getTaskIsolated(SILValue value) {
@@ -244,6 +285,18 @@ class SILIsolationInfo {
244285
return {};
245286
}
246287

288+
/// A helper that is used to ensure that we treat certain builtin values as
289+
/// non-Sendable that the AST level otherwise thinks are non-Sendable.
290+
///
291+
/// E.x.: Builtin.RawPointer and Builtin.NativeObject
292+
///
293+
/// TODO: Fix the type checker.
294+
static bool isNonSendableType(SILType type, SILFunction *fn);
295+
296+
static bool isNonSendableType(SILValue value) {
297+
return isNonSendableType(value->getType(), value->getFunction());
298+
}
299+
247300
bool hasSameIsolation(ActorIsolation actorIsolation) const;
248301

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

lib/SILOptimizer/Analysis/RegionAnalysis.cpp

Lines changed: 33 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,8 @@ struct UseDefChainVisitor
124124
// If this is a type case, see if the result of the cast is sendable. In
125125
// such a case, we do not want to look through this cast.
126126
if (castType == AccessStorageCast::Type &&
127-
!isNonSendableType(cast->getType(), cast->getFunction()))
127+
!SILIsolationInfo::isNonSendableType(cast->getType(),
128+
cast->getFunction()))
128129
return SILValue();
129130

130131
// If we do not have an identity cast, mark this as a merge.
@@ -160,7 +161,8 @@ struct UseDefChainVisitor
160161

161162
// See if our operand type is a sendable type. In such a case, we do not
162163
// want to look through our operand.
163-
if (!isNonSendableType(op->getType(), op->getFunction()))
164+
if (!SILIsolationInfo::isNonSendableType(op->getType(),
165+
op->getFunction()))
164166
return SILValue();
165167

166168
break;
@@ -169,7 +171,8 @@ struct UseDefChainVisitor
169171
// These are merges if we have multiple fields.
170172
auto op = cast<TupleElementAddrInst>(inst)->getOperand();
171173

172-
if (!isNonSendableType(op->getType(), op->getFunction()))
174+
if (!SILIsolationInfo::isNonSendableType(op->getType(),
175+
op->getFunction()))
173176
return SILValue();
174177

175178
isMerge |= op->getType().getNumTupleElements() > 1;
@@ -183,7 +186,8 @@ struct UseDefChainVisitor
183186
// identify the sendable type with the non-sendable operand. These we
184187
// are always going to ignore anyways since a sendable let/var field of
185188
// a struct can always be used.
186-
if (!isNonSendableType(op->getType(), op->getFunction()))
189+
if (!SILIsolationInfo::isNonSendableType(op->getType(),
190+
op->getFunction()))
187191
return SILValue();
188192

189193
// These are merges if we have multiple fields.
@@ -314,21 +318,23 @@ static SILValue getUnderlyingTrackedObjectValue(SILValue value) {
314318
// If we have a cast and our operand and result are non-Sendable, treat it
315319
// as a look through.
316320
if (isLookThroughIfOperandAndResultNonSendable(svi)) {
317-
if (isNonSendableType(svi->getType(), fn) &&
318-
isNonSendableType(svi->getOperand(0)->getType(), fn)) {
321+
if (SILIsolationInfo::isNonSendableType(svi->getType(), fn) &&
322+
SILIsolationInfo::isNonSendableType(svi->getOperand(0)->getType(),
323+
fn)) {
319324
temp = svi->getOperand(0);
320325
}
321326
}
322327

323328
if (isLookThroughIfResultNonSendable(svi)) {
324-
if (isNonSendableType(svi->getType(), fn)) {
329+
if (SILIsolationInfo::isNonSendableType(svi->getType(), fn)) {
325330
temp = svi->getOperand(0);
326331
}
327332
}
328333

329334
if (isLookThroughIfOperandNonSendable(svi)) {
330335
// If our operand is a non-Sendable type, look through this instruction.
331-
if (isNonSendableType(svi->getOperand(0)->getType(), fn)) {
336+
if (SILIsolationInfo::isNonSendableType(svi->getOperand(0)->getType(),
337+
fn)) {
332338
temp = svi->getOperand(0);
333339
}
334340
}
@@ -1464,7 +1470,7 @@ class PartitionOpTranslator {
14641470
/// NOTE: We special case RawPointer and NativeObject to ensure they are
14651471
/// treated as non-Sendable and strict checking is applied to it.
14661472
bool isNonSendableType(SILType type) const {
1467-
return ::isNonSendableType(type, function);
1473+
return SILIsolationInfo::isNonSendableType(type, function);
14681474
}
14691475

14701476
TrackableValue
@@ -2221,7 +2227,8 @@ class PartitionOpTranslator {
22212227
case TranslationSemantics::AssertingIfNonSendable:
22222228
// Do not error if all of our operands are sendable.
22232229
if (llvm::none_of(inst->getOperandValues(), [&](SILValue value) {
2224-
return ::isNonSendableType(value->getType(), inst->getFunction());
2230+
return ::SILIsolationInfo::isNonSendableType(value->getType(),
2231+
inst->getFunction());
22252232
}))
22262233
return;
22272234
llvm::errs() << "BadInst: " << *inst;
@@ -3241,11 +3248,18 @@ TrackableValue RegionAnalysisValueMap::getTrackableValue(
32413248
// If we were able to find this was actor isolated from finding our
32423249
// underlying object, use that. It is never wrong.
32433250
if (info.actorIsolation) {
3244-
SILValue actorInstance =
3245-
info.value->getType().isAnyActor() ? info.value : SILValue();
3246-
iter.first->getSecond().mergeIsolationRegionInfo(
3247-
SILIsolationInfo::getActorIsolated(value, actorInstance,
3248-
*info.actorIsolation));
3251+
SILIsolationInfo isolation;
3252+
if (info.value->getType().isAnyActor()) {
3253+
isolation = SILIsolationInfo::getActorInstanceIsolated(
3254+
value, info.value, info.actorIsolation->getActor());
3255+
} else if (info.actorIsolation->isGlobalActor()) {
3256+
isolation = SILIsolationInfo::getGlobalActorIsolated(
3257+
value, info.actorIsolation->getGlobalActor());
3258+
}
3259+
3260+
if (isolation) {
3261+
iter.first->getSecond().mergeIsolationRegionInfo(isolation);
3262+
}
32493263
}
32503264

32513265
auto storage = AccessStorageWithBase::compute(value);
@@ -3277,7 +3291,7 @@ TrackableValue RegionAnalysisValueMap::getTrackableValue(
32773291
}
32783292

32793293
// Otherwise refer to the oracle. If we have a Sendable value, just return.
3280-
if (!isNonSendableType(value->getType(), fn)) {
3294+
if (!SILIsolationInfo::isNonSendableType(value->getType(), fn)) {
32813295
iter.first->getSecond().addFlag(TrackableValueFlag::isSendable);
32823296
return {iter.first->first, iter.first->second};
32833297
}
@@ -3295,8 +3309,9 @@ TrackableValue RegionAnalysisValueMap::getTrackableValue(
32953309
auto parentAddrInfo = getUnderlyingTrackedValue(svi);
32963310
if (parentAddrInfo.actorIsolation) {
32973311
iter.first->getSecond().mergeIsolationRegionInfo(
3298-
SILIsolationInfo::getActorIsolated(svi, parentAddrInfo.value,
3299-
*parentAddrInfo.actorIsolation));
3312+
SILIsolationInfo::getActorInstanceIsolated(
3313+
svi, parentAddrInfo.value,
3314+
parentAddrInfo.actorIsolation->getActor()));
33003315
}
33013316

33023317
auto storage = AccessStorageWithBase::compute(svi->getOperand(0));

lib/SILOptimizer/Mandatory/TransferNonSendable.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1466,8 +1466,8 @@ struct DiagnosticEvaluator final
14661466
if (auto *svi =
14671467
dyn_cast<SingleValueInstruction>(partitionOp.getSourceInst())) {
14681468
if (isa<TupleElementAddrInst, StructElementAddrInst>(svi) &&
1469-
!regionanalysisimpl::isNonSendableType(svi->getType(),
1470-
svi->getFunction())) {
1469+
!SILIsolationInfo::isNonSendableType(svi->getType(),
1470+
svi->getFunction())) {
14711471
bool isCapture = operandState.isClosureCaptured;
14721472
if (!isCapture) {
14731473
return;

0 commit comments

Comments
 (0)