Skip to content

Commit cd8029a

Browse files
authored
Merge pull request #34759 from DougGregor/concurrency-future-builtin
[Concurrency] Add Builtin.createAsyncTaskFuture and implement runDetached on it
2 parents 094ca80 + 2a41920 commit cd8029a

File tree

14 files changed

+319
-27
lines changed

14 files changed

+319
-27
lines changed

include/swift/AST/Builtins.def

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -736,6 +736,15 @@ BUILTIN_MISC_OPERATION_WITH_SILGEN(CancelAsyncTask, "cancelAsyncTask", "", Speci
736736
/// a function to execute.
737737
BUILTIN_MISC_OPERATION_WITH_SILGEN(CreateAsyncTask, "createAsyncTask", "", Special)
738738

739+
/// createAsyncTaskFuture(): (
740+
/// Int, Builtin.NativeObject?, @escaping () async throws -> T
741+
/// ) -> Builtin.NativeObject
742+
///
743+
/// Create a new asynchronous task future, given flags, an (optional) parent
744+
/// task and a function to execute.
745+
BUILTIN_MISC_OPERATION_WITH_SILGEN(CreateAsyncTaskFuture,
746+
"createAsyncTaskFuture", "", Special)
747+
739748
/// globalStringTablePointer has type String -> Builtin.RawPointer.
740749
/// It returns an immortal, global string table pointer for strings constructed
741750
/// from string literals. We consider it effects as readnone meaning that it

include/swift/Runtime/RuntimeFunctions.def

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1506,6 +1506,17 @@ FUNCTION(TaskCreateFunc,
15061506
ARGS(SizeTy, SwiftTaskPtrTy, AsyncFunctionPointerPtrTy),
15071507
ATTRS(NoUnwind, ArgMemOnly))
15081508

1509+
// AsyncTaskAndContext swift_task_create_future(
1510+
// size_t flags, AsyncTask *task, const Metadata *futureResultType,
1511+
// AsyncFunctionPointer *function);
1512+
FUNCTION(TaskCreateFutureFunc,
1513+
swift_task_create_future, SwiftCC,
1514+
ConcurrencyAvailability,
1515+
RETURNS(AsyncTaskAndContextTy),
1516+
ARGS(SizeTy, SwiftTaskPtrTy, TypeMetadataPtrTy,
1517+
AsyncFunctionPointerPtrTy),
1518+
ATTRS(NoUnwind, ArgMemOnly))
1519+
15091520
#undef RETURNS
15101521
#undef ARGS
15111522
#undef ATTRS

lib/AST/Builtins.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1369,6 +1369,20 @@ static ValueDecl *getCreateAsyncTask(ASTContext &ctx, Identifier id) {
13691369
getAsyncTaskAndContextType(ctx));
13701370
}
13711371

1372+
static ValueDecl *getCreateAsyncTaskFuture(ASTContext &ctx, Identifier id) {
1373+
BuiltinFunctionBuilder builder(ctx);
1374+
auto genericParam = makeGenericParam().build(builder);
1375+
builder.addParameter(
1376+
makeConcrete(ctx.getIntDecl()->getDeclaredInterfaceType()));
1377+
builder.addParameter(
1378+
makeConcrete(OptionalType::get(ctx.TheNativeObjectType)));
1379+
auto extInfo = ASTExtInfoBuilder().withAsync().withThrows().build();
1380+
builder.addParameter(
1381+
makeConcrete(FunctionType::get({ }, genericParam, extInfo)));
1382+
builder.setResult(makeConcrete(getAsyncTaskAndContextType(ctx)));
1383+
return builder.build(id);
1384+
}
1385+
13721386
static ValueDecl *getPoundAssert(ASTContext &Context, Identifier Id) {
13731387
auto int1Type = BuiltinIntegerType::get(1, Context);
13741388
auto optionalRawPointerType = BoundGenericEnumType::get(
@@ -2504,6 +2518,9 @@ ValueDecl *swift::getBuiltinValueDecl(ASTContext &Context, Identifier Id) {
25042518
case BuiltinValueKind::CreateAsyncTask:
25052519
return getCreateAsyncTask(Context, Id);
25062520

2521+
case BuiltinValueKind::CreateAsyncTaskFuture:
2522+
return getCreateAsyncTaskFuture(Context, Id);
2523+
25072524
case BuiltinValueKind::PoundAssert:
25082525
return getPoundAssert(Context, Id);
25092526

lib/IRGen/GenBuiltin.cpp

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

228-
if (Builtin.ID == BuiltinValueKind::CreateAsyncTask) {
228+
if (Builtin.ID == BuiltinValueKind::CreateAsyncTask ||
229+
Builtin.ID == BuiltinValueKind::CreateAsyncTaskFuture) {
229230
auto flags = args.claimNext();
230231
auto parentTask = args.claimNext();
232+
auto futureResultType =
233+
(Builtin.ID == BuiltinValueKind::CreateAsyncTaskFuture)
234+
? args.claimNext()
235+
: nullptr;
231236
auto taskFunction = args.claimNext();
232237
auto taskContext = args.claimNext();
233238

@@ -237,7 +242,8 @@ void irgen::emitBuiltinCall(IRGenFunction &IGF, const BuiltinInfo &Builtin,
237242
IGF.emitNativeStrongRetain(taskContext, IGF.getDefaultAtomicity());
238243

239244
auto newTaskAndContext = emitTaskCreate(
240-
IGF, flags, parentTask, taskFunction, taskContext);
245+
IGF, flags, parentTask, futureResultType, taskFunction, taskContext,
246+
substitutions);
241247

242248
// Cast back to NativeObject/RawPointer.
243249
auto newTask = IGF.Builder.CreateExtractValue(newTaskAndContext, { 0 });
@@ -249,6 +255,7 @@ void irgen::emitBuiltinCall(IRGenFunction &IGF, const BuiltinInfo &Builtin,
249255
return;
250256
}
251257

258+
252259
// If this is an LLVM IR intrinsic, lower it to an intrinsic call.
253260
const IntrinsicInfo &IInfo = IGF.getSILModule().getIntrinsicInfo(FnId);
254261
llvm::Intrinsic::ID IID = IInfo.ID;

lib/IRGen/GenCall.cpp

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3595,7 +3595,9 @@ void irgen::emitTaskCancel(IRGenFunction &IGF, llvm::Value *task) {
35953595

35963596
llvm::Value *irgen::emitTaskCreate(
35973597
IRGenFunction &IGF, llvm::Value *flags, llvm::Value *parentTask,
3598-
llvm::Value *taskFunction, llvm::Value *localContextInfo) {
3598+
llvm::Value *futureResultType,
3599+
llvm::Value *taskFunction, llvm::Value *localContextInfo,
3600+
SubstitutionMap subs) {
35993601
parentTask = IGF.Builder.CreateBitOrPointerCast(
36003602
parentTask, IGF.IGM.SwiftTaskPtrTy);
36013603
taskFunction = IGF.Builder.CreateBitOrPointerCast(
@@ -3604,18 +3606,34 @@ llvm::Value *irgen::emitTaskCreate(
36043606
// Determine the size of the async context for the closure.
36053607
ASTContext &ctx = IGF.IGM.IRGen.SIL.getASTContext();
36063608
auto extInfo = ASTExtInfoBuilder().withAsync().withThrows().build();
3607-
auto taskFunctionType = FunctionType::get(
3608-
{ }, ctx.TheEmptyTupleType, extInfo);
3609+
AnyFunctionType *taskFunctionType;
3610+
if (futureResultType) {
3611+
auto genericParam = GenericTypeParamType::get(0, 0, ctx);
3612+
auto genericSig = GenericSignature::get({genericParam}, {});
3613+
taskFunctionType = GenericFunctionType::get(
3614+
genericSig, { }, genericParam, extInfo);
3615+
3616+
taskFunctionType = Type(taskFunctionType).subst(subs)->castTo<FunctionType>();
3617+
} else {
3618+
taskFunctionType = FunctionType::get(
3619+
{ }, ctx.TheEmptyTupleType, extInfo);
3620+
}
36093621
CanSILFunctionType taskFunctionCanSILType =
36103622
IGF.IGM.getLoweredType(taskFunctionType).castTo<SILFunctionType>();
36113623
auto layout = getAsyncContextLayout(
3612-
IGF.IGM, taskFunctionCanSILType, taskFunctionCanSILType,
3613-
SubstitutionMap());
3624+
IGF.IGM, taskFunctionCanSILType, taskFunctionCanSILType, subs);
36143625

36153626
// Call the function.
3616-
auto *result = IGF.Builder.CreateCall(
3627+
llvm::CallInst *result;
3628+
if (futureResultType) {
3629+
result = IGF.Builder.CreateCall(
3630+
IGF.IGM.getTaskCreateFutureFuncFn(),
3631+
{ flags, parentTask, futureResultType, taskFunction });
3632+
} else {
3633+
result = IGF.Builder.CreateCall(
36173634
IGF.IGM.getTaskCreateFuncFn(),
36183635
{ flags, parentTask, taskFunction });
3636+
}
36193637
result->setDoesNotThrow();
36203638
result->setCallingConv(IGF.IGM.SwiftCC);
36213639

lib/IRGen/GenCall.h

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -399,11 +399,16 @@ namespace irgen {
399399

400400
void emitTaskCancel(IRGenFunction &IGF, llvm::Value *task);
401401

402-
/// Emit a class to swift_task_create[_f] with the given flags, parent task,
403-
/// and task function.
402+
/// Emit a class to swift_task_create[_f] or swift_task_create_future[__f]
403+
/// with the given flags, parent task, and task function.
404+
///
405+
/// When \c futureResultType is non-null, calls the future variant to create
406+
/// a future.
404407
llvm::Value *emitTaskCreate(
405408
IRGenFunction &IGF, llvm::Value *flags, llvm::Value *parentTask,
406-
llvm::Value *taskFunction, llvm::Value *localContextInfo);
409+
llvm::Value *futureResultType,
410+
llvm::Value *taskFunction, llvm::Value *localContextInfo,
411+
SubstitutionMap subs);
407412

408413
/// Allocate task local storage for the provided dynamic size.
409414
Address emitAllocAsyncContext(IRGenFunction &IGF, llvm::Value *sizeValue);

lib/SIL/IR/OperandOwnership.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -879,6 +879,7 @@ CONSTANT_OWNERSHIP_BUILTIN(Owned, LifetimeEnding, COWBufferForReading)
879879
CONSTANT_OWNERSHIP_BUILTIN(Owned, LifetimeEnding, UnsafeGuaranteed)
880880
CONSTANT_OWNERSHIP_BUILTIN(Guaranteed, NonLifetimeEnding, CancelAsyncTask)
881881
CONSTANT_OWNERSHIP_BUILTIN(Guaranteed, NonLifetimeEnding, CreateAsyncTask)
882+
CONSTANT_OWNERSHIP_BUILTIN(Guaranteed, NonLifetimeEnding, CreateAsyncTaskFuture)
882883

883884
#undef CONSTANT_OWNERSHIP_BUILTIN
884885

lib/SIL/IR/ValueOwnership.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -544,6 +544,7 @@ CONSTANT_OWNERSHIP_BUILTIN(None, GlobalStringTablePointer)
544544
CONSTANT_OWNERSHIP_BUILTIN(Owned, GetCurrentAsyncTask)
545545
CONSTANT_OWNERSHIP_BUILTIN(None, CancelAsyncTask)
546546
CONSTANT_OWNERSHIP_BUILTIN(Owned, CreateAsyncTask)
547+
CONSTANT_OWNERSHIP_BUILTIN(Owned, CreateAsyncTaskFuture)
547548

548549
#undef CONSTANT_OWNERSHIP_BUILTIN
549550

lib/SIL/Utils/MemAccessUtils.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1803,6 +1803,7 @@ static void visitBuiltinAddress(BuiltinInst *builtin,
18031803
case BuiltinValueKind::TSanInoutAccess:
18041804
case BuiltinValueKind::CancelAsyncTask:
18051805
case BuiltinValueKind::CreateAsyncTask:
1806+
case BuiltinValueKind::CreateAsyncTaskFuture:
18061807
return;
18071808

18081809
// General memory access to a pointer in first operand position.

lib/SILGen/SILGenBuiltin.cpp

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1430,11 +1430,45 @@ static ManagedValue emitBuiltinCreateAsyncTask(
14301430
auto apply = SGF.B.createBuiltin(
14311431
loc,
14321432
ctx.getIdentifier(getBuiltinName(BuiltinValueKind::CreateAsyncTask)),
1433-
SGF.getLoweredType(getAsyncTaskAndContextType(ctx)), SubstitutionMap(),
1433+
SGF.getLoweredType(getAsyncTaskAndContextType(ctx)), subs,
14341434
{ flags, parentTask, function });
14351435
return SGF.emitManagedRValueWithCleanup(apply);
14361436
}
14371437

1438+
// Emit SIL for the named builtin: createAsyncTaskFuture.
1439+
static ManagedValue emitBuiltinCreateAsyncTaskFuture(
1440+
SILGenFunction &SGF, SILLocation loc, SubstitutionMap subs,
1441+
ArrayRef<ManagedValue> args, SGFContext C) {
1442+
ASTContext &ctx = SGF.getASTContext();
1443+
auto flags = args[0].forward(SGF);
1444+
auto parentTask = args[1].borrow(SGF, loc).forward(SGF);
1445+
1446+
// Form the metatype of the result type.
1447+
CanType futureResultType =
1448+
Type(
1449+
MetatypeType::get(GenericTypeParamType::get(0, 0, SGF.getASTContext())))
1450+
.subst(subs)->getCanonicalType();
1451+
CanType anyTypeType = ExistentialMetatypeType::get(
1452+
ProtocolCompositionType::get(ctx, { }, false))->getCanonicalType();
1453+
auto &anyTypeTL = SGF.getTypeLowering(anyTypeType);
1454+
auto &futureResultTL = SGF.getTypeLowering(futureResultType);
1455+
auto futureResultMetadata = SGF.emitExistentialErasure(
1456+
loc, futureResultType, futureResultTL, anyTypeTL, { }, C,
1457+
[&](SGFContext C) -> ManagedValue {
1458+
return ManagedValue::forTrivialObjectRValue(
1459+
SGF.B.createMetatype(loc, SGF.getLoweredType(futureResultType)));
1460+
}).borrow(SGF, loc).forward(SGF);
1461+
1462+
auto function = args[2].borrow(SGF, loc).forward(SGF);
1463+
auto apply = SGF.B.createBuiltin(
1464+
loc,
1465+
ctx.getIdentifier(
1466+
getBuiltinName(BuiltinValueKind::CreateAsyncTaskFuture)),
1467+
SGF.getLoweredType(getAsyncTaskAndContextType(ctx)), subs,
1468+
{ flags, parentTask, futureResultMetadata, function });
1469+
return SGF.emitManagedRValueWithCleanup(apply);
1470+
}
1471+
14381472
Optional<SpecializedEmitter>
14391473
SpecializedEmitter::forDecl(SILGenModule &SGM, SILDeclRef function) {
14401474
// Only consider standalone declarations in the Builtin module.

lib/SILOptimizer/Transforms/AccessEnforcementReleaseSinking.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ static bool isBarrier(SILInstruction *inst) {
167167
case BuiltinValueKind::UnsafeGuaranteedEnd:
168168
case BuiltinValueKind::CancelAsyncTask:
169169
case BuiltinValueKind::CreateAsyncTask:
170+
case BuiltinValueKind::CreateAsyncTaskFuture:
170171
return true;
171172
}
172173
}

0 commit comments

Comments
 (0)