Skip to content

Commit e7e922e

Browse files
committed
Introduce a createAsyncTaskInGroup SIL builtin.
Rather than using group task options constructed from the Swift parts of the _Concurrency library and passed through `createAsyncTask`'s options, introduce a separate builtin that always takes a group. Move the responsibility for creating the options structure into IRGen, so we don't need to expose the TaskGroupTaskOptionRecord type in Swift.
1 parent 23e6f7b commit e7e922e

File tree

18 files changed

+194
-85
lines changed

18 files changed

+194
-85
lines changed

include/swift/AST/Builtins.def

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -816,6 +816,17 @@ BUILTIN_MISC_OPERATION_WITH_SILGEN(EndAsyncLet, "endAsyncLet", "", Special)
816816
BUILTIN_MISC_OPERATION_WITH_SILGEN(CreateAsyncTask,
817817
"createAsyncTask", "", Special)
818818

819+
/// createAsyncTaskInGroup(): (
820+
/// Int, // flags
821+
/// Builtin.RawPointer, // group
822+
/// @escaping () async throws -> T // function
823+
/// ) -> Builtin.NativeObject
824+
///
825+
/// Create a new asynchronous task future, given flags, a parent task,
826+
/// task group and a function to execute.
827+
BUILTIN_MISC_OPERATION_WITH_SILGEN(CreateAsyncTaskInGroup,
828+
"createAsyncTaskInGroup", "", Special)
829+
819830
/// globalStringTablePointer has type String -> Builtin.RawPointer.
820831
/// It returns an immortal, global string table pointer for strings constructed
821832
/// from string literals. We consider it effects as readnone meaning that it

include/swift/Basic/Features.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,5 +52,6 @@ LANGUAGE_FEATURE(InheritActorContext, 0, "@_inheritActorContext attribute", true
5252
LANGUAGE_FEATURE(ImplicitSelfCapture, 0, "@_implicitSelfCapture attribute", true)
5353
LANGUAGE_FEATURE(BuiltinBuildExecutor, 0, "Executor-building builtins", true)
5454
LANGUAGE_FEATURE(BuiltinBuildMainExecutor, 0, "MainActor executor building builtin", true)
55+
LANGUAGE_FEATURE(BuiltinCreateAsyncTaskInGroup, 0, "MainActor executor building builtin", true)
5556

5657
#undef LANGUAGE_FEATURE

lib/AST/ASTPrinter.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2779,6 +2779,10 @@ static bool usesFeatureBuiltinTaskGroupWithArgument(Decl *decl) {
27792779
return false;
27802780
}
27812781

2782+
static bool usesFeatureBuiltinCreateAsyncTaskInGroup(Decl *decl) {
2783+
return false;
2784+
}
2785+
27822786
static bool usesFeatureInheritActorContext(Decl *decl) {
27832787
if (auto func = dyn_cast<AbstractFunctionDecl>(decl)) {
27842788
for (auto param : *func->getParameters()) {

lib/AST/Builtins.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1437,6 +1437,19 @@ static ValueDecl *getCreateAsyncTask(ASTContext &ctx, Identifier id) {
14371437
return builder.build(id);
14381438
}
14391439

1440+
static ValueDecl *getCreateAsyncTaskInGroup(ASTContext &ctx, Identifier id) {
1441+
BuiltinFunctionBuilder builder(ctx);
1442+
auto genericParam = makeGenericParam().build(builder); // <T>
1443+
builder.addParameter(makeConcrete(ctx.getIntType())); // 0 flags
1444+
builder.addParameter(makeConcrete(ctx.TheRawPointerType)); // 1 group
1445+
auto extInfo = ASTExtInfoBuilder().withAsync().withThrows().build();
1446+
builder.addParameter(
1447+
makeConcrete(FunctionType::get({ }, genericParam, extInfo))); // 2 operation
1448+
builder.setResult(makeConcrete(getAsyncTaskAndContextType(ctx)));
1449+
1450+
return builder.build(id);
1451+
}
1452+
14401453
static ValueDecl *getConvertTaskToJob(ASTContext &ctx, Identifier id) {
14411454
return getBuiltinFunction(ctx, id,
14421455
_thin,
@@ -2748,6 +2761,9 @@ ValueDecl *swift::getBuiltinValueDecl(ASTContext &Context, Identifier Id) {
27482761
case BuiltinValueKind::CreateAsyncTask:
27492762
return getCreateAsyncTask(Context, Id);
27502763

2764+
case BuiltinValueKind::CreateAsyncTaskInGroup:
2765+
return getCreateAsyncTaskInGroup(Context, Id);
2766+
27512767
case BuiltinValueKind::ConvertTaskToJob:
27522768
return getConvertTaskToJob(Context, Id);
27532769

lib/IRGen/GenBuiltin.cpp

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -270,16 +270,26 @@ void irgen::emitBuiltinCall(IRGenFunction &IGF, const BuiltinInfo &Builtin,
270270
return;
271271
}
272272

273-
if (Builtin.ID == BuiltinValueKind::CreateAsyncTask) {
273+
if (Builtin.ID == BuiltinValueKind::CreateAsyncTask ||
274+
Builtin.ID == BuiltinValueKind::CreateAsyncTaskInGroup) {
275+
274276
auto flags = args.claimNext();
275-
auto taskOptions = args.claimNext();
277+
auto taskGroup =
278+
(Builtin.ID == BuiltinValueKind::CreateAsyncTaskInGroup)
279+
? args.claimNext()
280+
: nullptr;
281+
llvm::Value *taskOptions =
282+
(Builtin.ID == BuiltinValueKind::CreateAsyncTask)
283+
? args.claimNext()
284+
: llvm::ConstantInt::get(IGF.IGM.SwiftTaskOptionRecordPtrTy, 0);
276285
auto futureResultType = args.claimNext();
277286
auto taskFunction = args.claimNext();
278287
auto taskContext = args.claimNext();
279288

280289
auto newTaskAndContext = emitTaskCreate(
281290
IGF,
282291
flags,
292+
taskGroup,
283293
taskOptions,
284294
futureResultType,
285295
taskFunction, taskContext,

lib/IRGen/GenCall.cpp

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3860,16 +3860,41 @@ void irgen::emitTaskCancel(IRGenFunction &IGF, llvm::Value *task) {
38603860
llvm::Value *irgen::emitTaskCreate(
38613861
IRGenFunction &IGF,
38623862
llvm::Value *flags,
3863+
llvm::Value *taskGroup,
38633864
llvm::Value *taskOptions,
38643865
llvm::Value *futureResultType,
38653866
llvm::Value *taskFunction,
38663867
llvm::Value *localContextInfo,
38673868
SubstitutionMap subs) {
3868-
llvm::CallInst *result;
38693869
taskOptions = IGF.Builder.CreateBitOrPointerCast(
38703870
taskOptions, IGF.IGM.SwiftTaskOptionRecordPtrTy);
3871-
assert(futureResultType && "No future?!");
3872-
result = IGF.Builder.CreateCall(
3871+
3872+
// If there is a task group, emit a task group option structure to contain
3873+
// it.
3874+
if (taskGroup) {
3875+
TaskOptionRecordFlags optionsFlags(TaskOptionRecordKind::TaskGroup);
3876+
llvm::Value *optionsFlagsVal = llvm::ConstantInt::get(
3877+
IGF.IGM.SizeTy, optionsFlags.getOpaqueValue());
3878+
3879+
auto optionsRecord = IGF.createAlloca(
3880+
IGF.IGM.SwiftTaskGroupTaskOptionRecordTy, Alignment(),
3881+
"task_group_options");
3882+
auto optionsBaseRecord = IGF.Builder.CreateStructGEP(
3883+
optionsRecord, 0, Size());
3884+
IGF.Builder.CreateStore(
3885+
optionsFlagsVal,
3886+
IGF.Builder.CreateStructGEP(optionsBaseRecord, 0, Size()));
3887+
IGF.Builder.CreateStore(
3888+
taskOptions, IGF.Builder.CreateStructGEP(optionsBaseRecord, 1, Size()));
3889+
3890+
IGF.Builder.CreateStore(
3891+
taskGroup, IGF.Builder.CreateStructGEP(optionsRecord, 1, Size()));
3892+
taskOptions = IGF.Builder.CreateBitOrPointerCast(
3893+
optionsRecord.getAddress(), IGF.IGM.SwiftTaskOptionRecordPtrTy);
3894+
}
3895+
3896+
assert(futureResultType && "no future?!");
3897+
llvm::CallInst *result = IGF.Builder.CreateCall(
38733898
IGF.IGM.getTaskCreateFn(),
38743899
{flags,
38753900
taskOptions,

lib/IRGen/GenCall.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,7 @@ namespace irgen {
229229
llvm::Value *emitTaskCreate(
230230
IRGenFunction &IGF,
231231
llvm::Value *flags,
232+
llvm::Value *taskGroup,
232233
llvm::Value *taskOptions,
233234
llvm::Value *futureResultType,
234235
llvm::Value *taskFunction,

lib/IRGen/IRGenModule.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -623,6 +623,15 @@ IRGenModule::IRGenModule(IRGenerator &irgen,
623623
SwiftAsyncLetPtrTy = Int8PtrTy; // we pass it opaquely (AsyncLet*)
624624
SwiftTaskOptionRecordPtrTy = SizeTy; // Builtin.RawPointer? that we get as (TaskOptionRecord*)
625625
SwiftTaskGroupPtrTy = Int8PtrTy; // we pass it opaquely (TaskGroup*)
626+
SwiftTaskOptionRecordTy = createStructType(*this, "swift.task_option", {
627+
SizeTy, // Flags
628+
SwiftTaskOptionRecordPtrTy, // Parent
629+
});
630+
SwiftTaskGroupTaskOptionRecordTy = createStructType(
631+
*this, "swift.task_group_task_option", {
632+
SwiftTaskOptionRecordTy, // Base option record
633+
SwiftTaskGroupPtrTy, // Task group
634+
});
626635
ExecutorFirstTy = SizeTy;
627636
ExecutorSecondTy = SizeTy;
628637
SwiftExecutorTy = createStructType(*this, "swift.executor", {

lib/IRGen/IRGenModule.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -735,6 +735,8 @@ class IRGenModule {
735735
llvm::PointerType *SwiftAsyncLetPtrTy;
736736
llvm::IntegerType *SwiftTaskOptionRecordPtrTy;
737737
llvm::PointerType *SwiftTaskGroupPtrTy;
738+
llvm::StructType *SwiftTaskOptionRecordTy;
739+
llvm::StructType *SwiftTaskGroupTaskOptionRecordTy;
738740
llvm::PointerType *SwiftJobPtrTy;
739741
llvm::IntegerType *ExecutorFirstTy;
740742
llvm::IntegerType *ExecutorSecondTy;

lib/SIL/IR/OperandOwnership.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -766,6 +766,7 @@ BUILTIN_OPERAND_OWNERSHIP(ForwardingConsume, COWBufferForReading)
766766
BUILTIN_OPERAND_OWNERSHIP(ForwardingConsume, UnsafeGuaranteed)
767767

768768
const int PARAMETER_INDEX_CREATE_ASYNC_TASK_FUTURE_FUNCTION = 3;
769+
const int PARAMETER_INDEX_CREATE_ASYNC_TASK_GROUP_FUTURE_FUNCTION = 3;
769770

770771
OperandOwnership
771772
OperandOwnershipBuiltinClassifier::visitCreateAsyncTask(BuiltinInst *bi,
@@ -781,6 +782,20 @@ OperandOwnershipBuiltinClassifier::visitCreateAsyncTask(BuiltinInst *bi,
781782
return OperandOwnership::InteriorPointer;
782783
}
783784

785+
OperandOwnership
786+
OperandOwnershipBuiltinClassifier::visitCreateAsyncTaskInGroup(BuiltinInst *bi,
787+
StringRef attr) {
788+
// The function operand is consumed by the new task.
789+
if (&op == &bi->getOperandRef(PARAMETER_INDEX_CREATE_ASYNC_TASK_GROUP_FUTURE_FUNCTION))
790+
return OperandOwnership::DestroyingConsume;
791+
792+
// FIXME: These are considered InteriorPointer because they may propagate a
793+
// pointer into a borrowed values. If they do not propagate an interior pointer,
794+
// then they should be InstantaneousUse instead and should not require a
795+
// guaranteed value.
796+
return OperandOwnership::InteriorPointer;
797+
}
798+
784799
OperandOwnership OperandOwnershipBuiltinClassifier::
785800
visitResumeNonThrowingContinuationReturning(BuiltinInst *bi, StringRef attr) {
786801
// The value operand is consumed.

0 commit comments

Comments
 (0)