Skip to content

Commit 88fa5ed

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 286ea81 commit 88fa5ed

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
@@ -805,6 +805,17 @@ BUILTIN_MISC_OPERATION_WITH_SILGEN(EndAsyncLet, "endAsyncLet", "", Special)
805805
BUILTIN_MISC_OPERATION_WITH_SILGEN(CreateAsyncTask,
806806
"createAsyncTask", "", Special)
807807

808+
/// createAsyncTaskInGroup(): (
809+
/// Int, // flags
810+
/// Builtin.RawPointer, // group
811+
/// @escaping () async throws -> T // function
812+
/// ) -> Builtin.NativeObject
813+
///
814+
/// Create a new asynchronous task future, given flags, a parent task,
815+
/// task group and a function to execute.
816+
BUILTIN_MISC_OPERATION_WITH_SILGEN(CreateAsyncTaskInGroup,
817+
"createAsyncTaskInGroup", "", Special)
818+
808819
/// globalStringTablePointer has type String -> Builtin.RawPointer.
809820
/// It returns an immortal, global string table pointer for strings constructed
810821
/// 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
@@ -2785,6 +2785,10 @@ static bool usesFeatureBuiltinTaskGroup(Decl *decl) {
27852785
return false;
27862786
}
27872787

2788+
static bool usesFeatureBuiltinCreateAsyncTaskInGroup(Decl *decl) {
2789+
return false;
2790+
}
2791+
27882792
static bool usesFeatureInheritActorContext(Decl *decl) {
27892793
if (auto func = dyn_cast<AbstractFunctionDecl>(decl)) {
27902794
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,
@@ -2730,6 +2743,9 @@ ValueDecl *swift::getBuiltinValueDecl(ASTContext &Context, Identifier Id) {
27302743
case BuiltinValueKind::CreateAsyncTask:
27312744
return getCreateAsyncTask(Context, Id);
27322745

2746+
case BuiltinValueKind::CreateAsyncTaskInGroup:
2747+
return getCreateAsyncTaskInGroup(Context, Id);
2748+
27332749
case BuiltinValueKind::ConvertTaskToJob:
27342750
return getConvertTaskToJob(Context, Id);
27352751

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
@@ -3859,16 +3859,41 @@ void irgen::emitTaskCancel(IRGenFunction &IGF, llvm::Value *task) {
38593859
llvm::Value *irgen::emitTaskCreate(
38603860
IRGenFunction &IGF,
38613861
llvm::Value *flags,
3862+
llvm::Value *taskGroup,
38623863
llvm::Value *taskOptions,
38633864
llvm::Value *futureResultType,
38643865
llvm::Value *taskFunction,
38653866
llvm::Value *localContextInfo,
38663867
SubstitutionMap subs) {
3867-
llvm::CallInst *result;
38683868
taskOptions = IGF.Builder.CreateBitOrPointerCast(
38693869
taskOptions, IGF.IGM.SwiftTaskOptionRecordPtrTy);
3870-
assert(futureResultType && "No future?!");
3871-
result = IGF.Builder.CreateCall(
3870+
3871+
// If there is a task group, emit a task group option structure to contain
3872+
// it.
3873+
if (taskGroup) {
3874+
TaskOptionRecordFlags optionsFlags(TaskOptionRecordKind::TaskGroup);
3875+
llvm::Value *optionsFlagsVal = llvm::ConstantInt::get(
3876+
IGF.IGM.SizeTy, optionsFlags.getOpaqueValue());
3877+
3878+
auto optionsRecord = IGF.createAlloca(
3879+
IGF.IGM.SwiftTaskGroupTaskOptionRecordTy, Alignment(),
3880+
"task_group_options");
3881+
auto optionsBaseRecord = IGF.Builder.CreateStructGEP(
3882+
optionsRecord, 0, Size());
3883+
IGF.Builder.CreateStore(
3884+
optionsFlagsVal,
3885+
IGF.Builder.CreateStructGEP(optionsBaseRecord, 0, Size()));
3886+
IGF.Builder.CreateStore(
3887+
taskOptions, IGF.Builder.CreateStructGEP(optionsBaseRecord, 1, Size()));
3888+
3889+
IGF.Builder.CreateStore(
3890+
taskGroup, IGF.Builder.CreateStructGEP(optionsRecord, 1, Size()));
3891+
taskOptions = IGF.Builder.CreateBitOrPointerCast(
3892+
optionsRecord.getAddress(), IGF.IGM.SwiftTaskOptionRecordPtrTy);
3893+
}
3894+
3895+
assert(futureResultType && "no future?!");
3896+
llvm::CallInst *result = IGF.Builder.CreateCall(
38723897
IGF.IGM.getTaskCreateFn(),
38733898
{flags,
38743899
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
@@ -754,6 +754,7 @@ BUILTIN_OPERAND_OWNERSHIP(ForwardingConsume, COWBufferForReading)
754754
BUILTIN_OPERAND_OWNERSHIP(ForwardingConsume, UnsafeGuaranteed)
755755

756756
const int PARAMETER_INDEX_CREATE_ASYNC_TASK_FUTURE_FUNCTION = 3;
757+
const int PARAMETER_INDEX_CREATE_ASYNC_TASK_GROUP_FUTURE_FUNCTION = 3;
757758

758759
OperandOwnership
759760
OperandOwnershipBuiltinClassifier::visitCreateAsyncTask(BuiltinInst *bi,
@@ -769,6 +770,20 @@ OperandOwnershipBuiltinClassifier::visitCreateAsyncTask(BuiltinInst *bi,
769770
return OperandOwnership::InteriorPointer;
770771
}
771772

773+
OperandOwnership
774+
OperandOwnershipBuiltinClassifier::visitCreateAsyncTaskInGroup(BuiltinInst *bi,
775+
StringRef attr) {
776+
// The function operand is consumed by the new task.
777+
if (&op == &bi->getOperandRef(PARAMETER_INDEX_CREATE_ASYNC_TASK_GROUP_FUTURE_FUNCTION))
778+
return OperandOwnership::DestroyingConsume;
779+
780+
// FIXME: These are considered InteriorPointer because they may propagate a
781+
// pointer into a borrowed values. If they do not propagate an interior pointer,
782+
// then they should be InstantaneousUse instead and should not require a
783+
// guaranteed value.
784+
return OperandOwnership::InteriorPointer;
785+
}
786+
772787
OperandOwnership OperandOwnershipBuiltinClassifier::
773788
visitResumeNonThrowingContinuationReturning(BuiltinInst *bi, StringRef attr) {
774789
// The value operand is consumed.

0 commit comments

Comments
 (0)