Skip to content

SIL: Add instructions to represent async suspend points. #34142

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 2, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions include/swift/AST/ASTContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -499,13 +499,13 @@ class ASTContext final {
/// Retrieve the type Swift.Never.
CanType getNeverType() const;

#define KNOWN_OBJC_TYPE_DECL(MODULE, NAME, DECL_CLASS) \
#define KNOWN_SDK_TYPE_DECL(MODULE, NAME, DECL_CLASS, NUM_GENERIC_PARAMS) \
/** Retrieve the declaration of MODULE.NAME. */ \
DECL_CLASS *get##NAME##Decl() const; \
\
/** Retrieve the type of MODULE.NAME. */ \
Type get##NAME##Type() const;
#include "swift/AST/KnownObjCTypes.def"
#include "swift/AST/KnownSDKTypes.def"

// Declare accessors for the known declarations.
#define FUNC_DECL(Name, Id) \
Expand Down
37 changes: 0 additions & 37 deletions include/swift/AST/KnownObjCTypes.def

This file was deleted.

43 changes: 43 additions & 0 deletions include/swift/AST/KnownSDKTypes.def
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
//===--- KnownSDKTypes.def - Common SDK types -----------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2019 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This xmacro generates code for common SDK types the
// compiler has special knowledge of.
//
//===----------------------------------------------------------------------===//

#ifndef KNOWN_SDK_TYPE_DECL
/// KNOWN_SDK_TYPE_DECL(MODULE, NAME, DECL_CLASS, NUM_GENERIC_ARGS)
///
/// The macro is expanded for each known SDK type. MODULE is
/// bound to the name of the module the type comes from. NAME is bound to the
/// unqualified name of the type. DECL_CLASS is bound to the Decl subclass it
/// is expected to be an instance of. NUM_GENERIC_ARGS is the number of generic
/// parameters the decl ought to have.
#define KNOWN_SDK_TYPE_DECL(MODULE, NAME, DECL_CLASS, NUM_GENERIC_ARGS)
#endif

KNOWN_SDK_TYPE_DECL(Foundation, NSCopying, ProtocolDecl, 0)
KNOWN_SDK_TYPE_DECL(Foundation, NSError, ClassDecl, 0)
KNOWN_SDK_TYPE_DECL(Foundation, NSNumber, ClassDecl, 0)
KNOWN_SDK_TYPE_DECL(Foundation, NSValue, ClassDecl, 0)

KNOWN_SDK_TYPE_DECL(ObjectiveC, NSObject, ClassDecl, 0)
KNOWN_SDK_TYPE_DECL(ObjectiveC, Selector, StructDecl, 0)
KNOWN_SDK_TYPE_DECL(ObjectiveC, ObjCBool, StructDecl, 0)

// TODO(async): These might move to the stdlib module when concurrency is
// standardized
KNOWN_SDK_TYPE_DECL(Concurrency, UnsafeContinuation, NominalTypeDecl, 1)
KNOWN_SDK_TYPE_DECL(Concurrency, UnsafeThrowingContinuation, NominalTypeDecl, 1)

#undef KNOWN_SDK_TYPE_DECL
26 changes: 25 additions & 1 deletion include/swift/SIL/SILBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -1934,6 +1934,20 @@ class SILBuilder {
getSILDebugLocation(Loc), Operand, Index));
}

GetAsyncContinuationInst *createGetAsyncContinuation(SILLocation Loc,
SILType ContinuationTy) {
return insert(new (getModule()) GetAsyncContinuationInst(getSILDebugLocation(Loc),
ContinuationTy));
}

GetAsyncContinuationAddrInst *createGetAsyncContinuationAddr(SILLocation Loc,
SILValue Operand,
SILType ContinuationTy) {
return insert(new (getModule()) GetAsyncContinuationAddrInst(getSILDebugLocation(Loc),
Operand,
ContinuationTy));
}

//===--------------------------------------------------------------------===//
// Terminator SILInstruction Creation Methods
//===--------------------------------------------------------------------===//
Expand Down Expand Up @@ -1964,7 +1978,17 @@ class SILBuilder {
YieldInst::create(getSILDebugLocation(loc), yieldedValues,
resumeBB, unwindBB, getFunction()));
}


AwaitAsyncContinuationInst *createAwaitAsyncContinuation(SILLocation loc,
SILValue continuation,
SILBasicBlock *resumeBB,
SILBasicBlock *errorBB) {
return insertTerminator(
new (getModule()) AwaitAsyncContinuationInst(getSILDebugLocation(loc),
continuation,
resumeBB, errorBB));
}

CondBranchInst *
createCondBranch(SILLocation Loc, SILValue Cond, SILBasicBlock *Target1,
SILBasicBlock *Target2,
Expand Down
35 changes: 35 additions & 0 deletions include/swift/SIL/SILCloner.h
Original file line number Diff line number Diff line change
Expand Up @@ -2928,6 +2928,41 @@ void SILCloner<ImplClass>::visitDifferentiabilityWitnessFunctionInst(
Inst->getWitnessKind(), Inst->getWitness()));
}

template <typename ImplClass>
void SILCloner<ImplClass>
::visitGetAsyncContinuationInst(GetAsyncContinuationInst *Inst) {
getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
recordClonedInstruction(Inst,
getBuilder().createGetAsyncContinuation(
getOpLocation(Inst->getLoc()),
getOpType(Inst->getType())));
}

template <typename ImplClass>
void SILCloner<ImplClass>
::visitGetAsyncContinuationAddrInst(GetAsyncContinuationAddrInst *Inst) {
getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
recordClonedInstruction(Inst,
getBuilder().createGetAsyncContinuationAddr(
getOpLocation(Inst->getLoc()),
getOpValue(Inst->getOperand()),
getOpType(Inst->getType())));
}

template <typename ImplClass>
void SILCloner<ImplClass>
::visitAwaitAsyncContinuationInst(AwaitAsyncContinuationInst *Inst) {
getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
recordClonedInstruction(Inst,
getBuilder().createAwaitAsyncContinuation(
getOpLocation(Inst->getLoc()),
getOpValue(Inst->getOperand()),
getOpBasicBlock(Inst->getResumeBB()),
Inst->getErrorBB()
? getOpBasicBlock(Inst->getErrorBB())
: nullptr));
}

} // end namespace swift

#endif
101 changes: 101 additions & 0 deletions include/swift/SIL/SILInstruction.h
Original file line number Diff line number Diff line change
Expand Up @@ -3039,6 +3039,60 @@ class KeyPathPattern final
}
};

/// Accesses the continuation for an async task, to prepare a primitive suspend operation.
/// The continuation must be consumed by an AwaitAsyncContinuation instruction locally,
/// and must dynamically be resumed exactly once during the program's ensuing execution.
class GetAsyncContinuationInst final
: public InstructionBase<SILInstructionKind::GetAsyncContinuationInst,
SingleValueInstruction>
{
friend SILBuilder;

GetAsyncContinuationInst(SILDebugLocation Loc,
SILType ContinuationTy)
: InstructionBase(Loc, ContinuationTy)
{}

public:

/// Get the type of the value the async task receives on a resume.
CanType getFormalResumeType() const;
SILType getLoweredResumeType() const;

/// True if the continuation can be used to resume the task by throwing an error.
bool throws() const;

ArrayRef<Operand> getAllOperands() const { return {}; }
MutableArrayRef<Operand> getAllOperands() { return {}; }
};

/// Accesses the continuation for an async task, to prepare a primitive suspend operation.
/// The continuation must be consumed by an AwaitAsyncContinuation instruction locally,
/// and must dynamically be resumed exactly once during the program's ensuing execution.
///
/// This variation of the instruction additionally takes an operand for the address of the
/// buffer that receives the incoming value when the continuation is resumed.
class GetAsyncContinuationAddrInst final
: public UnaryInstructionBase<SILInstructionKind::GetAsyncContinuationAddrInst,
SingleValueInstruction>
{
friend SILBuilder;
GetAsyncContinuationAddrInst(SILDebugLocation Loc,
SILValue Operand,
SILType ContinuationTy)
: UnaryInstructionBase(Loc, Operand, ContinuationTy)
{}

public:

/// Get the type of the value the async task receives on a resume.
CanType getFormalResumeType() const;
SILType getLoweredResumeType() const;

/// True if the continuation can be used to resume the task by throwing an error.
bool throws() const;
};

/// Instantiates a key path object.
class KeyPathInst final
: public InstructionBase<SILInstructionKind::KeyPathInst,
Expand Down Expand Up @@ -7231,6 +7285,7 @@ class TermInst : public NonValueInstruction {
case TermKind::DynamicMethodBranchInst:
case TermKind::CheckedCastAddrBranchInst:
case TermKind::CheckedCastValueBranchInst:
case TermKind::AwaitAsyncContinuationInst:
return false;
case TermKind::SwitchEnumInst:
case TermKind::CheckedCastBranchInst:
Expand Down Expand Up @@ -7326,6 +7381,52 @@ class UnwindInst
MutableArrayRef<Operand> getAllOperands() { return {}; }
};

/// Suspend execution of an async task until
/// essentially just a funny kind of return).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Half-written comment?

class AwaitAsyncContinuationInst final
: public UnaryInstructionBase<SILInstructionKind::AwaitAsyncContinuationInst,
TermInst>
{
friend SILBuilder;

std::array<SILSuccessor, 2> Successors;

AwaitAsyncContinuationInst(SILDebugLocation Loc, SILValue Continuation,
SILBasicBlock *resumeBB,
SILBasicBlock *errorBBOrNull)
: UnaryInstructionBase(Loc, Continuation),
Successors{{{this}, {this}}}
{
Successors[0] = resumeBB;
if (errorBBOrNull)
Successors[1] = errorBBOrNull;
}

public:
/// Returns the basic block to which control is transferred when the task is
/// resumed normally.
///
/// This basic block should take an argument of the continuation's resume type,
/// unless the continuation is formed by a \c GetAsyncContinuationAddrInst
/// that binds a specific memory location to receive the resume value.
SILBasicBlock *getResumeBB() const { return Successors[0].getBB(); }

/// Returns the basic block to which control is transferred when the task is
/// resumed in an error state, or `nullptr` if the continuation does not support
/// failure.
///
/// This basic block should take an argument of Error type.
SILBasicBlock *getErrorBB() const {
return Successors[1].getBB();
}

SuccessorListTy getSuccessors() {
if (getErrorBB())
return Successors;
return SuccessorListTy(Successors.data(), 1);
}
};

/// YieldInst - Yield control temporarily to the caller of this coroutine.
///
/// This is a terminator because the caller can abort the coroutine,
Expand Down
12 changes: 12 additions & 0 deletions include/swift/SIL/SILNodes.def
Original file line number Diff line number Diff line change
Expand Up @@ -713,6 +713,16 @@ ABSTRACT_VALUE_AND_INST(SingleValueInstruction, ValueBase, SILInstruction)
SINGLE_VALUE_INST(DifferentiabilityWitnessFunctionInst,
differentiability_witness_function,
SingleValueInstruction, None, DoesNotRelease)

// Async
// TODO: The side effects declarations on this instruction could likely
// be tightened, though we want to be careful that passes that try to do
// code motion or eliminate this instruction don't do so without awareness of
// its structural requirements.
SINGLE_VALUE_INST(GetAsyncContinuationInst, get_async_continuation,
SingleValueInstruction, MayHaveSideEffects, MayRelease)
SINGLE_VALUE_INST(GetAsyncContinuationAddrInst, get_async_continuation_addr,
SingleValueInstruction, MayHaveSideEffects, MayRelease)

// Key paths
// TODO: The only "side effect" is potentially retaining the returned key path
Expand Down Expand Up @@ -750,6 +760,8 @@ ABSTRACT_INST(TermInst, SILInstruction)
TermInst, MayRead, DoesNotRelease)
TERMINATOR(DynamicMethodBranchInst, dynamic_method_br,
TermInst, None, DoesNotRelease)
TERMINATOR(AwaitAsyncContinuationInst, await_async_continuation,
TermInst, MayHaveSideEffects, MayRelease)
DYNAMICCAST_TERMINATOR(CheckedCastBranchInst, checked_cast_br,
TermInst, None, DoesNotRelease)
DYNAMICCAST_TERMINATOR(CheckedCastAddrBranchInst, checked_cast_addr_br,
Expand Down
6 changes: 6 additions & 0 deletions include/swift/SILOptimizer/Utils/SCCVisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,12 @@ class SCCVisitor {
Operands.push_back(CBI->getFalseArgs()[Index]);
return;
}

case TermKind::AwaitAsyncContinuationInst: {
auto *AACI = cast<AwaitAsyncContinuationInst>(Term);
Operands.push_back(AACI->getOperand());
return;
}

case TermKind::SwitchEnumInst:
case TermKind::SwitchEnumAddrInst:
Expand Down
11 changes: 6 additions & 5 deletions lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -191,10 +191,10 @@ struct ASTContext::Implementation {
DECL_CLASS *NAME##Decl = nullptr;
#include "swift/AST/KnownStdlibTypes.def"

#define KNOWN_OBJC_TYPE_DECL(MODULE, NAME, DECL_CLASS) \
#define KNOWN_SDK_TYPE_DECL(MODULE, NAME, DECL_CLASS, NUM_GENERIC_PARAMS) \
/** The declaration of MODULE.NAME. */ \
DECL_CLASS *NAME##Decl = nullptr;
#include "swift/AST/KnownObjCTypes.def"
#include "swift/AST/KnownSDKTypes.def"

/// The declaration of '+' function for two RangeReplaceableCollection.
FuncDecl *PlusFunctionOnRangeReplaceableCollection = nullptr;
Expand Down Expand Up @@ -894,7 +894,7 @@ CanType ASTContext::getNeverType() const {
return neverDecl->getDeclaredInterfaceType()->getCanonicalType();
}

#define KNOWN_OBJC_TYPE_DECL(MODULE, NAME, DECLTYPE) \
#define KNOWN_SDK_TYPE_DECL(MODULE, NAME, DECLTYPE, GENERIC_ARGS) \
DECLTYPE *ASTContext::get##NAME##Decl() const { \
if (!getImpl().NAME##Decl) { \
if (ModuleDecl *M = getLoadedModule(Id_##MODULE)) { \
Expand All @@ -905,7 +905,8 @@ DECLTYPE *ASTContext::get##NAME##Decl() const { \
decls); \
if (decls.size() == 1 && isa<DECLTYPE>(decls[0])) { \
auto decl = cast<DECLTYPE>(decls[0]); \
if (isa<ProtocolDecl>(decl) || decl->getGenericParams() == nullptr) { \
if (isa<ProtocolDecl>(decl) \
|| (bool)decl->getGenericParams() == (bool)GENERIC_ARGS) { \
getImpl().NAME##Decl = decl; \
} \
} \
Expand All @@ -922,7 +923,7 @@ Type ASTContext::get##NAME##Type() const { \
return decl->getDeclaredInterfaceType(); \
}

#include "swift/AST/KnownObjCTypes.def"
#include "swift/AST/KnownSDKTypes.def"

ProtocolDecl *ASTContext::getProtocol(KnownProtocolKind kind) const {
// Check whether we've already looked for and cached this protocol.
Expand Down
Loading