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 &param : 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 &param, 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
+}
+