Skip to content

Commit 6798ed1

Browse files
authored
Merge pull request swiftlang#34627 from DougGregor/create-async-task-builtin
[Concurrency] Implement a builtin createAsyncTask() to create a new task
2 parents cdfff19 + d038989 commit 6798ed1

File tree

16 files changed

+178
-7
lines changed

16 files changed

+178
-7
lines changed

include/swift/AST/Builtins.def

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -728,6 +728,13 @@ BUILTIN_MISC_OPERATION_WITH_SILGEN(GetCurrentAsyncTask, "getCurrentAsyncTask", "
728728
/// Cancel the given asynchronous task.
729729
BUILTIN_MISC_OPERATION_WITH_SILGEN(CancelAsyncTask, "cancelAsyncTask", "", Special)
730730

731+
/// createAsyncTask(): (
732+
/// Int, Builtin.NativeObject?, @escaping () async throws -> Void
733+
/// ) -> Builtin.NativeObject
734+
///
735+
/// Create a new asynchronous task, given flags, an (optional) parent task, and
736+
/// a function to execute.
737+
BUILTIN_MISC_OPERATION_WITH_SILGEN(CreateAsyncTask, "createAsyncTask", "", Special)
731738

732739
/// globalStringTablePointer has type String -> Builtin.RawPointer.
733740
/// It returns an immortal, global string table pointer for strings constructed

include/swift/AST/Builtins.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,11 @@ llvm::AtomicOrdering decodeLLVMAtomicOrdering(StringRef O);
135135
/// Returns true if the builtin with ID \p ID has a defined static overload for
136136
/// the type \p Ty.
137137
bool canBuiltinBeOverloadedForType(BuiltinValueKind ID, Type Ty);
138+
139+
/// Retrieve the AST-level AsyncTaskAndContext type, used for the
140+
/// createAsyncTask builtin.
141+
Type getAsyncTaskAndContextType(ASTContext &ctx);
142+
138143
}
139144

140145
#endif

include/swift/Runtime/RuntimeFunctions.def

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1489,14 +1489,24 @@ FUNCTION(TaskDealloc,
14891489
ARGS(SwiftTaskPtrTy, Int8PtrTy),
14901490
ATTRS(NoUnwind, ArgMemOnly))
14911491

1492-
// void swift_task_dealloc(AsyncTask *task, void *ptr);
1492+
// void swift_task_cancel(AsyncTask *task);
14931493
FUNCTION(TaskCancel,
14941494
swift_task_cancel, SwiftCC,
14951495
ConcurrencyAvailability,
14961496
RETURNS(VoidTy),
14971497
ARGS(SwiftTaskPtrTy),
14981498
ATTRS(NoUnwind, ArgMemOnly))
14991499

1500+
// AsyncTaskAndContext swift_task_create_f(
1501+
// size_t flags, AsyncTask *task, AsyncFunctionType<void()> *function,
1502+
// size_t initialContextSize);
1503+
FUNCTION(TaskCreateFunc,
1504+
swift_task_create_f, SwiftCC,
1505+
ConcurrencyAvailability,
1506+
RETURNS(AsyncTaskAndContextTy),
1507+
ARGS(SizeTy, SwiftTaskPtrTy, TaskContinuationFunctionPtrTy, SizeTy),
1508+
ATTRS(NoUnwind, ArgMemOnly))
1509+
15001510
#undef RETURNS
15011511
#undef ARGS
15021512
#undef ATTRS

lib/AST/Builtins.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1350,6 +1350,25 @@ static ValueDecl *getCancelAsyncTask(ASTContext &ctx, Identifier id) {
13501350
id, { ctx.TheNativeObjectType }, ctx.TheEmptyTupleType);
13511351
}
13521352

1353+
Type swift::getAsyncTaskAndContextType(ASTContext &ctx) {
1354+
TupleTypeElt resultTupleElements[2] = {
1355+
ctx.TheNativeObjectType, // task,
1356+
ctx.TheRawPointerType // initial context
1357+
};
1358+
1359+
return TupleType::get(resultTupleElements, ctx);
1360+
}
1361+
1362+
static ValueDecl *getCreateAsyncTask(ASTContext &ctx, Identifier id) {
1363+
auto extInfo = ASTExtInfoBuilder().withAsync().withThrows().build();
1364+
return getBuiltinFunction(
1365+
id,
1366+
{ ctx.getIntDecl()->getDeclaredInterfaceType(),
1367+
OptionalType::get(ctx.TheNativeObjectType),
1368+
FunctionType::get({ }, ctx.TheEmptyTupleType, extInfo) },
1369+
getAsyncTaskAndContextType(ctx));
1370+
}
1371+
13531372
static ValueDecl *getPoundAssert(ASTContext &Context, Identifier Id) {
13541373
auto int1Type = BuiltinIntegerType::get(1, Context);
13551374
auto optionalRawPointerType = BoundGenericEnumType::get(
@@ -2482,6 +2501,9 @@ ValueDecl *swift::getBuiltinValueDecl(ASTContext &Context, Identifier Id) {
24822501
case BuiltinValueKind::CancelAsyncTask:
24832502
return getCancelAsyncTask(Context, Id);
24842503

2504+
case BuiltinValueKind::CreateAsyncTask:
2505+
return getCreateAsyncTask(Context, Id);
2506+
24852507
case BuiltinValueKind::PoundAssert:
24862508
return getPoundAssert(Context, Id);
24872509

lib/IRGen/GenBuiltin.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,30 @@ void irgen::emitBuiltinCall(IRGenFunction &IGF, const BuiltinInfo &Builtin,
225225
return;
226226
}
227227

228+
if (Builtin.ID == BuiltinValueKind::CreateAsyncTask) {
229+
auto flags = args.claimNext();
230+
auto parentTask = args.claimNext();
231+
auto taskFunction = args.claimNext();
232+
auto taskContext = args.claimNext();
233+
234+
// FIXME: SIL treats the function/context parameter as "guaranteed", but
235+
// the runtime entry point assumes it is owned. Introduce an extra retain
236+
// of the context to balance things out.
237+
IGF.emitNativeStrongRetain(taskContext, IGF.getDefaultAtomicity());
238+
239+
auto newTaskAndContext = emitTaskCreate(
240+
IGF, flags, parentTask, taskFunction, taskContext);
241+
242+
// Cast back to NativeObject/RawPointer.
243+
auto newTask = IGF.Builder.CreateExtractValue(newTaskAndContext, { 0 });
244+
newTask = IGF.Builder.CreateBitCast(newTask, IGF.IGM.RefCountedPtrTy);
245+
auto newContext = IGF.Builder.CreateExtractValue(newTaskAndContext, { 1 });
246+
newContext = IGF.Builder.CreateBitCast(newContext, IGF.IGM.Int8PtrTy);
247+
out.add(newTask);
248+
out.add(newContext);
249+
return;
250+
}
251+
228252
// If this is an LLVM IR intrinsic, lower it to an intrinsic call.
229253
const IntrinsicInfo &IInfo = IGF.getSILModule().getIntrinsicInfo(FnId);
230254
llvm::Intrinsic::ID IID = IInfo.ID;

lib/IRGen/GenCall.cpp

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3466,8 +3466,52 @@ void irgen::emitTaskCancel(IRGenFunction &IGF, llvm::Value *task) {
34663466
auto *call = IGF.Builder.CreateCall(IGF.IGM.getTaskCancelFn(), {task});
34673467
call->setDoesNotThrow();
34683468
call->setCallingConv(IGF.IGM.SwiftCC);
3469-
call->addAttribute(llvm::AttributeList::FunctionIndex,
3470-
llvm::Attribute::ReadNone);
3469+
}
3470+
3471+
llvm::Value *irgen::emitTaskCreate(
3472+
IRGenFunction &IGF, llvm::Value *flags, llvm::Value *parentTask,
3473+
llvm::Value *taskFunction, llvm::Value *localContextInfo) {
3474+
parentTask = IGF.Builder.CreateBitOrPointerCast(
3475+
parentTask, IGF.IGM.SwiftTaskPtrTy);
3476+
taskFunction = IGF.Builder.CreateBitOrPointerCast(
3477+
taskFunction, IGF.IGM.TaskContinuationFunctionPtrTy);
3478+
3479+
// Determine the size of the async context for the closure.
3480+
// FIXME: If the task function comes in as an AsyncFunctionPointer, we might
3481+
// want to use swift_task_create instead of swift_task_create_f.
3482+
ASTContext &ctx = IGF.IGM.IRGen.SIL.getASTContext();
3483+
auto extInfo = ASTExtInfoBuilder().withAsync().withThrows().build();
3484+
auto taskFunctionType = FunctionType::get(
3485+
{ }, ctx.TheEmptyTupleType, extInfo);
3486+
CanSILFunctionType taskFunctionCanSILType =
3487+
IGF.IGM.getLoweredType(taskFunctionType).castTo<SILFunctionType>();
3488+
auto layout = getAsyncContextLayout(
3489+
IGF.IGM, taskFunctionCanSILType, taskFunctionCanSILType,
3490+
SubstitutionMap());
3491+
auto layoutSize = getAsyncContextSize(layout);
3492+
auto layoutSizeVal = llvm::ConstantInt::get(
3493+
IGF.IGM.SizeTy, layoutSize.getValue());
3494+
3495+
// Call the function.
3496+
auto *result = IGF.Builder.CreateCall(
3497+
IGF.IGM.getTaskCreateFuncFn(),
3498+
{ flags, parentTask, taskFunction, layoutSizeVal });
3499+
result->setDoesNotThrow();
3500+
result->setCallingConv(IGF.IGM.SwiftCC);
3501+
3502+
// Write the local context information into the initial context for the task.
3503+
if (layout.hasLocalContext()) {
3504+
// Dig out the initial context returned from task creation.
3505+
auto initialContext = IGF.Builder.CreateExtractValue(result, { 1 });
3506+
Address initialContextAddr = layout.emitCastTo(IGF, initialContext);
3507+
3508+
auto localContextLayout = layout.getLocalContextLayout();
3509+
auto localContextAddr = localContextLayout.project(
3510+
IGF, initialContextAddr, llvm::None);
3511+
IGF.Builder.CreateStore(localContextInfo, localContextAddr);
3512+
}
3513+
3514+
return result;
34713515
}
34723516

34733517
std::pair<Address, Size> irgen::emitAllocAsyncContext(IRGenFunction &IGF,

lib/IRGen/GenCall.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,12 @@ namespace irgen {
390390
void emitTaskDealloc(IRGenFunction &IGF, Address address, llvm::Value *size);
391391
void emitTaskCancel(IRGenFunction &IGF, llvm::Value *task);
392392

393+
/// Emit a class to swift_task_create[_f] with the given flags, parent task,
394+
/// and task function.
395+
llvm::Value *emitTaskCreate(
396+
IRGenFunction &IGF, llvm::Value *flags, llvm::Value *parentTask,
397+
llvm::Value *taskFunction, llvm::Value *localContextInfo);
398+
393399
/// Allocate task local storage for the specified layout but using the
394400
/// provided dynamic size. Allowing the size to be specified dynamically is
395401
/// necessary for applies of thick functions the sizes of whose async contexts

lib/IRGen/IRGenModule.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -602,6 +602,10 @@ IRGenModule::IRGenModule(IRGenerator &irgen,
602602
/*isVarArg*/ false);
603603
TaskContinuationFunctionPtrTy = TaskContinuationFunctionTy->getPointerTo();
604604

605+
AsyncTaskAndContextTy = createStructType(
606+
*this, "swift.async_task_and_context",
607+
{ SwiftTaskPtrTy, SwiftContextPtrTy });
608+
605609
DifferentiabilityWitnessTy = createStructType(
606610
*this, "swift.differentiability_witness", {Int8PtrTy, Int8PtrTy});
607611
}

lib/IRGen/IRGenModule.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -731,7 +731,7 @@ class IRGenModule {
731731
llvm::PointerType *SwiftExecutorPtrTy;
732732
llvm::FunctionType *TaskContinuationFunctionTy;
733733
llvm::PointerType *TaskContinuationFunctionPtrTy;
734-
734+
llvm::StructType *AsyncTaskAndContextTy;
735735
llvm::StructType *DifferentiabilityWitnessTy; // { i8*, i8* }
736736

737737
llvm::GlobalVariable *TheTrivialPropertyDescriptor = nullptr;

lib/SIL/IR/OperandOwnership.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -918,6 +918,7 @@ ANY_OWNERSHIP_BUILTIN(IntInstrprofIncrement)
918918
CONSTANT_OWNERSHIP_BUILTIN(Owned, LifetimeEnding, COWBufferForReading)
919919
CONSTANT_OWNERSHIP_BUILTIN(Owned, LifetimeEnding, UnsafeGuaranteed)
920920
CONSTANT_OWNERSHIP_BUILTIN(Guaranteed, NonLifetimeEnding, CancelAsyncTask)
921+
CONSTANT_OWNERSHIP_BUILTIN(Guaranteed, NonLifetimeEnding, CreateAsyncTask)
921922

922923
#undef CONSTANT_OWNERSHIP_BUILTIN
923924

0 commit comments

Comments
 (0)