Skip to content

Commit b23bc82

Browse files
authored
Merge pull request #71574 from rjmccall/isolation-any-sil-irgen
SIL and IRGen support for `@isolated(any)` function types
2 parents eeeb8c3 + d514266 commit b23bc82

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

65 files changed

+697
-109
lines changed

docs/ABI/Mangling.rst

+3-1
Original file line numberDiff line numberDiff line change
@@ -734,14 +734,16 @@ mangled in to disambiguate.
734734
impl-function-type ::= type* 'I' FUNC-ATTRIBUTES '_'
735735
impl-function-type ::= type* generic-signature 'I' FUNC-ATTRIBUTES '_'
736736

737-
FUNC-ATTRIBUTES ::= PATTERN-SUBS? INVOCATION-SUBS? PSEUDO-GENERIC? CALLEE-ESCAPE? DIFFERENTIABILITY-KIND? CALLEE-CONVENTION FUNC-REPRESENTATION? COROUTINE-KIND? SENDABLE? ASYNC? (PARAM-CONVENTION PARAM-DIFFERENTIABILITY?)* RESULT-CONVENTION* ('Y' PARAM-CONVENTION)* ('z' RESULT-CONVENTION RESULT-DIFFERENTIABILITY?)?
737+
FUNC-ATTRIBUTES ::= PATTERN-SUBS? INVOCATION-SUBS? PSEUDO-GENERIC? CALLEE-ESCAPE? ISOLATION? DIFFERENTIABILITY-KIND? CALLEE-CONVENTION FUNC-REPRESENTATION? COROUTINE-KIND? SENDABLE? ASYNC? (PARAM-CONVENTION PARAM-DIFFERENTIABILITY?)* RESULT-CONVENTION* ('Y' PARAM-CONVENTION)* ('z' RESULT-CONVENTION RESULT-DIFFERENTIABILITY?)?
738738

739739
PATTERN-SUBS ::= 's' // has pattern substitutions
740740
INVOCATION-SUB ::= 'I' // has invocation substitutions
741741
PSEUDO-GENERIC ::= 'P'
742742

743743
CALLEE-ESCAPE ::= 'e' // @escaping (inverse of SIL @noescape)
744744

745+
ISOLATION ::= 'A' // @isolated(any)
746+
745747
DIFFERENTIABILITY-KIND ::= 'd' // @differentiable
746748
DIFFERENTIABILITY-KIND ::= 'l' // @differentiable(_linear)
747749
DIFFERENTIABILITY-KIND ::= 'f' // @differentiable(_forward)

docs/SIL.rst

+44-7
Original file line numberDiff line numberDiff line change
@@ -459,6 +459,20 @@ number of ways:
459459
- Other function type conventions are described in ``Properties of Types`` and
460460
``Calling Convention``.
461461

462+
- SIL function types do not directly carry most of the actor-isolation
463+
information available in the Swift type system. Actor isolation is mostly
464+
simply erased from the SIL type system and treated as a dynamic property
465+
in SIL functions.
466+
467+
However, ``@isolated(any)`` requires some additional ABI support and
468+
therefore must be carried on SIL function types. ``@isolated(any)`` is
469+
only allowed in combination with ``@convention(thick)``; in particular,
470+
this precludes SIL function declarations from having ``@isolated(any)``
471+
type. Instead, ``@isolated(any)`` function values are constructed with
472+
``partial_apply [isolated_any]``, which has additional requirements.
473+
The isolation of an ``@isolated(any)`` function can be read with the
474+
``function_extract_isolation`` instruction.
475+
462476
- A SIL function type declares the conventions for its parameters.
463477
The parameters are written as an unlabeled tuple; the elements of that
464478
tuple must be legal SIL types, optionally decorated with one of the
@@ -6118,12 +6132,13 @@ partial_apply
61186132
`````````````
61196133
::
61206134

6121-
sil-instruction ::= 'partial_apply' callee-ownership-attr? on-stack-attr? sil-value
6135+
sil-instruction ::= 'partial_apply' partial-apply-attr* sil-value
61226136
sil-apply-substitution-list?
61236137
'(' (sil-value (',' sil-value)*)? ')'
61246138
':' sil-type
6125-
callee-ownership-attr ::= '[callee_guaranteed]'
6126-
on-stack-attr ::= '[on_stack]'
6139+
partial-apply-attr ::= '[callee_guaranteed]'
6140+
partial-apply-attr ::= '[isolated_any]'
6141+
partial-apply-attr ::= '[on_stack]'
61276142

61286143
%c = partial_apply %0(%1, %2, ...) : $(Z..., A, B, ...) -> R
61296144
// Note that the type of the callee '%0' is specified *after* the arguments
@@ -6179,13 +6194,24 @@ lowers to an uncurried entry point and is curried in the enclosing function::
61796194
return %ret : $Int
61806195
}
61816196

6197+
**Erased Isolation**: If the ``partial_apply`` is marked with the flag
6198+
``[isolated_any]``, the first applied argument must have type
6199+
``Optional<any Actor>``. In addition to being provided as an argument to
6200+
the partially-applied function, this value will be stored in a special
6201+
place in the context and can be recovered with ``function_extract_isolation``.
6202+
The result type of the ``partial_apply`` will be an ``@isolated(any)``
6203+
function type.
6204+
61826205
**Ownership Semantics of Closure Context during Invocation**: By default, an
61836206
escaping ``partial_apply`` (``partial_apply`` without ``[on_stack]]`` creates a
61846207
closure whose invocation takes ownership of the context, meaning that a call
6185-
implicitly releases the closure. If the ``partial_apply`` is marked with the
6186-
flag ``[callee_guaranteed]`` the invocation instead uses a caller-guaranteed
6187-
model, where the caller promises not to release the closure while the function
6188-
is being called.
6208+
implicitly releases the closure.
6209+
6210+
If the ``partial_apply`` is marked with the flag ``[callee_guaranteed]``,
6211+
the invocation instead uses a caller-guaranteed model, where the caller
6212+
promises not to release the closure while the function is being called.
6213+
The result type of the ``partial_apply`` will be a ``@callee_guaranteed``
6214+
function type.
61896215

61906216
**Captured Value Ownership Semantics**: In the instruction syntax, the type of
61916217
the callee is specified after the argument list; the types of the argument and
@@ -6581,6 +6607,17 @@ autorelease_value
65816607

65826608
*TODO* Complete this section.
65836609

6610+
function_extract_isolation
6611+
``````````````````````````
6612+
6613+
::
6614+
sil-instruction ::= function_extract_isolation sil-operand
6615+
6616+
Reads the isolation of a `@isolated(any)` function value. The result is
6617+
always a borrowed value of type `$Optional<any Actor>`. It is exactly
6618+
the value that was originally used to construct the function with
6619+
`partial_apply [isolated_any]`.
6620+
65846621
tuple
65856622
`````
65866623
::

include/swift/AST/ASTSynthesis.h

+19
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ enum SingletonTypeSynthesizer {
5151
_word,
5252
_serialExecutor, // the '_Concurrency.SerialExecutor' protocol
5353
_taskExecutor, // the '_Concurrency.TaskExecutor' protocol
54+
_actor, // the '_Concurrency.Actor' protocol
5455
};
5556
inline Type synthesizeType(SynthesisContext &SC,
5657
SingletonTypeSynthesizer kind) {
@@ -73,6 +74,9 @@ inline Type synthesizeType(SynthesisContext &SC,
7374
case _taskExecutor:
7475
return SC.Context.getProtocol(KnownProtocolKind::TaskExecutor)
7576
->getDeclaredInterfaceType();
77+
case _actor:
78+
return SC.Context.getProtocol(KnownProtocolKind::Actor)
79+
->getDeclaredInterfaceType();
7680
}
7781
}
7882

@@ -119,6 +123,21 @@ Type synthesizeType(SynthesisContext &SC,
119123
return MetatypeType::get(synthesizeType(SC, M.Sub));
120124
}
121125

126+
/// A synthesizer which generates an existential type from a requirement type.
127+
template <class S>
128+
struct ExistentialTypeSynthesizer {
129+
S Sub;
130+
};
131+
template <class S>
132+
constexpr ExistentialTypeSynthesizer<S> _existential(S sub) {
133+
return {sub};
134+
}
135+
template <class S>
136+
Type synthesizeType(SynthesisContext &SC,
137+
const ExistentialTypeSynthesizer<S> &M) {
138+
return ExistentialType::get(synthesizeType(SC, M.Sub));
139+
}
140+
122141
/// A synthesizer which generates an existential metatype type.
123142
template <class S>
124143
struct ExistentialMetatypeTypeSynthesizer {

include/swift/AST/Builtins.def

+7
Original file line numberDiff line numberDiff line change
@@ -1068,6 +1068,13 @@ BUILTIN_MISC_OPERATION_WITH_SILGEN(BuildDefaultActorExecutorRef,
10681068
BUILTIN_MISC_OPERATION_WITH_SILGEN(BuildMainActorExecutorRef,
10691069
"buildMainActorExecutorRef", "n", Special)
10701070

1071+
/// extractFunctionIsolation: <T>(_: T) -> (any Actor)?
1072+
///
1073+
/// Returns the isolation of a value, which must be an @isolated(any)
1074+
/// function type.
1075+
BUILTIN_MISC_OPERATION_WITH_SILGEN(ExtractFunctionIsolation,
1076+
"extractFunctionIsolation", "", Special)
1077+
10711078
/// getEnumTag: <T>(_: T) -> Builtin.Int32
10721079
///
10731080
/// Given a dynamic generic value, unsafely assume it is an enum type and call

include/swift/AST/DiagnosticsSIL.def

+5
Original file line numberDiff line numberDiff line change
@@ -744,6 +744,11 @@ ERROR(polymorphic_builtin_passed_type_without_static_overload, none, "Static"
744744
"overload implied by passing argument of type %2",
745745
(Identifier, StringRef, Type))
746746

747+
ERROR(builtin_get_function_isolation_bad_argument, none,
748+
"argument to 'extractFunctionIsolation' must have '@isolated(any)' "
749+
"function type",
750+
())
751+
747752
ERROR(box_to_stack_cannot_promote_box_to_stack_due_to_escape_alloc, none,
748753
"Can not promote value from heap to stack due to value escaping", ())
749754
NOTE(box_to_stack_cannot_promote_box_to_stack_due_to_escape_location, none,

include/swift/AST/DiagnosticsSema.def

+3
Original file line numberDiff line numberDiff line change
@@ -5558,6 +5558,9 @@ ERROR(isolated_any_experimental,none,
55585558
ERROR(isolated_attr_global_actor_type,none,
55595559
"function type cannot have both a global actor and '@isolated(%0)'",
55605560
(StringRef))
5561+
ERROR(isolated_attr_bad_convention,none,
5562+
"'@isolated(%0)' function type cannot have %1 convention",
5563+
(StringRef, StringRef))
55615564
ERROR(isolation_macro_experimental,none,
55625565
"#isolation macro is experimental", ())
55635566

include/swift/AST/ExtInfo.h

+66-2
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,20 @@ class FunctionTypeIsolation {
120120
}
121121
};
122122

123+
/// For now, the kinds of isolation we carry on SIL function types
124+
/// are significantly reduced compared to AST function types.
125+
/// Isolation is not part of the SIL function model after the
126+
/// early portion of the pipeline.
127+
enum class SILFunctionTypeIsolation {
128+
/// We don't normally record isolation in SIL function types,
129+
/// so the empty case here is "unknown".
130+
Unknown,
131+
132+
/// The isolation of the function has been statically erased.
133+
/// This corresponds to @isolated(any).
134+
Erased,
135+
};
136+
123137
// MARK: - ClangTypeInfo
124138
/// Wrapper class for storing a clang::Type in an (AST|SIL)ExtInfo.
125139
class ClangTypeInfo {
@@ -893,7 +907,8 @@ class SILExtInfoBuilder {
893907
DifferentiabilityMaskOffset = 9,
894908
DifferentiabilityMask = 0x7 << DifferentiabilityMaskOffset,
895909
UnimplementableMask = 1 << 12,
896-
NumMaskBits = 13
910+
ErasedIsolationMask = 1 << 13,
911+
NumMaskBits = 14
897912
};
898913

899914
unsigned bits; // Naturally sized for speed.
@@ -913,12 +928,15 @@ class SILExtInfoBuilder {
913928
static constexpr unsigned makeBits(Representation rep, bool isPseudogeneric,
914929
bool isNoEscape, bool isSendable,
915930
bool isAsync, bool isUnimplementable,
931+
SILFunctionTypeIsolation isolation,
916932
DifferentiabilityKind diffKind) {
917933
return ((unsigned)rep) | (isPseudogeneric ? PseudogenericMask : 0) |
918934
(isNoEscape ? NoEscapeMask : 0) |
919935
(isSendable ? SendableMask : 0) |
920936
(isAsync ? AsyncMask : 0) |
921937
(isUnimplementable ? UnimplementableMask : 0) |
938+
(isolation == SILFunctionTypeIsolation::Erased
939+
? ErasedIsolationMask : 0) |
922940
(((unsigned)diffKind << DifferentiabilityMaskOffset) &
923941
DifferentiabilityMask);
924942
}
@@ -929,22 +947,28 @@ class SILExtInfoBuilder {
929947
SILExtInfoBuilder()
930948
: SILExtInfoBuilder(makeBits(SILFunctionTypeRepresentation::Thick, false,
931949
false, false, false, false,
950+
SILFunctionTypeIsolation::Unknown,
932951
DifferentiabilityKind::NonDifferentiable),
933952
ClangTypeInfo(nullptr), LifetimeDependenceInfo()) {}
934953

935954
SILExtInfoBuilder(Representation rep, bool isPseudogeneric, bool isNoEscape,
936955
bool isSendable, bool isAsync, bool isUnimplementable,
956+
SILFunctionTypeIsolation isolation,
937957
DifferentiabilityKind diffKind, const clang::Type *type,
938958
LifetimeDependenceInfo lifetimeDependenceInfo)
939959
: SILExtInfoBuilder(makeBits(rep, isPseudogeneric, isNoEscape, isSendable,
940-
isAsync, isUnimplementable, diffKind),
960+
isAsync, isUnimplementable,
961+
isolation, diffKind),
941962
ClangTypeInfo(type), lifetimeDependenceInfo) {}
942963

943964
// Constructor for polymorphic type.
944965
SILExtInfoBuilder(ASTExtInfoBuilder info, bool isPseudogeneric)
945966
: SILExtInfoBuilder(makeBits(info.getSILRepresentation(), isPseudogeneric,
946967
info.isNoEscape(), info.isSendable(),
947968
info.isAsync(), /*unimplementable*/ false,
969+
info.getIsolation().isErased()
970+
? SILFunctionTypeIsolation::Erased
971+
: SILFunctionTypeIsolation::Unknown,
948972
info.getDifferentiabilityKind()),
949973
info.getClangTypeInfo(),
950974
info.getLifetimeDependenceInfo()) {}
@@ -988,6 +1012,18 @@ class SILExtInfoBuilder {
9881012
return bits & UnimplementableMask;
9891013
}
9901014

1015+
/// Does this function type have erased isolation (i.e. is it the
1016+
/// lowering of an @isolated(any) function type)?
1017+
constexpr bool hasErasedIsolation() const {
1018+
return bits & ErasedIsolationMask;
1019+
}
1020+
1021+
constexpr SILFunctionTypeIsolation getIsolation() const {
1022+
return hasErasedIsolation()
1023+
? SILFunctionTypeIsolation::Erased
1024+
: SILFunctionTypeIsolation::Unknown;
1025+
}
1026+
9911027
/// Get the underlying ClangTypeInfo value.
9921028
ClangTypeInfo getClangTypeInfo() const { return clangTypeInfo; }
9931029

@@ -1071,6 +1107,22 @@ class SILExtInfoBuilder {
10711107
clangTypeInfo, lifetimeDependenceInfo);
10721108
}
10731109
[[nodiscard]]
1110+
SILExtInfoBuilder withErasedIsolation(bool erased = true) const {
1111+
return SILExtInfoBuilder(erased ? (bits | ErasedIsolationMask)
1112+
: (bits & ~ErasedIsolationMask),
1113+
clangTypeInfo, lifetimeDependenceInfo);
1114+
}
1115+
[[nodiscard]]
1116+
SILExtInfoBuilder withIsolation(SILFunctionTypeIsolation isolation) const {
1117+
switch (isolation) {
1118+
case SILFunctionTypeIsolation::Unknown:
1119+
return *this;
1120+
case SILFunctionTypeIsolation::Erased:
1121+
return withErasedIsolation(true);
1122+
}
1123+
llvm_unreachable("bad kind");
1124+
}
1125+
[[nodiscard]]
10741126
SILExtInfoBuilder withUnimplementable(bool isUnimplementable = true) const {
10751127
return SILExtInfoBuilder(isUnimplementable ? (bits | UnimplementableMask)
10761128
: (bits & ~UnimplementableMask),
@@ -1143,6 +1195,7 @@ class SILExtInfo {
11431195
static SILExtInfo getThin() {
11441196
return SILExtInfoBuilder(SILExtInfoBuilder::Representation::Thin, false,
11451197
false, false, false, false,
1198+
SILFunctionTypeIsolation::Unknown,
11461199
DifferentiabilityKind::NonDifferentiable, nullptr,
11471200
LifetimeDependenceInfo())
11481201
.build();
@@ -1175,6 +1228,13 @@ class SILExtInfo {
11751228
return builder.isUnimplementable();
11761229
}
11771230

1231+
constexpr bool hasErasedIsolation() const {
1232+
return builder.hasErasedIsolation();
1233+
}
1234+
constexpr SILFunctionTypeIsolation getIsolation() const {
1235+
return builder.getIsolation();
1236+
}
1237+
11781238
constexpr DifferentiabilityKind getDifferentiabilityKind() const {
11791239
return builder.getDifferentiabilityKind();
11801240
}
@@ -1213,6 +1273,10 @@ class SILExtInfo {
12131273
return builder.withAsync(isAsync).build();
12141274
}
12151275

1276+
SILExtInfo withErasedIsolation(bool erased = true) const {
1277+
return builder.withErasedIsolation(erased).build();
1278+
}
1279+
12161280
SILExtInfo withUnimplementable(bool isUnimplementable = true) const {
12171281
return builder.withUnimplementable(isUnimplementable).build();
12181282
}

include/swift/AST/Types.h

+7-1
Original file line numberDiff line numberDiff line change
@@ -384,7 +384,7 @@ class alignas(1 << TypeAlignInBits) TypeBase
384384

385385
protected:
386386
enum { NumAFTExtInfoBits = 14 };
387-
enum { NumSILExtInfoBits = 13 };
387+
enum { NumSILExtInfoBits = 14 };
388388

389389
// clang-format off
390390
union { uint64_t OpaqueBits;
@@ -4883,6 +4883,10 @@ class SILFunctionType final
48834883
bool isSendable() const { return getExtInfo().isSendable(); }
48844884
bool isUnimplementable() const { return getExtInfo().isUnimplementable(); }
48854885
bool isAsync() const { return getExtInfo().isAsync(); }
4886+
bool hasErasedIsolation() const { return getExtInfo().hasErasedIsolation(); }
4887+
SILFunctionTypeIsolation getIsolation() const {
4888+
return getExtInfo().getIsolation();
4889+
}
48864890

48874891
/// Return the array of all the yields.
48884892
ArrayRef<SILYieldInfo> getYields() const {
@@ -5467,6 +5471,8 @@ class SILFunctionType final
54675471
enum innerty {
54685472
None,
54695473
DifferentFunctionRepresentations,
5474+
DifferentAsyncness,
5475+
DifferentErasedIsolation,
54705476
ABIEscapeToNoEscapeConversion,
54715477
DifferentNumberOfResults,
54725478
DifferentReturnValueConventions,

include/swift/Demangling/DemangleNodes.def

+1
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ CONTEXT_NODE(IVarDestroyer)
131131
NODE(ImplEscaping)
132132
NODE(ImplConvention)
133133
NODE(ImplDifferentiabilityKind)
134+
NODE(ImplErasedIsolation)
134135
NODE(ImplParameterResultDifferentiability)
135136
NODE(ImplFunctionAttribute)
136137
NODE(ImplFunctionConvention)

0 commit comments

Comments
 (0)