Skip to content

Commit 34c08b8

Browse files
committed
[TaskToThread] Add Task.runInline.
The new intrinsic, exposed via static functions on Task<T, Never> and Task<T, Error> (rethrowing), begins an asynchronous context within a synchronous caller's context. This is only available for use under the task-to-thread concurrency model, and even then only under SPI.
1 parent 84f5eb5 commit 34c08b8

File tree

23 files changed

+780
-8
lines changed

23 files changed

+780
-8
lines changed

include/swift/ABI/MetadataValues.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2360,6 +2360,8 @@ enum class TaskOptionRecordKind : uint8_t {
23602360
AsyncLet = 2,
23612361
/// Request a child task for an 'async let'.
23622362
AsyncLetWithBuffer = 3,
2363+
/// Request a child task for swift_task_run_inline.
2364+
RunInline = UINT8_MAX,
23632365
};
23642366

23652367
/// Flags for cancellation records.

include/swift/ABI/TaskOptions.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,24 @@ class AsyncLetWithBufferTaskOptionRecord : public TaskOptionRecord {
141141
}
142142
};
143143

144+
class RunInlineTaskOptionRecord : public TaskOptionRecord {
145+
void *allocation;
146+
size_t allocationBytes;
147+
148+
public:
149+
RunInlineTaskOptionRecord(void *allocation, size_t allocationBytes)
150+
: TaskOptionRecord(TaskOptionRecordKind::RunInline),
151+
allocation(allocation), allocationBytes(allocationBytes) {}
152+
153+
void *getAllocation() const { return allocation; }
154+
155+
size_t getAllocationBytes() const { return allocationBytes; }
156+
157+
static bool classof(const TaskOptionRecord *record) {
158+
return record->getKind() == TaskOptionRecordKind::RunInline;
159+
}
160+
};
161+
144162
} // end namespace swift
145163

146164
#endif

include/swift/AST/Builtins.def

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -894,6 +894,16 @@ BUILTIN_MISC_OPERATION(StartAsyncLet, "startAsyncLet", "", Special)
894894
/// destruction.
895895
BUILTIN_MISC_OPERATION(StartAsyncLetWithLocalBuffer, "startAsyncLetWithLocalBuffer", "", Special)
896896

897+
/// taskRunInline()<T>: (
898+
/// () async -> T
899+
/// ) -> T
900+
///
901+
/// Create an async context inline in the current synchronous context and run
902+
/// the specified closure.
903+
///
904+
/// This is only supported under the task-to-thread concurrency model.
905+
BUILTIN_MISC_OPERATION(TaskRunInline, "taskRunInline", "", Special)
906+
897907
/// endAsyncLet(): (Builtin.RawPointer) -> Void
898908
///
899909
/// DEPRECATED. The swift_asyncLet_finish intrinsic and endAsyncLetLifetime

include/swift/Basic/Features.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ LANGUAGE_FEATURE(BuiltinCreateAsyncTaskInGroup, 0, "MainActor executor building
8282
LANGUAGE_FEATURE(BuiltinMove, 0, "Builtin.move()", true)
8383
LANGUAGE_FEATURE(BuiltinCopy, 0, "Builtin.copy()", true)
8484
LANGUAGE_FEATURE(BuiltinStackAlloc, 0, "Builtin.stackAlloc", true)
85+
LANGUAGE_FEATURE(BuiltinTaskRunInline, 0, "Builtin.taskRunInline", true)
8586
SUPPRESSIBLE_LANGUAGE_FEATURE(SpecializeAttributeWithAvailability, 0, "@_specialize attribute with availability", true)
8687
LANGUAGE_FEATURE(BuiltinAssumeAlignment, 0, "Builtin.assumeAlignment", true)
8788
SUPPRESSIBLE_LANGUAGE_FEATURE(UnsafeInheritExecutor, 0, "@_unsafeInheritExecutor", true)

include/swift/Runtime/Concurrency.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,20 @@ AsyncTaskAndContext swift_task_create_common(
9292
TaskContinuationFunction *function, void *closureContext,
9393
size_t initialContextSize);
9494

95+
#if SWIFT_CONCURRENCY_TASK_TO_THREAD_MODEL
96+
#define SWIFT_TASK_RUN_INLINE_INITIAL_CONTEXT_BYTES 4096
97+
/// Begin an async context in the current sync context and run the indicated
98+
/// closure in it.
99+
///
100+
/// This is only supported under the task-to-thread concurrency model and
101+
/// relies on a synchronous implementation of task blocking in order to work.
102+
SWIFT_EXPORT_FROM(swift_Concurrency)
103+
SWIFT_CC(swift)
104+
void swift_task_run_inline(OpaqueValue *result, void *closureAFP,
105+
OpaqueValue *closureContext,
106+
const Metadata *futureResultType);
107+
#endif
108+
95109
/// Allocate memory in a task.
96110
///
97111
/// This must be called synchronously with the task.

include/swift/Runtime/RuntimeFunctions.def

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2033,6 +2033,24 @@ FUNCTION(EndAsyncLet,
20332033
ATTRS(NoUnwind),
20342034
EFFECT(Concurrency))
20352035

2036+
/// void swift_task_run_inline(
2037+
/// OpaqueValue *result,
2038+
/// void *closureAFP,
2039+
/// OpaqueValue *closureContext,
2040+
/// const Metadata *futureResultType
2041+
/// )
2042+
FUNCTION(TaskRunInline,
2043+
swift_task_run_inline, SwiftCC,
2044+
TaskRunInlineAvailability,
2045+
RETURNS(VoidTy),
2046+
ARGS(OpaquePtrTy, // OpaqueValue *result
2047+
Int8PtrTy, // void *closure
2048+
OpaquePtrTy, // OpaqueValue *closureContext
2049+
TypeMetadataPtrTy, // const Metadata *futureResultType
2050+
),
2051+
ATTRS(NoUnwind),
2052+
EFFECT(NoEffect))
2053+
20362054
// void swift_taskGroup_initialize(TaskGroup *group);
20372055
FUNCTION(TaskGroupInitialize,
20382056
swift_taskGroup_initialize, SwiftCC,

lib/AST/ASTPrinter.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2905,6 +2905,8 @@ static bool usesFeatureBuiltinMove(Decl *decl) {
29052905

29062906
static bool usesFeatureBuiltinCopy(Decl *decl) { return false; }
29072907

2908+
static bool usesFeatureBuiltinTaskRunInline(Decl *) { return false; }
2909+
29082910
static bool usesFeatureSpecializeAttributeWithAvailability(Decl *decl) {
29092911
if (auto func = dyn_cast<AbstractFunctionDecl>(decl)) {
29102912
for (auto specialize : func->getAttrs().getAttributes<SpecializeAttr>()) {

lib/AST/Builtins.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1488,6 +1488,14 @@ static ValueDecl *getCreateAsyncTaskInGroup(ASTContext &ctx, Identifier id) {
14881488
return builder.build(id);
14891489
}
14901490

1491+
static ValueDecl *getTaskRunInline(ASTContext &ctx, Identifier id) {
1492+
return getBuiltinFunction(
1493+
ctx, id, _thin, _generics(_unrestricted),
1494+
_parameters(
1495+
_function(_async(_noescape(_thick)), _typeparam(0), _parameters())),
1496+
_typeparam(0));
1497+
}
1498+
14911499
static ValueDecl *getConvertTaskToJob(ASTContext &ctx, Identifier id) {
14921500
return getBuiltinFunction(ctx, id,
14931501
_thin,
@@ -2838,6 +2846,9 @@ ValueDecl *swift::getBuiltinValueDecl(ASTContext &Context, Identifier Id) {
28382846
case BuiltinValueKind::CreateAsyncTaskInGroup:
28392847
return getCreateAsyncTaskInGroup(Context, Id);
28402848

2849+
case BuiltinValueKind::TaskRunInline:
2850+
return getTaskRunInline(Context, Id);
2851+
28412852
case BuiltinValueKind::TargetOSVersionAtLeast:
28422853
return getTargetOSVersionAtLeast(Context, Id);
28432854

lib/IRGen/GenBuiltin.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,15 @@ void irgen::emitBuiltinCall(IRGenFunction &IGF, const BuiltinInfo &Builtin,
283283
return;
284284
}
285285

286+
if (Builtin.ID == BuiltinValueKind::TaskRunInline) {
287+
auto result = args.claimNext();
288+
auto closure = args.claimNext();
289+
auto closureContext = args.claimNext();
290+
291+
emitTaskRunInline(IGF, substitutions, result, closure, closureContext);
292+
return;
293+
}
294+
286295
if (Builtin.ID == BuiltinValueKind::CreateTaskGroup) {
287296
// Claim metadata pointer.
288297
(void)args.claimAll();

lib/IRGen/GenConcurrency.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -333,3 +333,18 @@ llvm::Function *IRGenModule::getAwaitAsyncContinuationFn() {
333333
Builder.CreateRetVoid();
334334
return suspendFn;
335335
}
336+
337+
void irgen::emitTaskRunInline(IRGenFunction &IGF, SubstitutionMap subs,
338+
llvm::Value *result, llvm::Value *closure,
339+
llvm::Value *closureContext) {
340+
assert(subs.getReplacementTypes().size() == 1 &&
341+
"taskRunInline should have a type substitution");
342+
auto resultType = subs.getReplacementTypes()[0]->getCanonicalType();
343+
auto resultTypeMetadata = IGF.emitAbstractTypeMetadataRef(resultType);
344+
345+
auto *call = IGF.Builder.CreateCall(
346+
IGF.IGM.getTaskRunInlineFn(),
347+
{result, closure, closureContext, resultTypeMetadata});
348+
call->setDoesNotThrow();
349+
call->setCallingConv(IGF.IGM.SwiftCC);
350+
}

0 commit comments

Comments
 (0)