Skip to content

Commit 341d630

Browse files
authored
Merge pull request #76767 from kubamracek/embedded-concurrency-task-groups
[Concurrency] Enable TaskGroup/DiscardingTaskGroup in Embedded Swift
2 parents 6dea968 + 3833c91 commit 341d630

File tree

15 files changed

+282
-28
lines changed

15 files changed

+282
-28
lines changed

include/swift/AST/Builtins.def

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -800,18 +800,6 @@ BUILTIN_MISC_OPERATION(ResumeThrowingContinuationReturning,
800800
BUILTIN_MISC_OPERATION(ResumeThrowingContinuationThrowing,
801801
"resumeThrowingContinuationThrowing", "", Special)
802802

803-
/// Create a task group.
804-
BUILTIN_MISC_OPERATION(CreateTaskGroup,
805-
"createTaskGroup", "", Special)
806-
807-
/// Create a task group, with options.
808-
BUILTIN_MISC_OPERATION(CreateTaskGroupWithFlags,
809-
"createTaskGroupWithFlags", "", Special)
810-
811-
/// Destroy a task group.
812-
BUILTIN_MISC_OPERATION(DestroyTaskGroup,
813-
"destroyTaskGroup", "", Special)
814-
815803
/// Unchecked pointer alignment assertion. Allows the compiler to assume
816804
/// alignment of the pointer to emit more efficient code.
817805
///
@@ -1054,6 +1042,15 @@ BUILTIN_SIL_OPERATION(CreateAsyncDiscardingTaskInGroupWithExecutor,
10541042
BUILTIN_MISC_OPERATION_WITH_SILGEN(BuildOrdinaryTaskExecutorRef,
10551043
"buildOrdinaryTaskExecutorRef", "n", Special)
10561044

1045+
/// Create a task group.
1046+
BUILTIN_MISC_OPERATION_WITH_SILGEN(CreateTaskGroup, "createTaskGroup", "", Special)
1047+
1048+
/// Create a task group, with options.
1049+
BUILTIN_MISC_OPERATION_WITH_SILGEN(CreateTaskGroupWithFlags, "createTaskGroupWithFlags", "", Special)
1050+
1051+
/// Destroy a task group.
1052+
BUILTIN_MISC_OPERATION(DestroyTaskGroup, "destroyTaskGroup", "", Special)
1053+
10571054
/// globalStringTablePointer has type String -> Builtin.RawPointer.
10581055
/// It returns an immortal, global string table pointer for strings constructed
10591056
/// from string literals. We consider it effects as readnone meaning that it

include/swift/Runtime/Concurrency.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,17 @@ void swift_taskGroup_initialize(TaskGroup *group, const Metadata *T);
215215
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
216216
void swift_taskGroup_initializeWithFlags(size_t flags, TaskGroup *group, const Metadata *T);
217217

218+
/// Initialize a `TaskGroup` in the passed `group` memory location.
219+
/// The caller is responsible for retaining and managing the group's lifecycle.
220+
///
221+
/// Its Swift signature is
222+
///
223+
/// \code
224+
/// func swift_taskGroup_initialize(flags: Int, group: Builtin.RawPointer)
225+
/// \endcode
226+
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
227+
void swift_taskGroup_initializeWithOptions(size_t flags, TaskGroup *group, const Metadata *T, TaskOptionRecord *options);
228+
218229
/// Attach a child task to the parent task's task group record.
219230
///
220231
/// This function MUST be called from the AsyncTask running the task group.

include/swift/Runtime/RuntimeFunctions.def

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2569,7 +2569,7 @@ FUNCTION(TaskRunInline,
25692569
EFFECT(NoEffect),
25702570
UNKNOWN_MEMEFFECTS)
25712571

2572-
// void swift_taskGroup_initialize(TaskGroup *group);
2572+
// void swift_taskGroup_initialize(TaskGroup *group, const Metadata *T);
25732573
FUNCTION(TaskGroupInitialize,
25742574
swift_taskGroup_initialize, SwiftCC,
25752575
ConcurrencyAvailability,
@@ -2579,7 +2579,7 @@ FUNCTION(TaskGroupInitialize,
25792579
EFFECT(Concurrency),
25802580
UNKNOWN_MEMEFFECTS)
25812581

2582-
// void swift_taskGroup_initializeWithFlags(size_t flags, TaskGroup *group);
2582+
// void swift_taskGroup_initializeWithFlags(size_t flags, TaskGroup *group, const Metadata *T);
25832583
FUNCTION(TaskGroupInitializeWithFlags,
25842584
swift_taskGroup_initializeWithFlags, SwiftCC,
25852585
ConcurrencyDiscardingTaskGroupAvailability,
@@ -2592,6 +2592,20 @@ FUNCTION(TaskGroupInitializeWithFlags,
25922592
EFFECT(Concurrency),
25932593
UNKNOWN_MEMEFFECTS)
25942594

2595+
// void swift_taskGroup_initializeWithTaskOptions(size_t flags, TaskGroup *group, const Metadata *T, TaskOptionRecord *options);
2596+
FUNCTION(TaskGroupInitializeWithOptions,
2597+
swift_taskGroup_initializeWithOptions, SwiftCC,
2598+
ConcurrencyDiscardingTaskGroupAvailability,
2599+
RETURNS(VoidTy),
2600+
ARGS(SizeTy, // flags
2601+
Int8PtrTy, // group
2602+
TypeMetadataPtrTy, // T.Type
2603+
SwiftTaskOptionRecordPtrTy // options
2604+
),
2605+
ATTRS(NoUnwind),
2606+
EFFECT(Concurrency),
2607+
UNKNOWN_MEMEFFECTS)
2608+
25952609
// void swift_taskGroup_destroy(TaskGroup *group);
25962610
FUNCTION(TaskGroupDestroy,
25972611
swift_taskGroup_destroy, SwiftCC,

lib/IRGen/GenBuiltin.cpp

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -295,20 +295,14 @@ void irgen::emitBuiltinCall(IRGenFunction &IGF, const BuiltinInfo &Builtin,
295295

296296
if (Builtin.ID == BuiltinValueKind::CreateTaskGroup) {
297297
llvm::Value *groupFlags = nullptr;
298-
// Claim metadata pointer.
299-
(void)args.claimAll();
298+
assert(args.size() == 0);
300299
out.add(emitCreateTaskGroup(IGF, substitutions, groupFlags));
301300
return;
302301
}
303302

304303
if (Builtin.ID == BuiltinValueKind::CreateTaskGroupWithFlags) {
305304
auto groupFlags = args.claimNext();
306-
// Claim the remaining metadata pointer.
307-
if (args.size() == 1) {
308-
(void)args.claimNext();
309-
} else if (args.size() > 1) {
310-
llvm_unreachable("createTaskGroupWithFlags expects 1 or 2 arguments");
311-
}
305+
assert(args.size() == 0);
312306
out.add(emitCreateTaskGroup(IGF, substitutions, groupFlags));
313307
return;
314308
}

lib/IRGen/GenConcurrency.cpp

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -335,15 +335,31 @@ llvm::Value *irgen::emitCreateTaskGroup(IRGenFunction &IGF,
335335
assert(subs.getReplacementTypes().size() == 1 &&
336336
"createTaskGroup should have a type substitution");
337337
auto resultType = subs.getReplacementTypes()[0]->getCanonicalType();
338+
339+
if (IGF.IGM.Context.LangOpts.hasFeature(Feature::Embedded)) {
340+
// In Embedded Swift, call swift_taskGroup_initializeWithOptions instead, to
341+
// avoid needing a Metadata argument.
342+
llvm::Value *options = llvm::ConstantPointerNull::get(IGF.IGM.Int8PtrTy);
343+
llvm::Value *resultTypeMetadata = llvm::ConstantPointerNull::get(IGF.IGM.Int8PtrTy);
344+
options = maybeAddEmbeddedSwiftResultTypeInfo(IGF, options, resultType);
345+
if (!groupFlags) groupFlags = llvm::ConstantInt::get(IGF.IGM.SizeTy, 0);
346+
llvm::CallInst *call = IGF.Builder.CreateCall(IGF.IGM.getTaskGroupInitializeWithOptionsFunctionPointer(),
347+
{groupFlags, group, resultTypeMetadata, options});
348+
call->setDoesNotThrow();
349+
call->setCallingConv(IGF.IGM.SwiftCC);
350+
return group;
351+
}
352+
338353
auto resultTypeMetadata = IGF.emitAbstractTypeMetadataRef(resultType);
339354

340355
llvm::CallInst *call;
341356
if (groupFlags) {
342357
call = IGF.Builder.CreateCall(IGF.IGM.getTaskGroupInitializeWithFlagsFunctionPointer(),
343358
{groupFlags, group, resultTypeMetadata});
344359
} else {
345-
call = IGF.Builder.CreateCall(IGF.IGM.getTaskGroupInitializeFunctionPointer(),
346-
{group, resultTypeMetadata});
360+
call =
361+
IGF.Builder.CreateCall(IGF.IGM.getTaskGroupInitializeFunctionPointer(),
362+
{group, resultTypeMetadata});
347363
}
348364
call->setDoesNotThrow();
349365
call->setCallingConv(IGF.IGM.SwiftCC);

lib/SILGen/SILGenBuiltin.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1750,6 +1750,38 @@ static ManagedValue emitBuiltinCreateDiscardingTask(
17501750
CreateTaskOptions::Discarding });
17511751
}
17521752

1753+
// Emit SIL for the named builtin: createTaskGroup.
1754+
// These formally take a metatype argument that's never actually used, so
1755+
// we ignore it.
1756+
static ManagedValue emitBuiltinCreateTaskGroup(SILGenFunction &SGF,
1757+
SILLocation loc,
1758+
SubstitutionMap subs,
1759+
ArrayRef<ManagedValue> args,
1760+
SGFContext C) {
1761+
auto &ctx = SGF.getASTContext();
1762+
auto resultType = SILType::getRawPointerType(ctx);
1763+
auto value = SGF.B.createBuiltin(
1764+
loc, ctx.getIdentifier(getBuiltinName(BuiltinValueKind::CreateTaskGroup)),
1765+
resultType, subs, {});
1766+
return ManagedValue::forObjectRValueWithoutOwnership(value);
1767+
}
1768+
1769+
// Emit SIL for the named builtin: createTaskGroupWithFlags.
1770+
// These formally take a metatype argument that's never actually used, so
1771+
// we ignore it.
1772+
static ManagedValue emitBuiltinCreateTaskGroupWithFlags(
1773+
SILGenFunction &SGF, SILLocation loc, SubstitutionMap subs,
1774+
ArrayRef<ManagedValue> args, SGFContext C) {
1775+
auto &ctx = SGF.getASTContext();
1776+
auto resultType = SILType::getRawPointerType(ctx);
1777+
auto value = SGF.B.createBuiltin(
1778+
loc,
1779+
ctx.getIdentifier(
1780+
getBuiltinName(BuiltinValueKind::CreateTaskGroupWithFlags)),
1781+
resultType, subs, {args[0].getValue()});
1782+
return ManagedValue::forObjectRValueWithoutOwnership(value);
1783+
}
1784+
17531785
ManagedValue
17541786
SILGenFunction::emitCreateAsyncMainTask(SILLocation loc, SubstitutionMap subs,
17551787
ManagedValue flags,

stdlib/public/CompatibilityOverride/CompatibilityOverrideConcurrency.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,10 @@ OVERRIDE_TASK_GROUP(taskGroup_initializeWithFlags, void,
305305
SWIFT_EXPORT_FROM(swift_Concurrency), SWIFT_CC(swift),
306306
swift::, (size_t flags, TaskGroup *group, const Metadata *T), (flags, group, T))
307307

308+
OVERRIDE_TASK_GROUP(taskGroup_initializeWithOptions, void,
309+
SWIFT_EXPORT_FROM(swift_Concurrency), SWIFT_CC(swift),
310+
swift::, (size_t flags, TaskGroup *group, const Metadata *T, TaskOptionRecord *options), (flags, group, T, options))
311+
308312
OVERRIDE_TASK_STATUS(taskGroup_attachChild, void,
309313
SWIFT_EXPORT_FROM(swift_Concurrency), SWIFT_CC(swift),
310314
swift::, (TaskGroup *group, AsyncTask *child),

stdlib/public/Concurrency/DiscardingTaskGroup.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,9 @@ import Swift
6767
///
6868
/// - SeeAlso: ``withThrowingDiscardingTaskGroup(returning:body:)``
6969
@available(SwiftStdlib 5.9, *)
70+
#if !hasFeature(Embedded)
7071
@backDeployed(before: SwiftStdlib 6.0)
72+
#endif
7173
@inlinable
7274
public func withDiscardingTaskGroup<GroupResult>(
7375
returning returnType: GroupResult.Type = GroupResult.self,
@@ -478,7 +480,9 @@ extension DiscardingTaskGroup: Sendable { }
478480
/// }
479481
/// ```
480482
@available(SwiftStdlib 5.9, *)
483+
#if !hasFeature(Embedded)
481484
@backDeployed(before: SwiftStdlib 6.0)
485+
#endif
482486
@inlinable
483487
public func withThrowingDiscardingTaskGroup<GroupResult>(
484488
returning returnType: GroupResult.Type = GroupResult.self,

stdlib/public/Concurrency/TaskGroup.cpp

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "swift/ABI/Metadata.h"
2727
#include "swift/ABI/Task.h"
2828
#include "swift/ABI/TaskGroup.h"
29+
#include "swift/ABI/TaskOptions.h"
2930
#include "swift/Basic/RelativePointer.h"
3031
#include "swift/Basic/STLExtras.h"
3132
#include "swift/Runtime/Concurrency.h"
@@ -954,6 +955,8 @@ TaskGroup* TaskGroupTaskStatusRecord::getGroup() {
954955
// =============================================================================
955956
// ==== initialize -------------------------------------------------------------
956957

958+
static void _swift_taskGroup_initialize(ResultTypeInfo resultType, size_t rawGroupFlags, TaskGroup *group);
959+
957960
// Initializes into the preallocated _group an actual TaskGroupBase.
958961
SWIFT_CC(swift)
959962
static void swift_taskGroup_initializeImpl(TaskGroup *group, const Metadata *T) {
@@ -964,11 +967,51 @@ static void swift_taskGroup_initializeImpl(TaskGroup *group, const Metadata *T)
964967
SWIFT_CC(swift)
965968
static void swift_taskGroup_initializeWithFlagsImpl(size_t rawGroupFlags,
966969
TaskGroup *group, const Metadata *T) {
967-
970+
ResultTypeInfo resultType;
968971
#if !SWIFT_CONCURRENCY_EMBEDDED
972+
resultType.metadata = T;
973+
#else
974+
swift_unreachable("swift_taskGroup_initializeWithFlags in embedded");
975+
#endif
976+
_swift_taskGroup_initialize(resultType, rawGroupFlags, group);
977+
}
978+
979+
// Initializes into the preallocated _group an actual instance.
980+
SWIFT_CC(swift)
981+
static void swift_taskGroup_initializeWithOptionsImpl(size_t rawGroupFlags, TaskGroup *group, const Metadata *T, TaskOptionRecord *options) {
969982
ResultTypeInfo resultType;
983+
#if !SWIFT_CONCURRENCY_EMBEDDED
970984
resultType.metadata = T;
985+
#endif
971986

987+
for (auto option = options; option; option = option->getParent()) {
988+
switch (option->getKind()) {
989+
case TaskOptionRecordKind::ResultTypeInfo: {
990+
#if SWIFT_CONCURRENCY_EMBEDDED
991+
auto *typeInfo = cast<ResultTypeInfoTaskOptionRecord>(option);
992+
resultType = {
993+
.size = typeInfo->size,
994+
.alignMask = typeInfo->alignMask,
995+
.initializeWithCopy = typeInfo->initializeWithCopy,
996+
.storeEnumTagSinglePayload = typeInfo->storeEnumTagSinglePayload,
997+
.destroy = typeInfo->destroy,
998+
};
999+
#else
1000+
swift_unreachable("ResultTypeInfo in non embedded");
1001+
#endif
1002+
break;
1003+
}
1004+
default:
1005+
break; // ignore unknown records
1006+
}
1007+
}
1008+
1009+
assert(!resultType.isNull());
1010+
1011+
_swift_taskGroup_initialize(resultType, rawGroupFlags, group);
1012+
}
1013+
1014+
static void _swift_taskGroup_initialize(ResultTypeInfo resultType, size_t rawGroupFlags, TaskGroup *group) {
9721015
TaskGroupFlags groupFlags(rawGroupFlags);
9731016
SWIFT_TASK_GROUP_DEBUG_LOG_0(group, "create group, from task:%p; flags: isDiscardingResults=%d",
9741017
swift_task_getCurrent(),
@@ -993,9 +1036,6 @@ static void swift_taskGroup_initializeWithFlagsImpl(size_t rawGroupFlags,
9931036
}
9941037
return true;
9951038
});
996-
#else
997-
swift_unreachable("task groups not supported yet in embedded Swift");
998-
#endif
9991039
}
10001040

10011041
// =============================================================================

stdlib/public/Concurrency/TaskGroup.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,9 @@ import Swift
6363
/// For tasks that need to handle cancellation by throwing an error,
6464
/// use the `withThrowingTaskGroup(of:returning:body:)` method instead.
6565
@available(SwiftStdlib 5.1, *)
66+
#if !hasFeature(Embedded)
6667
@backDeployed(before: SwiftStdlib 6.0)
68+
#endif
6769
@inlinable
6870
public func withTaskGroup<ChildTaskResult, GroupResult>(
6971
of childTaskResultType: ChildTaskResult.Type = ChildTaskResult.self,
@@ -198,7 +200,9 @@ public func _unsafeInheritExecutor_withTaskGroup<ChildTaskResult, GroupResult>(
198200
/// which gives you a chance to handle the individual error
199201
/// or to let the group rethrow the error.
200202
@available(SwiftStdlib 5.1, *)
203+
#if !hasFeature(Embedded)
201204
@backDeployed(before: SwiftStdlib 6.0)
205+
#endif
202206
@inlinable
203207
public func withThrowingTaskGroup<ChildTaskResult, GroupResult>(
204208
of childTaskResultType: ChildTaskResult.Type = ChildTaskResult.self,
@@ -535,7 +539,9 @@ public struct TaskGroup<ChildTaskResult: Sendable> {
535539
///
536540
/// - Returns: The value returned by the next child task that completes.
537541
@available(SwiftStdlib 5.1, *)
542+
#if !hasFeature(Embedded)
538543
@backDeployed(before: SwiftStdlib 6.0)
544+
#endif
539545
public mutating func next(isolation: isolated (any Actor)? = #isolation) async -> ChildTaskResult? {
540546
// try!-safe because this function only exists for Failure == Never,
541547
// and as such, it is impossible to spawn a throwing child task.
@@ -553,7 +559,9 @@ public struct TaskGroup<ChildTaskResult: Sendable> {
553559
/// Await all of the pending tasks added this group.
554560
@usableFromInline
555561
@available(SwiftStdlib 5.1, *)
562+
#if !hasFeature(Embedded)
556563
@backDeployed(before: SwiftStdlib 6.0)
564+
#endif
557565
internal mutating func awaitAllRemainingTasks(isolation: isolated (any Actor)? = #isolation) async {
558566
while let _ = await next(isolation: isolation) {}
559567
}
@@ -693,7 +701,9 @@ public struct ThrowingTaskGroup<ChildTaskResult: Sendable, Failure: Error> {
693701
/// Await all the remaining tasks on this group.
694702
@usableFromInline
695703
@available(SwiftStdlib 5.1, *)
704+
#if !hasFeature(Embedded)
696705
@backDeployed(before: SwiftStdlib 6.0)
706+
#endif
697707
internal mutating func awaitAllRemainingTasks(isolation: isolated (any Actor)? = #isolation) async {
698708
while true {
699709
do {
@@ -971,7 +981,9 @@ public struct ThrowingTaskGroup<ChildTaskResult: Sendable, Failure: Error> {
971981
///
972982
/// - SeeAlso: `nextResult()`
973983
@available(SwiftStdlib 5.1, *)
984+
#if !hasFeature(Embedded)
974985
@backDeployed(before: SwiftStdlib 6.0)
986+
#endif
975987
public mutating func next(isolation: isolated (any Actor)? = #isolation) async throws -> ChildTaskResult? {
976988
return try await _taskGroupWaitNext(group: _group)
977989
}

0 commit comments

Comments
 (0)