Skip to content

Add begin_apply, abort_apply, and end_apply instructions to SIL #12894

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 3 commits into from
Nov 13, 2017
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
1 change: 1 addition & 0 deletions docs/ABI/Mangling.rst
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,7 @@ Types
type ::= 'BO' // Builtin.UnknownObject
type ::= 'Bo' // Builtin.NativeObject
type ::= 'Bp' // Builtin.RawPointer
type ::= 'Bt' // Builtin.SILToken
type ::= type 'Bv' NATURAL '_' // Builtin.Vec<n>x<type>
type ::= 'Bw' // Builtin.Word
type ::= function-signature 'c' // function type
Expand Down
101 changes: 100 additions & 1 deletion docs/SIL.rst
Original file line number Diff line number Diff line change
Expand Up @@ -604,7 +604,10 @@ Currently, a coroutine may not have normal results.

Coroutine functions may be used in many of the same ways as normal
function values. However, they cannot be called with the standard
``apply`` or ``try_apply`` instructions.
``apply`` or ``try_apply`` instructions. A non-throwing yield-once
coroutine can be called with the ``begin_apply`` instruction. There
is no support yet for calling a throwing yield-once coroutine or for
calling a yield-many coroutine of any kind.

Coroutines may contain the special ``yield`` and ``unwind`` instructions.

Expand Down Expand Up @@ -3137,6 +3140,102 @@ If the callee is generic, all of its generic parameters must be bound by the
given substitution list. The arguments and return value is
given with these generic substitutions applied.

begin_apply
```````````
::

sil-instruction ::= 'begin_apply' '[nothrow]'? sil-value
sil-apply-substitution-list?
'(' (sil-value (',' sil-value)*)? ')'
':' sil-type

(%anyAddr, %float, %token) = begin_apply %0() : $@yield_once () -> (@yields @inout %Any, @yields Float)
// %anyAddr : $*Any
// %float : $Float
// %token is a token

Transfers control to coroutine ``%0``, passing it the given arguments.
The rules for the application generally follow the rules for ``apply``,
except:

- the callee value must have a ``yield_once`` coroutine type,

- control returns to this function not when the coroutine performs a
``return``, but when it performs a ``yield`, and

- the instruction results are derived from the yields of the coroutine
instead of its normal results.

The final result of a ``begin_apply`` is a "token", a special value which
can only be used as the operand of an ``end_apply`` or ``abort_apply``
instruction. Before this second instruction is executed, the coroutine
is said to be "suspended", and the token represents a reference to its
suspended activation record.

The other results of the instruction correspond to the yields in the
coroutine type. In general, the rules of a yield are similar to the rules
for a parameter, interpreted as if the coroutine caller (the one
executing the ``begin_apply``) were being "called" by the ``yield``:

- If a yield has an indirect convention, the corresponding result will
have an address type; otherwise it has an object type. For example,
a result corresponding to an ``@in Any`` yield will have type ``$Any``.

- The convention attributes are the same as the parameter convention
attributes, interpreted as if the ``yield`` were the "call" and the
``begin_apply`` marked the entry to the "callee". For example,
an ``@in Any`` yield transferrs ownership of the ``Any`` value
reference from the coroutine to the caller, which must destroy
or move the value from that position before ending or aborting the
coroutine.

A ``begin_apply`` must be uniquely either ended or aborted before
exiting the function or looping to an earlier portion of the function.

When throwing coroutines are supported, there will need to be a
``try_begin_apply`` instruction.

abort_apply
```````````
::

sil-instruction ::= 'abort_apply' sil-value

abort_apply %token

Aborts the given coroutine activation, which is currently suspended at
a ``yield`` instruction. Transfers control to the coroutine and takes
the ``unwind`` path from the ``yield``. Control is transferred back
when the coroutine reaches an ``unwind`` instruction.

The operand must always be the token result of a ``begin_apply``
instruction, which is why it need not specify a type.

Throwing coroutines will not require a new instruction for aborting
a coroutine; a coroutine is not allowed to throw when it is being aborted.

end_apply
`````````
::

sil-instruction ::= 'end_apply' sil-value

end_apply %token

Ends the given coroutine activation, which is currently suspended at
a ``yield`` instruction. Transfers control to the coroutine and takes
the ``resume`` path from the ``yield``. Control is transferred back
when the coroutine reaches a ``return`` instruction.

The operand must always be the token result of a ``begin_apply``
instruction, which is why it need not specify a type.

``end_apply`` currently has no instruction results. If coroutines were
allowed to have normal results, they would be producted by ``end_apply``.

When throwing coroutines are supported, there will need to be a
``try_end_apply`` instruction.

partial_apply
`````````````
::
Expand Down
1 change: 1 addition & 0 deletions include/swift/AST/ASTContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -573,6 +573,7 @@ class ASTContext {
const CanType TheUnknownObjectType; /// Builtin.UnknownObject
const CanType TheRawPointerType; /// Builtin.RawPointer
const CanType TheUnsafeValueBufferType; /// Builtin.UnsafeValueBuffer
const CanType TheSILTokenType; /// Builtin.SILToken

const CanType TheIEEE32Type; /// 32-bit IEEE floating point
const CanType TheIEEE64Type; /// 64-bit IEEE floating point
Expand Down
1 change: 1 addition & 0 deletions include/swift/AST/TypeMatcher.h
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ class TypeMatcher {
TRIVIAL_CASE(BuiltinUnknownObjectType)
TRIVIAL_CASE(BuiltinUnsafeValueBufferType)
TRIVIAL_CASE(BuiltinVectorType)
TRIVIAL_CASE(SILTokenType)

bool visitTupleType(CanTupleType firstTuple, Type secondType,
Type sugaredFirstType) {
Expand Down
1 change: 1 addition & 0 deletions include/swift/AST/TypeNodes.def
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ ABSTRACT_TYPE(AnyFunction, Type)
ARTIFICIAL_TYPE(SILFunction, Type)
ARTIFICIAL_TYPE(SILBlockStorage, Type)
ARTIFICIAL_TYPE(SILBox, Type)
ARTIFICIAL_TYPE(SILToken, Type)
ABSTRACT_SUGARED_TYPE(SyntaxSugar, Type)
SUGARED_TYPE(ArraySlice, SyntaxSugarType)
SUGARED_TYPE(Optional, SyntaxSugarType)
Expand Down
18 changes: 17 additions & 1 deletion include/swift/AST/Types.h
Original file line number Diff line number Diff line change
Expand Up @@ -3797,7 +3797,23 @@ class SILBlockStorageType : public TypeBase {
}
};
DEFINE_EMPTY_CAN_TYPE_WRAPPER(SILBlockStorageType, Type)


/// A singleton 'token' type, which establishes a formal dependency
/// between two SIL nodes. A token 'value' cannot be abstracted in
/// SIL: it cannot be returned, yielded, or passed as a function or
/// block argument.
class SILTokenType final : public TypeBase {
friend class ASTContext;
SILTokenType(const ASTContext &C)
: TypeBase(TypeKind::SILToken, &C, RecursiveTypeProperties()) {}
public:
// The singleton instance of this type is ASTContext::TheSILTokenType.

static bool classof(const TypeBase *T) {
return T->getKind() == TypeKind::SILToken;
}
};
DEFINE_EMPTY_CAN_TYPE_WRAPPER(SILTokenType, Type)

/// A type with a special syntax that is always sugar for a library type.
///
Expand Down
19 changes: 19 additions & 0 deletions include/swift/SIL/SILBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,25 @@ class SILBuilder {
SpecializationInfo));
}

BeginApplyInst *createBeginApply(
SILLocation Loc, SILValue Fn, SubstitutionList Subs,
ArrayRef<SILValue> Args, bool isNonThrowing,
const GenericSpecializationInformation *SpecializationInfo = nullptr) {
return insert(BeginApplyInst::create(getSILDebugLocation(Loc), Fn, Subs,
Args, isNonThrowing, silConv, *F,
OpenedArchetypes, SpecializationInfo));
}

AbortApplyInst *createAbortApply(SILLocation loc, SILValue beginApply) {
return insert(new (getModule()) AbortApplyInst(getSILDebugLocation(loc),
beginApply));
}

EndApplyInst *createEndApply(SILLocation loc, SILValue beginApply) {
return insert(new (getModule()) EndApplyInst(getSILDebugLocation(loc),
beginApply));
}

BuiltinInst *createBuiltin(SILLocation Loc, Identifier Name, SILType ResultTy,
SubstitutionList Subs,
ArrayRef<SILValue> Args) {
Expand Down
33 changes: 33 additions & 0 deletions include/swift/SIL/SILCloner.h
Original file line number Diff line number Diff line change
Expand Up @@ -614,6 +614,39 @@ SILCloner<ImplClass>::visitPartialApplyInst(PartialApplyInst *Inst) {
getBuilder())));
}

template<typename ImplClass>
void
SILCloner<ImplClass>::visitBeginApplyInst(BeginApplyInst *Inst) {
auto Args = getOpValueArray<8>(Inst->getArguments());
getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
doPostProcess(Inst,
getBuilder().createBeginApply(getOpLocation(Inst->getLoc()),
getOpValue(Inst->getCallee()),
getOpSubstitutions(Inst->getSubstitutions()),
Args,
Inst->isNonThrowing(),
GenericSpecializationInformation::create(
Inst, getBuilder())));
}

template<typename ImplClass>
void
SILCloner<ImplClass>::visitAbortApplyInst(AbortApplyInst *Inst) {
getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
doPostProcess(Inst,
getBuilder().createAbortApply(getOpLocation(Inst->getLoc()),
getOpValue(Inst->getOperand())));
}

template<typename ImplClass>
void
SILCloner<ImplClass>::visitEndApplyInst(EndApplyInst *Inst) {
getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
doPostProcess(Inst,
getBuilder().createEndApply(getOpLocation(Inst->getLoc()),
getOpValue(Inst->getOperand())));
}

template<typename ImplClass>
void
SILCloner<ImplClass>::visitFunctionRefInst(FunctionRefInst *Inst) {
Expand Down
Loading