Skip to content

Commit 8cd55ec

Browse files
committed
Turn swift_asyncLet_finish into a builtin.
Reflect the potential stack allocation of the begin/finish pair in SIL, which should prevent the optimizer from trying to move stack allocations around them. I'm not actually sold that the runtime *has* to do a stack allocation here, because it only really does it because it creates a result buffer in the future that it should be able to avoid. But it's undisputable that it currently does so, and we may come up with good reasons for it to continue to do so even if we remove the current allocation, so modeling the allocation is the right thing to do. Fixes rdar://109850951
1 parent 492a0a3 commit 8cd55ec

27 files changed

+184
-38
lines changed

include/swift/AST/Builtins.def

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -923,6 +923,12 @@ BUILTIN_MISC_OPERATION(FlowSensitiveSelfIsolation, "flowSensitiveSelfIsolation",
923923
BUILTIN_MISC_OPERATION(FlowSensitiveDistributedSelfIsolation,
924924
"flowSensitiveDistributedSelfIsolation", "", Special)
925925

926+
/// finishAsyncLet(Builtin.RawPointer, Builtin.RawPointer) -> Void
927+
///
928+
/// End the scope of an async let. An async operation. Deallocates stack
929+
/// memory that was allocated by startAsyncLetWithLocalBuffer.
930+
BUILTIN_MISC_OPERATION(FinishAsyncLet, "finishAsyncLet", "", Special)
931+
926932
/// endAsyncLetLifetime(): (Builtin.RawPointer) -> Void
927933
///
928934
/// Marks the end of an async-let's lifetime.

include/swift/AST/Builtins.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ enum class OverloadedBuiltinKind : uint8_t {
7777
};
7878

7979
/// BuiltinValueKind - The set of (possibly overloaded) builtin functions.
80-
enum class BuiltinValueKind {
80+
enum class BuiltinValueKind : unsigned {
8181
None = 0,
8282
#define BUILTIN(Id, Name, Attrs) Id,
8383
#include "swift/AST/Builtins.def"

include/swift/Runtime/RuntimeFunctions.def

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2534,6 +2534,28 @@ FUNCTION(AsyncLetBegin,
25342534
EFFECT(RuntimeEffect::Concurrency),
25352535
MEMEFFECTS(ArgMemOnly))
25362536

2537+
/// void swift_asyncLet_finish(
2538+
/// AsyncLet *alet,
2539+
/// TaskOptionRecord *options,
2540+
/// const Metadata *futureResultType,
2541+
/// void *closureEntryPoint,
2542+
/// HeapObject *closureContext,
2543+
/// void *resultBuffer
2544+
/// );
2545+
FUNCTION(AsyncLetFinish,
2546+
_Concurrency, swift_asyncLet_finish, SwiftAsyncCC,
2547+
ConcurrencyAvailability,
2548+
RETURNS(VoidTy),
2549+
ARGS(SwiftContextPtrTy, // current context
2550+
SwiftAsyncLetPtrTy, // AsyncLet*
2551+
Int8PtrTy, // resultBuffer
2552+
TaskContinuationFunctionPtrTy, // continuation
2553+
SwiftContextPtrTy // temp context
2554+
),
2555+
ATTRS(NoUnwind),
2556+
EFFECT(RuntimeEffect::Concurrency),
2557+
MEMEFFECTS(ArgMemOnly))
2558+
25372559
/// void swift_task_run_inline(
25382560
/// OpaqueValue *result,
25392561
/// void *closureAFP,

lib/AST/Builtins.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1759,6 +1759,12 @@ static ValueDecl *getStartAsyncLet(ASTContext &ctx, Identifier id) {
17591759
return builder.build(id);
17601760
}
17611761

1762+
static ValueDecl *getFinishAsyncLet(ASTContext &ctx, Identifier id) {
1763+
return getBuiltinFunction(ctx, id, _async(_thin),
1764+
_parameters(_rawPointer, _rawPointer),
1765+
_void);
1766+
}
1767+
17621768
static ValueDecl *getEndAsyncLet(ASTContext &ctx, Identifier id) {
17631769
return getBuiltinFunction(ctx, id, _thin,
17641770
_parameters(_rawPointer),
@@ -3392,6 +3398,9 @@ ValueDecl *swift::getBuiltinValueDecl(ASTContext &Context, Identifier Id) {
33923398
case BuiltinValueKind::StartAsyncLetWithLocalBuffer:
33933399
return getStartAsyncLet(Context, Id);
33943400

3401+
case BuiltinValueKind::FinishAsyncLet:
3402+
return getFinishAsyncLet(Context, Id);
3403+
33953404
case BuiltinValueKind::EndAsyncLetLifetime:
33963405
return getEndAsyncLet(Context, Id);
33973406

lib/IRGen/Callee.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ namespace llvm {
3030
}
3131

3232
namespace swift {
33+
enum class BuiltinValueKind : unsigned;
3334

3435
namespace irgen {
3536
class Callee;
@@ -571,6 +572,13 @@ namespace irgen {
571572
llvm::Value *firstData = nullptr,
572573
llvm::Value *secondData = nullptr);
573574

575+
static Callee forBuiltinRuntimeFunction(IRGenModule &IGM,
576+
llvm::Constant *fnPtr,
577+
BuiltinValueKind builtin,
578+
SubstitutionMap subs,
579+
FunctionPointerKind fpKind =
580+
FunctionPointerKind::Function);
581+
574582
SILFunctionTypeRepresentation getRepresentation() const {
575583
return Info.OrigFnType->getRepresentation();
576584
}

lib/IRGen/GenBuiltin.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,13 @@ void irgen::emitBuiltinCall(IRGenFunction &IGF, const BuiltinInfo &Builtin,
250250
return;
251251
}
252252

253+
if (Builtin.ID == BuiltinValueKind::FinishAsyncLet) {
254+
auto asyncLet = args.claimNext();
255+
auto resultBuffer = args.claimNext();
256+
emitFinishAsyncLet(IGF, asyncLet, resultBuffer);
257+
return;
258+
}
259+
253260
if (Builtin.ID == BuiltinValueKind::EndAsyncLetLifetime) {
254261
IGF.Builder.CreateLifetimeEnd(args.claimNext());
255262
// Ignore a second operand which is inserted by ClosureLifetimeFixup and

lib/IRGen/GenCall.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6596,6 +6596,32 @@ Callee irgen::getCFunctionPointerCallee(IRGenFunction &IGF,
65966596
return Callee(std::move(calleeInfo), fn);
65976597
}
65986598

6599+
Callee Callee::forBuiltinRuntimeFunction(IRGenModule &IGM,
6600+
llvm::Constant *fnPtr,
6601+
BuiltinValueKind builtin,
6602+
SubstitutionMap subs,
6603+
FunctionPointerKind fpKind) {
6604+
auto &ctx = IGM.Context;
6605+
auto builtinDecl =
6606+
getBuiltinValueDecl(ctx, ctx.getIdentifier(getBuiltinName(builtin)));
6607+
6608+
auto loweredFnType = IGM.getSILTypes().getConstantFunctionType(
6609+
TypeExpansionContext::minimal(),
6610+
SILDeclRef(builtinDecl, SILDeclRef::Kind::Func));
6611+
auto signature = IGM.getSignature(loweredFnType, fpKind);
6612+
6613+
auto fp = FunctionPointer::forDirect(fpKind, fnPtr, nullptr, signature);
6614+
6615+
auto substFnType = loweredFnType;
6616+
if (subs) {
6617+
substFnType = loweredFnType->substGenericArgs(IGM.getSILModule(), subs,
6618+
TypeExpansionContext::minimal());
6619+
}
6620+
CalleeInfo calleeInfo(loweredFnType, substFnType, subs);
6621+
6622+
return Callee(std::move(calleeInfo), fp);
6623+
}
6624+
65996625
FunctionPointer FunctionPointer::forDirect(IRGenModule &IGM,
66006626
llvm::Constant *fnPtr,
66016627
llvm::Constant *secondaryValue,

lib/IRGen/GenConcurrency.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "GenConcurrency.h"
1919

2020
#include "BitPatternBuilder.h"
21+
#include "CallEmission.h"
2122
#include "ExtraInhabitants.h"
2223
#include "GenCall.h"
2324
#include "GenPointerAuth.h"
@@ -312,6 +313,28 @@ llvm::Value *irgen::emitBuiltinStartAsyncLet(IRGenFunction &IGF,
312313
return alet;
313314
}
314315

316+
void irgen::emitFinishAsyncLet(IRGenFunction &IGF,
317+
llvm::Value *asyncLet,
318+
llvm::Value *resultBuffer) {
319+
llvm::Constant *function = IGF.IGM.getAsyncLetFinishFn();
320+
auto callee = Callee::forBuiltinRuntimeFunction(IGF.IGM, function,
321+
BuiltinValueKind::FinishAsyncLet, SubstitutionMap(),
322+
FunctionPointerKind::SpecialKind::AsyncLetFinish);
323+
auto emission = getCallEmission(IGF, nullptr, std::move(callee));
324+
325+
emission->begin();
326+
327+
Explosion args;
328+
args.add(asyncLet);
329+
args.add(resultBuffer);
330+
emission->setArgs(args, /*outlined*/ false, /*witness metadata*/ nullptr);
331+
332+
Explosion result;
333+
emission->emitToExplosion(result, false);
334+
335+
emission->end();
336+
}
337+
315338
llvm::Value *irgen::emitCreateTaskGroup(IRGenFunction &IGF,
316339
SubstitutionMap subs,
317340
llvm::Value *groupFlags) {

lib/IRGen/GenConcurrency.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,11 @@ llvm::Value *emitBuiltinStartAsyncLet(IRGenFunction &IGF,
7878
llvm::Value *resultBuffer,
7979
SubstitutionMap subs);
8080

81+
/// Emit the finishAsyncLet builtin.
82+
void emitFinishAsyncLet(IRGenFunction &IGF,
83+
llvm::Value *asyncLet,
84+
llvm::Value *resultBuffer);
85+
8186
/// Emit the createTaskGroup builtin.
8287
llvm::Value *emitCreateTaskGroup(IRGenFunction &IGF, SubstitutionMap subs,
8388
llvm::Value *groupFlags);

lib/SIL/IR/OperandOwnership.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -933,6 +933,7 @@ BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, GetEnumTag)
933933
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, InjectEnumTag)
934934
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, DistributedActorAsAnyActor)
935935
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, AddressOfRawLayout)
936+
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, FinishAsyncLet)
936937
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, EndAsyncLetLifetime)
937938
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, CreateTaskGroup)
938939
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, CreateTaskGroupWithFlags)

0 commit comments

Comments
 (0)