Merge pull request #12789 from rjmccall/sil-coroutines
diff --git a/docs/SIL.rst b/docs/SIL.rst
index a6753b4..5452e82 100644
--- a/docs/SIL.rst
+++ b/docs/SIL.rst
@@ -582,6 +582,43 @@
importer only imports non-native methods and types as ``throws``
when it is possible to do this automatically.
+Coroutine Types
+`````````````
+
+A coroutine is a function which can suspend itself and return control to
+its caller without terminating the function. That is, it does not need to
+obey a strict stack discipline.
+
+SIL supports two kinds of coroutine: ``@yield_many`` and ``@yield_once``.
+Either of these attributes may be written before a function type to
+indicate that it is a coroutine type.
+
+A coroutine type may declare any number of *yielded values*, which is to
+say, values which are provided to the caller at a yield point. Yielded
+values are written in the result list of a function type, prefixed by
+the ``@yields`` attribute. A yielded value may have a convention attribute,
+taken from the set of parameter attributes and interpreted as if the yield
+site were calling back to the calling function.
+
+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.
+
+Coroutines may contain the special ``yield`` and ``unwind`` instructions.
+
+A ``@yield_many`` coroutine may yield as many times as it desires.
+A ``@yield_once`` coroutine may yield exactly once before returning,
+although it may also ``throw`` before reaching that point.
+
+This coroutine representation is well-suited to coroutines whose control
+flow is tightly integrated with their callers and which intend to pass
+information back and forth. This matches the needs of generalized
+accessor and generator features in Swift. It is not a particularly good
+match for ``async``/``await``-style features; a simpler representation
+would probably do fine for that.
+
Properties of Types
```````````````````
@@ -4698,6 +4735,10 @@
resumes at the normal destination, and the value of the basic block argument
will be the operand of this ``return`` instruction.
+If the current function is a ``yield_once`` coroutine, there must not be
+a path from the entry block to a ``return`` which does not pass through
+a ``yield`` instruction. This rule does not apply in the ``raw`` SIL stage.
+
``return`` does not retain or release its operand or any other values.
A function must not contain more than one ``return`` instruction.
@@ -4713,7 +4754,7 @@
Exits the current function and returns control to the calling
function. The current function must have an error result, and so the
-function must have been invoked with a ``try_apply` instruction.
+function must have been invoked with a ``try_apply`` instruction.
Control will resume in the error destination of that instruction, and
the basic block argument will be the operand of the ``throw``.
@@ -4721,6 +4762,50 @@
A function must not contain more than one ``throw`` instruction.
+yield
+`````
+::
+
+ sil-terminator ::= 'yield' sil-yield-values
+ ',' 'resume' sil-identifier
+ ',' 'unwind' sil-identifier
+ sil-yield-values ::= sil-operand
+ sil-yield-values ::= '(' (sil-operand (',' sil-operand)*)? ')'
+
+Temporarily suspends the current function and provides the given
+values to the calling function. The current function must be a coroutine,
+and the yield values must match the yield types of the coroutine.
+If the calling function resumes the coroutine normally, control passes to
+the ``resume`` destination. If the calling function aborts the coroutine,
+control passes to the ``unwind`` destination.
+
+The ``resume`` and ``unwind`` destination blocks must be uniquely
+referenced by the ``yield`` instruction. This prevents them from becoming
+critical edges.
+
+In a ``yield_once`` coroutine, there must not be a control flow path leading
+from the ``resume`` edge to another ``yield`` instruction in this function.
+This rule does not apply in the ``raw`` SIL stage.
+
+There must not be a control flow path leading from the ``unwind`` edge to
+a ``return`` instruction, to a ``throw`` instruction, or to any block
+reachable from the entry block via a path that does not pass through
+an ``unwind`` edge. That is, the blocks reachable from ``unwind`` edges
+must jointly form a disjoint subfunction of the coroutine.
+
+unwind
+`````
+::
+
+ sil-terminator ::= 'unwind'
+
+Exits the current function and returns control to the calling function,
+completing an unwind from a ``yield``. The current function must be a
+coroutine.
+
+``unwind`` is only permitted in blocks reachable from the ``unwind`` edges
+of ``yield`` instructions.
+
br
``
::
diff --git a/include/swift/AST/Attr.def b/include/swift/AST/Attr.def
index c7629da..d9fc118 100644
--- a/include/swift/AST/Attr.def
+++ b/include/swift/AST/Attr.def
@@ -60,6 +60,9 @@
TYPE_ATTR(objc_metatype)
TYPE_ATTR(opened)
TYPE_ATTR(pseudogeneric)
+TYPE_ATTR(yields)
+TYPE_ATTR(yield_once)
+TYPE_ATTR(yield_many)
// SIL metatype attributes.
TYPE_ATTR(thin)
diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def
index a832920..e64b60b 100644
--- a/include/swift/AST/DiagnosticsSema.def
+++ b/include/swift/AST/DiagnosticsSema.def
@@ -3183,6 +3183,8 @@
"SIL function types cannot have labeled inputs", ())
ERROR(sil_function_output_label,PointsToFirstBadToken,
"SIL function types cannot have labeled results", ())
+ERROR(sil_non_coro_yields,PointsToFirstBadToken,
+ "non-coroutine SIL function types cannot have @yield results", ())
ERROR(sil_function_repeat_convention,PointsToFirstBadToken,
"repeated %select{parameter|result|callee}0 convention attribute",
(unsigned))
diff --git a/include/swift/AST/Types.h b/include/swift/AST/Types.h
index 10ca863..5663a15 100644
--- a/include/swift/AST/Types.h
+++ b/include/swift/AST/Types.h
@@ -319,8 +319,9 @@
unsigned ExtInfo : 16;
unsigned CalleeConvention : 3;
unsigned HasErrorResult : 1;
+ unsigned CoroutineKind : 2;
};
- enum { NumSILFunctionTypeBits = NumTypeBaseBits + 16+5 };
+ enum { NumSILFunctionTypeBits = NumTypeBaseBits + 16 + 6 };
static_assert(NumSILFunctionTypeBits <= 32, "fits in an unsigned");
struct AnyMetatypeTypeBitfields {
@@ -3175,6 +3176,42 @@
return !(*this == rhs);
}
};
+
+using YieldConvention = ParameterConvention;
+
+/// The type and convention of a value yielded from a yield-once or
+/// yield-many coroutine.
+class SILYieldInfo : public SILParameterInfo {
+public:
+ SILYieldInfo() {}
+ SILYieldInfo(CanType type, YieldConvention conv)
+ : SILParameterInfo(type, conv) {
+ }
+
+ SILYieldInfo getWithType(CanType type) const {
+ return SILYieldInfo(type, getConvention());
+ }
+
+ template<typename F>
+ SILYieldInfo map(const F &fn) const {
+ return getWithType(fn(getType()));
+ }
+};
+
+/// SILCoroutineKind - What kind of coroutine is this SILFunction?
+enum class SILCoroutineKind : uint8_t {
+ /// This function is not a coroutine. It may have arbitrary normal
+ /// results and may not have yield results.
+ None,
+
+ /// This function is a yield-once coroutine (used by e.g. accessors).
+ /// It must not have normal results and may have arbitrary yield results.
+ YieldOnce,
+
+ /// This function is a yield-many coroutine (used by e.g. generators).
+ /// It must not have normal results and may have arbitrary yield results.
+ YieldMany,
+};
class SILFunctionType;
typedef CanTypeWrapper<SILFunctionType> CanSILFunctionType;
@@ -3334,16 +3371,20 @@
private:
unsigned NumParameters;
- unsigned NumResults : 16; // Not including the ErrorResult.
- unsigned NumIndirectFormalResults : 16; // Subset of NumResults.
+
+ // These are *normal* results if this is not a coroutine and *yield* results
+ // otherwise.
+ unsigned NumAnyResults : 16; // Not including the ErrorResult.
+ unsigned NumAnyIndirectFormalResults : 16; // Subset of NumAnyResults.
// The layout of a SILFunctionType in memory is:
// SILFunctionType
// SILParameterInfo[NumParameters]
- // SILResultInfo[NumResults]
- // SILResultInfo? // if hasErrorResult()
- // CanType? // if NumResults > 1, formal result cache
- // CanType? // if NumResults > 1, all result cache
+ // SILResultInfo[isCoroutine() ? 0 : NumAnyResults]
+ // SILYieldInfo[isCoroutine() ? NumAnyResults : 0]
+ // SILResultInfo? // if hasErrorResult()
+ // CanType? // if !isCoro && NumAnyResults > 1, formal result cache
+ // CanType? // if !isCoro && NumAnyResults > 1, all result cache
CanGenericSignature GenericSig;
Optional<ProtocolConformanceRef> WitnessMethodConformance;
@@ -3354,48 +3395,74 @@
MutableArrayRef<SILResultInfo> getMutableResults() {
auto *ptr = reinterpret_cast<SILResultInfo *>(getMutableParameters().end());
- return MutableArrayRef<SILResultInfo>(ptr, getNumResults());
+ return {ptr, getNumResults()};
}
- SILResultInfo *getEndOfNormalResults() { return getMutableResults().end(); }
+ MutableArrayRef<SILYieldInfo> getMutableYields() {
+ auto *ptr = reinterpret_cast<SILYieldInfo *>(getMutableParameters().end());
+ return {ptr, getNumYields()};
+ }
+
+ /// Return a pointer past the end of the formal results, whether they
+ /// are yield-results or normal results.
+ void *getEndOfFormalResults() {
+ return isCoroutine() ? static_cast<void*>(getMutableYields().end())
+ : static_cast<void*>(getMutableResults().end());
+ }
SILResultInfo &getMutableErrorResult() {
assert(hasErrorResult());
- return *getEndOfNormalResults();
+ return *reinterpret_cast<SILResultInfo*>(getEndOfFormalResults());
}
- bool hasResultCache() const { return NumResults > 1; }
+ /// Return a pointer past the end of all of the results, including the
+ /// error result if one is present.
+ void *getEndOfAllResults() {
+ void *end = getEndOfFormalResults();
+ if (hasErrorResult())
+ end = reinterpret_cast<char*>(end) + sizeof(SILResultInfo);
+ return end;
+ }
+
+ /// Do we have slots for caches of the normal-result tuple type?
+ bool hasResultCache() const {
+ return NumAnyResults > 1 && !isCoroutine();
+ }
CanType &getMutableFormalResultsCache() const {
assert(hasResultCache());
- auto *ptr = const_cast<SILFunctionType *>(this)->getEndOfNormalResults()
- + size_t(hasErrorResult());
+ auto *ptr = const_cast<SILFunctionType *>(this)->getEndOfAllResults();
return *reinterpret_cast<CanType*>(ptr);
}
CanType &getMutableAllResultsCache() const {
assert(hasResultCache());
- auto *ptr = const_cast<SILFunctionType *>(this)->getEndOfNormalResults()
- + size_t(hasErrorResult());
+ auto *ptr = const_cast<SILFunctionType *>(this)->getEndOfAllResults();
return *(reinterpret_cast<CanType *>(ptr) + 1);
}
- SILFunctionType(
- GenericSignature *genericSig, ExtInfo ext,
- ParameterConvention calleeConvention, ArrayRef<SILParameterInfo> params,
- ArrayRef<SILResultInfo> normalResults,
- Optional<SILResultInfo> errorResult, const ASTContext &ctx,
- RecursiveTypeProperties properties,
- Optional<ProtocolConformanceRef> witnessMethodConformance = None);
+ SILFunctionType(GenericSignature *genericSig, ExtInfo ext,
+ SILCoroutineKind coroutineKind,
+ ParameterConvention calleeConvention,
+ ArrayRef<SILParameterInfo> params,
+ ArrayRef<SILYieldInfo> yieldResults,
+ ArrayRef<SILResultInfo> normalResults,
+ Optional<SILResultInfo> errorResult,
+ const ASTContext &ctx,
+ RecursiveTypeProperties properties,
+ Optional<ProtocolConformanceRef> witnessMethodConformance);
public:
- static CanSILFunctionType
- get(GenericSignature *genericSig, ExtInfo ext,
- ParameterConvention calleeConvention,
- ArrayRef<SILParameterInfo> interfaceParams,
- ArrayRef<SILResultInfo> interfaceResults,
- Optional<SILResultInfo> interfaceErrorResult, const ASTContext &ctx,
- Optional<ProtocolConformanceRef> witnessMethodConformance = None);
+ static CanSILFunctionType get(GenericSignature *genericSig,
+ ExtInfo ext,
+ SILCoroutineKind coroutineKind,
+ ParameterConvention calleeConvention,
+ ArrayRef<SILParameterInfo> interfaceParams,
+ ArrayRef<SILYieldInfo> interfaceYields,
+ ArrayRef<SILResultInfo> interfaceResults,
+ Optional<SILResultInfo> interfaceErrorResult,
+ const ASTContext &ctx,
+ Optional<ProtocolConformanceRef> witnessMethodConformance = None);
/// Given that this function type uses a C-language convention, return its
/// formal semantic result type.
@@ -3423,12 +3490,26 @@
return getCalleeConvention() == ParameterConvention::Direct_Guaranteed;
}
+ /// Is this some kind of coroutine?
+ bool isCoroutine() const {
+ return getCoroutineKind() != SILCoroutineKind::None;
+ }
+ SILCoroutineKind getCoroutineKind() const {
+ return SILCoroutineKind(SILFunctionTypeBits.CoroutineKind);
+ }
+
+ /// Return the array of all the yields.
+ ArrayRef<SILYieldInfo> getYields() const {
+ return const_cast<SILFunctionType *>(this)->getMutableYields();
+ }
+ unsigned getNumYields() const { return isCoroutine() ? NumAnyResults : 0; }
+
/// Return the array of all result information. This may contain inter-mingled
/// direct and indirect results.
ArrayRef<SILResultInfo> getResults() const {
return const_cast<SILFunctionType *>(this)->getMutableResults();
}
- unsigned getNumResults() const { return NumResults; }
+ unsigned getNumResults() const { return isCoroutine() ? 0 : NumAnyResults; }
/// Given that this function type has exactly one result, return it.
/// This is a common situation when working with a function with a known
@@ -3458,14 +3539,14 @@
// indirect property, not the SIL indirect property, should be consulted to
// determine whether function reabstraction is necessary.
unsigned getNumIndirectFormalResults() const {
- return NumIndirectFormalResults;
+ return isCoroutine() ? 0 : NumAnyIndirectFormalResults;
}
/// Does this function have any formally indirect results?
bool hasIndirectFormalResults() const {
return getNumIndirectFormalResults() != 0;
}
unsigned getNumDirectFormalResults() const {
- return NumResults - NumIndirectFormalResults;
+ return isCoroutine() ? 0 : NumAnyResults - NumAnyIndirectFormalResults;
}
struct IndirectFormalResultFilter {
@@ -3607,15 +3688,18 @@
LookupConformanceFn conformances);
void Profile(llvm::FoldingSetNodeID &ID) {
- Profile(ID, getGenericSignature(), getExtInfo(), getCalleeConvention(),
- getParameters(), getResults(), getOptionalErrorResult());
+ Profile(ID, getGenericSignature(), getExtInfo(), getCoroutineKind(),
+ getCalleeConvention(), getParameters(), getYields(),
+ getResults(), getOptionalErrorResult());
}
static void Profile(llvm::FoldingSetNodeID &ID,
GenericSignature *genericSig,
ExtInfo info,
+ SILCoroutineKind coroutineKind,
ParameterConvention calleeConvention,
ArrayRef<SILParameterInfo> params,
- ArrayRef<SILResultInfo> result,
+ ArrayRef<SILYieldInfo> yields,
+ ArrayRef<SILResultInfo> results,
Optional<SILResultInfo> errorResult);
// Implement isa/cast/dyncast/etc.
diff --git a/include/swift/SIL/SILBuilder.h b/include/swift/SIL/SILBuilder.h
index 09e8629..2e1f4c5 100644
--- a/include/swift/SIL/SILBuilder.h
+++ b/include/swift/SIL/SILBuilder.h
@@ -1617,6 +1617,18 @@
new (getModule()) ThrowInst(getSILDebugLocation(Loc), errorValue));
}
+ UnwindInst *createUnwind(SILLocation loc) {
+ return insertTerminator(
+ new (getModule()) UnwindInst(getSILDebugLocation(loc)));
+ }
+
+ YieldInst *createYield(SILLocation loc, ArrayRef<SILValue> yieldedValues,
+ SILBasicBlock *resumeBB, SILBasicBlock *unwindBB) {
+ return insertTerminator(
+ YieldInst::create(getSILDebugLocation(loc), yieldedValues,
+ resumeBB, unwindBB, getFunction()));
+ }
+
CondBranchInst *
createCondBranch(SILLocation Loc, SILValue Cond, SILBasicBlock *Target1,
SILBasicBlock *Target2,
diff --git a/include/swift/SIL/SILCloner.h b/include/swift/SIL/SILCloner.h
index 833719b..c4345ed 100644
--- a/include/swift/SIL/SILCloner.h
+++ b/include/swift/SIL/SILCloner.h
@@ -2118,6 +2118,27 @@
template<typename ImplClass>
void
+SILCloner<ImplClass>::visitUnwindInst(UnwindInst *Inst) {
+ getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
+ doPostProcess(Inst,
+ getBuilder().createUnwind(getOpLocation(Inst->getLoc())));
+}
+
+template<typename ImplClass>
+void
+SILCloner<ImplClass>::visitYieldInst(YieldInst *Inst) {
+ auto Values = getOpValueArray<8>(Inst->getYieldedValues());
+ auto ResumeBB = getOpBasicBlock(Inst->getResumeBB());
+ auto UnwindBB = getOpBasicBlock(Inst->getUnwindBB());
+
+ getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
+ doPostProcess(Inst,
+ getBuilder().createYield(getOpLocation(Inst->getLoc()), Values,
+ ResumeBB, UnwindBB));
+}
+
+template<typename ImplClass>
+void
SILCloner<ImplClass>::visitBranchInst(BranchInst *Inst) {
auto Args = getOpValueArray<8>(Inst->getArgs());
getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
diff --git a/include/swift/SIL/SILFunctionConventions.h b/include/swift/SIL/SILFunctionConventions.h
index 558541e..d26e981 100644
--- a/include/swift/SIL/SILFunctionConventions.h
+++ b/include/swift/SIL/SILFunctionConventions.h
@@ -45,10 +45,14 @@
static bool isIndirectSILParam(SILParameterInfo param, bool loweredAddresses);
+ static bool isIndirectSILYield(SILYieldInfo yield, bool loweredAddresses);
+
static bool isIndirectSILResult(SILResultInfo result, bool loweredAddresses);
static SILType getSILParamType(SILParameterInfo param, bool loweredAddresses);
+ static SILType getSILYieldType(SILYieldInfo yield, bool loweredAddresses);
+
static SILType getSILResultType(SILResultInfo param, bool loweredAddresses);
public:
@@ -77,6 +81,10 @@
return isIndirectSILParam(param, loweredAddresses);
}
+ bool isSILIndirect(SILYieldInfo yield) const {
+ return isIndirectSILYield(yield, loweredAddresses);
+ }
+
bool isSILIndirect(SILResultInfo result) const {
return isIndirectSILResult(result, loweredAddresses);
}
@@ -85,6 +93,10 @@
return getSILParamType(param, loweredAddresses);
}
+ SILType getSILType(SILYieldInfo yield) const {
+ return getSILYieldType(yield, loweredAddresses);
+ }
+
SILType getSILType(SILResultInfo result) const {
return getSILResultType(result, loweredAddresses);
}
@@ -115,6 +127,10 @@
return silConv.isSILIndirect(param);
}
+ bool isSILIndirect(SILYieldInfo yield) const {
+ return silConv.isSILIndirect(yield);
+ }
+
bool isSILIndirect(SILResultInfo result) const {
return silConv.isSILIndirect(result);
}
@@ -123,6 +139,10 @@
return silConv.getSILType(param);
}
+ SILType getSILType(SILYieldInfo yield) const {
+ return silConv.getSILType(yield);
+ }
+
SILType getSILType(SILResultInfo result) const {
return silConv.getSILType(result);
}
@@ -279,6 +299,28 @@
}
//===--------------------------------------------------------------------===//
+ // SIL yield types.
+ //===--------------------------------------------------------------------===//
+
+ unsigned getNumYields() const { return funcTy->getNumYields(); }
+
+ ArrayRef<SILYieldInfo> getYields() const {
+ return funcTy->getYields();
+ }
+
+ using SILYieldTypeIter =
+ llvm::mapped_iterator<const SILYieldInfo *, SILParameterTypeFunc>;
+ using SILYieldTypeRange = IteratorRange<SILYieldTypeIter>;
+
+ SILYieldTypeRange getYieldSILTypes() const {
+ return makeIteratorRange(
+ SILYieldTypeIter(funcTy->getYields().begin(),
+ SILParameterTypeFunc(silConv)),
+ SILYieldTypeIter(funcTy->getYields().end(),
+ SILParameterTypeFunc(silConv)));
+ }
+
+ //===--------------------------------------------------------------------===//
// SILArgument API, including indirect results and parameters.
//
// The argument indices below relate to full applies in which the caller and
@@ -363,6 +405,11 @@
llvm_unreachable("covered switch isn't covered?!");
}
+inline bool SILModuleConventions::isIndirectSILYield(SILYieldInfo yield,
+ bool loweredAddresses) {
+ return isIndirectSILParam(yield, loweredAddresses);
+}
+
inline bool SILModuleConventions::isIndirectSILResult(SILResultInfo result,
bool loweredAddresses) {
switch (result.getConvention()) {
@@ -386,6 +433,11 @@
: SILType::getPrimitiveObjectType(param.getType());
}
+inline SILType SILModuleConventions::getSILYieldType(SILYieldInfo yield,
+ bool loweredAddresses) {
+ return getSILParamType(yield, loweredAddresses);
+}
+
inline SILType SILModuleConventions::getSILResultType(SILResultInfo result,
bool loweredAddresses) {
return SILModuleConventions::isIndirectSILResult(result, loweredAddresses)
diff --git a/include/swift/SIL/SILInstruction.h b/include/swift/SIL/SILInstruction.h
index 1ed4bcb..a7c5364 100644
--- a/include/swift/SIL/SILInstruction.h
+++ b/include/swift/SIL/SILInstruction.h
@@ -6242,6 +6242,84 @@
}
};
+/// UnwindInst - Continue unwinding out of this function. Currently this is
+/// only used in coroutines as the eventual terminator of the unwind edge
+/// out of a 'yield'.
+class UnwindInst
+ : public InstructionBase<SILInstructionKind::UnwindInst,
+ TermInst> {
+ friend SILBuilder;
+
+ UnwindInst(SILDebugLocation loc)
+ : InstructionBase(loc) {}
+
+public:
+ SuccessorListTy getSuccessors() {
+ // No successors.
+ return SuccessorListTy();
+ }
+
+ ArrayRef<Operand> getAllOperands() const { return {}; }
+ MutableArrayRef<Operand> getAllOperands() { return {}; }
+};
+
+/// YieldInst - Yield control temporarily to the caller of this coroutine.
+///
+/// This is a terminator because the caller can abort the coroutine,
+/// e.g. if an error is thrown and an unwind is provoked.
+class YieldInst
+ : public InstructionBase<SILInstructionKind::YieldInst,
+ TermInst> {
+ friend SILBuilder;
+
+ SILSuccessor DestBBs[2];
+
+ TailAllocatedOperandList<0> Operands;
+
+ YieldInst(SILDebugLocation loc, ArrayRef<SILValue> yieldedValues,
+ SILBasicBlock *normalBB, SILBasicBlock *unwindBB);
+
+ static YieldInst *create(SILDebugLocation loc,
+ ArrayRef<SILValue> yieldedValues,
+ SILBasicBlock *normalBB, SILBasicBlock *unwindBB,
+ SILFunction &F);
+
+public:
+ /// Return the normal resume destination of the yield, which is where the
+ /// coroutine resumes when the caller is ready to continue normally.
+ ///
+ /// This must be the unique predecessor edge of the given block.
+ ///
+ /// Control flow along every path from this block must either loop or
+ /// eventually terminate in a 'return', 'throw', or 'unreachable'
+ /// instruction. In a yield_many coroutine, control is permitted to
+ /// first reach a 'yield' instruction; this is prohibited in a
+ /// yield_once coroutine.
+ SILBasicBlock *getResumeBB() const { return DestBBs[0]; }
+
+ /// Return the 'unwind' destination of the yield, which is where the
+ /// coroutine resumes when the caller is unconditionally aborting the
+ /// coroutine.
+ ///
+ /// This must be the unique predecessor edge of the given block.
+ ///
+ /// Control flow along every path from this block must either loop or
+ /// eventually terminate in an 'unwind' or 'unreachable' instruction.
+ /// It is not permitted to reach a 'yield' instruction.
+ SILBasicBlock *getUnwindBB() const { return DestBBs[1]; }
+
+ OperandValueArrayRef getYieldedValues() const {
+ return Operands.asValueArray();
+ }
+
+ ArrayRef<Operand> getAllOperands() const { return Operands.asArray(); }
+ MutableArrayRef<Operand> getAllOperands() { return Operands.asArray(); }
+
+ SuccessorListTy getSuccessors() {
+ return DestBBs;
+ }
+};
+
/// BranchInst - An unconditional branch.
class BranchInst
: public InstructionBase<SILInstructionKind::BranchInst,
diff --git a/include/swift/SIL/SILNodes.def b/include/swift/SIL/SILNodes.def
index 78a6318..6afe2fe 100644
--- a/include/swift/SIL/SILNodes.def
+++ b/include/swift/SIL/SILNodes.def
@@ -498,6 +498,10 @@
TermInst, None, DoesNotRelease)
TERMINATOR(ThrowInst, throw,
TermInst, None, DoesNotRelease)
+ TERMINATOR(YieldInst, yield,
+ TermInst, MayHaveSideEffects, MayRelease)
+ TERMINATOR(UnwindInst, unwind,
+ TermInst, None, DoesNotRelease)
TERMINATOR(TryApplyInst, try_apply,
TermInst, MayHaveSideEffects, MayRelease)
TERMINATOR(BranchInst, br,
diff --git a/include/swift/SILOptimizer/Utils/SCCVisitor.h b/include/swift/SILOptimizer/Utils/SCCVisitor.h
index c0f2b4f..9ea03d2 100644
--- a/include/swift/SILOptimizer/Utils/SCCVisitor.h
+++ b/include/swift/SILOptimizer/Utils/SCCVisitor.h
@@ -133,8 +133,14 @@
case TermKind::ReturnInst:
case TermKind::SwitchValueInst:
case TermKind::ThrowInst:
+ case TermKind::UnwindInst:
llvm_unreachable("Did not expect terminator that does not have args!");
+ case TermKind::YieldInst:
+ for (auto &O : cast<YieldInst>(Term)->getAllOperands())
+ Operands.push_back(O.get());
+ return;
+
case TermKind::TryApplyInst:
for (auto &O : cast<TryApplyInst>(Term)->getAllOperands())
Operands.push_back(O.get());
diff --git a/include/swift/Serialization/ModuleFormat.h b/include/swift/Serialization/ModuleFormat.h
index 746988f..1b0dec9 100644
--- a/include/swift/Serialization/ModuleFormat.h
+++ b/include/swift/Serialization/ModuleFormat.h
@@ -156,6 +156,15 @@
// These IDs must \em not be renumbered or reordered without incrementing
// VERSION_MAJOR.
+enum class SILCoroutineKind : uint8_t {
+ None = 0,
+ YieldOnce = 1,
+ YieldMany = 2,
+};
+using SILCoroutineKindField = BCFixed<2>;
+
+// These IDs must \em not be renumbered or reordered without incrementing
+// VERSION_MAJOR.
enum OperatorKind : uint8_t {
Infix = 0,
Prefix,
@@ -735,12 +744,14 @@
using SILFunctionTypeLayout = BCRecordLayout<
SIL_FUNCTION_TYPE,
+ SILCoroutineKindField, // coroutine kind
ParameterConventionField, // callee convention
SILFunctionTypeRepresentationField, // representation
BCFixed<1>, // pseudogeneric?
BCFixed<1>, // noescape?
BCFixed<1>, // error result?
BCFixed<30>, // number of parameters
+ BCFixed<30>, // number of yields
BCFixed<30>, // number of results
BCArray<TypeIDField> // parameter types/conventions, alternating
// followed by result types/conventions, alternating
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 314321f..e57bd64 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -3787,16 +3787,22 @@
void SILFunctionType::Profile(llvm::FoldingSetNodeID &id,
GenericSignature *genericParams,
ExtInfo info,
+ SILCoroutineKind coroutineKind,
ParameterConvention calleeConvention,
ArrayRef<SILParameterInfo> params,
+ ArrayRef<SILYieldInfo> yields,
ArrayRef<SILResultInfo> results,
Optional<SILResultInfo> errorResult) {
id.AddPointer(genericParams);
id.AddInteger(info.getFuncAttrKey());
+ id.AddInteger(unsigned(coroutineKind));
id.AddInteger(unsigned(calleeConvention));
id.AddInteger(params.size());
for (auto param : params)
param.profile(id);
+ id.AddInteger(yields.size());
+ for (auto yield : yields)
+ yield.profile(id);
id.AddInteger(results.size());
for (auto result : results)
result.profile(id);
@@ -3806,32 +3812,47 @@
if (errorResult) errorResult->profile(id);
}
-SILFunctionType::SILFunctionType(
- GenericSignature *genericSig, ExtInfo ext,
- ParameterConvention calleeConvention, ArrayRef<SILParameterInfo> params,
- ArrayRef<SILResultInfo> normalResults, Optional<SILResultInfo> errorResult,
- const ASTContext &ctx, RecursiveTypeProperties properties,
- Optional<ProtocolConformanceRef> witnessMethodConformance)
- : TypeBase(TypeKind::SILFunction, &ctx, properties), GenericSig(genericSig),
+SILFunctionType::SILFunctionType(GenericSignature *genericSig, ExtInfo ext,
+ SILCoroutineKind coroutineKind,
+ ParameterConvention calleeConvention,
+ ArrayRef<SILParameterInfo> params,
+ ArrayRef<SILYieldInfo> yields,
+ ArrayRef<SILResultInfo> normalResults,
+ Optional<SILResultInfo> errorResult,
+ const ASTContext &ctx,
+ RecursiveTypeProperties properties,
+ Optional<ProtocolConformanceRef> witnessMethodConformance)
+ : TypeBase(TypeKind::SILFunction, &ctx, properties),
+ GenericSig(genericSig),
WitnessMethodConformance(witnessMethodConformance) {
SILFunctionTypeBits.HasErrorResult = errorResult.hasValue();
SILFunctionTypeBits.ExtInfo = ext.Bits;
+ SILFunctionTypeBits.CoroutineKind = unsigned(coroutineKind);
NumParameters = params.size();
- NumResults = normalResults.size();
- NumIndirectFormalResults =
+ if (coroutineKind == SILCoroutineKind::None) {
+ assert(yields.empty());
+ NumAnyResults = normalResults.size();
+ NumAnyIndirectFormalResults =
std::count_if(normalResults.begin(), normalResults.end(),
[](const SILResultInfo &resultInfo) {
return resultInfo.isFormalIndirect();
});
+ memcpy(getMutableResults().data(), normalResults.data(),
+ normalResults.size() * sizeof(SILResultInfo));
+ } else {
+ assert(normalResults.empty());
+ NumAnyResults = yields.size();
+ NumAnyIndirectFormalResults = 0; // unused
+ memcpy(getMutableYields().data(), yields.data(),
+ yields.size() * sizeof(SILYieldInfo));
+ }
assert(!isIndirectFormalParameter(calleeConvention));
SILFunctionTypeBits.CalleeConvention = unsigned(calleeConvention);
memcpy(getMutableParameters().data(), params.data(),
params.size() * sizeof(SILParameterInfo));
- memcpy(getMutableResults().data(), normalResults.data(),
- normalResults.size() * sizeof(SILResultInfo));
if (errorResult)
getMutableErrorResult() = *errorResult;
@@ -3868,6 +3889,13 @@
assert(!result.getType()->hasArchetype()
&& "interface type of result should not contain context archetypes");
}
+ for (auto yield : getYields()) {
+ (void)yield;
+ assert(!yield.getType()->hasError()
+ && "interface type of yield should not contain error types");
+ assert(!yield.getType()->hasArchetype()
+ && "interface type of yield should not contain context archetypes");
+ }
if (hasErrorResult()) {
assert(!getErrorResult().getType()->hasError()
&& "interface type of result should not contain error types");
@@ -3892,14 +3920,22 @@
return CanSILBlockStorageType(storageTy);
}
-CanSILFunctionType SILFunctionType::get(
- GenericSignature *genericSig, ExtInfo ext, ParameterConvention callee,
- ArrayRef<SILParameterInfo> params, ArrayRef<SILResultInfo> normalResults,
- Optional<SILResultInfo> errorResult, const ASTContext &ctx,
- Optional<ProtocolConformanceRef> witnessMethodConformance) {
+CanSILFunctionType SILFunctionType::get(GenericSignature *genericSig,
+ ExtInfo ext,
+ SILCoroutineKind coroutineKind,
+ ParameterConvention callee,
+ ArrayRef<SILParameterInfo> params,
+ ArrayRef<SILYieldInfo> yields,
+ ArrayRef<SILResultInfo> normalResults,
+ Optional<SILResultInfo> errorResult,
+ const ASTContext &ctx,
+ Optional<ProtocolConformanceRef> witnessMethodConformance) {
+ assert(coroutineKind == SILCoroutineKind::None || normalResults.empty());
+ assert(coroutineKind != SILCoroutineKind::None || yields.empty());
+
llvm::FoldingSetNodeID id;
- SILFunctionType::Profile(id, genericSig, ext, callee, params, normalResults,
- errorResult);
+ SILFunctionType::Profile(id, genericSig, ext, coroutineKind, callee,
+ params, yields, normalResults, errorResult);
// Do we already have this generic function type?
void *insertPos;
@@ -3912,6 +3948,7 @@
// Allocate storage for the object.
size_t bytes = sizeof(SILFunctionType)
+ sizeof(SILParameterInfo) * params.size()
+ + sizeof(SILYieldInfo) * yields.size()
+ sizeof(SILResultInfo) * normalResults.size()
+ (errorResult ? sizeof(SILResultInfo) : 0)
+ (normalResults.size() > 1 ? sizeof(CanType) * 2 : 0);
@@ -3922,6 +3959,8 @@
"revisit this if you add new recursive type properties");
for (auto ¶m : params)
properties |= param.getType()->getRecursiveProperties();
+ for (auto &yield : yields)
+ properties |= yield.getType()->getRecursiveProperties();
for (auto &result : normalResults)
properties |= result.getType()->getRecursiveProperties();
if (errorResult)
@@ -3934,9 +3973,10 @@
properties.removeHasDependentMember();
}
- auto fnType = new (mem)
- SILFunctionType(genericSig, ext, callee, params, normalResults,
- errorResult, ctx, properties, witnessMethodConformance);
+ auto fnType =
+ new (mem) SILFunctionType(genericSig, ext, coroutineKind, callee,
+ params, yields, normalResults, errorResult,
+ ctx, properties, witnessMethodConformance);
ctx.Impl.SILFunctionTypes.InsertNode(fnType, insertPos);
return CanSILFunctionType(fnType);
}
diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp
index 6a8cebf..6cad624 100644
--- a/lib/AST/ASTPrinter.cpp
+++ b/lib/AST/ASTPrinter.cpp
@@ -3630,6 +3630,20 @@
Printer.printStructurePost(PrintStructureKind::FunctionReturnType);
}
+ void printSILCoroutineKind(SILCoroutineKind kind) {
+ switch (kind) {
+ case SILCoroutineKind::None:
+ return;
+ case SILCoroutineKind::YieldOnce:
+ Printer << "@yield_once ";
+ return;
+ case SILCoroutineKind::YieldMany:
+ Printer << "@yield_many ";
+ return;
+ }
+ llvm_unreachable("bad convention");
+ }
+
void printCalleeConvention(ParameterConvention conv) {
switch (conv) {
case ParameterConvention::Direct_Unowned:
@@ -3651,6 +3665,7 @@
}
void visitSILFunctionType(SILFunctionType *T) {
+ printSILCoroutineKind(T->getCoroutineKind());
printFunctionExtInfo(T->getExtInfo(),
T->getWitnessMethodConformanceOrNone());
printCalleeConvention(T->getCalleeConvention());
@@ -3669,11 +3684,19 @@
}
Printer << ") -> ";
- unsigned totalResults = T->getNumResults() + unsigned(T->hasErrorResult());
+ unsigned totalResults =
+ T->getNumYields() + T->getNumResults() + unsigned(T->hasErrorResult());
if (totalResults != 1) Printer << "(";
first = true;
+
+ for (auto yield : T->getYields()) {
+ Printer.printSeparator(first, ", ");
+ Printer << "@yields ";
+ yield.print(Printer, Options);
+ }
+
for (auto result : T->getResults()) {
Printer.printSeparator(first, ", ");
result.print(Printer, Options);
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index 9f67cdf..1a15a3f 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -3560,6 +3560,20 @@
return false;
}
+static bool transformSILYield(
+ SILYieldInfo &yield, bool &changed,
+ llvm::function_ref<Optional<Type>(TypeBase *)> fn) {
+ Type transType = yield.getType().transformRec(fn);
+ if (!transType) return true;
+
+ CanType canTransType = transType->getCanonicalType();
+ if (canTransType != yield.getType()) {
+ changed = true;
+ yield = yield.getWithType(canTransType);
+ }
+ return false;
+}
+
static bool transformSILParameter(
SILParameterInfo ¶m, bool &changed,
llvm::function_ref<Optional<Type>(TypeBase *)> fn) {
@@ -3665,6 +3679,12 @@
transInterfaceParams.push_back(param);
}
+ SmallVector<SILYieldInfo, 8> transInterfaceYields;
+ for (SILYieldInfo yield : fnTy->getYields()) {
+ if (transformSILYield(yield, changed, fn)) return Type();
+ transInterfaceYields.push_back(yield);
+ }
+
SmallVector<SILResultInfo, 8> transInterfaceResults;
for (SILResultInfo result : fnTy->getResults()) {
if (transformSILResult(result, changed, fn)) return Type();
@@ -3680,10 +3700,15 @@
if (!changed) return *this;
- return SILFunctionType::get(fnTy->getGenericSignature(), fnTy->getExtInfo(),
+ return SILFunctionType::get(fnTy->getGenericSignature(),
+ fnTy->getExtInfo(),
+ fnTy->getCoroutineKind(),
fnTy->getCalleeConvention(),
- transInterfaceParams, transInterfaceResults,
- transErrorResult, Ptr->getASTContext(),
+ transInterfaceParams,
+ transInterfaceYields,
+ transInterfaceResults,
+ transErrorResult,
+ Ptr->getASTContext(),
fnTy->getWitnessMethodConformanceOrNone());
}
diff --git a/lib/IRGen/GenProto.cpp b/lib/IRGen/GenProto.cpp
index 4797745..5b4c114 100644
--- a/lib/IRGen/GenProto.cpp
+++ b/lib/IRGen/GenProto.cpp
@@ -2594,8 +2594,10 @@
auto generics = ncGenerics->getCanonicalSignature();
CanSILFunctionType fnType = [&]() -> CanSILFunctionType {
return SILFunctionType::get(generics, SILFunctionType::ExtInfo(),
+ SILCoroutineKind::None,
/*callee*/ ParameterConvention::Direct_Unowned,
- /*params*/ {}, /*results*/ {}, /*error*/ None,
+ /*params*/ {}, /*yields*/ {},
+ /*results*/ {}, /*error*/ None,
IGM.Context);
}();
diff --git a/lib/IRGen/IRGenSIL.cpp b/lib/IRGen/IRGenSIL.cpp
index 6656db0..c5a5524 100644
--- a/lib/IRGen/IRGenSIL.cpp
+++ b/lib/IRGen/IRGenSIL.cpp
@@ -1024,6 +1024,8 @@
void visitCondBranchInst(CondBranchInst *i);
void visitReturnInst(ReturnInst *i);
void visitThrowInst(ThrowInst *i);
+ void visitUnwindInst(UnwindInst *i);
+ void visitYieldInst(YieldInst *i);
void visitSwitchValueInst(SwitchValueInst *i);
void visitSwitchEnumInst(SwitchEnumInst *i);
void visitSwitchEnumAddrInst(SwitchEnumAddrInst *i);
@@ -2470,6 +2472,20 @@
}
}
+void IRGenSILFunction::visitUnwindInst(swift::UnwindInst *i) {
+ IGM.unimplemented(i->getLoc().getSourceLoc(),
+ "unwind instruction");
+ Builder.CreateUnreachable();
+ Builder.emitBlock(createBasicBlock("unwind"));
+}
+
+void IRGenSILFunction::visitYieldInst(swift::YieldInst *i) {
+ IGM.unimplemented(i->getLoc().getSourceLoc(),
+ "yield instruction");
+ Builder.CreateUnreachable();
+ Builder.emitBlock(createBasicBlock("yield"));
+}
+
static llvm::BasicBlock *emitBBMapForSwitchValue(
IRGenSILFunction &IGF,
SmallVectorImpl<std::pair<SILValue, llvm::BasicBlock*>> &dests,
diff --git a/lib/IRGen/LoadableByAddress.cpp b/lib/IRGen/LoadableByAddress.cpp
index 31069ff..80c2e9b 100644
--- a/lib/IRGen/LoadableByAddress.cpp
+++ b/lib/IRGen/LoadableByAddress.cpp
@@ -73,47 +73,60 @@
return true;
}
-static bool modResultType(GenericEnvironment *genEnv,
- CanSILFunctionType loweredTy,
- irgen::IRGenModule &Mod);
+static bool shouldTransformResults(GenericEnvironment *env,
+ CanSILFunctionType fnType,
+ irgen::IRGenModule &IGM);
-static bool containsLargeLoadable(GenericEnvironment *GenericEnv,
- ArrayRef<SILParameterInfo> params,
- irgen::IRGenModule &Mod) {
- for (SILParameterInfo param : params) {
- SILType storageType = param.getSILStorageType();
- CanType currCanType = storageType.getSwiftRValueType();
- if (SILFunctionType *currSILFunctionType =
- dyn_cast<SILFunctionType>(currCanType.getPointer())) {
- if (containsLargeLoadable(GenericEnv,
- currSILFunctionType->getParameters(), Mod) ||
- modResultType(GenericEnv, CanSILFunctionType(currSILFunctionType),
- Mod)) {
- return true;
- }
- } else {
- switch (param.getConvention()) {
- case ParameterConvention::Indirect_In_Guaranteed:
- case ParameterConvention::Indirect_Inout:
- case ParameterConvention::Indirect_InoutAliasable:
- case ParameterConvention::Indirect_In: {
- continue;
- }
- default:
- break;
- }
- if (isLargeLoadableType(GenericEnv, storageType, Mod)) {
- return true;
- }
- }
+static bool shouldTransformFunctionType(GenericEnvironment *env,
+ CanSILFunctionType fnType,
+ irgen::IRGenModule &IGM);
+
+static bool shouldTransformParameter(GenericEnvironment *env,
+ SILParameterInfo param,
+ irgen::IRGenModule &IGM) {
+ SILType storageType = param.getSILStorageType();
+
+ // FIXME: only function types and not recursively-transformable types?
+ if (auto fnType = storageType.getAs<SILFunctionType>())
+ return shouldTransformFunctionType(env, fnType, IGM);
+
+ switch (param.getConvention()) {
+ case ParameterConvention::Indirect_In_Guaranteed:
+ case ParameterConvention::Indirect_Inout:
+ case ParameterConvention::Indirect_InoutAliasable:
+ case ParameterConvention::Indirect_In:
+ return false;
+ default:
+ return isLargeLoadableType(env, storageType, IGM);
}
+}
+
+static bool shouldTransformFunctionType(GenericEnvironment *env,
+ CanSILFunctionType fnType,
+ irgen::IRGenModule &IGM) {
+ if (shouldTransformResults(env, fnType, IGM))
+ return true;
+
+ for (auto param : fnType->getParameters()) {
+ if (shouldTransformParameter(env, param, IGM))
+ return true;
+ }
+
+ for (auto yield : fnType->getYields()) {
+ if (shouldTransformParameter(env, yield, IGM))
+ return true;
+ }
+
return false;
}
// Forward declarations - functions depend on each other
static SmallVector<SILParameterInfo, 4>
-getNewArgTys(GenericEnvironment *GenericEnv,
- SILFunctionType *currSILFunctionType, irgen::IRGenModule &Mod);
+getNewParameters(GenericEnvironment *env, CanSILFunctionType fnType,
+ irgen::IRGenModule &IGM);
+static SmallVector<SILYieldInfo, 2>
+getNewYields(GenericEnvironment *env, CanSILFunctionType fnType,
+ irgen::IRGenModule &IGM);
static SILType getNewSILType(GenericEnvironment *GenericEnv,
SILType storageType, irgen::IRGenModule &Mod);
@@ -135,11 +148,11 @@
static SmallVector<SILResultInfo, 2>
getNewResults(GenericEnvironment *GenericEnv,
- SILFunctionType *currSILFunctionType, irgen::IRGenModule &Mod) {
+ CanSILFunctionType fnType, irgen::IRGenModule &Mod) {
// Get new SIL Function results - same as old results UNLESS:
// 1) Function type results might have a different signature
// 2) Large loadables are replaced by @out version
- auto origResults = currSILFunctionType->getResults();
+ auto origResults = fnType->getResults();
SmallVector<SILResultInfo, 2> newResults;
for (auto result : origResults) {
SILType currResultTy = result.getSILStorageType();
@@ -152,8 +165,7 @@
result.getConvention());
newResults.push_back(newResult);
} else if ((newSILType != currResultTy) &&
- modResultType(GenericEnv,
- CanSILFunctionType(currSILFunctionType), Mod)) {
+ shouldTransformResults(GenericEnv, fnType, Mod)) {
// Case (2) Above
SILResultInfo newSILResultInfo(newSILType.getSwiftRValueType(),
ResultConvention::Indirect);
@@ -165,39 +177,28 @@
return newResults;
}
-static SILFunctionType *
-getNewSILFunctionTypePtr(GenericEnvironment *GenericEnv,
- SILFunctionType *currSILFunctionType,
- irgen::IRGenModule &Mod) {
- if (!modifiableFunction(CanSILFunctionType(currSILFunctionType))) {
- return currSILFunctionType;
+static CanSILFunctionType
+getNewSILFunctionType(GenericEnvironment *env,
+ CanSILFunctionType fnType,
+ irgen::IRGenModule &IGM) {
+ if (!modifiableFunction(fnType)) {
+ return fnType;
}
- SmallVector<SILParameterInfo, 4> newArgTys =
- getNewArgTys(GenericEnv, currSILFunctionType, Mod);
- SILFunctionType *newSILFunctionType = SILFunctionType::get(
- currSILFunctionType->getGenericSignature(),
- currSILFunctionType->getExtInfo(),
- currSILFunctionType->getCalleeConvention(), newArgTys,
- getNewResults(GenericEnv, currSILFunctionType, Mod),
- currSILFunctionType->getOptionalErrorResult(),
- currSILFunctionType->getASTContext(),
- currSILFunctionType->getWitnessMethodConformanceOrNone());
- return newSILFunctionType;
-}
-
-static SILType getNewSILFunctionType(GenericEnvironment *GenericEnv,
- SILFunctionType *currSILFunctionType,
- irgen::IRGenModule &Mod) {
- if (!modifiableFunction(CanSILFunctionType(currSILFunctionType))) {
- SILType newSILType = SILType::getPrimitiveObjectType(
- currSILFunctionType->getCanonicalType());
- return newSILType;
- }
- SILFunctionType *newSILFunctionType =
- getNewSILFunctionTypePtr(GenericEnv, currSILFunctionType, Mod);
- SILType newSILType =
- SILType::getPrimitiveObjectType(newSILFunctionType->getCanonicalType());
- return newSILType;
+ auto newParams = getNewParameters(env, fnType, IGM);
+ auto newYields = getNewYields(env, fnType, IGM);
+ auto newResults = getNewResults(env, fnType, IGM);
+ auto newFnType = SILFunctionType::get(
+ fnType->getGenericSignature(),
+ fnType->getExtInfo(),
+ fnType->getCoroutineKind(),
+ fnType->getCalleeConvention(),
+ newParams,
+ newYields,
+ newResults,
+ fnType->getOptionalErrorResult(),
+ fnType->getASTContext(),
+ fnType->getWitnessMethodConformanceOrNone());
+ return newFnType;
}
// Get the function type or the optional function type
@@ -223,35 +224,22 @@
SILType storageType,
irgen::IRGenModule &Mod) {
SILType newSILType = storageType;
- CanType currCanType = storageType.getSwiftRValueType();
- OptionalTypeKind optKind;
- if (auto optionalType = currCanType.getAnyOptionalObjectType(optKind)) {
- assert(optKind != OptionalTypeKind::OTK_None &&
- "Expected Real Optional Type");
- if (auto *currSILFunctionType =
- dyn_cast<SILFunctionType>(optionalType.getPointer())) {
- if (containsLargeLoadable(GenericEnv,
- currSILFunctionType->getParameters(), Mod) ||
- modResultType(GenericEnv, CanSILFunctionType(currSILFunctionType),
- Mod)) {
+ if (auto objectType = storageType.getAnyOptionalObjectType()) {
+ if (auto fnType = objectType.getAs<SILFunctionType>()) {
+ if (shouldTransformFunctionType(GenericEnv, fnType, Mod)) {
+ auto newFnType = getNewSILFunctionType(GenericEnv, fnType, Mod);
newSILType =
- getNewSILFunctionType(GenericEnv, currSILFunctionType, Mod);
- currCanType = newSILType.getSwiftRValueType();
- auto newType = OptionalType::get(optKind, currCanType);
- CanType newCanType = newType->getCanonicalType();
- newSILType = SILType::getPrimitiveObjectType(newCanType);
- if (storageType.isAddress()) {
- newSILType = newSILType.getAddressType();
- }
+ SILType::getPrimitiveType(newFnType, storageType.getCategory());
+ newSILType = SILType::getOptionalType(newSILType);
}
}
}
return newSILType;
}
-static bool modResultType(GenericEnvironment *genEnv,
- CanSILFunctionType loweredTy,
- irgen::IRGenModule &Mod) {
+static bool shouldTransformResults(GenericEnvironment *genEnv,
+ CanSILFunctionType loweredTy,
+ irgen::IRGenModule &Mod) {
if (!modifiableFunction(loweredTy)) {
return false;
}
@@ -274,53 +262,55 @@
genEnv = getGenericEnvironment(F->getModule(), loweredTy);
}
- return modResultType(genEnv, loweredTy, Mod);
+ return shouldTransformResults(genEnv, loweredTy, Mod);
+}
+
+static SILParameterInfo
+getNewParameter(GenericEnvironment *env, SILParameterInfo param,
+ irgen::IRGenModule &IGM) {
+ SILType storageType = param.getSILStorageType();
+ SILType newOptFuncType =
+ getNewOptionalFunctionType(env, storageType, IGM);
+ if (newOptFuncType != storageType) {
+ return param.getWithType(newOptFuncType.getSwiftRValueType());
+ }
+
+ if (auto paramFnType = storageType.getAs<SILFunctionType>()) {
+ if (shouldTransformFunctionType(env, paramFnType, IGM)) {
+ auto newFnType = getNewSILFunctionType(env, paramFnType, IGM);
+ return param.getWithType(newFnType);
+ } else {
+ return param;
+ }
+ } else if (isLargeLoadableType(env, storageType, IGM)) {
+ return SILParameterInfo(storageType.getSwiftRValueType(),
+ ParameterConvention::Indirect_In_Constant);
+ } else {
+ return param;
+ }
}
static SmallVector<SILParameterInfo, 4>
-getNewArgTys(GenericEnvironment *GenericEnv,
- SILFunctionType *currSILFunctionType, irgen::IRGenModule &Mod) {
- ArrayRef<SILParameterInfo> params = currSILFunctionType->getParameters();
- SmallVector<SILParameterInfo, 4> newArgTys;
- for (SILParameterInfo param : params) {
- SILType storageType = param.getSILStorageType();
- SILType newOptFuncType =
- getNewOptionalFunctionType(GenericEnv, storageType, Mod);
- if (newOptFuncType != storageType) {
- auto newParam = SILParameterInfo(newOptFuncType.getSwiftRValueType(),
- param.getConvention());
- newArgTys.push_back(newParam);
- continue;
- }
- CanType currCanType = storageType.getSwiftRValueType();
- if (SILFunctionType *currSILFunctionType =
- dyn_cast<SILFunctionType>(currCanType.getPointer())) {
- if (containsLargeLoadable(GenericEnv,
- currSILFunctionType->getParameters(), Mod) ||
- modResultType(GenericEnv, CanSILFunctionType(currSILFunctionType),
- Mod)) {
- SILType newSILType =
- getNewSILFunctionType(GenericEnv, currSILFunctionType, Mod);
- if (storageType.isAddress()) {
- newSILType = newSILType.getAddressType();
- }
- auto newParam = SILParameterInfo(newSILType.getSwiftRValueType(),
- param.getConvention());
- newArgTys.push_back(newParam);
- } else {
- newArgTys.push_back(param);
- }
- } else if (isLargeLoadableType(GenericEnv, storageType, Mod)) {
- SILType addrType = storageType.getAddressType();
- auto newParam =
- SILParameterInfo(addrType.getSwiftRValueType(),
- ParameterConvention::Indirect_In_Constant);
- newArgTys.push_back(newParam);
- } else {
- newArgTys.push_back(param);
- }
+getNewParameters(GenericEnvironment *env, CanSILFunctionType fnType,
+ irgen::IRGenModule &IGM) {
+ SmallVector<SILParameterInfo, 4> newParams;
+ for (SILParameterInfo param : fnType->getParameters()) {
+ auto newParam = getNewParameter(env, param, IGM);
+ newParams.push_back(newParam);
}
- return newArgTys;
+ return newParams;
+}
+
+static SmallVector<SILYieldInfo, 2>
+getNewYields(GenericEnvironment *env, CanSILFunctionType fnType,
+ irgen::IRGenModule &IGM) {
+ SmallVector<SILYieldInfo, 2> newYields;
+ for (auto oldYield : fnType->getYields()) {
+ auto newYieldAsParam = getNewParameter(env, oldYield, IGM);
+ newYields.push_back(SILYieldInfo(newYieldAsParam.getType(),
+ newYieldAsParam.getConvention()));
+ }
+ return newYields;
}
static SILType getNewSILType(GenericEnvironment *GenericEnv,
@@ -329,17 +319,11 @@
if (newSILType != storageType) {
return newSILType;
}
- CanType currCanType = storageType.getSwiftRValueType();
- if (SILFunctionType *currSILFunctionType =
- dyn_cast<SILFunctionType>(currCanType.getPointer())) {
- if (containsLargeLoadable(GenericEnv, currSILFunctionType->getParameters(),
- Mod) ||
- modResultType(GenericEnv, CanSILFunctionType(currSILFunctionType),
- Mod)) {
- newSILType = getNewSILFunctionType(GenericEnv, currSILFunctionType, Mod);
- if (storageType.isAddress()) {
- newSILType = newSILType.getAddressType();
- }
+ if (auto fnType = storageType.getAs<SILFunctionType>()) {
+ if (shouldTransformFunctionType(GenericEnv, fnType, Mod)) {
+ auto newFnType = getNewSILFunctionType(GenericEnv, fnType, Mod);
+ newSILType = SILType::getPrimitiveType(newFnType,
+ storageType.getCategory());
}
} else if (isLargeLoadableType(GenericEnv, storageType, Mod)) {
newSILType = storageType.getAddressType();
@@ -584,14 +568,14 @@
return;
}
// Check callee - need new generic env:
- SILFunctionType *origSILFunctionType = applySite.getSubstCalleeType();
+ CanSILFunctionType origSILFunctionType = applySite.getSubstCalleeType();
GenericEnvironment *genEnvCallee = nullptr;
if (origSILFunctionType->isPolymorphic()) {
genEnvCallee = getGenericEnvironment(
applySite.getModule(), CanSILFunctionType(origSILFunctionType));
}
- SILFunctionType *newSILFunctionType =
- getNewSILFunctionTypePtr(genEnvCallee, origSILFunctionType, pass.Mod);
+ auto newSILFunctionType =
+ getNewSILFunctionType(genEnvCallee, origSILFunctionType, pass.Mod);
if (origSILFunctionType != newSILFunctionType) {
pass.applies.push_back(applySite.getInstruction());
}
@@ -617,27 +601,19 @@
return;
}
SILType currSILType = instr->getType();
- CanType currCanType = currSILType.getSwiftRValueType();
- SILFunctionType *currSILFunctionType =
- dyn_cast<SILFunctionType>(currCanType.getPointer());
- if (!currSILFunctionType) {
- llvm_unreachable("unsupported type");
- }
+ auto fnType = currSILType.castTo<SILFunctionType>();
+
GenericEnvironment *genEnv = nullptr;
- if (currSILFunctionType->isPolymorphic()) {
- genEnv = getGenericEnvironment(instr->getModule(),
- CanSILFunctionType(currSILFunctionType));
+ if (fnType->isPolymorphic()) {
+ genEnv = getGenericEnvironment(instr->getModule(), fnType);
}
Lowering::GenericContextScope GenericScope(
- instr->getModule().Types, currSILFunctionType->getGenericSignature());
- if (containsLargeLoadable(genEnv, currSILFunctionType->getParameters(),
- pass.Mod) ||
- modResultType(genEnv, CanSILFunctionType(currSILFunctionType),
- pass.Mod)) {
+ instr->getModule().Types, fnType->getGenericSignature());
+ if (shouldTransformFunctionType(genEnv, fnType, pass.Mod)) {
pass.methodInstsToMod.push_back(instr);
return;
}
- if (newResultsDiffer(genEnv, currSILFunctionType->getResults(), pass.Mod)) {
+ if (newResultsDiffer(genEnv, fnType->getResults(), pass.Mod)) {
pass.methodInstsToMod.push_back(instr);
}
}
@@ -763,8 +739,8 @@
if (!genEnv && canFuncType->isPolymorphic()) {
genEnv = getGenericEnvironment(instr->getModule(), canFuncType);
}
- SILFunctionType *newSILFunctionType =
- getNewSILFunctionTypePtr(genEnv, funcType, pass.Mod);
+ auto newSILFunctionType =
+ getNewSILFunctionType(genEnv, funcType, pass.Mod);
if (funcType != newSILFunctionType) {
pass.tupleInstsToMod.push_back(instr);
}
@@ -1255,23 +1231,22 @@
if (!modifiableApply(applySite, pass.Mod)) {
continue;
}
- SILFunctionType *origSILFunctionType = applySite.getSubstCalleeType();
- auto canSILFunctionType = CanSILFunctionType(origSILFunctionType);
+ CanSILFunctionType origSILFunctionType = applySite.getSubstCalleeType();
Lowering::GenericContextScope GenericScope(
- silModue.Types, canSILFunctionType->getGenericSignature());
+ silModue.Types, origSILFunctionType->getGenericSignature());
GenericEnvironment *genEnv = nullptr;
if (origSILFunctionType->isPolymorphic()) {
- genEnv = getGenericEnvironment(silModue, canSILFunctionType);
+ genEnv = getGenericEnvironment(silModue, origSILFunctionType);
}
- if (!modResultType(genEnv, canSILFunctionType, pass.Mod)) {
+ if (!shouldTransformResults(genEnv, origSILFunctionType, pass.Mod)) {
continue;
}
- auto singleResult = canSILFunctionType->getSingleResult();
+ auto singleResult = origSILFunctionType->getSingleResult();
auto resultStorageType = singleResult.getSILStorageType();
if (!isLargeLoadableType(genEnv, resultStorageType, pass.Mod)) {
// Make sure it is a function type
auto canType = resultStorageType.getSwiftRValueType();
- if (!dyn_cast<SILFunctionType>(canType.getPointer())) {
+ if (!isa<SILFunctionType>(canType)) {
// Check if it is an optional funciton type
OptionalTypeKind optKind;
auto optionalType = canType.getAnyOptionalObjectType(optKind);
@@ -1607,19 +1582,16 @@
}
static void castTupleInstr(SingleValueInstruction *instr, IRGenModule &Mod) {
- SILType currSILType = instr->getType().getObjectType();
- CanType currCanType = currSILType.getSwiftRValueType();
- SILFunctionType *funcType = dyn_cast<SILFunctionType>(currCanType);
- assert(funcType && "Expected SILFunctionType as tuple's return");
- CanSILFunctionType canFuncType = CanSILFunctionType(funcType);
+ SILType currSILType = instr->getType();
+ auto funcType = currSILType.castTo<SILFunctionType>();
GenericEnvironment *genEnv = instr->getFunction()->getGenericEnvironment();
- if (!genEnv && canFuncType->isPolymorphic()) {
- genEnv = getGenericEnvironment(instr->getModule(), canFuncType);
+ if (!genEnv && funcType->isPolymorphic()) {
+ genEnv = getGenericEnvironment(instr->getModule(), funcType);
}
- SILType newSILType = getNewSILFunctionType(genEnv, funcType, Mod);
- if (currSILType.isAddress()) {
- newSILType = newSILType.getAddressType();
- }
+ auto newFnType = getNewSILFunctionType(genEnv, funcType, Mod);
+ SILType newSILType =
+ SILType::getPrimitiveType(newFnType, currSILType.getCategory());
+
auto II = instr->getIterator();
++II;
SILBuilder castBuilder(II);
@@ -1993,16 +1965,14 @@
for (MethodInst *instr : pass.methodInstsToMod) {
SILType currSILType = instr->getType();
- CanType currCanType = currSILType.getSwiftRValueType();
- SILFunctionType *currSILFunctionType =
- dyn_cast<SILFunctionType>(currCanType.getPointer());
+ auto currSILFunctionType = currSILType.castTo<SILFunctionType>();
GenericEnvironment *genEnvForMethod = nullptr;
if (currSILFunctionType->isPolymorphic()) {
genEnvForMethod = getGenericEnvironment(
instr->getModule(), CanSILFunctionType(currSILFunctionType));
}
- SILType newSILType =
- getNewSILFunctionType(genEnvForMethod, currSILFunctionType, pass.Mod);
+ SILType newSILType = SILType::getPrimitiveObjectType(
+ getNewSILFunctionType(genEnvForMethod, currSILFunctionType, pass.Mod));
auto member = instr->getMember();
auto loc = instr->getLoc();
SILBuilder methodBuilder(instr);
@@ -2104,7 +2074,9 @@
origResultInfo.getConvention());
auto NewTy = SILFunctionType::get(
loweredTy->getGenericSignature(), loweredTy->getExtInfo(),
+ loweredTy->getCoroutineKind(),
loweredTy->getCalleeConvention(), loweredTy->getParameters(),
+ loweredTy->getYields(),
newSILResultInfo, loweredTy->getOptionalErrorResult(),
F->getModule().getASTContext(),
loweredTy->getWitnessMethodConformanceOrNone());
@@ -2131,10 +2103,8 @@
if (!genEnv && loweredTy->isPolymorphic()) {
genEnv = getGenericEnvironment(F->getModule(), loweredTy);
}
- if (containsLargeLoadable(
- genEnv, F->getLoweredFunctionType()->getParameters(), *currIRMod) ||
- modResultType(genEnv, CanSILFunctionType(F->getLoweredFunctionType()),
- *currIRMod)) {
+ if (shouldTransformFunctionType(genEnv, F->getLoweredFunctionType(),
+ *currIRMod)) {
modFuncs.insert(F);
}
return;
@@ -2178,16 +2148,15 @@
getOperandTypeWithCastIfNecessary(SILInstruction *containingInstr, SILValue op,
IRGenModule &Mod, SILBuilder &builder) {
SILType currSILType = op->getType();
- CanType currCanType = currSILType.getSwiftRValueType();
- SILFunctionType *funcType = dyn_cast<SILFunctionType>(currCanType);
- if (funcType) {
+ if (auto funcType = currSILType.getAs<SILFunctionType>()) {
CanSILFunctionType canFuncType = CanSILFunctionType(funcType);
GenericEnvironment *genEnv =
containingInstr->getFunction()->getGenericEnvironment();
if (!genEnv && canFuncType->isPolymorphic()) {
genEnv = getGenericEnvironment(containingInstr->getModule(), canFuncType);
}
- SILType newSILType = getNewSILFunctionType(genEnv, funcType, Mod);
+ auto newFnType = getNewSILFunctionType(genEnv, funcType, Mod);
+ SILType newSILType = SILType::getPrimitiveObjectType(newFnType);
if (currSILType.isAddress()) {
newSILType = newSILType.getAddressType(); // we need address for loads
if (newSILType != currSILType) {
@@ -2242,7 +2211,7 @@
callee = applySite.getCallee();
}
}
- SILFunctionType *origSILFunctionType = applySite.getSubstCalleeType();
+ CanSILFunctionType origSILFunctionType = applySite.getSubstCalleeType();
auto origCanType = CanSILFunctionType(origSILFunctionType);
Lowering::GenericContextScope GenericScope(
getModule()->Types, origCanType->getGenericSignature());
@@ -2251,8 +2220,8 @@
genEnv = getGenericEnvironment(applyInst->getModule(),
CanSILFunctionType(origSILFunctionType));
}
- SILFunctionType *newSILFunctionType =
- getNewSILFunctionTypePtr(genEnv, origSILFunctionType, *currIRMod);
+ CanSILFunctionType newSILFunctionType =
+ getNewSILFunctionType(genEnv, origSILFunctionType, *currIRMod);
CanSILFunctionType newCanSILFuncType(newSILFunctionType);
SILFunctionConventions newSILFunctionConventions(newCanSILFuncType,
*getModule());
@@ -2432,23 +2401,19 @@
if (auto *thinToPointer = dyn_cast<ThinFunctionToPointerInst>(convInstr)) {
currSILType = thinToPointer->getOperand()->getType();
}
- CanType currCanType = currSILType.getSwiftRValueType();
- SILFunctionType *currSILFunctionType =
- dyn_cast<SILFunctionType>(currCanType.getPointer());
+ auto currSILFunctionType = currSILType.castTo<SILFunctionType>();
Lowering::GenericContextScope GenericScope(
getModule()->Types,
- CanSILFunctionType(currSILFunctionType)->getGenericSignature());
- if (!currSILFunctionType) {
- llvm_unreachable("unsupported type");
- }
+ currSILFunctionType->getGenericSignature());
GenericEnvironment *genEnv =
convInstr->getFunction()->getGenericEnvironment();
auto loweredTy = convInstr->getFunction()->getLoweredFunctionType();
if (!genEnv && loweredTy->isPolymorphic()) {
genEnv = getGenericEnvironment(convInstr->getModule(), loweredTy);
}
- SILType newType =
+ CanSILFunctionType newFnType =
getNewSILFunctionType(genEnv, currSILFunctionType, *currIRMod);
+ SILType newType = SILType::getPrimitiveObjectType(newFnType);
SILBuilder convBuilder(convInstr);
SingleValueInstruction *newInstr = nullptr;
switch (convInstr->getKind()) {
@@ -2511,7 +2476,6 @@
void LoadableByAddress::updateLoweredTypes(SILFunction *F) {
IRGenModule *currIRMod = getIRGenModule()->IRGen.getGenModule(F);
CanSILFunctionType funcType = F->getLoweredFunctionType();
- auto *currSILFunctionType = dyn_cast<SILFunctionType>(funcType.getPointer());
Lowering::GenericContextScope GenericScope(getModule()->Types,
funcType->getGenericSignature());
GenericEnvironment *genEnv = F->getGenericEnvironment();
@@ -2519,10 +2483,8 @@
if (!genEnv && loweredTy->isPolymorphic()) {
genEnv = getGenericEnvironment(F->getModule(), loweredTy);
}
- auto *newFuncTy =
- getNewSILFunctionTypePtr(genEnv, currSILFunctionType, *currIRMod);
-
- F->rewriteLoweredTypeUnsafe(CanSILFunctionType(newFuncTy));
+ auto newFuncTy = getNewSILFunctionType(genEnv, funcType, *currIRMod);
+ F->rewriteLoweredTypeUnsafe(newFuncTy);
}
/// The entry point to this function transformation.
diff --git a/lib/ParseSIL/ParseSIL.cpp b/lib/ParseSIL/ParseSIL.cpp
index 460c6fc..2ba989d 100644
--- a/lib/ParseSIL/ParseSIL.cpp
+++ b/lib/ParseSIL/ParseSIL.cpp
@@ -3735,6 +3735,51 @@
ResultVal = B.createThrow(InstLoc, Val);
break;
}
+ case SILInstructionKind::UnwindInst: {
+ if (parseSILDebugLocation(InstLoc, B))
+ return true;
+ ResultVal = B.createUnwind(InstLoc);
+ break;
+ }
+ case SILInstructionKind::YieldInst: {
+ SmallVector<SILValue, 6> values;
+
+ // Parse a parenthesized (unless length-1), comma-separated list
+ // of yielded values.
+ if (P.consumeIf(tok::l_paren)) {
+ do {
+ if (parseTypedValueRef(Val, B))
+ return true;
+ values.push_back(Val);
+ } while (P.consumeIf(tok::comma));
+
+ if (P.parseToken(tok::r_paren, diag::expected_tok_in_sil_instr, ")"))
+ return true;
+
+ } else {
+ if (parseTypedValueRef(Val, B))
+ return true;
+ values.push_back(Val);
+ }
+
+ Identifier resumeName, unwindName;
+ SourceLoc resumeLoc, unwindLoc;
+ if (P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") ||
+ parseVerbatim("resume") ||
+ parseSILIdentifier(resumeName, resumeLoc,
+ diag::expected_sil_block_name) ||
+ P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") ||
+ parseVerbatim("unwind") ||
+ parseSILIdentifier(unwindName, unwindLoc,
+ diag::expected_sil_block_name) ||
+ parseSILDebugLocation(InstLoc, B))
+ return true;
+
+ auto resumeBB = getBBForReference(resumeName, resumeLoc);
+ auto unwindBB = getBBForReference(unwindName, unwindLoc);
+ ResultVal = B.createYield(InstLoc, values, resumeBB, unwindBB);
+ break;
+ }
case SILInstructionKind::BranchInst: {
Identifier BBName;
SourceLoc NameLoc;
diff --git a/lib/SIL/SILArgument.cpp b/lib/SIL/SILArgument.cpp
index dfd1686..87ed4af 100644
--- a/lib/SIL/SILArgument.cpp
+++ b/lib/SIL/SILArgument.cpp
@@ -73,12 +73,14 @@
case TermKind::UnreachableInst:
case TermKind::ReturnInst:
case TermKind::ThrowInst:
+ case TermKind::UnwindInst:
llvm_unreachable("Have terminator that implies no successors?!");
case TermKind::TryApplyInst:
case TermKind::SwitchValueInst:
case TermKind::SwitchEnumAddrInst:
case TermKind::CheckedCastAddrBranchInst:
case TermKind::DynamicMethodBranchInst:
+ case TermKind::YieldInst:
return SILValue();
case TermKind::BranchInst:
return cast<const BranchInst>(TI)->getArg(Index);
diff --git a/lib/SIL/SILBuilder.cpp b/lib/SIL/SILBuilder.cpp
index 06d7bff..aa65f47 100644
--- a/lib/SIL/SILBuilder.cpp
+++ b/lib/SIL/SILBuilder.cpp
@@ -79,8 +79,10 @@
}
auto appliedFnType = SILFunctionType::get(nullptr, extInfo,
+ FTI->getCoroutineKind(),
calleeConvention,
newParams,
+ FTI->getYields(),
results,
FTI->getOptionalErrorResult(),
M.getASTContext());
diff --git a/lib/SIL/SILFunctionType.cpp b/lib/SIL/SILFunctionType.cpp
index b58e3ad..81f745e 100644
--- a/lib/SIL/SILFunctionType.cpp
+++ b/lib/SIL/SILFunctionType.cpp
@@ -196,10 +196,13 @@
type->getWitnessMethodConformanceOrNone() == witnessMethodConformance)
return type;
- return SILFunctionType::get(type->getGenericSignature(), extInfo, callee,
- type->getParameters(), type->getResults(),
+ return SILFunctionType::get(type->getGenericSignature(),
+ extInfo, type->getCoroutineKind(), callee,
+ type->getParameters(), type->getYields(),
+ type->getResults(),
type->getOptionalErrorResult(),
- type->getASTContext(), witnessMethodConformance);
+ type->getASTContext(),
+ witnessMethodConformance);
}
namespace {
@@ -960,7 +963,8 @@
.withIsPseudogeneric(pseudogeneric)
.withNoEscape(extInfo.isNoEscape());
- return SILFunctionType::get(genericSig, silExtInfo, calleeConvention, inputs,
+ return SILFunctionType::get(genericSig, silExtInfo, SILCoroutineKind::None,
+ calleeConvention, inputs, /*yields*/ {},
results, errorResult, M.getASTContext(),
witnessMethodConformance);
}
@@ -2235,6 +2239,12 @@
substParams.push_back(subst(origParam));
}
+ SmallVector<SILYieldInfo, 8> substYields;
+ substYields.reserve(origType->getYields().size());
+ for (auto &origYield : origType->getYields()) {
+ substYields.push_back(subst(origYield));
+ }
+
Optional<ProtocolConformanceRef> witnessMethodConformance;
if (auto conformance = origType->getWitnessMethodConformanceOrNone()) {
assert(origType->getExtInfo().hasSelfParam());
@@ -2253,8 +2263,9 @@
}
return SILFunctionType::get(nullptr, origType->getExtInfo(),
+ origType->getCoroutineKind(),
origType->getCalleeConvention(), substParams,
- substResults, substErrorResult,
+ substYields, substResults, substErrorResult,
getASTContext(), witnessMethodConformance);
}
@@ -2267,6 +2278,10 @@
return SILResultInfo(visit(orig.getType()), orig.getConvention());
}
+ SILYieldInfo subst(SILYieldInfo orig) {
+ return SILYieldInfo(visit(orig.getType()), orig.getConvention());
+ }
+
SILParameterInfo subst(SILParameterInfo orig) {
return SILParameterInfo(visit(orig.getType()), orig.getConvention());
}
diff --git a/lib/SIL/SILInstructions.cpp b/lib/SIL/SILInstructions.cpp
index 2af36c2..d7ea5dd 100644
--- a/lib/SIL/SILInstructions.cpp
+++ b/lib/SIL/SILInstructions.cpp
@@ -1056,15 +1056,33 @@
case TermKind::CheckedCastAddrBranchInst:
case TermKind::UnreachableInst:
case TermKind::TryApplyInst:
+ case TermKind::YieldInst:
return false;
case TermKind::ReturnInst:
case TermKind::ThrowInst:
+ case TermKind::UnwindInst:
return true;
}
llvm_unreachable("Unhandled TermKind in switch.");
}
+YieldInst::YieldInst(SILDebugLocation loc, ArrayRef<SILValue> yieldedValues,
+ SILBasicBlock *normalBB, SILBasicBlock *unwindBB)
+ : InstructionBase(loc),
+ DestBBs{{this, normalBB}, {this, unwindBB}},
+ Operands(this, yieldedValues) {}
+
+YieldInst *YieldInst::create(SILDebugLocation loc,
+ ArrayRef<SILValue> yieldedValues,
+ SILBasicBlock *normalBB, SILBasicBlock *unwindBB,
+ SILFunction &F) {
+ void *buffer = F.getModule().allocateInst(sizeof(YieldInst) +
+ decltype(Operands)::getExtraSize(yieldedValues.size()),
+ alignof(YieldInst));
+ return ::new (buffer) YieldInst(loc, yieldedValues, normalBB, unwindBB);
+}
+
BranchInst::BranchInst(SILDebugLocation Loc, SILBasicBlock *DestBB,
ArrayRef<SILValue> Args)
: InstructionBase(Loc), DestBB(this, DestBB),
diff --git a/lib/SIL/SILOwnershipVerifier.cpp b/lib/SIL/SILOwnershipVerifier.cpp
index 8372dce..ecade1b 100644
--- a/lib/SIL/SILOwnershipVerifier.cpp
+++ b/lib/SIL/SILOwnershipVerifier.cpp
@@ -448,6 +448,7 @@
NO_OPERAND_INST(StrongRetainUnowned)
NO_OPERAND_INST(UnownedRetain)
NO_OPERAND_INST(Unreachable)
+NO_OPERAND_INST(Unwind)
#undef NO_OPERAND_INST
/// Instructions whose arguments are always compatible with one convention.
@@ -1109,6 +1110,35 @@
}
OwnershipUseCheckerResult
+OwnershipCompatibilityUseChecker::visitYieldInst(YieldInst *I) {
+ // Indirect return arguments are address types.
+ if (isAddressOrTrivialType())
+ return {compatibleWithOwnership(ValueOwnershipKind::Trivial),
+ UseLifetimeConstraint::MustBeLive};
+
+ auto fnType = I->getFunction()->getLoweredFunctionType();
+ auto yieldInfo = fnType->getYields()[getOperandIndex()];
+ switch (yieldInfo.getConvention()) {
+ case ParameterConvention::Indirect_In:
+ case ParameterConvention::Direct_Owned:
+ return visitApplyParameter(ValueOwnershipKind::Owned,
+ UseLifetimeConstraint::MustBeInvalidated);
+ case ParameterConvention::Indirect_In_Constant:
+ case ParameterConvention::Direct_Unowned:
+ // We accept unowned, owned, and guaranteed in unowned positions.
+ return {true, UseLifetimeConstraint::MustBeLive};
+ case ParameterConvention::Indirect_In_Guaranteed:
+ case ParameterConvention::Direct_Guaranteed:
+ return visitApplyParameter(ValueOwnershipKind::Guaranteed,
+ UseLifetimeConstraint::MustBeLive);
+ // The following conventions should take address types.
+ case ParameterConvention::Indirect_Inout:
+ case ParameterConvention::Indirect_InoutAliasable:
+ llvm_unreachable("Unexpected non-trivial parameter convention.");
+ }
+}
+
+OwnershipUseCheckerResult
OwnershipCompatibilityUseChecker::visitAssignInst(AssignInst *I) {
if (getValue() == I->getSrc()) {
if (isAddressOrTrivialType()) {
diff --git a/lib/SIL/SILPrinter.cpp b/lib/SIL/SILPrinter.cpp
index 929d746..541c479 100644
--- a/lib/SIL/SILPrinter.cpp
+++ b/lib/SIL/SILPrinter.cpp
@@ -1854,6 +1854,21 @@
*this << getIDAndType(TI->getOperand());
}
+ void visitUnwindInst(UnwindInst *UI) {
+ // no operands
+ }
+
+ void visitYieldInst(YieldInst *YI) {
+ auto values = YI->getYieldedValues();
+ if (values.size() != 1) *this << '(';
+ interleave(values,
+ [&](SILValue value) { *this << getIDAndType(value); },
+ [&] { *this << ", "; });
+ if (values.size() != 1) *this << ')';
+ *this << ", resume " << Ctx.getID(YI->getResumeBB())
+ << ", unwind " << Ctx.getID(YI->getUnwindBB());
+ }
+
void visitSwitchValueInst(SwitchValueInst *SII) {
*this << getIDAndType(SII->getOperand());
for (unsigned i = 0, e = SII->getNumCases(); i < e; ++i) {
diff --git a/lib/SIL/SILVerifier.cpp b/lib/SIL/SILVerifier.cpp
index 7252575..f3630bf 100644
--- a/lib/SIL/SILVerifier.cpp
+++ b/lib/SIL/SILVerifier.cpp
@@ -941,6 +941,9 @@
"apply instruction cannot call function with error result");
}
+ require(!calleeConv.funcTy->isCoroutine(),
+ "cannot call coroutine with normal apply");
+
// Check that if the apply is of a noreturn callee, make sure that an
// unreachable is the next instruction.
if (AI->getModule().getStage() == SILStage::Raw ||
@@ -955,6 +958,9 @@
SILFunctionConventions calleeConv(AI->getSubstCalleeType(), F.getModule());
+ require(!calleeConv.funcTy->isCoroutine(),
+ "cannot call coroutine with normal apply");
+
auto normalBB = AI->getNormalBB();
require(normalBB->args_size() == 1,
"normal destination of try_apply must take one argument");
@@ -2164,6 +2170,8 @@
auto constantInfo = F.getModule().Types.getConstantInfo(method);
auto methodTy = constantInfo.SILFnType;
+ assert(!methodTy->isCoroutine());
+
// Map interface types to archetypes.
if (auto *env = constantInfo.GenericEnv) {
auto subs = env->getForwardingSubstitutions();
@@ -2196,8 +2204,10 @@
auto fnTy = SILFunctionType::get(nullptr,
methodTy->getExtInfo(),
+ methodTy->getCoroutineKind(),
methodTy->getCalleeConvention(),
dynParams,
+ methodTy->getYields(),
dynResults,
methodTy->getOptionalErrorResult(),
F.getASTContext());
@@ -3309,6 +3319,35 @@
"throw operand type does not match error result type of function");
}
+ void checkUnwindInst(UnwindInst *UI) {
+ require(F.getLoweredFunctionType()->isCoroutine(),
+ "unwind in non-coroutine function");
+ }
+
+ void checkYieldInst(YieldInst *YI) {
+ CanSILFunctionType fnType = F.getLoweredFunctionType();
+ require(fnType->isCoroutine(),
+ "yield in non-coroutine function");
+
+ auto yieldedValues = YI->getYieldedValues();
+ auto yieldInfos = fnType->getYields();
+ require(yieldedValues.size() == yieldInfos.size(),
+ "wrong number of yielded values for function");
+ for (auto i : indices(yieldedValues)) {
+ SILType yieldType =
+ F.mapTypeIntoContext(fnConv.getSILType(yieldInfos[i]));
+ require(yieldedValues[i]->getType() == yieldType,
+ "yielded value does not match yield type of coroutine");
+ }
+
+ // We require the resume and unwind destinations to be unique in order
+ // to prevent either edge from becoming critical.
+ require(YI->getResumeBB()->getSinglePredecessorBlock(),
+ "resume dest of 'yield' must be uniquely used");
+ require(YI->getUnwindBB()->getSinglePredecessorBlock(),
+ "unwind dest of 'yield' must be uniquely used");
+ }
+
void checkSelectEnumCases(SelectEnumInstBase *I) {
EnumDecl *eDecl = I->getEnumOperand()->getType().getEnumOrBoundGenericEnum();
require(eDecl, "select_enum operand must be an enum");
@@ -4147,9 +4186,18 @@
/// - accesses must be uniquely ended
/// - flow-sensitive states must be equivalent on all paths into a block
void verifyFlowSensitiveRules(SILFunction *F) {
+ enum CFGState {
+ /// No special rules are in play.
+ Normal,
+ /// We've followed the resume edge of a yield in a yield_once coroutine.
+ YieldOnceResume,
+ /// We've followed the unwind edge of a yield.
+ YieldUnwind
+ };
struct BBState {
std::vector<SingleValueInstruction*> Stack;
std::set<BeginAccessInst*> Accesses;
+ CFGState CFG = Normal;
};
// Do a breath-first search through the basic blocks.
@@ -4195,6 +4243,29 @@
"return with stack allocs that haven't been deallocated");
require(state.Accesses.empty(),
"return with accesses that haven't been ended");
+
+ if (isa<UnwindInst>(term)) {
+ require(state.CFG == YieldUnwind,
+ "encountered 'unwind' when not on unwind path");
+ } else {
+ require(state.CFG != YieldUnwind,
+ "encountered 'return' or 'throw' when on unwind path");
+ if (isa<ReturnInst>(term) &&
+ F->getLoweredFunctionType()->getCoroutineKind() ==
+ SILCoroutineKind::YieldOnce &&
+ F->getModule().getStage() != SILStage::Raw) {
+ require(state.CFG == YieldOnceResume,
+ "encountered 'return' before yielding a value in "
+ "yield_once coroutine");
+ }
+ }
+ }
+
+ if (isa<YieldInst>(term)) {
+ require(state.CFG != YieldOnceResume,
+ "encountered multiple 'yield's along single path");
+ require(state.CFG == Normal,
+ "encountered 'yield' on abnormal CFG path");
}
auto successors = term->getSuccessors();
@@ -4215,9 +4286,30 @@
// worklist and continue.
if (insertResult.second) {
Worklist.push_back(succBB);
+
+ // If we're following a 'yield', update the CFG state:
+ if (isa<YieldInst>(term)) {
+ // Enforce that the unwind logic is segregated in all stages.
+ if (i == 1) {
+ insertResult.first->second.CFG = YieldUnwind;
+
+ // We check the yield_once rule in the mandatory analyses,
+ // so we can't assert it yet in the raw stage.
+ } else if (F->getLoweredFunctionType()->getCoroutineKind()
+ == SILCoroutineKind::YieldOnce &&
+ F->getModule().getStage() != SILStage::Raw) {
+ insertResult.first->second.CFG = YieldOnceResume;
+ }
+ }
+
continue;
}
+ // This rule is checked elsewhere, but we'd want to assert it
+ // here anyway.
+ require(!isa<YieldInst>(term),
+ "successor of 'yield' should not be encountered twice");
+
// Check that the stack height is consistent coming from all entry
// points into this BB. We only care about consistency if there is
// a possible return from this function along the path starting at
@@ -4233,6 +4325,8 @@
"inconsistent stack heights entering basic block");
require(state.Accesses == foundState.Accesses || isUnreachable(),
"inconsistent access sets entering basic block");
+ require(state.CFG == foundState.CFG,
+ "inconsistent coroutine states entering basic block");
}
}
}
diff --git a/lib/SIL/TypeLowering.cpp b/lib/SIL/TypeLowering.cpp
index da1b89c..9cfd5e6 100644
--- a/lib/SIL/TypeLowering.cpp
+++ b/lib/SIL/TypeLowering.cpp
@@ -2107,9 +2107,9 @@
if (genericSig && genericSig->areAllParamsConcrete())
genericSig = nullptr;
- return SILFunctionType::get(genericSig, extInfo,
+ return SILFunctionType::get(genericSig, extInfo, SILCoroutineKind::None,
/*callee*/ ParameterConvention::Direct_Unowned,
- params, results, None, ctx,
+ params, {}, results, None, ctx,
witnessMethodConformance);
}
diff --git a/lib/SILGen/SILGen.cpp b/lib/SILGen/SILGen.cpp
index bb4e271..d182a49 100644
--- a/lib/SILGen/SILGen.cpp
+++ b/lib/SILGen/SILGen.cpp
@@ -432,8 +432,9 @@
};
CanSILFunctionType topLevelType = SILFunctionType::get(nullptr, extInfo,
+ SILCoroutineKind::None,
ParameterConvention::Direct_Unowned,
- params,
+ params, /*yields*/ {},
SILResultInfo(Int32Ty,
ResultConvention::Unowned),
None,
diff --git a/lib/SILGen/SILGenApply.cpp b/lib/SILGen/SILGenApply.cpp
index 3491497..1813f86 100644
--- a/lib/SILGen/SILGenApply.cpp
+++ b/lib/SILGen/SILGenApply.cpp
@@ -119,6 +119,7 @@
CanSILFunctionType fnType,
CanType newSelfType,
SILDeclRef methodName) {
+ assert(!fnType->isCoroutine());
auto oldParams = fnType->getParameters();
SmallVector<SILParameterInfo, 4> newParams;
newParams.append(oldParams.begin(), oldParams.end() - 1);
@@ -139,7 +140,8 @@
}
return SILFunctionType::get(nullptr, fnType->getExtInfo(),
- fnType->getCalleeConvention(), newParams,
+ SILCoroutineKind::None,
+ fnType->getCalleeConvention(), newParams, {},
newResults, fnType->getOptionalErrorResult(), ctx,
fnType->getWitnessMethodConformanceOrNone());
}
diff --git a/lib/SILGen/SILGenBridging.cpp b/lib/SILGen/SILGenBridging.cpp
index f3a4cc2..c48ce35 100644
--- a/lib/SILGen/SILGenBridging.cpp
+++ b/lib/SILGen/SILGenBridging.cpp
@@ -498,6 +498,8 @@
auto blockInterfaceTy = cast<SILFunctionType>(
F.mapTypeOutOfContext(loweredBlockTy)->getCanonicalType());
+ assert(!blockInterfaceTy->isCoroutine());
+
auto storageTy = SILBlockStorageType::get(loweredFuncTy);
auto storageInterfaceTy = SILBlockStorageType::get(fnInterfaceTy);
@@ -535,8 +537,9 @@
}
auto invokeTy = SILFunctionType::get(
- genericSig, extInfo, ParameterConvention::Direct_Unowned, params,
- blockInterfaceTy->getResults(),
+ genericSig, extInfo, SILCoroutineKind::None,
+ ParameterConvention::Direct_Unowned, params,
+ /*yields*/ {}, blockInterfaceTy->getResults(),
blockInterfaceTy->getOptionalErrorResult(), getASTContext());
// Create the invoke function. Borrow the mangling scheme from reabstraction
diff --git a/lib/SILGen/SILGenConstructor.cpp b/lib/SILGen/SILGenConstructor.cpp
index f782af6..d08ad65 100644
--- a/lib/SILGen/SILGenConstructor.cpp
+++ b/lib/SILGen/SILGenConstructor.cpp
@@ -857,8 +857,10 @@
initConstantTy = SILFunctionType::get(initConstantTy->getGenericSignature(),
initConstantTy->getExtInfo(),
+ SILCoroutineKind::None,
ParameterConvention::Direct_Unowned,
param,
+ /*yields*/ {},
result,
// TODO: throwing initializer?
None,
diff --git a/lib/SILGen/SILGenExpr.cpp b/lib/SILGen/SILGenExpr.cpp
index e1451ef..a0f3f0e 100644
--- a/lib/SILGen/SILGenExpr.cpp
+++ b/lib/SILGen/SILGenExpr.cpp
@@ -3032,8 +3032,9 @@
SILFunctionType::ExtInfo(SILFunctionType::Representation::Thin,
/*pseudogeneric*/ false,
/*noescape*/ false),
+ SILCoroutineKind::None,
ParameterConvention::Direct_Unowned,
- params, result, None, SGF.getASTContext());
+ params, {}, result, None, SGF.getASTContext());
// Find the function and see if we already created it.
SmallVector<CanType, 2> interfaceSubs;
@@ -3152,8 +3153,9 @@
SILFunctionType::ExtInfo(SILFunctionType::Representation::Thin,
/*pseudogeneric*/ false,
/*noescape*/ false),
+ SILCoroutineKind::None,
ParameterConvention::Direct_Unowned,
- params, {}, None, SGF.getASTContext());
+ params, {}, {}, None, SGF.getASTContext());
// Mangle the name of the thunk to see if we already created it.
SmallString<64> nameBuf;
@@ -3320,8 +3322,9 @@
SILFunctionType::ExtInfo(SILFunctionType::Representation::Thin,
/*pseudogeneric*/ false,
/*noescape*/ false),
+ SILCoroutineKind::None,
ParameterConvention::Direct_Unowned,
- params, results, None, C);
+ params, /*yields*/ {}, results, None, C);
// Mangle the name of the thunk to see if we already created it.
SmallString<64> nameBuf;
@@ -3486,8 +3489,9 @@
SILFunctionType::ExtInfo(SILFunctionType::Representation::Thin,
/*pseudogeneric*/ false,
/*noescape*/ false),
+ SILCoroutineKind::None,
ParameterConvention::Direct_Unowned,
- params, results, None, C);
+ params, /*yields*/ {}, results, None, C);
// Mangle the name of the thunk to see if we already created it.
SmallString<64> nameBuf;
diff --git a/lib/SILGen/SILGenFunction.cpp b/lib/SILGen/SILGenFunction.cpp
index 8844bc6..f579dcc 100644
--- a/lib/SILGen/SILGenFunction.cpp
+++ b/lib/SILGen/SILGenFunction.cpp
@@ -475,9 +475,11 @@
SILFunctionType::ExtInfo()
.withRepresentation(SILFunctionType::Representation::
CFunctionPointer),
+ SILCoroutineKind::None,
ParameterConvention::Direct_Unowned,
SILParameterInfo(anyObjectMetaTy,
ParameterConvention::Direct_Unowned),
+ /*yields*/ {},
SILResultInfo(OptNSStringTy,
ResultConvention::Autoreleased),
/*error result*/ None,
@@ -577,8 +579,10 @@
// Should be C calling convention, but NSApplicationMain
// has an overlay to fix the type of argv.
.withRepresentation(SILFunctionType::Representation::Thin),
+ SILCoroutineKind::None,
ParameterConvention::Direct_Unowned,
argTypes,
+ /*yields*/ {},
SILResultInfo(argc->getType().getSwiftRValueType(),
ResultConvention::Unowned),
/*error result*/ None,
diff --git a/lib/SILGen/SILGenPoly.cpp b/lib/SILGen/SILGenPoly.cpp
index 4cd88e0..33dc4ec 100644
--- a/lib/SILGen/SILGenPoly.cpp
+++ b/lib/SILGen/SILGenPoly.cpp
@@ -2837,6 +2837,15 @@
param.getConvention()));
}
+ SmallVector<SILYieldInfo, 4> interfaceYields;
+ for (auto &yield : expectedType->getYields()) {
+ auto yieldIfaceTy = GenericEnvironment::mapTypeOutOfContext(
+ genericEnv, yield.getType());
+ auto interfaceYield =
+ yield.getWithType(yieldIfaceTy->getCanonicalType(genericSig));
+ interfaceYields.push_back(interfaceYield);
+ }
+
SmallVector<SILResultInfo, 4> interfaceResults;
for (auto &result : expectedType->getResults()) {
auto resultIfaceTy = GenericEnvironment::mapTypeOutOfContext(
@@ -2858,9 +2867,10 @@
// The type of the thunk function.
return SILFunctionType::get(genericSig, extInfo,
+ expectedType->getCoroutineKind(),
ParameterConvention::Direct_Unowned,
- interfaceParams, interfaceResults,
- interfaceErrorResult,
+ interfaceParams, interfaceYields,
+ interfaceResults, interfaceErrorResult,
getASTContext());
}
diff --git a/lib/SILOptimizer/ARC/ARCRegionState.cpp b/lib/SILOptimizer/ARC/ARCRegionState.cpp
index e4c2eed..f776571 100644
--- a/lib/SILOptimizer/ARC/ARCRegionState.cpp
+++ b/lib/SILOptimizer/ARC/ARCRegionState.cpp
@@ -170,6 +170,8 @@
// against the operand or can use the value in some way.
case TermKind::ThrowInst:
case TermKind::ReturnInst:
+ case TermKind::UnwindInst:
+ case TermKind::YieldInst:
case TermKind::TryApplyInst:
case TermKind::SwitchValueInst:
case TermKind::SwitchEnumInst:
diff --git a/lib/SILOptimizer/ARC/GlobalARCSequenceDataflow.cpp b/lib/SILOptimizer/ARC/GlobalARCSequenceDataflow.cpp
index bf3d1ae..50ae744 100644
--- a/lib/SILOptimizer/ARC/GlobalARCSequenceDataflow.cpp
+++ b/lib/SILOptimizer/ARC/GlobalARCSequenceDataflow.cpp
@@ -211,6 +211,8 @@
// against the operand or can use the value in some way.
case TermKind::ThrowInst:
case TermKind::ReturnInst:
+ case TermKind::UnwindInst:
+ case TermKind::YieldInst:
case TermKind::TryApplyInst:
case TermKind::SwitchValueInst:
case TermKind::SwitchEnumInst:
diff --git a/lib/SILOptimizer/Analysis/CFG.cpp b/lib/SILOptimizer/Analysis/CFG.cpp
index ef1b825..e0e84de 100644
--- a/lib/SILOptimizer/Analysis/CFG.cpp
+++ b/lib/SILOptimizer/Analysis/CFG.cpp
@@ -34,6 +34,11 @@
case TermKind::UnreachableInst:
case TermKind::ReturnInst:
case TermKind::ThrowInst:
+ case TermKind::UnwindInst:
+ return false;
+ // yield and try_apply are special because they can do arbitrary,
+ // potentially-process-terminating things.
+ case TermKind::YieldInst:
case TermKind::TryApplyInst:
return false;
}
diff --git a/lib/SILOptimizer/IPO/CapturePromotion.cpp b/lib/SILOptimizer/IPO/CapturePromotion.cpp
index 49b1c64..ddaacb2 100644
--- a/lib/SILOptimizer/IPO/CapturePromotion.cpp
+++ b/lib/SILOptimizer/IPO/CapturePromotion.cpp
@@ -416,7 +416,8 @@
// Create the thin function type for the cloned closure.
auto ClonedTy = SILFunctionType::get(
OrigFTI->getGenericSignature(), OrigFTI->getExtInfo(),
- OrigFTI->getCalleeConvention(), ClonedInterfaceArgTys,
+ OrigFTI->getCoroutineKind(), OrigFTI->getCalleeConvention(),
+ ClonedInterfaceArgTys, OrigFTI->getYields(),
OrigFTI->getResults(), OrigFTI->getOptionalErrorResult(),
M.getASTContext(), OrigFTI->getWitnessMethodConformanceOrNone());
diff --git a/lib/SILOptimizer/IPO/ClosureSpecializer.cpp b/lib/SILOptimizer/IPO/ClosureSpecializer.cpp
index 73c0ff0..c21f9c9 100644
--- a/lib/SILOptimizer/IPO/ClosureSpecializer.cpp
+++ b/lib/SILOptimizer/IPO/ClosureSpecializer.cpp
@@ -614,8 +614,9 @@
auto ClonedTy = SILFunctionType::get(
ClosureUserFunTy->getGenericSignature(), ExtInfo,
+ ClosureUserFunTy->getCoroutineKind(),
ClosureUserFunTy->getCalleeConvention(), NewParameterInfoList,
- ClosureUserFunTy->getResults(),
+ ClosureUserFunTy->getYields(), ClosureUserFunTy->getResults(),
ClosureUserFunTy->getOptionalErrorResult(), M.getASTContext());
// We make this function bare so we don't have to worry about decls in the
diff --git a/lib/SILOptimizer/IPO/GlobalOpt.cpp b/lib/SILOptimizer/IPO/GlobalOpt.cpp
index 7de21a7..4d3581c 100644
--- a/lib/SILOptimizer/IPO/GlobalOpt.cpp
+++ b/lib/SILOptimizer/IPO/GlobalOpt.cpp
@@ -260,7 +260,8 @@
SILFunctionType::ExtInfo EInfo;
EInfo = EInfo.withRepresentation(SILFunctionType::Representation::Thin);
auto LoweredType = SILFunctionType::get(nullptr, EInfo,
- ParameterConvention::Direct_Owned, { }, Results, None,
+ SILCoroutineKind::None, ParameterConvention::Direct_Owned,
+ /*params*/ {}, /*yields*/ {}, Results, None,
Store->getModule().getASTContext());
auto *GetterF = Store->getModule().getOrCreateFunction(
Store->getLoc(),
@@ -514,7 +515,8 @@
SILFunctionType::ExtInfo EInfo;
EInfo = EInfo.withRepresentation(SILFunctionType::Representation::Thin);
auto LoweredType = SILFunctionType::get(nullptr, EInfo,
- ParameterConvention::Direct_Owned, { }, Results, None,
+ SILCoroutineKind::None, ParameterConvention::Direct_Owned,
+ /*params*/ {}, /*yields*/ {}, Results, None,
InitF->getASTContext());
auto *GetterF = InitF->getModule().getOrCreateFunction(
InitF->getLocation(),
diff --git a/lib/SILOptimizer/Transforms/AllocBoxToStack.cpp b/lib/SILOptimizer/Transforms/AllocBoxToStack.cpp
index b92c698..996215f 100644
--- a/lib/SILOptimizer/Transforms/AllocBoxToStack.cpp
+++ b/lib/SILOptimizer/Transforms/AllocBoxToStack.cpp
@@ -629,7 +629,8 @@
// the parameters promoted.
auto ClonedTy = SILFunctionType::get(
OrigFTI->getGenericSignature(), OrigFTI->getExtInfo(),
- OrigFTI->getCalleeConvention(), ClonedInterfaceArgTys,
+ OrigFTI->getCoroutineKind(), OrigFTI->getCalleeConvention(),
+ ClonedInterfaceArgTys, OrigFTI->getYields(),
OrigFTI->getResults(), OrigFTI->getOptionalErrorResult(),
M.getASTContext(), OrigFTI->getWitnessMethodConformanceOrNone());
diff --git a/lib/SILOptimizer/Transforms/DeadCodeElimination.cpp b/lib/SILOptimizer/Transforms/DeadCodeElimination.cpp
index 6d0e0df..5e1bca0 100644
--- a/lib/SILOptimizer/Transforms/DeadCodeElimination.cpp
+++ b/lib/SILOptimizer/Transforms/DeadCodeElimination.cpp
@@ -291,6 +291,8 @@
switch (Term->getTermKind()) {
case TermKind::ReturnInst:
case TermKind::ThrowInst:
+ case TermKind::UnwindInst:
+ case TermKind::YieldInst:
case TermKind::UnreachableInst:
case TermKind::SwitchValueInst:
@@ -381,6 +383,7 @@
switch (cast<TermInst>(I)->getTermKind()) {
case TermKind::BranchInst:
case TermKind::UnreachableInst:
+ case TermKind::UnwindInst:
return;
case TermKind::ReturnInst:
@@ -396,6 +399,7 @@
case TermKind::TryApplyInst:
case TermKind::SwitchValueInst:
+ case TermKind::YieldInst:
for (auto &O : I->getAllOperands())
markValueLive(O.get());
return;
diff --git a/lib/SILOptimizer/Transforms/FunctionSignatureOpts.cpp b/lib/SILOptimizer/Transforms/FunctionSignatureOpts.cpp
index c3304da..f43224d 100644
--- a/lib/SILOptimizer/Transforms/FunctionSignatureOpts.cpp
+++ b/lib/SILOptimizer/Transforms/FunctionSignatureOpts.cpp
@@ -577,6 +577,12 @@
InterfaceResults.push_back(InterfaceResult);
}
+ llvm::SmallVector<SILYieldInfo, 8> InterfaceYields;
+ for (SILYieldInfo InterfaceYield : FTy->getYields()) {
+ // For now, don't touch the yield types.
+ InterfaceYields.push_back(InterfaceYield);
+ }
+
bool UsesGenerics = false;
if (HasGenericSignature) {
// Not all of the generic type parameters are used by the function
@@ -630,9 +636,9 @@
UsesGenerics ? FTy->getGenericSignature() : nullptr;
return SILFunctionType::get(
- GenericSig, ExtInfo, FTy->getCalleeConvention(), InterfaceParams,
- InterfaceResults, InterfaceErrorResult, F->getModule().getASTContext(),
- witnessMethodConformance);
+ GenericSig, ExtInfo, FTy->getCoroutineKind(), FTy->getCalleeConvention(),
+ InterfaceParams, InterfaceYields, InterfaceResults, InterfaceErrorResult,
+ F->getModule().getASTContext(), witnessMethodConformance);
}
void FunctionSignatureTransform::createFunctionSignatureOptimizedFunction() {
diff --git a/lib/SILOptimizer/Transforms/Outliner.cpp b/lib/SILOptimizer/Transforms/Outliner.cpp
index 76741f7..47cc57e 100644
--- a/lib/SILOptimizer/Transforms/Outliner.cpp
+++ b/lib/SILOptimizer/Transforms/Outliner.cpp
@@ -290,7 +290,8 @@
SILFunctionType::ExtInfo(SILFunctionType::Representation::Thin,
/*pseudogeneric*/ false, /*noescape*/ false);
auto FunctionType = SILFunctionType::get(
- nullptr, ExtInfo, ParameterConvention::Direct_Unowned, Parameters,
+ nullptr, ExtInfo, SILCoroutineKind::None,
+ ParameterConvention::Direct_Unowned, Parameters, /*yields*/ {},
Results, None, M.getASTContext());
return FunctionType;
}
@@ -1197,7 +1198,8 @@
SILResultInfo(BridgedReturn.getReturnType(), ResultConvention::Owned));
}
auto FunctionType = SILFunctionType::get(
- nullptr, ExtInfo, ParameterConvention::Direct_Unowned, Parameters,
+ nullptr, ExtInfo, SILCoroutineKind::None,
+ ParameterConvention::Direct_Unowned, Parameters, {},
Results, None, M.getASTContext());
return FunctionType;
}
diff --git a/lib/SILOptimizer/Transforms/SimplifyCFG.cpp b/lib/SILOptimizer/Transforms/SimplifyCFG.cpp
index fe6da5e..145a57b 100644
--- a/lib/SILOptimizer/Transforms/SimplifyCFG.cpp
+++ b/lib/SILOptimizer/Transforms/SimplifyCFG.cpp
@@ -2302,6 +2302,8 @@
case TermKind::ThrowInst:
case TermKind::DynamicMethodBranchInst:
case TermKind::ReturnInst:
+ case TermKind::UnwindInst:
+ case TermKind::YieldInst:
break;
}
// If the block has a cond_fail, try to move it to the predecessors.
diff --git a/lib/SILOptimizer/UtilityPasses/BugReducerTester.cpp b/lib/SILOptimizer/UtilityPasses/BugReducerTester.cpp
index 3d6da3c..4219ac2 100644
--- a/lib/SILOptimizer/UtilityPasses/BugReducerTester.cpp
+++ b/lib/SILOptimizer/UtilityPasses/BugReducerTester.cpp
@@ -84,7 +84,8 @@
nullptr, SILFunctionType::ExtInfo(SILFunctionType::Representation::Thin,
false /*isPseudoGeneric*/,
false /*noescape*/),
- ParameterConvention::Direct_Unowned, ArrayRef<SILParameterInfo>(),
+ SILCoroutineKind::None, ParameterConvention::Direct_Unowned,
+ ArrayRef<SILParameterInfo>(), ArrayRef<SILYieldInfo>(),
ResultInfoArray, None, getFunction()->getModule().getASTContext());
SILFunction *F = getFunction()->getModule().getOrCreateSharedFunction(
diff --git a/lib/SILOptimizer/Utils/CFG.cpp b/lib/SILOptimizer/Utils/CFG.cpp
index 452e58d..9f419ba 100644
--- a/lib/SILOptimizer/Utils/CFG.cpp
+++ b/lib/SILOptimizer/Utils/CFG.cpp
@@ -307,9 +307,25 @@
return;
}
+ case TermKind::YieldInst: {
+ auto *YI = cast<YieldInst>(T);
+ assert((EdgeIdx == 0 || EdgeIdx == 1) && "Invalid edge index");
+ auto *resumeBB = !EdgeIdx ? NewDest : YI->getResumeBB();
+ auto *unwindBB = EdgeIdx ? NewDest : YI->getUnwindBB();
+ SmallVector<SILValue, 4> yieldedValues;
+ for (auto value : YI->getYieldedValues())
+ yieldedValues.push_back(value);
+
+ B.createYield(YI->getLoc(), yieldedValues, resumeBB, unwindBB);
+
+ YI->eraseFromParent();
+ return;
+ }
+
case TermKind::ReturnInst:
case TermKind::ThrowInst:
case TermKind::UnreachableInst:
+ case TermKind::UnwindInst:
llvm_unreachable("Branch target cannot be changed for this terminator instruction!");
}
llvm_unreachable("Not yet implemented!");
@@ -469,6 +485,8 @@
case TermKind::ThrowInst:
case TermKind::TryApplyInst:
case TermKind::UnreachableInst:
+ case TermKind::UnwindInst:
+ case TermKind::YieldInst:
llvm_unreachable("Branch target cannot be replaced for this terminator instruction!");
}
llvm_unreachable("Not yet implemented!");
diff --git a/lib/SILOptimizer/Utils/Generics.cpp b/lib/SILOptimizer/Utils/Generics.cpp
index e7dfb6f..eb69a59 100644
--- a/lib/SILOptimizer/Utils/Generics.cpp
+++ b/lib/SILOptimizer/Utils/Generics.cpp
@@ -721,8 +721,10 @@
// Use the new specialized generic signature.
auto NewFnTy = SILFunctionType::get(
- CanSpecializedGenericSig, FnTy->getExtInfo(), FnTy->getCalleeConvention(),
- FnTy->getParameters(), FnTy->getResults(), FnTy->getOptionalErrorResult(),
+ CanSpecializedGenericSig, FnTy->getExtInfo(),
+ FnTy->getCoroutineKind(), FnTy->getCalleeConvention(),
+ FnTy->getParameters(), FnTy->getYields(),
+ FnTy->getResults(), FnTy->getOptionalErrorResult(),
M.getASTContext(), FnTy->getWitnessMethodConformanceOrNone());
// This is an interface type. It should not have any archetypes.
@@ -735,6 +737,7 @@
CanSILFunctionType ReabstractionInfo::
createSpecializedType(CanSILFunctionType SubstFTy, SILModule &M) const {
llvm::SmallVector<SILResultInfo, 8> SpecializedResults;
+ llvm::SmallVector<SILYieldInfo, 8> SpecializedYields;
llvm::SmallVector<SILParameterInfo, 8> SpecializedParams;
unsigned IndirectResultIdx = 0;
@@ -769,9 +772,15 @@
SpecializedParams.push_back(PI);
}
}
+ for (SILYieldInfo YI : SubstFTy->getYields()) {
+ // For now, always just use the original, substituted parameter info.
+ SpecializedYields.push_back(YI);
+ }
return SILFunctionType::get(
- SubstFTy->getGenericSignature(), SubstFTy->getExtInfo(),
- SubstFTy->getCalleeConvention(), SpecializedParams, SpecializedResults,
+ SubstFTy->getGenericSignature(),
+ SubstFTy->getExtInfo(), SubstFTy->getCoroutineKind(),
+ SubstFTy->getCalleeConvention(),
+ SpecializedParams, SpecializedYields, SpecializedResults,
SubstFTy->getOptionalErrorResult(), M.getASTContext(),
SubstFTy->getWitnessMethodConformanceOrNone());
}
diff --git a/lib/SILOptimizer/Utils/SILInliner.cpp b/lib/SILOptimizer/Utils/SILInliner.cpp
index 96c67bb..1fdf29d 100644
--- a/lib/SILOptimizer/Utils/SILInliner.cpp
+++ b/lib/SILOptimizer/Utils/SILInliner.cpp
@@ -338,6 +338,8 @@
case SILInstructionKind::UnreachableInst:
case SILInstructionKind::ReturnInst:
case SILInstructionKind::ThrowInst:
+ case SILInstructionKind::UnwindInst:
+ case SILInstructionKind::YieldInst:
return InlineCost::Free;
case SILInstructionKind::ApplyInst:
diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp
index 5b7508b..9aa42f8 100644
--- a/lib/Sema/TypeCheckType.cpp
+++ b/lib/Sema/TypeCheckType.cpp
@@ -1702,17 +1702,25 @@
TypeResolutionOptions options,
FunctionType::ExtInfo extInfo
= FunctionType::ExtInfo());
- Type resolveSILFunctionType(
- FunctionTypeRepr *repr, TypeResolutionOptions options,
- SILFunctionType::ExtInfo extInfo = SILFunctionType::ExtInfo(),
- ParameterConvention calleeConvention = DefaultParameterConvention,
- TypeRepr *witnessmethodProtocol = nullptr);
+ Type resolveSILFunctionType(FunctionTypeRepr *repr,
+ TypeResolutionOptions options,
+ SILCoroutineKind coroutineKind
+ = SILCoroutineKind::None,
+ SILFunctionType::ExtInfo extInfo
+ = SILFunctionType::ExtInfo(),
+ ParameterConvention calleeConvention
+ = DefaultParameterConvention,
+ TypeRepr *witnessmethodProtocol = nullptr);
SILParameterInfo resolveSILParameter(TypeRepr *repr,
TypeResolutionOptions options);
+ SILYieldInfo resolveSILYield(TypeAttributes &remainingAttrs,
+ TypeRepr *repr, TypeResolutionOptions options);
bool resolveSILResults(TypeRepr *repr, TypeResolutionOptions options,
+ SmallVectorImpl<SILYieldInfo> &yields,
SmallVectorImpl<SILResultInfo> &results,
Optional<SILResultInfo> &errorResult);
bool resolveSingleSILResult(TypeRepr *repr, TypeResolutionOptions options,
+ SmallVectorImpl<SILYieldInfo> &yields,
SmallVectorImpl<SILResultInfo> &results,
Optional<SILResultInfo> &errorResult);
Type resolveSpecifierTypeRepr(SpecifierTypeRepr *repr,
@@ -1970,7 +1978,7 @@
static const TypeAttrKind FunctionAttrs[] = {
TAK_convention, TAK_noreturn, TAK_pseudogeneric,
TAK_callee_owned, TAK_callee_guaranteed, TAK_noescape, TAK_autoclosure,
- TAK_escaping
+ TAK_escaping, TAK_yield_once, TAK_yield_many
};
auto checkUnsupportedAttr = [&](TypeAttrKind attr) {
@@ -2018,6 +2026,13 @@
SILFunctionType::Representation rep;
TypeRepr *witnessMethodProtocol = nullptr;
+ auto coroutineKind = SILCoroutineKind::None;
+ if (attrs.has(TAK_yield_once)) {
+ coroutineKind = SILCoroutineKind::YieldOnce;
+ } else if (attrs.has(TAK_yield_many)) {
+ coroutineKind = SILCoroutineKind::YieldMany;
+ }
+
auto calleeConvention = ParameterConvention::Direct_Unowned;
if (attrs.has(TAK_callee_owned)) {
if (attrs.has(TAK_callee_guaranteed)) {
@@ -2065,7 +2080,8 @@
SILFunctionType::ExtInfo extInfo(rep, attrs.has(TAK_pseudogeneric),
attrs.has(TAK_noescape));
- ty = resolveSILFunctionType(fnRepr, options, extInfo, calleeConvention,
+ ty = resolveSILFunctionType(fnRepr, options, coroutineKind,
+ extInfo, calleeConvention,
witnessMethodProtocol);
if (!ty || ty->hasError()) return ty;
} else if (hasFunctionAttr) {
@@ -2429,6 +2445,7 @@
Type TypeResolver::resolveSILFunctionType(FunctionTypeRepr *repr,
TypeResolutionOptions options,
+ SILCoroutineKind coroutineKind,
SILFunctionType::ExtInfo extInfo,
ParameterConvention callee,
TypeRepr *witnessMethodProtocol) {
@@ -2441,6 +2458,7 @@
// Resolve parameter and result types using the function's generic
// environment.
SmallVector<SILParameterInfo, 4> params;
+ SmallVector<SILYieldInfo, 4> yields;
SmallVector<SILResultInfo, 4> results;
Optional<SILResultInfo> errorResult;
{
@@ -2489,10 +2507,17 @@
{
// FIXME: Deal with unsatisfied dependencies.
- if (resolveSILResults(repr->getResultTypeRepr(), options,
+ if (resolveSILResults(repr->getResultTypeRepr(), options, yields,
results, errorResult)) {
hasError = true;
}
+
+ // Diagnose non-coroutines that declare yields.
+ if (coroutineKind == SILCoroutineKind::None && !yields.empty()) {
+ TC.diagnose(repr->getResultTypeRepr()->getLoc(),
+ diag::sil_non_coro_yields);
+ hasError = true;
+ }
}
} // restore generic type resolver
@@ -2503,6 +2528,7 @@
// FIXME: Remap the parsed context types to interface types.
CanGenericSignature genericSig;
SmallVector<SILParameterInfo, 4> interfaceParams;
+ SmallVector<SILYieldInfo, 4> interfaceYields;
SmallVector<SILResultInfo, 4> interfaceResults;
Optional<SILResultInfo> interfaceErrorResult;
if (auto *genericEnv = repr->getGenericEnvironment()) {
@@ -2513,6 +2539,11 @@
param.getType())->getCanonicalType();
interfaceParams.push_back(param.getWithType(transParamType));
}
+ for (auto &yield : yields) {
+ auto transYieldType = genericEnv->mapTypeOutOfContext(
+ yield.getType())->getCanonicalType();
+ interfaceYields.push_back(yield.getWithType(transYieldType));
+ }
for (auto &result : results) {
auto transResultType = genericEnv->mapTypeOutOfContext(
result.getType())->getCanonicalType();
@@ -2527,6 +2558,7 @@
}
} else {
interfaceParams = params;
+ interfaceYields = yields;
interfaceResults = results;
interfaceErrorResult = errorResult;
}
@@ -2557,9 +2589,20 @@
"found witness_method without matching conformance");
}
- return SILFunctionType::get(genericSig, extInfo, callee, interfaceParams,
- interfaceResults, interfaceErrorResult, Context,
- witnessMethodConformance);
+ return SILFunctionType::get(genericSig, extInfo, coroutineKind,
+ callee,
+ interfaceParams, interfaceYields,
+ interfaceResults, interfaceErrorResult,
+ Context, witnessMethodConformance);
+}
+
+SILYieldInfo TypeResolver::resolveSILYield(TypeAttributes &attrs,
+ TypeRepr *repr,
+ TypeResolutionOptions options) {
+ AttributedTypeRepr attrRepr(attrs, repr);
+ SILParameterInfo paramInfo =
+ resolveSILParameter(&attrRepr, options | TR_ImmediateFunctionInput);
+ return SILYieldInfo(paramInfo.getType(), paramInfo.getConvention());
}
SILParameterInfo TypeResolver::resolveSILParameter(
@@ -2573,6 +2616,7 @@
if (auto attrRepr = dyn_cast<AttributedTypeRepr>(repr)) {
auto attrs = attrRepr->getAttrs();
+
auto checkFor = [&](TypeAttrKind tak, ParameterConvention attrConv) {
if (!attrs.has(tak)) return;
if (convention != DefaultParameterConvention) {
@@ -2615,6 +2659,7 @@
bool TypeResolver::resolveSingleSILResult(TypeRepr *repr,
TypeResolutionOptions options,
+ SmallVectorImpl<SILYieldInfo> &yields,
SmallVectorImpl<SILResultInfo> &ordinaryResults,
Optional<SILResultInfo> &errorResult) {
Type type;
@@ -2625,6 +2670,19 @@
// Copy the attributes out; we're going to destructively modify them.
auto attrs = attrRepr->getAttrs();
+ // Recognize @yields.
+ if (attrs.has(TypeAttrKind::TAK_yields)) {
+ attrs.clearAttribute(TypeAttrKind::TAK_yields);
+
+ // The treatment from this point on is basically completely different.
+ auto yield = resolveSILYield(attrs, attrRepr->getTypeRepr(), options);
+ if (yield.getType()->hasError())
+ return true;
+
+ yields.push_back(yield);
+ return false;
+ }
+
// Recognize @error.
if (attrs.has(TypeAttrKind::TAK_error)) {
attrs.clearAttribute(TypeAttrKind::TAK_error);
@@ -2692,6 +2750,7 @@
bool TypeResolver::resolveSILResults(TypeRepr *repr,
TypeResolutionOptions options,
+ SmallVectorImpl<SILYieldInfo> &yields,
SmallVectorImpl<SILResultInfo> &ordinaryResults,
Optional<SILResultInfo> &errorResult) {
if (auto tuple = dyn_cast<TupleTypeRepr>(repr)) {
@@ -2701,13 +2760,15 @@
TC.diagnose(element.UnderscoreLoc, diag::sil_function_output_label);
}
for (auto elt : tuple->getElements()) {
- if (resolveSingleSILResult(elt.Type, options, ordinaryResults, errorResult))
+ if (resolveSingleSILResult(elt.Type, options,
+ yields, ordinaryResults, errorResult))
hadError = true;
}
return hadError;
}
- return resolveSingleSILResult(repr, options, ordinaryResults, errorResult);
+ return resolveSingleSILResult(repr, options,
+ yields, ordinaryResults, errorResult);
}
Type TypeResolver::resolveSpecifierTypeRepr(SpecifierTypeRepr *repr,
diff --git a/lib/Serialization/Deserialization.cpp b/lib/Serialization/Deserialization.cpp
index 68890a2..be70da1 100644
--- a/lib/Serialization/Deserialization.cpp
+++ b/lib/Serialization/Deserialization.cpp
@@ -3771,6 +3771,26 @@
}
}
+/// Translate from the Serialization coroutine kind enum values to the AST
+/// strongly-typed enum.
+///
+/// The former is guaranteed to be stable, but may not reflect this version of
+/// the AST.
+static Optional<swift::SILCoroutineKind>
+getActualSILCoroutineKind(uint8_t rep) {
+ switch (rep) {
+#define CASE(KIND) \
+ case (uint8_t)serialization::SILCoroutineKind::KIND: \
+ return swift::SILCoroutineKind::KIND;
+ CASE(None)
+ CASE(YieldOnce)
+ CASE(YieldMany)
+#undef CASE
+ default:
+ return None;
+ }
+}
+
/// Translate from the serialization Ownership enumerators, which are
/// guaranteed to be stable, to the AST ones.
static
@@ -4354,22 +4374,26 @@
}
case decls_block::SIL_FUNCTION_TYPE: {
+ uint8_t rawCoroutineKind;
uint8_t rawCalleeConvention;
uint8_t rawRepresentation;
bool pseudogeneric = false;
bool noescape;
bool hasErrorResult;
unsigned numParams;
+ unsigned numYields;
unsigned numResults;
ArrayRef<uint64_t> variableData;
decls_block::SILFunctionTypeLayout::readRecord(scratch,
+ rawCoroutineKind,
rawCalleeConvention,
rawRepresentation,
pseudogeneric,
noescape,
hasErrorResult,
numParams,
+ numYields,
numResults,
variableData);
@@ -4382,6 +4406,13 @@
}
SILFunctionType::ExtInfo extInfo(*representation, pseudogeneric, noescape);
+ // Process the coroutine kind.
+ auto coroutineKind = getActualSILCoroutineKind(rawCoroutineKind);
+ if (!coroutineKind.hasValue()) {
+ error();
+ return nullptr;
+ }
+
// Process the callee convention.
auto calleeConvention = getActualParameterConvention(rawCalleeConvention);
if (!calleeConvention.hasValue()) {
@@ -4397,6 +4428,14 @@
return SILParameterInfo(type->getCanonicalType(), *convention);
};
+ auto processYield = [&](TypeID typeID, uint64_t rawConvention)
+ -> Optional<SILYieldInfo> {
+ auto convention = getActualParameterConvention(rawConvention);
+ auto type = getType(typeID);
+ if (!convention || !type) return None;
+ return SILYieldInfo(type->getCanonicalType(), *convention);
+ };
+
auto processResult = [&](TypeID typeID, uint64_t rawConvention)
-> Optional<SILResultInfo> {
auto convention = getActualResultConvention(rawConvention);
@@ -4428,6 +4467,20 @@
allParams.push_back(*param);
}
+ // Process the yields.
+ SmallVector<SILYieldInfo, 8> allYields;
+ allYields.reserve(numYields);
+ for (unsigned i = 0; i != numYields; ++i) {
+ auto typeID = variableData[nextVariableDataIndex++];
+ auto rawConvention = variableData[nextVariableDataIndex++];
+ auto yield = processYield(typeID, rawConvention);
+ if (!yield) {
+ error();
+ return nullptr;
+ }
+ allYields.push_back(*yield);
+ }
+
// Process the results.
SmallVector<SILResultInfo, 8> allResults;
allParams.reserve(numResults);
@@ -4475,9 +4528,12 @@
genericSig = GenericSignature::get(genericParamTypes, requirements,
/*isKnownCanonical=*/true);
- typeOrOffset = SILFunctionType::get(
- genericSig, extInfo, calleeConvention.getValue(), allParams, allResults,
- errorResult, ctx, witnessMethodConformance);
+ typeOrOffset = SILFunctionType::get(genericSig, extInfo,
+ coroutineKind.getValue(),
+ calleeConvention.getValue(),
+ allParams, allYields, allResults,
+ errorResult,
+ ctx, witnessMethodConformance);
break;
}
diff --git a/lib/Serialization/DeserializeSIL.cpp b/lib/Serialization/DeserializeSIL.cpp
index c9cc2c0..b1e78e8 100644
--- a/lib/Serialization/DeserializeSIL.cpp
+++ b/lib/Serialization/DeserializeSIL.cpp
@@ -2112,6 +2112,27 @@
ResultVal = Builder.createUnreachable(Loc);
break;
}
+ case SILInstructionKind::UnwindInst: {
+ ResultVal = Builder.createUnwind(Loc);
+ break;
+ }
+ case SILInstructionKind::YieldInst: {
+ SILBasicBlock *unwindBB = getBBForReference(Fn, ListOfValues.back());
+ ListOfValues = ListOfValues.drop_back();
+ SILBasicBlock *resumeBB = getBBForReference(Fn, ListOfValues.back());
+ ListOfValues = ListOfValues.drop_back();
+
+ SmallVector<SILValue, 4> yieldedValues;
+ for (unsigned I = 0, E = ListOfValues.size(); I < E; I += 3) {
+ auto valueTy = MF->getType(ListOfValues[I]);
+ auto valueCategory = (SILValueCategory) ListOfValues[I+1];
+ yieldedValues.push_back(
+ getLocalValue(ListOfValues[I+2], getSILType(valueTy, valueCategory)));
+ }
+
+ ResultVal = Builder.createYield(Loc, yieldedValues, resumeBB, unwindBB);
+ break;
+ }
case SILInstructionKind::KeyPathInst: {
unsigned nextValue = 0;
SILType kpTy
diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp
index 524bc75..838bb11 100644
--- a/lib/Serialization/Serialization.cpp
+++ b/lib/Serialization/Serialization.cpp
@@ -3354,6 +3354,18 @@
llvm_unreachable("bad calling convention");
}
+/// Translate from the AST coroutine-kind enum to the Serialization enum
+/// values, which are guaranteed to be stable.
+static uint8_t getRawStableSILCoroutineKind(
+ swift::SILCoroutineKind kind) {
+ switch (kind) {
+ SIMPLE_CASE(SILCoroutineKind, None)
+ SIMPLE_CASE(SILCoroutineKind, YieldOnce)
+ SIMPLE_CASE(SILCoroutineKind, YieldMany)
+ }
+ llvm_unreachable("bad kind");
+}
+
/// Translate from the AST ownership enum to the Serialization enum
/// values, which are guaranteed to be stable.
static uint8_t getRawStableOwnership(swift::Ownership ownership) {
@@ -3674,6 +3686,11 @@
unsigned conv = getRawStableParameterConvention(param.getConvention());
variableData.push_back(TypeID(conv));
}
+ for (auto yield : fnTy->getYields()) {
+ variableData.push_back(addTypeRef(yield.getType()));
+ unsigned conv = getRawStableParameterConvention(yield.getConvention());
+ variableData.push_back(TypeID(conv));
+ }
for (auto result : fnTy->getResults()) {
variableData.push_back(addTypeRef(result.getType()));
unsigned conv = getRawStableResultConvention(result.getConvention());
@@ -3692,15 +3709,19 @@
variableData.push_back(addTypeRef(param));
}
+ auto stableCoroutineKind =
+ getRawStableSILCoroutineKind(fnTy->getCoroutineKind());
+
auto stableCalleeConvention =
getRawStableParameterConvention(fnTy->getCalleeConvention());
unsigned abbrCode = DeclTypeAbbrCodes[SILFunctionTypeLayout::Code];
SILFunctionTypeLayout::emitRecord(
- Out, ScratchRecord, abbrCode, stableCalleeConvention,
+ Out, ScratchRecord, abbrCode,
+ stableCoroutineKind, stableCalleeConvention,
stableRepresentation, fnTy->isPseudogeneric(), fnTy->isNoEscape(),
fnTy->hasErrorResult(), fnTy->getParameters().size(),
- fnTy->getNumResults(), variableData);
+ fnTy->getNumYields(), fnTy->getNumResults(), variableData);
if (auto conformance = fnTy->getWitnessMethodConformanceOrNone())
writeConformance(*conformance, DeclTypeAbbrCodes);
diff --git a/lib/Serialization/SerializeSIL.cpp b/lib/Serialization/SerializeSIL.cpp
index f82cc56..02317e9 100644
--- a/lib/Serialization/SerializeSIL.cpp
+++ b/lib/Serialization/SerializeSIL.cpp
@@ -582,6 +582,7 @@
// TODO: decide if we want to serialize those instructions.
return;
+ case SILInstructionKind::UnwindInst:
case SILInstructionKind::UnreachableInst: {
unsigned abbrCode = SILAbbrCodes[SILInstNoOperandLayout::Code];
SILInstNoOperandLayout::emitRecord(Out, ScratchRecord, abbrCode,
@@ -1124,6 +1125,21 @@
writeOneOperandLayout(SI.getKind(), Attr, SI.getOperand(0));
break;
}
+ case SILInstructionKind::YieldInst: {
+ auto YI = cast<YieldInst>(&SI);
+ SmallVector<ValueID, 4> args;
+ for (auto arg: YI->getYieldedValues()) {
+ args.push_back(S.addTypeRef(arg->getType().getSwiftRValueType()));
+ args.push_back((unsigned)arg->getType().getCategory());
+ args.push_back(addValueRef(arg));
+ }
+ args.push_back(BasicBlockMap[YI->getResumeBB()]);
+ args.push_back(BasicBlockMap[YI->getUnwindBB()]);
+ SILOneTypeValuesLayout::emitRecord(Out, ScratchRecord,
+ SILAbbrCodes[SILOneTypeValuesLayout::Code],
+ (unsigned)YI->getKind(), 0, 0, args);
+ break;
+ }
case SILInstructionKind::FunctionRefInst: {
// Use SILOneOperandLayout to specify the function type and the function
// name (IdentifierID).
diff --git a/test/SIL/Parser/coroutines.sil b/test/SIL/Parser/coroutines.sil
new file mode 100644
index 0000000..2841c71
--- /dev/null
+++ b/test/SIL/Parser/coroutines.sil
@@ -0,0 +1,47 @@
+// RUN: %target-swift-frontend %s -emit-silgen -verify
+
+sil_stage raw
+
+import Swift
+
+sil @once_signature : $@yield_once () -> (@yields Int, @yields Float) {
+bb0:
+ %0 = tuple ()
+ return %0 : $()
+}
+
+sil @many_signature : $@yield_many () -> (@yields Int, @yields Float) {
+bb0:
+ %0 = tuple ()
+ return %0 : $()
+}
+
+sil @yield : $@yield_once (Int, Float) -> (@yields Int, @yields Float) {
+bb0(%0 : $Int, %1 : $Float):
+ yield (%0 : $Int, %1 : $Float), resume bb1, unwind bb2
+
+bb1:
+ %r = tuple ()
+ return %r : $()
+
+bb2:
+ unwind
+}
+
+sil @yield_many : $@yield_many (Int, Float) -> (@yields Int, @yields Float) {
+bb0(%0 : $Int, %1 : $Float):
+ yield (%0 : $Int, %1 : $Float), resume bb1, unwind bb3
+
+bb1:
+ yield (%0 : $Int, %1 : $Float), resume bb2, unwind bb4
+
+bb2:
+ %r = tuple ()
+ return %r : $()
+
+bb3:
+ unwind
+
+bb4:
+ unwind
+}
diff --git a/test/SIL/Parser/coroutines_failure_merge.sil b/test/SIL/Parser/coroutines_failure_merge.sil
new file mode 100644
index 0000000..bf791ee
--- /dev/null
+++ b/test/SIL/Parser/coroutines_failure_merge.sil
@@ -0,0 +1,20 @@
+// RUN: not --crash %target-swift-frontend %s -emit-silgen -verify
+
+sil_stage raw
+
+import Swift
+
+sil @yield : $@yield_many (Int, Float) -> (@yields Int, @yields Float) {
+bb0(%0 : $Int, %1 : $Float):
+ yield (%0 : $Int, %1 : $Float), resume bb1, unwind bb2
+
+bb1:
+ br bb3
+
+bb2:
+ br bb3
+
+bb3:
+ unreachable
+}
+
diff --git a/test/SIL/Parser/coroutines_failure_unwind_return.sil b/test/SIL/Parser/coroutines_failure_unwind_return.sil
new file mode 100644
index 0000000..4f66823
--- /dev/null
+++ b/test/SIL/Parser/coroutines_failure_unwind_return.sil
@@ -0,0 +1,18 @@
+// RUN: not --crash %target-swift-frontend %s -emit-silgen -verify
+
+sil_stage raw
+
+import Swift
+
+sil @yield : $@yield_once (Int, Float) -> (@yields Int, @yields Float) {
+bb0(%0 : $Int, %1 : $Float):
+ yield (%0 : $Int, %1 : $Float), resume bb1, unwind bb2
+
+bb1:
+ %r = tuple ()
+ return %r : $()
+
+bb2:
+ %r2 = tuple ()
+ return %r2 : $()
+}
diff --git a/test/SIL/Parser/coroutines_failure_unwind_reuse.sil b/test/SIL/Parser/coroutines_failure_unwind_reuse.sil
new file mode 100644
index 0000000..39c6dfb
--- /dev/null
+++ b/test/SIL/Parser/coroutines_failure_unwind_reuse.sil
@@ -0,0 +1,24 @@
+// RUN: not --crash %target-swift-frontend %s -emit-silgen -verify
+
+sil_stage raw
+
+import Swift
+
+sil @yield : $@yield_many (Int, Float) -> (@yields Int, @yields Float) {
+bb0(%0 : $Int, %1 : $Float):
+ yield (%0 : $Int, %1 : $Float), resume bb1, unwind bb3
+
+bb1:
+ yield (%0 : $Int, %1 : $Float), resume bb2, unwind bb3
+
+bb2:
+ %r = tuple ()
+ return %r : $()
+
+bb3:
+ unwind
+
+bb4:
+ unwind
+}
+
diff --git a/test/SIL/Parser/coroutines_failure_yieldonce_return.sil b/test/SIL/Parser/coroutines_failure_yieldonce_return.sil
new file mode 100644
index 0000000..05de652
--- /dev/null
+++ b/test/SIL/Parser/coroutines_failure_yieldonce_return.sil
@@ -0,0 +1,11 @@
+// RUN: not --crash %target-swift-frontend %s -emit-silgen -verify
+
+sil_stage canonical
+
+import Swift
+
+sil @once_signature : $@yield_once () -> (@yields Int, @yields Float) {
+bb0:
+ %0 = tuple ()
+ return %0 : $()
+}
diff --git a/test/SIL/Parser/coroutines_failure_yieldonce_twice.sil b/test/SIL/Parser/coroutines_failure_yieldonce_twice.sil
new file mode 100644
index 0000000..382169d
--- /dev/null
+++ b/test/SIL/Parser/coroutines_failure_yieldonce_twice.sil
@@ -0,0 +1,24 @@
+// RUN: not --crash %target-swift-frontend %s -emit-silgen -verify
+
+sil_stage canonical
+
+import Swift
+
+sil @yield : $@yield_once (Int, Float) -> (@yields Int, @yields Float) {
+bb0(%0 : $Int, %1 : $Float):
+ yield (%0 : $Int, %1 : $Float), resume bb1, unwind bb3
+
+bb1:
+ yield (%0 : $Int, %1 : $Float), resume bb2, unwind bb4
+
+bb2:
+ %r = tuple ()
+ return %r : $()
+
+bb3:
+ unwind
+
+bb4:
+ unwind
+}
+