Merge pull request #15128 from rudkx/handle-relational-constraints-in-bindings

Begin refactoring type variable binding code.
diff --git a/CHANGELOG.md b/CHANGELOG.md
index ab911cf..390d338 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -23,6 +23,19 @@
 Swift 4.2
 ---------
 
+* [SE-0196][]
+  
+  Custom compile-time warnings or error messages can be emitted using the
+  `#warning(_:)` and `#error(_:)` directives.
+
+  ```swift
+  #warning("this is incomplete")
+
+  #if MY_BUILD_CONFIG && MY_OTHER_BUILD_CONFIG
+    #error("MY_BUILD_CONFIG and MY_OTHER_BUILD_CONFIG cannot both be set")
+  #endif
+  ```
+
 * Public classes may now have internal `required` initializers. The rule for
   `required` initializers is that they must be available everywhere the class
   can be subclassed, but previously we said that `required` initializers on
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 0050546..bc10278 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -822,20 +822,23 @@
 endif()
 
 message(STATUS "Building host Swift tools for ${SWIFT_HOST_VARIANT_SDK} ${SWIFT_HOST_VARIANT_ARCH}")
-message(STATUS "  Build type: ${CMAKE_BUILD_TYPE}")
-message(STATUS "  Assertions: ${LLVM_ENABLE_ASSERTIONS}")
-message(STATUS "  LTO:        ${SWIFT_TOOLS_ENABLE_LTO}")
+message(STATUS "  Build type:     ${CMAKE_BUILD_TYPE}")
+message(STATUS "  Assertions:     ${LLVM_ENABLE_ASSERTIONS}")
+message(STATUS "  LTO:            ${SWIFT_TOOLS_ENABLE_LTO}")
+message(STATUS "  +0 Normal Args: ${SWIFT_ENABLE_GUARANTEED_NORMAL_ARGUMENTS}")
 message(STATUS "")
 
-if (SWIFT_BULID_STDLIB OR SWIFT_BUILD_SDK_OVERLAY)
+if (SWIFT_BUILD_STDLIB OR SWIFT_BUILD_SDK_OVERLAY)
 
   message(STATUS "Building Swift standard library and overlays for SDKs: ${SWIFT_SDKS}")
-  message(STATUS "  Build type: ${SWIFT_STDLIB_BUILD_TYPE}")
-  message(STATUS "  Assertions: ${SWIFT_STDLIB_ASSERTIONS}")
+  message(STATUS "  Build type:       ${SWIFT_STDLIB_BUILD_TYPE}")
+  message(STATUS "  Assertions:       ${SWIFT_STDLIB_ASSERTIONS}")
+  message(STATUS "  +0 Normal Args:   ${SWIFT_ENABLE_GUARANTEED_NORMAL_ARGUMENTS}")
   message(STATUS "")
 
   message(STATUS "Building Swift runtime with:")
   message(STATUS "  Leak Detection Checker Entrypoints: ${SWIFT_RUNTIME_ENABLE_LEAK_CHECKER}")
+  message(STATUS "  +0 Normal Args:                     ${SWIFT_ENABLE_GUARANTEED_NORMAL_ARGUMENTS}")
   message(STATUS "")
 
 else()
diff --git a/cmake/modules/AddSwift.cmake b/cmake/modules/AddSwift.cmake
index e837cf6..a251222 100644
--- a/cmake/modules/AddSwift.cmake
+++ b/cmake/modules/AddSwift.cmake
@@ -100,26 +100,8 @@
 
   set(result ${${CFLAGS_RESULT_VAR_NAME}})
 
-  # MSVC and clang-cl don't understand -target.
-  if (NOT SWIFT_COMPILER_IS_MSVC_LIKE)
-    list(APPEND result "-target" "${SWIFT_SDK_${CFLAGS_SDK}_ARCH_${CFLAGS_ARCH}_TRIPLE}")
-  endif()
-
   is_darwin_based_sdk("${CFLAGS_SDK}" IS_DARWIN)
   if(IS_DARWIN)
-    list(APPEND result "-isysroot" "${SWIFT_SDK_${CFLAGS_SDK}_PATH}")
-  elseif(NOT SWIFT_COMPILER_IS_MSVC_LIKE AND NOT "${SWIFT_SDK_${CFLAGS_SDK}_PATH}" STREQUAL "/")
-    list(APPEND result "--sysroot=${SWIFT_SDK_${CFLAGS_SDK}_PATH}")
-  endif()
-
-  if("${CFLAGS_SDK}" STREQUAL "ANDROID")
-    list(APPEND result
-      "--sysroot=${SWIFT_ANDROID_SDK_PATH}"
-      # Use the linker included in the Android NDK.
-      "-B" "${SWIFT_ANDROID_PREBUILT_PATH}/arm-linux-androideabi/bin/")
-  endif()
-
-  if(IS_DARWIN)
     # Check if there's a specific OS deployment version needed for this invocation
     if("${CFLAGS_SDK}" STREQUAL "OSX")
       set(DEPLOYMENT_VERSION ${CFLAGS_DEPLOYMENT_VERSION_OSX})
@@ -134,7 +116,27 @@
     if("${DEPLOYMENT_VERSION}" STREQUAL "")
       set(DEPLOYMENT_VERSION "${SWIFT_SDK_${CFLAGS_SDK}_DEPLOYMENT_VERSION}")
     endif()
+  endif()
 
+  # MSVC and clang-cl don't understand -target.
+  if (NOT SWIFT_COMPILER_IS_MSVC_LIKE)
+    list(APPEND result "-target" "${SWIFT_SDK_${CFLAGS_SDK}_ARCH_${CFLAGS_ARCH}_TRIPLE}${DEPLOYMENT_VERSION}")
+  endif()
+
+  if(IS_DARWIN)
+    list(APPEND result "-isysroot" "${SWIFT_SDK_${CFLAGS_SDK}_PATH}")
+  elseif(NOT SWIFT_COMPILER_IS_MSVC_LIKE AND NOT "${SWIFT_SDK_${CFLAGS_SDK}_PATH}" STREQUAL "/")
+    list(APPEND result "--sysroot=${SWIFT_SDK_${CFLAGS_SDK}_PATH}")
+  endif()
+
+  if("${CFLAGS_SDK}" STREQUAL "ANDROID")
+    list(APPEND result
+      "--sysroot=${SWIFT_ANDROID_SDK_PATH}"
+      # Use the linker included in the Android NDK.
+      "-B" "${SWIFT_ANDROID_PREBUILT_PATH}/arm-linux-androideabi/bin/")
+  endif()
+
+  if(IS_DARWIN)
     list(APPEND result
       "-arch" "${CFLAGS_ARCH}"
       "-F" "${SWIFT_SDK_${CFLAGS_SDK}_PATH}/../../../Developer/Library/Frameworks"
@@ -297,16 +299,19 @@
     list(APPEND result "-sdk" "${SWIFT_SDK_${sdk}_PATH}")
   endif()
 
-  if(BUILD_STANDALONE)
+  is_darwin_based_sdk("${sdk}" IS_DARWIN)
+  if(IS_DARWIN)
     list(APPEND result
-        "-target" "${SWIFT_SDK_${sdk}_ARCH_${arch}_TRIPLE}")
+        "-target" "${SWIFT_SDK_${sdk}_ARCH_${arch}_TRIPLE}${SWIFT_SDK_${sdk}_DEPLOYMENT_VERSION}")
   else()
     list(APPEND result
-        "-target" "${SWIFT_SDK_${sdk}_ARCH_${arch}_TRIPLE}"
-        "-resource-dir" "${SWIFTLIB_DIR}")
+        "-target" "${SWIFT_SDK_${sdk}_ARCH_${arch}_TRIPLE}")
   endif()
 
-  is_darwin_based_sdk("${sdk}" IS_DARWIN)
+  if(NOT BUILD_STANDALONE)
+    list(APPEND result "-resource-dir" "${SWIFTLIB_DIR}")
+  endif()
+
   if(IS_DARWIN)
     list(APPEND result
         "-F" "${SWIFT_SDK_${sdk}_PATH}/../../../Developer/Library/Frameworks")
@@ -2002,7 +2007,7 @@
       BINARY_DIR ${SWIFT_RUNTIME_OUTPUT_INTDIR}
       LIBRARY_DIR ${SWIFT_LIBRARY_OUTPUT_INTDIR})
 
-  target_link_libraries("${name}" ${SWIFTEXE_SINGLE_LINK_LIBRARIES} ${SWIFTEXE_SINGLE_LINK_FAT_LIBRARIES})
+  target_link_libraries("${name}" PRIVATE ${SWIFTEXE_SINGLE_LINK_LIBRARIES} ${SWIFTEXE_SINGLE_LINK_FAT_LIBRARIES})
   swift_common_llvm_config("${name}" ${SWIFTEXE_SINGLE_LLVM_COMPONENT_DEPENDS})
 
   set_target_properties(${name}
diff --git a/cmake/modules/SwiftConfigureSDK.cmake b/cmake/modules/SwiftConfigureSDK.cmake
index 75682c1..ab3c7fb 100644
--- a/cmake/modules/SwiftConfigureSDK.cmake
+++ b/cmake/modules/SwiftConfigureSDK.cmake
@@ -123,7 +123,7 @@
 
   foreach(arch ${architectures})
     set(SWIFT_SDK_${prefix}_ARCH_${arch}_TRIPLE
-        "${arch}-apple-${SWIFT_SDK_${prefix}_TRIPLE_NAME}${SWIFT_SDK_${prefix}_DEPLOYMENT_VERSION}")
+        "${arch}-apple-${SWIFT_SDK_${prefix}_TRIPLE_NAME}")
   endforeach()
 
   # Add this to the list of known SDKs.
@@ -141,7 +141,7 @@
   set(SWIFT_SDK_${prefix}_PATH "${sdkpath}")
   set(SWIFT_SDK_${prefix}_VERSION "don't use")
   set(SWIFT_SDK_${prefix}_BUILD_NUMBER "don't use")
-  set(SWIFT_SDK_${prefix}_DEPLOYMENT_VERSION "don't use")
+  set(SWIFT_SDK_${prefix}_DEPLOYMENT_VERSION "")
   set(SWIFT_SDK_${prefix}_LIB_SUBDIR "${lib_subdir}")
   set(SWIFT_SDK_${prefix}_VERSION_MIN_NAME "")
   set(SWIFT_SDK_${prefix}_TRIPLE_NAME "${triple_name}")
@@ -171,7 +171,7 @@
   set(SWIFT_SDK_${prefix}_PATH "/")
   set(SWIFT_SDK_${prefix}_VERSION "NOTFOUND")
   set(SWIFT_SDK_${prefix}_BUILD_NUMBER "NOTFOUND")
-  set(SWIFT_SDK_${prefix}_DEPLOYMENT_VERSION "NOTFOUND")
+  set(SWIFT_SDK_${prefix}_DEPLOYMENT_VERSION "")
   set(SWIFT_SDK_${prefix}_LIB_SUBDIR "windows")
   set(SWIFT_SDK_${prefix}_VERSION_MIN_NAME "NOTFOUND")
   set(SWIFT_SDK_${prefix}_TRIPLE_NAME "Win32")
diff --git a/cmake/modules/SwiftSharedCMakeConfig.cmake b/cmake/modules/SwiftSharedCMakeConfig.cmake
index a832224..8edeed4 100644
--- a/cmake/modules/SwiftSharedCMakeConfig.cmake
+++ b/cmake/modules/SwiftSharedCMakeConfig.cmake
@@ -309,7 +309,7 @@
     else()
       # HACK: Otherwise (for example, for executables), use a plain signature,
       # because LLVM CMake does that already.
-      target_link_libraries("${target}" ${libnames})
+      target_link_libraries("${target}" PRIVATE ${libnames})
     endif()
   else()
     # If Swift was not built standalone, dispatch to 'llvm_config()'.
diff --git a/docs/OptimizationTips.rst b/docs/OptimizationTips.rst
index f428915..8661d07 100644
--- a/docs/OptimizationTips.rst
+++ b/docs/OptimizationTips.rst
@@ -21,7 +21,7 @@
 ======================
 
 The first thing one should always do is to enable optimization. Swift provides
-three different optimization levels:
+four different optimization levels:
 
 - ``-Onone``: This is meant for normal development. It performs minimal
   optimizations and preserves all debug info.
@@ -35,6 +35,8 @@
   result in undetected memory safety issues and integer overflows. Only use this
   if you have carefully reviewed that your code is safe with respect to integer
   overflow and type casts.
+- ``-Osize``: This is a special optimization mode where the compiler prioritizes
+  code size over performance.
 
 In the Xcode UI, one can modify the current optimization level as follows:
 
diff --git a/docs/WindowsBuild.md b/docs/WindowsBuild.md
index 734729b..7bf7324 100644
--- a/docs/WindowsBuild.md
+++ b/docs/WindowsBuild.md
@@ -121,8 +121,6 @@
   two hours depending on your system.
 - You may need to adjust the `SWIFT_WINDOWS_LIB_DIRECTORY` parameter depending on
   your target platform or Windows SDK version.
-- While the commands here use MSVC to build, using `clang-cl` is recommended (see
-  the **Clang-cl** section below).
 ```cmd
 mkdir "%swift_source_dir%/build/Ninja-DebugAssert/swift-windows-amd64/ninja"
 pushd "%swift_source_dir%/build/Ninja-DebugAssert/swift-windows-amd64/ninja"
diff --git a/include/swift/AST/ConcreteDeclRef.h b/include/swift/AST/ConcreteDeclRef.h
index 6dc3159..d9c378e 100644
--- a/include/swift/AST/ConcreteDeclRef.h
+++ b/include/swift/AST/ConcreteDeclRef.h
@@ -71,7 +71,7 @@
 
   llvm::PointerUnion<ValueDecl *, SpecializedDeclRef *> Data;
 
-  friend class llvm::PointerLikeTypeTraits<ConcreteDeclRef>;
+  friend struct llvm::PointerLikeTypeTraits<ConcreteDeclRef>;
 
 public:
   /// Create an empty declaration reference.
@@ -140,7 +140,7 @@
 } // end namespace swift
 
 namespace llvm {
-  template<> class PointerLikeTypeTraits<swift::ConcreteDeclRef> {
+  template<> struct PointerLikeTypeTraits<swift::ConcreteDeclRef> {
     typedef llvm::PointerUnion<swift::ValueDecl *,
                                swift::ConcreteDeclRef::SpecializedDeclRef *>
       DataPointer;
diff --git a/include/swift/AST/GenericSignatureBuilder.h b/include/swift/AST/GenericSignatureBuilder.h
index ba7931f..ca901bf 100644
--- a/include/swift/AST/GenericSignatureBuilder.h
+++ b/include/swift/AST/GenericSignatureBuilder.h
@@ -447,7 +447,9 @@
 
   /// Add a rewrite rule that makes \c otherPA a part of the given equivalence
   /// class.
-  void addSameTypeRewriteRule(EquivalenceClass *equivClass,
+  ///
+  /// \returns true if a new rewrite rule was added, and false otherwise.
+  bool addSameTypeRewriteRule(EquivalenceClass *equivClass,
                               PotentialArchetype *otherPA);
 
   /// \brief Add a new conformance requirement specifying that the given
diff --git a/include/swift/AST/Identifier.h b/include/swift/AST/Identifier.h
index 784ed2a..957632e 100644
--- a/include/swift/AST/Identifier.h
+++ b/include/swift/AST/Identifier.h
@@ -191,9 +191,9 @@
   };
   
   // An Identifier is "pointer like".
-  template<typename T> class PointerLikeTypeTraits;
+  template<typename T> struct PointerLikeTypeTraits;
   template<>
-  class PointerLikeTypeTraits<swift::Identifier> {
+  struct PointerLikeTypeTraits<swift::Identifier> {
   public:
     static inline void *getAsVoidPointer(swift::Identifier I) {
       return const_cast<void *>(I.getAsOpaquePointer());
@@ -333,8 +333,8 @@
 };
 
 // A DeclBaseName is "pointer like".
-template <typename T> class PointerLikeTypeTraits;
-template <> class PointerLikeTypeTraits<swift::DeclBaseName> {
+template <typename T> struct PointerLikeTypeTraits;
+template <> struct PointerLikeTypeTraits<swift::DeclBaseName> {
 public:
   static inline void *getAsVoidPointer(swift::DeclBaseName D) {
     return const_cast<void *>(D.getAsOpaquePointer());
@@ -687,9 +687,9 @@
 
 namespace llvm {
   // A DeclName is "pointer like".
-  template<typename T> class PointerLikeTypeTraits;
+  template<typename T> struct PointerLikeTypeTraits;
   template<>
-  class PointerLikeTypeTraits<swift::DeclName> {
+  struct PointerLikeTypeTraits<swift::DeclName> {
   public:
     static inline void *getAsVoidPointer(swift::DeclName name) {
       return name.getOpaqueValue();
@@ -717,9 +717,9 @@
   };
 
   // An ObjCSelector is "pointer like".
-  template<typename T> class PointerLikeTypeTraits;
+  template<typename T> struct PointerLikeTypeTraits;
   template<>
-  class PointerLikeTypeTraits<swift::ObjCSelector> {
+  struct PointerLikeTypeTraits<swift::ObjCSelector> {
   public:
     static inline void *getAsVoidPointer(swift::ObjCSelector name) {
       return name.getOpaqueValue();
diff --git a/include/swift/AST/LayoutConstraint.h b/include/swift/AST/LayoutConstraint.h
index ef0561c..961fa8a 100644
--- a/include/swift/AST/LayoutConstraint.h
+++ b/include/swift/AST/LayoutConstraint.h
@@ -395,7 +395,7 @@
 };
 
 // A LayoutConstraint is "pointer like".
-template <> class PointerLikeTypeTraits<swift::LayoutConstraint> {
+template <> struct PointerLikeTypeTraits<swift::LayoutConstraint> {
 public:
   static inline void *getAsVoidPointer(swift::LayoutConstraint I) {
     return (void *)I.getPointer();
diff --git a/include/swift/AST/Type.h b/include/swift/AST/Type.h
index 2619c78..fd1e1ca 100644
--- a/include/swift/AST/Type.h
+++ b/include/swift/AST/Type.h
@@ -674,7 +674,7 @@
 
   // A Type is "pointer like".
   template<>
-  class PointerLikeTypeTraits<swift::Type> {
+  struct PointerLikeTypeTraits<swift::Type> {
   public:
     static inline void *getAsVoidPointer(swift::Type I) {
       return (void*)I.getPointer();
@@ -686,7 +686,7 @@
   };
   
   template<>
-  class PointerLikeTypeTraits<swift::CanType> :
+  struct PointerLikeTypeTraits<swift::CanType> :
     public PointerLikeTypeTraits<swift::Type> {
   public:
     static inline swift::CanType getFromVoidPointer(void *P) {
@@ -695,7 +695,7 @@
   };
 
   template<>
-  class PointerLikeTypeTraits<swift::CanGenericSignature> {
+  struct PointerLikeTypeTraits<swift::CanGenericSignature> {
   public:
     static inline swift::CanGenericSignature getFromVoidPointer(void *P) {
       return swift::CanGenericSignature((swift::GenericSignature*)P);
diff --git a/include/swift/AST/TypeAlignments.h b/include/swift/AST/TypeAlignments.h
index 3c68c5a..f4c4b78 100644
--- a/include/swift/AST/TypeAlignments.h
+++ b/include/swift/AST/TypeAlignments.h
@@ -72,14 +72,14 @@
     }
   };
 
-  template <class T> class PointerLikeTypeTraits;
+  template <class T> struct PointerLikeTypeTraits;
 }
 
 /// Declare the expected alignment of pointers to the given type.
 /// This macro should be invoked from a top-level file context.
 #define LLVM_DECLARE_TYPE_ALIGNMENT(CLASS, ALIGNMENT)     \
 namespace llvm {                                          \
-template <> class PointerLikeTypeTraits<CLASS*>           \
+template <> struct PointerLikeTypeTraits<CLASS*>          \
   : public MoreAlignedPointerTraits<CLASS, ALIGNMENT> {}; \
 }
 
diff --git a/include/swift/Basic/DiverseStack.h b/include/swift/Basic/DiverseStack.h
index 9403912..7445512 100644
--- a/include/swift/Basic/DiverseStack.h
+++ b/include/swift/Basic/DiverseStack.h
@@ -378,7 +378,7 @@
 /// Allow stable_iterators to be put in things like TinyPtrVectors.
 namespace llvm {
   template <>
-  class PointerLikeTypeTraits<
+  struct PointerLikeTypeTraits<
                       swift::DiverseStackBase::stable_iterator::AsPointer> {
     using AsPointer = swift::DiverseStackBase::stable_iterator::AsPointer;
   public:
diff --git a/include/swift/Basic/FlaggedPointer.h b/include/swift/Basic/FlaggedPointer.h
index b409f47..5b5743d 100644
--- a/include/swift/Basic/FlaggedPointer.h
+++ b/include/swift/Basic/FlaggedPointer.h
@@ -152,7 +152,7 @@
 
 // Teach SmallPtrSet that FlaggedPointer is "basically a pointer".
 template <typename PointerTy, unsigned BitPosition, typename PtrTraits>
-class llvm::PointerLikeTypeTraits<
+struct llvm::PointerLikeTypeTraits<
   swift::FlaggedPointer<PointerTy, BitPosition, PtrTraits>> {
 public:
   static inline void *
diff --git a/include/swift/Basic/SupplementaryOutputPaths.h b/include/swift/Basic/SupplementaryOutputPaths.h
index 95098da..6653c7e 100644
--- a/include/swift/Basic/SupplementaryOutputPaths.h
+++ b/include/swift/Basic/SupplementaryOutputPaths.h
@@ -49,6 +49,9 @@
   /// frontend invocation.
   std::string SerializedDiagnosticsPath;
 
+  /// The path to which we should output fix-its as source edits.
+  std::string FixItsOutputPath;
+
   /// The path to which we should output a loaded module trace file.
   /// It is currently only used with WMO, but could be generalized.
   std::string LoadedModuleTracePath;
diff --git a/include/swift/Frontend/FrontendOptions.h b/include/swift/Frontend/FrontendOptions.h
index 0e8146d..62e4829 100644
--- a/include/swift/Frontend/FrontendOptions.h
+++ b/include/swift/Frontend/FrontendOptions.h
@@ -55,9 +55,6 @@
   /// The name of the library to link against when using this module.
   std::string ModuleLinkName;
 
-  /// The path to which we should output fixits as source edits.
-  std::string FixitsOutputPath;
-
   /// Arguments which should be passed in immediate mode.
   std::vector<std::string> ImmediateArgv;
 
diff --git a/include/swift/Frontend/InputFile.h b/include/swift/Frontend/InputFile.h
index caed06f..6965501 100644
--- a/include/swift/Frontend/InputFile.h
+++ b/include/swift/Frontend/InputFile.h
@@ -95,6 +95,9 @@
     return getPrimarySpecificPaths().SupplementaryOutputs
         .SerializedDiagnosticsPath;
   }
+  std::string fixItsOutputPath() const {
+    return getPrimarySpecificPaths().SupplementaryOutputs.FixItsOutputPath;
+  }
 };
 } // namespace swift
 
diff --git a/include/swift/Parse/Lexer.h b/include/swift/Parse/Lexer.h
index 90b544c..9440aa6 100644
--- a/include/swift/Parse/Lexer.h
+++ b/include/swift/Parse/Lexer.h
@@ -195,8 +195,10 @@
   void lex(Token &Result, syntax::Trivia &LeadingTriviaResult,
            syntax::Trivia &TrailingTriviaResult) {
     Result = NextToken;
-    LeadingTriviaResult = {LeadingTrivia};
-    TrailingTriviaResult = {TrailingTrivia};
+    if (TriviaRetention == TriviaRetentionMode::WithTrivia) {
+      LeadingTriviaResult = {LeadingTrivia};
+      TrailingTriviaResult = {TrailingTrivia};
+    }
     if (Result.isNot(tok::eof))
       lexImpl();
   }
diff --git a/include/swift/Runtime/Debug.h b/include/swift/Runtime/Debug.h
index f2fa9a2..c495998 100644
--- a/include/swift/Runtime/Debug.h
+++ b/include/swift/Runtime/Debug.h
@@ -224,6 +224,10 @@
 SWIFT_RUNTIME_STDLIB_SPI
 bool _swift_reportFatalErrorsToDebugger;
 
+SWIFT_RUNTIME_STDLIB_SPI
+bool _swift_shouldReportFatalErrorsToDebugger();
+
+
 LLVM_ATTRIBUTE_ALWAYS_INLINE
 inline static int swift_asprintf(char **strp, const char *fmt, ...) {
   va_list args;
diff --git a/include/swift/SIL/Dominance.h b/include/swift/SIL/Dominance.h
index 539c580..091a9a6 100644
--- a/include/swift/SIL/Dominance.h
+++ b/include/swift/SIL/Dominance.h
@@ -30,10 +30,8 @@
 using SILDomTree = llvm::DomTreeBase<swift::SILBasicBlock>;
 using SILPostDomTree = llvm::PostDomTreeBase<swift::SILBasicBlock>;
 
-extern template void Calculate<SILDomTree, swift::SILFunction>(
-    SILDomTree &DT, swift::SILFunction &F);
-extern template void Calculate<SILPostDomTree, swift::SILFunction>(
-    SILPostDomTree &DT, swift::SILFunction &F);
+extern template void Calculate<SILDomTree>(SILDomTree &DT);
+extern template void Calculate<SILPostDomTree>(SILPostDomTree &DT);
 } // namespace DomTreeBuilder
 } // namespace llvm
 
diff --git a/include/swift/SIL/SILInstruction.h b/include/swift/SIL/SILInstruction.h
index d3ac08b..29b5d64 100644
--- a/include/swift/SIL/SILInstruction.h
+++ b/include/swift/SIL/SILInstruction.h
@@ -166,7 +166,7 @@
   reverse_range getReversedValues() const;
 
   using type_range = llvm::iterator_range<
-      llvm::mapped_iterator<iterator, std::function<SILType(SILValue)>>>;
+    llvm::mapped_iterator<iterator, std::function<SILType(SILValue)>, SILType>>;
   type_range getTypes() const;
 
   bool operator==(const SILInstructionResultArray &rhs);
diff --git a/include/swift/SIL/SILNode.h b/include/swift/SIL/SILNode.h
index b6e0b84..106365a 100644
--- a/include/swift/SIL/SILNode.h
+++ b/include/swift/SIL/SILNode.h
@@ -544,7 +544,7 @@
 /// ValueBase * is always at least eight-byte aligned; make the three tag bits
 /// available through PointerLikeTypeTraits.
 template<>
-class PointerLikeTypeTraits<swift::SILNode *> {
+struct PointerLikeTypeTraits<swift::SILNode *> {
 public:
   static inline void *getAsVoidPointer(swift::SILNode *I) {
     return (void*)I;
diff --git a/include/swift/SIL/SILType.h b/include/swift/SIL/SILType.h
index 9a65ee9..05883c7 100644
--- a/include/swift/SIL/SILType.h
+++ b/include/swift/SIL/SILType.h
@@ -615,7 +615,7 @@
 // Allow the low bit of SILType to be used for nefarious purposes, e.g. putting
 // a SILType into a PointerUnion.
 template<>
-class PointerLikeTypeTraits<swift::SILType> {
+struct PointerLikeTypeTraits<swift::SILType> {
 public:
   static inline void *getAsVoidPointer(swift::SILType T) {
     return T.getOpaqueValue();
diff --git a/include/swift/SIL/SILValue.h b/include/swift/SIL/SILValue.h
index bfc202c..dedf753 100644
--- a/include/swift/SIL/SILValue.h
+++ b/include/swift/SIL/SILValue.h
@@ -272,7 +272,7 @@
 /// ValueBase * is always at least eight-byte aligned; make the three tag bits
 /// available through PointerLikeTypeTraits.
 template<>
-class PointerLikeTypeTraits<swift::ValueBase *> {
+struct PointerLikeTypeTraits<swift::ValueBase *> {
 public:
   static inline void *getAsVoidPointer(swift::ValueBase *I) {
     return (void*)I;
@@ -627,7 +627,7 @@
   };
 
   /// SILValue is a PointerLikeType.
-  template<> class PointerLikeTypeTraits<::swift::SILValue> {
+  template<> struct PointerLikeTypeTraits<::swift::SILValue> {
     using SILValue = ::swift::SILValue;
   public:
     static void *getAsVoidPointer(SILValue v) {
diff --git a/lib/AST/ASTVerifier.cpp b/lib/AST/ASTVerifier.cpp
index cd0c9a1..e8e86f8 100644
--- a/lib/AST/ASTVerifier.cpp
+++ b/lib/AST/ASTVerifier.cpp
@@ -2143,7 +2143,7 @@
         if (ASD->getSetter() &&
             ASD->getSetter()->getFormalAccess() != setterAccess) {
           Out << "AbstractStorageDecl's setter access is out of sync"
-                 " with the access actually on the setter";
+                 " with the access actually on the setter\n";
           abort();
         }
       }
@@ -2151,21 +2151,22 @@
       if (auto getter = ASD->getGetter()) {
         if (getter->isMutating() != ASD->isGetterMutating()) {
           Out << "AbstractStorageDecl::isGetterMutating is out of sync"
-                 " with whether the getter is actually mutating";
+                 " with whether the getter is actually mutating\n";
           abort();
         }
       }
       if (auto setter = ASD->getSetter()) {
         if (setter->isMutating() != ASD->isSetterMutating()) {
           Out << "AbstractStorageDecl::isSetterMutating is out of sync"
-                 " with whether the setter is actually mutating";
+                 " with whether the setter is actually mutating\n";
           abort();
         }
       }
       if (auto materializeForSet = ASD->getMaterializeForSetFunc()) {
-        if (materializeForSet->isMutating() != ASD->isSetterMutating()) {
-          Out << "AbstractStorageDecl::isSetterMutating is out of sync"
-                 " with whether materializeForSet is mutating";
+        if (materializeForSet->isMutating() !=
+            (ASD->isSetterMutating() || ASD->isGetterMutating())) {
+          Out << "AbstractStorageDecl::is{Getter,Setter}Mutating is out of sync"
+                 " with whether materializeForSet is mutating\n";
           abort();
         }
       }
diff --git a/lib/AST/GenericSignatureBuilder.cpp b/lib/AST/GenericSignatureBuilder.cpp
index a63cf56..0d96054 100644
--- a/lib/AST/GenericSignatureBuilder.cpp
+++ b/lib/AST/GenericSignatureBuilder.cpp
@@ -107,6 +107,14 @@
           "Delayed requirements left unresolved");
 STATISTIC(NumConditionalRequirementsAdded,
           "# of conditional requirements added");
+STATISTIC(NumRewriteMinimizations,
+          "# of rewrite system minimizations performed");
+STATISTIC(NumRewriteRhsSimplified,
+          "# of rewrite rule right-hand sides simplified");
+STATISTIC(NumRewriteRhsSimplifiedToLhs,
+          "# of rewrite rule right-hand sides simplified to lhs (and removed)");
+STATISTIC(NumRewriteRulesRedundant,
+          "# of rewrite rules that are redundant (and removed)");
 
 namespace  {
 
@@ -114,6 +122,8 @@
 /// sequence of associated type references.
 using RelativeRewritePath = ArrayRef<AssociatedTypeDecl *>;
 
+class AnchorPathCache;
+
 /// Describes a rewrite path, which contains an optional base (generic
 /// parameter) followed by a sequence of associated type references.
 class RewritePath {
@@ -158,13 +168,25 @@
   /// types.
   Optional<RewritePath> static createPath(Type type);
 
+  /// Decompose a type into a path.
+  ///
+  /// \param path Will be filled in with the components of the path, in
+  /// reverse order.
+  ///
+  /// \returns the generic parameter at the start of the path, or \c None if
+  ///
+  Optional<GenericParamKey>
+  static createPath(Type type, SmallVectorImpl<AssociatedTypeDecl *> &path);
+
   /// Compute the longer common prefix between this path and \c other.
   RewritePath commonPath(const RewritePath &other) const;
 
   /// Form a canonical, dependent type.
   ///
-  /// This requires that the rewrite path have a base.
-  CanType formDependentType(ASTContext &ctx) const;
+  /// This requires that either the rewrite path have a base, or the
+  /// \c baseEquivClass to be non-null (which substitutes in a base).
+  CanType formDependentType(ASTContext &ctx,
+                            AnchorPathCache *anchorPathCache = nullptr) const;
 
   /// Compare the given rewrite paths.
   int compare(const RewritePath &other) const;
@@ -182,6 +204,26 @@
   }
 };
 
+/// A cache that lazily computes the anchor path for the given equivalence
+/// class.
+class AnchorPathCache {
+  GenericSignatureBuilder &builder;
+  EquivalenceClass &equivClass;
+  Optional<RewritePath> anchorPath;
+
+public:
+  AnchorPathCache(GenericSignatureBuilder &builder,
+                  EquivalenceClass &equivClass)
+    : builder(builder), equivClass(equivClass) { }
+
+  Optional<RewritePath> getAnchorPath() {
+    if (anchorPath) return anchorPath;
+
+    anchorPath = RewritePath::createPath(equivClass.getAnchor(builder, { }));
+    return anchorPath;
+  }
+};
+
 /// A node within the prefix tree that is used to match associated type
 /// references.
 class RewriteTreeNode {
@@ -239,12 +281,24 @@
     rewrite = replacementPath;
   }
 
+  /// Remove the rewrite rule.
+  void removeRewriteRule() {
+    assert(hasRewriteRule());
+    assocTypeAndHasRewrite.setInt(false);
+  }
+
   /// Retrieve the path to which this node will be rewritten.
-  const RewritePath &getRewriteRule() const {
+  const RewritePath &getRewriteRule() const & {
     assert(hasRewriteRule());
     return rewrite;
   }
 
+  /// Retrieve the path to which this node will be rewritten.
+  RewritePath &&getRewriteRule() && {
+    assert(hasRewriteRule());
+    return std::move(rewrite);
+  }
+
   /// Add a new rewrite rule to this tree node.
   ///
   /// \param matchPath The path of associated type declarations that must
@@ -252,7 +306,10 @@
   ///
   /// \param replacementPath The sequence of associated type declarations
   /// with which a match will be replaced.
-  void addRewriteRule(RelativeRewritePath matchPath,
+  ///
+  /// \returns true if a rewrite rule was added, and false if it already
+  /// existed.
+  bool addRewriteRule(RelativeRewritePath matchPath,
                       RewritePath replacementPath);
 
   /// Enumerate all of the paths to which the given matched path can be
@@ -283,11 +340,62 @@
   /// \param path The path to match.
   /// \param prefixLength The length of the prefix leading up to \c path.
   Optional<std::pair<unsigned, RewritePath>>
-  bestMatch(GenericParamKey base, RelativeRewritePath path,
+  bestRewritePath(GenericParamKey base, RelativeRewritePath path,
             unsigned prefixLength);
 
   /// Merge the given rewrite tree into \c other.
-  void mergeInto(RewriteTreeNode *other);
+  ///
+  /// \returns true if any rules were created by this merge.
+  bool mergeInto(RewriteTreeNode *other);
+
+  /// An action to perform for the given rule
+  class RuleAction {
+    enum Kind {
+      /// No action; continue traversal.
+      None,
+
+      /// Stop traversal.
+      Stop,
+
+      /// Remove the given rule completely.
+      Remove,
+
+      /// Replace the right-hand side of the rule with the given new path.
+      Replace,
+    } kind;
+
+    RewritePath path;
+
+    RuleAction(Kind kind, RewritePath path = {})
+      : kind(kind), path(path) { }
+
+    friend class RewriteTreeNode;
+
+  public:
+    static RuleAction none() { return RuleAction(None); }
+    static RuleAction stop() { return RuleAction(Stop); }
+    static RuleAction remove() { return RuleAction(Remove); }
+
+    static RuleAction replace(RewritePath path) {
+      return RuleAction(Replace, std::move(path));
+    }
+
+    operator Kind() const { return kind; }
+  };
+
+  /// Callback function for enumerating rules in a tree.
+  using EnumerateCallback =
+    RuleAction(RelativeRewritePath lhs, const RewritePath &rhs);
+
+  /// Enumerate all of the rewrite rules, calling \c fn with the left and
+  /// right-hand sides of each rule.
+  ///
+  /// \returns true if the action function returned \c Stop at any point.
+  bool enumerateRules(llvm::function_ref<EnumerateCallback> fn,
+                      bool temporarilyDisableVisitedRule = false) {
+    SmallVector<AssociatedTypeDecl *, 4> lhs;
+    return enumerateRulesRec(fn, temporarilyDisableVisitedRule, lhs);
+  }
 
   LLVM_ATTRIBUTE_DEPRECATED(void dump() const LLVM_ATTRIBUTE_USED,
                             "only for use within the debugger");
@@ -296,9 +404,13 @@
   void dump(llvm::raw_ostream &out, bool lastChild = true) const;
 
 private:
-  /// Merge the given rewrite tree into \c other.
-  void mergeIntoRec(RewriteTreeNode *other,
-                    llvm::SmallVectorImpl<AssociatedTypeDecl *> &matchPath);
+  /// Enumerate all of the rewrite rules, calling \c fn with the left and
+  /// right-hand sides of each rule.
+  ///
+  /// \returns true if the action function returned \c Stop at any point.
+  bool enumerateRulesRec(llvm::function_ref<EnumerateCallback> &fn,
+                         bool temporarilyDisableVisitedRule,
+                         llvm::SmallVectorImpl<AssociatedTypeDecl *> &lhs);
 };
 }
 
@@ -329,6 +441,13 @@
   DenseMap<const EquivalenceClass *, std::unique_ptr<RewriteTreeNode>>
     RewriteTreeRoots;
 
+  /// The generation number for the term-rewriting system, which is
+  /// increased every time a new rule gets added.
+  unsigned RewriteGeneration = 0;
+
+  /// The generation at which the term-rewriting system was last minimized.
+  unsigned LastRewriteMinimizedGeneration = 0;
+
   /// The generation number, which is incremented whenever we successfully
   /// introduce a new constraint.
   unsigned Generation = 0;
@@ -339,6 +458,9 @@
   /// Whether we are currently processing delayed requirements.
   bool ProcessingDelayedRequirements = false;
 
+  /// Whether we are currently minimizing the term-rewriting system.
+  bool MinimizingRewriteSystem = false;
+
   /// Whether there were any errors.
   bool HadAnyError = false;
 
@@ -369,6 +491,21 @@
   /// creating it if needed.
   RewriteTreeNode *getOrCreateRewriteTreeRoot(
                                         const EquivalenceClass *equivClass);
+
+  /// Minimize the rewrite tree by minimizing the right-hand sides and
+  /// removing redundant rules.
+  void minimizeRewriteTree(GenericSignatureBuilder &builder);
+
+private:
+  /// Minimize the right-hand sides of the rewrite tree, simplifying them
+  /// as far as possible and removing any changes that result in trivial
+  /// rules.
+  void minimizeRewriteTreeRhs(GenericSignatureBuilder &builder);
+
+  /// Minimize the right-hand sides of the rewrite tree, simplifying them
+  /// as far as possible and removing any changes that result in trivial
+  /// rules.
+  void removeRewriteTreeRedundancies(GenericSignatureBuilder &builder);
 };
 
 #pragma mark Memory management
@@ -3038,6 +3175,16 @@
 
 Optional<RewritePath> RewritePath::createPath(Type type) {
   SmallVector<AssociatedTypeDecl *, 4> path;
+  if (auto genericParam = createPath(type, path)) {
+    return RewritePath(*genericParam, path, Reverse);
+  }
+
+  return None;
+}
+
+Optional<GenericParamKey>
+RewritePath::createPath(Type type,
+                        SmallVectorImpl<AssociatedTypeDecl *> &path) {
   while (auto depMemTy = type->getAs<DependentMemberType>()) {
     auto assocType = depMemTy->getAssocType();
     if (!assocType) return None;
@@ -3049,7 +3196,7 @@
   auto genericParam = type->getAs<GenericTypeParamType>();
   if (!genericParam) return None;
 
-  return RewritePath(GenericParamKey(genericParam), path, Reverse);
+  return GenericParamKey(genericParam);
 }
 
 RewritePath RewritePath::commonPath(const RewritePath &other) const {
@@ -3090,9 +3237,24 @@
                            path);
 }
 
-CanType RewritePath::formDependentType(ASTContext &ctx) const {
-  assert(getBase());
-  return CanType(::formDependentType(ctx, *getBase(), getPath()));
+CanType RewritePath::formDependentType(
+                                     ASTContext &ctx,
+                                     AnchorPathCache *anchorPathCache) const {
+  if (auto base = getBase())
+    return CanType(::formDependentType(ctx, *base, getPath()));
+
+  assert(anchorPathCache && "Need an anchor path cache");
+  Optional<RewritePath> anchorPath = anchorPathCache->getAnchorPath();
+  if (!anchorPath) return CanType();
+
+  // Add the relative path to the anchor path.
+  SmallVector<AssociatedTypeDecl *, 4> absolutePath;
+  absolutePath.append(anchorPath->getPath().begin(),
+                      anchorPath->getPath().end());
+  absolutePath.append(getPath().begin(), getPath().end());
+  return CanType(::formDependentType(ctx, *anchorPath->getBase(),
+                                     absolutePath));
+
 }
 
 int RewritePath::compare(const RewritePath &other) const {
@@ -3162,25 +3324,25 @@
 };
 }
 
-void RewriteTreeNode::addRewriteRule(RelativeRewritePath matchPath,
+bool RewriteTreeNode::addRewriteRule(RelativeRewritePath matchPath,
                                      RewritePath replacementPath) {
   // If the match path is empty, we're adding the rewrite rule to this node.
   if (matchPath.empty()) {
     // If we don't already have a rewrite rule, add it.
     if (!hasRewriteRule()) {
       setRewriteRule(replacementPath);
-      return;
+      return true;
     }
 
     // If we already have this rewrite rule, we're done.
-    if (getRewriteRule() == replacementPath) return;
+    if (getRewriteRule() == replacementPath) return false;
 
     // Check whether any of the continuation children matches.
     auto insertPos = children.begin();
     while (insertPos != children.end() && !(*insertPos)->getMatch()) {
       if ((*insertPos)->hasRewriteRule() &&
           (*insertPos)->getRewriteRule() == replacementPath)
-        return;
+        return false;
 
       ++insertPos;
     }
@@ -3190,7 +3352,7 @@
     auto newChild = new RewriteTreeNode(nullptr);
     newChild->setRewriteRule(replacementPath);
     children.insert(insertPos, newChild);
-    return;
+    return true;
   }
 
   // Find (or create) a child node describing the next step in the match.
@@ -3203,7 +3365,7 @@
   }
 
   // Add the rewrite rule to the child.
-  (*childPos)->addRewriteRule(matchPath.slice(1), replacementPath);
+  return (*childPos)->addRewriteRule(matchPath.slice(1), replacementPath);
 }
 
 void RewriteTreeNode::enumerateRewritePathsImpl(
@@ -3236,7 +3398,7 @@
 }
 
 Optional<std::pair<unsigned, RewritePath>>
-RewriteTreeNode::bestMatch(GenericParamKey base, RelativeRewritePath path,
+RewriteTreeNode::bestRewritePath(GenericParamKey base, RelativeRewritePath path,
                            unsigned prefixLength) {
   Optional<std::pair<unsigned, RewritePath>> best;
   unsigned bestAdjustedLength = 0;
@@ -3267,29 +3429,82 @@
   return best;
 }
 
-void RewriteTreeNode::mergeInto(RewriteTreeNode *other) {
-  SmallVector<AssociatedTypeDecl *, 4> matchPath;
-  mergeIntoRec(other, matchPath);
-}
-
-void RewriteTreeNode::mergeIntoRec(
-                     RewriteTreeNode *other,
-                     llvm::SmallVectorImpl<AssociatedTypeDecl *> &matchPath) {
+bool RewriteTreeNode::mergeInto(RewriteTreeNode *other) {
   // FIXME: A destructive version of this operation would be more efficient,
   // since we generally don't care about \c other after doing this.
-  if (auto assocType = getMatch())
-    matchPath.push_back(assocType);
+  bool anyAdded = false;
+  (void)enumerateRules([other, &anyAdded](RelativeRewritePath lhs,
+                                          const RewritePath &rhs) {
+    if (other->addRewriteRule(lhs, rhs))
+      anyAdded = true;
+    return RuleAction::none();
+  });
 
-  // Add this rewrite rule, if there is one.
-  if (hasRewriteRule())
-    other->addRewriteRule(matchPath, rewrite);
+  return anyAdded;
+}
+
+bool RewriteTreeNode::enumerateRulesRec(
+                            llvm::function_ref<EnumerateCallback> &fn,
+                            bool temporarilyDisableVisitedRule,
+                            llvm::SmallVectorImpl<AssociatedTypeDecl *> &lhs) {
+  if (auto assocType = getMatch())
+    lhs.push_back(assocType);
+
+  SWIFT_DEFER {
+    if (auto assocType = getMatch())
+      lhs.pop_back();
+  };
+
+  // If there is a rewrite rule, invoke the callback.
+  if (hasRewriteRule()) {
+    // If we're supposed to temporarily disabled the visited rule, do so
+    // now.
+    Optional<RewritePath> rewriteRule;
+    if (temporarilyDisableVisitedRule) {
+      rewriteRule = std::move(*this).getRewriteRule();
+      removeRewriteRule();
+    }
+
+    // Make sure that we put the rewrite rule back in place if we moved it
+    // aside.
+    SWIFT_DEFER {
+      if (temporarilyDisableVisitedRule && rewriteRule)
+        setRewriteRule(*std::move(rewriteRule));
+    };
+
+    switch (auto action =
+                fn(lhs, rewriteRule ? *rewriteRule : getRewriteRule())) {
+    case RuleAction::None:
+      break;
+
+    case RuleAction::Stop:
+      return true;
+
+    case RuleAction::Remove:
+      if (temporarilyDisableVisitedRule)
+        rewriteRule = None;
+      else
+        removeRewriteRule();
+      break;
+
+    case RuleAction::Replace:
+      if (temporarilyDisableVisitedRule) {
+        rewriteRule = std::move(action.path);
+      } else {
+        removeRewriteRule();
+        setRewriteRule(action.path);
+      }
+      break;
+    }
+  }
 
   // Recurse into the child nodes.
-  for (auto child : children)
-    child->mergeIntoRec(other, matchPath);
+  for (auto child : children) {
+    if (child->enumerateRulesRec(fn, temporarilyDisableVisitedRule, lhs))
+      return true;
+  }
 
-  if (getMatch())
-    matchPath.pop_back();
+  return false;
 }
 
 void RewriteTreeNode::dump() const {
@@ -3354,22 +3569,133 @@
   return root.get();
 }
 
-void GenericSignatureBuilder::addSameTypeRewriteRule(
+void GenericSignatureBuilder::Implementation::minimizeRewriteTree(
+                                            GenericSignatureBuilder &builder) {
+  // Only perform minimization if the term-rewriting tree has changed.
+  if (LastRewriteMinimizedGeneration == RewriteGeneration
+      || MinimizingRewriteSystem)
+    return;
+
+  ++NumRewriteMinimizations;
+  llvm::SaveAndRestore<bool> minimizingRewriteSystem(MinimizingRewriteSystem,
+                                                     true);
+  SWIFT_DEFER {
+    LastRewriteMinimizedGeneration = RewriteGeneration;
+  };
+
+  minimizeRewriteTreeRhs(builder);
+  removeRewriteTreeRedundancies(builder);
+}
+
+void GenericSignatureBuilder::Implementation::minimizeRewriteTreeRhs(
+                                            GenericSignatureBuilder &builder) {
+  assert(MinimizingRewriteSystem);
+
+  // Minimize the right-hand sides of each rule in the tree.
+  for (auto &equivClass : EquivalenceClasses) {
+    auto root = RewriteTreeRoots.find(&equivClass);
+    if (root == RewriteTreeRoots.end()) continue;
+
+    AnchorPathCache anchorPathCache(builder, equivClass);
+
+    ASTContext &ctx = builder.getASTContext();
+    root->second->enumerateRules([&](RelativeRewritePath lhs,
+                                     const RewritePath &rhs) {
+      // Compute the type of the right-hand side.
+      Type rhsType = rhs.formDependentType(ctx, &anchorPathCache);
+      if (!rhsType) return RewriteTreeNode::RuleAction::none();
+
+      // Compute the canonical type for the right-hand side.
+      Type canonicalRhsType = builder.getCanonicalTypeParameter(rhsType);
+
+      // If the canonicalized result is equivalent to the right-hand side we
+      // had, there's nothing to do.
+      if (rhsType->isEqual(canonicalRhsType))
+        return RewriteTreeNode::RuleAction::none();
+
+      // We have a canonical replacement path. Determine its encoding and
+      // perform the replacement.
+      ++NumRewriteRhsSimplified;
+
+      // Determine replacement path, which might be relative to the anchor.
+      auto canonicalRhsPath = *RewritePath::createPath(canonicalRhsType);
+      auto anchorPath = anchorPathCache.getAnchorPath();
+      if (auto prefix = anchorPath->commonPath(canonicalRhsPath)) {
+        unsigned prefixLength = prefix.getPath().size();
+        RelativeRewritePath replacementRhsPath =
+          canonicalRhsPath.getPath().slice(prefixLength);
+
+        // If the left and right-hand sides are equivalent, just remove the
+        // rule.
+        if (lhs == replacementRhsPath) {
+          ++NumRewriteRhsSimplifiedToLhs;
+          return RewriteTreeNode::RuleAction::remove();
+        }
+
+        RewritePath replacementRhs(None, replacementRhsPath,
+                                   RewritePath::Forward);
+        return RewriteTreeNode::RuleAction::replace(std::move(replacementRhs));
+      }
+
+      return RewriteTreeNode::RuleAction::replace(canonicalRhsPath);
+    });
+  }
+}
+
+void GenericSignatureBuilder::Implementation::removeRewriteTreeRedundancies(
+                                            GenericSignatureBuilder &builder) {
+  assert(MinimizingRewriteSystem);
+
+  // Minimize the right-hand sides of each rule in the tree.
+  for (auto &equivClass : EquivalenceClasses) {
+    auto root = RewriteTreeRoots.find(&equivClass);
+    if (root == RewriteTreeRoots.end()) continue;
+
+    AnchorPathCache anchorPathCache(builder, equivClass);
+
+    ASTContext &ctx = builder.getASTContext();
+    root->second->enumerateRules([&](RelativeRewritePath lhs,
+                                     const RewritePath &rhs) {
+      /// Left-hand side type.
+      Type lhsType = RewritePath(None, lhs, RewritePath::Forward)
+                       .formDependentType(ctx, &anchorPathCache);
+      if (!lhsType) return RewriteTreeNode::RuleAction::none();
+
+      // Simplify the left-hand type.
+      Type simplifiedLhsType = builder.getCanonicalTypeParameter(lhsType);
+      if (!simplifiedLhsType) return RewriteTreeNode::RuleAction::none();
+
+      // Compute the type of the right-hand side.
+      Type rhsType = rhs.formDependentType(ctx, &anchorPathCache);
+      if (!rhsType) return RewriteTreeNode::RuleAction::none();
+
+      if (simplifiedLhsType->isEqual(rhsType)) {
+        ++NumRewriteRulesRedundant;
+        return RewriteTreeNode::RuleAction::remove();
+      }
+
+      return RewriteTreeNode::RuleAction::none();
+    },
+    /*temporarilyDisableVisitedRule=*/true);
+  }
+}
+
+bool GenericSignatureBuilder::addSameTypeRewriteRule(
                                                 EquivalenceClass *equivClass,
                                                 PotentialArchetype *otherPA){
   // Simplify both sides in the hope of uncovering a common path.
   Type simplifiedType1 = equivClass->getAnchor(*this, { });
-  if (!simplifiedType1) return;
+  if (!simplifiedType1) return false;
 
   Type simplifiedType2;
   if (auto otherEquivClass = otherPA->getEquivalenceClassIfPresent())
     simplifiedType2 = otherEquivClass->getAnchor(*this, { });
   else
     simplifiedType2 = getCanonicalTypeParameter(otherPA->getDependentType({ }));
-  if (!simplifiedType2) return;
+  if (!simplifiedType2) return false;
 
   // We already effectively have this rewrite rule.
-  if (simplifiedType1->isEqual(simplifiedType2)) return;
+  if (simplifiedType1->isEqual(simplifiedType2)) return false;
 
   auto path1 = *RewritePath::createPath(simplifiedType1);
   auto path2 = *RewritePath::createPath(simplifiedType2);
@@ -3394,10 +3720,9 @@
 
     // Add the rewrite rule.
     auto root = Impl->getOrCreateRewriteTreeRoot(equivClass);
-    root->addRewriteRule(relPath1,
-                         RewritePath(None, relPath2, RewritePath::Forward));
-
-    return;
+    return root->addRewriteRule(
+                          relPath1,
+                          RewritePath(None, relPath2, RewritePath::Forward));
   }
 
   // Otherwise, form a rewrite rule with absolute paths.
@@ -3417,7 +3742,7 @@
   assert(baseEquivClass && "Base cannot be resolved?");
 
   auto root = Impl->getOrCreateRewriteTreeRoot(baseEquivClass);
-  root->addRewriteRule(path1.getPath(), path2);
+  return root->addRewriteRule(path1.getPath(), path2);
 }
 
 Type GenericSignatureBuilder::getCanonicalTypeParameter(Type type) {
@@ -3443,7 +3768,7 @@
     if (auto rootNode = Impl->getRewriteTreeRootIfPresent(equivClass)) {
       // Find the best rewrite rule for the path starting at startIndex.
       auto match =
-        rootNode->bestMatch(genericParamType,
+        rootNode->bestRewritePath(genericParamType,
                             llvm::makeArrayRef(path).slice(startIndex),
                             startIndex);
 
@@ -4143,7 +4468,9 @@
         // ... from the same module as the protocol.
         if (type->getModuleContext() != proto->getModuleContext()) continue;
 
-        // Or is constrained.
+        // Ignore types defined in constrained extensions; their equivalence
+        // to the associated type would have to be conditional, which we cannot
+        // model.
         if (auto ext = dyn_cast<ExtensionDecl>(type->getDeclContext())) {
           if (ext->isConstrainedExtension()) continue;
         }
@@ -4564,7 +4891,8 @@
 
   // Add a rewrite rule to map T2 down to the anchor.
   auto equivClass = T1->getOrCreateEquivalenceClass(*this);
-  addSameTypeRewriteRule(equivClass, T2);
+  if (addSameTypeRewriteRule(equivClass, T2))
+    ++Impl->RewriteGeneration;
 
   // Merge the equivalence classes.
   equivClass->modified(*this);
@@ -4595,7 +4923,8 @@
     if (auto rewriteRoot2 = Impl->getOrCreateRewriteTreeRoot(equivClass2)) {
       if (auto rewriteRoot1 = Impl->getOrCreateRewriteTreeRoot(equivClass)) {
         // Merge the second rewrite tree into the first.
-        rewriteRoot2->mergeInto(rewriteRoot1);
+        if (rewriteRoot2->mergeInto(rewriteRoot1))
+          ++Impl->RewriteGeneration;
         Impl->RewriteTreeRoots.erase(equivClass2);
       } else {
         // Take the second rewrite tree and make it the first.
diff --git a/lib/Basic/CMakeLists.txt b/lib/Basic/CMakeLists.txt
index 5510318..debe5ce 100644
--- a/lib/Basic/CMakeLists.txt
+++ b/lib/Basic/CMakeLists.txt
@@ -5,7 +5,7 @@
   set(UUID_LIBRARIES "")
 elseif(CMAKE_SYSTEM_NAME STREQUAL "Windows")
   set(UUID_INCLUDE "")
-  set(UUID_LIBRARIES "ole32.lib")
+  set(UUID_LIBRARIES "rpcrt4.lib")
 else()
   find_package(UUID REQUIRED)
   set(UUID_INCLUDE "-I${UUID_INCLUDE_DIRS}")
diff --git a/lib/Basic/Platform.cpp b/lib/Basic/Platform.cpp
index 206aaca..2c90231 100644
--- a/lib/Basic/Platform.cpp
+++ b/lib/Basic/Platform.cpp
@@ -113,7 +113,6 @@
   case llvm::Triple::RTEMS:
   case llvm::Triple::NaCl:
   case llvm::Triple::CNK:
-  case llvm::Triple::Bitrig:
   case llvm::Triple::AIX:
   case llvm::Triple::CUDA:
   case llvm::Triple::NVCL:
@@ -121,6 +120,7 @@
   case llvm::Triple::ELFIAMCU:
   case llvm::Triple::Mesa3D:
   case llvm::Triple::Contiki:
+  case llvm::Triple::AMDPAL:
     return "";
   case llvm::Triple::Darwin:
   case llvm::Triple::MacOSX:
diff --git a/lib/Basic/UUID.cpp b/lib/Basic/UUID.cpp
index a8099ba..f17aab4 100644
--- a/lib/Basic/UUID.cpp
+++ b/lib/Basic/UUID.cpp
@@ -42,7 +42,7 @@
 
 swift::UUID::UUID(FromTime_t) {
 #if defined(_WIN32)
-  ::GUID uuid;
+  ::UUID uuid;
   ::CoCreateGuid(&uuid);
 
   memcpy(Value, &uuid, Size);
@@ -53,7 +53,8 @@
 
 swift::UUID::UUID() {
 #if defined(_WIN32)
-  ::GUID uuid = GUID();
+  ::UUID uuid = *((::UUID *)&Value);
+  UuidCreateNil(&uuid);
 
   memcpy(Value, &uuid, Size);
 #else
@@ -63,18 +64,11 @@
 
 Optional<swift::UUID> swift::UUID::fromString(const char *s) {
 #if defined(_WIN32)
-  int length = strlen(s) + 1;
-  wchar_t *unicodeString = new wchar_t[length];
+  RPC_CSTR t = const_cast<RPC_CSTR>(reinterpret_cast<const unsigned char*>(s));
 
-  size_t convertedChars = 0;
-  errno_t conversionResult =
-    mbstowcs_s(&convertedChars, unicodeString, length, s, length);
-  assert(conversionResult == 0 &&
-    "expected successful conversion of char* to wchar_t*");
-
-  ::GUID uuid;
-  HRESULT parseResult = CLSIDFromString(unicodeString, &uuid);
-  if (parseResult != 0) {
+  ::UUID uuid;
+  RPC_STATUS status = UuidFromStringA(t, &uuid);
+  if (status == RPC_S_INVALID_STRING_UUID) {
     return None;
   }
 
@@ -92,19 +86,14 @@
 void swift::UUID::toString(llvm::SmallVectorImpl<char> &out) const {
   out.resize(UUID::StringBufferSize);
 #if defined(_WIN32)
-  ::GUID uuid;
+  ::UUID uuid;
   memcpy(&uuid, Value, Size);
 
-  LPOLESTR unicodeStr;
-  StringFromCLSID(uuid, &unicodeStr);
+  RPC_CSTR str;
+  UuidToStringA(&uuid, &str);
 
-  char str[StringBufferSize];
-  int strLen = wcstombs(str, unicodeStr, sizeof(str));
-
-  assert(strLen == 37 && "expected ascii convertible output from StringFromCLSID.");
-  (void)strLen;
-
-  memcpy(out.data(), str, StringBufferSize);
+  char* signedStr = reinterpret_cast<char*>(str);
+  memcpy(out.data(), signedStr, StringBufferSize);
 #else
   uuid_unparse_upper(Value, out.data());
 #endif
@@ -115,13 +104,14 @@
 
 int swift::UUID::compare(UUID y) const {
 #if defined(_WIN32)
-  ::GUID uuid1;
+  RPC_STATUS s;
+  ::UUID uuid1;
   memcpy(&uuid1, Value, Size);
 
-  ::GUID uuid2;
+  ::UUID uuid2;
   memcpy(&uuid2, y.Value, Size);
 
-  return memcmp(Value, y.Value, Size);
+  return UuidCompare(&uuid1, &uuid2, &s);
 #else
   return uuid_compare(Value, y.Value);
 #endif
diff --git a/lib/ClangImporter/ClangAdapter.cpp b/lib/ClangImporter/ClangAdapter.cpp
index 04daaf81..6ed0bf4 100644
--- a/lib/ClangImporter/ClangAdapter.cpp
+++ b/lib/ClangImporter/ClangAdapter.cpp
@@ -337,6 +337,7 @@
     // FIXME: Types that can be mapped, but aren't yet.
     case clang::BuiltinType::Half:
     case clang::BuiltinType::LongDouble:
+    case clang::BuiltinType::Float16:
     case clang::BuiltinType::Float128:
     case clang::BuiltinType::NullPtr:
       return OmissionTypeName();
diff --git a/lib/ClangImporter/ClangImporter.cpp b/lib/ClangImporter/ClangImporter.cpp
index b43cc42..d8cc57d 100644
--- a/lib/ClangImporter/ClangImporter.cpp
+++ b/lib/ClangImporter/ClangImporter.cpp
@@ -406,27 +406,6 @@
 
 #define SHIMS_INCLUDE_FLAG "-isystem"
 
-static StringRef
-getMinVersionOptNameForDarwinTriple(const llvm::Triple &triple) {
-  switch(getDarwinPlatformKind(triple)) {
-    case DarwinPlatformKind::MacOS:
-      return "-mmacosx-version-min=";
-    case DarwinPlatformKind::IPhoneOS:
-      return "-mios-version-min=";
-    case DarwinPlatformKind::IPhoneOSSimulator:
-      return "-mios-simulator-version-min=";
-    case DarwinPlatformKind::TvOS:
-      return "-mtvos-version-min=";
-    case DarwinPlatformKind::TvOSSimulator:
-      return "-mtvos-simulator-version-min=";
-    case DarwinPlatformKind::WatchOS:
-      return "-mwatchos-version-min=";
-    case DarwinPlatformKind::WatchOSSimulator:
-      return "-mwatchos-simulator-version-min=";
-  }
-  llvm_unreachable("Unsupported Darwin platform");
-}
-
 static void
 getNormalInvocationArguments(std::vector<std::string> &invocationArgStrs,
                              ASTContext &ctx,
@@ -659,24 +638,6 @@
   invocationArgStrs.push_back("-target");
   invocationArgStrs.push_back(triple.str());
 
-  if (triple.isOSDarwin()) {
-    std::string minVersionBuf;
-    llvm::raw_string_ostream minVersionOpt{minVersionBuf};
-    minVersionOpt << getMinVersionOptNameForDarwinTriple(triple);
-
-    unsigned major, minor, micro;
-    if (triple.isiOS()) {
-      triple.getiOSVersion(major, minor, micro);
-    } else if (triple.isWatchOS()) {
-      triple.getWatchOSVersion(major, minor, micro);
-    } else {
-      assert(triple.isMacOSX());
-      triple.getMacOSXVersion(major, minor, micro);
-    }
-    minVersionOpt << clang::VersionTuple(major, minor, micro);
-    invocationArgStrs.push_back(std::move(minVersionOpt.str()));
-  }
-
   invocationArgStrs.push_back(ImporterImpl::moduleImportBufferName);
 
   if (ctx.LangOpts.EnableAppExtensionRestrictions) {
diff --git a/lib/ClangImporter/ImportType.cpp b/lib/ClangImporter/ImportType.cpp
index c1b09ad..d2c6249 100644
--- a/lib/ClangImporter/ImportType.cpp
+++ b/lib/ClangImporter/ImportType.cpp
@@ -224,6 +224,7 @@
 
       // FIXME: Types that can be mapped, but aren't yet.
       case clang::BuiltinType::Half:
+      case clang::BuiltinType::Float16:
       case clang::BuiltinType::Float128:
       case clang::BuiltinType::NullPtr:
         return Type();
diff --git a/lib/Frontend/ArgsToFrontendOptionsConverter.cpp b/lib/Frontend/ArgsToFrontendOptionsConverter.cpp
index 68c583a..697f015 100644
--- a/lib/Frontend/ArgsToFrontendOptionsConverter.cpp
+++ b/lib/Frontend/ArgsToFrontendOptionsConverter.cpp
@@ -117,9 +117,6 @@
   if (checkUnusedSupplementaryOutputPaths())
     return true;
 
-  if (const Arg *A = Args.getLastArg(OPT_emit_fixits_path))
-    Opts.FixitsOutputPath = A->getValue();
-
   if (const Arg *A = Args.getLastArg(OPT_module_link_name))
     Opts.ModuleLinkName = A->getValue();
 
diff --git a/lib/Frontend/ArgsToFrontendOutputsConverter.cpp b/lib/Frontend/ArgsToFrontendOutputsConverter.cpp
index 5698a56..f9616c2 100644
--- a/lib/Frontend/ArgsToFrontendOutputsConverter.cpp
+++ b/lib/Frontend/ArgsToFrontendOutputsConverter.cpp
@@ -283,13 +283,15 @@
       options::OPT_emit_reference_dependencies_path);
   auto serializedDiagnostics = getSupplementaryFilenamesFromArguments(
       options::OPT_serialize_diagnostics_path);
+  auto fixItsOutput = getSupplementaryFilenamesFromArguments(
+      options::OPT_emit_fixits_path);
   auto loadedModuleTrace = getSupplementaryFilenamesFromArguments(
       options::OPT_emit_loaded_module_trace_path);
   auto TBD = getSupplementaryFilenamesFromArguments(options::OPT_emit_tbd_path);
 
   if (!objCHeaderOutput || !moduleOutput || !moduleDocOutput ||
       !dependenciesFile || !referenceDependenciesFile ||
-      !serializedDiagnostics || !loadedModuleTrace || !TBD) {
+      !serializedDiagnostics || !fixItsOutput || !loadedModuleTrace || !TBD) {
     return None;
   }
   std::vector<SupplementaryOutputPaths> result;
@@ -304,6 +306,7 @@
     sop.DependenciesFilePath = (*dependenciesFile)[i];
     sop.ReferenceDependenciesFilePath = (*referenceDependenciesFile)[i];
     sop.SerializedDiagnosticsPath = (*serializedDiagnostics)[i];
+    sop.FixItsOutputPath = (*fixItsOutput)[i];
     sop.LoadedModuleTracePath = (*loadedModuleTrace)[i];
     sop.TBDPath = (*TBD)[i];
 
@@ -356,6 +359,9 @@
       OPT_serialize_diagnostics, pathsFromArguments.SerializedDiagnosticsPath,
       "dia", "", defaultSupplementaryOutputPathExcludingExtension);
 
+  // There is no non-path form of -emit-fixits-path
+  auto fixItsOutputPath = pathsFromArguments.FixItsOutputPath;
+
   auto objcHeaderOutputPath = determineSupplementaryOutputFilename(
       OPT_emit_objc_header, pathsFromArguments.ObjCHeaderOutputPath, "h", "",
       defaultSupplementaryOutputPathExcludingExtension);
@@ -391,6 +397,7 @@
   sop.DependenciesFilePath = dependenciesFilePath;
   sop.ReferenceDependenciesFilePath = referenceDependenciesFilePath;
   sop.SerializedDiagnosticsPath = serializedDiagnosticsPath;
+  sop.FixItsOutputPath = fixItsOutputPath;
   sop.LoadedModuleTracePath = loadedModuleTracePath;
   sop.TBDPath = tbdPath;
   return sop;
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index 6eb05c3..b522760 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -908,8 +908,10 @@
   return false;
 }
 
-bool ParseMigratorArgs(MigratorOptions &Opts, llvm::Triple &Triple,
-                       StringRef ResourcePath, ArgList &Args,
+bool ParseMigratorArgs(MigratorOptions &Opts,
+                       const FrontendOptions &FrontendOpts,
+                       const llvm::Triple &Triple,
+                       StringRef ResourcePath, const ArgList &Args,
                        DiagnosticEngine &Diags) {
   using namespace options;
 
@@ -958,6 +960,21 @@
     }
   }
 
+  if (Opts.shouldRunMigrator()) {
+    assert(!FrontendOpts.InputsAndOutputs.isWholeModule());
+    // FIXME: In order to support batch mode properly, the migrator would have
+    // to support having one remap file path and one migrated file path per
+    // primary input. The easiest way to do this would be to move processing of
+    // these paths into FrontendOptions, like other supplementary outputs, and
+    // to call migrator::updateCodeAndEmitRemapIfNeeded once for each primary
+    // file.
+    //
+    // Supporting WMO would be similar, but WMO is set up to only produce one
+    // supplementary output for the whole compilation instead of one per input,
+    // so it's probably not worth it.
+    FrontendOpts.InputsAndOutputs.assertMustNotBeMoreThanOnePrimaryInput();
+  }
+
   return false;
 }
 
@@ -1022,7 +1039,7 @@
     return true;
   }
 
-  if (ParseMigratorArgs(MigratorOpts, LangOpts.Target,
+  if (ParseMigratorArgs(MigratorOpts, FrontendOpts, LangOpts.Target,
                         SearchPathOpts.RuntimeResourcePath, ParsedArgs, Diags)) {
     return true;
   }
diff --git a/lib/Frontend/DiagnosticVerifier.cpp b/lib/Frontend/DiagnosticVerifier.cpp
index 604bb78..e43fc97 100644
--- a/lib/Frontend/DiagnosticVerifier.cpp
+++ b/lib/Frontend/DiagnosticVerifier.cpp
@@ -17,9 +17,10 @@
 #include "swift/Frontend/DiagnosticVerifier.h"
 #include "swift/Basic/SourceManager.h"
 #include "swift/Parse/Lexer.h"
+#include "llvm/Support/FileSystem.h"
 #include "llvm/Support/MemoryBuffer.h"
 #include "llvm/Support/raw_ostream.h"
-#include <fstream>
+
 using namespace swift;
 
 namespace {
@@ -688,9 +689,12 @@
   
   // Retain the end of the file.
   Result.append(LastPos, bufferRange.end());
-  
-  std::ofstream outs(memBuffer->getBufferIdentifier());
-  outs << Result;
+
+  std::error_code error;
+  llvm::raw_fd_ostream outs(memBuffer->getBufferIdentifier(), error,
+                            llvm::sys::fs::OpenFlags::F_None);
+  if (!error)
+    outs << Result;
 }
 
 //===----------------------------------------------------------------------===//
diff --git a/lib/FrontendTool/FrontendTool.cpp b/lib/FrontendTool/FrontendTool.cpp
index 041886c..743c1d7 100644
--- a/lib/FrontendTool/FrontendTool.cpp
+++ b/lib/FrontendTool/FrontendTool.cpp
@@ -1509,6 +1509,41 @@
       ProfileEvents, ProfileEntities);
 }
 
+/// Creates a diagnostic consumer that handles dispatching diagnostics to
+/// multiple output files, based on the supplementary output paths specified by
+/// \p inputsAndOutputs.
+///
+/// If no output files are needed, returns null.
+static std::unique_ptr<DiagnosticConsumer>
+createDispatchingDiagnosticConsumerIfNeeded(
+    const FrontendInputsAndOutputs &inputsAndOutputs,
+    llvm::function_ref<std::unique_ptr<DiagnosticConsumer>(const InputFile &)>
+      maybeCreateSingleConsumer) {
+
+  // The "4" here is somewhat arbitrary. In practice we're going to have one
+  // sub-consumer for each diagnostic file we're trying to output, which (again
+  // in practice) is going to be 1 in WMO mode and equal to the number of
+  // primary inputs in batch mode. That in turn is going to be "the number of
+  // files we need to recompile in this build, divided by the number of jobs".
+  // So a value of "4" here means that there would be no heap allocation on a
+  // clean build of a module with up to 32 files on an 8-core machine, if the
+  // user doesn't customize anything.
+  SmallVector<FileSpecificDiagnosticConsumer::ConsumerPair, 4> subConsumers;
+
+  inputsAndOutputs.forEachInputProducingSupplementaryOutput(
+      [&](const InputFile &input) -> bool {
+    if (auto subConsumer = maybeCreateSingleConsumer(input))
+      subConsumers.emplace_back(input.file(), std::move(subConsumer));
+    return false;
+  });
+
+  if (subConsumers.empty())
+    return nullptr;
+  if (subConsumers.size() == 1)
+    return std::move(subConsumers.front()).second;
+  return llvm::make_unique<FileSpecificDiagnosticConsumer>(subConsumers);
+}
+
 /// Creates a diagnostic consumer that handles serializing diagnostics, based on
 /// the supplementary output paths specified by \p inputsAndOutputs.
 ///
@@ -1520,39 +1555,39 @@
 static std::unique_ptr<DiagnosticConsumer>
 createSerializedDiagnosticConsumerIfNeeded(
     const FrontendInputsAndOutputs &inputsAndOutputs) {
-
-  // The "4" here is somewhat arbitrary. In practice we're going to have one
-  // sub-consumer for each .dia file we're trying to output, which (again in
-  // practice) is going to be 1 in WMO mode and equal to the number of primary
-  // inputs in batch mode. That in turn is going to be "the number of files we
-  // need to recompile in this build, divided by the number of jobs". So a
-  // value of "4" here means that there would be no heap allocation on a clean
-  // build of a module with up to 32 files on an 8-core machine, if the user
-  // doesn't customize anything.
-  SmallVector<FileSpecificDiagnosticConsumer::ConsumerPair, 4>
-      serializedConsumers;
-
-  inputsAndOutputs.forEachInputProducingSupplementaryOutput(
-      [&](const InputFile &Input) -> bool {
-    std::string serializedDiagnosticsPath = Input.serializedDiagnosticsPath();
+  return createDispatchingDiagnosticConsumerIfNeeded(
+      inputsAndOutputs,
+      [](const InputFile &input) -> std::unique_ptr<DiagnosticConsumer> {
+    std::string serializedDiagnosticsPath = input.serializedDiagnosticsPath();
     if (serializedDiagnosticsPath.empty())
-      return false;
-
-    serializedConsumers.emplace_back(
-        Input.file(),
-        serialized_diagnostics::createConsumer(serializedDiagnosticsPath));
-
-    // Continue for other inputs.
-    return false;
+      return nullptr;
+    return serialized_diagnostics::createConsumer(serializedDiagnosticsPath);
   });
-
-  if (serializedConsumers.empty())
-    return nullptr;
-  if (serializedConsumers.size() == 1)
-    return std::move(serializedConsumers.front()).second;
-  return llvm::make_unique<FileSpecificDiagnosticConsumer>(serializedConsumers);
 }
 
+/// Creates a diagnostic consumer that handles serializing diagnostics, based on
+/// the supplementary output paths specified in \p options.
+///
+/// The returned consumer will handle producing multiple serialized diagnostics
+/// files if necessary, by using sub-consumers for each file and dispatching to
+/// the right one.
+///
+/// If no serialized diagnostics are being produced, returns null.
+static std::unique_ptr<DiagnosticConsumer>
+createJSONFixItDiagnosticConsumerIfNeeded(
+    const CompilerInvocation &invocation) {
+  return createDispatchingDiagnosticConsumerIfNeeded(
+      invocation.getFrontendOptions().InputsAndOutputs,
+      [&](const InputFile &input) -> std::unique_ptr<DiagnosticConsumer> {
+    std::string fixItsOutputPath = input.fixItsOutputPath();
+    if (fixItsOutputPath.empty())
+      return nullptr;
+    return llvm::make_unique<JSONFixitWriter>(
+        fixItsOutputPath, invocation.getDiagnosticOptions());
+  });
+}
+
+
 int swift::performFrontend(ArrayRef<const char *> Args,
                            const char *Argv0, void *MainAddr,
                            FrontendObserver *observer) {
@@ -1671,17 +1706,10 @@
   if (SerializedConsumerDispatcher)
     Instance->addDiagnosticConsumer(SerializedConsumerDispatcher.get());
 
-  // FIXME: The fix-its need to be multiplexed like the serialized diagnostics.
-  std::unique_ptr<DiagnosticConsumer> FixitsConsumer;
-  {
-    const std::string &FixitsOutputPath =
-      Invocation.getFrontendOptions().FixitsOutputPath;
-    if (!FixitsOutputPath.empty()) {
-      FixitsConsumer.reset(new JSONFixitWriter(FixitsOutputPath,
-                                            Invocation.getDiagnosticOptions()));
-      Instance->addDiagnosticConsumer(FixitsConsumer.get());
-    }
-  }
+  std::unique_ptr<DiagnosticConsumer> FixItsConsumer =
+      createJSONFixItDiagnosticConsumerIfNeeded(Invocation);
+  if (FixItsConsumer)
+    Instance->addDiagnosticConsumer(FixItsConsumer.get());
 
   if (Invocation.getDiagnosticOptions().UseColor)
     PDC.forceColors();
diff --git a/lib/IDE/APIDigesterData.cpp b/lib/IDE/APIDigesterData.cpp
index 8e7450d..cc6d032 100644
--- a/lib/IDE/APIDigesterData.cpp
+++ b/lib/IDE/APIDigesterData.cpp
@@ -309,7 +309,7 @@
 #define DIFF_ITEM_KEY_KIND_STRING(NAME) StringRef NAME;
 #define DIFF_ITEM_KEY_KIND_INT(NAME) Optional<int> NAME;
 #include "swift/IDE/DigesterEnums.def"
-  for (auto Pair : *Node) {
+  for (auto &Pair : *Node) {
     switch(parseKeyKind(getScalarString(Pair.getKey()))) {
 #define DIFF_ITEM_KEY_KIND_STRING(NAME)                                       \
     case DiffItemKeyKind::KK_##NAME:                                          \
diff --git a/lib/IRGen/GenCall.cpp b/lib/IRGen/GenCall.cpp
index a90895f..b2157ce 100644
--- a/lib/IRGen/GenCall.cpp
+++ b/lib/IRGen/GenCall.cpp
@@ -870,6 +870,9 @@
         return convertFloatingType(Ctx.getTargetInfo().getDoubleFormat());
       case clang::BuiltinType::LongDouble:
         return convertFloatingType(Ctx.getTargetInfo().getLongDoubleFormat());
+      case clang::BuiltinType::Float16:
+        llvm_unreachable("When upstream support is added for Float16 in "
+                         "clang::TargetInfo, use the implementation here");
       case clang::BuiltinType::Float128:
         return convertFloatingType(Ctx.getTargetInfo().getFloat128Format());
 
diff --git a/lib/IRGen/IRBuilder.h b/lib/IRGen/IRBuilder.h
index ac59edc..8c2d1d2 100644
--- a/lib/IRGen/IRBuilder.h
+++ b/lib/IRGen/IRBuilder.h
@@ -376,7 +376,7 @@
 } // end namespace swift
 
 namespace llvm {
-  template <> class PointerLikeTypeTraits<swift::irgen::IRBuilder::StableIP> {
+  template <> struct PointerLikeTypeTraits<swift::irgen::IRBuilder::StableIP> {
     typedef swift::irgen::IRBuilder::StableIP type;
   public:
     static void *getAsVoidPointer(type IP) {
diff --git a/lib/IRGen/IRGen.cpp b/lib/IRGen/IRGen.cpp
index 353faeb..40d3a5f 100644
--- a/lib/IRGen/IRGen.cpp
+++ b/lib/IRGen/IRGen.cpp
@@ -41,6 +41,7 @@
 #include "llvm/Bitcode/BitcodeWriter.h"
 #include "llvm/Bitcode/BitcodeWriterPass.h"
 #include "llvm/CodeGen/BasicTTIImpl.h"
+#include "llvm/CodeGen/TargetSubtargetInfo.h"
 #include "llvm/IR/Constants.h"
 #include "llvm/IR/DataLayout.h"
 #include "llvm/IR/IRPrintingPasses.h"
@@ -62,7 +63,6 @@
 #include "llvm/Support/Path.h"
 #include "llvm/Support/TargetRegistry.h"
 #include "llvm/Target/TargetMachine.h"
-#include "llvm/Target/TargetSubtargetInfo.h"
 #include "llvm/Transforms/Coroutines.h"
 #include "llvm/Transforms/IPO.h"
 #include "llvm/Transforms/IPO/AlwaysInliner.h"
@@ -556,7 +556,7 @@
   // Create a target machine.
   llvm::TargetMachine *TargetMachine = Target->createTargetMachine(
       EffectiveTriple.str(), CPU, targetFeatures, TargetOpts, Reloc::PIC_,
-      CodeModel::Default, OptLevel);
+      None, OptLevel);
   if (!TargetMachine) {
     Ctx.Diags.diagnose(SourceLoc(), diag::no_llvm_target,
                        EffectiveTriple.str(), "no LLVM target machine");
diff --git a/lib/IRGen/SwiftTargetInfo.cpp b/lib/IRGen/SwiftTargetInfo.cpp
index 3a5b504..c8a5a1c 100644
--- a/lib/IRGen/SwiftTargetInfo.cpp
+++ b/lib/IRGen/SwiftTargetInfo.cpp
@@ -51,7 +51,7 @@
 
   // arm64 requires marker assembly for objc_retainAutoreleasedReturnValue.
   target.ObjCRetainAutoreleasedReturnValueMarker =
-    "mov\tfp, fp\t\t# marker for objc_retainAutoreleaseReturnValue";
+    "mov\tfp, fp\t\t// marker for objc_retainAutoreleaseReturnValue";
 
   // arm64 requires ISA-masking.
   target.ObjCUseISAMask = true;
@@ -100,7 +100,7 @@
                          SwiftTargetInfo &target) {
   // ARM requires marker assembly for objc_retainAutoreleasedReturnValue.
   target.ObjCRetainAutoreleasedReturnValueMarker =
-    "mov\tr7, r7\t\t@ marker for objc_retainAutoreleaseReturnValue";
+    "mov\tr7, r7\t\t// marker for objc_retainAutoreleaseReturnValue";
 
   // armv7k has opaque ISAs which must go through the ObjC runtime.
   if (triple.getSubArch() == llvm::Triple::SubArchType::ARMSubArch_v7k)
diff --git a/lib/Index/Index.cpp b/lib/Index/Index.cpp
index 06b2c47..44b2391 100644
--- a/lib/Index/Index.cpp
+++ b/lib/Index/Index.cpp
@@ -1209,7 +1209,7 @@
     IndexSymbol Info;
     Info.decl = nullptr;
     Info.symInfo = SymbolInfo{ SymbolKind::CommentTag, SymbolSubKind::None,
-      SymbolPropertySet(), SymbolLanguage::Swift };
+      SymbolLanguage::Swift, SymbolPropertySet() };
     Info.roles |= (unsigned)SymbolRole::Definition;
     Info.name = StringRef();
     SmallString<128> storage;
diff --git a/lib/Index/IndexSymbol.cpp b/lib/Index/IndexSymbol.cpp
index acfd1f1..afcc92d 100644
--- a/lib/Index/IndexSymbol.cpp
+++ b/lib/Index/IndexSymbol.cpp
@@ -138,7 +138,7 @@
 
 SymbolInfo index::getSymbolInfoForDecl(const Decl *D) {
   SymbolInfo info{ SymbolKind::Unknown, SymbolSubKind::None,
-                   SymbolPropertySet(), SymbolLanguage::Swift };
+                   SymbolLanguage::Swift, SymbolPropertySet() };
   switch (D->getKind()) {
     case DeclKind::Enum:             info.Kind = SymbolKind::Enum; break;
     case DeclKind::Struct:           info.Kind = SymbolKind::Struct; break;
diff --git a/lib/LLVMPasses/LLVMSwiftAA.cpp b/lib/LLVMPasses/LLVMSwiftAA.cpp
index 4b349b4..97e3350 100644
--- a/lib/LLVMPasses/LLVMSwiftAA.cpp
+++ b/lib/LLVMPasses/LLVMSwiftAA.cpp
@@ -25,7 +25,7 @@
 
 static ModRefInfo getConservativeModRefForKind(const llvm::Instruction &I) {
   switch (classifyInstruction(I)) {
-#define KIND(Name, MemBehavior) case RT_ ## Name: return MRI_ ## MemBehavior;
+#define KIND(Name, MemBehavior) case RT_ ## Name: return ModRefInfo:: MemBehavior;
 #include "LLVMSwift.def"
   }
 
@@ -37,8 +37,9 @@
   // We know at compile time that certain entry points do not modify any
   // compiler-visible state ever. Quickly check if we have one of those
   // instructions and return if so.
-  if (MRI_NoModRef == getConservativeModRefForKind(*CS.getInstruction()))
-    return MRI_NoModRef;
+  if (ModRefInfo::NoModRef ==
+      getConservativeModRefForKind(*CS.getInstruction()))
+    return ModRefInfo::NoModRef;
 
   // Otherwise, delegate to the rest of the AA ModRefInfo machinery.
   return AAResultBase::getModRefInfo(CS, Loc);
diff --git a/lib/Parse/Lexer.cpp b/lib/Parse/Lexer.cpp
index 66829cd..047e880 100644
--- a/lib/Parse/Lexer.cpp
+++ b/lib/Parse/Lexer.cpp
@@ -283,7 +283,9 @@
 
   StringRef TokenText { TokStart, static_cast<size_t>(CurPtr - TokStart) };
 
-  lexTrivia(TrailingTrivia, /* IsForTrailingTrivia */ true);
+  if (TriviaRetention == TriviaRetentionMode::WithTrivia) {
+    lexTrivia(TrailingTrivia, /* IsForTrailingTrivia */ true);
+  }
 
   NextToken.setToken(Kind, TokenText, CommentLength, MultilineString);
 }
@@ -292,11 +294,11 @@
   assert(CurPtr - TokStart >= 3 && "escaped identifier must be longer than or equal 3 bytes");
   assert(TokStart[0] == '`' && "escaped identifier starts with backtick");
   assert(CurPtr[-1] == '`' && "escaped identifier ends with backtick");
-  if (TriviaRetention == TriviaRetentionMode::WithTrivia) {
-    LeadingTrivia.push_back(TriviaPiece::backtick());
-    assert(TrailingTrivia.empty() && "TrailingTrivia is empty here");
-    TrailingTrivia.push_back(TriviaPiece::backtick());
-  }
+
+  LeadingTrivia.push_back(TriviaPiece::backtick());
+  assert(TrailingTrivia.empty() && "TrailingTrivia is empty here");
+  TrailingTrivia.push_back(TriviaPiece::backtick());
+
   formToken(tok::identifier, TokStart);
   // If this token is at ArtificialEOF, it's forced to be tok::eof. Don't mark
   // this as escaped-identifier in this case.
@@ -2159,18 +2161,15 @@
   assert(CurPtr >= BufferStart &&
          CurPtr <= BufferEnd && "Current pointer out of range!");
 
-  if (TriviaRetention == TriviaRetentionMode::WithTrivia) {
-    LeadingTrivia.clear();
-    TrailingTrivia.clear();
-  }
+  LeadingTrivia.clear();
+  TrailingTrivia.clear();
+
   if (CurPtr == BufferStart) {
     if (BufferStart < ContentStart) {
       size_t BOMLen = ContentStart - BufferStart;
       assert(BOMLen == 3 && "UTF-8 BOM is 3 bytes");
-      if (TriviaRetention == TriviaRetentionMode::WithTrivia) {
-        // Add UTF-8 BOM to LeadingTrivia.
-        LeadingTrivia.push_back(TriviaPiece::garbageText({CurPtr, BOMLen}));
-      }
+      // Add UTF-8 BOM to LeadingTrivia.
+      LeadingTrivia.push_back(TriviaPiece::garbageText({CurPtr, BOMLen}));
       CurPtr += BOMLen;
     }
     NextToken.setAtStartOfLine(true);
@@ -2182,7 +2181,6 @@
   LastCommentBlockStart = CurPtr;
   SeenComment = false;
 
-Restart:
   lexTrivia(LeadingTrivia, /* IsForTrailingTrivia */ false);
 
   // Remember the start of the token so we can form the text range.
@@ -2198,24 +2196,23 @@
       return lexOperatorIdentifier();
 
     bool ShouldTokenize = lexUnknown(/*EmitDiagnosticsIfToken=*/true);
-    if (ShouldTokenize) {
-      return formToken(tok::unknown, TokStart);
-    }
-    goto Restart; // Skip presumed whitespace.
+    assert(
+        ShouldTokenize &&
+        "Invalid UTF-8 sequence should be eaten by lexTrivia as LeadingTrivia");
+    (void)ShouldTokenize;
+    return formToken(tok::unknown, TokStart);
   }
 
   case '\n':
   case '\r':
-    assert(TriviaRetention != TriviaRetentionMode::WithTrivia &&
-           "newlines should be eaten by lexTrivia as LeadingTrivia");
-    NextToken.setAtStartOfLine(true);
-    goto Restart;  // Skip whitespace.
+    llvm_unreachable("Newlines should be eaten by lexTrivia as LeadingTrivia");
 
   case ' ':
   case '\t':
   case '\f':
   case '\v':
-    goto Restart;  // Skip whitespace.
+    llvm_unreachable(
+        "Whitespaces should be eaten by lexTrivia as LeadingTrivia");
 
   case -1:
   case -2:
@@ -2228,17 +2225,16 @@
     case NulCharacterKind::CodeCompletion:
       return formToken(tok::code_complete, TokStart);
 
-    case NulCharacterKind::Embedded:
-      // If this is a random nul character in the middle of a buffer, skip it as
-      // whitespace.
-      diagnoseEmbeddedNul(Diags, CurPtr-1);
-      goto Restart;
     case NulCharacterKind::BufferEnd:
-      // Otherwise, this is the real end of the buffer.  Put CurPtr back into
-      // buffer bounds.
+      // This is the real end of the buffer.
+      // Put CurPtr back into buffer bounds.
       --CurPtr;
       // Return EOF.
       return formToken(tok::eof, TokStart);
+
+    case NulCharacterKind::Embedded:
+      llvm_unreachable(
+          "Embedded nul should be eaten by lexTrivia as LeadingTrivia");
     }
 
   case '@': return formToken(tok::at_sign, TokStart);
@@ -2275,16 +2271,16 @@
     if (CurPtr[0] == '/') {  // "//"
       skipSlashSlashComment(/*EatNewline=*/true);
       SeenComment = true;
-      if (isKeepingComments())
-        return formToken(tok::comment, TokStart);
-      goto Restart;
+      assert(isKeepingComments() &&
+             "Non token comment should be eaten by lexTrivia as LeadingTrivia");
+      return formToken(tok::comment, TokStart);
     }
     if (CurPtr[0] == '*') { // "/*"
       skipSlashStarComment();
       SeenComment = true;
-      if (isKeepingComments())
-        return formToken(tok::comment, TokStart);
-      goto Restart;
+      assert(isKeepingComments() &&
+             "Non token comment should be eaten by lexTrivia as LeadingTrivia");
+      return formToken(tok::comment, TokStart);
     }
     return lexOperatorIdentifier();
   case '%':
@@ -2313,13 +2309,9 @@
   case '<':
     if (CurPtr[0] == '#')
       return tryLexEditorPlaceholder();
-    else if (CurPtr[0] == '<' && tryLexConflictMarker(/*EatNewline=*/true))
-      goto Restart;
-    return lexOperatorIdentifier();
 
+    return lexOperatorIdentifier();
   case '>':
-    if (CurPtr[0] == '>' && tryLexConflictMarker(/*EatNewline=*/true))
-      goto Restart;
     return lexOperatorIdentifier();
  
   case '=': case '-': case '+': case '*':
@@ -2378,9 +2370,6 @@
 }
 
 void Lexer::lexTrivia(syntax::Trivia &Pieces, bool IsForTrailingTrivia) {
-  if (TriviaRetention == TriviaRetentionMode::WithoutTrivia)
-    return;
-
 Restart:
   const char *TriviaStart = CurPtr;
 
diff --git a/lib/SIL/Dominance.cpp b/lib/SIL/Dominance.cpp
index eb27420..88e034c 100644
--- a/lib/SIL/Dominance.cpp
+++ b/lib/SIL/Dominance.cpp
@@ -24,10 +24,8 @@
 
 namespace llvm {
 namespace DomTreeBuilder {
-template void Calculate<SILDomTree, swift::SILFunction>(
-    SILDomTree &DT, swift::SILFunction &F);
-template void Calculate<SILPostDomTree, swift::SILFunction>(
-    SILPostDomTree &DT, swift::SILFunction &F);
+template void Calculate<SILDomTree>(SILDomTree &DT);
+template void Calculate<SILPostDomTree>(SILPostDomTree &DT);
 } // namespace DomTreeBuilder
 } // namespace llvm
 
diff --git a/lib/SIL/SILOwnershipVerifier.cpp b/lib/SIL/SILOwnershipVerifier.cpp
index 67c1107..70d3889 100644
--- a/lib/SIL/SILOwnershipVerifier.cpp
+++ b/lib/SIL/SILOwnershipVerifier.cpp
@@ -150,7 +150,7 @@
 
 namespace llvm {
 
-template <> class PointerLikeTypeTraits<GeneralizedUser> {
+template <> struct PointerLikeTypeTraits<GeneralizedUser> {
 
 public:
   static void *getAsVoidPointer(GeneralizedUser v) {
diff --git a/lib/SIL/SILVerifier.cpp b/lib/SIL/SILVerifier.cpp
index cf92a42..2ac2bff 100644
--- a/lib/SIL/SILVerifier.cpp
+++ b/lib/SIL/SILVerifier.cpp
@@ -2342,14 +2342,6 @@
         case SILInstructionKind::ApplyInst:
         case SILInstructionKind::TryApplyInst:
         case SILInstructionKind::PartialApplyInst:
-          // Non-Mutating set pattern that allows a inout (that can't really
-          // write back. Only SILGen generates PointerToThinkFunction
-          // instructions in the writeback code.
-          if (auto *AI = dyn_cast<ApplyInst>(inst)) {
-            if (isa<PointerToThinFunctionInst>(AI->getCallee())) {
-              break;
-            }
-          }
           if (isConsumingOrMutatingApplyUse(use))
             return true;
           else
@@ -3849,7 +3841,13 @@
         case KeyPathPatternComponent::Kind::SettableProperty: {
           bool hasIndices = !component.getSubscriptIndices().empty();
         
-          // Getter should be <Sig...> @convention(thin) (@in Base) -> @out Result
+          ParameterConvention normalArgConvention;
+          if (F.getModule().getOptions().EnableGuaranteedNormalArguments)
+            normalArgConvention = ParameterConvention::Indirect_In_Guaranteed;
+          else
+            normalArgConvention = ParameterConvention::Indirect_In;
+        
+          // Getter should be <Sig...> @convention(thin) (@in_guaranteed Base) -> @out Result
           {
             auto getter = component.getComputedPropertyGetter();
             auto substGetterType = getter->getLoweredFunctionType()
@@ -3861,9 +3859,8 @@
             require(substGetterType->getNumParameters() == 1 + hasIndices,
                     "getter should have one parameter");
             auto baseParam = substGetterType->getParameters()[0];
-            require(baseParam.getConvention() ==
-                      ParameterConvention::Indirect_In,
-                    "getter base parameter should be @in");
+            require(baseParam.getConvention() == normalArgConvention,
+                    "getter base parameter should have normal arg convention");
             require(baseParam.getType() == loweredBaseTy.getSwiftRValueType(),
                     "getter base parameter should match base of component");
             
@@ -3889,7 +3886,7 @@
           
           if (kind == KeyPathPatternComponent::Kind::SettableProperty) {
             // Setter should be
-            // <Sig...> @convention(thin) (@in Result, @in Base) -> ()
+            // <Sig...> @convention(thin) (@in_guaranteed Result, @in Base) -> ()
             
             auto setter = component.getComputedPropertySetter();
             auto substSetterType = setter->getLoweredFunctionType()
@@ -3903,16 +3900,17 @@
                     "setter should have two parameters");
 
             auto newValueParam = substSetterType->getParameters()[0];
-            require(newValueParam.getConvention() ==
-                      ParameterConvention::Indirect_In,
-                    "setter value parameter should be @in");
+            // TODO: This should probably be unconditionally +1 when we
+            // can represent that.
+            require(newValueParam.getConvention() == normalArgConvention,
+                    "setter value parameter should havee normal arg convention");
 
             auto baseParam = substSetterType->getParameters()[1];
-            require(baseParam.getConvention() ==
-                      ParameterConvention::Indirect_In
+            require(baseParam.getConvention() == normalArgConvention
                     || baseParam.getConvention() ==
                         ParameterConvention::Indirect_Inout,
-                    "setter base parameter should be @in or @inout");
+                    "setter base parameter should be normal arg convention "
+                    "or @inout");
             
             if (hasIndices) {
               auto indicesParam = substSetterType->getParameters()[2];
diff --git a/lib/SIL/TypeLowering.cpp b/lib/SIL/TypeLowering.cpp
index 37a0957..c54f546 100644
--- a/lib/SIL/TypeLowering.cpp
+++ b/lib/SIL/TypeLowering.cpp
@@ -2071,25 +2071,28 @@
   auto selfMetatypeType = MetatypeType::get(selfType,
                                             MetatypeRepresentation::Thick);
 
+  auto canSelfType = selfType->getCanonicalType(genericSig);
+  auto canSelfMetatypeType = selfMetatypeType->getCanonicalType(genericSig);
+  auto selfConvention = (storage->isSetterMutating()
+                         ? ParameterConvention::Indirect_Inout
+                         : ParameterConvention::Indirect_In_Guaranteed);
+
   {
     GenericContextScope scope(*this, genericSig);
 
     // If 'self' is a metatype, make it @thin or @thick as needed, but not inside
     // selfMetatypeType.
-    if (auto metatype = selfType->getAs<MetatypeType>()) {
+    if (auto metatype = canSelfType->getAs<MetatypeType>()) {
       if (!metatype->hasRepresentation())
-        selfType = getLoweredType(metatype).getSwiftRValueType();
+        canSelfType = getLoweredType(metatype).getSwiftRValueType();
     }
   }
 
-  auto canSelfType = selfType->getCanonicalType(genericSig);
-  auto canSelfMetatypeType = selfMetatypeType->getCanonicalType(genericSig);
-
   // Create the SILFunctionType for the callback.
   SILParameterInfo params[] = {
     { ctx.TheRawPointerType, ParameterConvention::Direct_Unowned },
     { ctx.TheUnsafeValueBufferType, ParameterConvention::Indirect_Inout },
-    { canSelfType, ParameterConvention::Indirect_Inout },
+    { canSelfType, selfConvention },
     { canSelfMetatypeType, ParameterConvention::Direct_Unowned },
   };
   ArrayRef<SILResultInfo> results = {};
diff --git a/lib/SILGen/ArgumentSource.cpp b/lib/SILGen/ArgumentSource.cpp
index 9f5ce5e..765a145 100644
--- a/lib/SILGen/ArgumentSource.cpp
+++ b/lib/SILGen/ArgumentSource.cpp
@@ -174,7 +174,9 @@
   case Kind::RValue: {
     auto loc = getKnownRValueLocation();
     if (auto init = C.getEmitInto()) {
-      std::move(*this).asKnownRValue(SGF).forwardInto(SGF, loc, init);
+      std::move(*this).asKnownRValue(SGF)
+                      .ensurePlusOne(SGF, loc)
+                      .forwardInto(SGF, loc, init);
       return ManagedValue::forInContext();
     } else {
       return std::move(*this).asKnownRValue(SGF).getAsSingleValue(SGF, loc);
diff --git a/lib/SILGen/SILGenExpr.cpp b/lib/SILGen/SILGenExpr.cpp
index 53ead97..3149b26 100644
--- a/lib/SILGen/SILGenExpr.cpp
+++ b/lib/SILGen/SILGenExpr.cpp
@@ -3008,7 +3008,14 @@
   if (!storage->getDeclContext()->isTypeContext())
     return ManagedValue();
   
-  auto paramOrigValue = subSGF.emitManagedRValueWithCleanup(paramArg);
+  ManagedValue paramOrigValue;
+  
+  if (subSGF.SGM.M.getOptions().EnableGuaranteedNormalArguments) {
+    paramOrigValue =
+      ManagedValue::forBorrowedRValue(paramArg).copy(subSGF, loc);
+  } else {
+    paramOrigValue = subSGF.emitManagedRValueWithCleanup(paramArg);
+  }
   auto paramSubstValue = subSGF.emitOrigToSubstValue(loc, paramOrigValue,
                                              AbstractionPattern::getOpaque(),
                                              baseType);
@@ -3107,9 +3114,15 @@
                                              propertyType);
   }
   
+  ParameterConvention paramConvention;
+  if (SGM.M.getOptions().EnableGuaranteedNormalArguments)
+    paramConvention = ParameterConvention::Indirect_In_Guaranteed;
+  else
+    paramConvention = ParameterConvention::Indirect_In;
+
   SmallVector<SILParameterInfo, 2> params;
   params.push_back({loweredBaseTy.getSwiftRValueType(),
-                    ParameterConvention::Indirect_In});
+                    paramConvention});
   auto &C = SGM.getASTContext();
   if (!indexes.empty())
     params.push_back({C.getUnsafeRawPointerDecl()->getDeclaredType()
@@ -3224,15 +3237,21 @@
   
   auto &C = SGM.getASTContext();
   
+  ParameterConvention paramConvention;
+  if (SGM.M.getOptions().EnableGuaranteedNormalArguments)
+    paramConvention = ParameterConvention::Indirect_In_Guaranteed;
+  else
+    paramConvention = ParameterConvention::Indirect_In;
+
   SmallVector<SILParameterInfo, 3> params;
   // property value
   params.push_back({loweredPropTy.getSwiftRValueType(),
-                    ParameterConvention::Indirect_In});
+                    paramConvention});
   // base
   params.push_back({loweredBaseTy.getSwiftRValueType(),
                     property->isSetterMutating()
                       ? ParameterConvention::Indirect_Inout
-                      : ParameterConvention::Indirect_In});
+                      : paramConvention});
   // indexes
   if (!indexes.empty())
     params.push_back({C.getUnsafeRawPointerDecl()->getDeclaredType()
@@ -3298,7 +3317,12 @@
                                                          indexes,
                                                          indexPtrArg);
   
-  auto valueOrig = subSGF.emitManagedRValueWithCleanup(valueArg);
+  ManagedValue valueOrig;
+  if (SGM.M.getOptions().EnableGuaranteedNormalArguments)
+    valueOrig = ManagedValue::forBorrowedRValue(valueArg)
+      .copy(subSGF, loc);
+  else
+    valueOrig = subSGF.emitManagedRValueWithCleanup(valueArg);
   auto valueSubst = subSGF.emitOrigToSubstValue(loc, valueOrig,
                                                 AbstractionPattern::getOpaque(),
                                                 propertyType);
@@ -3613,8 +3637,7 @@
 
     SILValue hashCode;
 
-    // TODO: Combine hashes of the indexes. There isn't a great hash combining
-    // interface in the standard library to do this yet.
+    // TODO: Combine hashes of the indexes using an inout _Hasher
     {
       auto &index = indexes[0];
       
diff --git a/lib/SILGen/SILGenMaterializeForSet.cpp b/lib/SILGen/SILGenMaterializeForSet.cpp
index 046948d..b3c4cb5 100644
--- a/lib/SILGen/SILGenMaterializeForSet.cpp
+++ b/lib/SILGen/SILGenMaterializeForSet.cpp
@@ -964,7 +964,7 @@
     }
 
     // The callback gets the address of 'self' at +0.
-    ManagedValue mSelf = ManagedValue::forLValue(self);
+    ManagedValue mSelf = ManagedValue::forUnmanaged(self);
 
     // That's enough to build the l-value.
     LValue lvalue = buildLValue(SGF, loc, mSelf, std::move(indices),
diff --git a/lib/SILOptimizer/Transforms/ObjectOutliner.cpp b/lib/SILOptimizer/Transforms/ObjectOutliner.cpp
index 7b846a8..ee77a47 100644
--- a/lib/SILOptimizer/Transforms/ObjectOutliner.cpp
+++ b/lib/SILOptimizer/Transforms/ObjectOutliner.cpp
@@ -286,20 +286,25 @@
   ArrayRef<Operand> TailCounts = ARI->getTailAllocatedCounts();
   SILType TailType;
   unsigned NumTailElems = 0;
-  if (!TailCounts.empty()) {
-    // We only support a single tail allocated array.
-    if (TailCounts.size() > 1)
+
+  // We only support a single tail allocated arrays.
+  // Stdlib's tail allocated arrays don't have any side-effects in the
+  // constructor if the element type is trivial.
+  // TODO: also exclude custom tail allocated arrays which might have
+  // side-effects in the destructor.
+  if (TailCounts.size() != 1)
       return false;
-    // The number of tail allocated elements must be constant.
-    if (auto *ILI = dyn_cast<IntegerLiteralInst>(TailCounts[0].get())) {
-      if (ILI->getValue().getActiveBits() > 20)
-        return false;
-      NumTailElems = ILI->getValue().getZExtValue();
-      TailType = ARI->getTailAllocatedTypes()[0];
-    } else {
+
+  // The number of tail allocated elements must be constant.
+  if (auto *ILI = dyn_cast<IntegerLiteralInst>(TailCounts[0].get())) {
+    if (ILI->getValue().getActiveBits() > 20)
       return false;
-    }
+    NumTailElems = ILI->getValue().getZExtValue();
+    TailType = ARI->getTailAllocatedTypes()[0];
+  } else {
+    return false;
   }
+
   SILType Ty = ARI->getType();
   ClassDecl *Cl = Ty.getClassOrBoundGenericClass();
   if (!Cl)
diff --git a/lib/Sema/CodeSynthesis.cpp b/lib/Sema/CodeSynthesis.cpp
index 2dcc3fb..1e93ffc 100644
--- a/lib/Sema/CodeSynthesis.cpp
+++ b/lib/Sema/CodeSynthesis.cpp
@@ -296,7 +296,9 @@
 
 static AccessorDecl *
 createMaterializeForSetPrototype(AbstractStorageDecl *storage,
-                                 FuncDecl *setter, TypeChecker &TC) {
+                                 FuncDecl *getter,
+                                 FuncDecl *setter,
+                                 TypeChecker &TC) {
   auto &ctx = storage->getASTContext();
   SourceLoc loc = storage->getLoc();
 
@@ -319,7 +321,7 @@
   params.push_back(buildIndexForwardingParamList(storage, bufferElements));
 
   // The accessor returns (temporary: Builtin.RawPointer,
-  //                       callback: Builtin.RawPointer),
+  //                       callback: Optional<Builtin.RawPointer>),
   // where the first pointer is the materialized address and the
   // second is the address of an optional callback.
   TupleTypeElt retElts[] = {
@@ -349,10 +351,15 @@
   // Open-code the setMutating() calculation since we might run before
   // the setter has been type checked.
   Type contextTy = DC->getDeclaredInterfaceType();
-  if (contextTy && !contextTy->hasReferenceSemantics() &&
+  if (contextTy && !contextTy->hasReferenceSemantics()) {
+    bool hasMutatingSetter =
       !setter->getAttrs().hasAttribute<NonMutatingAttr>() &&
-      storage->isSetterMutating())
-    materializeForSet->setSelfAccessKind(SelfAccessKind::Mutating);
+      storage->isSetterMutating();
+    bool hasMutatingGetter =
+      getter->getAttrs().hasAttribute<MutatingAttr>();
+    if (hasMutatingSetter || hasMutatingGetter)
+      materializeForSet->setSelfAccessKind(SelfAccessKind::Mutating);
+  }
 
   materializeForSet->setStatic(storage->isStatic());
 
@@ -847,7 +854,7 @@
   }
 
   auto materializeForSet = createMaterializeForSetPrototype(
-      storage, storage->getSetter(), TC);
+      storage, storage->getGetter(), storage->getSetter(), TC);
   addMemberToContextIfNeeded(materializeForSet, storage->getDeclContext(),
                              storage->getSetter());
   storage->setMaterializeForSetFunc(materializeForSet);
@@ -1815,7 +1822,9 @@
 
     AccessorDecl *materializeForSet = nullptr;
     if (dc->getAsNominalTypeOrNominalTypeExtensionContext())
-      materializeForSet = createMaterializeForSetPrototype(var, setter, TC);
+      materializeForSet = createMaterializeForSetPrototype(var,
+                                                           getter, setter,
+                                                           TC);
 
     var->makeComputed(SourceLoc(), getter, setter, materializeForSet, SourceLoc());
 
diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp
index 7833007..e6b40b8 100644
--- a/lib/Serialization/Serialization.cpp
+++ b/lib/Serialization/Serialization.cpp
@@ -4347,7 +4347,7 @@
     if (!MapNode) {
       return true;
     }
-    for (auto Pair : *MapNode) {
+    for (auto &Pair : *MapNode) {
       auto *Key = dyn_cast_or_null<llvm::yaml::ScalarNode>(Pair.getKey());
       auto *Value = dyn_cast_or_null<llvm::yaml::SequenceNode>(Pair.getValue());
 
diff --git a/stdlib/private/StdlibUnittest/StdlibUnittest.swift.gyb b/stdlib/private/StdlibUnittest/StdlibUnittest.swift.gyb
index 6be54c0..9f626c4 100644
--- a/stdlib/private/StdlibUnittest/StdlibUnittest.swift.gyb
+++ b/stdlib/private/StdlibUnittest/StdlibUnittest.swift.gyb
@@ -1089,6 +1089,15 @@
   static var runNoTestsWasCalled: Bool = false
   static var ranSomething: Bool = false
   static var complaintInstalled = false
+  static var hashingKeyOverridden = false
+
+  static func overrideHashingKey() {
+    if !hashingKeyOverridden {
+      // FIXME(hasher): This has to run before creating the first Set/Dictionary
+      _Hasher._secretKey = (0, 0)
+      hashingKeyOverridden = true
+    }
+  }
 
   static func complainIfNothingRuns() {
     if !complaintInstalled {
@@ -1200,6 +1209,7 @@
 
 public final class TestSuite {
   public init(_ name: String) {
+    PersistentState.overrideHashingKey()
     self.name = name
     _precondition(
       _testNameToIndex[name] == nil,
diff --git a/stdlib/public/core/AnyHashable.swift b/stdlib/public/core/AnyHashable.swift
index ef3087b..3e8b243 100644
--- a/stdlib/public/core/AnyHashable.swift
+++ b/stdlib/public/core/AnyHashable.swift
@@ -48,6 +48,7 @@
   ///   no comparison is possible. Otherwise, contains the result of `==`.
   func _isEqual(to: _AnyHashableBox) -> Bool?
   var _hashValue: Int { get }
+  func _hash(_into hasher: inout _Hasher)
 
   var _base: Any { get }
   func _downCastConditional<T>(into result: UnsafeMutablePointer<T>) -> Bool
@@ -95,6 +96,12 @@
 
   @_inlineable // FIXME(sil-serialize-all)
   @_versioned // FIXME(sil-serialize-all)
+  func _hash(_into hasher: inout _Hasher) {
+    _baseHashable._hash(into: &hasher)
+  }
+
+  @_inlineable // FIXME(sil-serialize-all)
+  @_versioned // FIXME(sil-serialize-all)
   internal var _base: Any {
     return _baseHashable
   }
@@ -295,6 +302,11 @@
   public var hashValue: Int {
     return _box._hashValue
   }
+
+  @_inlineable // FIXME(sil-serialize-all)
+  public func _hash(into hasher: inout _Hasher) {
+    _box._hash(_into: &hasher)
+  }
 }
 
 extension AnyHashable : CustomStringConvertible {
diff --git a/stdlib/public/core/Bool.swift b/stdlib/public/core/Bool.swift
index 6ab1c17..c4b22c6 100644
--- a/stdlib/public/core/Bool.swift
+++ b/stdlib/public/core/Bool.swift
@@ -154,9 +154,13 @@
   ///   invocations of the same program. Do not persist the hash value across
   ///   program runs.
   @_inlineable // FIXME(sil-serialize-all)
-  @_transparent
   public var hashValue: Int {
-    return self ? 1 : 0
+    return _hashValue(for: self)
+  }
+
+  @_inlineable // FIXME(sil-serialize-all)
+  public func _hash(into hasher: inout _Hasher) {
+    hasher.append((self ? 1 : 0) as UInt8)
   }
 
   @_inlineable // FIXME(sil-serialize-all)
diff --git a/stdlib/public/core/CTypes.swift b/stdlib/public/core/CTypes.swift
index e35d1d7..628903b 100644
--- a/stdlib/public/core/CTypes.swift
+++ b/stdlib/public/core/CTypes.swift
@@ -182,7 +182,12 @@
   /// program runs.
   @_inlineable // FIXME(sil-serialize-all)
   public var hashValue: Int {
-    return Int(Builtin.ptrtoint_Word(_rawValue))
+    return _hashValue(for: self)
+  }
+
+  @_inlineable // FIXME(sil-serialize-all)
+  public func _hash(into hasher: inout _Hasher) {
+    hasher.append(Int(Builtin.ptrtoint_Word(_rawValue)))
   }
 }
 
diff --git a/stdlib/public/core/DoubleWidth.swift.gyb b/stdlib/public/core/DoubleWidth.swift.gyb
index b7474bb..fe6f93c 100644
--- a/stdlib/public/core/DoubleWidth.swift.gyb
+++ b/stdlib/public/core/DoubleWidth.swift.gyb
@@ -151,10 +151,13 @@
 extension DoubleWidth : Hashable {
   @_inlineable // FIXME(sil-serialize-all)
   public var hashValue: Int {
-    var result = 0
-    result = _combineHashValues(result, _storage.high.hashValue)
-    result = _combineHashValues(result, _storage.low.hashValue)
-    return result
+    return _hashValue(for: self)
+  }
+
+  @_inlineable // FIXME(sil-serialize-all)
+  public func _hash(into hasher: inout _Hasher) {
+    hasher.append(low)
+    hasher.append(high)
   }
 }
 
diff --git a/stdlib/public/core/DropWhile.swift b/stdlib/public/core/DropWhile.swift
index 741808d..08e8ed8 100644
--- a/stdlib/public/core/DropWhile.swift
+++ b/stdlib/public/core/DropWhile.swift
@@ -190,6 +190,10 @@
   public var hashValue: Int {
     return base.hashValue
   }
+
+  public func _hash(into hasher: inout _Hasher) {
+    hasher.append(base)
+  }
 }
 
 extension LazyDropWhileCollection: Collection {
diff --git a/stdlib/public/core/Flatten.swift b/stdlib/public/core/Flatten.swift
index ea8bade..f94f0af 100644
--- a/stdlib/public/core/Flatten.swift
+++ b/stdlib/public/core/Flatten.swift
@@ -233,7 +233,14 @@
 extension FlattenCollection.Index : Hashable
   where Base.Index : Hashable, Base.Element.Index : Hashable {
   public var hashValue: Int {
-    return _combineHashValues(_inner?.hashValue ?? 0, _outer.hashValue)
+    return _hashValue(for: self)
+  }
+
+  public func _hash(into hasher: inout _Hasher) {
+    hasher.append(_outer)
+    if let inner = _inner {
+      hasher.append(inner)
+    }
   }
 }
 
diff --git a/stdlib/public/core/FloatingPointTypes.swift.gyb b/stdlib/public/core/FloatingPointTypes.swift.gyb
index 39cdc31..ff9a700 100644
--- a/stdlib/public/core/FloatingPointTypes.swift.gyb
+++ b/stdlib/public/core/FloatingPointTypes.swift.gyb
@@ -1524,26 +1524,25 @@
   /// your program. Do not save hash values to use during a future execution.
   @_inlineable // FIXME(sil-serialize-all)
   public var hashValue: Int {
+    return _hashValue(for: self)
+  }
+
+  @_inlineable // FIXME(sil-serialize-all)
+  public func _hash(into hasher: inout _Hasher) {
+    var v = self
     if isZero {
       // To satisfy the axiom that equality implies hash equality, we need to
       // finesse the hash value of -0.0 to match +0.0.
-      return 0
-    } else {
-    %if bits <= word_bits:
-      return Int(bitPattern: UInt(bitPattern))
-    %elif bits == 64: # Double -> 32-bit Int
-      return Int(truncatingIfNeeded: bitPattern &>> 32) ^
-             Int(truncatingIfNeeded: bitPattern)
-    %elif word_bits == 32: # Float80 -> 32-bit Int
-      return Int(truncatingIfNeeded: significandBitPattern &>> 32) ^
-             Int(truncatingIfNeeded: significandBitPattern) ^
-             Int(_representation.signAndExponent)
-    %else: # Float80 -> 64-bit Int
-      return Int(bitPattern: UInt(significandBitPattern)) ^
-             Int(_representation.signAndExponent)
-    %end
+      v = 0
     }
+  %if bits == 80:
+    hasher.append(v._representation.signAndExponent)
+    hasher.append(v.significandBitPattern)
+  %else:
+    hasher.append(v.bitPattern)
+  %end
   }
+
 }
 
 extension ${Self} {
diff --git a/stdlib/public/core/Hashable.swift b/stdlib/public/core/Hashable.swift
index 98fd5ff..d92cad5 100644
--- a/stdlib/public/core/Hashable.swift
+++ b/stdlib/public/core/Hashable.swift
@@ -108,6 +108,24 @@
   /// Hash values are not guaranteed to be equal across different executions of
   /// your program. Do not save hash values to use during a future execution.
   var hashValue: Int { get }
+
+  /// Feed bits to be hashed into the hash function represented by `hasher`.
+  func _hash(into hasher: inout _Hasher)
+}
+
+extension Hashable {
+  @inline(__always)
+  public func _hash(into hasher: inout _Hasher) {
+    hasher.append(self.hashValue)
+  }
+}
+
+// Called by synthesized `hashValue` implementations.
+@inline(__always)
+public func _hashValue<H: Hashable>(for value: H) -> Int {
+  var hasher = _Hasher()
+  hasher.append(value)
+  return hasher.finalize()
 }
 
 // Called by the SwiftValue implementation.
@@ -126,4 +144,3 @@
 ) -> Int {
   return value.pointee.hashValue
 }
-
diff --git a/stdlib/public/core/HashedCollections.swift.gyb b/stdlib/public/core/HashedCollections.swift.gyb
index b91923f..e755ee2 100644
--- a/stdlib/public/core/HashedCollections.swift.gyb
+++ b/stdlib/public/core/HashedCollections.swift.gyb
@@ -792,11 +792,16 @@
   @_inlineable // FIXME(sil-serialize-all)
   public var hashValue: Int {
     // FIXME(ABI)#177: <rdar://problem/18915294> Cache Set<T> hashValue
-    var result: Int = _mixInt(0)
+    return _hashValue(for: self)
+  }
+
+  @_inlineable // FIXME(sil-serialize-all)
+  public func _hash(into hasher: inout _Hasher) {
+    var hash = 0
     for member in self {
-       result ^= _mixInt(member.hashValue)
+      hash ^= _hashValue(for: member)
     }
-    return result
+    hasher.append(hash)
   }
 }
 
@@ -3985,7 +3990,7 @@
   @_versioned
   @inline(__always) // For performance reasons.
   internal func _bucket(_ k: Key) -> Int {
-    return _squeezeHashValue(k.hashValue, bucketCount)
+    return _hashValue(for: k) & _bucketMask
   }
 
   @_inlineable // FIXME(sil-serialize-all)
diff --git a/stdlib/public/core/Hashing.swift b/stdlib/public/core/Hashing.swift
index f6fef16..97ff40b 100644
--- a/stdlib/public/core/Hashing.swift
+++ b/stdlib/public/core/Hashing.swift
@@ -25,31 +25,9 @@
 
 @_fixed_layout // FIXME(sil-serialize-all)
 public // @testable
-enum _Hashing {
-  // FIXME(ABI)#41 : make this an actual public API.
-  @_inlineable // FIXME(sil-serialize-all)
-  public // SPI
-  static var secretKey: (UInt64, UInt64) {
-    get {
-      // The variable itself is defined in C++ code so that it is initialized
-      // during static construction.  Almost every Swift program uses hash
-      // tables, so initializing the secret key during the startup seems to be
-      // the right trade-off.
-      return (
-        _swift_stdlib_Hashing_secretKey.key0,
-        _swift_stdlib_Hashing_secretKey.key1)
-    }
-    set {
-      (_swift_stdlib_Hashing_secretKey.key0,
-       _swift_stdlib_Hashing_secretKey.key1) = newValue
-    }
-  }
-}
-
-@_fixed_layout // FIXME(sil-serialize-all)
-public // @testable
 enum _HashingDetail {
 
+  // FIXME(hasher): Remove
   @_inlineable // FIXME(sil-serialize-all)
   public // @testable
   static var fixedSeedOverride: UInt64 {
@@ -64,6 +42,7 @@
     }
   }
 
+  // FIXME(hasher): Remove
   @_inlineable // FIXME(sil-serialize-all)
   @_versioned
   @_transparent
@@ -74,6 +53,7 @@
     return _HashingDetail.fixedSeedOverride == 0 ? seed : fixedSeedOverride
   }
 
+  // FIXME(hasher): Remove
   @_inlineable // FIXME(sil-serialize-all)
   @_versioned
   @_transparent
@@ -98,6 +78,7 @@
 // their inputs and just exhibit avalanche effect.
 //
 
+// FIXME(hasher): Remove
 @_inlineable // FIXME(sil-serialize-all)
 @_transparent
 public // @testable
@@ -112,6 +93,7 @@
   return UInt32((extendedResult >> 3) & 0xffff_ffff)
 }
 
+// FIXME(hasher): Remove
 @_inlineable // FIXME(sil-serialize-all)
 @_transparent
 public // @testable
@@ -119,6 +101,7 @@
   return Int32(bitPattern: _mixUInt32(UInt32(bitPattern: value)))
 }
 
+// FIXME(hasher): Remove
 @_inlineable // FIXME(sil-serialize-all)
 @_transparent
 public // @testable
@@ -130,6 +113,7 @@
   return _HashingDetail.hash16Bytes(seed &+ (low << 3), high)
 }
 
+// FIXME(hasher): Remove
 @_inlineable // FIXME(sil-serialize-all)
 @_transparent
 public // @testable
@@ -137,6 +121,7 @@
   return Int64(bitPattern: _mixUInt64(UInt64(bitPattern: value)))
 }
 
+// FIXME(hasher): Remove
 @_inlineable // FIXME(sil-serialize-all)
 @_transparent
 public // @testable
@@ -148,6 +133,7 @@
 #endif
 }
 
+// FIXME(hasher): Remove
 @_inlineable // FIXME(sil-serialize-all)
 @_transparent
 public // @testable
@@ -159,35 +145,6 @@
 #endif
 }
 
-/// Given a hash value, returns an integer value in the range of
-/// 0..<`upperBound` that corresponds to a hash value.
-///
-/// The `upperBound` must be positive and a power of 2.
-///
-/// This function is superior to computing the remainder of `hashValue` by
-/// the range length.  Some types have bad hash functions; sometimes simple
-/// patterns in data sets create patterns in hash values and applying the
-/// remainder operation just throws away even more information and invites
-/// even more hash collisions.  This effect is especially bad because the
-/// range is a power of two, which means to throws away high bits of the hash
-/// (which would not be a problem if the hash was known to be good). This
-/// function mixes the bits in the hash value to compensate for such cases.
-///
-/// Of course, this function is a compressing function, and applying it to a
-/// hash value does not change anything fundamentally: collisions are still
-/// possible, and it does not prevent malicious users from constructing data
-/// sets that will exhibit pathological collisions.
-@_inlineable // FIXME(sil-serialize-all)
-public // @testable
-func _squeezeHashValue(_ hashValue: Int, _ upperBound: Int) -> Int {
-  _sanityCheck(_isPowerOf2(upperBound))
-  let mixedHashValue = _mixInt(hashValue)
-
-  // As `upperBound` is a power of two we can do a bitwise-and to calculate
-  // mixedHashValue % upperBound.
-  return mixedHashValue & (upperBound &- 1)
-}
-
 /// Returns a new value that combines the two given hash values.
 ///
 /// Combining is performed using [a hash function][ref] described by T.C. Hoad
@@ -214,3 +171,130 @@
   x ^= UInt(bitPattern: secondValue) &+ magic &+ (x &<< 6) &+ (x &>> 2)
   return Int(bitPattern: x)
 }
+
+// FIXME(hasher): This hasher emulates Swift 4.1 hashValues. It is purely for
+// benchmarking; to be removed.
+internal struct _LegacyHasher {
+  internal var _hash: Int
+
+  @inline(__always)
+  internal init(key: (UInt64, UInt64) = (0, 0)) { // key is ignored
+    _hash = 0
+  }
+
+  @inline(__always)
+  internal mutating func append(_ value: Int) {
+    _hash = (_hash == 0 ? value : _combineHashValues(_hash, value))
+  }
+
+  @inline(__always)
+  internal mutating func append(_ value: UInt) {
+    append(Int(bitPattern: value))
+  }
+
+  @inline(__always)
+  internal mutating func append(_ value: UInt32) {
+    append(Int(truncatingIfNeeded: value))
+  }
+
+  @inline(__always)
+  internal mutating func append(_ value: UInt64) {
+    if UInt64.bitWidth > Int.bitWidth {
+      append(Int(truncatingIfNeeded: value ^ (value &>> 32)))
+    } else {
+      append(Int(truncatingIfNeeded: value))
+    }
+  }
+
+  @inline(__always)
+  internal mutating func finalize() -> UInt64 {
+    return UInt64(
+      _truncatingBits: UInt(bitPattern: _mixInt(_hash))._lowWord)
+  }
+}
+
+
+// NOT @_fixed_layout
+public struct _Hasher {
+  internal typealias Core = _SipHash13
+
+  // NOT @_versioned
+  internal var _core: Core
+
+  // NOT @_inlineable
+  @effects(releasenone)
+  public init() {
+    self._core = Core(key: _Hasher._secretKey)
+  }
+
+  // NOT @_inlineable
+  @effects(releasenone)
+  public init(key: (UInt64, UInt64)) {
+    self._core = Core(key: key)
+  }
+
+  // FIXME(ABI)#41 : make this an actual public API.
+  @_inlineable // FIXME(sil-serialize-all)
+  public // SPI
+  static var _secretKey: (UInt64, UInt64) {
+    get {
+      // The variable itself is defined in C++ code so that it is initialized
+      // during static construction.  Almost every Swift program uses hash
+      // tables, so initializing the secret key during the startup seems to be
+      // the right trade-off.
+      return (
+        _swift_stdlib_Hashing_secretKey.key0,
+        _swift_stdlib_Hashing_secretKey.key1)
+    }
+    set {
+      // FIXME(hasher) Replace setter with some override mechanism inside 
+      // the runtime
+      (_swift_stdlib_Hashing_secretKey.key0,
+       _swift_stdlib_Hashing_secretKey.key1) = newValue
+    }
+  }
+
+  @_inlineable
+  @inline(__always)
+  public mutating func append<H: Hashable>(_ value: H) {
+    value._hash(into: &self)
+  }
+
+  // NOT @_inlineable
+  @effects(releasenone)
+  public mutating func append(bits: UInt) {
+    _core.append(bits)
+  }
+  // NOT @_inlineable
+  @effects(releasenone)
+  public mutating func append(bits: UInt32) {
+    _core.append(bits)
+  }
+  // NOT @_inlineable
+  @effects(releasenone)
+  public mutating func append(bits: UInt64) {
+    _core.append(bits)
+  }
+
+  // NOT @_inlineable
+  @effects(releasenone)
+  public mutating func append(bits: Int) {
+    _core.append(UInt(bitPattern: bits))
+  }
+  // NOT @_inlineable
+  @effects(releasenone)
+  public mutating func append(bits: Int32) {
+    _core.append(UInt32(bitPattern: bits))
+  }
+  // NOT @_inlineable
+  @effects(releasenone)
+  public mutating func append(bits: Int64) {
+    _core.append(UInt64(bitPattern: bits))
+  }
+
+  // NOT @_inlineable
+  @effects(releasenone)
+  public mutating func finalize() -> Int {
+    return Int(truncatingIfNeeded: _core.finalize())
+  }
+}
diff --git a/stdlib/public/core/Integers.swift.gyb b/stdlib/public/core/Integers.swift.gyb
index 76bc9ca..a2a02b8 100644
--- a/stdlib/public/core/Integers.swift.gyb
+++ b/stdlib/public/core/Integers.swift.gyb
@@ -3610,22 +3610,29 @@
   public var hashValue: Int {
     @inline(__always)
     get {
-% if bits <= word_bits and signed:
-      // Sign extend the value.
-      return Int(self)
-% elif bits <= word_bits and not signed:
-      // Sign extend the value.
-      return Int(${OtherSelf}(bitPattern: self))
-% elif bits == word_bits * 2:
-      // We have twice as many bits as we need to return.
-      return
-        Int(truncatingIfNeeded: self) ^
-        Int(truncatingIfNeeded: self &>> 32)
-% else:
-      _Unimplemented()
-% end
+      return _hashValue(for: self)
     }
   }
+
+  @_inlineable // FIXME(sil-serialize-all)
+  public func _hash(into hasher: inout _Hasher) {
+    // FIXME(hasher): To correctly bridge `Set`s/`Dictionary`s containing
+    // `AnyHashable`-boxed integers, all integer values are currently required
+    // to hash exactly the same way as the corresponding (U)Int64 value.  To fix
+    // this, we should introduce a custom AnyHashable box for integer values
+    // that sign-extends values to 64 bits.
+    % if bits <= word_bits:
+    hasher.append(bits: _lowWord)
+    % elif bits == 2 * word_bits:
+    if let word = ${"" if signed else "U"}Int(exactly: self) {
+      hasher.append(bits: word._lowWord)
+    } else {
+      hasher.append(bits: UInt64(_value))
+    }
+    % else:
+    fatalError("Unsupported integer width")
+    % end
+  }
 }
 
 
diff --git a/stdlib/public/core/KeyPath.swift b/stdlib/public/core/KeyPath.swift
index 70dace6..28e9cb7 100644
--- a/stdlib/public/core/KeyPath.swift
+++ b/stdlib/public/core/KeyPath.swift
@@ -49,21 +49,25 @@
   
   @_inlineable // FIXME(sil-serialize-all)
   final public var hashValue: Int {
-    var hash = 0
-    withBuffer {
+    return _hashValue(for: self)
+  }
+
+  @_inlineable // FIXME(sil-serialize-all)
+  public func _hash(into hasher: inout _Hasher) {
+    return withBuffer {
       var buffer = $0
       while true {
         let (component, type) = buffer.next()
-        hash ^= _mixInt(component.value.hashValue)
+        hasher.append(component.value)
         if let type = type {
-          hash ^= _mixInt(unsafeBitCast(type, to: Int.self))
+          hasher.append(unsafeBitCast(type, to: Int.self))
         } else {
           break
         }
       }
     }
-    return hash
   }
+  
   @_inlineable // FIXME(sil-serialize-all)
   public static func ==(a: AnyKeyPath, b: AnyKeyPath) -> Bool {
     // Fast-path identical objects
@@ -452,11 +456,14 @@
   @_inlineable // FIXME(sil-serialize-all)
   @_versioned // FIXME(sil-serialize-all)
   internal var hashValue: Int {
-    var hash = 0
-    hash ^= _mixInt(value)
-    hash ^= _mixInt(isStoredProperty ? 13 : 17)
-    hash ^= _mixInt(isTableOffset ? 19 : 23)
-    return hash
+    return _hashValue(for: self)
+  }
+
+  @_inlineable // FIXME(sil-serialize-all)
+  public func _hash(into hasher: inout _Hasher) {
+    hasher.append(value)
+    hasher.append(isStoredProperty)
+    hasher.append(isTableOffset)
   }
 }
 
@@ -473,6 +480,7 @@
     (_ xInstanceArguments: UnsafeRawPointer,
      _ yInstanceArguments: UnsafeRawPointer,
      _ size: Int) -> Bool
+  // FIXME(hasher) Append to an inout _Hasher instead
   internal typealias Hash = @convention(thin)
     (_ instanceArguments: UnsafeRawPointer,
      _ size: Int) -> Int
@@ -584,46 +592,54 @@
   @_inlineable // FIXME(sil-serialize-all)
   @_versioned // FIXME(sil-serialize-all)
   internal var hashValue: Int {
-    var hash: Int = 0
-    func mixHashFromArgument(_ argument: KeyPathComponent.ArgumentRef?) {
+    return _hashValue(for: self)
+  }
+
+  @_inlineable // FIXME(sil-serialize-all)
+  @_versioned // FIXME(sil-serialize-all)
+  internal func _hash(into hasher: inout _Hasher) {
+    var hasher = hasher
+    func appendHashFromArgument(
+      _ argument: KeyPathComponent.ArgumentRef?
+    ) {
       if let argument = argument {
-        let addedHash = argument.witnesses.pointee.hash(
+        let hash = argument.witnesses.pointee.hash(
           argument.data.baseAddress.unsafelyUnwrapped,
           argument.data.count)
         // Returning 0 indicates that the arguments should not impact the
         // hash value of the overall key path.
-        if addedHash != 0 {
-          hash ^= _mixInt(addedHash)
+        // FIXME(hasher): hash witness should just mutate hasher directly
+        if hash != 0 {
+          hasher.append(hash)
         }
       }
     }
     switch self {
     case .struct(offset: let a):
-      hash ^= _mixInt(0)
-      hash ^= _mixInt(a)
+      hasher.append(0)
+      hasher.append(a)
     case .class(offset: let b):
-      hash ^= _mixInt(1)
-      hash ^= _mixInt(b)
+      hasher.append(1)
+      hasher.append(b)
     case .optionalChain:
-      hash ^= _mixInt(2)
+      hasher.append(2)
     case .optionalForce:
-      hash ^= _mixInt(3)
+      hasher.append(3)
     case .optionalWrap:
-      hash ^= _mixInt(4)
+      hasher.append(4)
     case .get(id: let id, get: _, argument: let argument):
-      hash ^= _mixInt(5)
-      hash ^= _mixInt(id.hashValue)
-      mixHashFromArgument(argument)
+      hasher.append(5)
+      hasher.append(id)
+      appendHashFromArgument(argument)
     case .mutatingGetSet(id: let id, get: _, set: _, argument: let argument):
-      hash ^= _mixInt(6)
-      hash ^= _mixInt(id.hashValue)
-      mixHashFromArgument(argument)
+      hasher.append(6)
+      hasher.append(id)
+      appendHashFromArgument(argument)
     case .nonmutatingGetSet(id: let id, get: _, set: _, argument: let argument):
-      hash ^= _mixInt(7)
-      hash ^= _mixInt(id.hashValue)
-      mixHashFromArgument(argument)
+      hasher.append(7)
+      hasher.append(id)
+      appendHashFromArgument(argument)
     }
-    return hash
   }
 }
 
diff --git a/stdlib/public/core/PrefixWhile.swift b/stdlib/public/core/PrefixWhile.swift
index 92a627d..b5e7b1e 100644
--- a/stdlib/public/core/PrefixWhile.swift
+++ b/stdlib/public/core/PrefixWhile.swift
@@ -208,11 +208,15 @@
 
 extension LazyPrefixWhileCollection.Index: Hashable where Base.Index: Hashable {
   public var hashValue: Int {
+    return _hashValue(for: self)
+  }
+
+  public func _hash(into hasher: inout _Hasher) {
     switch _value {
     case .index(let value):
-      return value.hashValue
+      hasher.append(value)
     case .pastEnd:
-      return .max
+      hasher.append(Int.max)
     }
   }
 }
diff --git a/stdlib/public/core/Reverse.swift b/stdlib/public/core/Reverse.swift
index ad08943..01585dd 100644
--- a/stdlib/public/core/Reverse.swift
+++ b/stdlib/public/core/Reverse.swift
@@ -197,6 +197,10 @@
   public var hashValue: Int {
     return base.hashValue
   }
+
+  public func _hash(into hasher: inout _Hasher) {
+    hasher.append(base)
+  }
 }
 
 extension ReversedCollection: BidirectionalCollection {  
diff --git a/stdlib/public/core/SipHash.swift.gyb b/stdlib/public/core/SipHash.swift.gyb
index 558cca3..54f4d0d 100644
--- a/stdlib/public/core/SipHash.swift.gyb
+++ b/stdlib/public/core/SipHash.swift.gyb
@@ -19,63 +19,20 @@
 /// * Daniel J. Bernstein <djb@cr.yp.to>
 //===----------------------------------------------------------------------===//
 
+%{
+# Number of bits in the Builtin.Word type
+word_bits = int(CMAKE_SIZEOF_VOID_P) * 8
+}%
+
 @_fixed_layout // FIXME(sil-serialize-all)
 @_versioned
 internal enum _SipHashDetail {
-  @_inlineable // FIXME(sil-serialize-all)
   @_versioned
   @inline(__always)
-  internal static func _rotate(_ x: UInt64, leftBy amount: Int) -> UInt64 {
-    return (x &<< UInt64(amount)) | (x &>> UInt64(64 - amount))
+  internal static func _rotate(_ x: UInt64, leftBy amount: UInt64) -> UInt64 {
+    return (x &<< amount) | (x &>> (64 - amount))
   }
 
-  @_inlineable // FIXME(sil-serialize-all)
-  @_versioned
-  @inline(__always)
-  internal static func _loadUnalignedUInt64LE(
-    from p: UnsafeRawPointer
-  ) -> UInt64 {
-    // FIXME(integers): split into multiple expressions to speed up the
-    // typechecking
-    var result =
-      UInt64(p.load(fromByteOffset: 0, as: UInt8.self))
-    result |=
-      (UInt64(p.load(fromByteOffset: 1, as: UInt8.self)) &<< (8 as UInt64))
-    result |=
-      (UInt64(p.load(fromByteOffset: 2, as: UInt8.self)) &<< (16 as UInt64))
-    result |=
-      (UInt64(p.load(fromByteOffset: 3, as: UInt8.self)) &<< (24 as UInt64))
-    result |=
-      (UInt64(p.load(fromByteOffset: 4, as: UInt8.self)) &<< (32 as UInt64))
-    result |=
-      (UInt64(p.load(fromByteOffset: 5, as: UInt8.self)) &<< (40 as UInt64))
-    result |=
-      (UInt64(p.load(fromByteOffset: 6, as: UInt8.self)) &<< (48 as UInt64))
-    result |=
-      (UInt64(p.load(fromByteOffset: 7, as: UInt8.self)) &<< (56 as UInt64))
-    return result
-  }
-
-  @_inlineable // FIXME(sil-serialize-all)
-  @_versioned
-  @inline(__always)
-  internal static func _loadPartialUnalignedUInt64LE(
-    from p: UnsafeRawPointer,
-    byteCount: Int
-  ) -> UInt64 {
-    _sanityCheck((0..<8).contains(byteCount))
-    var result: UInt64 = 0
-    if byteCount >= 1 { result |= UInt64(p.load(fromByteOffset: 0, as: UInt8.self)) }
-    if byteCount >= 2 { result |= UInt64(p.load(fromByteOffset: 1, as: UInt8.self)) &<< (8 as UInt64) }
-    if byteCount >= 3 { result |= UInt64(p.load(fromByteOffset: 2, as: UInt8.self)) &<< (16 as UInt64) }
-    if byteCount >= 4 { result |= UInt64(p.load(fromByteOffset: 3, as: UInt8.self)) &<< (24 as UInt64) }
-    if byteCount >= 5 { result |= UInt64(p.load(fromByteOffset: 4, as: UInt8.self)) &<< (32 as UInt64) }
-    if byteCount >= 6 { result |= UInt64(p.load(fromByteOffset: 5, as: UInt8.self)) &<< (40 as UInt64) }
-    if byteCount >= 7 { result |= UInt64(p.load(fromByteOffset: 6, as: UInt8.self)) &<< (48 as UInt64) }
-    return result
-  }
-
-  @_inlineable // FIXME(sil-serialize-all)
   @_versioned
   @inline(__always)
   internal static func _sipRound(
@@ -102,7 +59,7 @@
 }
 
 % for (c_rounds, d_rounds) in [(2, 4), (1, 3)]:
-%   Self = '_SipHash{}{}Context'.format(c_rounds, d_rounds)
+%   Self = '_SipHash{}{}'.format(c_rounds, d_rounds)
 
 @_fixed_layout // FIXME(sil-serialize-all)
 public // @testable
@@ -120,19 +77,14 @@
   @_versioned
   internal var v3: UInt64 = 0x7465646279746573
 
+  /// This value holds the byte count and the pending bytes that haven't been
+  /// compressed yet, in the format that the finalization step needs. (The least
+  /// significant 56 bits hold the trailing bytes, while the most significant 8
+  /// bits hold the count of bytes appended so far, mod 256.)
   @_versioned
-  internal var hashedByteCount: UInt64 = 0
+  internal var tailAndByteCount: UInt64 = 0
 
-  @_versioned
-  internal var dataTail: UInt64 = 0
-
-  @_versioned
-  internal var dataTailByteCount: Int = 0
-
-  @_versioned
-  internal var finalizedHash: UInt64?
-
-  @_inlineable // FIXME(sil-serialize-all)
+  @inline(__always)
   public init(key: (UInt64, UInt64)) {
     v3 ^= key.1
     v2 ^= key.0
@@ -140,113 +92,102 @@
     v0 ^= key.0
   }
 
-  // FIXME(ABI)#62 (UnsafeRawBufferPointer): Use UnsafeRawBufferPointer.
-  @_inlineable // FIXME(sil-serialize-all)
-  public // @testable
-  mutating func append(_ data: UnsafeRawPointer, byteCount: Int) {
-    _append_alwaysInline(data, byteCount: byteCount)
-  }
-
-  // FIXME(ABI)#63 (UnsafeRawBufferPointer): Use UnsafeRawBufferPointer.
-  @_inlineable // FIXME(sil-serialize-all)
   @_versioned
-  @inline(__always)
-  internal mutating func _append_alwaysInline(
-    _ data: UnsafeRawPointer,
-    byteCount: Int
-  ) {
-    precondition(finalizedHash == nil)
-    _sanityCheck((0..<8).contains(dataTailByteCount))
-
-    let dataEnd = data + byteCount
-
-    var data = data
-    var byteCount = byteCount
-    if dataTailByteCount != 0 {
-      let restByteCount = min(
-        MemoryLayout<UInt64>.size - dataTailByteCount,
-        byteCount)
-      let rest = _SipHashDetail._loadPartialUnalignedUInt64LE(
-        from: data,
-        byteCount: restByteCount)
-      dataTail |= rest &<< UInt64(dataTailByteCount * 8)
-      dataTailByteCount += restByteCount
-      data += restByteCount
-      byteCount -= restByteCount
-    }
-
-    if dataTailByteCount == MemoryLayout<UInt64>.size {
-      _appendDirectly(dataTail)
-      dataTail = 0
-      dataTailByteCount = 0
-    } else if dataTailByteCount != 0 {
-      _sanityCheck(data == dataEnd)
-      return
-    }
-
-    let endOfWords =
-      data + byteCount - (byteCount % MemoryLayout<UInt64>.size)
-    while data != endOfWords {
-      _appendDirectly(_SipHashDetail._loadUnalignedUInt64LE(from: data))
-      data += 8
-      // No need to update `byteCount`, it is not used beyond this point.
-    }
-
-    if data != dataEnd {
-      dataTailByteCount = dataEnd - data
-      dataTail = _SipHashDetail._loadPartialUnalignedUInt64LE(
-        from: data,
-        byteCount: dataTailByteCount)
+  internal var byteCount: UInt64 {
+    @inline(__always)
+    get {
+      return tailAndByteCount &>> 56
     }
   }
 
-  /// This function mixes in the given word directly into the state,
-  /// ignoring `dataTail`.
-  @_inlineable // FIXME(sil-serialize-all)
   @_versioned
+  internal var tail: UInt64 {
+    @inline(__always)
+    get {
+      return tailAndByteCount & ~(0xFF &<< 56)
+    }
+  }
+
   @inline(__always)
-  internal mutating func _appendDirectly(_ m: UInt64) {
+  @_versioned
+  internal mutating func _compress(_ m: UInt64) {
     v3 ^= m
     for _ in 0..<${c_rounds} {
       _SipHashDetail._sipRound(v0: &v0, v1: &v1, v2: &v2, v3: &v3)
     }
     v0 ^= m
-    hashedByteCount += 8
   }
 
-% for data_type in ['UInt', 'Int', 'UInt64', 'Int64', 'UInt32', 'Int32']:
-  @_inlineable // FIXME(sil-serialize-all)
-  public // @testable
-  mutating func append(_ data: ${data_type}) {
-    var data = data
-    _append_alwaysInline(&data, byteCount: MemoryLayout.size(ofValue: data))
-  }
-% end
-
-  @_inlineable // FIXME(sil-serialize-all)
-  public // @testable
-  mutating func finalizeAndReturnHash() -> UInt64 {
-    return _finalizeAndReturnHash_alwaysInline()
-  }
-
-  @_inlineable // FIXME(sil-serialize-all)
-  @_versioned
   @inline(__always)
-  internal mutating func _finalizeAndReturnHash_alwaysInline() -> UInt64 {
-    if let finalizedHash = finalizedHash {
-      return finalizedHash
+  public mutating func append(_ value: Int) {
+    append(UInt(bitPattern: value))
+  }
+
+  @inline(__always)
+  public mutating func append(_ value: UInt) {
+    % if word_bits == 64:
+    append(UInt64(_truncatingBits: value._lowWord))
+    % elif word_bits == 32:
+    append(UInt32(_truncatingBits: value._lowWord))
+    % else:
+    fatalError("Unsupported word width")
+    % end
+  }
+
+  @inline(__always)
+  public mutating func append(_ value: Int32) {
+    append(UInt32(bitPattern: value))
+  }
+
+  @inline(__always)
+  public mutating func append(_ value: UInt32) {
+    let m = UInt64(_truncatingBits: value._lowWord)
+    if byteCount & 4 == 0 {
+      _sanityCheck(byteCount & 7 == 0 && tail == 0)
+      tailAndByteCount = (tailAndByteCount | m) &+ (4 &<< 56)
+    } else {
+      _sanityCheck(byteCount & 3 == 0)
+      _compress((m &<< 32) | tail)
+      tailAndByteCount = (byteCount &+ 4) &<< 56
     }
+  }
 
-    _sanityCheck((0..<8).contains(dataTailByteCount))
+  @inline(__always)
+  public mutating func append(_ value: Int64) {
+    append(UInt64(bitPattern: value))
+  }
 
-    hashedByteCount += UInt64(dataTailByteCount)
-    let b: UInt64 = (hashedByteCount << 56) | dataTail
-
-    v3 ^= b
-    for _ in 0..<${c_rounds} {
-      _SipHashDetail._sipRound(v0: &v0, v1: &v1, v2: &v2, v3: &v3)
+  @inline(__always)
+  public mutating func append(_ m: UInt64) {
+    if byteCount & 4 == 0 {
+      _sanityCheck(byteCount & 7 == 0 && tail == 0)
+      _compress(m)
+      tailAndByteCount = tailAndByteCount &+ (8 &<< 56)
+    } else {
+      _sanityCheck(byteCount & 3 == 0)
+      _compress((m &<< 32) | tail)
+      tailAndByteCount = ((byteCount &+ 8) &<< 56) | (m &>> 32)
     }
-    v0 ^= b
+  }
+
+  @inline(__always)
+  public mutating func finalize(
+    tailBytes: UInt64,
+    tailByteCount: Int
+  ) -> UInt64 {
+    _sanityCheck(tailByteCount >= 0)
+    _sanityCheck(tailByteCount < 8 - (byteCount & 7))
+    _sanityCheck(tailBytes >> (tailByteCount << 3) == 0)
+    let count = UInt64(_truncatingBits: tailByteCount._lowWord)
+    let currentByteCount = byteCount & 7
+    tailAndByteCount |= (tailBytes &<< (currentByteCount &<< 3))
+    tailAndByteCount = tailAndByteCount &+ (count &<< 56)
+    return finalize()
+  }
+
+  @inline(__always)
+  public mutating func finalize() -> UInt64 {
+    _compress(tailAndByteCount)
 
     v2 ^= 0xff
 
@@ -254,47 +195,7 @@
       _SipHashDetail._sipRound(v0: &v0, v1: &v1, v2: &v2, v3: &v3)
     }
 
-    finalizedHash = v0 ^ v1 ^ v2 ^ v3
-    return finalizedHash!
-  }
-
-  @_inlineable // FIXME(sil-serialize-all)
-  @_versioned // FIXME(sil-serialize-all)
-  internal mutating func _finalizeAndReturnIntHash() -> Int {
-    let hash: UInt64 = finalizeAndReturnHash()
-#if arch(i386) || arch(arm)
-    return Int(truncatingIfNeeded: hash)
-#elseif arch(x86_64) || arch(arm64) || arch(powerpc64) || arch(powerpc64le) || arch(s390x)
-    return Int(Int64(bitPattern: hash))
-#endif
-  }
-
-  // FIXME(ABI)#64 (UnsafeRawBufferPointer): Use UnsafeRawBufferPointer.
-  @_inlineable // FIXME(sil-serialize-all)
-  public // @testable
-  static func hash(
-    data: UnsafeRawPointer,
-    dataByteCount: Int,
-    key: (UInt64, UInt64)
-  ) -> UInt64 {
-    return ${Self}._hash_alwaysInline(
-      data: data,
-      dataByteCount: dataByteCount,
-      key: key)
-  }
-
-  // FIXME(ABI)#65 (UnsafeRawBufferPointer): Use UnsafeRawBufferPointer.
-  @_inlineable // FIXME(sil-serialize-all)
-  @inline(__always)
-  public // @testable
-  static func _hash_alwaysInline(
-    data: UnsafeRawPointer,
-    dataByteCount: Int,
-    key: (UInt64, UInt64)
-  ) -> UInt64 {
-    var context = ${Self}(key: key)
-    context._append_alwaysInline(data, byteCount: dataByteCount)
-    return context._finalizeAndReturnHash_alwaysInline()
+    return (v0 ^ v1 ^ v2 ^ v3)
   }
 }
 % end
diff --git a/stdlib/public/core/StringHashable.swift b/stdlib/public/core/StringHashable.swift
index 7607c9b..c87ff59 100644
--- a/stdlib/public/core/StringHashable.swift
+++ b/stdlib/public/core/StringHashable.swift
@@ -37,34 +37,33 @@
   // @_inlineable // FIXME(sil-serialize-all)
   // @_versioned // FIXME(sil-serialize-all)
   internal static func hashASCII(
-    _ string: UnsafeBufferPointer<UInt8>
-  ) -> Int {
+    _ string: UnsafeBufferPointer<UInt8>,
+    into hasher: inout _Hasher
+  ) {
     let collationTable = _swift_stdlib_unicode_getASCIICollationTable()
-    var hasher = _SipHash13Context(key: _Hashing.secretKey)
     for c in string {
       _precondition(c <= 127)
       let element = collationTable[Int(c)]
       // Ignore zero valued collation elements. They don't participate in the
       // ordering relation.
       if element != 0 {
-        hasher.append(element)
+        hasher.append(Int(truncatingIfNeeded: element))
       }
     }
-    return hasher._finalizeAndReturnIntHash()
   }
 
   // FIXME: cannot be marked @_versioned. See <rdar://problem/34438258>
   // @_inlineable // FIXME(sil-serialize-all)
   // @_versioned // FIXME(sil-serialize-all)
   internal static func hashUTF16(
-    _ string: UnsafeBufferPointer<UInt16>
-  ) -> Int {
+    _ string: UnsafeBufferPointer<UInt16>,
+    into hasher: inout _Hasher
+  ) {
     let collationIterator = _swift_stdlib_unicodeCollationIterator_create(
       string.baseAddress!,
       UInt32(string.count))
     defer { _swift_stdlib_unicodeCollationIterator_delete(collationIterator) }
 
-    var hasher = _SipHash13Context(key: _Hashing.secretKey)
     while true {
       var hitEnd = false
       let element =
@@ -75,10 +74,9 @@
       // Ignore zero valued collation elements. They don't participate in the
       // ordering relation.
       if element != 0 {
-        hasher.append(element)
+        hasher.append(Int(truncatingIfNeeded: element))
       }
     }
-    return hasher._finalizeAndReturnIntHash()
   }
 }
 
@@ -100,7 +98,9 @@
     // Swift.String.hashValue and NSString.hash being the same.
     return stringHashOffset ^ hash
 #else
-    return Unicode.hashASCII(self.buffer)
+    var hasher = _Hasher()
+    Unicode.hashASCII(self.buffer, into: &hasher)
+    return Int(truncatingIfNeeded: hasher.finalize())
 #endif // _runtime(_ObjC)
   }
 }
@@ -118,7 +118,9 @@
     // Swift.String.hashValue and NSString.hash being the same.
     return stringHashOffset ^ hash
 #else
-    return Unicode.hashUTF16(self.buffer)
+    var hasher = _Hasher()
+    Unicode.hashUTF16(self.buffer, into: &hasher)
+    return Int(truncatingIfNeeded: hasher.finalize())
 #endif // _runtime(_ObjC)
   }
 }
@@ -139,7 +141,11 @@
     defer { p.deallocate(capacity: count) }
     let buffer = UnsafeMutableBufferPointer(start: p, count: count)
     _copy(into: buffer)
-    return Unicode.hashUTF16(UnsafeBufferPointer(buffer))
+    var hasher = _Hasher()
+    Unicode.hashUTF16(
+      UnsafeBufferPointer(start: p, count: count),
+      into: &hasher)
+    return Int(truncatingIfNeeded: hasher.finalize())
 #endif
   }
 }
@@ -195,6 +201,11 @@
     let gutsBits = _guts.rawBits
     return _StringGuts._computeHashValue(_unsafeBitPattern: gutsBits)
   }
+
+  @_inlineable
+  public func _hash(into hasher: inout _Hasher) {
+    hasher.append(self.hashValue)
+  }
 }
 
 extension StringProtocol {
@@ -202,4 +213,9 @@
   public var hashValue : Int {
     return _wholeString._guts._computeHashValue(_encodedOffsetRange)
   }
+
+  @_inlineable
+  public func _hash(into hasher: inout _Hasher) {
+    hasher.append(self.hashValue)
+  }
 }
diff --git a/stdlib/public/core/UnsafePointer.swift.gyb b/stdlib/public/core/UnsafePointer.swift.gyb
index 288b484..4e314bd 100644
--- a/stdlib/public/core/UnsafePointer.swift.gyb
+++ b/stdlib/public/core/UnsafePointer.swift.gyb
@@ -904,10 +904,15 @@
   /// program runs.
   @_inlineable
   public var hashValue: Int {
-    return Int(bitPattern: self)
+    return _hashValue(for: self)
+  }
+
+  @_inlineable // FIXME(sil-serialize-all)
+  public func _hash(into hasher: inout _Hasher) {
+    hasher.append(Int(bitPattern: self))
   }
 }
-  
+
 extension ${Self}: Strideable {
   /// Returns a pointer to the next consecutive instance.
   ///
diff --git a/stdlib/public/runtime/Casting.cpp b/stdlib/public/runtime/Casting.cpp
index 5a70cf3..d1c2c77 100644
--- a/stdlib/public/runtime/Casting.cpp
+++ b/stdlib/public/runtime/Casting.cpp
@@ -2823,8 +2823,7 @@
     return _fail(src, srcType, targetType, flags);
   }
 
-  // Unless we're always supposed to consume the input, retain the
-  // object because the witness takes it at +1.
+  // TODO: Avoid the retain here in +0 mode if the input is never consumed.
   bool alwaysConsumeSrc = (flags & DynamicCastFlags::TakeOnSuccess) &&
                           (flags & DynamicCastFlags::DestroyOnFailure);
   if (!alwaysConsumeSrc) {
@@ -2880,6 +2879,7 @@
                 (HeapObject *)srcObject, (OpaqueValue *)optDestBuffer,
                 targetType, targetType, targetBridgeWitness);
   }
+  SWIFT_CC_PLUSZERO_GUARD(swift_unknownRelease(srcObject));
 
   // If we succeeded, take from the optional buffer into the
   // destination buffer.
@@ -2887,8 +2887,6 @@
     targetType->vw_initializeWithTake(dest, (OpaqueValue *)optDestBuffer);
   }
 
-  // Unless we're always supposed to consume the input, release the
-  // input if we need to now.
   if (!alwaysConsumeSrc && shouldDeallocateSource(success, flags)) {
     swift_unknownRelease(srcObject);
   }
diff --git a/stdlib/public/runtime/ErrorObject.mm b/stdlib/public/runtime/ErrorObject.mm
index d5303b3..fadba49 100644
--- a/stdlib/public/runtime/ErrorObject.mm
+++ b/stdlib/public/runtime/ErrorObject.mm
@@ -409,8 +409,10 @@
   // initialization of the object happens-before the domain initialization so
   // that the domain can be used alone as a flag for the initialization of the
   // object.
-  if (errorObject->domain.load(std::memory_order_acquire))
+  if (errorObject->domain.load(std::memory_order_acquire)) {
+    SWIFT_CC_PLUSZERO_GUARD([ns retain]);
     return ns;
+  }
 
   // Otherwise, calculate the domain, code, and user info, and
   // initialize the NSError.
@@ -451,6 +453,7 @@
                                                    std::memory_order_acq_rel))
     objc_release(domain);
 
+  SWIFT_CC_PLUSZERO_GUARD([ns retain]);
   return ns;
 }
 
diff --git a/stdlib/public/runtime/Errors.cpp b/stdlib/public/runtime/Errors.cpp
index a603936..d91e8cd 100644
--- a/stdlib/public/runtime/Errors.cpp
+++ b/stdlib/public/runtime/Errors.cpp
@@ -292,6 +292,12 @@
   _swift_runtime_on_report(flags, message, details);
 }
 
+bool swift::_swift_reportFatalErrorsToDebugger = true;
+
+bool swift::_swift_shouldReportFatalErrorsToDebugger() {
+  return _swift_reportFatalErrorsToDebugger;
+}
+
 /// Report a fatal error to system console, stderr, and crash logs.
 /// Does not crash by itself.
 void swift::swift_reportError(uint32_t flags,
diff --git a/stdlib/public/runtime/ReflectionMirror.mm b/stdlib/public/runtime/ReflectionMirror.mm
index 7280fdf..637a217 100644
--- a/stdlib/public/runtime/ReflectionMirror.mm
+++ b/stdlib/public/runtime/ReflectionMirror.mm
@@ -635,19 +635,20 @@
 
     /// TODO: Implement specialized mirror witnesses for all kinds.
     case MetadataKind::Function:
-    case MetadataKind::Existential: {
-      OpaqueImpl impl;
-      return call(&impl);
-    }
+    case MetadataKind::Existential:
+      break;
 
     // Types can't have these kinds.
     case MetadataKind::HeapLocalVariable:
     case MetadataKind::HeapGenericLocalVariable:
     case MetadataKind::ErrorObject:
       swift::crash("Swift mirror lookup failure");
-  }
+    }
 
-  swift_runtime_unreachable("Unhandled MetadataKind in switch.");
+    // If we have an unknown kind of type, or a type without special handling,
+    // treat it as opaque.
+    OpaqueImpl impl;
+    return call(&impl);
 }
 
 } // end anonymous namespace
@@ -738,7 +739,7 @@
       return "(ErrorType Object)";
   }
 
-  swift_runtime_unreachable("Unhandled MetadataKind in switch.");
+  return "(Unknown)";
 }
 
 #if SWIFT_OBJC_INTEROP
diff --git a/stdlib/public/runtime/SwiftObject.mm b/stdlib/public/runtime/SwiftObject.mm
index 03e4816..02da955 100644
--- a/stdlib/public/runtime/SwiftObject.mm
+++ b/stdlib/public/runtime/SwiftObject.mm
@@ -1398,7 +1398,7 @@
                               "withoutActuallyEscaping block";
     auto messageLength = strlen(message);
 
-    if (_swift_reportFatalErrorsToDebugger)
+    if (_swift_shouldReportFatalErrorsToDebugger())
       _swift_reportToDebugger(RuntimeErrorFlagFatal, message);
 
     char *log;
diff --git a/stdlib/public/stubs/Assert.cpp b/stdlib/public/stubs/Assert.cpp
index a4b29ab..ceb369e 100644
--- a/stdlib/public/stubs/Assert.cpp
+++ b/stdlib/public/stubs/Assert.cpp
@@ -21,13 +21,11 @@
 
 using namespace swift;
 
-bool swift::_swift_reportFatalErrorsToDebugger = true;
-
 static void logPrefixAndMessageToDebugger(
     const unsigned char *prefix, int prefixLength,
     const unsigned char *message, int messageLength
 ) {
-  if (!_swift_reportFatalErrorsToDebugger)
+  if (!_swift_shouldReportFatalErrorsToDebugger())
     return;
 
   char *debuggerMessage;
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 64800a1..bc3ec41 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -158,7 +158,7 @@
   foreach(ARCH ${SWIFT_SDK_${SDK}_ARCHITECTURES})
     # Configure variables for this subdirectory.
     set(VARIANT_SUFFIX "-${SWIFT_SDK_${SDK}_LIB_SUBDIR}-${ARCH}")
-    set(VARIANT_TRIPLE "${SWIFT_SDK_${SDK}_ARCH_${ARCH}_TRIPLE}")
+    set(VARIANT_TRIPLE "${SWIFT_SDK_${SDK}_ARCH_${ARCH}_TRIPLE}${SWIFT_SDK_${SDK}_DEPLOYMENT_VERSION}")
     set(VARIANT_SDK "${SWIFT_SDK_${SDK}_PATH}")
 
     # A directory where to put the xUnit-style XML test results.
diff --git a/test/ClangImporter/availability_returns_twice.swift b/test/ClangImporter/availability_returns_twice.swift
index f0cee90..537c184 100644
--- a/test/ClangImporter/availability_returns_twice.swift
+++ b/test/ClangImporter/availability_returns_twice.swift
@@ -1,6 +1,6 @@
 // RUN: %target-swift-frontend -typecheck -verify %s
 
-#if os(OSX) || os(iOS) || os(watchOS) || os(tvOS)
+#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS)
   import Darwin
   typealias JumpBuffer = Int32
 #else
diff --git a/test/ClangImporter/clang_builtins.swift b/test/ClangImporter/clang_builtins.swift
index 73ef91e..b9a72eb 100644
--- a/test/ClangImporter/clang_builtins.swift
+++ b/test/ClangImporter/clang_builtins.swift
@@ -3,7 +3,7 @@
 // RUN: not %target-swift-frontend -swift-version 4 -typecheck %s 2> %t.4.txt
 // RUN: %FileCheck -check-prefix=CHECK-4 -check-prefix=CHECK-%target-runtime-4 %s < %t.4.txt
 
-#if os(OSX) || os(iOS) || os(watchOS) || os(tvOS)
+#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS)
   import Darwin
 #else
   import Glibc
@@ -27,7 +27,7 @@
   // CHECK-4: [[@LINE-2]]:16: error: cannot convert value of type '({{.+}}) -> Int'{{( [(]aka .+[)])?}} to specified type 'Int'
 }
 
-#if os(OSX) || os(iOS) || os(watchOS) || os(tvOS)
+#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS)
 // These functions aren't consistently available across platforms, so only
 // test for them on Apple platforms.
 func testApple() {
diff --git a/test/ClangImporter/objc_ir.swift b/test/ClangImporter/objc_ir.swift
index d95743d..7f9b8c2 100644
--- a/test/ClangImporter/objc_ir.swift
+++ b/test/ClangImporter/objc_ir.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %empty-directory(%t)
 // RUN: %build-clang-importer-objc-overlays
 // RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk-nosource -I %t) -I %S/Inputs/custom-modules -emit-ir -g -o - -primary-file %s | %FileCheck %s
diff --git a/test/ClangImporter/optional.swift b/test/ClangImporter/optional.swift
index 9feb50b..c510215 100644
--- a/test/ClangImporter/optional.swift
+++ b/test/ClangImporter/optional.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -I %S/Inputs/custom-modules -emit-silgen -o - %s | %FileCheck %s
 
 // REQUIRES: objc_interop
diff --git a/test/ClangImporter/plus_zero_objc_ir.swift b/test/ClangImporter/plus_zero_objc_ir.swift
new file mode 100644
index 0000000..4ea8181
--- /dev/null
+++ b/test/ClangImporter/plus_zero_objc_ir.swift
@@ -0,0 +1,349 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %empty-directory(%t)
+// RUN: %build-clang-importer-objc-overlays
+// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk-nosource -I %t) -I %S/Inputs/custom-modules -emit-ir -g -o - -primary-file %s | %FileCheck %s
+
+// REQUIRES: objc_interop
+// REQUIRES: OS=macosx
+
+// CHECK: %TSo1BC = type
+
+import ObjectiveC
+import Foundation
+import objc_ext
+import TestProtocols
+import ObjCIRExtras
+
+// CHECK: @"\01L_selector_data(method:withFloat:)" = private global [18 x i8] c"method:withFloat:\00"
+// CHECK: @"\01L_selector_data(method:withDouble:)" = private global [19 x i8] c"method:withDouble:\00"
+// CHECK: @"\01L_selector_data(method:separateExtMethod:)" = private global [26 x i8] c"method:separateExtMethod:\00", section "__TEXT,__objc_methname,cstring_literals"
+
+// Instance method invocation
+// CHECK-LABEL: define hidden swiftcc void @"$S7objc_ir15instanceMethodsyySo1BCF"(%TSo1BC*
+func instanceMethods(_ b: B) {
+  // CHECK: load i8*, i8** @"\01L_selector(method:withFloat:)"
+  // CHECK: call i32 bitcast (void ()* @objc_msgSend to i32
+  var i = b.method(1, with: 2.5 as Float)
+  // CHECK: load i8*, i8** @"\01L_selector(method:withDouble:)"
+  // CHECK: call i32 bitcast (void ()* @objc_msgSend to i32
+  i = i + b.method(1, with: 2.5 as Double)
+}
+
+// CHECK-LABEL: define hidden swiftcc void @"$S7objc_ir16extensionMethods1bySo1BC_tF"
+func extensionMethods(b b: B) {
+  // CHECK:      load i8*, i8** @"\01L_selector(method:separateExtMethod:)", align 8
+  // CHECK:      [[T0:%.*]] = call i8* bitcast (void ()* @objc_msgSend to i8*
+  // CHECK-NEXT: [[T1:%.*]] = {{.*}}call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]])
+  // CHECK-NOT:  [[T0]]
+  // CHECK:      [[T1]]
+  b.method(1, separateExtMethod:1.5)
+}
+
+// CHECK-LABEL: define hidden swiftcc void @"$S7objc_ir19initCallToAllocInit1iys5Int32V_tF"
+func initCallToAllocInit(i i: CInt) {
+  // CHECK: call {{.*}} @"$SSo1BC3intABSgs5Int32V_tcfC"
+ 
+  B(int: i)
+}
+
+// CHECK-LABEL: linkonce_odr hidden {{.*}} @"$SSo1BC3intABSgs5Int32V_tcfC"
+// CHECK: call [[OPAQUE:%.*]]* @objc_allocWithZone
+
+// Indexed subscripting
+// CHECK-LABEL: define hidden swiftcc void @"$S7objc_ir19indexedSubscripting1b3idx1aySo1BC_SiSo1ACtF"
+func indexedSubscripting(b b: B, idx: Int, a: A) {
+  // CHECK: load i8*, i8** @"\01L_selector(setObject:atIndexedSubscript:)", align 8
+  b[idx] = a
+
+  // CHECK: load i8*, i8** @"\01L_selector(objectAtIndexedSubscript:)"
+  var a2 = b[idx] as! A
+}
+
+// CHECK-LABEL: define hidden swiftcc void @"$S7objc_ir17keyedSubscripting1b3idx1aySo1BC_So1ACAItF"
+func keyedSubscripting(b b: B, idx: A, a: A) {
+  // CHECK: load i8*, i8** @"\01L_selector(setObject:forKeyedSubscript:)"
+  b[a] = a
+  // CHECK: load i8*, i8** @"\01L_selector(objectForKeyedSubscript:)"
+  var a2 = b[a] as! A
+}
+
+// CHECK-LABEL: define hidden swiftcc void @"$S7objc_ir14propertyAccess1bySo1BC_tF"
+func propertyAccess(b b: B) {
+   // CHECK: load i8*, i8** @"\01L_selector(counter)"
+   // CHECK: load i8*, i8** @"\01L_selector(setCounter:)"
+   b.counter = b.counter + 1
+
+   // CHECK: load %objc_class*, %objc_class** @"OBJC_CLASS_REF_$_B"
+   // CHECK: load i8*, i8** @"\01L_selector(sharedCounter)"
+   // CHECK: load i8*, i8** @"\01L_selector(setSharedCounter:)"
+   B.sharedCounter = B.sharedCounter + 1
+}
+
+// CHECK-LABEL: define hidden swiftcc %TSo1BC* @"$S7objc_ir8downcast1aSo1BCSo1AC_tF"(
+func downcast(a a: A) -> B {
+  // CHECK: [[CLASS:%.*]] = load %objc_class*, %objc_class** @"OBJC_CLASS_REF_$_B"
+  // CHECK: [[T0:%.*]] = call %objc_class* @swift_getInitializedObjCClass(%objc_class* [[CLASS]])
+  // CHECK: [[T1:%.*]] = bitcast %objc_class* [[T0]] to i8*
+  // CHECK: call i8* @swift_dynamicCastObjCClassUnconditional(i8* [[A:%.*]], i8* [[T1]]) [[NOUNWIND:#[0-9]+]]
+  return a as! B
+}
+
+// CHECK-LABEL: define hidden swiftcc void @"$S7objc_ir19almostSubscriptable3as11aySo06AlmostD0C_So1ACtF"
+func almostSubscriptable(as1 as1: AlmostSubscriptable, a: A) {
+  as1.objectForKeyedSubscript(a)
+}
+
+// CHECK-LABEL: define hidden swiftcc void @"$S7objc_ir13protocolTypes1a1bySo7NSMinceC_So9NSRuncing_ptF"(%TSo7NSMinceC*, %objc_object*) {{.*}} {
+func protocolTypes(a a: NSMince, b: NSRuncing) {
+  // - (void)eatWith:(id <NSRuncing>)runcer;
+  a.eat(with: b)
+  // CHECK: [[SEL:%.*]] = load i8*, i8** @"\01L_selector(eatWith:)", align 8
+  // CHECK: call void bitcast (void ()* @objc_msgSend to void ([[OPAQUE:%.*]]*, i8*, i8*)*)([[OPAQUE:%.*]]* {{%.*}}, i8* [[SEL]], i8* {{%.*}})
+}
+
+// CHECK-LABEL: define hidden swiftcc void @"$S7objc_ir6getset1pySo8FooProto_p_tF"(%objc_object*) {{.*}} {
+func getset(p p: FooProto) {
+  // CHECK: load i8*, i8** @"\01L_selector(bar)"
+  // CHECK: load i8*, i8** @"\01L_selector(setBar:)"
+  let prop = p.bar
+  p.bar = prop
+}
+
+// CHECK-LABEL: define hidden swiftcc %swift.type* @"$S7objc_ir16protocolMetatype1pSo8FooProto_pXpSoAD_p_tF"(%objc_object*) {{.*}} {
+func protocolMetatype(p: FooProto) -> FooProto.Type {
+  // CHECK: = call %swift.type* @swift_getObjectType(%objc_object* %0)
+  // CHECK-NOT: {{retain|release}}
+  // CHECK: [[RAW_RESULT:%.+]] = call i8* @processFooType(i8* {{%.+}})
+  // CHECK: [[CASTED_RESULT:%.+]] = bitcast i8* [[RAW_RESULT]] to %objc_class*
+  // CHECK: [[SWIFT_RESULT:%.+]] = call %swift.type* @swift_getObjCClassMetadata(%objc_class* [[CASTED_RESULT]])
+  // CHECK-NOT: call void @swift_unknownRelease(%objc_object* %0)
+  // CHECK: ret %swift.type* [[SWIFT_RESULT]]
+  let type = processFooType(type(of: p))
+  return type
+} // CHECK: }
+
+class Impl: FooProto, AnotherProto {
+  @objc var bar: Int32 = 0
+}
+
+// CHECK-LABEL: define hidden swiftcc %swift.type* @"$S7objc_ir27protocolCompositionMetatype1pSo12AnotherProto_So03FooG0pXpAA4ImplC_tF"(%T7objc_ir4ImplC*) {{.*}} {
+func protocolCompositionMetatype(p: Impl) -> (FooProto & AnotherProto).Type {
+  // CHECK: = getelementptr inbounds %T7objc_ir4ImplC, %T7objc_ir4ImplC* %0, i32 0, i32 0, i32 0
+  // CHECK-NOT: {{retain|release}}
+  // CHECK: [[RAW_RESULT:%.+]] = call i8* @processComboType(i8* {{%.+}})
+  // CHECK: [[CASTED_RESULT:%.+]] = bitcast i8* [[RAW_RESULT]] to %objc_class*
+  // CHECK: [[SWIFT_RESULT:%.+]] = call %swift.type* @swift_getObjCClassMetadata(%objc_class* [[CASTED_RESULT]])
+  // CHECK-NOT: call void bitcast (void (%swift.refcounted*)* @swift_release to void (%T7objc_ir4ImplC*)*)(%T7objc_ir4ImplC* %0)
+  // CHECK: ret %swift.type* [[SWIFT_RESULT]]
+  let type = processComboType(type(of: p))
+  return type
+} // CHECK: }
+
+// CHECK-LABEL: define hidden swiftcc %swift.type* @"$S7objc_ir28protocolCompositionMetatype21pSo12AnotherProto_So03FooG0pXpAA4ImplC_tF"(%T7objc_ir4ImplC*) {{.*}} {
+func protocolCompositionMetatype2(p: Impl) -> (FooProto & AnotherProto).Type {
+  // CHECK: = getelementptr inbounds %T7objc_ir4ImplC, %T7objc_ir4ImplC* %0, i32 0, i32 0, i32 0
+  // CHECK-NOT: {{retain|release}}
+  // CHECK: [[RAW_RESULT:%.+]] = call i8* @processComboType2(i8* {{%.+}})
+  // CHECK: [[CASTED_RESULT:%.+]] = bitcast i8* [[RAW_RESULT]] to %objc_class*
+  // CHECK: [[SWIFT_RESULT:%.+]] = call %swift.type* @swift_getObjCClassMetadata(%objc_class* [[CASTED_RESULT]])
+  // CHECK-NOT: @swift_release
+  // CHECK: ret %swift.type* [[SWIFT_RESULT]]
+  let type = processComboType2(type(of: p))
+  return type
+} // CHECK: }
+
+// CHECK-LABEL: define hidden swiftcc void @"$S7objc_ir17pointerPropertiesyySo14PointerWrapperCF"(%TSo14PointerWrapperC*) {{.*}} {
+func pointerProperties(_ obj: PointerWrapper) {
+  // CHECK: load i8*, i8** @"\01L_selector(setVoidPtr:)"
+  // CHECK: load i8*, i8** @"\01L_selector(setIntPtr:)"
+  // CHECK: load i8*, i8** @"\01L_selector(setIdPtr:)"
+  obj.voidPtr = nil as UnsafeMutableRawPointer?
+  obj.intPtr = nil as UnsafeMutablePointer?
+  obj.idPtr = nil as AutoreleasingUnsafeMutablePointer?
+}
+
+// CHECK-LABEL: define hidden swiftcc void @"$S7objc_ir16strangeSelectorsyySo13SwiftNameTestCF"(%TSo13SwiftNameTestC*) {{.*}} {
+func strangeSelectors(_ obj: SwiftNameTest) {
+  // CHECK: load i8*, i8** @"\01L_selector(:b:)"
+  obj.empty(a: 0, b: 0)
+}
+
+// CHECK-LABEL: define hidden swiftcc void @"$S7objc_ir20customFactoryMethodsyyF"() {{.*}} {
+func customFactoryMethods() {
+  // CHECK: call swiftcc %TSo13SwiftNameTestC* @"$SSo13SwiftNameTestC10dummyParamAByt_tcfCTO"
+  // CHECK: call swiftcc %TSo13SwiftNameTestC* @"$SSo13SwiftNameTestC2ccABypSg_tcfCTO"
+  // CHECK: call swiftcc %TSo13SwiftNameTestC* @"$SSo13SwiftNameTestC5emptyABs5Int32V_tcfCTO"
+  _ = SwiftNameTest(dummyParam: ())
+  _ = SwiftNameTest(cc: nil)
+  _ = SwiftNameTest(empty: 0)
+
+  // CHECK: load i8*, i8** @"\01L_selector(testZ)"
+  // CHECK: load i8*, i8** @"\01L_selector(testY:)"
+  // CHECK: load i8*, i8** @"\01L_selector(testX:xx:)"
+  // CHECK: load i8*, i8** @"\01L_selector(::)"
+  _ = SwiftNameTest.zz()
+  _ = SwiftNameTest.yy(aa: nil)
+  _ = SwiftNameTest.xx(nil, bb: nil)
+  _ = SwiftNameTest.empty(1, 2)
+
+  do {
+    // CHECK: call swiftcc %TSo18SwiftNameTestErrorC* @"$SSo18SwiftNameTestErrorC5errorAByt_tKcfCTO"
+    // CHECK: call swiftcc %TSo18SwiftNameTestErrorC* @"$SSo18SwiftNameTestErrorC2aa5errorABypSg_yttKcfCTO"
+    // CHECK: call swiftcc %TSo18SwiftNameTestErrorC* @"$SSo18SwiftNameTestErrorC2aa5error5blockABypSg_ytyyctKcfCTO"
+    // CHECK: call swiftcc %TSo18SwiftNameTestErrorC* @"$SSo18SwiftNameTestErrorC5error5blockAByt_yyctKcfCTO"
+    // CHECK: call swiftcc %TSo18SwiftNameTestErrorC* @"$SSo18SwiftNameTestErrorC2aaABypSg_tKcfCTO"
+    // CHECK: call swiftcc %TSo18SwiftNameTestErrorC* @"$SSo18SwiftNameTestErrorC2aa5blockABypSg_yyctKcfCTO"
+    // CHECK: call swiftcc %TSo18SwiftNameTestErrorC* @"$SSo18SwiftNameTestErrorC5blockAByyc_tKcfCTO"
+    _ = try SwiftNameTestError(error: ())
+    _ = try SwiftNameTestError(aa: nil, error: ())
+    _ = try SwiftNameTestError(aa: nil, error: (), block: {})
+    _ = try SwiftNameTestError(error: (), block: {})
+
+    _ = try SwiftNameTestError(aa: nil)
+    _ = try SwiftNameTestError(aa: nil, block: {})
+    _ = try SwiftNameTestError(block: {})
+
+    // CHECK: load i8*, i8** @"\01L_selector(testW:error:)"
+    // CHECK: load i8*, i8** @"\01L_selector(testW2:error:)"
+    // CHECK: load i8*, i8** @"\01L_selector(testV:)"
+    // CHECK: load i8*, i8** @"\01L_selector(testV2:)"
+    _ = try SwiftNameTestError.ww(nil)
+    _ = try SwiftNameTestError.w2(nil, error: ())
+    _ = try SwiftNameTestError.vv()
+    _ = try SwiftNameTestError.v2(error: ())
+  } catch _ {
+  }
+}
+
+// CHECK-LABEL: define linkonce_odr hidden swiftcc %TSo13SwiftNameTestC* @"$SSo13SwiftNameTestC10dummyParamAByt_tcfCTO"
+// CHECK: load i8*, i8** @"\01L_selector(b)"
+// CHECK: }
+
+// CHECK-LABEL: define linkonce_odr hidden swiftcc %TSo13SwiftNameTestC* @"$SSo13SwiftNameTestC2ccABypSg_tcfCTO"
+// CHECK: load i8*, i8** @"\01L_selector(c:)"
+// CHECK: }
+
+// CHECK-LABEL: define linkonce_odr hidden swiftcc %TSo18SwiftNameTestErrorC* @"$SSo18SwiftNameTestErrorC5errorAByt_tKcfCTO"
+// CHECK: load i8*, i8** @"\01L_selector(err1:)"
+// CHECK: }
+
+// CHECK-LABEL: define linkonce_odr hidden swiftcc %TSo18SwiftNameTestErrorC* @"$SSo18SwiftNameTestErrorC2aa5errorABypSg_yttKcfCTO"
+// CHECK: load i8*, i8** @"\01L_selector(err2:error:)"
+// CHECK: }
+
+// CHECK-LABEL: define linkonce_odr hidden swiftcc %TSo18SwiftNameTestErrorC* @"$SSo18SwiftNameTestErrorC2aa5error5blockABypSg_ytyyctKcfCTO"
+// CHECK: load i8*, i8** @"\01L_selector(err3:error:callback:)"
+// CHECK: }
+
+// CHECK-LABEL: define linkonce_odr hidden swiftcc %TSo18SwiftNameTestErrorC* @"$SSo18SwiftNameTestErrorC5error5blockAByt_yyctKcfCTO"
+// CHECK: load i8*, i8** @"\01L_selector(err4:callback:)"
+// CHECK: }
+
+// CHECK-LABEL: define linkonce_odr hidden swiftcc %TSo18SwiftNameTestErrorC* @"$SSo18SwiftNameTestErrorC2aaABypSg_tKcfCTO"
+// CHECK: load i8*, i8** @"\01L_selector(err5:error:)"
+// CHECK: }
+
+// CHECK-LABEL: define linkonce_odr hidden swiftcc %TSo18SwiftNameTestErrorC* @"$SSo18SwiftNameTestErrorC2aa5blockABypSg_yyctKcfCTO"
+// CHECK: load i8*, i8** @"\01L_selector(err6:error:callback:)"
+// CHECK: }
+
+// CHECK-LABEL: define linkonce_odr hidden swiftcc %TSo18SwiftNameTestErrorC* @"$SSo18SwiftNameTestErrorC5blockAByyc_tKcfCTO"
+// CHECK: load i8*, i8** @"\01L_selector(err7:callback:)"
+// CHECK: }
+
+// CHECK-LABEL: define hidden swiftcc void @"$S7objc_ir29customFactoryMethodsInheritedyyF"() {{.*}} {
+func customFactoryMethodsInherited() {
+  // CHECK: call swiftcc %TSo16SwiftNameTestSubC* @"$SSo16SwiftNameTestSubC10dummyParamAByt_tcfCTO"
+  // CHECK: call swiftcc %TSo16SwiftNameTestSubC* @"$SSo16SwiftNameTestSubC2ccABypSg_tcfCTO"
+  _ = SwiftNameTestSub(dummyParam: ())
+  _ = SwiftNameTestSub(cc: nil)
+
+  // CHECK: load i8*, i8** @"\01L_selector(testZ)"
+  // CHECK: load i8*, i8** @"\01L_selector(testY:)"
+  // CHECK: load i8*, i8** @"\01L_selector(testX:xx:)"
+  _ = SwiftNameTestSub.zz()
+  _ = SwiftNameTestSub.yy(aa: nil)
+  _ = SwiftNameTestSub.xx(nil, bb: nil)
+
+  do {
+    // CHECK: call swiftcc %TSo21SwiftNameTestErrorSubC* @"$SSo21SwiftNameTestErrorSubC5errorAByt_tKcfCTO"
+    // CHECK: call swiftcc %TSo21SwiftNameTestErrorSubC* @"$SSo21SwiftNameTestErrorSubC2aa5errorABypSg_yttKcfCTO"
+    // CHECK: call swiftcc %TSo21SwiftNameTestErrorSubC* @"$SSo21SwiftNameTestErrorSubC2aa5error5blockABypSg_ytyyctKcfCTO"
+    // CHECK: call swiftcc %TSo21SwiftNameTestErrorSubC* @"$SSo21SwiftNameTestErrorSubC5error5blockAByt_yyctKcfCTO"
+    // CHECK: call swiftcc %TSo21SwiftNameTestErrorSubC* @"$SSo21SwiftNameTestErrorSubC2aaABypSg_tKcfCTO"
+    // CHECK: call swiftcc %TSo21SwiftNameTestErrorSubC* @"$SSo21SwiftNameTestErrorSubC2aa5blockABypSg_yyctKcfCTO"
+    // CHECK: call swiftcc %TSo21SwiftNameTestErrorSubC* @"$SSo21SwiftNameTestErrorSubC5blockAByyc_tKcfCTO"
+    _ = try SwiftNameTestErrorSub(error: ())
+    _ = try SwiftNameTestErrorSub(aa: nil, error: ())
+    _ = try SwiftNameTestErrorSub(aa: nil, error: (), block: {})
+    _ = try SwiftNameTestErrorSub(error: (), block: {})
+
+    _ = try SwiftNameTestErrorSub(aa: nil)
+    _ = try SwiftNameTestErrorSub(aa: nil, block: {})
+    _ = try SwiftNameTestErrorSub(block: {})
+
+    // CHECK: load i8*, i8** @"\01L_selector(testW:error:)"
+    // CHECK: load i8*, i8** @"\01L_selector(testW2:error:)"
+    // CHECK: load i8*, i8** @"\01L_selector(testV:)"
+    // CHECK: load i8*, i8** @"\01L_selector(testV2:)"
+    _ = try SwiftNameTestErrorSub.ww(nil)
+    _ = try SwiftNameTestErrorSub.w2(nil, error: ())
+    _ = try SwiftNameTestErrorSub.vv()
+    _ = try SwiftNameTestErrorSub.v2(error: ())
+  } catch _ {
+  }
+}
+
+// CHECK-LABEL: define linkonce_odr hidden swiftcc %TSo16SwiftNameTestSubC* @"$SSo16SwiftNameTestSubC10dummyParamAByt_tcfCTO"
+// CHECK: load i8*, i8** @"\01L_selector(b)"
+// CHECK: }
+
+// CHECK-LABEL: define linkonce_odr hidden swiftcc %TSo16SwiftNameTestSubC* @"$SSo16SwiftNameTestSubC2ccABypSg_tcfCTO"
+// CHECK: load i8*, i8** @"\01L_selector(c:)"
+// CHECK: }
+
+// CHECK-LABEL: define linkonce_odr hidden swiftcc %TSo21SwiftNameTestErrorSubC* @"$SSo21SwiftNameTestErrorSubC5errorAByt_tKcfCTO"
+// CHECK: load i8*, i8** @"\01L_selector(err1:)"
+// CHECK: }
+
+// CHECK-LABEL: define linkonce_odr hidden swiftcc %TSo21SwiftNameTestErrorSubC* @"$SSo21SwiftNameTestErrorSubC2aa5errorABypSg_yttKcfCTO"
+// CHECK: load i8*, i8** @"\01L_selector(err2:error:)"
+// CHECK: }
+
+// CHECK-LABEL: define linkonce_odr hidden swiftcc %TSo21SwiftNameTestErrorSubC* @"$SSo21SwiftNameTestErrorSubC2aa5error5blockABypSg_ytyyctKcfCTO"
+// CHECK: load i8*, i8** @"\01L_selector(err3:error:callback:)"
+// CHECK: }
+
+// CHECK-LABEL: define linkonce_odr hidden swiftcc %TSo21SwiftNameTestErrorSubC* @"$SSo21SwiftNameTestErrorSubC5error5blockAByt_yyctKcfCTO"
+// CHECK: load i8*, i8** @"\01L_selector(err4:callback:)"
+// CHECK: }
+
+// CHECK-LABEL: define linkonce_odr hidden swiftcc %TSo21SwiftNameTestErrorSubC* @"$SSo21SwiftNameTestErrorSubC2aaABypSg_tKcfCTO"
+// CHECK: load i8*, i8** @"\01L_selector(err5:error:)"
+// CHECK: }
+
+// CHECK-LABEL: define linkonce_odr hidden swiftcc %TSo21SwiftNameTestErrorSubC* @"$SSo21SwiftNameTestErrorSubC2aa5blockABypSg_yyctKcfCTO"
+// CHECK: load i8*, i8** @"\01L_selector(err6:error:callback:)"
+// CHECK: }
+
+// CHECK-LABEL: define linkonce_odr hidden swiftcc %TSo21SwiftNameTestErrorSubC* @"$SSo21SwiftNameTestErrorSubC5blockAByyc_tKcfCTO"
+// CHECK: load i8*, i8** @"\01L_selector(err7:callback:)"
+// CHECK: }
+
+
+// CHECK-LABEL: define hidden swiftcc void @"$S7objc_ir30testCompatibilityAliasMangling3objySo13SwiftNameTestC_tF"
+func testCompatibilityAliasMangling(obj: SwiftNameAlias) {
+  // CHECK: call void @llvm.dbg.declare(metadata %TSo13SwiftNameTestC** {{%.+}}, metadata ![[SWIFT_NAME_ALIAS_VAR:[0-9]+]], metadata !DIExpression())
+}
+
+
+// CHECK: linkonce_odr hidden {{.*}} @"$SSo1BC3intABSgs5Int32V_tcfcTO"
+// CHECK: load i8*, i8** @"\01L_selector(initWithInt:)"
+// CHECK: call [[OPAQUE:%.*]]* bitcast (void ()* @objc_msgSend
+
+
+// CHECK: attributes [[NOUNWIND]] = { nounwind }
+
+// CHECK: ![[SWIFT_NAME_ALIAS_VAR]] = !DILocalVariable(name: "obj", arg: 1, scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: ![[SWIFT_NAME_ALIAS_TYPE:[0-9]+]])
+// CHECK: ![[SWIFT_NAME_ALIAS_TYPE]] = !DIDerivedType(tag: DW_TAG_typedef, name: "$SSo14SwiftNameAliasaD", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, baseType: !{{[0-9]+}})
+
diff --git a/test/ClangImporter/plus_zero_optional.swift b/test/ClangImporter/plus_zero_optional.swift
new file mode 100644
index 0000000..f36c2af
--- /dev/null
+++ b/test/ClangImporter/plus_zero_optional.swift
@@ -0,0 +1,83 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -I %S/Inputs/custom-modules -enable-sil-ownership -emit-silgen -o - %s | %FileCheck %s
+
+// REQUIRES: objc_interop
+
+import ObjectiveC
+import Foundation
+import objc_ext
+import TestProtocols
+
+class A {
+  @objc func foo() -> String? {
+    return ""
+  }
+// CHECK-LABEL:    sil hidden [thunk] @$S8optional1AC3fooSSSgyFTo : $@convention(objc_method) (A) -> @autoreleased Optional<NSString>
+// CHECK:    bb0([[SELF:%.*]] : @unowned $A):
+// CHECK:      [[SELF_COPY:%.*]] = copy_value [[SELF]]
+// CHECK:      [[BORROWED_SELF_COPY:%.*]] = begin_borrow [[SELF_COPY]]
+// CHECK:      [[T0:%.*]] = function_ref @$S8optional1AC3fooSSSgyF
+// CHECK-NEXT: [[T1:%.*]] = apply [[T0]]([[BORROWED_SELF_COPY]])
+// CHECK-NEXT: end_borrow [[BORROWED_SELF_COPY]] from [[SELF_COPY]]
+// CHECK-NEXT: destroy_value [[SELF_COPY]]
+// CHECK-NEXT: switch_enum [[T1]] : $Optional<String>, case #Optional.some!enumelt.1: [[SOME_BB:bb[0-9]+]], case #Optional.none!enumelt: [[NONE_BB:bb[0-9]+]]
+//
+//   Something branch: project value, translate, inject into result.
+// CHECK:    [[SOME_BB]]([[STR:%.*]] : @owned $String):
+// CHECK:      [[T0:%.*]] = function_ref @$SSS10FoundationE19_bridgeToObjectiveCSo8NSStringCyF
+// CHECK-NEXT: [[BORROWED_STR:%.*]] = begin_borrow [[STR]]
+// CHECK-NEXT: [[T1:%.*]] = apply [[T0]]([[BORROWED_STR]])
+// CHECK-NEXT: enum $Optional<NSString>, #Optional.some!enumelt.1, [[T1]]
+// CHECK-NEXT: end_borrow [[BORROWED_STR:%.*]] from [[STR]]
+// CHECK-NEXT: destroy_value [[STR]]
+// CHECK-NEXT: br
+//   Nothing branch: inject nothing into result.
+//
+// CHECK: [[NONE_BB]]:
+// CHECK-NEXT: enum $Optional<NSString>, #Optional.none!enumelt
+// CHECK-NEXT: br
+//   Continuation.
+// CHECK: bb3([[T0:%.*]] : @owned $Optional<NSString>):
+// CHECK-NEXT: return [[T0]]
+
+  @objc func bar(x x : String?) {}
+// CHECK-LABEL:    sil hidden [thunk] @$S8optional1AC3bar1xySSSg_tFTo : $@convention(objc_method) (Optional<NSString>, A) -> ()
+// CHECK:    bb0([[ARG:%.*]] : @unowned $Optional<NSString>, [[SELF:%.*]] : @unowned $A):
+// CHECK:      [[ARG_COPY:%.*]] = copy_value [[ARG]]
+// CHECK:      [[SELF_COPY:%.*]] = copy_value [[SELF]]
+// CHECK:      switch_enum [[ARG_COPY]] : $Optional<NSString>, case #Optional.some!enumelt.1: [[SOME_BB:bb[0-9]+]], case #Optional.none!enumelt: [[NONE_BB:bb[0-9]+]]
+//
+//   Something branch: project value, translate, inject into result.
+// CHECK:    [[SOME_BB]]([[NSSTR:%.*]] : @owned $NSString):
+// CHECK:      [[T0:%.*]] = function_ref @$SSS10FoundationE36_unconditionallyBridgeFromObjectiveCySSSo8NSStringCSgFZ
+//   Make a temporary initialized string that we're going to clobber as part of the conversion process (?).
+// CHECK-NEXT: [[NSSTR_BOX:%.*]] = enum $Optional<NSString>, #Optional.some!enumelt.1, [[NSSTR]] : $NSString
+// CHECK-NEXT: [[STRING_META:%.*]] = metatype $@thin String.Type
+// CHECK-NEXT: [[T1:%.*]] = apply [[T0]]([[NSSTR_BOX]], [[STRING_META]])
+// CHECK-NEXT: enum $Optional<String>, #Optional.some!enumelt.1, [[T1]]
+// CHECK-NEXT: destroy_value [[NSSTR_BOX]]
+// CHECK-NEXT: br
+//
+//   Nothing branch: inject nothing into result.
+// CHECK:   [[NONE_BB]]:
+// CHECK:      enum $Optional<String>, #Optional.none!enumelt
+// CHECK-NEXT: br
+//   Continuation.
+// CHECK:      bb3([[T0:%.*]] : @owned $Optional<String>):
+// CHECK:      [[BORROWED_T0:%.*]] = begin_borrow [[T0]]
+// CHECK:      [[BORROWED_SELF_COPY:%.*]] = begin_borrow [[SELF_COPY]]
+// CHECK:      [[T1:%.*]] = function_ref @$S8optional1AC3bar1xySSSg_tF
+// CHECK-NEXT: [[T2:%.*]] = apply [[T1]]([[BORROWED_T0]], [[BORROWED_SELF_COPY]])
+// CHECK-NEXT: end_borrow [[BORROWED_SELF_COPY]] from [[SELF_COPY]]
+// CHECK-NEXT: end_borrow [[BORROWED_T0]] from [[T0]]
+// CHECK-NEXT: destroy_value [[T0]]
+// CHECK-NEXT: destroy_value [[SELF_COPY]]
+// CHECK-NEXT: return [[T2]] : $()
+}
+
+
+// rdar://15144951
+class TestWeak : NSObject {
+  weak var b : WeakObject? = nil
+}
+class WeakObject : NSObject {}
diff --git a/test/ClangImporter/plus_zero_serialization-sil.swift b/test/ClangImporter/plus_zero_serialization-sil.swift
new file mode 100644
index 0000000..2c063a6
--- /dev/null
+++ b/test/ClangImporter/plus_zero_serialization-sil.swift
@@ -0,0 +1,44 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %empty-directory(%t)
+// RUN: %target-swift-frontend -emit-module-path %t/Test.swiftmodule -emit-sil -o /dev/null -module-name Test %s -sdk "" -import-objc-header %S/Inputs/serialization-sil.h -enable-sil-ownership
+// RUN: %target-sil-func-extractor %t/Test.swiftmodule -sil-print-debuginfo  -func='$S4Test16testPartialApplyyySoAA_pF' -o - | %FileCheck %s
+
+// REQUIRES: objc_interop
+
+// @_transparent to force serialization.
+@_transparent
+public func testPartialApply(_ obj: Test) {
+  // CHECK-LABEL: @$S4Test16testPartialApplyyySoAA_pF : $@convention(thin) (@guaranteed Test) -> () {
+  if let curried1 = obj.normalObject {
+    // CHECK: dynamic_method_br [[CURRIED1_OBJ:%.+]] : $@opened([[CURRIED1_EXISTENTIAL:.+]]) Test, #Test.normalObject!1.foreign, [[CURRIED1_TRUE:[^,]+]], [[CURRIED1_FALSE:[^,]+]]
+    // CHECK: [[CURRIED1_FALSE]]:
+    // CHECK: [[CURRIED1_TRUE]]([[CURRIED1_METHOD:%.+]] : $@convention(objc_method) (@opened([[CURRIED1_EXISTENTIAL]]) Test) -> @autoreleased AnyObject):
+    // CHECK: [[CURRIED1_PARTIAL:%.+]] = partial_apply [callee_guaranteed] [[CURRIED1_METHOD]]([[CURRIED1_OBJ]]) : $@convention(objc_method) (@opened([[CURRIED1_EXISTENTIAL]]) Test) -> @autoreleased AnyObject
+    // CHECK: [[CURRIED1_THUNK:%.+]] = function_ref @$SyXlIego_ypIegr_TR : $@convention(thin) (@guaranteed @callee_guaranteed () -> @owned AnyObject) -> @out Any
+    // CHECK: = partial_apply [callee_guaranteed] [[CURRIED1_THUNK]]([[CURRIED1_PARTIAL]])
+    curried1()
+  }
+  if let curried2 = obj.innerPointer {
+    // CHECK: dynamic_method_br [[CURRIED2_OBJ:%.+]] : $@opened([[CURRIED2_EXISTENTIAL:.+]]) Test, #Test.innerPointer!1.foreign, [[CURRIED2_TRUE:[^,]+]], [[CURRIED2_FALSE:[^,]+]]
+    // CHECK: [[CURRIED2_FALSE]]:
+    // CHECK: [[CURRIED2_TRUE]]([[CURRIED2_METHOD:%.+]] : $@convention(objc_method) (@opened([[CURRIED2_EXISTENTIAL]]) Test) -> @unowned_inner_pointer UnsafeMutableRawPointer):
+    // CHECK: [[CURRIED2_PARTIAL:%.+]] = partial_apply [callee_guaranteed] [[CURRIED2_METHOD]]([[CURRIED2_OBJ]]) : $@convention(objc_method) (@opened([[CURRIED2_EXISTENTIAL]]) Test) -> @unowned_inner_pointer UnsafeMutableRawPointer
+    curried2()
+  }
+  if let prop1 = obj.normalObjectProp {
+    // CHECK: dynamic_method_br [[PROP1_OBJ:%.+]] : $@opened([[PROP1_EXISTENTIAL:.+]]) Test, #Test.normalObjectProp!getter.1.foreign, [[PROP1_TRUE:[^,]+]], [[PROP1_FALSE:[^,]+]]
+    // CHECK: [[PROP1_FALSE]]:
+    // CHECK: [[PROP1_TRUE]]([[PROP1_METHOD:%.+]] : $@convention(objc_method) (@opened([[PROP1_EXISTENTIAL]]) Test) -> @autoreleased AnyObject):
+    // CHECK: [[PROP1_PARTIAL:%.+]] = partial_apply [callee_guaranteed] [[PROP1_METHOD]]([[PROP1_OBJ]]) : $@convention(objc_method) (@opened([[PROP1_EXISTENTIAL]]) Test) -> @autoreleased AnyObject
+    // CHECK: = apply [[PROP1_PARTIAL]]() : $@callee_guaranteed () -> @owned AnyObject
+    _ = prop1
+  }
+  if let prop2 = obj.innerPointerProp {
+    // CHECK: dynamic_method_br [[PROP2_OBJ:%.+]] : $@opened([[PROP2_EXISTENTIAL:.+]]) Test, #Test.innerPointerProp!getter.1.foreign, [[PROP2_TRUE:[^,]+]], [[PROP2_FALSE:[^,]+]]
+    // CHECK: [[PROP2_FALSE]]:
+    // CHECK: [[PROP2_TRUE]]([[PROP2_METHOD:%.+]] : $@convention(objc_method) (@opened([[PROP2_EXISTENTIAL]]) Test) -> @unowned_inner_pointer UnsafeMutableRawPointer):
+    // CHECK: [[PROP2_PARTIAL:%.+]] = partial_apply [callee_guaranteed] [[PROP2_METHOD]]([[PROP2_OBJ]]) : $@convention(objc_method) (@opened([[PROP2_EXISTENTIAL]]) Test) -> @unowned_inner_pointer UnsafeMutableRawPointer
+    // CHECK: = apply [[PROP2_PARTIAL]]() : $@callee_guaranteed () -> UnsafeMutableRawPointer
+    _ = prop2
+  }
+} // CHECK: // end sil function '$S4Test16testPartialApplyyySoAA_pF'
diff --git a/test/ClangImporter/serialization-sil.swift b/test/ClangImporter/serialization-sil.swift
index dc43fdd..eeb1d66 100644
--- a/test/ClangImporter/serialization-sil.swift
+++ b/test/ClangImporter/serialization-sil.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %empty-directory(%t)
 // RUN: %target-swift-frontend -emit-module-path %t/Test.swiftmodule -emit-sil -o /dev/null -module-name Test %s -sdk "" -import-objc-header %S/Inputs/serialization-sil.h
 // RUN: %target-sil-func-extractor %t/Test.swiftmodule -sil-print-debuginfo  -func='$S4Test16testPartialApplyyySoAA_pF' -o - | %FileCheck %s
diff --git a/test/DebugInfo/apple-names-accel.swift b/test/DebugInfo/apple-names-accel.swift
new file mode 100644
index 0000000..ff28e6e
--- /dev/null
+++ b/test/DebugInfo/apple-names-accel.swift
@@ -0,0 +1,10 @@
+// Check that the apple-names section is emitted on Darwin.
+// Adapted from llvm/test/DebugInfo/X86/debugger-tune.ll
+// RUN: %target-swiftc_driver -emit-object -g %s -o %t
+// RUN: llvm-readobj -sections %t | %FileCheck --check-prefix=CHECK-LLDB %s
+
+// CHECK-LLDB-NOT: debug_pubnames
+// CHECK-LLDB:     apple_names
+// CHECK-LLDB-NOT: debug_pubnames
+
+// REQUIRES: OS=macosx
diff --git a/test/DebugInfo/apple-types-accel.swift b/test/DebugInfo/apple-types-accel.swift
index 94e1fe1..7279181 100644
--- a/test/DebugInfo/apple-types-accel.swift
+++ b/test/DebugInfo/apple-types-accel.swift
@@ -4,12 +4,12 @@
 // RUN:    | %FileCheck --check-prefix=CHECK-ACCEL %s
 // RUN: %llvm-dwarfdump --debug-info %t.o  \
 // RUN:    | %FileCheck --check-prefix=CHECK-DWARF %s
-// DISABLED <rdar://problem/28232630>: dwarfdump --verify %t.o
+// RUN: %llvm-dwarfdump --verify %t.o
 // REQUIRES: OS=macosx
 
 // Verify that the unmangles basenames end up in the accelerator table.
-// CHECK-ACCEL-DAG:	 Name: {{.*}}"Int64"
-// CHECK-ACCEL-DAG:	 Name: {{.*}}"foo"
+// CHECK-ACCEL-DAG:	 String: {{.*}}"Int64"
+// CHECK-ACCEL-DAG:	 String: {{.*}}"foo"
 
 // Verify that the mangled names end up in the debug info.
 // CHECK-DWARF: TAG_module
diff --git a/test/DebugInfo/closure-multivalue.swift b/test/DebugInfo/closure-multivalue.swift
index bd541ab..c724ad1 100644
--- a/test/DebugInfo/closure-multivalue.swift
+++ b/test/DebugInfo/closure-multivalue.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // rdar://problem/23727705:
 // RUN-DISABLED: %target-swift-frontend -O %s -disable-llvm-optzns -emit-ir -g -o - | %FileCheck %s
 import StdlibUnittest
@@ -35,8 +36,8 @@
 // Verify that a reabstraction thunk does not have a line number.
 // CHECK-O0-NOT: DW_OP_bit_piece
 // CHECK-O0-NOT: DW_OP_bit_piece
-// CHECK-O0: !DILocalVariable(name: "a", arg: 1{{.*}} line: 17,
+// CHECK-O0: !DILocalVariable(name: "a", arg: 1{{.*}} line: 18,
 // CHECK-O0-NOT: DW_OP_bit_piece
-// CHECK-O0: !DILocalVariable(name: "b", arg: 2{{.*}} line: 17,
+// CHECK-O0: !DILocalVariable(name: "b", arg: 2{{.*}} line: 18,
 // CHECK-O0-NOT: DW_OP_bit_piece
 // CHECK-O0: !DISubprogram(linkageName: "$SS2SSbs5Error_pIgxxdzo_S2SSbsAA_pIegiidzo_TR",
diff --git a/test/DebugInfo/compiler-flags.swift b/test/DebugInfo/compiler-flags.swift
index a68fd68..f13b430 100644
--- a/test/DebugInfo/compiler-flags.swift
+++ b/test/DebugInfo/compiler-flags.swift
@@ -12,16 +12,6 @@
 // CHECK-EXPLICIT-NOT:            "
 // CHECK-EXPLICIT-SAME:           -resource-dir 
 
-
-// Check that we tune the debug output for LLDB.
-// Adapted from llvm/test/DebugInfo/X86/debugger-tune.ll
-// RUN: %target-swiftc_driver -emit-object -g %s -o %t
-// RUN: llvm-readobj -sections %t | %FileCheck --check-prefix=CHECK-LLDB %s
-
-// CHECK-LLDB-NOT: debug_pubnames
-// CHECK-LLDB:     apple_names
-// CHECK-LLDB-NOT: debug_pubnames
-
 // Check that we don't write temporary file names in the debug info
 // RUN: TMPDIR=abc/def %target-swift-frontend %s -I abc/def/xyz -g -emit-ir -o - | %FileCheck --check-prefix CHECK-TEMP %s
 // CHECK-TEMP: !DICompileUnit({{.*}} flags: "{{.*}} -I <temporary-file>
diff --git a/test/DebugInfo/generic_args.swift b/test/DebugInfo/generic_args.swift
index 3f57123..a0974eb 100644
--- a/test/DebugInfo/generic_args.swift
+++ b/test/DebugInfo/generic_args.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -primary-file %s -emit-ir -verify -g -o - | %FileCheck %s
 
 func markUsed<T>(_ t: T) {}
diff --git a/test/DebugInfo/local-vars.swift.gyb b/test/DebugInfo/local-vars.swift.gyb
index b8e5320..ab9a294 100644
--- a/test/DebugInfo/local-vars.swift.gyb
+++ b/test/DebugInfo/local-vars.swift.gyb
@@ -7,6 +7,7 @@
 // RUN: %target-swift-frontend %t.swift -g -c -o %t.o
 // RUN: %llvm-dwarfdump %t.o \
 // RUN:   | %FileCheck %t.swift --check-prefix=DWARF
+// RUN: %llvm-dwarfdump --verify %t.o
 // RUN: %target-swift-frontend %t.swift -O -g -emit-ir -o - \
 // RUN:   | %FileCheck %t.swift --check-prefix=OPTZNS
 
diff --git a/test/DebugInfo/plus_zero_closure-multivalue.swift b/test/DebugInfo/plus_zero_closure-multivalue.swift
new file mode 100644
index 0000000..f77552f
--- /dev/null
+++ b/test/DebugInfo/plus_zero_closure-multivalue.swift
@@ -0,0 +1,43 @@
+// REQUIRES: plus_zero_runtime
+// rdar://problem/23727705:
+// RUN-DISABLED: %target-swift-frontend -O %s -disable-llvm-optzns -emit-ir -g -o - | %FileCheck %s
+import StdlibUnittest
+
+// CHECK: define {{.*}}i1 {{.*}}4main4sort
+// CHECK: call void @llvm.dbg.value(metadata i8*{{.*}}, metadata ![[A:.*]], metadata ![[P1:.*]])
+// CHECK: call void @llvm.dbg.value(metadata i{{[0-9]+}} {{.*}}, metadata ![[A]], metadata ![[P2:.*]])
+// CHECK: call void @llvm.dbg.value(metadata i{{[0-9]+}} {{.*}}, metadata ![[A]], metadata ![[P3:.*]])
+// CHECK: call void @llvm.dbg.value(metadata i8*{{.*}}, metadata ![[B:.*]], metadata ![[P1]])
+// CHECK: call void @llvm.dbg.value(metadata i{{[0-9]+}} {{.*}}, metadata ![[B]], metadata ![[P2]])
+// CHECK: call void @llvm.dbg.value(metadata i{{[0-9]+}} {{.*}}, metadata ![[B]], metadata ![[P3]])
+// CHECK-DAG: ![[A]] = !DILocalVariable(name: "a",{{.*}} line: 17
+// CHECK-DAG: ![[B]] = !DILocalVariable(name: "b",{{.*}} line: 17
+// CHECK-DAG: ![[P1]] = !DIExpression(DW_OP_bit_piece, 0, {{(32|64)}})
+// CHECK-DAG: ![[P2]] = !DIExpression(DW_OP_bit_piece, {{(32, 32|64, 64)}})
+// CHECK-DAG: ![[P3]] = !DIExpression(DW_OP_bit_piece, {{(64, 32|128, 64)}})
+public func sort(_ a: String, b: String) -> Bool {
+  _blackHole("Sorting..\(a) & \(b)")
+  return (a < b)
+}
+
+public func demo() {
+    let names = ["Sean", "Barry", "Kate"]
+    let sortedNames = names.sorted(by: sort)
+    var sortedNamesAsString : String = String()
+    for name in sortedNames {
+        sortedNamesAsString += ("\(name), ")
+    }
+    _blackHole(sortedNamesAsString)
+}
+demo()
+
+// At -O0, we should have a single aggregate argument.
+// RUN: %target-swift-frontend %s -emit-ir -g -o - | %FileCheck %s --check-prefix=CHECK-O0
+// Verify that a reabstraction thunk does not have a line number.
+// CHECK-O0-NOT: DW_OP_bit_piece
+// CHECK-O0-NOT: DW_OP_bit_piece
+// CHECK-O0: !DILocalVariable(name: "a", arg: 1{{.*}} line: 17,
+// CHECK-O0-NOT: DW_OP_bit_piece
+// CHECK-O0: !DILocalVariable(name: "b", arg: 2{{.*}} line: 17,
+// CHECK-O0-NOT: DW_OP_bit_piece
+// CHECK-O0: !DISubprogram(linkageName: "$SS2SSbs5Error_pIgggdzo_S2SSbsAA_pIegnndzo_TR",
diff --git a/test/DebugInfo/plus_zero_generic_args.swift b/test/DebugInfo/plus_zero_generic_args.swift
new file mode 100644
index 0000000..e4de262
--- /dev/null
+++ b/test/DebugInfo/plus_zero_generic_args.swift
@@ -0,0 +1,54 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -primary-file %s -emit-ir -verify -g -o - | %FileCheck %s
+
+func markUsed<T>(_ t: T) {}
+
+protocol AProtocol {
+  func f() -> String
+}
+class AClass : AProtocol {
+  func f() -> String { return "A" }
+}
+class AnotherClass : AProtocol {
+  func f() -> String { return "B" }
+}
+
+// CHECK-DAG: !DICompositeType(tag: DW_TAG_structure_type, name: "$S12generic_args9aFunction{{.*}}D",{{.*}} elements: ![[PROTOS:[0-9]+]]
+// CHECK-DAG: ![[PROTOS]] = !{![[INHERIT:.*]]}
+// CHECK-DAG: ![[INHERIT]] = !DIDerivedType(tag: DW_TAG_inheritance,{{.*}} baseType: ![[PROTOCOL:[0-9]+]]
+// CHECK-DAG: ![[PROTOCOL]] = !DICompositeType(tag: DW_TAG_structure_type, name: "$S12generic_args9AProtocol_pmD",
+// CHECK-DAG: !DILocalVariable(name: "x", arg: 1,{{.*}} type: ![[T:.*]])
+// CHECK-DAG: ![[T]] = !DICompositeType(tag: DW_TAG_structure_type, name: "$S12generic_args9aFunction
+// CHECK-DAG: !DILocalVariable(name: "y", arg: 2,{{.*}} type: ![[Q:.*]])
+// CHECK-DAG: ![[Q]] = !DICompositeType(tag: DW_TAG_structure_type, name: "$S12generic_args9aFunction
+func aFunction<T : AProtocol, Q : AProtocol>(_ x: T, _ y: Q, _ z: String) {
+   markUsed("I am in \(z): \(x.f()) \(y.f())")
+}
+
+aFunction(AClass(),AnotherClass(),"aFunction")
+
+struct Wrapper<T: AProtocol> {
+
+  init<U>(from : Wrapper<U>) {
+  // CHECK-DAG: !DICompositeType(tag: DW_TAG_structure_type, name: "Wrapper",{{.*}} identifier: "$S12generic_args7WrapperVyAC4fromACyxGACyqd__G_tcAA9AProtocolRd__lufcQq_GD")
+    var wrapped = from
+    wrapped = from
+    _ = wrapped
+  }
+
+  func passthrough(_ t: T) -> T {
+    // The type of local should have the context Wrapper<T>.
+    // CHECK-DAG: ![[WRAPPER:.*]] = !DICompositeType({{.*}}identifier: "$S12generic_args7WrapperVQq_D")
+    // CHECK-DAG: !DILocalVariable(name: "local",{{.*}} line: [[@LINE+1]],{{.*}} type: ![[WRAPPER]]
+    var local = t
+    local = t
+    return local
+  }
+}
+
+// CHECK-DAG: ![[FNTY:.*]] = !DICompositeType({{.*}}identifier: "$S12generic_args5apply_1fq_x_q_xXEtr0_lFQq_AaB_ACq_x_q_xXEtr0_lFQq0_Ignr_D"
+// CHECK-DAG: !DILocalVariable(name: "f", {{.*}}, line: [[@LINE+1]], type: ![[FNTY]])
+func apply<T, U> (_ x: T, f: (T) -> (U)) -> U {
+  return f(x)
+}
+
diff --git a/test/DebugInfo/plus_zero_resilience.swift b/test/DebugInfo/plus_zero_resilience.swift
new file mode 100644
index 0000000..0e50528
--- /dev/null
+++ b/test/DebugInfo/plus_zero_resilience.swift
@@ -0,0 +1,39 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %empty-directory(%t)
+//
+// Compile the external swift module.
+// RUN: %target-swift-frontend -g -emit-module -enable-resilience \
+// RUN:   -emit-module-path=%t/resilient_struct.swiftmodule \
+// RUN:   -module-name=resilient_struct %S/../Inputs/resilient_struct.swift
+//
+// RUN: %target-swift-frontend -g -I %t -emit-ir -enable-resilience %s  -o - \
+// RUN:  | %FileCheck %s
+//
+// RUN: %target-swift-frontend -g -I %t -emit-sil -enable-resilience %s -o - \
+// RUN:    | %FileCheck %s --check-prefix=CHECK-SIL
+// RUN: %target-swift-frontend -g -I %t -emit-sil -enable-resilience %s -o - \
+// RUN:    -debugger-support | %FileCheck %s --check-prefix=CHECK-LLDB
+import resilient_struct
+
+func use<T>(_ t: T) {}
+
+public func f() {
+  let s1 = Size(w: 1, h: 2)
+  use(s1)
+  // CHECK: %[[ADDR:.*]] = alloca i8*
+  // CHECK: call void @llvm.dbg.declare(metadata i8** %[[ADDR]],
+  // CHECK-SAME:                        metadata ![[V1:[0-9]+]],
+  // CHECK-SAME:                        metadata !DIExpression(DW_OP_deref))
+  // CHECK: %[[S1:.*]] = alloca i8,
+  // CHECK: store i8* %[[S1]], i8** %[[ADDR]]
+  // CHECK: ![[V1]] = !DILocalVariable(name: "s1", {{.*}}type: ![[TY:[0-9]+]])
+  // CHECK: ![[TY]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Size",
+  // FIXME-NOT: size:
+  // CHECK: =
+}
+
+// CHECK-SIL: // f()
+// CHECK-LLDB: // f()
+// CHECK-SIL: %0 = alloc_stack $Size, let, name "s1"
+// CHECK-LLDB: %0 = metatype $@thin Size.Type
+// CHECK-LLDB: debug_value %{{.*}} : $Size, let, name "s1"
diff --git a/test/DebugInfo/resilience.swift b/test/DebugInfo/resilience.swift
index 34651fe..5f78283 100644
--- a/test/DebugInfo/resilience.swift
+++ b/test/DebugInfo/resilience.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %empty-directory(%t)
 //
 // Compile the external swift module.
diff --git a/test/FixCode/Inputs/batch-mode-helper.swift b/test/FixCode/Inputs/batch-mode-helper.swift
new file mode 100644
index 0000000..8b3bcbd
--- /dev/null
+++ b/test/FixCode/Inputs/batch-mode-helper.swift
@@ -0,0 +1,10 @@
+enum E2 {
+  case x
+  case y
+  case z
+}
+
+func fooHelper(_ e: E2) {
+  switch e {
+  }
+}
diff --git a/test/FixCode/batch-mode.swift b/test/FixCode/batch-mode.swift
new file mode 100644
index 0000000..a2504ed
--- /dev/null
+++ b/test/FixCode/batch-mode.swift
@@ -0,0 +1,24 @@
+// RUN: not %swift -typecheck -target %target-triple -primary-file %s  -emit-fixits-path %t.main.remap -primary-file %S/Inputs/batch-mode-helper.swift -emit-fixits-path %t.helper.remap -diagnostics-editor-mode
+// RUN: %FileCheck -check-prefix=CHECK-MAIN %s < %t.main.remap
+// RUN: %FileCheck -check-prefix=NEGATIVE-MAIN %s < %t.main.remap
+// RUN: %FileCheck -check-prefix=CHECK-HELPER %s < %t.helper.remap
+// RUN: %FileCheck -check-prefix=NEGATIVE-HELPER %s < %t.helper.remap
+
+// CHECK-MAIN: "file": "{{.+}}batch-mode.swift"
+// CHECK-MAIN: "text": "case .a:\n<#code#>\ncase .b:\n<#code#>\ncase .c:\n<#code#>\n"
+// NEGATIVE-MAIN-NOT: batch-mode-helper.swift
+
+// CHECK-HELPER: "file": "{{.+}}batch-mode-helper.swift"
+// CHECK-HELPER: "text": "case .x:\n<#code#>\ncase .y:\n<#code#>\ncase .z:\n<#code#>\n"
+// NEGATIVE-HELPER-NOT: batch-mode.swift
+
+enum E1 {
+  case a
+  case b
+  case c
+}
+
+func fooMain(_ e: E1) {
+  switch e {
+  }
+}
diff --git a/test/Frontend/embed-bitcode-tvos.ll b/test/Frontend/embed-bitcode-tvos.ll
index ccac443..d1b874d 100644
--- a/test/Frontend/embed-bitcode-tvos.ll
+++ b/test/Frontend/embed-bitcode-tvos.ll
@@ -12,7 +12,7 @@
 ; CHECK-IMPORTER: clang
 ; CHECK-IMPORTER: -fembed-bitcode
 ; CHECK-IMPORTER: -target
-; CHECK-IMPORTER: -mtvos-version-min=9
+; CHECK-IMPORTER: arm64-apple-tvos9
 ; CHECK-IMPORTER-NOT: argument unused
 
 define i32 @f0() nounwind ssp {
diff --git a/test/Fuzzing/fuzzer_test.swift b/test/Fuzzing/fuzzer_test.swift
index 054bf41..3795c4c 100644
--- a/test/Fuzzing/fuzzer_test.swift
+++ b/test/Fuzzing/fuzzer_test.swift
@@ -8,7 +8,7 @@
 // XFAIL: OS=watchos
 // CHECK: Crash!
 
-#if os(OSX) || os(iOS)
+#if os(macOS) || os(iOS)
 import Darwin
 #elseif os(Linux) || os(FreeBSD) || os(PS4) || os(Android) || os(Cygwin)
 import Glibc
diff --git a/test/Fuzzing/fuzzer_test_simpler.swift b/test/Fuzzing/fuzzer_test_simpler.swift
index 94e9b6c..beade8e 100644
--- a/test/Fuzzing/fuzzer_test_simpler.swift
+++ b/test/Fuzzing/fuzzer_test_simpler.swift
@@ -8,7 +8,7 @@
 // XFAIL: OS=tvos
 // XFAIL: OS=watchos
 
-#if os(OSX) || os(iOS)
+#if os(macOS) || os(iOS)
 import Darwin
 #elseif os(Linux) || os(FreeBSD) || os(PS4) || os(Android) || os(Cygwin)
 import Glibc
diff --git a/test/IDE/coloring_configs.swift b/test/IDE/coloring_configs.swift
index 6bd6393..69445d0 100644
--- a/test/IDE/coloring_configs.swift
+++ b/test/IDE/coloring_configs.swift
@@ -280,8 +280,8 @@
 // CHECK: <kw>class</kw> NestedPoundIf {
     func foo1() {
 // CHECK: <kw>func</kw> foo1() {
-        #if os(OSX)
-// CHECK: <#kw>#if</#kw> <#id>os</#id>(<#id>OSX</#id>)
+        #if os(macOS)
+// CHECK: <#kw>#if</#kw> <#id>os</#id>(<#id>macOS</#id>)
           var a = 1
 // CHECK: <kw>var</kw> a = <int>1</int>
             #if USE_METAL
diff --git a/test/IDE/structure.swift b/test/IDE/structure.swift
index edee06d..87bbdfd 100644
--- a/test/IDE/structure.swift
+++ b/test/IDE/structure.swift
@@ -154,7 +154,7 @@
 
 class NestedPoundIf{
     func foo1() {
-        #if os(OSX)
+        #if os(macOS)
           var a = 1
             #if USE_METAL
               var b = 2
diff --git a/test/IRGen/Inputs/ObjectiveC.swift b/test/IRGen/Inputs/ObjectiveC.swift
index 7457f48..0e155bb 100644
--- a/test/IRGen/Inputs/ObjectiveC.swift
+++ b/test/IRGen/Inputs/ObjectiveC.swift
@@ -2,8 +2,8 @@
 @_exported import ObjectiveC
 
 public struct ObjCBool : CustomStringConvertible {
-#if os(OSX) || (os(iOS) && (arch(i386) || arch(arm)))
-  // On OS X and 32-bit iOS, Objective-C's BOOL type is a "signed char".
+#if os(macOS) || (os(iOS) && (arch(i386) || arch(arm)))
+  // On macOS and 32-bit iOS, Objective-C's BOOL type is a "signed char".
   private var value: Int8
 
   public init(_ value: Bool) {
diff --git a/test/IRGen/big_types_corner_cases.swift b/test/IRGen/big_types_corner_cases.swift
index 7dfb3eb..7d3886d 100644
--- a/test/IRGen/big_types_corner_cases.swift
+++ b/test/IRGen/big_types_corner_cases.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -assume-parsing-unqualified-ownership-sil -enable-large-loadable-types %s -emit-ir | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize
 // REQUIRES: optimized_stdlib
 // UNSUPPORTED: resilient_stdlib
diff --git a/test/IRGen/builtin_math.swift b/test/IRGen/builtin_math.swift
index 43a84b5..04a3a39 100644
--- a/test/IRGen/builtin_math.swift
+++ b/test/IRGen/builtin_math.swift
@@ -20,21 +20,22 @@
   return _exp(f)
 }
 
-// LLVM's sqrt intrinsic does not have the same semantics as libm's sqrt.
-// In particular, llvm.sqrt(negative) is documented as being undef, but
-// we want sqrt(negative) to be defined to be NaN for IEEE 754 conformance.
-
 // CHECK-LABEL: define {{.*}}test3
 // CHECK: call double @sqrt
 
 public func test3(d : Double) -> Double {
+  // This call uses the sqrt function imported from C.
   return sqrt(d)
 }
 
 // CHECK-LABEL: define {{.*}}test4
-// CHECK: call float @sqrtf
+// CHECK: call float @llvm.sqrt.f32
 
 public func test4(f : Float) -> Float {
+  // This call does not match the signature for the C sqrt function
+  // (as opposed to sqrtf) so instead it gets compiled using the generic
+  // sqrt function from the stdlib's tgmath.swift. That translates to
+  // _stdlib_squareRootf and then to __builtin_sqrtf via SwiftShims.
   return sqrt(f)
 }
 
diff --git a/test/IRGen/builtins.swift b/test/IRGen/builtins.swift
index 92d1f49..7046e14 100644
--- a/test/IRGen/builtins.swift
+++ b/test/IRGen/builtins.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -assume-parsing-unqualified-ownership-sil -parse-stdlib -primary-file %s -emit-ir -o - -disable-objc-attr-requires-foundation-module | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%target-runtime
 
 // REQUIRES: CPU=x86_64
diff --git a/test/IRGen/class_bounded_generics.swift b/test/IRGen/class_bounded_generics.swift
index d66fc4a..f1db660 100644
--- a/test/IRGen/class_bounded_generics.swift
+++ b/test/IRGen/class_bounded_generics.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -emit-ir -primary-file %s -disable-objc-attr-requires-foundation-module | %FileCheck %s
 
 // REQUIRES: CPU=x86_64
diff --git a/test/IRGen/enum_resilience.swift b/test/IRGen/enum_resilience.swift
index 8370768..7c3393a 100644
--- a/test/IRGen/enum_resilience.swift
+++ b/test/IRGen/enum_resilience.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %empty-directory(%t)
 // RUN: %target-swift-frontend -emit-module -enable-resilience -emit-module-path=%t/resilient_struct.swiftmodule -module-name=resilient_struct %S/../Inputs/resilient_struct.swift
 // RUN: %target-swift-frontend -emit-module -enable-resilience -emit-module-path=%t/resilient_enum.swiftmodule -module-name=resilient_enum -I %t %S/../Inputs/resilient_enum.swift
diff --git a/test/IRGen/generic_metatypes.swift b/test/IRGen/generic_metatypes.swift
index ff14d93..fef162f 100644
--- a/test/IRGen/generic_metatypes.swift
+++ b/test/IRGen/generic_metatypes.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %swift -target x86_64-apple-macosx10.9 -emit-ir -parse-stdlib -primary-file %s | %FileCheck --check-prefix=CHECK --check-prefix=CHECK-64 %s
 // RUN: %swift -target i386-apple-ios7.0 -emit-ir -parse-stdlib -primary-file %s | %FileCheck --check-prefix=CHECK --check-prefix=CHECK-32 %s
 // RUN: %swift -target x86_64-apple-ios7.0 -emit-ir -parse-stdlib -primary-file %s | %FileCheck --check-prefix=CHECK --check-prefix=CHECK-64 %s
diff --git a/test/IRGen/generic_metatypes_arm.swift b/test/IRGen/generic_metatypes_arm.swift
index e5f28b0..58bfd76 100644
--- a/test/IRGen/generic_metatypes_arm.swift
+++ b/test/IRGen/generic_metatypes_arm.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %swift -target armv7-apple-ios7.0 -module-name generic_metatypes -emit-ir -parse-stdlib -primary-file %s | %FileCheck --check-prefix=CHECK --check-prefix=CHECK-32 %s
 // RUN: %swift -target arm64-apple-ios7.0 -emit-ir -module-name generic_metatypes -parse-stdlib -primary-file %s | %FileCheck --check-prefix=CHECK --check-prefix=CHECK-64 %s
 // RUN: %swift -target armv7-apple-tvos9.0 -emit-ir -module-name generic_metatypes -parse-stdlib -primary-file %s | %FileCheck --check-prefix=CHECK --check-prefix=CHECK-32 %s
diff --git a/test/IRGen/generic_tuples.swift b/test/IRGen/generic_tuples.swift
index 99fd2ff..9f2968d 100644
--- a/test/IRGen/generic_tuples.swift
+++ b/test/IRGen/generic_tuples.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -assume-parsing-unqualified-ownership-sil -emit-ir -primary-file %s | %FileCheck %s
 
 // Make sure that optimization passes don't choke on storage types for generic tuples
diff --git a/test/IRGen/keypaths.sil b/test/IRGen/keypaths.sil
index 9c8636b..3c736a8 100644
--- a/test/IRGen/keypaths.sil
+++ b/test/IRGen/keypaths.sil
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %empty-directory(%t)
 // -- Convert <i32 0x...> constants to decimal constants that LLVM will print
 // RUN: %utils/chex.py < %s > %t/keypaths.sil
diff --git a/test/IRGen/keypaths_objc.sil b/test/IRGen/keypaths_objc.sil
index 589fe23..bd94794 100644
--- a/test/IRGen/keypaths_objc.sil
+++ b/test/IRGen/keypaths_objc.sil
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %empty-directory(%t)
 // RUN: %utils/chex.py < %s > %t/keypaths_objc.sil
 // RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -emit-ir %t/keypaths_objc.sil | %FileCheck %t/keypaths_objc.sil --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize
diff --git a/test/IRGen/lowered_optional_self_metadata.sil b/test/IRGen/lowered_optional_self_metadata.sil
index 11edc8f..8f14c95 100644
--- a/test/IRGen/lowered_optional_self_metadata.sil
+++ b/test/IRGen/lowered_optional_self_metadata.sil
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -assume-parsing-unqualified-ownership-sil -emit-ir %s
 sil_stage canonical
 
diff --git a/test/IRGen/objc.swift b/test/IRGen/objc.swift
index ec4d58a..0a15e37 100644
--- a/test/IRGen/objc.swift
+++ b/test/IRGen/objc.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %empty-directory(%t)
 // RUN: %build-irgen-test-overlays
 // RUN: %target-swift-frontend(mock-sdk: -sdk %S/Inputs -I %t) -primary-file %s -emit-ir -disable-objc-attr-requires-foundation-module | %FileCheck %s
diff --git a/test/IRGen/objc_retainAutoreleasedReturnValue.swift b/test/IRGen/objc_retainAutoreleasedReturnValue.swift
index a8d1a27..65c781c 100644
--- a/test/IRGen/objc_retainAutoreleasedReturnValue.swift
+++ b/test/IRGen/objc_retainAutoreleasedReturnValue.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -target x86_64-apple-macosx10.12 -assume-parsing-unqualified-ownership-sil -import-objc-header %S/Inputs/StaticInline.h %s -emit-ir | %FileCheck %s
 // RUN: %target-swift-frontend -O -target x86_64-apple-macosx10.12 -assume-parsing-unqualified-ownership-sil -import-objc-header %S/Inputs/StaticInline.h %s -emit-ir | %FileCheck %s --check-prefix=OPT
 
diff --git a/test/IRGen/plus_zero_big_types_corner_cases.swift b/test/IRGen/plus_zero_big_types_corner_cases.swift
new file mode 100644
index 0000000..05b8339
--- /dev/null
+++ b/test/IRGen/plus_zero_big_types_corner_cases.swift
@@ -0,0 +1,236 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -assume-parsing-unqualified-ownership-sil -enable-large-loadable-types %s -emit-ir | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize
+// REQUIRES: optimized_stdlib
+// UNSUPPORTED: resilient_stdlib
+
+public struct BigStruct {
+  var i0 : Int32 = 0
+  var i1 : Int32 = 1
+  var i2 : Int32 = 2
+  var i3 : Int32 = 3
+  var i4 : Int32 = 4
+  var i5 : Int32 = 5
+  var i6 : Int32 = 6
+  var i7 : Int32 = 7
+  var i8 : Int32 = 8
+}
+
+func takeClosure(execute block: () -> Void) {
+}
+
+class OptionalInoutFuncType {
+  private var lp :  BigStruct?
+  private var _handler : ((BigStruct?, Error?) -> ())?
+
+  func execute(_ error: Error?) {
+    var p : BigStruct?
+    var handler: ((BigStruct?, Error?) -> ())?
+    
+    takeClosure {
+      p = self.lp
+      handler = self._handler
+      self._handler = nil
+    }
+
+    handler?(p, error)
+  }
+}
+
+// CHECK-LABEL: define{{( protected)?}} i32 @main(i32, i8**)
+// CHECK: call void @llvm.lifetime.start
+// CHECK: call void @llvm.memcpy
+// CHECK: call void @llvm.lifetime.end
+// CHECK: ret i32 0
+let bigStructGlobalArray : [BigStruct] = [
+  BigStruct()
+]
+
+// CHECK-LABEL: define{{( protected)?}} internal swiftcc void @"$S22big_types_corner_cases21OptionalInoutFuncTypeC7executeyys5Error_pSgFyyXEfU_"(%T22big_types_corner_cases9BigStructVSg* nocapture dereferenceable({{.*}}), %T22big_types_corner_cases21OptionalInoutFuncTypeC*, %T22big_types_corner_cases9BigStructVSgs5Error_pSgIegcg_Sg* nocapture dereferenceable({{.*}})
+// CHECK: call void @"$SSqWy
+// CHECK: call void @"$SSqWe
+// CHECK: ret void
+
+public func f1_returns_BigType(_ x: BigStruct) -> BigStruct {
+  return x
+}
+
+public func f2_returns_f1() -> (_ x: BigStruct) -> BigStruct {
+  return f1_returns_BigType
+}
+
+public func f3_uses_f2() {
+  let x = BigStruct()
+  let useOfF2 = f2_returns_f1()
+  let _ = useOfF2(x)
+}
+
+// CHECK-LABEL: define{{( protected)?}} swiftcc void @"$S22big_types_corner_cases10f3_uses_f2yyF"()
+// CHECK: call swiftcc void @"$S22big_types_corner_cases9BigStructVACycfC"(%T22big_types_corner_cases9BigStructV* noalias nocapture sret 
+// CHECK: call swiftcc { i8*, %swift.refcounted* } @"$S22big_types_corner_cases13f2_returns_f1AA9BigStructVADcyF"()
+// CHECK: call swiftcc void {{.*}}(%T22big_types_corner_cases9BigStructV* noalias nocapture sret {{.*}}, %T22big_types_corner_cases9BigStructV* noalias nocapture dereferenceable({{.*}}) {{.*}}, %swift.refcounted* swiftself {{.*}})
+// CHECK: ret void
+
+public func f4_tuple_use_of_f2() {
+  let x = BigStruct()
+  let tupleWithFunc = (f2_returns_f1(), x)
+  let useOfF2 = tupleWithFunc.0
+  let _ = useOfF2(x)
+}
+
+// CHECK-LABEL: define{{( protected)?}} swiftcc void @"$S22big_types_corner_cases18f4_tuple_use_of_f2yyF"()
+// CHECK: [[TUPLE:%.*]] = call swiftcc { i8*, %swift.refcounted* } @"$S22big_types_corner_cases13f2_returns_f1AA9BigStructVADcyF"()
+// CHECK: [[TUPLE_EXTRACT:%.*]] = extractvalue { i8*, %swift.refcounted* } [[TUPLE]], 0
+// CHECK: [[CAST_EXTRACT:%.*]] = bitcast i8* [[TUPLE_EXTRACT]] to void (%T22big_types_corner_cases9BigStructV*, %T22big_types_corner_cases9BigStructV*, %swift.refcounted*)*
+// CHECK:  call swiftcc void [[CAST_EXTRACT]](%T22big_types_corner_cases9BigStructV* noalias nocapture sret {{.*}}, %T22big_types_corner_cases9BigStructV* noalias nocapture dereferenceable({{.*}}) {{.*}}, %swift.refcounted* swiftself %{{.*}})
+// CHECK: ret void
+
+public class BigClass {
+  public init() {
+  }
+
+  public var optVar: ((BigStruct)-> Void)? = nil
+    
+  func useBigStruct(bigStruct: BigStruct) {
+    optVar!(bigStruct)
+  }
+}
+
+// CHECK-LABEL: define{{( protected)?}} hidden swiftcc void @"$S22big_types_corner_cases8BigClassC03useE6Struct0aH0yAA0eH0V_tF"(%T22big_types_corner_cases9BigStructV* noalias nocapture dereferenceable({{.*}}), %T22big_types_corner_cases8BigClassC* swiftself)
+// CHECK: [[BITCAST:%.*]] = bitcast i8* {{.*}} to void (%T22big_types_corner_cases9BigStructV*, %swift.refcounted*)*
+// CHECK: call swiftcc void [[BITCAST]](%T22big_types_corner_cases9BigStructV* noalias nocapture dereferenceable({{.*}}) %0, %swift.refcounted* swiftself 
+// CHECK: ret void
+
+public struct MyStruct {
+  public let a: Int
+  public let b: String?
+ }
+
+typealias UploadFunction = ((MyStruct, Int?) -> Void) -> Void
+func takesUploader(_ u: UploadFunction) { }
+
+class Foo {
+  func blam() {
+    takesUploader(self.myMethod) // crash compiling this
+  }
+
+  func myMethod(_ callback: (MyStruct, Int) -> Void) -> Void { }
+}
+
+// CHECK-LABEL: define{{( protected)?}} linkonce_odr hidden swiftcc { i8*, %swift.refcounted* } @"$S22big_types_corner_cases3FooC8myMethodyyyAA8MyStructV_SitXEFTc"(%T22big_types_corner_cases3FooC*)
+// CHECK: getelementptr inbounds %T22big_types_corner_cases3FooC, %T22big_types_corner_cases3FooC*
+// CHECK: getelementptr inbounds void (i8*, %swift.opaque*, %T22big_types_corner_cases3FooC*)*, void (i8*, %swift.opaque*, %T22big_types_corner_cases3FooC*)**
+// CHECK: call noalias %swift.refcounted* @swift_allocObject(%swift.type* getelementptr inbounds (%swift.full_boxmetadata, %swift.full_boxmetadata*
+// CHECK: ret { i8*, %swift.refcounted* }
+
+public enum LargeEnum {
+  public enum InnerEnum {
+    case simple(Int64)
+    case hard(Int64, String?, Int64)
+  }
+  case Empty1
+  case Empty2
+  case Full(InnerEnum)
+}
+
+public func enumCallee(_ x: LargeEnum) {
+  switch x {
+    case .Full(let inner): print(inner)
+    case .Empty1: break
+    case .Empty2: break
+  }
+}
+// CHECK-LABEL-64: define{{( protected)?}} swiftcc void @"$S22big_types_corner_cases10enumCalleeyAA9LargeEnumOF"(%T22big_types_corner_cases9LargeEnumO* noalias nocapture dereferenceable({{.*}})) #0 {
+// CHECK-64: alloca %T22big_types_corner_cases9LargeEnumO05InnerF0O
+// CHECK-64: alloca %T22big_types_corner_cases9LargeEnumO
+// CHECK-64: call void @llvm.memcpy.p0i8.p0i8.i64
+// CHECK-64: call void @llvm.memcpy.p0i8.p0i8.i64
+// CHECK-64: $Ss5print_9separator10terminatoryypd_S2StF
+// CHECK-64: ret void
+
+// CHECK-LABEL: define{{( protected)?}} internal swiftcc void @"$S22big_types_corner_cases8SuperSubC1fyyFAA9BigStructVycfU_"(%T22big_types_corner_cases9BigStructV* noalias nocapture sret, %T22big_types_corner_cases8SuperSubC*)
+// CHECK-64: [[ALLOC1:%.*]] = alloca %T22big_types_corner_cases9BigStructV
+// CHECK-64: [[ALLOC2:%.*]] = alloca %T22big_types_corner_cases9BigStructV
+// CHECK-64: [[ALLOC3:%.*]] = alloca %T22big_types_corner_cases9BigStructVSg
+// CHECK-64: [[ALLOC4:%.*]] = alloca %T22big_types_corner_cases9BigStructVSg
+// CHECK-64: call swiftcc void @"$S22big_types_corner_cases9SuperBaseC4boomAA9BigStructVyF"(%T22big_types_corner_cases9BigStructV* noalias nocapture sret [[ALLOC1]], %T22big_types_corner_cases9SuperBaseC* swiftself {{.*}})
+// CHECK: ret void
+class SuperBase {
+  func boom() -> BigStruct {
+    return BigStruct()
+  }
+}
+
+class SuperSub : SuperBase {
+  override func boom() -> BigStruct {
+    return BigStruct()
+  }
+  func f() {
+    let _ = {
+      nil ?? super.boom()
+    }
+  }
+}
+
+// CHECK-LABEL: define{{( protected)?}} swiftcc void @"$S22big_types_corner_cases10MUseStructV16superclassMirrorAA03BigF0VSgvg"(%T22big_types_corner_cases9BigStructVSg* noalias nocapture sret, %T22big_types_corner_cases10MUseStructV* noalias nocapture swiftself dereferenceable({{.*}}))
+// CHECK: [[ALLOC:%.*]] = alloca %T22big_types_corner_cases9BigStructVSg
+// CHECK: [[LOAD:%.*]] = load %swift.refcounted*, %swift.refcounted** %.callInternalLet.data
+// CHECK: call swiftcc void %7(%T22big_types_corner_cases9BigStructVSg* noalias nocapture sret [[ALLOC]], %swift.refcounted* swiftself [[LOAD]])
+// CHECK: ret void
+public struct MUseStruct {
+  var x = BigStruct()
+  public var superclassMirror: BigStruct? {
+    return callInternalLet()
+  }
+
+  internal let callInternalLet: () -> BigStruct?
+}
+
+// CHECK-LABEL-64: define{{( protected)?}} swiftcc void @"$S22big_types_corner_cases18stringAndSubstringSS_s0G0VtyF"(<{ %TSS, %Ts9SubstringV }>* noalias nocapture sret) #0 {
+// CHECK-LABEL-32: define{{( protected)?}} swiftcc void @"$S22big_types_corner_cases18stringAndSubstringSS_s0G0VtyF"(<{ %TSS, [4 x i8], %Ts9SubstringV }>* noalias nocapture sret) #0 {
+// CHECK: alloca %Ts9SubstringV
+// CHECK: alloca %Ts9SubstringV
+// CHECK: ret void
+public func stringAndSubstring() -> (String, Substring) {
+  let s = "Hello, World"
+  let a = Substring(s).dropFirst()
+  return (s, a)
+}
+
+func bigStructGet() -> BigStruct {
+  return BigStruct()
+}
+
+// CHECK-LABEL: define{{( protected)?}} swiftcc void @"$S22big_types_corner_cases11testGetFuncyyF"()
+// CHECK: ret void
+public func testGetFunc() {
+  let testGetPtr: @convention(thin) () -> BigStruct = bigStructGet
+}
+
+// CHECK-LABEL: define{{( protected)?}} hidden swiftcc void @"$S22big_types_corner_cases7TestBigC4testyyF"(%T22big_types_corner_cases7TestBigC* swiftself)
+// CHECK: [[CALL1:%.*]] = call %swift.type* @"$SSayy22big_types_corner_cases9BigStructVcSgGMa"
+// CHECK: [[CALL2:%.*]] = call i8** @"$SSayy22big_types_corner_cases9BigStructVcSgGSayxGs10CollectionsWl
+// CHECK: call swiftcc void @"$Ss10CollectionPsE5index5where5IndexQzSgSb7ElementQzKXE_tKF"(%TSq.{{.*}}* noalias nocapture sret {{.*}}, i8* bitcast (i1 (%T22big_types_corner_cases9BigStructVytIegnr_Sg*, %swift.refcounted*, %swift.error**)* @"$S22big_types_corner_cases9BigStructVIegy_SgSbs5Error_pIggdzo_ACytIegnr_SgSbsAE_pIegndzo_TRTA" to i8*), %swift.opaque* {{.*}}, %swift.type* [[CALL1]], i8** [[CALL2]], %swift.opaque* noalias nocapture swiftself
+// CHECK: ret void
+
+// CHECK-LABEL: define{{( protected)?}} hidden swiftcc void @"$S22big_types_corner_cases7TestBigC5test2yyF"(%T22big_types_corner_cases7TestBigC* swiftself)
+// CHECK: [[CALL1:%.*]] = call %swift.type* @"$SSaySS2ID_y22big_types_corner_cases9BigStructVcSg7handlertGMa"
+// CHECK: [[CALL2:%.*]] = call i8** @"$SSaySS2ID_y22big_types_corner_cases9BigStructVcSg7handlertGSayxGs10CollectionsWl"
+// CHECK: call swiftcc void @"$Ss10CollectionPss16IndexingIteratorVyxG0C0RtzrlE04makeC0AEyF"(%Ts16IndexingIteratorV* noalias nocapture sret {{.*}}, %swift.type* [[CALL1]], i8** [[CALL2]], %swift.opaque* noalias nocapture swiftself {{.*}})
+// CHECK: ret void
+class TestBig {
+    typealias Handler = (BigStruct) -> Void
+
+    func test() {
+        let arr = [Handler?]()
+        let d = arr.index(where: { _ in true })
+    }
+    
+    func test2() {
+        let arr: [(ID: String, handler: Handler?)] = []
+        for (_, handler) in arr {
+        takeClosure {
+          		handler?(BigStruct())
+        	}
+        }
+    }
+}
diff --git a/test/IRGen/plus_zero_builtins.swift b/test/IRGen/plus_zero_builtins.swift
new file mode 100644
index 0000000..b4479ad
--- /dev/null
+++ b/test/IRGen/plus_zero_builtins.swift
@@ -0,0 +1,872 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -assume-parsing-unqualified-ownership-sil -parse-stdlib -primary-file %s -emit-ir -o - -disable-objc-attr-requires-foundation-module | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%target-runtime
+
+// REQUIRES: CPU=x86_64
+
+import Swift
+
+// CHECK-DAG: [[REFCOUNT:%swift.refcounted.*]] = type
+// CHECK-DAG: [[X:%T8builtins1XC]] = type
+// CHECK-DAG: [[Y:%T8builtins1YC]] = type
+
+typealias Int = Builtin.Int32
+typealias Bool = Builtin.Int1
+
+// CHECK: call swiftcc void @swift_errorInMain(
+
+infix operator * {
+  associativity left
+  precedence 200
+}
+infix operator / {
+  associativity left
+  precedence 200
+}
+infix operator % {
+  associativity left
+  precedence 200
+}
+
+infix operator + {
+  associativity left
+  precedence 190
+}
+infix operator - {
+  associativity left
+  precedence 190
+}
+
+infix operator << {
+  associativity none
+  precedence 180
+}
+infix operator >> {
+  associativity none
+  precedence 180
+}
+
+infix operator ... {
+  associativity none
+  precedence 175
+}
+
+infix operator < {
+  associativity none
+  precedence 170
+}
+infix operator <= {
+  associativity none
+  precedence 170
+}
+infix operator > {
+  associativity none
+  precedence 170
+}
+infix operator >= {
+  associativity none
+  precedence 170
+}
+
+infix operator == {
+  associativity none
+  precedence 160
+}
+infix operator != {
+  associativity none
+  precedence 160
+}
+
+func * (lhs: Int, rhs: Int) -> Int {
+  return Builtin.mul_Int32(lhs, rhs)
+  // CHECK: mul i32
+}
+func / (lhs: Int, rhs: Int) -> Int {
+  return Builtin.sdiv_Int32(lhs, rhs)
+  // CHECK: sdiv i32
+}
+func % (lhs: Int, rhs: Int) -> Int {
+  return Builtin.srem_Int32(lhs, rhs)
+  // CHECK: srem i32
+}
+func + (lhs: Int, rhs: Int) -> Int {
+  return Builtin.add_Int32(lhs, rhs)
+  // CHECK: add i32
+}
+func - (lhs: Int, rhs: Int) -> Int {
+  return Builtin.sub_Int32(lhs, rhs)
+  // CHECK: sub i32
+}
+// In C, 180 is <<, >>
+func < (lhs: Int, rhs: Int) -> Bool {
+  return Builtin.cmp_slt_Int32(lhs, rhs)
+  // CHECK: icmp slt i32
+}
+func > (lhs: Int, rhs: Int) -> Bool {
+  return Builtin.cmp_sgt_Int32(lhs, rhs)
+  // CHECK: icmp sgt i32
+}
+func <=(lhs: Int, rhs: Int) -> Bool {
+  return Builtin.cmp_sle_Int32(lhs, rhs)
+  // CHECK: icmp sle i32
+}
+func >=(lhs: Int, rhs: Int) -> Bool {
+  return Builtin.cmp_sge_Int32(lhs, rhs)
+  // CHECK: icmp sge i32
+}
+func ==(lhs: Int, rhs: Int) -> Bool {
+  return Builtin.cmp_eq_Int32(lhs, rhs)
+  // CHECK: icmp eq i32
+}
+func !=(lhs: Int, rhs: Int) -> Bool {
+  return Builtin.cmp_ne_Int32(lhs, rhs)
+  // CHECK: icmp ne i32
+}
+
+func gepRaw_test(_ ptr: Builtin.RawPointer, offset: Builtin.Int64)
+   -> Builtin.RawPointer {
+  return Builtin.gepRaw_Int64(ptr, offset)
+  // CHECK: getelementptr inbounds i8, i8*
+}
+
+// CHECK: define hidden {{.*}}i64 @"$S8builtins9load_test{{[_0-9a-zA-Z]*}}F"
+func load_test(_ ptr: Builtin.RawPointer) -> Builtin.Int64 {
+  // CHECK: [[CASTPTR:%.*]] = bitcast i8* [[PTR:%.*]] to i64*
+  // CHECK-NEXT: load i64, i64* [[CASTPTR]]
+  // CHECK: ret
+  return Builtin.load(ptr)
+}
+
+// CHECK: define hidden {{.*}}i64 @"$S8builtins13load_raw_test{{[_0-9a-zA-Z]*}}F"
+func load_raw_test(_ ptr: Builtin.RawPointer) -> Builtin.Int64 {
+  // CHECK: [[CASTPTR:%.*]] = bitcast i8* [[PTR:%.*]] to i64*
+  // CHECK-NEXT: load i64, i64* [[CASTPTR]]
+  // CHECK: ret
+  return Builtin.loadRaw(ptr)
+}
+
+// CHECK: define hidden {{.*}}void @"$S8builtins11assign_test{{[_0-9a-zA-Z]*}}F"
+func assign_test(_ value: Builtin.Int64, ptr: Builtin.RawPointer) {
+  Builtin.assign(value, ptr)
+  // CHECK: ret
+}
+
+// CHECK: define hidden {{.*}}%swift.refcounted* @"$S8builtins16load_object_test{{[_0-9a-zA-Z]*}}F"
+func load_object_test(_ ptr: Builtin.RawPointer) -> Builtin.NativeObject {
+  // CHECK: [[T0:%.*]] = load [[REFCOUNT]]*, [[REFCOUNT]]**
+  // CHECK: call [[REFCOUNT]]* @swift_retain([[REFCOUNT]]* returned [[T0]])
+  // CHECK: ret [[REFCOUNT]]* [[T0]]
+  return Builtin.load(ptr)
+}
+
+// CHECK: define hidden {{.*}}%swift.refcounted* @"$S8builtins20load_raw_object_test{{[_0-9a-zA-Z]*}}F"
+func load_raw_object_test(_ ptr: Builtin.RawPointer) -> Builtin.NativeObject {
+  // CHECK: [[T0:%.*]] = load [[REFCOUNT]]*, [[REFCOUNT]]**
+  // CHECK: call [[REFCOUNT]]* @swift_retain([[REFCOUNT]]* returned [[T0]])
+  // CHECK: ret [[REFCOUNT]]* [[T0]]
+  return Builtin.loadRaw(ptr)
+}
+
+// CHECK: define hidden {{.*}}void @"$S8builtins18assign_object_test{{[_0-9a-zA-Z]*}}F"
+func assign_object_test(_ value: Builtin.NativeObject, ptr: Builtin.RawPointer) {
+  Builtin.assign(value, ptr)
+}
+
+// CHECK: define hidden {{.*}}void @"$S8builtins16init_object_test{{[_0-9a-zA-Z]*}}F"
+func init_object_test(_ value: Builtin.NativeObject, ptr: Builtin.RawPointer) {
+  // CHECK: [[DEST:%.*]] = bitcast i8* {{%.*}} to [[REFCOUNT]]**
+  // CHECK-NEXT: call [[REFCOUNT]]* @swift_retain([[REFCOUNT]]* returned [[SRC:%.*]])
+  // CHECK-NEXT: store [[REFCOUNT]]* [[SRC]], [[REFCOUNT]]** [[DEST]]
+  Builtin.initialize(value, ptr)
+}
+
+func cast_test(_ ptr: inout Builtin.RawPointer, i8: inout Builtin.Int8,
+               i64: inout Builtin.Int64, f: inout Builtin.FPIEEE32,
+               d: inout Builtin.FPIEEE64
+) {
+  // CHECK: cast_test
+
+  i8 = Builtin.trunc_Int64_Int8(i64)    // CHECK: trunc
+  i64 = Builtin.zext_Int8_Int64(i8)     // CHECK: zext
+  i64 = Builtin.sext_Int8_Int64(i8)     // CHECK: sext
+  i64 = Builtin.ptrtoint_Int64(ptr)     // CHECK: ptrtoint
+  ptr = Builtin.inttoptr_Int64(i64)     // CHECK: inttoptr
+  i64 = Builtin.fptoui_FPIEEE64_Int64(d) // CHECK: fptoui
+  i64 = Builtin.fptosi_FPIEEE64_Int64(d) // CHECK: fptosi
+  d = Builtin.uitofp_Int64_FPIEEE64(i64) // CHECK: uitofp
+  d = Builtin.sitofp_Int64_FPIEEE64(i64) // CHECK: sitofp
+  d = Builtin.fpext_FPIEEE32_FPIEEE64(f) // CHECK: fpext
+  f = Builtin.fptrunc_FPIEEE64_FPIEEE32(d) // CHECK: fptrunc
+  i64 = Builtin.bitcast_FPIEEE64_Int64(d)   // CHECK: bitcast
+  d = Builtin.bitcast_Int64_FPIEEE64(i64)   // CHECK: bitcast
+}
+
+func intrinsic_test(_ i32: inout Builtin.Int32, i16: inout Builtin.Int16) {
+  i32 = Builtin.int_bswap_Int32(i32) // CHECK: llvm.bswap.i32(
+
+  i16 = Builtin.int_bswap_Int16(i16) // CHECK: llvm.bswap.i16(
+  
+  var x = Builtin.int_sadd_with_overflow_Int16(i16, i16) // CHECK: call { i16, i1 } @llvm.sadd.with.overflow.i16(
+  
+  Builtin.int_trap() // CHECK: llvm.trap()
+}
+
+// CHECK: define hidden {{.*}}void @"$S8builtins19sizeof_alignof_testyyF"()
+func sizeof_alignof_test() {
+  // CHECK: store i64 4, i64*
+  var xs = Builtin.sizeof(Int.self) 
+  // CHECK: store i64 4, i64*
+  var xa = Builtin.alignof(Int.self) 
+  // CHECK: store i64 1, i64*
+  var ys = Builtin.sizeof(Bool.self) 
+  // CHECK: store i64 1, i64*
+  var ya = Builtin.alignof(Bool.self) 
+
+}
+
+// CHECK: define hidden {{.*}}void @"$S8builtins27generic_sizeof_alignof_testyyxlF"
+func generic_sizeof_alignof_test<T>(_: T) {
+  // CHECK:      [[T0:%.*]] = getelementptr inbounds i8*, i8** [[T:%.*]], i32 9
+  // CHECK-NEXT: [[T1:%.*]] = load i8*, i8** [[T0]]
+  // CHECK-NEXT: [[SIZE:%.*]] = ptrtoint i8* [[T1]] to i64
+  // CHECK-NEXT: store i64 [[SIZE]], i64* [[S:%.*]]
+  var s = Builtin.sizeof(T.self)
+  // CHECK: [[T0:%.*]] = getelementptr inbounds i8*, i8** [[T:%.*]], i32 10
+  // CHECK-NEXT: [[T1:%.*]] = load i8*, i8** [[T0]]
+  // CHECK-NEXT: [[T2:%.*]] = ptrtoint i8* [[T1]] to i64
+  // CHECK-NEXT: [[T3:%.*]] = and i64 [[T2]], 65535
+  // CHECK-NEXT: [[ALIGN:%.*]] = add i64 [[T3]], 1
+  // CHECK-NEXT: store i64 [[ALIGN]], i64* [[A:%.*]]
+  var a = Builtin.alignof(T.self)
+}
+
+// CHECK: define hidden {{.*}}void @"$S8builtins21generic_strideof_testyyxlF"
+func generic_strideof_test<T>(_: T) {
+  // CHECK:      [[T0:%.*]] = getelementptr inbounds i8*, i8** [[T:%.*]], i32 11
+  // CHECK-NEXT: [[T1:%.*]] = load i8*, i8** [[T0]]
+  // CHECK-NEXT: [[STRIDE:%.*]] = ptrtoint i8* [[T1]] to i64
+  // CHECK-NEXT: store i64 [[STRIDE]], i64* [[S:%.*]]
+  var s = Builtin.strideof(T.self)
+}
+
+class X {}
+
+class Y {}
+func move(_ ptr: Builtin.RawPointer) {
+  var temp : Y = Builtin.take(ptr)
+  // CHECK:      define hidden {{.*}}void @"$S8builtins4move{{[_0-9a-zA-Z]*}}F"
+  // CHECK:        [[SRC:%.*]] = bitcast i8* {{%.*}} to [[Y]]**
+  // CHECK-NEXT:   [[VAL:%.*]] = load [[Y]]*, [[Y]]** [[SRC]]
+  // CHECK-NEXT:   store [[Y]]* [[VAL]], [[Y]]** {{%.*}}
+}
+
+func allocDealloc(_ size: Builtin.Word, align: Builtin.Word) {
+  var ptr = Builtin.allocRaw(size, align)
+  Builtin.deallocRaw(ptr, size, align)
+}
+
+func fence_test() {
+  // CHECK: fence acquire
+  Builtin.fence_acquire()
+
+  // CHECK: fence syncscope("singlethread") acq_rel
+  Builtin.fence_acqrel_singlethread()
+}
+
+func cmpxchg_test(_ ptr: Builtin.RawPointer, a: Builtin.Int32, b: Builtin.Int32) {
+  // rdar://12939803 - ER: support atomic cmpxchg/xchg with pointers
+
+  // CHECK: [[Z_RES:%.*]] = cmpxchg i32* {{.*}}, i32 {{.*}}, i32 {{.*}} acquire acquire
+  // CHECK: [[Z_VAL:%.*]] = extractvalue { i32, i1 } [[Z_RES]], 0
+  // CHECK: [[Z_SUCCESS:%.*]] = extractvalue { i32, i1 } [[Z_RES]], 1
+  // CHECK: store i32 [[Z_VAL]], i32* {{.*}}, align 4
+  // CHECK: store i1 [[Z_SUCCESS]], i1* {{.*}}, align 1
+  var (z, zSuccess) = Builtin.cmpxchg_acquire_acquire_Int32(ptr, a, b)
+
+  // CHECK: [[Y_RES:%.*]] = cmpxchg volatile i32* {{.*}}, i32 {{.*}}, i32 {{.*}} monotonic monotonic
+  // CHECK: [[Y_VAL:%.*]] = extractvalue { i32, i1 } [[Y_RES]], 0
+  // CHECK: [[Y_SUCCESS:%.*]] = extractvalue { i32, i1 } [[Y_RES]], 1
+  // CHECK: store i32 [[Y_VAL]], i32* {{.*}}, align 4
+  // CHECK: store i1 [[Y_SUCCESS]], i1* {{.*}}, align 1
+  var (y, ySuccess) = Builtin.cmpxchg_monotonic_monotonic_volatile_Int32(ptr, a, b)
+
+  // CHECK: [[X_RES:%.*]] = cmpxchg volatile i32* {{.*}}, i32 {{.*}}, i32 {{.*}} syncscope("singlethread") acquire monotonic
+  // CHECK: [[X_VAL:%.*]] = extractvalue { i32, i1 } [[X_RES]], 0
+  // CHECK: [[X_SUCCESS:%.*]] = extractvalue { i32, i1 } [[X_RES]], 1
+  // CHECK: store i32 [[X_VAL]], i32* {{.*}}, align 4
+  // CHECK: store i1 [[X_SUCCESS]], i1* {{.*}}, align 1
+  var (x, xSuccess) = Builtin.cmpxchg_acquire_monotonic_volatile_singlethread_Int32(ptr, a, b)
+
+  // CHECK: [[W_RES:%.*]] = cmpxchg volatile i64* {{.*}}, i64 {{.*}}, i64 {{.*}} seq_cst seq_cst
+  // CHECK: [[W_VAL:%.*]] = extractvalue { i64, i1 } [[W_RES]], 0
+  // CHECK: [[W_SUCCESS:%.*]] = extractvalue { i64, i1 } [[W_RES]], 1
+  // CHECK: [[W_VAL_PTR:%.*]] = inttoptr i64 [[W_VAL]] to i8*
+  // CHECK: store i8* [[W_VAL_PTR]], i8** {{.*}}, align 8
+  // CHECK: store i1 [[W_SUCCESS]], i1* {{.*}}, align 1
+  var (w, wSuccess) = Builtin.cmpxchg_seqcst_seqcst_volatile_singlethread_RawPointer(ptr, ptr, ptr)
+
+  // CHECK: [[V_RES:%.*]] = cmpxchg weak volatile i64* {{.*}}, i64 {{.*}}, i64 {{.*}} seq_cst seq_cst
+  // CHECK: [[V_VAL:%.*]] = extractvalue { i64, i1 } [[V_RES]], 0
+  // CHECK: [[V_SUCCESS:%.*]] = extractvalue { i64, i1 } [[V_RES]], 1
+  // CHECK: [[V_VAL_PTR:%.*]] = inttoptr i64 [[V_VAL]] to i8*
+  // CHECK: store i8* [[V_VAL_PTR]], i8** {{.*}}, align 8
+  // CHECK: store i1 [[V_SUCCESS]], i1* {{.*}}, align 1
+  var (v, vSuccess) = Builtin.cmpxchg_seqcst_seqcst_weak_volatile_singlethread_RawPointer(ptr, ptr, ptr)
+}
+
+func atomicrmw_test(_ ptr: Builtin.RawPointer, a: Builtin.Int32,
+                    ptr2: Builtin.RawPointer) {
+  // CHECK: atomicrmw add i32* {{.*}}, i32 {{.*}} acquire
+  var z = Builtin.atomicrmw_add_acquire_Int32(ptr, a)
+
+  // CHECK: atomicrmw volatile max i32* {{.*}}, i32 {{.*}} monotonic
+  var y = Builtin.atomicrmw_max_monotonic_volatile_Int32(ptr, a)
+  
+  // CHECK: atomicrmw volatile xchg i32* {{.*}}, i32 {{.*}} syncscope("singlethread") acquire
+  var x = Builtin.atomicrmw_xchg_acquire_volatile_singlethread_Int32(ptr, a)
+  
+  // rdar://12939803 - ER: support atomic cmpxchg/xchg with pointers
+  // CHECK: atomicrmw volatile xchg i64* {{.*}}, i64 {{.*}} syncscope("singlethread") acquire
+  var w = Builtin.atomicrmw_xchg_acquire_volatile_singlethread_RawPointer(ptr, ptr2)
+
+}
+
+func addressof_test(_ a: inout Int, b: inout Bool) {
+  // CHECK: bitcast i32* {{.*}} to i8*
+  var ap : Builtin.RawPointer = Builtin.addressof(&a)
+  // CHECK: bitcast i1* {{.*}} to i8*
+  var bp : Builtin.RawPointer = Builtin.addressof(&b)
+}
+
+func fneg_test(_ half: Builtin.FPIEEE16,
+               single: Builtin.FPIEEE32,
+               double: Builtin.FPIEEE64)
+  -> (Builtin.FPIEEE16, Builtin.FPIEEE32, Builtin.FPIEEE64)
+{
+  // CHECK: fsub half 0xH8000, {{%.*}}
+  // CHECK: fsub float -0.000000e+00, {{%.*}}
+  // CHECK: fsub double -0.000000e+00, {{%.*}}
+  return (Builtin.fneg_FPIEEE16(half),
+          Builtin.fneg_FPIEEE32(single),
+          Builtin.fneg_FPIEEE64(double))
+}
+
+// The call to the builtins should get removed before we reach IRGen.
+func testStaticReport(_ b: Bool, ptr: Builtin.RawPointer) -> () {
+  Builtin.staticReport(b, b, ptr);
+  return Builtin.staticReport(b, b, ptr);
+}
+
+// CHECK-LABEL: define hidden {{.*}}void @"$S8builtins12testCondFail{{[_0-9a-zA-Z]*}}F"(i1, i1)
+func testCondFail(_ b: Bool, c: Bool) {
+  // CHECK: br i1 %0, label %[[FAIL:.*]], label %[[CONT:.*]]
+  Builtin.condfail(b)
+  // CHECK: <label>:[[CONT]]
+  // CHECK: br i1 %1, label %[[FAIL2:.*]], label %[[CONT:.*]]
+  Builtin.condfail(c)
+  // CHECK: <label>:[[CONT]]
+  // CHECK: ret void
+
+  // CHECK: <label>:[[FAIL]]
+  // CHECK: call void @llvm.trap()
+  // CHECK: unreachable
+
+  // CHECK: <label>:[[FAIL2]]
+  // CHECK: call void @llvm.trap()
+  // CHECK: unreachable
+}
+
+// CHECK-LABEL: define hidden {{.*}}void @"$S8builtins8testOnce{{[_0-9a-zA-Z]*}}F"(i8*, i8*) {{.*}} {
+// CHECK:         [[PRED_PTR:%.*]] = bitcast i8* %0 to [[WORD:i64|i32]]*
+// CHECK-objc:    [[PRED:%.*]] = load {{.*}} [[WORD]]* [[PRED_PTR]]
+// CHECK-objc:    [[IS_DONE:%.*]] = icmp eq [[WORD]] [[PRED]], -1
+// CHECK-objc:    br i1 [[IS_DONE]], label %[[DONE:.*]], label %[[NOT_DONE:.*]]
+// CHECK-objc:  [[NOT_DONE]]:
+// CHECK:         call void @swift_once([[WORD]]* [[PRED_PTR]], i8* %1, i8* undef)
+// CHECK-objc:    br label %[[DONE]]
+// CHECK-objc:  [[DONE]]:
+// CHECK-objc:    [[PRED:%.*]] = load {{.*}} [[WORD]]* [[PRED_PTR]]
+// CHECK-objc:    [[IS_DONE:%.*]] = icmp eq [[WORD]] [[PRED]], -1
+// CHECK-objc:    call void @llvm.assume(i1 [[IS_DONE]])
+
+func testOnce(_ p: Builtin.RawPointer, f: @escaping @convention(c) () -> ()) {
+  Builtin.once(p, f)
+}
+
+// CHECK-LABEL: define hidden {{.*}}void @"$S8builtins19testOnceWithContext{{[_0-9a-zA-Z]*}}F"(i8*, i8*, i8*) {{.*}} {
+// CHECK:         [[PRED_PTR:%.*]] = bitcast i8* %0 to [[WORD:i64|i32]]*
+// CHECK-objc:    [[PRED:%.*]] = load {{.*}} [[WORD]]* [[PRED_PTR]]
+// CHECK-objc:    [[IS_DONE:%.*]] = icmp eq [[WORD]] [[PRED]], -1
+// CHECK-objc:    br i1 [[IS_DONE]], label %[[DONE:.*]], label %[[NOT_DONE:.*]]
+// CHECK-objc:  [[NOT_DONE]]:
+// CHECK:         call void @swift_once([[WORD]]* [[PRED_PTR]], i8* %1, i8* %2)
+// CHECK-objc:    br label %[[DONE]]
+// CHECK-objc:  [[DONE]]:
+// CHECK-objc:    [[PRED:%.*]] = load {{.*}} [[WORD]]* [[PRED_PTR]]
+// CHECK-objc:    [[IS_DONE:%.*]] = icmp eq [[WORD]] [[PRED]], -1
+// CHECK-objc:    call void @llvm.assume(i1 [[IS_DONE]])
+func testOnceWithContext(_ p: Builtin.RawPointer, f: @escaping @convention(c) (Builtin.RawPointer) -> (), k: Builtin.RawPointer) {
+  Builtin.onceWithContext(p, f, k)
+}
+
+class C {}
+struct S {}
+@objc class O {}
+@objc protocol OP1 {}
+@objc protocol OP2 {}
+protocol P {}
+
+// CHECK-LABEL: define hidden {{.*}}void @"$S8builtins10canBeClass{{[_0-9a-zA-Z]*}}F"
+func canBeClass<T>(_ f: @escaping (Builtin.Int8) -> (), _: T) {
+  // CHECK: call {{.*}}void {{%.*}}(i8 1
+  f(Builtin.canBeClass(O.self))
+  // CHECK: call {{.*}}void {{%.*}}(i8 1
+  f(Builtin.canBeClass(OP1.self))
+  typealias ObjCCompo = OP1 & OP2
+  // CHECK: call {{.*}}void {{%.*}}(i8 1
+  f(Builtin.canBeClass(ObjCCompo.self))
+
+  // CHECK: call {{.*}}void {{%.*}}(i8 0
+  f(Builtin.canBeClass(S.self))
+  // CHECK: call {{.*}}void {{%.*}}(i8 1
+  f(Builtin.canBeClass(C.self))
+  // CHECK: call {{.*}}void {{%.*}}(i8 0
+  f(Builtin.canBeClass(P.self))
+  typealias MixedCompo = OP1 & P
+  // CHECK: call {{.*}}void {{%.*}}(i8 0
+  f(Builtin.canBeClass(MixedCompo.self))
+
+  // CHECK: call {{.*}}void {{%.*}}(i8 2
+  f(Builtin.canBeClass(T.self))
+}
+
+// CHECK-LABEL: define hidden {{.*}}void @"$S8builtins15destroyPODArray{{[_0-9a-zA-Z]*}}F"(i8*, i64)
+// CHECK-NOT:   loop:
+// CHECK:         ret void
+func destroyPODArray(_ array: Builtin.RawPointer, count: Builtin.Word) {
+  Builtin.destroyArray(Int.self, array, count)
+}
+
+// CHECK-LABEL: define hidden {{.*}}void @"$S8builtins18destroyNonPODArray{{[_0-9a-zA-Z]*}}F"(i8*, i64) {{.*}} {
+// CHECK-NOT:       loop:
+// CHECK:       call void @swift_arrayDestroy(
+func destroyNonPODArray(_ array: Builtin.RawPointer, count: Builtin.Word) {
+  Builtin.destroyArray(C.self, array, count)
+}
+
+// CHECK-LABEL: define hidden {{.*}}void @"$S8builtins15destroyGenArray_5count_yBp_BwxtlF"(i8*, i64, %swift.opaque* noalias nocapture, %swift.type* %T)
+// CHECK-NOT:   loop:
+// CHECK:         call void @swift_arrayDestroy
+func destroyGenArray<T>(_ array: Builtin.RawPointer, count: Builtin.Word, _: T) {
+  Builtin.destroyArray(T.self, array, count)
+}
+
+
+// CHECK-LABEL: define hidden {{.*}}void @"$S8builtins12copyPODArray{{[_0-9a-zA-Z]*}}F"(i8*, i8*, i64)
+// check:         mul nuw i64 4, %2
+// check:         call void @llvm.memcpy.p0i8.p0i8.i64(i8* {{.*}}, i8* {{.*}}, i64 {{.*}}, i32 4, i1 false)
+// check:         mul nuw i64 4, %2
+// check:         call void @llvm.memmove.p0i8.p0i8.i64(i8* {{.*}}, i8* {{.*}}, i64 {{.*}}, i32 4, i1 false)
+// check:         mul nuw i64 4, %2
+// check:         call void @llvm.memmove.p0i8.p0i8.i64(i8* {{.*}}, i8* {{.*}}, i64 {{.*}}, i32 4, i1 false)
+// check:         mul nuw i64 4, %2
+// check:         call void @llvm.memcpy.p0i8.p0i8.i64(i8* {{.*}}, i8* {{.*}}, i64 {{.*}}, i32 4, i1 false)
+// check:         mul nuw i64 4, %2
+// check:         call void @llvm.memmove.p0i8.p0i8.i64(i8* {{.*}}, i8* {{.*}}, i64 {{.*}}, i32 4, i1 false)
+// check:         mul nuw i64 4, %2
+// check:         call void @llvm.memmove.p0i8.p0i8.i64(i8* {{.*}}, i8* {{.*}}, i64 {{.*}}, i32 4, i1 false)
+// check:         mul nuw i64 4, %2
+// check:         call void @llvm.memcpy.p0i8.p0i8.i64(i8* {{.*}}, i8* {{.*}}, i64 {{.*}}, i32 4, i1 false)
+func copyPODArray(_ dest: Builtin.RawPointer, src: Builtin.RawPointer, count: Builtin.Word) {
+  Builtin.copyArray(Int.self, dest, src, count)
+  Builtin.takeArrayFrontToBack(Int.self, dest, src, count)
+  Builtin.takeArrayBackToFront(Int.self, dest, src, count)
+  Builtin.assignCopyArrayNoAlias(Int.self, dest, src, count)
+  Builtin.assignCopyArrayFrontToBack(Int.self, dest, src, count)
+  Builtin.assignCopyArrayBackToFront(Int.self, dest, src, count)
+  Builtin.assignTakeArray(Int.self, dest, src, count)
+}
+
+
+// CHECK-LABEL: define hidden {{.*}}void @"$S8builtins11copyBTArray{{[_0-9a-zA-Z]*}}F"(i8*, i8*, i64) {{.*}} {
+// CHECK-NOT:       loop:
+// CHECK:         call void @swift_arrayInitWithCopy
+// CHECK:         mul nuw i64 8, %2
+// CHECK:         call void @llvm.memmove.p0i8.p0i8.i64(i8* {{.*}}, i8* {{.*}}, i64 {{.*}}, i32 8, i1 false)
+// CHECK:         mul nuw i64 8, %2
+// CHECK:         call void @llvm.memmove.p0i8.p0i8.i64(i8* {{.*}}, i8* {{.*}}, i64 {{.*}}, i32 8, i1 false)
+// CHECK:         call void @swift_arrayAssignWithCopyNoAlias(
+// CHECK:         call void @swift_arrayAssignWithCopyFrontToBack(
+// CHECK:         call void @swift_arrayAssignWithCopyBackToFront(
+// CHECK:         call void @swift_arrayAssignWithTake(
+func copyBTArray(_ dest: Builtin.RawPointer, src: Builtin.RawPointer, count: Builtin.Word) {
+  Builtin.copyArray(C.self, dest, src, count)
+  Builtin.takeArrayFrontToBack(C.self, dest, src, count)
+  Builtin.takeArrayBackToFront(C.self, dest, src, count)
+  Builtin.assignCopyArrayNoAlias(C.self, dest, src, count)
+  Builtin.assignCopyArrayFrontToBack(C.self, dest, src, count)
+  Builtin.assignCopyArrayBackToFront(C.self, dest, src, count)
+  Builtin.assignTakeArray(C.self, dest, src, count)
+}
+
+struct W { weak var c: C? }
+
+// CHECK-LABEL: define hidden {{.*}}void @"$S8builtins15copyNonPODArray{{[_0-9a-zA-Z]*}}F"(i8*, i8*, i64) {{.*}} {
+// CHECK-NOT:       loop:
+// CHECK:         call void @swift_arrayInitWithCopy(
+// CHECK-NOT:       loop{{.*}}:
+// CHECK:         call void @swift_arrayInitWithTakeFrontToBack(
+// CHECK-NOT:       loop{{.*}}:
+// CHECK:          call void @swift_arrayInitWithTakeBackToFront(
+// CHECK:         call void @swift_arrayAssignWithCopyNoAlias(
+// CHECK:         call void @swift_arrayAssignWithCopyFrontToBack(
+// CHECK:         call void @swift_arrayAssignWithCopyBackToFront(
+// CHECK:         call void @swift_arrayAssignWithTake(
+func copyNonPODArray(_ dest: Builtin.RawPointer, src: Builtin.RawPointer, count: Builtin.Word) {
+  Builtin.copyArray(W.self, dest, src, count)
+  Builtin.takeArrayFrontToBack(W.self, dest, src, count)
+  Builtin.takeArrayBackToFront(W.self, dest, src, count)
+  Builtin.assignCopyArrayNoAlias(W.self, dest, src, count)
+  Builtin.assignCopyArrayFrontToBack(W.self, dest, src, count)
+  Builtin.assignCopyArrayBackToFront(W.self, dest, src, count)
+  Builtin.assignTakeArray(W.self, dest, src, count)
+}
+
+// CHECK-LABEL: define hidden {{.*}}void @"$S8builtins12copyGenArray{{[_0-9a-zA-Z]*}}F"(i8*, i8*, i64, %swift.opaque* noalias nocapture, %swift.type* %T)
+// CHECK-NOT:   loop:
+// CHECK:        call void @swift_arrayInitWithCopy
+// CHECK-NOT:   loop:
+// CHECK:        call void @swift_arrayInitWithTakeFrontToBack(
+// CHECK-NOT:   loop:
+// CHECK:        call void @swift_arrayInitWithTakeBackToFront(
+// CHECK:        call void @swift_arrayAssignWithCopyNoAlias(
+// CHECK:        call void @swift_arrayAssignWithCopyFrontToBack(
+// CHECK:        call void @swift_arrayAssignWithCopyBackToFront(
+// CHECK:        call void @swift_arrayAssignWithTake(
+func copyGenArray<T>(_ dest: Builtin.RawPointer, src: Builtin.RawPointer, count: Builtin.Word, _: T) {
+  Builtin.copyArray(T.self, dest, src, count)
+  Builtin.takeArrayFrontToBack(T.self, dest, src, count)
+  Builtin.takeArrayBackToFront(T.self, dest, src, count)
+  Builtin.assignCopyArrayNoAlias(T.self, dest, src, count)
+  Builtin.assignCopyArrayFrontToBack(T.self, dest, src, count)
+  Builtin.assignCopyArrayBackToFront(T.self, dest, src, count)
+  Builtin.assignTakeArray(T.self, dest, src, count)
+}
+
+// CHECK-LABEL: define hidden {{.*}}void @"$S8builtins24conditionallyUnreachableyyF"
+// CHECK-NEXT:  entry
+// CHECK-NEXT:    unreachable
+func conditionallyUnreachable() {
+  Builtin.conditionallyUnreachable()
+}
+
+struct Abc {
+	var value : Builtin.Word
+}
+
+// CHECK-LABEL: define hidden {{.*}}@"$S8builtins22assumeNonNegative_testyBwAA3AbcVzF"
+func assumeNonNegative_test(_ x: inout Abc) -> Builtin.Word {
+  // CHECK: load {{.*}}, !range ![[R:[0-9]+]]
+  return Builtin.assumeNonNegative_Word(x.value)
+}
+
+@inline(never)
+func return_word(_ x: Builtin.Word) -> Builtin.Word {
+	return x
+}
+
+// CHECK-LABEL: define hidden {{.*}}@"$S8builtins23assumeNonNegative_test2yBwBwF"
+func assumeNonNegative_test2(_ x: Builtin.Word) -> Builtin.Word {
+  // CHECK: call {{.*}}, !range ![[R]]
+  return Builtin.assumeNonNegative_Word(return_word(x))
+}
+
+struct Empty {}
+struct Pair { var i: Int, b: Bool }
+
+// CHECK-LABEL: define hidden {{.*}}i64 @"$S8builtins15zeroInitializerAA5EmptyV_AA4PairVtyF"() {{.*}} {
+// CHECK:  [[ALLOCA:%.*]] = alloca { i64 }
+// CHECK:  bitcast
+// CHECK:  lifetime.start
+// CHECK:  [[EMPTYPAIR:%.*]] = bitcast { i64 }* [[ALLOCA]]
+// CHECK:  [[PAIR:%.*]] = getelementptr inbounds {{.*}} [[EMPTYPAIR]], i32 0, i32 0
+// CHECK:  [[FLDI:%.*]] = getelementptr inbounds {{.*}} [[PAIR]], i32 0, i32 0
+// CHECK:  store i32 0, i32* [[FLDI]]
+// CHECK:  [[FLDB:%.*]] = getelementptr inbounds {{.*}} [[PAIR]], i32 0, i32 1
+// CHECK:  store i1 false, i1* [[FLDB]]
+// CHECK:  [[RET:%.*]] = getelementptr inbounds {{.*}} [[ALLOCA]], i32 0, i32 0
+// CHECK:  [[RES:%.*]] = load i64, i64* [[RET]]
+// CHECK:  ret i64 [[RES]]
+func zeroInitializer() -> (Empty, Pair) {
+  return (Builtin.zeroInitializer(), Builtin.zeroInitializer())
+}
+
+// CHECK-LABEL: define hidden {{.*}}i64 @"$S8builtins20zeroInitializerTupleAA5EmptyV_AA4PairVtyF"() {{.*}} {
+// CHECK:  [[ALLOCA:%.*]] = alloca { i64 }
+// CHECK:  bitcast
+// CHECK:  lifetime.start
+// CHECK:  [[EMPTYPAIR:%.*]] = bitcast { i64 }* [[ALLOCA]]
+// CHECK:  [[PAIR:%.*]] = getelementptr inbounds {{.*}} [[EMPTYPAIR]], i32 0, i32 0
+// CHECK:  [[FLDI:%.*]] = getelementptr inbounds {{.*}} [[PAIR]], i32 0, i32 0
+// CHECK:  store i32 0, i32* [[FLDI]]
+// CHECK:  [[FLDB:%.*]] = getelementptr inbounds {{.*}} [[PAIR]], i32 0, i32 1
+// CHECK:  store i1 false, i1* [[FLDB]]
+// CHECK:  [[RET:%.*]] = getelementptr inbounds {{.*}} [[ALLOCA]], i32 0, i32 0
+// CHECK:  [[RES:%.*]] = load i64, i64* [[RET]]
+// CHECK:  ret i64 [[RES]]
+func zeroInitializerTuple() -> (Empty, Pair) {
+  return Builtin.zeroInitializer()
+}
+
+// CHECK-LABEL: define hidden {{.*}}void @"$S8builtins20zeroInitializerEmptyyyF"() {{.*}} {
+// CHECK:         ret void
+func zeroInitializerEmpty() {
+  return Builtin.zeroInitializer()
+}
+
+// ----------------------------------------------------------------------------
+// isUnique variants
+// ----------------------------------------------------------------------------
+
+// CHECK: define hidden {{.*}}void @"$S8builtins26acceptsBuiltinNativeObjectyyBoSgzF"([[BUILTIN_NATIVE_OBJECT_TY:%.*]]* nocapture dereferenceable({{.*}})) {{.*}} {
+func acceptsBuiltinNativeObject(_ ref: inout Builtin.NativeObject?) {}
+
+// native
+// CHECK-LABEL: define hidden {{.*}}i1 @"$S8builtins8isUniqueyBi1_BoSgzF"({{%.*}}* nocapture dereferenceable({{.*}})) {{.*}} {
+// CHECK-NEXT: entry:
+// CHECK-NEXT: bitcast [[BUILTIN_NATIVE_OBJECT_TY]]* %0 to %swift.refcounted**
+// CHECK-NEXT: load %swift.refcounted*, %swift.refcounted** %1
+// CHECK-NEXT: call i1 @swift_isUniquelyReferenced_native(%swift.refcounted* %2)
+// CHECK-NEXT: ret i1 %3
+func isUnique(_ ref: inout Builtin.NativeObject?) -> Bool {
+  return Builtin.isUnique(&ref)
+}
+
+// native nonNull
+// CHECK-LABEL: define hidden {{.*}}i1 @"$S8builtins8isUniqueyBi1_BozF"(%swift.refcounted** nocapture dereferenceable({{.*}})) {{.*}} {
+// CHECK-NEXT: entry:
+// CHECK-NEXT: load %swift.refcounted*, %swift.refcounted** %0
+// CHECK-NEXT: call i1 @swift_isUniquelyReferenced_nonNull_native(%swift.refcounted* %1)
+// CHECK-NEXT: ret i1 %2
+func isUnique(_ ref: inout Builtin.NativeObject) -> Bool {
+  return Builtin.isUnique(&ref)
+}
+
+// native pinned
+// CHECK-LABEL: define hidden {{.*}}i1 @"$S8builtins16isUniqueOrPinnedyBi1_BoSgzF"({{%.*}}* nocapture dereferenceable({{.*}})) {{.*}} {
+// CHECK-NEXT: entry:
+// CHECK-NEXT: bitcast [[BUILTIN_NATIVE_OBJECT_TY]]* %0 to %swift.refcounted**
+// CHECK-NEXT: load %swift.refcounted*, %swift.refcounted** %1
+// CHECK-NEXT: call i1 @swift_isUniquelyReferencedOrPinned_native(%swift.refcounted* %2)
+// CHECK-NEXT: ret i1 %3
+func isUniqueOrPinned(_ ref: inout Builtin.NativeObject?) -> Bool {
+  return Builtin.isUniqueOrPinned(&ref)
+}
+
+// native pinned nonNull
+// CHECK-LABEL: define hidden {{.*}}i1 @"$S8builtins16isUniqueOrPinnedyBi1_BozF"(%swift.refcounted** nocapture dereferenceable({{.*}})) {{.*}} {
+// CHECK-NEXT: entry:
+// CHECK-NEXT: load %swift.refcounted*, %swift.refcounted** %0
+// CHECK-NEXT: call i1 @swift_isUniquelyReferencedOrPinned_nonNull_native(%swift.refcounted* %1)
+// CHECK-NEXT: ret i1 %2
+func isUniqueOrPinned(_ ref: inout Builtin.NativeObject) -> Bool {
+  return Builtin.isUniqueOrPinned(&ref)
+}
+
+// CHECK: define hidden {{.*}}void @"$S8builtins27acceptsBuiltinUnknownObjectyyBOSgzF"([[BUILTIN_UNKNOWN_OBJECT_TY:%.*]]* nocapture dereferenceable({{.*}})) {{.*}} {
+func acceptsBuiltinUnknownObject(_ ref: inout Builtin.UnknownObject?) {}
+
+// ObjC
+// CHECK-LABEL: define hidden {{.*}}i1 @"$S8builtins8isUniqueyBi1_BOSgzF"({{%.*}}* nocapture dereferenceable({{.*}})) {{.*}} {
+// CHECK-NEXT: entry:
+// CHECK-NEXT: bitcast [[BUILTIN_UNKNOWN_OBJECT_TY]]* %0 to [[UNKNOWN_OBJECT:%objc_object|%swift\.refcounted]]**
+// CHECK-NEXT: load [[UNKNOWN_OBJECT]]*, [[UNKNOWN_OBJECT]]** %1
+// CHECK-objc-NEXT: call i1 @swift_isUniquelyReferencedNonObjC([[UNKNOWN_OBJECT]]* %2)
+// CHECK-native-NEXT: call i1 @swift_isUniquelyReferenced_native([[UNKNOWN_OBJECT]]* %2)
+// CHECK-NEXT: ret i1 %3
+func isUnique(_ ref: inout Builtin.UnknownObject?) -> Bool {
+  return Builtin.isUnique(&ref)
+}
+
+// ObjC nonNull
+// CHECK-LABEL: define hidden {{.*}}i1 @"$S8builtins8isUniqueyBi1_BOzF"
+// CHECK-SAME:    ([[UNKNOWN_OBJECT]]** nocapture dereferenceable({{.*}})) {{.*}} {
+// CHECK-NEXT: entry:
+// CHECK-NEXT: load [[UNKNOWN_OBJECT]]*, [[UNKNOWN_OBJECT]]** %0
+// CHECK-objc-NEXT: call i1 @swift_isUniquelyReferencedNonObjC_nonNull([[UNKNOWN_OBJECT]]* %1)
+// CHECK-native-NEXT: call i1 @swift_isUniquelyReferenced_nonNull_native([[UNKNOWN_OBJECT]]* %1)
+// CHECK-NEXT: ret i1 %2
+func isUnique(_ ref: inout Builtin.UnknownObject) -> Bool {
+  return Builtin.isUnique(&ref)
+}
+
+// ObjC pinned nonNull
+// CHECK-LABEL: define hidden {{.*}}i1 @"$S8builtins16isUniqueOrPinnedyBi1_BOzF"
+// CHECK-SAME:    ([[UNKNOWN_OBJECT]]** nocapture dereferenceable({{.*}})) {{.*}} {
+// CHECK-NEXT: entry:
+// CHECK-NEXT: load [[UNKNOWN_OBJECT]]*, [[UNKNOWN_OBJECT]]** %0
+// CHECK-native-NEXT: call i1 @swift_isUniquelyReferencedOrPinned_nonNull_native([[UNKNOWN_OBJECT]]* %1)
+// CHECK-objc-NEXT: call i1 @swift_isUniquelyReferencedOrPinnedNonObjC_nonNull([[UNKNOWN_OBJECT]]* %1)
+// CHECK-NEXT: ret i1 %2
+func isUniqueOrPinned(_ ref: inout Builtin.UnknownObject) -> Bool {
+  return Builtin.isUniqueOrPinned(&ref)
+}
+
+// BridgeObject nonNull
+// CHECK-LABEL: define hidden {{.*}}i1 @"$S8builtins8isUniqueyBi1_BbzF"(%swift.bridge** nocapture dereferenceable({{.*}})) {{.*}} {
+// CHECK-NEXT: entry:
+// CHECK-NEXT: load %swift.bridge*, %swift.bridge** %0
+// CHECK-NEXT: call i1 @swift_isUniquelyReferencedNonObjC_nonNull_bridgeObject(%swift.bridge* %1)
+// CHECK-NEXT: ret i1 %2
+func isUnique(_ ref: inout Builtin.BridgeObject) -> Bool {
+  return Builtin.isUnique(&ref)
+}
+
+// Bridge pinned nonNull
+// CHECK-LABEL: define hidden {{.*}}i1 @"$S8builtins16isUniqueOrPinnedyBi1_BbzF"(%swift.bridge** nocapture dereferenceable({{.*}})) {{.*}} {
+// CHECK-NEXT: entry:
+// CHECK-NEXT: load %swift.bridge*, %swift.bridge** %0
+// CHECK-NEXT: call i1 @swift_isUniquelyReferencedOrPinnedNonObjC_nonNull_bridgeObject(%swift.bridge* %1)
+// CHECK-NEXT: ret i1 %2
+func isUniqueOrPinned(_ ref: inout Builtin.BridgeObject) -> Bool {
+  return Builtin.isUniqueOrPinned(&ref)
+}
+
+// BridgeObject nonNull
+// CHECK-LABEL: define hidden {{.*}}i1 @"$S8builtins15isUnique_nativeyBi1_BbzF"(%swift.bridge** nocapture dereferenceable({{.*}})) {{.*}} {
+// CHECK-NEXT: entry:
+// CHECK-NEXT: bitcast %swift.bridge** %0 to %swift.refcounted**
+// CHECK-NEXT: load %swift.refcounted*, %swift.refcounted** %1
+// CHECK-NEXT: call i1 @swift_isUniquelyReferenced_nonNull_native(%swift.refcounted* %2)
+// CHECK-NEXT: ret i1 %3
+func isUnique_native(_ ref: inout Builtin.BridgeObject) -> Bool {
+  return Builtin.isUnique_native(&ref)
+}
+
+// Bridge pinned nonNull
+// CHECK-LABEL: define hidden {{.*}}i1 @"$S8builtins23isUniqueOrPinned_nativeyBi1_BbzF"(%swift.bridge** nocapture dereferenceable({{.*}})) {{.*}} {
+// CHECK-NEXT: entry:
+// CHECK-NEXT: bitcast %swift.bridge** %0 to %swift.refcounted**
+// CHECK-NEXT: load %swift.refcounted*, %swift.refcounted** %1
+// CHECK-NEXT: call i1 @swift_isUniquelyReferencedOrPinned_nonNull_native(%swift.refcounted* %2)
+// CHECK-NEXT: ret i1 %3
+func isUniqueOrPinned_native(_ ref: inout Builtin.BridgeObject) -> Bool {
+  return Builtin.isUniqueOrPinned_native(&ref)
+}
+
+// ImplicitlyUnwrappedOptional argument to isUnique.
+// CHECK-LABEL: define hidden {{.*}}i1 @"$S8builtins11isUniqueIUOyBi1_BoSgzF"(%{{.*}}* nocapture dereferenceable({{.*}})) {{.*}} {
+// CHECK-NEXT: entry:
+// CHECK: call i1 @swift_isUniquelyReferenced_native(%swift.refcounted*
+// CHECK: ret i1
+func isUniqueIUO(_ ref: inout Builtin.NativeObject?) -> Bool {
+  var iuo : Builtin.NativeObject! = ref
+  return Builtin.isUnique(&iuo)
+}
+
+// CHECK-LABEL: define {{.*}} @{{.*}}generic_ispod_test
+func generic_ispod_test<T>(_: T) {
+  // CHECK:      [[T0:%.*]] = getelementptr inbounds i8*, i8** [[T:%.*]], i32 10
+  // CHECK-NEXT: [[T1:%.*]] = load i8*, i8** [[T0]]
+  // CHECK-NEXT: [[FLAGS:%.*]] = ptrtoint i8* [[T1]] to i64
+  // CHECK-NEXT: [[ISNOTPOD:%.*]] = and i64 [[FLAGS]], 65536
+  // CHECK-NEXT: [[ISPOD:%.*]] = icmp eq i64 [[ISNOTPOD]], 0
+  // CHECK-NEXT: store i1 [[ISPOD]], i1* [[S:%.*]]
+  var s = Builtin.ispod(T.self)
+}
+
+// CHECK-LABEL: define {{.*}} @{{.*}}ispod_test
+func ispod_test() {
+  // CHECK: store i1 true, i1*
+  // CHECK: store i1 false, i1*
+  var t = Builtin.ispod(Int.self)
+  var f = Builtin.ispod(Builtin.NativeObject)
+}
+
+// CHECK-LABEL: define {{.*}} @{{.*}}is_same_metatype
+func is_same_metatype_test(_ t1: Any.Type, _ t2: Any.Type) {
+  // CHECK: [[MT1_AS_PTR:%.*]] = bitcast %swift.type* %0 to i8*
+  // CHECK: [[MT2_AS_PTR:%.*]] = bitcast %swift.type* %1 to i8*
+  // CHECK: icmp eq i8* [[MT1_AS_PTR]], [[MT2_AS_PTR]]
+  var t = Builtin.is_same_metatype(t1, t2)
+}
+
+// CHECK-LABEL: define {{.*}} @{{.*}}generic_unsafeGuaranteed_test
+// CHECK:  call {{.*}}* @{{.*}}swift_{{.*}}etain({{.*}}* returned %0)
+// CHECK:  call void @{{.*}}swift_{{.*}}elease({{.*}}* %0)
+// CHECK:  ret {{.*}}* %0
+func generic_unsafeGuaranteed_test<T: AnyObject>(_ t : T) -> T {
+  let (g, _) = Builtin.unsafeGuaranteed(t)
+  return g
+}
+
+// CHECK-LABEL: define {{.*}} @{{.*}}unsafeGuaranteed_test
+// CHECK:  [[LOCAL:%.*]] = alloca %swift.refcounted*
+// CHECK:  call %swift.refcounted* @swift_retain(%swift.refcounted* returned %0)
+// CHECK:  store %swift.refcounted* %0, %swift.refcounted** [[LOCAL]]
+// CHECK:  call void @swift_release(%swift.refcounted* %0)
+// CHECK:  ret %swift.refcounted* %0
+func unsafeGuaranteed_test(_ x: Builtin.NativeObject) -> Builtin.NativeObject {
+  var (g,t) = Builtin.unsafeGuaranteed(x)
+  Builtin.unsafeGuaranteedEnd(t)
+  return g
+}
+
+// CHECK-LABEL: define {{.*}} @{{.*}}unsafeGuaranteedEnd_test
+// CHECK-NEXT: {{.*}}:
+// CHECK-NEXT: ret void
+func unsafeGuaranteedEnd_test(_ x: Builtin.Int8) {
+  Builtin.unsafeGuaranteedEnd(x)
+}
+
+// CHECK-LABEL: define {{.*}} @{{.*}}atomicload
+func atomicload(_ p: Builtin.RawPointer) {
+  // CHECK: [[A:%.*]] = load atomic i8*, i8** {{%.*}} unordered, align 8
+  let a: Builtin.RawPointer = Builtin.atomicload_unordered_RawPointer(p)
+  // CHECK: [[B:%.*]] = load atomic i32, i32* {{%.*}} syncscope("singlethread") monotonic, align 4
+  let b: Builtin.Int32 = Builtin.atomicload_monotonic_singlethread_Int32(p)
+  // CHECK: [[C:%.*]] = load atomic volatile i64, i64* {{%.*}} syncscope("singlethread") acquire, align 8
+  let c: Builtin.Int64 =
+    Builtin.atomicload_acquire_volatile_singlethread_Int64(p)
+  // CHECK: [[D0:%.*]] = load atomic volatile i32, i32* {{%.*}} seq_cst, align 4
+  // CHECK: [[D:%.*]] = bitcast i32 [[D0]] to float
+  let d: Builtin.FPIEEE32 = Builtin.atomicload_seqcst_volatile_FPIEEE32(p)
+
+  // CHECK: store atomic i8* [[A]], i8** {{%.*}} unordered, align 8
+  Builtin.atomicstore_unordered_RawPointer(p, a)
+  // CHECK: store atomic i32 [[B]], i32* {{%.*}} syncscope("singlethread") monotonic, align 4
+  Builtin.atomicstore_monotonic_singlethread_Int32(p, b)
+  // CHECK: store atomic volatile i64 [[C]], i64* {{%.*}} syncscope("singlethread") release, align 8
+  Builtin.atomicstore_release_volatile_singlethread_Int64(p, c)
+  // CHECK: [[D1:%.*]] = bitcast float [[D]] to i32
+  // CHECK: store atomic volatile i32 [[D1]], i32* {{.*}} seq_cst, align 4
+  Builtin.atomicstore_seqcst_volatile_FPIEEE32(p, d)
+}
+
+// CHECK-LABEL: define {{.*}} @"$S8builtins14stringObjectOryS2u_SutF"(i64, i64)
+// CHECK-NEXT: {{.*}}:
+// CHECK-NEXT: %2 = or i64 %0, %1
+// CHECK-NEXT: ret i64 %2
+func stringObjectOr(_ x: UInt, _ y: UInt) -> UInt {
+  return UInt(Builtin.stringObjectOr_Int64(
+  x._value, y._value))
+}
+
+func createInt(_ fn: () -> ()) throws {}
+// CHECK-LABEL: define {{.*}}testForceTry
+// CHECK: call swiftcc void @swift_unexpectedError(%swift.error*
+func testForceTry(_ fn: () -> ()) {
+  try! createInt(fn)
+}
+
+// CHECK-LABEL: declare swiftcc void @swift_unexpectedError(%swift.error*
+
+enum MyError : Error {
+  case A, B
+}
+
+throw MyError.A
+
+
+
+// CHECK: ![[R]] = !{i64 0, i64 9223372036854775807}
+
diff --git a/test/IRGen/plus_zero_class_bounded_generics.swift b/test/IRGen/plus_zero_class_bounded_generics.swift
new file mode 100644
index 0000000..304f545
--- /dev/null
+++ b/test/IRGen/plus_zero_class_bounded_generics.swift
@@ -0,0 +1,312 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -emit-ir -primary-file %s -disable-objc-attr-requires-foundation-module | %FileCheck %s
+
+// REQUIRES: CPU=x86_64
+// XFAIL: linux
+
+protocol ClassBound : class {
+  func classBoundMethod()
+}
+protocol ClassBound2 : class {
+  func classBoundMethod2()
+}
+protocol ClassBoundBinary : ClassBound {
+  func classBoundBinaryMethod(_ x: Self)
+}
+@objc protocol ObjCClassBound {
+  func objCClassBoundMethod()
+}
+@objc protocol ObjCClassBound2 {
+  func objCClassBoundMethod2()
+}
+protocol NotClassBound {
+  func notClassBoundMethod()
+  func notClassBoundBinaryMethod(_ x: Self)
+}
+
+struct ClassGenericFieldStruct<T:ClassBound> {
+  var x : Int
+  var y : T
+  var z : Int
+}
+
+struct ClassProtocolFieldStruct {
+  var x : Int
+  var y : ClassBound
+  var z : Int
+}
+
+class ClassGenericFieldClass<T:ClassBound> {
+  final var x : Int = 0
+  final var y : T
+  final var z : Int = 0
+
+  init(t: T) {
+    y = t
+  }
+}
+
+class ClassProtocolFieldClass {
+  var x : Int = 0
+  var y : ClassBound
+  var z : Int = 0
+
+  init(classBound cb: ClassBound) {
+    y = cb
+  }
+}
+
+// CHECK-DAG: %T22class_bounded_generics017ClassGenericFieldD0C = type <{ %swift.refcounted, %TSi, %objc_object*, %TSi }>
+// CHECK-DAG: %T22class_bounded_generics23ClassGenericFieldStructV = type <{ %TSi, %objc_object*, %TSi }>
+// CHECK-DAG: %T22class_bounded_generics24ClassProtocolFieldStructV = type <{ %TSi, %T22class_bounded_generics10ClassBoundP, %TSi }>
+
+// CHECK-LABEL: define hidden swiftcc %objc_object* @"$S22class_bounded_generics0a1_B10_archetype{{[_0-9a-zA-Z]*}}F"(%objc_object*, %swift.type* %T, i8** %T.ClassBound)
+func class_bounded_archetype<T : ClassBound>(_ x: T) -> T {
+  return x
+}
+
+class SomeClass {}
+class SomeSubclass : SomeClass {}
+
+// CHECK-LABEL: define hidden swiftcc %T22class_bounded_generics9SomeClassC* @"$S22class_bounded_generics011superclass_B10_archetype{{[_0-9a-zA-Z]*}}F"(%T22class_bounded_generics9SomeClassC*, %swift.type* %T)
+func superclass_bounded_archetype<T : SomeClass>(_ x: T) -> T {
+  return x
+}
+
+// CHECK-LABEL: define hidden swiftcc { %T22class_bounded_generics9SomeClassC*, %T22class_bounded_generics12SomeSubclassC* } @"$S22class_bounded_generics011superclass_B15_archetype_call{{[_0-9a-zA-Z]*}}F"(%T22class_bounded_generics9SomeClassC*, %T22class_bounded_generics12SomeSubclassC*)
+func superclass_bounded_archetype_call(_ x: SomeClass, y: SomeSubclass) -> (SomeClass, SomeSubclass) {
+  return (superclass_bounded_archetype(x),
+          superclass_bounded_archetype(y));
+  // CHECK: [[SOMECLASS_RESULT:%.*]] = call swiftcc %T22class_bounded_generics9SomeClassC* @"$S22class_bounded_generics011superclass_B10_archetype{{[_0-9a-zA-Z]*}}F"(%T22class_bounded_generics9SomeClassC* {{%.*}}, {{.*}})
+  // CHECK: [[SOMESUPERCLASS_IN:%.*]] = bitcast %T22class_bounded_generics12SomeSubclassC* {{%.*}} to %T22class_bounded_generics9SomeClassC*
+  // CHECK: [[SOMESUPERCLASS_RESULT:%.*]] = call swiftcc %T22class_bounded_generics9SomeClassC* @"$S22class_bounded_generics011superclass_B10_archetype{{[_0-9a-zA-Z]*}}F"(%T22class_bounded_generics9SomeClassC* [[SOMESUPERCLASS_IN]], {{.*}})
+  // CHECK: bitcast %T22class_bounded_generics9SomeClassC* [[SOMESUPERCLASS_RESULT]] to %T22class_bounded_generics12SomeSubclassC*
+}
+
+// CHECK-LABEL: define hidden swiftcc void @"$S22class_bounded_generics0a1_B17_archetype_method{{[_0-9a-zA-Z]*}}F"(%objc_object*, %objc_object*, %swift.type* %T, i8** %T.ClassBoundBinary)
+func class_bounded_archetype_method<T : ClassBoundBinary>(_ x: T, y: T) {
+  x.classBoundMethod()
+  // CHECK: [[INHERITED_GEP:%.*]] = getelementptr inbounds i8*, i8** %T.ClassBoundBinary, i32 1
+  // CHECK: [[INHERITED:%.*]] = load i8*, i8** [[INHERITED_GEP]]
+  // CHECK: [[INHERITED_WTBL:%.*]] = bitcast i8* [[INHERITED]] to i8**
+  // CHECK: [[WITNESS_GEP:%.*]] = getelementptr inbounds i8*, i8** [[INHERITED_WTBL]], i32 1
+  // CHECK: [[WITNESS:%.*]] = load i8*, i8** [[WITNESS_GEP]], align 8
+  // CHECK: [[WITNESS_FUNC:%.*]] = bitcast i8* [[WITNESS]] to void (%objc_object*, %swift.type*, i8**)
+  // CHECK: call swiftcc void [[WITNESS_FUNC]](%objc_object* swiftself %0, %swift.type* {{.*}}, i8** [[INHERITED_WTBL]])
+  x.classBoundBinaryMethod(y)
+  // CHECK-NOT: call %objc_object* @swift_unknownRetain(%objc_object* returned [[Y:%.*]])
+  // CHECK: [[WITNESS_ENTRY:%.*]] = getelementptr inbounds i8*, i8** %T.ClassBoundBinary, i32 2
+  // CHECK: [[WITNESS:%.*]] = load i8*, i8** [[WITNESS_ENTRY]], align 8
+  // CHECK: [[WITNESS_FUNC:%.*]] = bitcast i8* [[WITNESS]] to void (%objc_object*, %objc_object*, %swift.type*, i8**)
+  // CHECK: call swiftcc void [[WITNESS_FUNC]](%objc_object* %1, %objc_object* swiftself %0, %swift.type* %T, i8** %T.ClassBoundBinary)
+}
+
+// CHECK-LABEL: define hidden swiftcc { %objc_object*, %objc_object* } @"$S22class_bounded_generics0a1_B16_archetype_tuple{{[_0-9a-zA-Z]*}}F"(%objc_object*, %swift.type* %T, i8** %T.ClassBound)
+func class_bounded_archetype_tuple<T : ClassBound>(_ x: T) -> (T, T) {
+  return (x, x)
+}
+
+class ConcreteClass : ClassBoundBinary, NotClassBound {
+  func classBoundMethod() {}
+  func classBoundBinaryMethod(_ x: ConcreteClass) {}
+  func notClassBoundMethod() {}
+  func notClassBoundBinaryMethod(_ x: ConcreteClass) {}
+}
+
+// CHECK-LABEL: define hidden swiftcc %T22class_bounded_generics13ConcreteClassC* @"$S22class_bounded_generics05call_a1_B10_archetype{{[_0-9a-zA-Z]*}}F"(%T22class_bounded_generics13ConcreteClassC*) {{.*}} {
+func call_class_bounded_archetype(_ x: ConcreteClass) -> ConcreteClass {
+  return class_bounded_archetype(x)
+  // CHECK: [[IN:%.*]] = bitcast %T22class_bounded_generics13ConcreteClassC* {{%.*}} to %objc_object*
+  // CHECK: [[OUT_ORIG:%.*]] = call swiftcc %objc_object* @"$S22class_bounded_generics0a1_B10_archetype{{[_0-9a-zA-Z]*}}F"(%objc_object* [[IN]], {{.*}})
+  // CHECK: [[OUT:%.*]] = bitcast %objc_object* [[OUT_ORIG]] to %T22class_bounded_generics13ConcreteClassC*
+  // CHECK: ret %T22class_bounded_generics13ConcreteClassC* [[OUT]]
+}
+
+// CHECK: define hidden swiftcc void @"$S22class_bounded_generics04not_a1_B10_archetype{{[_0-9a-zA-Z]*}}F"(%swift.opaque* noalias nocapture sret, %swift.opaque* noalias nocapture, %swift.type* %T, i8** %T.NotClassBound)
+func not_class_bounded_archetype<T : NotClassBound>(_ x: T) -> T {
+  return x
+}
+
+// CHECK-LABEL: define hidden swiftcc %objc_object* @"$S22class_bounded_generics0a1_b18_archetype_to_not_a1_B0{{[_0-9a-zA-Z]*}}F"(%objc_object*, %swift.type* %T, i8** %T.ClassBound, i8** %T.NotClassBound) {{.*}} {
+func class_bounded_archetype_to_not_class_bounded
+<T: ClassBound & NotClassBound>(_ x:T) -> T {
+  // CHECK: alloca %objc_object*, align 8
+  return not_class_bounded_archetype(x)
+}
+
+/* TODO Abstraction remapping to non-class-bounded witnesses
+func class_and_not_class_bounded_archetype_methods
+<T: ClassBound & NotClassBound>(_ x:T, y:T) {
+  x.classBoundMethod()
+  x.classBoundBinaryMethod(y)
+  x.notClassBoundMethod()
+  x.notClassBoundBinaryMethod(y)
+}
+*/
+
+// CHECK-LABEL: define hidden swiftcc { %objc_object*, i8** } @"$S22class_bounded_generics0a1_B8_erasure{{[_0-9a-zA-Z]*}}F"(%T22class_bounded_generics13ConcreteClassC*) {{.*}} {
+func class_bounded_erasure(_ x: ConcreteClass) -> ClassBound {
+  return x
+  // CHECK: [[INSTANCE_OPAQUE:%.*]] = bitcast %T22class_bounded_generics13ConcreteClassC* [[INSTANCE:%.*]] to %objc_object*
+  // CHECK: [[T0:%.*]] = insertvalue { %objc_object*, i8** } undef, %objc_object* [[INSTANCE_OPAQUE]], 0
+  // CHECK: [[T1:%.*]] = insertvalue { %objc_object*, i8** } [[T0]], i8** getelementptr inbounds ([2 x i8*], [2 x i8*]* @"$S22class_bounded_generics13ConcreteClassCAA0E5BoundAAWP", i32 0, i32 0), 1
+  // CHECK: ret { %objc_object*, i8** } [[T1]]
+}
+
+// CHECK-LABEL: define hidden swiftcc void @"$S22class_bounded_generics0a1_B16_protocol_method{{[_0-9a-zA-Z]*}}F"(%objc_object*, i8**) {{.*}} {
+func class_bounded_protocol_method(_ x: ClassBound) {
+  x.classBoundMethod()
+  // CHECK: [[METADATA:%.*]] = call %swift.type* @swift_getObjectType(%objc_object* %0)
+  // CHECK: [[WITNESS_GEP:%.*]] = getelementptr inbounds i8*, i8** [[WITNESS_TABLE:%.*]], i32 1
+  // CHECK: [[WITNESS:%.*]] = load i8*, i8** [[WITNESS_GEP]], align 8
+  // CHECK: [[WITNESS_FN:%.*]] = bitcast i8* [[WITNESS]] to void (%objc_object*, %swift.type*, i8**)
+  // CHECK: call swiftcc void [[WITNESS_FN]](%objc_object* swiftself %0, %swift.type* [[METADATA]], i8** [[WITNESS_TABLE]])
+}
+
+// CHECK-LABEL: define hidden swiftcc %T22class_bounded_generics13ConcreteClassC* @"$S22class_bounded_generics0a1_B15_archetype_cast{{[_0-9a-zA-Z]*}}F"(%objc_object*, %swift.type* %T, i8** %T.ClassBound)
+func class_bounded_archetype_cast<T : ClassBound>(_ x: T) -> ConcreteClass {
+  return x as! ConcreteClass
+  // CHECK: [[IN_PTR:%.*]] = bitcast %objc_object* {{%.*}} to i8*
+  // CHECK: [[T0:%.*]] = call %swift.type* @"$S22class_bounded_generics13ConcreteClassCMa"()
+  // CHECK: [[T1:%.*]] = bitcast %swift.type* [[T0]] to i8*
+  // CHECK: [[OUT_PTR:%.*]] = call i8* @swift_dynamicCastClassUnconditional(i8* [[IN_PTR]], i8* [[T1]])
+  // CHECK: [[OUT:%.*]] = bitcast i8* [[OUT_PTR]] to %T22class_bounded_generics13ConcreteClassC*
+  // CHECK: ret %T22class_bounded_generics13ConcreteClassC* [[OUT]]
+}
+
+// CHECK-LABEL: define hidden swiftcc %T22class_bounded_generics13ConcreteClassC* @"$S22class_bounded_generics0a1_B14_protocol_cast{{[_0-9a-zA-Z]*}}F"(%objc_object*, i8**)
+func class_bounded_protocol_cast(_ x: ClassBound) -> ConcreteClass {
+  return x as! ConcreteClass
+  // CHECK: [[IN_PTR:%.*]] = bitcast %objc_object* {{%.*}} to i8*
+  // CHECK: [[T0:%.*]] = call %swift.type* @"$S22class_bounded_generics13ConcreteClassCMa"()
+  // CHECK: [[T1:%.*]] = bitcast %swift.type* [[T0]] to i8*
+  // CHECK: [[OUT_PTR:%.*]] = call i8* @swift_dynamicCastClassUnconditional(i8* [[IN_PTR]], i8* [[T1]])
+  // CHECK: [[OUT:%.*]] = bitcast i8* [[OUT_PTR]] to %T22class_bounded_generics13ConcreteClassC*
+  // CHECK: ret %T22class_bounded_generics13ConcreteClassC* [[OUT]]
+}
+
+// CHECK-LABEL: define hidden swiftcc { %objc_object*, i8** } @"$S22class_bounded_generics0a1_B22_protocol_conversion_{{.*}}"(%objc_object*, i8**, i8**) {{.*}} {
+func class_bounded_protocol_conversion_1(_ x: ClassBound & ClassBound2)
+-> ClassBound {
+  return x
+}
+// CHECK-LABEL: define hidden swiftcc { %objc_object*, i8** } @"$S22class_bounded_generics0a1_B22_protocol_conversion_{{.*}}"(%objc_object*, i8**, i8**) {{.*}} {
+func class_bounded_protocol_conversion_2(_ x: ClassBound & ClassBound2)
+-> ClassBound2 {
+  return x
+}
+
+// CHECK-LABEL: define hidden swiftcc { %objc_object*, i8** } @"$S22class_bounded_generics05objc_a1_B22_protocol_conversion_{{.*}}"(%objc_object*, i8**) {{.*}} {
+func objc_class_bounded_protocol_conversion_1
+(_ x: ClassBound & ObjCClassBound) -> ClassBound {
+  return x
+}
+// CHECK-LABEL: define hidden swiftcc %objc_object* @"$S22class_bounded_generics05objc_a1_B22_protocol_conversion_{{.*}}"(%objc_object*, i8**) {{.*}} {
+func objc_class_bounded_protocol_conversion_2
+(_ x: ClassBound & ObjCClassBound) -> ObjCClassBound {
+  return x
+}
+// CHECK-LABEL: define hidden swiftcc %objc_object* @"$S22class_bounded_generics05objc_a1_B22_protocol_conversion_{{.*}}"(%objc_object*)
+func objc_class_bounded_protocol_conversion_3
+(_ x: ObjCClassBound & ObjCClassBound2) -> ObjCClassBound {
+  return x
+}
+// CHECK-LABEL: define hidden swiftcc %objc_object* @"$S22class_bounded_generics05objc_a1_B22_protocol_conversion_{{.*}}"(%objc_object*)
+func objc_class_bounded_protocol_conversion_4
+(_ x: ObjCClassBound & ObjCClassBound2) -> ObjCClassBound2 {
+  return x
+}
+
+// CHECK-LABEL: define hidden swiftcc { i64, %objc_object*, i64 } @"$S22class_bounded_generics0A28_generic_field_struct_fields{{[_0-9a-zA-Z]*}}F"(i64, %objc_object*, i64, %swift.type* %T, i8** %T.ClassBound)
+func class_generic_field_struct_fields<T>
+(_ x:ClassGenericFieldStruct<T>) -> (Int, T, Int) {
+  return (x.x, x.y, x.z)
+}
+
+// CHECK-LABEL: define hidden swiftcc { i64, %objc_object*, i8**, i64 } @"$S22class_bounded_generics0A29_protocol_field_struct_fields{{[_0-9a-zA-Z]*}}F"(i64, %objc_object*, i8**, i64)
+func class_protocol_field_struct_fields
+(_ x:ClassProtocolFieldStruct) -> (Int, ClassBound, Int) {
+  return (x.x, x.y, x.z)
+}
+
+// CHECK-LABEL: define hidden swiftcc { i64, %objc_object*, i64 } @"$S22class_bounded_generics0a15_generic_field_A7_fields{{[_0-9a-zA-Z]*}}F"(%T22class_bounded_generics017ClassGenericFieldD0C*)
+func class_generic_field_class_fields<T>
+(_ x:ClassGenericFieldClass<T>) -> (Int, T, Int) {
+  return (x.x, x.y, x.z)
+  // CHECK: getelementptr inbounds %T22class_bounded_generics017ClassGenericFieldD0C, %T22class_bounded_generics017ClassGenericFieldD0C* %0, i32 0, i32 1
+  // CHECK: getelementptr inbounds %T22class_bounded_generics017ClassGenericFieldD0C, %T22class_bounded_generics017ClassGenericFieldD0C* %0, i32 0, i32 2
+  // CHECK: getelementptr inbounds %T22class_bounded_generics017ClassGenericFieldD0C, %T22class_bounded_generics017ClassGenericFieldD0C* %0, i32 0, i32 3
+}
+
+// CHECK-LABEL: define hidden swiftcc { i64, %objc_object*, i8**, i64 } @"$S22class_bounded_generics0a16_protocol_field_A7_fields{{[_0-9a-zA-Z]*}}F"(%T22class_bounded_generics018ClassProtocolFieldD0C*)
+func class_protocol_field_class_fields(_ x: ClassProtocolFieldClass)
+-> (Int, ClassBound, Int) {
+  return (x.x, x.y, x.z)
+  // CHECK:  = call swiftcc i64 %{{[0-9]+}}
+  // CHECK:  = call swiftcc { %objc_object*, i8** } %{{[0-9]+}}
+  // CHECK:  = call swiftcc i64 %{{[0-9]+}}
+}
+
+class SomeSwiftClass {
+  class func foo() {}
+}
+
+// T must have a Swift layout, so we can load this metatype with a direct access.
+// CHECK-LABEL: define hidden swiftcc void @"$S22class_bounded_generics0a1_B9_metatype{{[_0-9a-zA-Z]*}}F"
+// CHECK:      [[T0:%.*]] = getelementptr inbounds %T22class_bounded_generics14SomeSwiftClassC, %T22class_bounded_generics14SomeSwiftClassC* {{%.*}}, i32 0, i32 0, i32 0
+// CHECK-NEXT: [[T1:%.*]] = load %swift.type*, %swift.type** [[T0]], align 8
+// CHECK-NEXT: [[T2:%.*]] = bitcast %swift.type* [[T1]] to void (%swift.type*)**
+// CHECK-NEXT: [[T3:%.*]] = getelementptr inbounds void (%swift.type*)*, void (%swift.type*)** [[T2]], i64 10
+// CHECK-NEXT: load void (%swift.type*)*, void (%swift.type*)** [[T3]], align 8
+func class_bounded_metatype<T: SomeSwiftClass>(_ t : T) {
+  type(of: t).foo()
+}
+
+class WeakRef<T: AnyObject> {
+  weak var value: T?
+}
+
+class A<T> {
+  required init() {}
+}
+
+class M<T, S: A<T>> {
+  private var s: S
+  init() {
+    // Don't crash generating the reference to 's'.
+    s = S.init()
+  }
+}
+
+// CHECK-LABEL: define hidden swiftcc void @"$S22class_bounded_generics14takes_metatypeyyxmlF"(%swift.type*, %swift.type* %T)
+func takes_metatype<T>(_: T.Type) {}
+
+// CHECK-LABEL: define hidden swiftcc void @"$S22class_bounded_generics023archetype_with_generic_A11_constraint1tyx_tAA1ACyq_GRbzr0_lF"(%T22class_bounded_generics1AC.2*, %swift.type* %T)
+// CHECK:      [[ISA_ADDR:%.*]] = bitcast %T22class_bounded_generics1AC.2* %0 to %swift.type**
+// CHECK-NEXT: [[ISA:%.*]] = load %swift.type*, %swift.type** [[ISA_ADDR]]
+// CHECK-NEXT: call swiftcc void @"$S22class_bounded_generics14takes_metatypeyyxmlF"(%swift.type* %T, %swift.type* %T)
+// CHECK-NEXT: [[ISA_PTR:%.*]] = bitcast %swift.type* [[ISA]] to %swift.type**
+// CHECK-NEXT: [[U_ADDR:%.*]] = getelementptr inbounds %swift.type*, %swift.type** [[ISA_PTR]], i64 10
+// CHECK-NEXT: [[U:%.*]] = load %swift.type*, %swift.type** [[U_ADDR]]
+// CHECK-NEXT: call swiftcc void @"$S22class_bounded_generics14takes_metatypeyyxmlF"(%swift.type* %U, %swift.type* %U)
+// CHECK:      ret void
+
+func archetype_with_generic_class_constraint<T, U>(t: T) where T : A<U> {
+  takes_metatype(T.self)
+  takes_metatype(U.self)
+}
+
+// CHECK-LABEL: define hidden swiftcc void @"$S22class_bounded_generics029calls_archetype_with_generic_A11_constraint1ayAA1ACyxG_tlF"(%T22class_bounded_generics1AC*) #0 {
+// CHECK:      [[ISA_ADDR:%.*]] = getelementptr inbounds %T22class_bounded_generics1AC, %T22class_bounded_generics1AC* %0, i32 0, i32 0, i32 0
+// CHECK-NEXT: [[ISA:%.*]] = load %swift.type*, %swift.type** [[ISA_ADDR]]
+// CHECK:      [[SELF:%.*]] = bitcast %T22class_bounded_generics1AC* %0 to %T22class_bounded_generics1AC.2*
+// CHECK-NEXT: [[ISA_PTR:%.*]] = bitcast %swift.type* [[ISA]] to %swift.type**
+// CHECK-NEXT: [[T_ADDR:%.*]] = getelementptr inbounds %swift.type*, %swift.type** [[ISA_PTR]], i64 10
+// CHECK-NEXT: [[T:%.*]] = load %swift.type*, %swift.type** [[T_ADDR]]
+// CHECK-NEXT: [[A_OF_T:%.*]] = call %swift.type* @"$S22class_bounded_generics1ACMa"(%swift.type* [[T]])
+// CHECK-NEXT: call swiftcc void @"$S22class_bounded_generics023archetype_with_generic_A11_constraint1tyx_tAA1ACyq_GRbzr0_lF"(%T22class_bounded_generics1AC.2* [[SELF]], %swift.type* [[A_OF_T]])
+// CHECK:      ret void
+
+func calls_archetype_with_generic_class_constraint<T>(a: A<T>) {
+  archetype_with_generic_class_constraint(t: a)
+}
diff --git a/test/IRGen/plus_zero_enum_resilience.swift b/test/IRGen/plus_zero_enum_resilience.swift
new file mode 100644
index 0000000..8332486
--- /dev/null
+++ b/test/IRGen/plus_zero_enum_resilience.swift
@@ -0,0 +1,275 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %empty-directory(%t)
+// RUN: %target-swift-frontend -emit-module -enable-resilience -emit-module-path=%t/resilient_struct.swiftmodule -module-name=resilient_struct %S/../Inputs/resilient_struct.swift
+// RUN: %target-swift-frontend -emit-module -enable-resilience -emit-module-path=%t/resilient_enum.swiftmodule -module-name=resilient_enum -I %t %S/../Inputs/resilient_enum.swift
+// RUN: %target-swift-frontend -I %t -emit-ir -enable-resilience %s | %FileCheck %s
+// RUN: %target-swift-frontend -I %t -emit-ir -enable-resilience -O %s
+
+import resilient_enum
+import resilient_struct
+
+// CHECK: %swift.type = type { [[INT:i32|i64]] }
+
+// CHECK: %T15enum_resilience5ClassC = type <{ %swift.refcounted }>
+// CHECK: %T15enum_resilience9ReferenceV = type <{ %T15enum_resilience5ClassC* }>
+
+// Public fixed layout struct contains a public resilient struct,
+// cannot use spare bits
+
+// CHECK: %T15enum_resilience6EitherO = type <{ [[REFERENCE_TYPE:\[(4|8) x i8\]]], [1 x i8] }>
+
+// Public resilient struct contains a public resilient struct,
+// can use spare bits
+
+// CHECK: %T15enum_resilience15ResilientEitherO = type <{ [[REFERENCE_TYPE]] }>
+
+// Internal fixed layout struct contains a public resilient struct,
+// can use spare bits
+
+// CHECK: %T15enum_resilience14InternalEitherO = type <{ [[REFERENCE_TYPE]] }>
+
+// Public fixed layout struct contains a fixed layout struct,
+// can use spare bits
+
+// CHECK: %T15enum_resilience10EitherFastO = type <{ [[REFERENCE_TYPE]] }>
+
+public class Class {}
+
+public struct Reference {
+  public var n: Class
+}
+
+@_fixed_layout public enum Either {
+  case Left(Reference)
+  case Right(Reference)
+}
+
+public enum ResilientEither {
+  case Left(Reference)
+  case Right(Reference)
+}
+
+enum InternalEither {
+  case Left(Reference)
+  case Right(Reference)
+}
+
+@_fixed_layout public struct ReferenceFast {
+  public var n: Class
+}
+
+@_fixed_layout public enum EitherFast {
+  case Left(ReferenceFast)
+  case Right(ReferenceFast)
+}
+
+// CHECK-LABEL: define{{( protected)?}} swiftcc void @"$S15enum_resilience25functionWithResilientEnumy010resilient_A06MediumOAEF"(%swift.opaque* noalias nocapture sret, %swift.opaque* noalias nocapture)
+public func functionWithResilientEnum(_ m: Medium) -> Medium {
+
+// CHECK:      [[METADATA:%.*]] = call %swift.type* @"$S14resilient_enum6MediumOMa"()
+// CHECK-NEXT: [[METADATA_ADDR:%.*]] = bitcast %swift.type* [[METADATA]] to i8***
+// CHECK-NEXT: [[VWT_ADDR:%.*]] = getelementptr inbounds i8**, i8*** [[METADATA_ADDR]], [[INT:i32|i64]] -1
+// CHECK-NEXT: [[VWT:%.*]] = load i8**, i8*** [[VWT_ADDR]]
+// This is copying the +0 argument to be used as a return value.
+// CHECK-NEXT: [[WITNESS_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 2
+// CHECK-NEXT: [[WITNESS:%.*]]  = load i8*, i8** [[WITNESS_ADDR]]
+// CHECK-NEXT: [[WITNESS_FN:%initializeWithCopy]] = bitcast i8* [[WITNESS]]
+// CHECK-NEXT: call %swift.opaque* [[WITNESS_FN]](%swift.opaque* noalias %0, %swift.opaque* noalias %1, %swift.type* [[METADATA]])
+// CHECK-NEXT: ret void
+
+  return m
+}
+
+// CHECK-LABEL: define{{( protected)?}} swiftcc void @"$S15enum_resilience33functionWithIndirectResilientEnumy010resilient_A00E8ApproachOAEF"(%swift.opaque* noalias nocapture sret, %swift.opaque* noalias nocapture)
+public func functionWithIndirectResilientEnum(_ ia: IndirectApproach) -> IndirectApproach {
+
+// CHECK:      [[METADATA:%.*]] = call %swift.type* @"$S14resilient_enum16IndirectApproachOMa"()
+// CHECK-NEXT: [[METADATA_ADDR:%.*]] = bitcast %swift.type* [[METADATA]] to i8***
+// CHECK-NEXT: [[VWT_ADDR:%.*]] = getelementptr inbounds i8**, i8*** [[METADATA_ADDR]], [[INT:i32|i64]] -1
+// CHECK-NEXT: [[VWT:%.*]] = load i8**, i8*** [[VWT_ADDR]]
+// This is copying the +0 argument into the return slot.
+// CHECK-NEXT: [[WITNESS_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 2
+// CHECK-NEXT: [[WITNESS:%.*]]  = load i8*, i8** [[WITNESS_ADDR]]
+// CHECK-NEXT: [[WITNESS_FN:%initializeWithCopy]] = bitcast i8* [[WITNESS]]
+// CHECK-NEXT: call %swift.opaque* [[WITNESS_FN]](%swift.opaque* noalias %0, %swift.opaque* noalias %1, %swift.type* [[METADATA]])
+// CHECK-NEXT: ret void
+
+  return ia
+}
+
+// CHECK-LABEL: define{{( protected)?}} swiftcc void @"$S15enum_resilience31constructResilientEnumNoPayload010resilient_A06MediumOyF"
+public func constructResilientEnumNoPayload() -> Medium {
+// CHECK:      [[METADATA:%.*]] = call %swift.type* @"$S14resilient_enum6MediumOMa"()
+// CHECK-NEXT: [[METADATA_ADDR:%.*]] = bitcast %swift.type* [[METADATA]] to i8***
+// CHECK-NEXT: [[VWT_ADDR:%.*]] = getelementptr inbounds i8**, i8*** [[METADATA_ADDR]], [[INT:i32|i64]] -1
+// CHECK-NEXT: [[VWT:%.*]] = load i8**, i8*** [[VWT_ADDR]]
+
+// CHECK-NEXT: [[WITNESS_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 17
+// CHECK-NEXT: [[WITNESS:%.*]] = load i8*, i8** [[WITNESS_ADDR]]
+// CHECK-NEXT: [[WITNESS_FN:%.*]] = bitcast i8* [[WITNESS]]
+// CHECK-NEXT: call void [[WITNESS_FN]](%swift.opaque* noalias %0, i32 0, %swift.type* [[METADATA]])
+
+// CHECK-NEXT: ret void
+  return Medium.Paper
+}
+
+// CHECK-LABEL: define{{( protected)?}} swiftcc void @"$S15enum_resilience29constructResilientEnumPayloady010resilient_A06MediumO0G7_struct4SizeVF"
+public func constructResilientEnumPayload(_ s: Size) -> Medium {
+// CHECK:      [[METADATA:%.*]] = call %swift.type* @"$S16resilient_struct4SizeVMa"()
+// CHECK-NEXT: [[METADATA_ADDR:%.*]] = bitcast %swift.type* [[METADATA]] to i8***
+// CHECK-NEXT: [[VWT_ADDR:%.*]] = getelementptr inbounds i8**, i8*** [[METADATA_ADDR]], [[INT:i32|i64]] -1
+// CHECK-NEXT: [[VWT:%.*]] = load i8**, i8*** [[VWT_ADDR]]
+
+// CHECK-NEXT: [[WITNESS_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 2
+// CHECK-NEXT: [[WITNESS:%.*]]  = load i8*, i8** [[WITNESS_ADDR]]
+// CHECK-NEXT: [[WITNESS_FN:%initializeWithCopy]] = bitcast i8* [[WITNESS]]
+// CHECK-NEXT: [[COPY:%.*]] = call %swift.opaque* [[WITNESS_FN]](%swift.opaque* noalias %0, %swift.opaque* noalias %1, %swift.type* [[METADATA]])
+
+// CHECK-NEXT: [[METADATA2:%.*]] = call %swift.type* @"$S14resilient_enum6MediumOMa"()
+// CHECK-NEXT: [[METADATA_ADDR2:%.*]] = bitcast %swift.type* [[METADATA2]] to i8***
+// CHECK-NEXT: [[VWT_ADDR2:%.*]] = getelementptr inbounds i8**, i8*** [[METADATA_ADDR2]], [[INT:i32|i64]] -1
+// CHECK-NEXT: [[VWT2:%.*]] = load i8**, i8*** [[VWT_ADDR2]]
+
+// CHECK-NEXT: [[WITNESS_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT2]], i32 17
+// CHECK-NEXT: [[WITNESS:%.*]] = load i8*, i8** [[WITNESS_ADDR]]
+// CHECK-NEXT: [[WITNESS_FN:%destructiveInjectEnumTag]] = bitcast i8* [[WITNESS]]
+// CHECK-NEXT: call void [[WITNESS_FN]](%swift.opaque* noalias %0, i32 -2, %swift.type* [[METADATA2]])
+// CHECK-NEXT: ret void
+
+  return Medium.Postcard(s)
+}
+
+// CHECK-LABEL: define{{( protected)?}} swiftcc {{i32|i64}} @"$S15enum_resilience19resilientSwitchTestySi0c1_A06MediumOF"(%swift.opaque* noalias nocapture)
+// CHECK: [[METADATA:%.*]] = call %swift.type* @"$S14resilient_enum6MediumOMa"()
+// CHECK: [[METADATA_ADDR:%.*]] = bitcast %swift.type* [[METADATA]] to i8***
+// CHECK: [[VWT_ADDR:%.*]] = getelementptr inbounds i8**, i8*** [[METADATA_ADDR]], [[INT]] -1
+// CHECK: [[VWT:%.*]] = load i8**, i8*** [[VWT_ADDR]]
+
+// CHECK: [[WITNESS_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 9
+// CHECK: [[WITNESS:%.*]] = load i8*, i8** [[WITNESS_ADDR]]
+// CHECK: [[WITNESS_FOR_SIZE:%size]] = ptrtoint i8* [[WITNESS]]
+// CHECK: [[ALLOCA:%.*]] = alloca i8, {{.*}} [[WITNESS_FOR_SIZE]], align 16
+// CHECK: [[ALLOCA:%.*]] = alloca i8, {{.*}} [[WITNESS_FOR_SIZE]], align 16
+// CHECK: [[ENUM_STORAGE:%.*]] = bitcast i8* [[ALLOCA]] to %swift.opaque*
+
+// CHECK: [[WITNESS_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 2
+// CHECK: [[WITNESS:%.*]] = load i8*, i8** [[WITNESS_ADDR]]
+// CHECK: [[WITNESS_FN:%initializeWithCopy]] = bitcast i8* [[WITNESS]]
+// CHECK: [[ENUM_COPY:%.*]] = call %swift.opaque* [[WITNESS_FN]](%swift.opaque* noalias [[ENUM_STORAGE]], %swift.opaque* noalias %0, %swift.type* [[METADATA]])
+
+// CHECK: [[WITNESS_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 15
+// CHECK: [[WITNESS:%.*]] = load i8*, i8** [[WITNESS_ADDR]]
+// CHECK: [[WITNESS_FN:%getEnumTag]] = bitcast i8* [[WITNESS]]
+// CHECK: [[TAG:%.*]] = call i32 [[WITNESS_FN]](%swift.opaque* noalias [[ENUM_STORAGE]], %swift.type* [[METADATA]])
+
+// CHECK: switch i32 [[TAG]], label %[[DEFAULT_CASE:.*]] [
+// CHECK:   i32 -1, label %[[PAMPHLET_CASE:.*]]
+// CHECK:   i32 0, label %[[PAPER_CASE:.*]]
+// CHECK:   i32 1, label %[[CANVAS_CASE:.*]]
+// CHECK: ]
+
+// CHECK: ; <label>:[[PAPER_CASE]]
+// CHECK: br label %[[END:.*]]
+
+// CHECK: ; <label>:[[CANVAS_CASE]]
+// CHECK: br label %[[END]]
+
+// CHECK: ; <label>:[[PAMPHLET_CASE]]
+// CHECK: br label %[[END]]
+
+// CHECK: ; <label>:[[DEFAULT_CASE]]
+// CHECK: br label %[[END]]
+
+// CHECK: ; <label>:[[END]]
+// CHECK: ret
+
+public func resilientSwitchTest(_ m: Medium) -> Int {
+  switch m {
+  case .Paper:
+    return 1
+  case .Canvas:
+    return 2
+  case .Pamphlet(let m):
+    return resilientSwitchTest(m)
+  default:
+    return 3
+  }
+}
+
+public func reabstraction<T>(_ f: (Medium) -> T) {}
+
+// CHECK-LABEL: define{{( protected)?}} swiftcc void @"$S15enum_resilience25resilientEnumPartialApplyyySi0c1_A06MediumOXEF"(i8*, %swift.opaque*)
+public func resilientEnumPartialApply(_ f: (Medium) -> Int) {
+
+// CHECK:     [[CONTEXT:%.*]] = call noalias %swift.refcounted* @swift_allocObject
+// CHECK:     call swiftcc void @"$S15enum_resilience13reabstractionyyx010resilient_A06MediumOXElF"(i8* bitcast (void (%TSi*, %swift.opaque*, %swift.refcounted*)* @"$S14resilient_enum6MediumOSiIgnd_ACSiIegnr_TRTA" to i8*), %swift.opaque* [[CONTEXT:%.*]], %swift.type* @"$SSiN")
+  reabstraction(f)
+
+// CHECK:     ret void
+}
+
+// CHECK-LABEL: define internal swiftcc void @"$S14resilient_enum6MediumOSiIgnd_ACSiIegnr_TRTA"(%TSi* noalias nocapture sret, %swift.opaque* noalias nocapture, %swift.refcounted* swiftself)
+
+
+// Enums with resilient payloads from a different resilience domain
+// require runtime metadata instantiation, just like generics.
+
+public enum EnumWithResilientPayload {
+  case OneSize(Size)
+  case TwoSizes(Size, Size)
+}
+
+// Make sure we call a function to access metadata of enums with
+// resilient layout.
+
+// CHECK-LABEL: define{{( protected)?}} swiftcc %swift.type* @"$S15enum_resilience20getResilientEnumTypeypXpyF"()
+// CHECK:      [[METADATA:%.*]] = call %swift.type* @"$S15enum_resilience24EnumWithResilientPayloadOMa"()
+// CHECK-NEXT: ret %swift.type* [[METADATA]]
+
+public func getResilientEnumType() -> Any.Type {
+  return EnumWithResilientPayload.self
+}
+
+// Public metadata accessor for our resilient enum
+// CHECK-LABEL: define{{( protected)?}} %swift.type* @"$S15enum_resilience24EnumWithResilientPayloadOMa"()
+// CHECK: [[METADATA:%.*]] = load %swift.type*, %swift.type** @"$S15enum_resilience24EnumWithResilientPayloadOML"
+// CHECK-NEXT: [[COND:%.*]] = icmp eq %swift.type* [[METADATA]], null
+// CHECK-NEXT: br i1 [[COND]], label %cacheIsNull, label %cont
+
+// CHECK: cacheIsNull:
+// CHECK-NEXT: call void @swift_once([[INT]]* @"$S15enum_resilience24EnumWithResilientPayloadOMa.once_token", i8* bitcast (void (i8*)* @initialize_metadata_EnumWithResilientPayload to i8*), i8* undef)
+// CHECK-NEXT: [[METADATA2:%.*]] = load %swift.type*, %swift.type** @"$S15enum_resilience24EnumWithResilientPayloadOML"
+// CHECK-NEXT: br label %cont
+
+// CHECK: cont:
+// CHECK-NEXT: [[RESULT:%.*]] = phi %swift.type* [ [[METADATA]], %entry ], [ [[METADATA2]], %cacheIsNull ]
+// CHECK-NEXT: ret %swift.type* [[RESULT]]
+
+// Methods inside extensions of resilient enums fish out type parameters
+// from metadata -- make sure we can do that
+extension ResilientMultiPayloadGenericEnum {
+
+// CHECK-LABEL: define{{( protected)?}} swiftcc %swift.type* @"$S14resilient_enum32ResilientMultiPayloadGenericEnumO0B11_resilienceE16getTypeParameterxmyF"(%swift.type* %"ResilientMultiPayloadGenericEnum<T>", %swift.opaque* noalias nocapture swiftself)
+// CHECK: [[METADATA:%.*]] = bitcast %swift.type* %"ResilientMultiPayloadGenericEnum<T>" to %swift.type**
+// CHECK-NEXT: [[T_ADDR:%.*]] = getelementptr inbounds %swift.type*, %swift.type** [[METADATA]], [[INT]] 2
+// CHECK-NEXT: [[T:%.*]] = load %swift.type*, %swift.type** [[T_ADDR]]
+  public func getTypeParameter() -> T.Type {
+    return T.self
+  }
+}
+
+// CHECK-LABEL: define{{( protected)?}} private void @initialize_metadata_EnumWithResilientPayload(i8*)
+// CHECK: call void @swift_initEnumMetadataMultiPayload(%swift.type* {{.*}}, [[INT]] 256, [[INT]] 2, i8*** {{.*}})
+
+
+
+public protocol Prot {
+}
+
+private enum ProtGenEnumWithSize<T: Prot> {
+    case c1(s1: Size)
+    case c2(s2: Size)
+}
+
+// CHECK-LABEL: define{{( protected)?}} internal %T15enum_resilience19ProtGenEnumWithSize33_59077B69D65A4A3BEE0C93708067D5F0LLO* @"$S15enum_resilienceytWh2_"(%T15enum_resilience19ProtGenEnumWithSize
+// CHECK:   ret %T15enum_resilience19ProtGenEnumWithSize33_59077B69D65A4A3BEE0C93708067D5F0LLO* %0
diff --git a/test/IRGen/plus_zero_generic_metatypes.swift b/test/IRGen/plus_zero_generic_metatypes.swift
new file mode 100644
index 0000000..0249939
--- /dev/null
+++ b/test/IRGen/plus_zero_generic_metatypes.swift
@@ -0,0 +1,181 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %swift -target x86_64-apple-macosx10.9 -emit-ir -parse-stdlib -primary-file %s | %FileCheck --check-prefix=CHECK --check-prefix=CHECK-64 %s
+// RUN: %swift -target i386-apple-ios7.0 -emit-ir -parse-stdlib -primary-file %s | %FileCheck --check-prefix=CHECK --check-prefix=CHECK-32 %s
+// RUN: %swift -target x86_64-apple-ios7.0 -emit-ir -parse-stdlib -primary-file %s | %FileCheck --check-prefix=CHECK --check-prefix=CHECK-64 %s
+// RUN: %swift -target i386-apple-tvos9.0 -emit-ir -parse-stdlib -primary-file %s | %FileCheck --check-prefix=CHECK --check-prefix=CHECK-32 %s
+// RUN: %swift -target x86_64-apple-tvos9.0 -emit-ir -parse-stdlib -primary-file %s | %FileCheck --check-prefix=CHECK --check-prefix=CHECK-64 %s
+// RUN: %swift -target i386-apple-watchos2.0 -emit-ir -parse-stdlib -primary-file %s | %FileCheck --check-prefix=CHECK --check-prefix=CHECK-32 %s
+// RUN: %swift -target x86_64-unknown-linux-gnu -disable-objc-interop -emit-ir -parse-stdlib -primary-file %s | %FileCheck --check-prefix=CHECK --check-prefix=CHECK-64 %s
+
+// REQUIRES: CODEGENERATOR=X86
+
+// CHECK: define hidden swiftcc %swift.type* [[GENERIC_TYPEOF:@"\$S17generic_metatypes0A6TypeofyxmxlF"]](%swift.opaque* noalias nocapture, %swift.type* [[TYPE:%.*]])
+func genericTypeof<T>(_ x: T) -> T.Type {
+  // CHECK: [[METATYPE:%.*]] = call %swift.type* @swift_getDynamicType(%swift.opaque* {{.*}}, %swift.type* [[TYPE]], i1 false)
+  // CHECK: ret %swift.type* [[METATYPE]]
+  return type(of: x)
+}
+
+struct Foo {}
+class Bar {}
+
+// CHECK-LABEL: define hidden swiftcc %swift.type* @"$S17generic_metatypes27remapToSubstitutedMetatypes{{.*}}"(%T17generic_metatypes3BarC*) {{.*}} {
+func remapToSubstitutedMetatypes(_ x: Foo, y: Bar)
+  -> (Foo.Type, Bar.Type)
+{
+  // CHECK: call swiftcc %swift.type* [[GENERIC_TYPEOF]](%swift.opaque* noalias nocapture undef, %swift.type* {{.*}} @"$S17generic_metatypes3FooVMf", {{.*}})
+  // CHECK: [[T0:%.*]] = call %swift.type* @"$S17generic_metatypes3BarCMa"()
+  // CHECK: [[BAR_META:%.*]] = call swiftcc %swift.type* [[GENERIC_TYPEOF]](%swift.opaque* noalias nocapture {{%.*}}, %swift.type* [[T0]])
+  // CHECK: ret %swift.type* [[BAR_META]]
+  return (genericTypeof(x), genericTypeof(y))
+}
+
+
+// CHECK-LABEL: define hidden swiftcc void @"$S17generic_metatypes23remapToGenericMetatypesyyF"()
+func remapToGenericMetatypes() {
+  // CHECK: [[T0:%.*]] = call %swift.type* @"$S17generic_metatypes3BarCMa"()
+  // CHECK: call swiftcc void @"$S17generic_metatypes0A9Metatypes{{.*}}"(%swift.type* {{.*}} @"$S17generic_metatypes3FooVMf", {{.*}} %swift.type* [[T0]], %swift.type* {{.*}} @"$S17generic_metatypes3FooVMf", {{.*}} %swift.type* [[T0]])
+  genericMetatypes(Foo.self, Bar.self)
+}
+
+func genericMetatypes<T, U>(_ t: T.Type, _ u: U.Type) {}
+
+protocol Bas {}
+
+// CHECK: define hidden swiftcc { %swift.type*, i8** } @"$S17generic_metatypes14protocolTypeof{{.*}}"(%T17generic_metatypes3BasP* noalias nocapture dereferenceable({{.*}}))
+func protocolTypeof(_ x: Bas) -> Bas.Type {
+  // CHECK: [[METADATA_ADDR:%.*]] = getelementptr inbounds %T17generic_metatypes3BasP, %T17generic_metatypes3BasP* [[X:%.*]], i32 0, i32 1
+  // CHECK: [[METADATA:%.*]] = load %swift.type*, %swift.type** [[METADATA_ADDR]]
+  // CHECK: [[BUFFER:%.*]] = getelementptr inbounds %T17generic_metatypes3BasP, %T17generic_metatypes3BasP* [[X]], i32 0, i32 0
+  // CHECK: [[VALUE_ADDR:%.*]] = call %swift.opaque* @__swift_project_boxed_opaque_existential_1({{.*}} [[BUFFER]], %swift.type* [[METADATA]])
+  // CHECK: [[METATYPE:%.*]] = call %swift.type* @swift_getDynamicType(%swift.opaque* [[VALUE_ADDR]], %swift.type* [[METADATA]], i1 true)
+  // CHECK: [[WTABLE_ADDR:%.*]] = getelementptr inbounds %T17generic_metatypes3BasP, %T17generic_metatypes3BasP* %0, i32 0, i32 2
+  // CHECK: [[WTABLE:%.*]] = load i8**, i8*** [[WTABLE_ADDR]]
+  // CHECK-NOT: call void @__swift_destroy_boxed_opaque_existential_1(%T17generic_metatypes3BasP* %0)
+  // CHECK: [[T0:%.*]] = insertvalue { %swift.type*, i8** } undef, %swift.type* [[METATYPE]], 0
+  // CHECK: [[T1:%.*]] = insertvalue { %swift.type*, i8** } [[T0]], i8** [[WTABLE]], 1
+  // CHECK: ret { %swift.type*, i8** } [[T1]]
+  return type(of: x)
+}
+
+struct Zim : Bas {}
+class Zang : Bas {}
+
+// CHECK-LABEL: define hidden swiftcc { %swift.type*, i8** } @"$S17generic_metatypes15metatypeErasureyAA3Bas_pXpAA3ZimVmF"() #0
+func metatypeErasure(_ z: Zim.Type) -> Bas.Type {
+  // CHECK: ret { %swift.type*, i8** } {{.*}} @"$S17generic_metatypes3ZimVMf", {{.*}} @"$S17generic_metatypes3ZimVAA3BasAAWP"
+  return z
+}
+
+// CHECK-LABEL: define hidden swiftcc { %swift.type*, i8** } @"$S17generic_metatypes15metatypeErasureyAA3Bas_pXpAA4ZangCmF"(%swift.type*) #0
+func metatypeErasure(_ z: Zang.Type) -> Bas.Type {
+  // CHECK: [[RET:%.*]] = insertvalue { %swift.type*, i8** } undef, %swift.type* %0, 0
+  // CHECK: [[RET2:%.*]] = insertvalue { %swift.type*, i8** } [[RET]], i8** getelementptr inbounds ([1 x i8*], [1 x i8*]* @"$S17generic_metatypes4ZangCAA3BasAAWP", i32 0, i32 0), 1
+  // CHECK: ret { %swift.type*, i8** } [[RET2]]
+  return z
+}
+
+struct OneArg<T> {}
+struct TwoArgs<T, U> {}
+struct ThreeArgs<T, U, V> {}
+struct FourArgs<T, U, V, W> {}
+struct FiveArgs<T, U, V, W, X> {}
+
+func genericMetatype<A>(_ x: A.Type) {}
+
+// CHECK-LABEL: define hidden swiftcc void @"$S17generic_metatypes20makeGenericMetatypesyyF"() {{.*}} {
+func makeGenericMetatypes() {
+  // CHECK: call %swift.type* @"$S17generic_metatypes6OneArgVyAA3FooVGMa"() [[NOUNWIND_READNONE:#[0-9]+]]
+  genericMetatype(OneArg<Foo>.self)
+
+  // CHECK: call %swift.type* @"$S17generic_metatypes7TwoArgsVyAA3FooVAA3BarCGMa"() [[NOUNWIND_READNONE]]
+  genericMetatype(TwoArgs<Foo, Bar>.self)
+
+  // CHECK: call %swift.type* @"$S17generic_metatypes9ThreeArgsVyAA3FooVAA3BarCAEGMa"() [[NOUNWIND_READNONE]]
+  genericMetatype(ThreeArgs<Foo, Bar, Foo>.self)
+
+  // CHECK: call %swift.type* @"$S17generic_metatypes8FourArgsVyAA3FooVAA3BarCAeGGMa"() [[NOUNWIND_READNONE]]
+  genericMetatype(FourArgs<Foo, Bar, Foo, Bar>.self)
+
+  // CHECK: call %swift.type* @"$S17generic_metatypes8FiveArgsVyAA3FooVAA3BarCAegEGMa"() [[NOUNWIND_READNONE]]
+  genericMetatype(FiveArgs<Foo, Bar, Foo, Bar, Foo>.self)
+}
+
+// CHECK: define linkonce_odr hidden %swift.type* @"$S17generic_metatypes6OneArgVyAA3FooVGMa"() [[NOUNWIND_READNONE_OPT:#[0-9]+]]
+// CHECK:   call %swift.type* @"$S17generic_metatypes6OneArgVMa"(%swift.type* {{.*}} @"$S17generic_metatypes3FooVMf", {{.*}}) [[NOUNWIND_READNONE:#[0-9]+]]
+
+// CHECK-LABEL: define hidden %swift.type* @"$S17generic_metatypes6OneArgVMa"(%swift.type*)
+// CHECK:   [[BUFFER:%.*]] = alloca { %swift.type* }
+// CHECK:   [[BUFFER_PTR:%.*]] = bitcast { %swift.type* }* [[BUFFER]] to i8*
+// CHECK:   call void @llvm.lifetime.start
+// CHECK:   [[BUFFER_ELT:%.*]] = getelementptr inbounds { %swift.type* }, { %swift.type* }* [[BUFFER]], i32 0, i32 0
+// CHECK:   store %swift.type* %0, %swift.type** [[BUFFER_ELT]]
+// CHECK:   [[BUFFER_PTR:%.*]] = bitcast { %swift.type* }* [[BUFFER]] to i8*
+// CHECK:   [[METADATA:%.*]] = call %swift.type* @swift_getGenericMetadata(%swift.type_descriptor* {{.*}} @"$S17generic_metatypes6OneArgVMn" {{.*}}, i8* [[BUFFER_PTR]])
+// CHECK:   [[BUFFER_PTR:%.*]] = bitcast { %swift.type* }* [[BUFFER]] to i8*
+// CHECK:   call void @llvm.lifetime.end
+// CHECK:   ret %swift.type* [[METADATA]]
+
+// CHECK: define linkonce_odr hidden %swift.type* @"$S17generic_metatypes7TwoArgsVyAA3FooVAA3BarCGMa"() [[NOUNWIND_READNONE_OPT]]
+// CHECK:   [[T0:%.*]] = call %swift.type* @"$S17generic_metatypes3BarCMa"()
+// CHECK:   call %swift.type* @"$S17generic_metatypes7TwoArgsVMa"(%swift.type* {{.*}} @"$S17generic_metatypes3FooVMf", {{.*}}, %swift.type* [[T0]])
+
+// CHECK-LABEL: define hidden %swift.type* @"$S17generic_metatypes7TwoArgsVMa"(%swift.type*, %swift.type*)
+// CHECK:   [[BUFFER:%.*]] = alloca { %swift.type*, %swift.type* }
+// CHECK:   [[BUFFER_PTR:%.*]] = bitcast { %swift.type*, %swift.type* }* [[BUFFER]] to i8*
+// CHECK:   call void @llvm.lifetime.start
+// CHECK:   [[BUFFER_ELT:%.*]] = getelementptr inbounds { %swift.type*, %swift.type* }, { %swift.type*, %swift.type* }* [[BUFFER]], i32 0, i32 0
+// CHECK:   store %swift.type* %0, %swift.type** [[BUFFER_ELT]]
+// CHECK:   [[BUFFER_ELT:%.*]] = getelementptr inbounds { %swift.type*, %swift.type* }, { %swift.type*, %swift.type* }* [[BUFFER]], i32 0, i32 1
+// CHECK:   store %swift.type* %1, %swift.type** [[BUFFER_ELT]]
+// CHECK:   [[BUFFER_PTR:%.*]] = bitcast { %swift.type*, %swift.type* }* [[BUFFER]] to i8*
+// CHECK:   [[METADATA:%.*]] = call %swift.type* @swift_getGenericMetadata(%swift.type_descriptor* {{.*}} @"$S17generic_metatypes7TwoArgsVMn" {{.*}}, i8* [[BUFFER_PTR]])
+// CHECK:   [[BUFFER_PTR:%.*]] = bitcast { %swift.type*, %swift.type* }* [[BUFFER]] to i8*
+// CHECK:   call void @llvm.lifetime.end
+// CHECK:   ret %swift.type* [[METADATA]]
+
+// CHECK: define linkonce_odr hidden %swift.type* @"$S17generic_metatypes9ThreeArgsVyAA3FooVAA3BarCAEGMa"() [[NOUNWIND_READNONE_OPT]]
+// CHECK:   [[T0:%.*]] = call %swift.type* @"$S17generic_metatypes3BarCMa"()
+// CHECK:   call %swift.type* @"$S17generic_metatypes9ThreeArgsVMa"(%swift.type* {{.*}} @"$S17generic_metatypes3FooVMf", {{.*}}, %swift.type* [[T0]], %swift.type* {{.*}} @"$S17generic_metatypes3FooVMf", {{.*}}) [[NOUNWIND_READNONE]]
+
+// CHECK-LABEL: define hidden %swift.type* @"$S17generic_metatypes9ThreeArgsVMa"(%swift.type*, %swift.type*, %swift.type*)
+// CHECK:   [[BUFFER:%.*]] = alloca { %swift.type*, %swift.type*, %swift.type* }
+// CHECK:   [[BUFFER_PTR:%.*]] = bitcast { %swift.type*, %swift.type*, %swift.type* }* [[BUFFER]] to i8*
+// CHECK:   call void @llvm.lifetime.start
+// CHECK:   [[BUFFER_ELT:%.*]] = getelementptr inbounds { %swift.type*, %swift.type*, %swift.type* }, { %swift.type*, %swift.type*, %swift.type* }* [[BUFFER]], i32 0, i32 0
+// CHECK:   store %swift.type* %0, %swift.type** [[BUFFER_ELT]]
+// CHECK:   [[BUFFER_ELT:%.*]] = getelementptr inbounds { %swift.type*, %swift.type*, %swift.type* }, { %swift.type*, %swift.type*, %swift.type* }* [[BUFFER]], i32 0, i32 1
+// CHECK:   store %swift.type* %1, %swift.type** [[BUFFER_ELT]]
+// CHECK:   [[BUFFER_ELT:%.*]] = getelementptr inbounds { %swift.type*, %swift.type*, %swift.type* }, { %swift.type*, %swift.type*, %swift.type* }* [[BUFFER]], i32 0, i32 2
+// CHECK:   store %swift.type* %2, %swift.type** [[BUFFER_ELT]]
+// CHECK:   [[BUFFER_PTR:%.*]] = bitcast { %swift.type*, %swift.type*, %swift.type* }* [[BUFFER]] to i8*
+// CHECK:   [[METADATA:%.*]] = call %swift.type* @swift_getGenericMetadata(%swift.type_descriptor* {{.*}} @"$S17generic_metatypes9ThreeArgsVMn" {{.*}}, i8* [[BUFFER_PTR]])
+// CHECK:   [[BUFFER_PTR:%.*]] = bitcast { %swift.type*, %swift.type*, %swift.type* }* [[BUFFER]] to i8*
+// CHECK:   call void @llvm.lifetime.end
+// CHECK:   ret %swift.type* [[METADATA]]
+
+// CHECK: define linkonce_odr hidden %swift.type* @"$S17generic_metatypes8FourArgsVyAA3FooVAA3BarCAeGGMa"() [[NOUNWIND_READNONE_OPT]]
+// CHECK:   [[BUFFER:%.*]] = alloca [4 x i8*]
+// CHECK:   [[T0:%.*]] = call %swift.type* @"$S17generic_metatypes3BarCMa"()
+// CHECK:   call void @llvm.lifetime.start
+// CHECK-NEXT: [[SLOT_3:%.*]] = getelementptr inbounds [4 x i8*], [4 x i8*]* [[BUFFER]], i32 0, i32 3
+// CHECK-NEXT:  [[T0_AS_VOIDPTR:%.*]] = bitcast %swift.type* [[T0]] to i8*
+// CHECK-NEXT:  store i8* [[T0_AS_VOIDPTR]], i8** [[SLOT_3]]
+// CHECK-NEXT:  [[BUFFER_PTR:%.*]] = bitcast [4 x i8*]* [[BUFFER]] to i8**
+// CHECK-NEXT:   call %swift.type* @"$S17generic_metatypes8FourArgsVMa"(%swift.type* {{.*}} @"$S17generic_metatypes3FooVMf", {{.*}}, %swift.type* [[T0]], %swift.type* {{.*}} @"$S17generic_metatypes3FooVMf", {{.*}}, i8** [[BUFFER_PTR]]) [[NOUNWIND_ARGMEM:#[0-9]+]]
+// CHECK: call void @llvm.lifetime.end.p0i8
+
+// CHECK: define linkonce_odr hidden %swift.type* @"$S17generic_metatypes8FiveArgsVyAA3FooVAA3BarCAegEGMa"() [[NOUNWIND_READNONE_OPT]]
+// CHECK:   [[T0:%.*]] = call %swift.type* @"$S17generic_metatypes3BarCMa"()
+// CHECK:   call %swift.type* @"$S17generic_metatypes8FiveArgsVMa"(%swift.type* {{.*}} @"$S17generic_metatypes3FooVMf", {{.*}}, %swift.type* [[T0]], %swift.type* {{.*}} @"$S17generic_metatypes3FooVMf", {{.*}}, i8**
+
+// CHECK: define hidden %swift.type* @"$S17generic_metatypes8FiveArgsVMa"(%swift.type*, %swift.type*, %swift.type*, i8**) [[NOUNWIND_OPT:#[0-9]+]]
+// CHECK-NOT: alloc
+// CHECK:   call %swift.type* @swift_getGenericMetadata(%swift.type_descriptor* {{.*}} @"$S17generic_metatypes8FiveArgsVMn" {{.*}}, i8*
+// CHECK-NOT: call void @llvm.lifetime.end
+// CHECK:   ret %swift.type*
+
+// CHECK: attributes [[NOUNWIND_READNONE_OPT]] = { nounwind readnone "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "target-cpu"
+// CHECK: attributes [[NOUNWIND_OPT]] = { nounwind "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "target-cpu"
+// CHECK: attributes [[NOUNWIND_READNONE]] = { nounwind readnone }
+// CHECK: attributes [[NOUNWIND_ARGMEM]] = { inaccessiblemem_or_argmemonly nounwind }
diff --git a/test/IRGen/plus_zero_generic_metatypes_arm.swift b/test/IRGen/plus_zero_generic_metatypes_arm.swift
new file mode 100644
index 0000000..ad87734
--- /dev/null
+++ b/test/IRGen/plus_zero_generic_metatypes_arm.swift
@@ -0,0 +1,176 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %swift -target armv7-apple-ios7.0 -module-name generic_metatypes -emit-ir -parse-stdlib -primary-file %s | %FileCheck --check-prefix=CHECK --check-prefix=CHECK-32 %s
+// RUN: %swift -target arm64-apple-ios7.0 -emit-ir -module-name generic_metatypes -parse-stdlib -primary-file %s | %FileCheck --check-prefix=CHECK --check-prefix=CHECK-64 %s
+// RUN: %swift -target armv7-apple-tvos9.0 -emit-ir -module-name generic_metatypes -parse-stdlib -primary-file %s | %FileCheck --check-prefix=CHECK --check-prefix=CHECK-32 %s
+// RUN: %swift -target arm64-apple-tvos9.0 -emit-ir -module-name generic_metatypes -parse-stdlib -primary-file %s | %FileCheck --check-prefix=CHECK --check-prefix=CHECK-64 %s
+// RUN: %swift -target armv7k-apple-watchos2.0 -emit-ir -module-name generic_metatypes -parse-stdlib -primary-file %s | %FileCheck --check-prefix=CHECK --check-prefix=CHECK-32 %s
+
+// REQUIRES: CODEGENERATOR=ARM
+
+// CHECK: define hidden swiftcc %swift.type* [[GENERIC_TYPEOF:@"\$S17generic_metatypes0A6TypeofyxmxlF"]](%swift.opaque* noalias nocapture, %swift.type* [[TYPE:%.*]])
+func genericTypeof<T>(_ x: T) -> T.Type {
+  // CHECK: [[METATYPE:%.*]] = call %swift.type* @swift_getDynamicType(%swift.opaque* {{.*}}, %swift.type* [[TYPE]], i1 false)
+  // CHECK: ret %swift.type* [[METATYPE]]
+  return type(of: x)
+}
+
+struct Foo {}
+class Bar {}
+
+// CHECK-LABEL: define hidden swiftcc %swift.type* @"$S17generic_metatypes27remapToSubstitutedMetatypes{{.*}}"(%T17generic_metatypes3BarC*) {{.*}} {
+func remapToSubstitutedMetatypes(_ x: Foo, y: Bar)
+  -> (Foo.Type, Bar.Type)
+{
+  // CHECK: call swiftcc %swift.type* [[GENERIC_TYPEOF]](%swift.opaque* noalias nocapture undef, %swift.type* {{.*}} @"$S17generic_metatypes3FooVMf", {{.*}})
+  // CHECK: [[T0:%.*]] = call %swift.type* @"$S17generic_metatypes3BarCMa"()
+  // CHECK: [[BAR_META:%.*]] = call swiftcc %swift.type* [[GENERIC_TYPEOF]](%swift.opaque* noalias nocapture {{%.*}}, %swift.type* [[T0]])
+  // CHECK: ret %swift.type* [[BAR_META]]
+  return (genericTypeof(x), genericTypeof(y))
+}
+
+
+// CHECK-LABEL: define hidden swiftcc void @"$S17generic_metatypes23remapToGenericMetatypesyyF"()
+func remapToGenericMetatypes() {
+  // CHECK: [[T0:%.*]] = call %swift.type* @"$S17generic_metatypes3BarCMa"()
+  // CHECK: call swiftcc void @"$S17generic_metatypes0A9Metatypes{{.*}}"(%swift.type* {{.*}} @"$S17generic_metatypes3FooVMf", {{.*}} %swift.type* [[T0]], %swift.type* {{.*}} @"$S17generic_metatypes3FooVMf", {{.*}} %swift.type* [[T0]])
+  genericMetatypes(Foo.self, Bar.self)
+}
+
+func genericMetatypes<T, U>(_ t: T.Type, _ u: U.Type) {}
+
+protocol Bas {}
+
+// CHECK: define hidden swiftcc { %swift.type*, i8** } @"$S17generic_metatypes14protocolTypeof{{.*}}"(%T17generic_metatypes3BasP* noalias nocapture dereferenceable({{.*}}))
+func protocolTypeof(_ x: Bas) -> Bas.Type {
+  // CHECK: [[METADATA_ADDR:%.*]] = getelementptr inbounds %T17generic_metatypes3BasP, %T17generic_metatypes3BasP* [[X:%.*]], i32 0, i32 1
+  // CHECK: [[METADATA:%.*]] = load %swift.type*, %swift.type** [[METADATA_ADDR]]
+  // CHECK: [[BUFFER:%.*]] = getelementptr inbounds %T17generic_metatypes3BasP, %T17generic_metatypes3BasP* [[X]], i32 0, i32 0
+  // CHECK: [[VALUE_ADDR:%.*]] = call %swift.opaque* @__swift_project_boxed_opaque_existential_1({{.*}} [[BUFFER]], %swift.type* [[METADATA]])
+  // CHECK: [[METATYPE:%.*]] = call %swift.type* @swift_getDynamicType(%swift.opaque* [[VALUE_ADDR]], %swift.type* [[METADATA]], i1 true)
+  // CHECK: [[WTABLE_ADDR:%.*]] = getelementptr inbounds %T17generic_metatypes3BasP, %T17generic_metatypes3BasP* %0, i32 0, i32 2
+  // CHECK: [[WTABLE:%.*]] = load i8**, i8*** [[WTABLE_ADDR]]
+  // CHECK-NOT: call void @__swift_destroy_boxed_opaque_existential_1(%T17generic_metatypes3BasP* %0)
+  // CHECK: [[T0:%.*]] = insertvalue { %swift.type*, i8** } undef, %swift.type* [[METATYPE]], 0
+  // CHECK: [[T1:%.*]] = insertvalue { %swift.type*, i8** } [[T0]], i8** [[WTABLE]], 1
+  // CHECK: ret { %swift.type*, i8** } [[T1]]
+  return type(of: x)
+}
+
+struct Zim : Bas {}
+class Zang : Bas {}
+
+// CHECK-LABEL: define hidden swiftcc { %swift.type*, i8** } @"$S17generic_metatypes15metatypeErasureyAA3Bas_pXpAA3ZimVmF"() #0
+func metatypeErasure(_ z: Zim.Type) -> Bas.Type {
+  // CHECK: ret { %swift.type*, i8** } {{.*}} @"$S17generic_metatypes3ZimVMf", {{.*}} @"$S17generic_metatypes3ZimVAA3BasAAWP"
+  return z
+}
+
+// CHECK-LABEL: define hidden swiftcc { %swift.type*, i8** } @"$S17generic_metatypes15metatypeErasureyAA3Bas_pXpAA4ZangCmF"(%swift.type*) #0
+func metatypeErasure(_ z: Zang.Type) -> Bas.Type {
+  // CHECK: [[RET:%.*]] = insertvalue { %swift.type*, i8** } undef, %swift.type* %0, 0
+  // CHECK: [[RET2:%.*]] = insertvalue { %swift.type*, i8** } [[RET]], i8** getelementptr inbounds ([1 x i8*], [1 x i8*]* @"$S17generic_metatypes4ZangCAA3BasAAWP", i32 0, i32 0), 1
+  // CHECK: ret { %swift.type*, i8** } [[RET2]]
+  return z
+}
+
+struct OneArg<T> {}
+struct TwoArgs<T, U> {}
+struct ThreeArgs<T, U, V> {}
+struct FourArgs<T, U, V, W> {}
+struct FiveArgs<T, U, V, W, X> {}
+
+func genericMetatype<A>(_ x: A.Type) {}
+
+// CHECK-LABEL: define hidden swiftcc void @"$S17generic_metatypes20makeGenericMetatypesyyF"() {{.*}} {
+func makeGenericMetatypes() {
+  // CHECK: call %swift.type* @"$S17generic_metatypes6OneArgVyAA3FooVGMa"() [[NOUNWIND_READNONE:#[0-9]+]]
+  genericMetatype(OneArg<Foo>.self)
+
+  // CHECK: call %swift.type* @"$S17generic_metatypes7TwoArgsVyAA3FooVAA3BarCGMa"() [[NOUNWIND_READNONE]]
+  genericMetatype(TwoArgs<Foo, Bar>.self)
+
+  // CHECK: call %swift.type* @"$S17generic_metatypes9ThreeArgsVyAA3FooVAA3BarCAEGMa"() [[NOUNWIND_READNONE]]
+  genericMetatype(ThreeArgs<Foo, Bar, Foo>.self)
+
+  // CHECK: call %swift.type* @"$S17generic_metatypes8FourArgsVyAA3FooVAA3BarCAeGGMa"() [[NOUNWIND_READNONE]]
+  genericMetatype(FourArgs<Foo, Bar, Foo, Bar>.self)
+
+  // CHECK: call %swift.type* @"$S17generic_metatypes8FiveArgsVyAA3FooVAA3BarCAegEGMa"() [[NOUNWIND_READNONE]]
+  genericMetatype(FiveArgs<Foo, Bar, Foo, Bar, Foo>.self)
+}
+
+// CHECK: define linkonce_odr hidden %swift.type* @"$S17generic_metatypes6OneArgVyAA3FooVGMa"() [[NOUNWIND_READNONE_OPT:#[0-9]+]]
+// CHECK:   call %swift.type* @"$S17generic_metatypes6OneArgVMa"(%swift.type* {{.*}} @"$S17generic_metatypes3FooVMf", {{.*}}) [[NOUNWIND_READNONE:#[0-9]+]]
+
+// CHECK-LABEL: define hidden %swift.type* @"$S17generic_metatypes6OneArgVMa"(%swift.type*)
+// CHECK:   [[BUFFER:%.*]] = alloca { %swift.type* }
+// CHECK:   [[BUFFER_PTR:%.*]] = bitcast { %swift.type* }* [[BUFFER]] to i8*
+// CHECK:   call void @llvm.lifetime.start
+// CHECK:   [[BUFFER_ELT:%.*]] = getelementptr inbounds { %swift.type* }, { %swift.type* }* [[BUFFER]], i32 0, i32 0
+// CHECK:   store %swift.type* %0, %swift.type** [[BUFFER_ELT]]
+// CHECK:   [[BUFFER_PTR:%.*]] = bitcast { %swift.type* }* [[BUFFER]] to i8*
+// CHECK:   [[METADATA:%.*]] = call %swift.type* @swift_getGenericMetadata(%swift.type_descriptor* {{.*}} @"$S17generic_metatypes6OneArgVMn" {{.*}}, i8* [[BUFFER_PTR]])
+// CHECK:   [[BUFFER_PTR:%.*]] = bitcast { %swift.type* }* [[BUFFER]] to i8*
+// CHECK:   call void @llvm.lifetime.end
+// CHECK:   ret %swift.type* [[METADATA]]
+
+// CHECK: define linkonce_odr hidden %swift.type* @"$S17generic_metatypes7TwoArgsVyAA3FooVAA3BarCGMa"() [[NOUNWIND_READNONE_OPT]]
+// CHECK:   [[T0:%.*]] = call %swift.type* @"$S17generic_metatypes3BarCMa"()
+// CHECK:   call %swift.type* @"$S17generic_metatypes7TwoArgsVMa"(%swift.type* {{.*}} @"$S17generic_metatypes3FooVMf", {{.*}}, %swift.type* [[T0]])
+
+// CHECK-LABEL: define hidden %swift.type* @"$S17generic_metatypes7TwoArgsVMa"(%swift.type*, %swift.type*)
+// CHECK:   [[BUFFER:%.*]] = alloca { %swift.type*, %swift.type* }
+// CHECK:   [[BUFFER_PTR:%.*]] = bitcast { %swift.type*, %swift.type* }* [[BUFFER]] to i8*
+// CHECK:   call void @llvm.lifetime.start
+// CHECK:   [[BUFFER_ELT:%.*]] = getelementptr inbounds { %swift.type*, %swift.type* }, { %swift.type*, %swift.type* }* [[BUFFER]], i32 0, i32 0
+// CHECK:   store %swift.type* %0, %swift.type** [[BUFFER_ELT]]
+// CHECK:   [[BUFFER_ELT:%.*]] = getelementptr inbounds { %swift.type*, %swift.type* }, { %swift.type*, %swift.type* }* [[BUFFER]], i32 0, i32 1
+// CHECK:   store %swift.type* %1, %swift.type** [[BUFFER_ELT]]
+// CHECK:   [[BUFFER_PTR:%.*]] = bitcast { %swift.type*, %swift.type* }* [[BUFFER]] to i8*
+// CHECK:   [[METADATA:%.*]] = call %swift.type* @swift_getGenericMetadata(%swift.type_descriptor* {{.*}} @"$S17generic_metatypes7TwoArgsVMn" {{.*}}, i8* [[BUFFER_PTR]])
+// CHECK:   [[BUFFER_PTR:%.*]] = bitcast { %swift.type*, %swift.type* }* [[BUFFER]] to i8*
+// CHECK:   call void @llvm.lifetime.end
+// CHECK:   ret %swift.type* [[METADATA]]
+
+// CHECK: define linkonce_odr hidden %swift.type* @"$S17generic_metatypes9ThreeArgsVyAA3FooVAA3BarCAEGMa"() [[NOUNWIND_READNONE_OPT]]
+// CHECK:   [[T0:%.*]] = call %swift.type* @"$S17generic_metatypes3BarCMa"()
+// CHECK:   call %swift.type* @"$S17generic_metatypes9ThreeArgsVMa"(%swift.type* {{.*}} @"$S17generic_metatypes3FooVMf", {{.*}}, %swift.type* [[T0]], %swift.type* {{.*}} @"$S17generic_metatypes3FooVMf", {{.*}}) [[NOUNWIND_READNONE]]
+
+// CHECK-LABEL: define hidden %swift.type* @"$S17generic_metatypes9ThreeArgsVMa"(%swift.type*, %swift.type*, %swift.type*)
+// CHECK:   [[BUFFER:%.*]] = alloca { %swift.type*, %swift.type*, %swift.type* }
+// CHECK:   [[BUFFER_PTR:%.*]] = bitcast { %swift.type*, %swift.type*, %swift.type* }* [[BUFFER]] to i8*
+// CHECK:   call void @llvm.lifetime.start
+// CHECK:   [[BUFFER_ELT:%.*]] = getelementptr inbounds { %swift.type*, %swift.type*, %swift.type* }, { %swift.type*, %swift.type*, %swift.type* }* [[BUFFER]], i32 0, i32 0
+// CHECK:   store %swift.type* %0, %swift.type** [[BUFFER_ELT]]
+// CHECK:   [[BUFFER_ELT:%.*]] = getelementptr inbounds { %swift.type*, %swift.type*, %swift.type* }, { %swift.type*, %swift.type*, %swift.type* }* [[BUFFER]], i32 0, i32 1
+// CHECK:   store %swift.type* %1, %swift.type** [[BUFFER_ELT]]
+// CHECK:   [[BUFFER_ELT:%.*]] = getelementptr inbounds { %swift.type*, %swift.type*, %swift.type* }, { %swift.type*, %swift.type*, %swift.type* }* [[BUFFER]], i32 0, i32 2
+// CHECK:   store %swift.type* %2, %swift.type** [[BUFFER_ELT]]
+// CHECK:   [[BUFFER_PTR:%.*]] = bitcast { %swift.type*, %swift.type*, %swift.type* }* [[BUFFER]] to i8*
+// CHECK:   [[METADATA:%.*]] = call %swift.type* @swift_getGenericMetadata(%swift.type_descriptor* {{.*}} @"$S17generic_metatypes9ThreeArgsVMn" {{.*}}, i8* [[BUFFER_PTR]])
+// CHECK:   [[BUFFER_PTR:%.*]] = bitcast { %swift.type*, %swift.type*, %swift.type* }* [[BUFFER]] to i8*
+// CHECK:   call void @llvm.lifetime.end
+// CHECK:   ret %swift.type* [[METADATA]]
+
+// CHECK: define linkonce_odr hidden %swift.type* @"$S17generic_metatypes8FourArgsVyAA3FooVAA3BarCAeGGMa"() [[NOUNWIND_READNONE_OPT]]
+// CHECK:   [[T0:%.*]] = call %swift.type* @"$S17generic_metatypes3BarCMa"()
+// CHECK:   call %swift.type* @"$S17generic_metatypes8FourArgsVMa"(%swift.type* {{.*}} @"$S17generic_metatypes3FooVMf", {{.*}}, %swift.type* [[T0]], %swift.type* {{.*}} @"$S17generic_metatypes3FooVMf", {{.*}}, i8**
+
+// CHECK-LABEL: define hidden %swift.type* @"$S17generic_metatypes8FourArgsVMa"(%swift.type*, %swift.type*, %swift.type*, i8**)
+// CHECK-NOT: alloc
+// CHECK:   call %swift.type* @swift_getGenericMetadata(
+// CHECK-NOT: call void @llvm.lifetime.end
+// CHECK:   ret %swift.type*
+
+// CHECK: define linkonce_odr hidden %swift.type* @"$S17generic_metatypes8FiveArgsVyAA3FooVAA3BarCAegEGMa"() [[NOUNWIND_READNONE_OPT]]
+// CHECK:   [[T0:%.*]] = call %swift.type* @"$S17generic_metatypes3BarCMa"()
+// CHECK:   call %swift.type* @"$S17generic_metatypes8FiveArgsVMa"(%swift.type* {{.*}} @"$S17generic_metatypes3FooVMf", {{.*}}, %swift.type* [[T0]], %swift.type* {{.*}} @"$S17generic_metatypes3FooVMf", {{.*}}, i8**
+
+// CHECK-LABEL: define hidden %swift.type* @"$S17generic_metatypes8FiveArgsVMa"(%swift.type*, %swift.type*, %swift.type*, i8**)
+// CHECK-NOT: alloca
+// CHECK:   call %swift.type* @swift_getGenericMetadata(%swift.type_descriptor* {{.*}} @"$S17generic_metatypes8FiveArgsVMn" {{.*}}, i8*
+// CHECK-NOT:   call void @llvm.lifetime.end
+// CHECK:   ret %swift.type*
+
+// CHECK: attributes [[NOUNWIND_READNONE_OPT]] = { nounwind readnone "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "target-cpu"
+// CHECK: attributes [[NOUNWIND_READNONE]] = { nounwind readnone }
diff --git a/test/IRGen/plus_zero_generic_tuples.swift b/test/IRGen/plus_zero_generic_tuples.swift
new file mode 100644
index 0000000..c45781d
--- /dev/null
+++ b/test/IRGen/plus_zero_generic_tuples.swift
@@ -0,0 +1,120 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -assume-parsing-unqualified-ownership-sil -emit-ir -primary-file %s | %FileCheck %s
+
+// Make sure that optimization passes don't choke on storage types for generic tuples
+// RUN: %target-swift-frontend -assume-parsing-unqualified-ownership-sil -emit-ir -O %s
+
+// REQUIRES: CPU=x86_64
+
+// CHECK: [[TYPE:%swift.type]] = type {
+// CHECK: [[OPAQUE:%swift.opaque]] = type opaque
+// CHECK: [[TUPLE_TYPE:%swift.tuple_type]] = type { [[TYPE]], i64, i8*, [0 x %swift.tuple_element_type] }
+// CHECK: %swift.tuple_element_type = type { [[TYPE]]*, i64 }
+
+func dup<T>(_ x: T) -> (T, T) { var x = x; return (x,x) }
+// CHECK:    define hidden swiftcc void @"$S14generic_tuples3dupyx_xtxlF"(%swift.opaque* noalias nocapture, %swift.opaque* noalias nocapture, %swift.opaque* noalias nocapture, %swift.type* %T)
+// CHECK:    entry:
+//   Allocate a local variable for 'x'.
+// CHECK: [[TYPE_ADDR:%.*]] = bitcast %swift.type* %T to i8***
+// CHECK: [[VWT_ADDR:%.*]] = getelementptr inbounds i8**, i8*** [[TYPE_ADDR]], i64 -1
+// CHECK: [[VWT:%.*]] = load i8**, i8*** [[VWT_ADDR]]
+// CHECK: [[SIZE_WITNESS_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 9
+// CHECK: [[SIZE_WITNESS:%.*]] = load i8*, i8** [[SIZE_WITNESS_ADDR]]
+// CHECK: [[SIZE:%.*]] = ptrtoint i8* [[SIZE_WITNESS]]
+// CHECK: [[X_ALLOCA:%.*]] = alloca i8, {{.*}} [[SIZE]], align 16
+// CHECK: [[X_TMP:%.*]] = bitcast i8* [[X_ALLOCA]] to %swift.opaque*
+// Debug info shadow copy.
+// CHECK-NEXT: store i8* [[X_ALLOCA]]
+// CHECK-NEXT: [[WITNESS_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 2
+// CHECK-NEXT: [[WITNESS:%.*]] = load i8*, i8** [[WITNESS_ADDR]], align 8
+// CHECK-NEXT: [[INITIALIZE_WITH_COPY:%.*]] = bitcast i8* [[WITNESS]] to [[OPAQUE]]* ([[OPAQUE]]*, [[OPAQUE]]*, [[TYPE]]*)*
+// CHECK-NEXT: [[X:%.*]] = call [[OPAQUE]]* [[INITIALIZE_WITH_COPY]]([[OPAQUE]]* noalias [[X_TMP]], [[OPAQUE]]* noalias {{.*}}, [[TYPE]]* %T)
+//   Copy 'x' into the first result.
+// CHECK-NEXT: call [[OPAQUE]]* [[INITIALIZE_WITH_COPY]]([[OPAQUE]]* noalias %0, [[OPAQUE]]* noalias [[X_TMP]], [[TYPE]]* %T)
+//   Copy 'x' into the second element.
+// CHECK-NEXT: [[WITNESS_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 4
+// CHECK-NEXT: [[WITNESS:%.*]] = load i8*, i8** [[WITNESS_ADDR]], align 8
+// CHECK-NEXT: [[TAKE_FN:%.*]] = bitcast i8* [[WITNESS]] to [[OPAQUE]]* ([[OPAQUE]]*, [[OPAQUE]]*, [[TYPE]]*)*
+// CHECK-NEXT: call [[OPAQUE]]* [[TAKE_FN]]([[OPAQUE]]* noalias %1, [[OPAQUE]]* noalias [[X_TMP]], [[TYPE]]* %T)
+
+struct S {}
+
+
+func callDup(_ s: S) { _ = dup(s) }
+// CHECK-LABEL: define hidden swiftcc void @"$S14generic_tuples7callDupyyAA1SVF"()
+// CHECK-NEXT: entry:
+// CHECK-NEXT: call swiftcc void @"$S14generic_tuples3dupyx_xtxlF"({{.*}} undef, {{.*}} undef, %swift.type* {{.*}} @"$S14generic_tuples1SVMf", {{.*}})
+// CHECK-NEXT: ret void
+
+class C {}
+
+func dupC<T : C>(_ x: T) -> (T, T) { return (x, x) }
+// CHECK-LABEL: define hidden swiftcc { %T14generic_tuples1CC*, %T14generic_tuples1CC* } @"$S14generic_tuples4dupCyx_xtxAA1CCRbzlF"(%T14generic_tuples1CC*, %swift.type* %T)
+// CHECK-NEXT: entry:
+// CHECK:      [[REF:%.*]] = bitcast %T14generic_tuples1CC* %0 to %swift.refcounted*
+// CHECK-NEXT: call %swift.refcounted* @swift_retain(%swift.refcounted* returned [[REF]])
+// CHECK-NEXT: [[REF:%.*]] = bitcast %T14generic_tuples1CC* %0 to %swift.refcounted*
+// CHECK-NEXT: call %swift.refcounted* @swift_retain(%swift.refcounted* returned [[REF]])
+// CHECK-NEXT: [[TUP1:%.*]] = insertvalue { %T14generic_tuples1CC*, %T14generic_tuples1CC* } undef, %T14generic_tuples1CC* %0, 0
+// CHECK-NEXT: [[TUP2:%.*]] = insertvalue { %T14generic_tuples1CC*, %T14generic_tuples1CC* } [[TUP1:%.*]], %T14generic_tuples1CC* %0, 1
+// CHECK-NEXT: ret { %T14generic_tuples1CC*, %T14generic_tuples1CC* } [[TUP2]]
+
+func callDupC(_ c: C) { _ = dupC(c) }
+// CHECK-LABEL: define hidden swiftcc void @"$S14generic_tuples8callDupCyyAA1CCF"(%T14generic_tuples1CC*)
+// CHECK-NEXT: entry:
+// CHECK-NEXT: [[METATYPE:%.*]] = call %swift.type* @"$S14generic_tuples1CCMa"()
+// CHECK-NEXT: [[TUPLE:%.*]] = call swiftcc { %T14generic_tuples1CC*, %T14generic_tuples1CC* } @"$S14generic_tuples4dupCyx_xtxAA1CCRbzlF"(%T14generic_tuples1CC* %0, %swift.type* [[METATYPE]])
+// CHECK-NEXT: [[LEFT:%.*]] = extractvalue { %T14generic_tuples1CC*, %T14generic_tuples1CC* } [[TUPLE]], 0
+// CHECK-NEXT: [[RIGHT:%.*]] = extractvalue { %T14generic_tuples1CC*, %T14generic_tuples1CC* } [[TUPLE]], 1
+// CHECK-NEXT: [[LEFT_CAST:%.*]] = bitcast %T14generic_tuples1CC* [[LEFT]] to %swift.refcounted*
+// CHECK-NEXT: call %swift.refcounted* @swift_retain(%swift.refcounted* returned [[LEFT_CAST]]
+// CHECK-NEXT: [[RIGHT_CAST:%.*]] = bitcast %T14generic_tuples1CC* [[RIGHT]] to %swift.refcounted*
+// CHECK-NEXT: call %swift.refcounted* @swift_retain(%swift.refcounted* returned [[RIGHT_CAST]]
+// CHECK-NEXT: call void bitcast (void (%swift.refcounted*)* @swift_release to void (%T14generic_tuples1CC*)*)(%T14generic_tuples1CC* [[LEFT]])
+// CHECK-NEXT: call void bitcast (void (%swift.refcounted*)* @swift_release to void (%T14generic_tuples1CC*)*)(%T14generic_tuples1CC* [[RIGHT]])
+// CHECK-NEXT: call void bitcast (void (%swift.refcounted*)* @swift_release to void (%T14generic_tuples1CC*)*)(%T14generic_tuples1CC* [[RIGHT]])
+// CHECK-NEXT: call void bitcast (void (%swift.refcounted*)* @swift_release to void (%T14generic_tuples1CC*)*)(%T14generic_tuples1CC* [[LEFT]])
+// CHECK-NEXT: ret void
+
+// CHECK: define hidden swiftcc i64 @"$S14generic_tuples4lumpySi_xxtxlF"(%swift.opaque* noalias nocapture, %swift.opaque* noalias nocapture, %swift.opaque* noalias nocapture, %swift.type* %T)
+func lump<T>(_ x: T) -> (Int, T, T) { return (0,x,x) }
+// CHECK: define hidden swiftcc { i64, i64 } @"$S14generic_tuples5lump2ySi_SixtxlF"(%swift.opaque* noalias nocapture, %swift.opaque* noalias nocapture, %swift.type* %T)
+func lump2<T>(_ x: T) -> (Int, Int, T) { return (0,0,x) }
+// CHECK: define hidden swiftcc void @"$S14generic_tuples5lump3yx_xxtxlF"(%swift.opaque* noalias nocapture, %swift.opaque* noalias nocapture, %swift.opaque* noalias nocapture, %swift.opaque* noalias nocapture, %swift.type* %T)
+func lump3<T>(_ x: T) -> (T, T, T) { return (x,x,x) }
+// CHECK: define hidden swiftcc i64 @"$S14generic_tuples5lump4yx_SixtxlF"(%swift.opaque* noalias nocapture, %swift.opaque* noalias nocapture, %swift.opaque* noalias nocapture, %swift.type* %T)
+func lump4<T>(_ x: T) -> (T, Int, T) { return (x,0,x) }
+
+// CHECK: define hidden swiftcc i64 @"$S14generic_tuples6unlumpyS2i_xxt_tlF"(i64, %swift.opaque* noalias nocapture, %swift.opaque* noalias nocapture, %swift.type* %T)
+func unlump<T>(_ x: (Int, T, T)) -> Int { return x.0 }
+// CHECK: define hidden swiftcc void @"$S14generic_tuples7unlump1yxSi_xxt_tlF"(%swift.opaque* noalias nocapture sret, i64, %swift.opaque* noalias nocapture, %swift.opaque* noalias nocapture, %swift.type* %T)
+func unlump1<T>(_ x: (Int, T, T)) -> T { return x.1 }
+// CHECK: define hidden swiftcc void @"$S14generic_tuples7unlump2yxx_Sixt_tlF"(%swift.opaque* noalias nocapture sret, %swift.opaque* noalias nocapture, i64, %swift.opaque* noalias nocapture, %swift.type* %T)
+func unlump2<T>(_ x: (T, Int, T)) -> T { return x.0 }
+// CHECK: define hidden swiftcc i64 @"$S14generic_tuples7unlump3ySix_Sixt_tlF"(%swift.opaque* noalias nocapture, i64, %swift.opaque* noalias nocapture, %swift.type* %T)
+func unlump3<T>(_ x: (T, Int, T)) -> Int { return x.1 }
+
+
+// CHECK: tuple_existentials
+func tuple_existentials() {
+  // Empty tuple:
+  var a : Any = ()
+  // CHECK: store %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* @"$SytN", i32 0, i32 1),
+
+  // 2 element tuple
+  var t2 = (1,2.0)
+  a = t2
+  // CHECK: call %swift.type* @swift_getTupleTypeMetadata2({{.*}}@"$SSiN{{.*}}",{{.*}}@"$SSdN{{.*}}", i8* null, i8** null)
+
+
+  // 3 element tuple
+  var t3 = ((),(),())
+  a = t3
+  // CHECK: call %swift.type* @swift_getTupleTypeMetadata3({{.*}}@"$SytN{{.*}},{{.*}}@"$SytN{{.*}},{{.*}}@"$SytN{{.*}}, i8* null, i8** null)
+
+  // 4 element tuple
+  var t4 = (1,2,3,4)
+  a = t4
+  // CHECK: call %swift.type* @swift_getTupleTypeMetadata(i64 4, {{.*}}, i8* null, i8** null)
+}
+
diff --git a/test/IRGen/plus_zero_keypaths.sil b/test/IRGen/plus_zero_keypaths.sil
new file mode 100644
index 0000000..7cafbd0
--- /dev/null
+++ b/test/IRGen/plus_zero_keypaths.sil
@@ -0,0 +1,438 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %empty-directory(%t)
+// -- Convert <i32 0x...> constants to decimal constants that LLVM will print
+// RUN: %utils/chex.py < %s > %t/keypaths.sil
+// RUN: %target-swift-frontend -emit-ir %s | %FileCheck %t/keypaths.sil --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize --check-prefix=CHECK-%target-os
+
+sil_stage canonical
+import Swift
+
+struct S: Hashable {
+  var x: Int
+  let y: String
+  var z: C
+  var reabstracted: () -> ()
+
+  var hashValue: Int { get }
+  static func ==(_: S, _: S) -> Bool
+}
+class C: Hashable {
+  final var x: Int
+  final let y: String
+  final var z: S
+  var w: Int { get set }
+
+  init()
+
+  var hashValue: Int { get }
+  static func ==(_: C, _: C) -> Bool
+}
+
+struct G<T> {
+  var x: T
+  subscript<U: Hashable>(x: U) -> T { get set }
+}
+
+sil_vtable C {}
+
+// CHECK: %TSi = type <{ [[WORD:i.*]] }>
+
+// -- %a: S.x
+// CHECK: [[KP_A:@keypath.*]] = private global <{ {{.*}} }> <{
+// CHECK-SAME: [[WORD]] 0,
+// CHECK-SAME: %swift.type* (i8*)*
+// CHECK-SAME: %swift.type* (i8*)*
+//               -- instantiable in-line, size 4
+// CHECK-SAME: <i32 0x8000_0004>,
+// CHECK-64-SAME: [4 x i8] zeroinitializer,
+// -- offset of S.x
+// CHECK-SAME: i32 0 }>
+
+// -- %b: S.y
+// CHECK: [[KP_B:@keypath.*]] = private global <{ {{.*}} }> <{
+// CHECK-SAME: [[WORD]] 0,
+// CHECK-SAME: %swift.type* (i8*)*
+// CHECK-SAME: %swift.type* (i8*)*
+//               -- instantiable in-line, size 4
+// CHECK-SAME: <i32 0x8000_0004>,
+// CHECK-64-SAME: [4 x i8] zeroinitializer,
+// -- offset of S.y
+// CHECK-32-SAME: i32 4 }>
+// CHECK-64-SAME: i32 8 }>
+
+// -- %c: S.z
+// CHECK: [[KP_C:@keypath.*]] = private global <{ {{.*}} }> <{
+// CHECK-SAME: [[WORD]] 0,
+// CHECK-SAME: %swift.type* (i8*)*
+// CHECK-SAME: %swift.type* (i8*)*
+//               -- instantiable in-line, size 4
+// CHECK-SAME: <i32 0x8000_0004>,
+// CHECK-64-SAME: [4 x i8] zeroinitializer,
+// -- offset of S.z
+// CHECK-32-SAME: i32 16 }>
+// CHECK-64-SAME: i32 24 }>
+
+// -- %d: C.x
+// CHECK: [[KP_D:@keypath.*]] = private global <{ {{.*}} }> <{
+// CHECK-SAME: [[WORD]] 0,
+// CHECK-SAME: %swift.type* (i8*)*
+// CHECK-SAME: %swift.type* (i8*)*
+//               -- instantiable in-line, size 4
+// CHECK-SAME: <i32 0x8000_0004>,
+// CHECK-64-SAME: [4 x i8] zeroinitializer,
+// -- 0x0200_0000 (class) + offset of C.x
+// CHECK-32-SAME: <i32 0x0200_0008> }>
+// CHECK-64-SAME: <i32 0x0200_0010> }>
+
+// -- %e: C.y
+// CHECK: [[KP_E:@keypath.*]] = private global <{ {{.*}} }> <{
+// CHECK-SAME: [[WORD]] 0,
+// CHECK-SAME: %swift.type* (i8*)*
+// CHECK-SAME: %swift.type* (i8*)*
+//               -- instantiable in-line, size 4
+// CHECK-SAME: <i32 0x8000_0004>,
+// CHECK-64-SAME: [4 x i8] zeroinitializer,
+// -- 0x0200_0000 (class) + offset of C.y
+// CHECK-32-SAME: <i32 0x0200_000c> }>
+// CHECK-64-SAME: <i32 0x0200_0018> }>
+
+// -- %f: C.z
+// CHECK: [[KP_F:@keypath.*]] = private global <{ {{.*}} }> <{
+// CHECK-SAME: [[WORD]] 0,
+// CHECK-SAME: %swift.type* (i8*)*
+// CHECK-SAME: %swift.type* (i8*)*
+//               -- instantiable in-line, size 4
+// CHECK-SAME: <i32 0x8000_0004>,
+// CHECK-64-SAME: [4 x i8] zeroinitializer,
+// -- 0x0200_0000 (class) + offset of C.z
+// CHECK-32-SAME: <i32 0x0200_0018> }>
+// CHECK-64-SAME: <i32 0x0200_0028> }>
+
+// -- %g: S.z.x
+// CHECK: [[KP_G:@keypath.*]] = private global <{ {{.*}} }> <{
+// CHECK-SAME: [[WORD]] 0,
+// CHECK-SAME: %swift.type* (i8*)*
+// CHECK-SAME: %swift.type* (i8*)*
+//                  -- instantiable in-line, size 12
+// CHECK-32-SAME: <i32 0x8000_000c>,
+//                  -- instantiable in-line, size 20
+// CHECK-64-SAME: <i32 0x8000_0014>,
+// CHECK-64-SAME: [4 x i8] zeroinitializer,
+// -- offset of S.z
+// CHECK-32-SAME: i32 16,
+// CHECK-64-SAME: i32 24,
+// CHECK-64-SAME: [4 x i8] zeroinitializer,
+// CHECK: %swift.type* (i8*)*
+// -- 0x0200_0000 (class) + offset of C.x
+// CHECK-32-SAME: <i32 0x0200_0008> }>
+// CHECK-64-SAME: <i32 0x0200_0010> }>
+
+// -- %h: C.z.x
+// CHECK: [[KP_H:@keypath.*]] = private global <{ {{.*}} }> <{
+// CHECK-SAME: [[WORD]] 0,
+// CHECK-SAME: %swift.type* (i8*)*
+// CHECK-SAME: %swift.type* (i8*)*
+//                  -- instantiable in-line, size 12
+// CHECK-32-SAME: <i32 0x8000_000c>,
+//                  -- instantiable in-line, size 20
+// CHECK-64-SAME: <i32 0x8000_0014>,
+// CHECK-64-SAME: [4 x i8] zeroinitializer,
+// -- 0x0200_0000 (class) + offset of C.z
+// CHECK-32-SAME: <i32 0x0200_0018>,
+// CHECK-64-SAME: <i32 0x0200_0028>,
+// CHECK-64-SAME: [4 x i8] zeroinitializer,
+// CHECK: %swift.type* (i8*)*
+// -- offset of S.x
+// CHECK-SAME: i32 0 }>
+
+// -- %k: computed
+// CHECK: [[KP_K:@keypath.*]] = private global <{ {{.*}} }> <{
+// CHECK-SAME: [[WORD]] 0,
+// CHECK-SAME: %swift.type* (i8*)*
+// CHECK-SAME: %swift.type* (i8*)*
+//              -- instantiable in-line, size 24
+// CHECK-64-SAME: <i32 0x8000_0018>,
+// CHECK-64-SAME: [4 x i8] zeroinitializer,
+//              -- instantiable in-line, size 12
+// CHECK-32-SAME: <i32 0x8000_000c>,
+// -- computed, get-only, identified by function pointer, no args
+// CHECK-SAME: <i32 0x0100_0000>,
+// CHECK-64-SAME: [4 x i8] zeroinitializer,
+// CHECK-SAME: void ()* @k_id,
+// CHECK-SAME: void (%TSi*, %T8keypaths1SV*)* @k_get }>
+
+// -- %l: computed
+// CHECK: [[KP_L:@keypath.*]] = private global <{ {{.*}} }> <{
+// CHECK-SAME: [[WORD]] 0,
+// CHECK-SAME: %swift.type* (i8*)*
+// CHECK-SAME: %swift.type* (i8*)*
+//              -- instantiable in-line, size 32
+// CHECK-64-SAME: <i32 0x8000_0020>,
+// CHECK-64-SAME: [4 x i8] zeroinitializer,
+//              -- instantiable in-line, size 16
+// CHECK-32-SAME: <i32 0x8000_0010>,
+// -- computed, settable, nonmutating, identified by vtable, no args
+// CHECK-SAME: <i32 0x0150_0000>,
+// CHECK-64-SAME: [4 x i8] zeroinitializer,
+// CHECK-SAME: [[WORD]]
+// CHECK-SAME: void (%TSi*, %T8keypaths1CC**)* @l_get,
+// CHECK-SAME: void (%TSi*, %T8keypaths1CC**)* @l_set }>
+
+// -- %m: computed
+// CHECK: [[KP_M:@keypath.*]] = private global <{ {{.*}} }> <{
+// CHECK-SAME: [[WORD]] 0,
+// CHECK-SAME: %swift.type* (i8*)*
+// CHECK-SAME: %swift.type* (i8*)*
+//              -- instantiable in-line, size 32
+// CHECK-64-SAME: <i32 0x8000_0020>,
+// CHECK-64-SAME: [4 x i8] zeroinitializer,
+//              -- instantiable in-line, size 16
+// CHECK-32-SAME: <i32 0x8000_0010>,
+// -- computed, settable, nonmutating, identified by property offset, no args
+// CHECK-SAME: <i32 0x01e0_0000>,
+// CHECK-64-SAME: [4 x i8] zeroinitializer,
+// CHECK-SAME: [[WORD]]
+// CHECK-SAME: void (%swift.function*, %T8keypaths1SV*)* @m_get,
+// CHECK-SAME: void (%swift.function*, %T8keypaths1SV*)* @m_set }>
+
+
+// -- %i: Gen<A>.x
+// CHECK: [[KP_I:@keypath.*]] = private global <{ {{.*}} }> <{
+// CHECK-SAME: [[WORD]] 0,
+// CHECK-SAME: %swift.type* (i8*)* [[I_GET_GEN_A_A:@[a-z_.0-9]+]],
+// CHECK-SAME: %swift.type* (i8*)* [[I_GET_A:@[a-z_.0-9]+]],
+//             -- size 8
+// CHECK-SAME: i32 8,
+// CHECK-64-SAME: [4 x i8] zeroinitializer,
+//             -- struct with runtime-resolved offset
+// CHECK-SAME: <i32 0x00fffffe>,
+// CHECK-32-SAME: i32 16 }>
+// CHECK-64-SAME: i32 32 }>
+
+// -- %j: Gen<A>.y
+// CHECK: [[KP_J:@keypath.*]] = private global <{ {{.*}} }> <{
+// CHECK-SAME: [[WORD]] 0,
+// CHECK-SAME: %swift.type* (i8*)* [[J_GET_GEN_A_A:@[a-z_.0-9]+]],
+// CHECK-SAME: %swift.type* (i8*)* [[J_GET_A:@[a-z_.0-9]+]],
+//             -- size 8
+// CHECK-SAME: i32 8,
+// CHECK-64-SAME: [4 x i8] zeroinitializer,
+//             -- struct with runtime-resolved offset
+// CHECK-SAME: <i32 0x00fffffe>,
+// CHECK-32-SAME: i32 20 }>
+// CHECK-64-SAME: i32 40 }>
+
+// CHECK-LABEL: define{{( protected)?}} swiftcc void @stored_property_fixed_offsets()
+sil @stored_property_fixed_offsets : $@convention(thin) () -> () {
+entry:
+  // CHECK: call %swift.refcounted* @swift_getKeyPath(i8* bitcast ({{.*}} [[KP_A]] to i8*), i8* undef)
+  %a = keypath $KeyPath<S, Int>, (root $S; stored_property #S.x : $Int)
+  // CHECK: call %swift.refcounted* @swift_getKeyPath(i8* bitcast ({{.*}} [[KP_B]] to i8*), i8* undef)
+  %b = keypath $KeyPath<S, String>, (root $S; stored_property #S.y : $String)
+  // CHECK: call %swift.refcounted* @swift_getKeyPath(i8* bitcast ({{.*}} [[KP_C]] to i8*), i8* undef)
+  %c = keypath $KeyPath<S, C>, (root $S; stored_property #S.z : $C)
+
+  // CHECK: call %swift.refcounted* @swift_getKeyPath(i8* bitcast ({{.*}} [[KP_D]] to i8*), i8* undef)
+  %d = keypath $KeyPath<C, Int>, (root $C; stored_property #C.x : $Int)
+  // CHECK: call %swift.refcounted* @swift_getKeyPath(i8* bitcast ({{.*}} [[KP_E]] to i8*), i8* undef)
+  %e = keypath $KeyPath<C, String>, (root $C; stored_property #C.y : $String)
+  // CHECK: call %swift.refcounted* @swift_getKeyPath(i8* bitcast ({{.*}} [[KP_F]] to i8*), i8* undef)
+  %f = keypath $KeyPath<C, S>, (root $C; stored_property #C.z : $S)
+
+  // CHECK: call %swift.refcounted* @swift_getKeyPath(i8* bitcast ({{.*}} [[KP_G]] to i8*), i8* undef)
+  %g = keypath $KeyPath<S, Int>, (root $S; stored_property #S.z : $C; stored_property #C.x : $Int)
+  // CHECK: call %swift.refcounted* @swift_getKeyPath(i8* bitcast ({{.*}} [[KP_H]] to i8*), i8* undef)
+  %h = keypath $KeyPath<C, Int>, (root $C; stored_property #C.z : $S; stored_property #S.x : $Int)
+
+  %k = keypath $KeyPath<S, Int>, (root $S; gettable_property $Int, id @k_id : $@convention(thin) () -> (), getter @k_get : $@convention(thin) (@in_guaranteed S) -> @out Int)
+  %l = keypath $KeyPath<C, Int>, (root $C; settable_property $Int, id #C.w!getter.1, getter @l_get : $@convention(thin) (@in_guaranteed C) -> @out Int, setter @l_set : $@convention(thin) (@in_guaranteed Int, @in_guaranteed C) -> ())
+  %m = keypath $KeyPath<S, () -> ()>, (root $S; settable_property $() -> (), id ##S.reabstracted, getter @m_get : $@convention(thin) (@in_guaranteed S) -> @out @callee_guaranteed (@in_guaranteed ()) -> @out (), setter @m_set : $@convention(thin) (@in_guaranteed @callee_guaranteed (@in_guaranteed ()) -> @out (), @inout S) -> ())
+
+  return undef : $()
+}
+
+sil @k_id : $@convention(thin) () -> ()
+sil @k_get : $@convention(thin) (@in_guaranteed S) -> @out Int
+
+sil @l_get : $@convention(thin) (@in_guaranteed C) -> @out Int
+sil @l_set : $@convention(thin) (@in_guaranteed Int, @in_guaranteed C) -> ()
+
+sil @m_get : $@convention(thin) (@in_guaranteed S) -> @out @callee_guaranteed (@in_guaranteed ()) -> @out ()
+sil @m_set : $@convention(thin) (@in_guaranteed @callee_guaranteed (@in_guaranteed ()) -> @out (), @inout S) -> ()
+
+struct Gen<T, U> {
+  var x: T
+  var y: U
+}
+
+struct Foo<T> {
+  var foo: T
+}
+
+// CHECK-LABEL: define{{( protected)?}} swiftcc void @stored_property_generics(%swift.type* %T, %swift.type* %U)
+sil @stored_property_generics : $@convention(thin) <T, U> () -> () {
+entry:
+  // CHECK: [[PTR:%.*]] = bitcast i8* [[ARGS:%.*]] to
+  // CHECK: store %swift.type* %T, %swift.type** [[PTR]]
+  // CHECK: call %swift.refcounted* @swift_getKeyPath(i8* bitcast ({{.*}} [[KP_I]] to i8*), i8* [[ARGS]])
+  %i = keypath $KeyPath<Gen<T,T>, T>, <A> (root $Gen<A, A>; stored_property #Gen.x : $A) <T>
+
+  // CHECK: [[PTR:%.*]] = bitcast i8* [[ARGS:%.*]] to
+  // CHECK: store %swift.type* %U, %swift.type** [[PTR]]
+  // CHECK: call %swift.refcounted* @swift_getKeyPath(i8* bitcast ({{.*}} [[KP_J]] to i8*), i8* [[ARGS]])
+  %j = keypath $KeyPath<Gen<U,U>, U>, <A> (root $Gen<A, A>; stored_property #Gen.y : $A) <U>
+
+  // CHECK: [[PTR:%.*]] = bitcast i8* [[ARGS:%.*]] to
+  // CHECK: [[FOO_T:%.*]] = call %swift.type* @"$S8keypaths3FooVMa"(%swift.type* %T)
+  // CHECK: store %swift.type* [[FOO_T]], %swift.type** [[PTR]]
+  // CHECK: call %swift.refcounted* @swift_getKeyPath(i8* bitcast ({{.*}} [[KP_I]] to i8*), i8* [[ARGS]])
+  %i2 = keypath $KeyPath<Gen<Foo<T>,Foo<T>>, Foo<T>>, <A> (root $Gen<A, A>; stored_property #Gen.x : $A) <Foo<T>>
+
+  return undef : $()
+}
+
+// CHECK: define private %swift.type* [[I_GET_GEN_A_A]](i8*)
+// CHECK:   [[BUF:%.*]] = bitcast i8* %0
+// CHECK:   [[A:%.*]] = load %swift.type*, %swift.type** [[BUF]]
+// CHECK:   [[GEN:%.*]] = call %swift.type* @"$S8keypaths3GenVMa"(%swift.type* [[A]], %swift.type* [[A]])
+// CHECK:   ret %swift.type* [[GEN]]
+
+
+// CHECK: define private %swift.type* [[I_GET_A]](i8*)
+// CHECK:   [[BUF:%.*]] = bitcast i8* %0
+// CHECK:   [[A:%.*]] = load %swift.type*, %swift.type** [[BUF]]
+// CHECK:   ret %swift.type* [[A]]
+
+// CHECK-LABEL: define{{( protected)?}} swiftcc void @computed_property_generics
+sil @computed_property_generics : $@convention(thin) <T, U> () -> () {
+entry:
+  %n = keypath $WritableKeyPath<T, U>, <UUU, TTT> (root $TTT; settable_property $UUU, id @n_get : $@convention(thin) <UU, TT> (@in_guaranteed TT) -> @out UU, getter @n_get : $@convention(thin) <UU, TT> (@in_guaranteed TT) -> @out UU, setter @n_set : $@convention(thin) <UU, TT> (@in_guaranteed UU, @in_guaranteed TT) -> ()) <U, T>
+
+  return undef : $()
+}
+
+sil @n_get : $@convention(thin) <UU, TT> (@in_guaranteed TT) -> @out UU
+sil @n_set : $@convention(thin) <UU, TT> (@in_guaranteed UU, @in_guaranteed TT) -> ()
+
+sil @computed_property_indices : $@convention(thin) (C, S, C, S, C, S) -> () {
+entry(%0 : $C, %1 : $S, %2 : $C, %3 : $S, %4 : $C, %5 : $S):
+  %o = keypath $WritableKeyPath<S, C>, (
+    root $S;
+    settable_property $C,
+      id @o_get : $@convention(thin) (@in_guaranteed S, UnsafeRawPointer) -> @out C,
+      getter @o_get : $@convention(thin) (@in_guaranteed S, UnsafeRawPointer) -> @out C,
+      setter @o_set : $@convention(thin) (@in_guaranteed C, @in_guaranteed S, UnsafeRawPointer) -> (),
+      indices [%$0 : $C : $C],
+      indices_equals @o_equals : $@convention(thin) (UnsafeRawPointer, UnsafeRawPointer) -> Bool,
+      indices_hash @o_hash : $@convention(thin) (UnsafeRawPointer) -> Int
+  ) (%0)
+  %p = keypath $WritableKeyPath<S, C>, (
+    root $S;
+    settable_property $C,
+      id @o_get : $@convention(thin) (@in_guaranteed S, UnsafeRawPointer) -> @out C,
+      getter @o_get : $@convention(thin) (@in_guaranteed S, UnsafeRawPointer) -> @out C,
+      setter @o_set : $@convention(thin) (@in_guaranteed C, @in_guaranteed S, UnsafeRawPointer) -> (),
+      indices [%$0 : $S : $S, %$1 : $C : $C],
+      indices_equals @o_equals : $@convention(thin) (UnsafeRawPointer, UnsafeRawPointer) -> Bool,
+      indices_hash @o_hash : $@convention(thin) (UnsafeRawPointer) -> Int
+  ) (%1, %2)
+  %r = keypath $WritableKeyPath<S, S>, (
+    root $S;
+    settable_property $C,
+      id @o_get : $@convention(thin) (@in_guaranteed S, UnsafeRawPointer) -> @out C,
+      getter @o_get : $@convention(thin) (@in_guaranteed S, UnsafeRawPointer) -> @out C,
+      setter @o_set : $@convention(thin) (@in_guaranteed C, @in_guaranteed S, UnsafeRawPointer) -> (),
+      indices [%$0 : $S : $S, %$1 : $C : $C],
+      indices_equals @o_equals : $@convention(thin) (UnsafeRawPointer, UnsafeRawPointer) -> Bool,
+      indices_hash @o_hash : $@convention(thin) (UnsafeRawPointer) -> Int;
+    settable_property $S,
+      id @r_get : $@convention(thin) (@in_guaranteed C, UnsafeRawPointer) -> @out S,
+      getter @r_get : $@convention(thin) (@in_guaranteed C, UnsafeRawPointer) -> @out S,
+      setter @r_set : $@convention(thin) (@in_guaranteed S, @in_guaranteed C, UnsafeRawPointer) -> (),
+      indices [%$2 : $S : $S],
+      indices_equals @o_equals : $@convention(thin) (UnsafeRawPointer, UnsafeRawPointer) -> Bool,
+      indices_hash @o_hash : $@convention(thin) (UnsafeRawPointer) -> Int
+  ) (%3, %4, %5)
+
+  return undef : $()
+}
+
+sil @o_get : $@convention(thin) (@in_guaranteed S, UnsafeRawPointer) -> @out C
+sil @o_set : $@convention(thin) (@in_guaranteed C, @in_guaranteed S, UnsafeRawPointer) -> ()
+sil @o_equals : $@convention(thin) (UnsafeRawPointer, UnsafeRawPointer) -> Bool
+sil @o_hash : $@convention(thin) (UnsafeRawPointer) -> Int
+
+sil @r_get : $@convention(thin) (@in_guaranteed C, UnsafeRawPointer) -> @out S
+sil @r_set : $@convention(thin) (@in_guaranteed S, @in_guaranteed C, UnsafeRawPointer) -> ()
+
+sil @generic_computed_property_indices : $@convention(thin) <A: Hashable, B: Hashable> (@in_guaranteed A, @in_guaranteed B, @in_guaranteed A, @in_guaranteed B, @in_guaranteed A, @in_guaranteed B) -> () {
+entry(%0 : $*A, %1 : $*B, %2 : $*A, %3 : $*B, %4 : $*A, %5 : $*B):
+  %s = keypath $WritableKeyPath<A, B>, <X: Hashable, Y: Hashable> (
+    root $X;
+    settable_property $Y,
+      id @s_get : $@convention(thin) <T: Hashable, U: Hashable> (@in_guaranteed T, UnsafeRawPointer) -> @out U,
+      getter @s_get : $@convention(thin) <T: Hashable, U: Hashable> (@in_guaranteed T, UnsafeRawPointer) -> @out U,
+      setter @s_set : $@convention(thin) <T: Hashable, U: Hashable> (@in_guaranteed U, @in_guaranteed T, UnsafeRawPointer) -> (),
+      indices [%$0 : $X : $*X],
+      indices_equals @s_equals : $@convention(thin) <T: Hashable, U: Hashable> (UnsafeRawPointer, UnsafeRawPointer) -> Bool,
+      indices_hash @s_hash : $@convention(thin) <T: Hashable, U: Hashable> (UnsafeRawPointer) -> Int
+  ) <A, B> (%0)
+  %t = keypath $WritableKeyPath<A, B>, <X: Hashable, Y: Hashable> (
+    root $X;
+    settable_property $Y,
+      id @s_get : $@convention(thin) <T: Hashable, U: Hashable> (@in_guaranteed T, UnsafeRawPointer) -> @out U,
+      getter @s_get : $@convention(thin) <T: Hashable, U: Hashable> (@in_guaranteed T, UnsafeRawPointer) -> @out U,
+      setter @s_set : $@convention(thin) <T: Hashable, U: Hashable> (@in_guaranteed U, @in_guaranteed T, UnsafeRawPointer) -> (),
+      indices [%$0 : $Y : $*Y, %$1 : $X : $*X],
+      indices_equals @s_equals : $@convention(thin) <T: Hashable, U: Hashable> (UnsafeRawPointer, UnsafeRawPointer) -> Bool,
+      indices_hash @s_hash : $@convention(thin) <T: Hashable, U: Hashable> (UnsafeRawPointer) -> Int
+  ) <A, B> (%1, %2)
+  %v = keypath $WritableKeyPath<A, A>, <X: Hashable, Y: Hashable> (
+    root $X;
+    settable_property $Y,
+      id @s_get : $@convention(thin) <T: Hashable, U: Hashable> (@in_guaranteed T, UnsafeRawPointer) -> @out U,
+      getter @s_get : $@convention(thin) <T: Hashable, U: Hashable> (@in_guaranteed T, UnsafeRawPointer) -> @out U,
+      setter @s_set : $@convention(thin) <T: Hashable, U: Hashable> (@in_guaranteed U, @in_guaranteed T, UnsafeRawPointer) -> (),
+      indices [%$0 : $Y : $*Y, %$1 : $X : $*X],
+      indices_equals @s_equals : $@convention(thin) <T: Hashable, U: Hashable> (UnsafeRawPointer, UnsafeRawPointer) -> Bool,
+      indices_hash @s_hash : $@convention(thin) <T: Hashable, U: Hashable> (UnsafeRawPointer) -> Int;
+    settable_property $X,
+      id @v_get : $@convention(thin) <T: Hashable, U: Hashable> (@in_guaranteed U, UnsafeRawPointer) -> @out T,
+      getter @v_get : $@convention(thin) <T: Hashable, U: Hashable> (@in_guaranteed U, UnsafeRawPointer) -> @out T,
+      setter @v_set : $@convention(thin) <T: Hashable, U: Hashable> (@in_guaranteed T, @in_guaranteed U, UnsafeRawPointer) -> (),
+      indices [%$2 : $Y : $*Y],
+      indices_equals @s_equals : $@convention(thin) <T: Hashable, U: Hashable> (UnsafeRawPointer, UnsafeRawPointer) -> Bool,
+      indices_hash @s_hash : $@convention(thin) <T: Hashable, U: Hashable> (UnsafeRawPointer) -> Int
+  ) <A, B> (%3, %4, %5)
+
+  return undef : $()
+}
+
+sil @generic_external : $@convention(thin) <A: Hashable, B: Hashable> (@in_guaranteed A, @in_guaranteed B, @in_guaranteed A, @in_guaranteed B, @in_guaranteed A, @in_guaranteed B) -> () {
+entry(%0 : $*A, %1 : $*B, %2 : $*A, %3 : $*B, %4 : $*A, %5 : $*B):
+  %t = keypath $KeyPath<G<B>, B>, <Z> (
+    root $G<Z>;
+    external #G.x<Z> : $Z
+  ) <B>
+
+  %u = keypath $KeyPath<G<A>, A>, <X: Hashable, Y: Hashable> (
+    root $G<Y>;
+    external #G.subscript<Y, X> [%$0 : $X : $*X] : $Y
+  ) <B, A> (%1)
+
+  %v = keypath $KeyPath<G<G<B>>, B>, <X: Hashable, Y: Hashable> (
+    root $G<G<X>>;
+    external #G.subscript<G<X>, Y> [%$1 : $Y : $*Y] : $G<X>;
+    external #G.subscript<X, X> [%$0 : $X : $*X] : $X
+  ) <B, A> (%3, %4)
+
+  return undef : $()
+}
+
+sil @s_get : $@convention(thin) <A: Hashable, B: Hashable> (@in_guaranteed A, UnsafeRawPointer) -> @out B
+sil @s_set : $@convention(thin) <A: Hashable, B: Hashable> (@in_guaranteed B, @in_guaranteed A, UnsafeRawPointer) -> ()
+sil @s_equals : $@convention(thin) <A: Hashable, B: Hashable> (UnsafeRawPointer, UnsafeRawPointer) -> Bool
+sil @s_hash : $@convention(thin) <A: Hashable, B: Hashable> (UnsafeRawPointer) -> Int
+
+sil @v_get : $@convention(thin) <A: Hashable, B: Hashable> (@in_guaranteed B, UnsafeRawPointer) -> @out A
+sil @v_set : $@convention(thin) <A: Hashable, B: Hashable> (@in_guaranteed A, @in_guaranteed B, UnsafeRawPointer) -> ()
diff --git a/test/IRGen/plus_zero_keypaths_objc.sil b/test/IRGen/plus_zero_keypaths_objc.sil
new file mode 100644
index 0000000..1504309
--- /dev/null
+++ b/test/IRGen/plus_zero_keypaths_objc.sil
@@ -0,0 +1,53 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %empty-directory(%t)
+// RUN: %utils/chex.py < %s > %t/keypaths_objc.sil
+// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -emit-ir %t/keypaths_objc.sil | %FileCheck %t/keypaths_objc.sil --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize
+// REQUIRES: objc_interop
+
+import Swift
+import Foundation
+
+class C: NSObject {
+  dynamic var x: NSString { get }
+  @sil_stored final var stored: Int
+  override init()
+}
+
+sil_vtable C {}
+
+sil @x_get : $@convention(thin) (@in_guaranteed C) -> @out NSString
+
+// CHECK: [[KEYPATH_A:@keypath.*]] = private global
+// --             0x0100_0002: computed, get-only, indirect identifier
+// CHECK-SAME: <i32 0x0100_0002>,
+// CHECK-SAME: i8** @"\01L_selector(x)"
+
+// CHECK: [[KEYPATH_B:@keypath.*]] = private global
+// --             0x02fffffd: class stored property with indirect offset
+// CHECK-SAME: <i32 0x02fffffd>,
+// CHECK-SAME: @"$S13keypaths_objc1CC6storedSivpWvd"
+
+// CHECK-LABEL: define swiftcc void @objc_only_property()
+sil @objc_only_property : $@convention(thin) () -> () {
+entry:
+  // CHECK: call %swift.refcounted* @swift_getKeyPath({{.*}} [[KEYPATH_A]]
+  %a = keypath $KeyPath<C, NSString>, (objc "x"; root $C; gettable_property $NSString, id #C.x!getter.1.foreign, getter @x_get : $@convention(thin) (@in_guaranteed C) -> @out NSString)
+  unreachable
+}
+
+sil hidden @$S13keypaths_objc1CC1xSo8NSStringCvgTo : $@convention(objc_method) (@guaranteed C) -> NSString {
+entry(%0 : $C):
+  unreachable
+}
+
+sil hidden @$S13keypaths_objc1CCACycfcTo : $@convention(objc_method) (@objc_metatype C.Type) -> @owned C {
+entry(%0 : $@objc_metatype C.Type):
+  unreachable
+}
+
+sil @objc_stored_property : $@convention(thin) () -> () {
+entry:
+  // CHECK: call %swift.refcounted* @swift_getKeyPath({{.*}} [[KEYPATH_B]]
+  %b = keypath $KeyPath<C, Int>, (objc "stored"; root $C; stored_property #C.stored : $Int)
+  unreachable
+}
diff --git a/test/IRGen/plus_zero_lowered_optional_self_metadata.sil b/test/IRGen/plus_zero_lowered_optional_self_metadata.sil
new file mode 100644
index 0000000..005e8bb
--- /dev/null
+++ b/test/IRGen/plus_zero_lowered_optional_self_metadata.sil
@@ -0,0 +1,33 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -assume-parsing-unqualified-ownership-sil -emit-ir %s
+sil_stage canonical
+
+import Swift
+
+public protocol Protocol {
+  static func foo(_: Self?)
+}
+
+// SR-3021: Ensure we pass the Self type metadata for Optional methods using the
+// formal Optional type and not a lowered SIL type.
+
+// CHECK-LABEL: @_TMaGSqFT_T__
+
+sil @optional_method : $@convention(method) <T> (@in_guaranteed Optional<T>) -> ()
+
+sil @call_optional_method_with_lowered_function : $@convention(thin) (@in_guaranteed Optional<@callee_guaranteed (@in_guaranteed ()) -> @out ()>) -> () {
+entry(%x : $*Optional<@callee_guaranteed (@in_guaranteed ()) -> @out ()>):
+  %f = function_ref @optional_method : $@convention(method) <T> (@in_guaranteed Optional<T>) -> ()
+  apply %f<() -> ()>(%x) : $@convention(method) <T> (@in_guaranteed Optional<T>) -> ()
+  %p = partial_apply [callee_guaranteed] %f<() -> ()>() : $@convention(method) <T> (@in_guaranteed Optional<T>) -> ()
+  return undef : $()
+}
+
+// SR-3548: Ensure we correctly emit "metadata for layout" for lowered Optional types.
+
+sil @alloc_stack_optional_with_generic : $@convention(thin) <T> () -> () {
+  %a = alloc_stack $*Optional<(T, @convention(thin) () -> ())>
+  dealloc_stack %a : $*Optional<(T, @convention(thin) () -> ())>
+  %t = tuple ()
+  return %t : $()
+}
diff --git a/test/IRGen/plus_zero_objc.swift b/test/IRGen/plus_zero_objc.swift
new file mode 100644
index 0000000..634a5a6
--- /dev/null
+++ b/test/IRGen/plus_zero_objc.swift
@@ -0,0 +1,148 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %empty-directory(%t)
+// RUN: %build-irgen-test-overlays
+// RUN: %target-swift-frontend(mock-sdk: -sdk %S/Inputs -I %t) -primary-file %s -emit-ir -disable-objc-attr-requires-foundation-module | %FileCheck %s
+
+// REQUIRES: CPU=x86_64
+// REQUIRES: objc_interop
+
+import Foundation
+import gizmo
+
+// CHECK: [[TYPE:%swift.type]] = type
+// CHECK: [[BLAMMO:%T4objc6BlammoC]] = type
+// CHECK: [[MYBLAMMO:%T4objc8MyBlammoC]] = type
+// CHECK: [[TEST2:%T4objc5Test2C]] = type
+// CHECK: [[OBJC:%objc_object]] = type
+// CHECK: [[ID:%T4objc2idV]] = type <{ %AnyObject }>
+// CHECK: [[GIZMO:%TSo5GizmoC]] = type
+// CHECK: [[RECT:%TSo4RectV]] = type
+// CHECK: [[FLOAT:%TSf]] = type
+
+// CHECK: @"\01L_selector_data(bar)" = private global [4 x i8] c"bar\00", section "__TEXT,__objc_methname,cstring_literals", align 1
+// CHECK: @"\01L_selector(bar)" = private externally_initialized global i8* getelementptr inbounds ([4 x i8], [4 x i8]* @"\01L_selector_data(bar)", i64 0, i64 0), section "__DATA,__objc_selrefs,literal_pointers,no_dead_strip", align 8
+
+// CHECK: @"$SSo4RectVMn" = linkonce_odr hidden constant
+// CHECK: @"$SSo4RectVN" = linkonce_odr hidden global
+
+// CHECK: @"\01L_selector_data(acquiesce)"
+// CHECK-NOT: @"\01L_selector_data(disharmonize)"
+// CHECK: @"\01L_selector_data(eviscerate)"
+
+struct id {
+  var data : AnyObject
+}
+
+// Exporting something as [objc] doesn't make it an ObjC class.
+@objc class Blammo {
+}
+// Class and methods are [objc] by inheritance.
+class MyBlammo : Blammo {
+  func foo() {}
+// CHECK:  define hidden swiftcc void @"$S4objc8MyBlammoC3fooyyF"([[MYBLAMMO]]* swiftself) {{.*}} {
+// CHECK:    call {{.*}} @swift_release
+// CHECK:    ret void
+}
+
+// Class and methods are [objc] by inheritance.
+class Test2 : Gizmo {
+  func foo() {}
+// CHECK:  define hidden swiftcc void @"$S4objc5Test2C3fooyyF"([[TEST2]]* swiftself) {{.*}} {
+// CHECK:    call {{.*}} @objc_release
+// CHECK:    ret void
+
+  dynamic func bar() {}
+}
+
+// Test @nonobjc.
+class Contrarian : Blammo {
+  func acquiesce() {}
+  @nonobjc func disharmonize() {}
+  @nonobjc func eviscerate() {}
+}
+
+class Octogenarian : Contrarian {
+  // Override of @nonobjc is @objc again unless made @nonobjc.
+  @nonobjc override func disharmonize() {}
+
+  // Override of @nonobjc can be @objc.
+  @objc override func eviscerate() {}
+}
+
+@_silgen_name("unknown")
+func unknown(_ x: id) -> id
+
+// CHECK:    define hidden swiftcc %objc_object* @"$S4objc5test0{{[_0-9a-zA-Z]*}}F"(%objc_object*)
+// CHECK-NOT:  call {{.*}} @swift_unknownRetain
+// CHECK:      call {{.*}} @swift_unknownRetain
+// CHECK-NOT:  call {{.*}} @swift_unknownRelease
+// CHECK:      call {{.*}} @swift_unknownRelease
+// CHECK:      ret %objc_object*
+func test0(_ arg: id) -> id {
+  var x : id
+  x = arg
+  unknown(x)
+  var y = x
+  return y
+}
+
+func test1(_ cell: Blammo) {}
+// CHECK:  define hidden swiftcc void @"$S4objc5test1{{[_0-9a-zA-Z]*}}F"([[BLAMMO]]*) {{.*}} {
+// CHECK-NEXT:    entry
+// CHECK-NEXT:    ret void
+
+
+// FIXME: These ownership convention tests should become SILGen tests.
+func test2(_ v: Test2) { v.bar() }
+func test3() -> NSObject {
+  return Gizmo()
+}
+// Normal message send with argument, no transfers.
+func test5(_ g: Gizmo) {
+  Gizmo.inspect(g)
+}
+// The argument to consume: is __attribute__((ns_consumed)).
+func test6(_ g: Gizmo) {
+  Gizmo.consume(g)
+}
+// fork is __attribute__((ns_consumes_self)).
+func test7(_ g: Gizmo) {
+  g.fork()
+}
+// clone is __attribute__((ns_returns_retained)).
+func test8(_ g: Gizmo) {
+  g.clone()
+}
+// duplicate has an object returned at +0.
+func test9(_ g: Gizmo) {
+  g.duplicate()
+}
+
+func test10(_ g: Gizmo, r: Rect) {
+  Gizmo.run(with: r, andGizmo:g);
+}
+
+// Force the emission of the Rect metadata.
+func test11_helper<T>(_ t: T) {}
+// NSRect's metadata needs to be uniqued at runtime using getForeignTypeMetadata.
+// CHECK-LABEL: define hidden swiftcc void @"$S4objc6test11yySo4RectVF"
+// CHECK:         call %swift.type* @swift_getForeignTypeMetadata({{.*}} @"$SSo4RectVN"
+func test11(_ r: Rect) { test11_helper(r) }
+
+class WeakObjC {
+  weak var obj: NSObject?
+  weak var id: AnyObject?
+
+  init() {
+    var foo = obj
+    var bar: AnyObject? = id
+  }
+}
+
+// rdar://17528908
+// CHECK:  i32 1, !"Objective-C Version", i32 2}
+// CHECK:  i32 1, !"Objective-C Image Info Version", i32 0}
+// CHECK:  i32 1, !"Objective-C Image Info Section", !"__DATA,__objc_imageinfo,regular,no_dead_strip"}
+//   1536 == (6 << 8).  6 is the Swift ABI version.
+// CHECK:  i32 4, !"Objective-C Garbage Collection", i32 1536}
+// CHECK:  i32 1, !"Swift Version", i32 6}
diff --git a/test/IRGen/plus_zero_objc_retainAutoreleasedReturnValue.swift b/test/IRGen/plus_zero_objc_retainAutoreleasedReturnValue.swift
new file mode 100644
index 0000000..67bf5d9
--- /dev/null
+++ b/test/IRGen/plus_zero_objc_retainAutoreleasedReturnValue.swift
@@ -0,0 +1,40 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -target x86_64-apple-macosx10.12 -assume-parsing-unqualified-ownership-sil -import-objc-header %S/Inputs/StaticInline.h %s -emit-ir | %FileCheck %s
+// RUN: %target-swift-frontend -O -target x86_64-apple-macosx10.12 -assume-parsing-unqualified-ownership-sil -import-objc-header %S/Inputs/StaticInline.h %s -emit-ir | %FileCheck %s --check-prefix=OPT
+
+// REQUIRES: objc_interop
+// REQUIRES: CPU=x86_64
+// REQUIRES: OS=macosx
+import Foundation
+
+@inline(never)
+public func useClosure(_ dict: NSDictionary, _ action : (NSDictionary) -> ()) {
+  action(dict)
+}
+
+@inline(never)
+public func test(_ dict: NSDictionary) {
+  useClosure(dict, { $0.objectEnumerator()} )
+}
+
+//  Don't tail call objc_retainAutoreleasedReturnValue as this would block the
+//  autorelease return value optimization.
+
+// callq  0x01ec08 ; symbol stub for: objc_msgSend
+// movq   %rax, %rdi
+// popq   %rbp  ;<== Blocks the handshake from objc_autoreleaseReturnValue
+// jmp    0x01ec20 ; symbol stub for: objc_retainAutoreleasedReturnValue
+
+// CHECK-LABEL: define {{.*}}swiftcc void @"$S34objc_retainAutoreleasedReturnValue4testyySo12NSDictionaryCFyADXEfU_"(%TSo12NSDictionaryC*)
+// CHECK: entry:
+// CHECK:   call {{.*}}@objc_msgSend
+// CHECK:   notail call i8* @objc_retainAutoreleasedReturnValue
+// CHECK:   ret void
+
+// CHECK-LABEL: define {{.*}}swiftcc void @"$SSo12NSDictionaryCSo12NSEnumeratorCIggo_ABIegg_TR"(%TSo12NSDictionaryC*, i8*, %swift.opaque*)
+
+// OPT-LABEL: define {{.*}}swiftcc void @"$S34objc_retainAutoreleasedReturnValue10useClosureyySo12NSDictionaryC_yADXEtF06$SSo12h44CSo12NSEnumeratorCIggo_ABIegg_TR049$S34objc_bcD42Value4testyySo12a6CFSo12B8CADXEfU_Tf3npf_nTf1nc_n"(%TSo12NSDictionaryC*)
+// OPT: entry:
+// OPT:   call {{.*}}@objc_msgSend
+// OPT:   notail call i8* @objc_retainAutoreleasedReturnValue
+// OPT:   ret void
diff --git a/test/IRGen/plus_zero_runtime_calling_conventions.swift b/test/IRGen/plus_zero_runtime_calling_conventions.swift
new file mode 100644
index 0000000..8322258
--- /dev/null
+++ b/test/IRGen/plus_zero_runtime_calling_conventions.swift
@@ -0,0 +1,19 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -assume-parsing-unqualified-ownership-sil -parse-as-library -emit-ir %s | %FileCheck %s
+// RUN: %target-swift-frontend -assume-parsing-unqualified-ownership-sil -parse-as-library -O -emit-ir %s | %FileCheck --check-prefix=OPT-CHECK %s
+
+// Test that runtime functions are invoked using the new calling convention.
+
+public class C {
+}
+
+// CHECK-LABEL: define {{(protected )?}}swiftcc void @"$S27runtime_calling_conventions3fooyyAA1CCF"(%T27runtime_calling_conventions1CC*)
+// Check that runtime functions use a proper calling convention.
+// CHECK-NOT: call void {{.*}} @swift_release
+
+// OPT-CHECK-LABEL: define {{(protected )?}}swiftcc void @"$S27runtime_calling_conventions3fooyyAA1CCF"(%T27runtime_calling_conventions1CC* nocapture)
+// Check that runtime functions use a proper calling convention.
+// OPT-CHECK-NOT: tail call void @swift_release
+
+public func foo(_ c: C) {
+}
diff --git a/test/IRGen/plus_zero_struct_resilience.swift b/test/IRGen/plus_zero_struct_resilience.swift
new file mode 100644
index 0000000..6f0bdf7
--- /dev/null
+++ b/test/IRGen/plus_zero_struct_resilience.swift
@@ -0,0 +1,173 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %empty-directory(%t)
+// RUN: %target-swift-frontend -emit-module -enable-resilience -emit-module-path=%t/resilient_struct.swiftmodule -module-name=resilient_struct %S/../Inputs/resilient_struct.swift
+// RUN: %target-swift-frontend -emit-module -enable-resilience -emit-module-path=%t/resilient_enum.swiftmodule -module-name=resilient_enum -I %t %S/../Inputs/resilient_enum.swift
+// RUN: %target-swift-frontend -I %t -emit-ir -enable-resilience %s | %FileCheck %s
+// RUN: %target-swift-frontend -I %t -emit-ir -enable-resilience -O %s
+
+import resilient_struct
+import resilient_enum
+
+// CHECK: %TSi = type <{ [[INT:i32|i64]] }>
+
+// CHECK-LABEL: @"$S17struct_resilience26StructWithResilientStorageVMf" = internal global
+
+// Resilient structs from outside our resilience domain are manipulated via
+// value witnesses
+
+// CHECK-LABEL: define{{( protected)?}} swiftcc void @"$S17struct_resilience26functionWithResilientTypes_1f010resilient_A04SizeVAF_A2FXEtF"(%swift.opaque* noalias nocapture sret, %swift.opaque* noalias nocapture, i8*, %swift.opaque*)
+
+public func functionWithResilientTypes(_ s: Size, f: (Size) -> Size) -> Size {
+// CHECK: entry:
+// CHECK-NEXT: [[FN:%.*]] = bitcast i8* %2 to void (%swift.opaque*, %swift.opaque*, %swift.refcounted*)*
+// CHECK-NEXT: [[SELF:%.*]] = bitcast %swift.opaque* %3 to %swift.refcounted*
+// CHECK-NEXT: call swiftcc void [[FN]](%swift.opaque* noalias nocapture sret %0, %swift.opaque* noalias nocapture %1, %swift.refcounted* swiftself [[SELF]])
+// CHECK-NEXT: ret void
+
+  return f(s)
+}
+
+// Rectangle has fixed layout inside its resilience domain, and dynamic
+// layout on the outside.
+//
+// Make sure we use a type metadata accessor function, and load indirect
+// field offsets from it.
+
+// CHECK-LABEL: define{{( protected)?}} swiftcc void @"$S17struct_resilience26functionWithResilientTypesyy010resilient_A09RectangleVF"(%T16resilient_struct9RectangleV* noalias nocapture)
+public func functionWithResilientTypes(_ r: Rectangle) {
+
+// CHECK: [[METADATA:%.*]] = call %swift.type* @"$S16resilient_struct9RectangleVMa"()
+// CHECK-NEXT: [[METADATA_ADDR:%.*]] = bitcast %swift.type* [[METADATA]] to [[INT]]*
+// CHECK-NEXT: [[FIELD_OFFSET_VECTOR:%.*]] = getelementptr inbounds [[INT]], [[INT]]* [[METADATA_ADDR]], [[INT]] 2
+// CHECK-NEXT: [[FIELD_OFFSET_PTR:%.*]] = getelementptr inbounds [[INT]], [[INT]]* [[FIELD_OFFSET_VECTOR]], i32 2
+// CHECK-NEXT: [[FIELD_OFFSET:%.*]] = load [[INT]], [[INT]]* [[FIELD_OFFSET_PTR]]
+// CHECK-NEXT: [[STRUCT_ADDR:%.*]] = bitcast %T16resilient_struct9RectangleV* %0 to i8*
+// CHECK-NEXT: [[FIELD_ADDR:%.*]] = getelementptr inbounds i8, i8* [[STRUCT_ADDR]], [[INT]] [[FIELD_OFFSET]]
+// CHECK-NEXT: [[FIELD_PTR:%.*]] = bitcast i8* [[FIELD_ADDR]] to %TSi*
+// CHECK-NEXT: [[FIELD_PAYLOAD_PTR:%.*]] = getelementptr inbounds %TSi, %TSi* [[FIELD_PTR]], i32 0, i32 0
+// CHECK-NEXT: [[FIELD_PAYLOAD:%.*]] = load [[INT]], [[INT]]* [[FIELD_PAYLOAD_PTR]]
+
+  _ = r.color
+
+// CHECK-NEXT: ret void
+
+}
+
+// Resilient structs from inside our resilience domain are manipulated
+// directly.
+
+public struct MySize {
+  public let w: Int
+  public let h: Int
+}
+
+// CHECK-LABEL: define{{( protected)?}} swiftcc void @"$S17struct_resilience28functionWithMyResilientTypes_1fAA0E4SizeVAE_A2EXEtF"(%T17struct_resilience6MySizeV* {{.*}}, %T17struct_resilience6MySizeV* {{.*}}, i8*, %swift.opaque*)
+public func functionWithMyResilientTypes(_ s: MySize, f: (MySize) -> MySize) -> MySize {
+// CHECK: entry:
+// CHECK-NEXT: [[FN:%.*]] = bitcast i8* %2
+// CHECK-NEXT: [[SELF:%.*]] = bitcast %swift.opaque* %3
+// CHECK-NEXT: call swiftcc void [[FN]](%T17struct_resilience6MySizeV* {{.*}} %0, {{.*}} %1, %swift.refcounted* swiftself [[SELF]])
+// CHECK-NEXT: ret void
+  return f(s)
+}
+
+// CHECK-LABEL: declare %swift.type* @"$S16resilient_struct4SizeVMa"()
+
+// Structs with resilient storage from a different resilience domain require
+// runtime metadata instantiation, just like generics.
+
+public struct StructWithResilientStorage {
+  public let s: Size
+  public let ss: (Size, Size)
+  public let n: Int
+  public let i: ResilientInt
+}
+
+// Make sure we call a function to access metadata of structs with
+// resilient layout, and go through the field offset vector in the
+// metadata when accessing stored properties.
+
+// CHECK-LABEL: define{{( protected)?}} swiftcc {{i32|i64}} @"$S17struct_resilience26StructWithResilientStorageV1nSivg"(%T17struct_resilience26StructWithResilientStorageV* {{.*}})
+// CHECK: [[METADATA:%.*]] = call %swift.type* @"$S17struct_resilience26StructWithResilientStorageVMa"()
+// CHECK-NEXT: [[METADATA_ADDR:%.*]] = bitcast %swift.type* [[METADATA]] to [[INT]]*
+// CHECK-NEXT: [[FIELD_OFFSET_VECTOR:%.*]] = getelementptr inbounds [[INT]], [[INT]]* [[METADATA_ADDR]], [[INT]] 2
+// CHECK-NEXT: [[FIELD_OFFSET_PTR:%.*]] = getelementptr inbounds [[INT]], [[INT]]* [[FIELD_OFFSET_VECTOR]], i32 2
+// CHECK-NEXT: [[FIELD_OFFSET:%.*]] = load [[INT]], [[INT]]* [[FIELD_OFFSET_PTR]]
+// CHECK-NEXT: [[STRUCT_ADDR:%.*]] = bitcast %T17struct_resilience26StructWithResilientStorageV* %0 to i8*
+// CHECK-NEXT: [[FIELD_ADDR:%.*]] = getelementptr inbounds i8, i8* [[STRUCT_ADDR]], [[INT]] [[FIELD_OFFSET]]
+// CHECK-NEXT: [[FIELD_PTR:%.*]] = bitcast i8* [[FIELD_ADDR]] to %TSi*
+// CHECK-NEXT: [[FIELD_PAYLOAD_PTR:%.*]] = getelementptr inbounds %TSi, %TSi* [[FIELD_PTR]], i32 0, i32 0
+// CHECK-NEXT: [[FIELD_PAYLOAD:%.*]] = load [[INT]], [[INT]]* [[FIELD_PAYLOAD_PTR]]
+// CHECK-NEXT: ret [[INT]] [[FIELD_PAYLOAD]]
+
+
+// Indirect enums with resilient payloads are still fixed-size.
+
+public struct StructWithIndirectResilientEnum {
+  public let s: FunnyShape
+  public let n: Int
+}
+
+
+// CHECK-LABEL: define{{( protected)?}} swiftcc {{i32|i64}} @"$S17struct_resilience31StructWithIndirectResilientEnumV1nSivg"(%T17struct_resilience31StructWithIndirectResilientEnumV* {{.*}})
+// CHECK: [[FIELD_PTR:%.*]] = getelementptr inbounds %T17struct_resilience31StructWithIndirectResilientEnumV, %T17struct_resilience31StructWithIndirectResilientEnumV* %0, i32 0, i32 1
+// CHECK-NEXT: [[FIELD_PAYLOAD_PTR:%.*]] = getelementptr inbounds %TSi, %TSi* [[FIELD_PTR]], i32 0, i32 0
+// CHECK-NEXT: [[FIELD_PAYLOAD:%.*]] = load [[INT]], [[INT]]* [[FIELD_PAYLOAD_PTR]]
+// CHECK-NEXT: ret [[INT]] [[FIELD_PAYLOAD]]
+
+
+// Partial application of methods on resilient value types
+
+public struct ResilientStructWithMethod {
+  public func method() {}
+}
+
+// Corner case -- type is address-only in SIL, but empty in IRGen
+
+// CHECK-LABEL: define{{( protected)?}} swiftcc void @"$S17struct_resilience29partialApplyOfResilientMethod1ryAA0f10StructWithG0V_tF"(%T17struct_resilience25ResilientStructWithMethodV* noalias nocapture)
+public func partialApplyOfResilientMethod(r: ResilientStructWithMethod) {
+  _ = r.method
+}
+
+// Type is address-only in SIL, and resilient in IRGen
+
+// CHECK-LABEL: define{{( protected)?}} swiftcc void @"$S17struct_resilience29partialApplyOfResilientMethod1sy010resilient_A04SizeV_tF"(%swift.opaque* noalias nocapture)
+public func partialApplyOfResilientMethod(s: Size) {
+  _ = s.method
+}
+
+// Public metadata accessor for our resilient struct
+
+// CHECK-LABEL: define{{( protected)?}} %swift.type* @"$S17struct_resilience6MySizeVMa"()
+// CHECK: ret %swift.type* bitcast ([[INT]]* getelementptr inbounds {{.*}} @"$S17struct_resilience6MySizeVMf", i32 0, i32 1) to %swift.type*)
+
+
+// CHECK-LABEL: define{{( protected)?}} private void @initialize_metadata_StructWithResilientStorage(i8*)
+// CHECK: [[FIELDS:%.*]] = alloca [4 x i8**]
+
+// CHECK: [[FIELDS_ADDR:%.*]] = getelementptr inbounds [4 x i8**], [4 x i8**]* [[FIELDS]], i32 0, i32 0
+
+// public let s: Size
+
+// CHECK: [[FIELD_1:%.*]] = getelementptr inbounds i8**, i8*** [[FIELDS_ADDR]], i32 0
+// CHECK: store i8** [[SIZE_AND_ALIGNMENT:%.*]], i8*** [[FIELD_1]]
+
+// public let ss: (Size, Size)
+
+// CHECK: [[FIELD_2:%.*]] = getelementptr inbounds i8**, i8*** [[FIELDS_ADDR]], i32 1
+// CHECK: store i8** [[SIZE_AND_ALIGNMENT:%.*]], i8*** [[FIELD_2]]
+
+// Fixed-layout aggregate -- we can reference a static value witness table
+// public let n: Int
+
+// CHECK: [[FIELD_3:%.*]] = getelementptr inbounds i8**, i8*** [[FIELDS_ADDR]], i32 2
+// CHECK: store i8** getelementptr inbounds (i8*, i8** @"$SBi{{32|64}}_WV", i32 {{.*}}), i8*** [[FIELD_3]]
+
+// Resilient aggregate with one field -- make sure we don't look inside it
+// public let i: ResilientInt
+// CHECK: [[FIELD_4:%.*]] = getelementptr inbounds i8**, i8*** [[FIELDS_ADDR]], i32 3
+// CHECK: store i8** [[SIZE_AND_ALIGNMENT:%.*]], i8*** [[FIELD_4]]
+
+// CHECK: call void @swift_initStructMetadata(%swift.type* {{.*}}, [[INT]] 256, [[INT]] 4, i8*** [[FIELDS_ADDR]], [[INT]]* {{.*}})
+// CHECK: store atomic %swift.type* {{.*}} @"$S17struct_resilience26StructWithResilientStorageVMf{{.*}}, %swift.type** @"$S17struct_resilience26StructWithResilientStorageVML" release,
+// CHECK: ret void
diff --git a/test/IRGen/runtime_calling_conventions.swift b/test/IRGen/runtime_calling_conventions.swift
index e7d0d97..74ca835 100644
--- a/test/IRGen/runtime_calling_conventions.swift
+++ b/test/IRGen/runtime_calling_conventions.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -assume-parsing-unqualified-ownership-sil -parse-as-library -emit-ir %s | %FileCheck %s
 // RUN: %target-swift-frontend -assume-parsing-unqualified-ownership-sil -parse-as-library -O -emit-ir %s | %FileCheck --check-prefix=OPT-CHECK %s
 
diff --git a/test/IRGen/struct_resilience.swift b/test/IRGen/struct_resilience.swift
index 1151eb1..2118662 100644
--- a/test/IRGen/struct_resilience.swift
+++ b/test/IRGen/struct_resilience.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %empty-directory(%t)
 // RUN: %target-swift-frontend -emit-module -enable-resilience -emit-module-path=%t/resilient_struct.swiftmodule -module-name=resilient_struct %S/../Inputs/resilient_struct.swift
 // RUN: %target-swift-frontend -emit-module -enable-resilience -emit-module-path=%t/resilient_enum.swiftmodule -module-name=resilient_enum -I %t %S/../Inputs/resilient_enum.swift
diff --git a/test/Interpreter/SDK/Foundation_test.swift b/test/Interpreter/SDK/Foundation_test.swift
index 50dfc96..f41b2a3 100644
--- a/test/Interpreter/SDK/Foundation_test.swift
+++ b/test/Interpreter/SDK/Foundation_test.swift
@@ -252,7 +252,7 @@
   let _: CFArrayEqualCallBack = { DarwinBoolean($0 == $1) }
 }
 
-#if os(OSX)
+#if os(macOS)
 FoundationTestSuite.test("NSRectEdge/constants") {
   // Check that the following constants have the correct type and value.
   //
diff --git a/test/Interpreter/SDK/c_pointers.swift b/test/Interpreter/SDK/c_pointers.swift
index f7f3657..c295c14 100644
--- a/test/Interpreter/SDK/c_pointers.swift
+++ b/test/Interpreter/SDK/c_pointers.swift
@@ -6,7 +6,7 @@
 // REQUIRES: objc_interop
 
 import Foundation
-#if os(OSX)
+#if os(macOS)
 import AppKit
 typealias XXColor = NSColor
 #endif
@@ -28,7 +28,7 @@
 let nsRed = XXColor(cgColor: cgRed)
 
 var r: CGFloat = 0.5, g: CGFloat = 0.5, b: CGFloat = 0.5, a: CGFloat = 0.5
-#if os(OSX)
+#if os(macOS)
 nsRed!.getRed(&r, green: &g, blue: &b, alpha: &a)
 #else
 nsRed.getRed(&r, green: &g, blue: &b, alpha: &a)
diff --git a/test/Interpreter/SDK/cf_extensions.swift b/test/Interpreter/SDK/cf_extensions.swift
index 57aa920..9dcc3cb 100644
--- a/test/Interpreter/SDK/cf_extensions.swift
+++ b/test/Interpreter/SDK/cf_extensions.swift
@@ -6,7 +6,7 @@
 import Foundation
 import StdlibUnittest
 
-#if os(OSX)
+#if os(macOS)
 import AppKit
 #endif
 
diff --git a/test/Interpreter/SDK/cf_type_bridging.swift b/test/Interpreter/SDK/cf_type_bridging.swift
index e755645..23dfa86 100644
--- a/test/Interpreter/SDK/cf_type_bridging.swift
+++ b/test/Interpreter/SDK/cf_type_bridging.swift
@@ -3,7 +3,7 @@
 
 // REQUIRES: objc_interop
 
-#if os(OSX)
+#if os(macOS)
 import AppKit
 #endif
 #if os(iOS) || os(tvOS) || os(watchOS)
diff --git a/test/Interpreter/SDK/libc.swift b/test/Interpreter/SDK/libc.swift
index 13a0e17..0e1dd7d 100644
--- a/test/Interpreter/SDK/libc.swift
+++ b/test/Interpreter/SDK/libc.swift
@@ -9,7 +9,7 @@
 // TODO: rdar://problem/33388782
 // REQUIRES: CPU=x86_64
 
-#if os(OSX) || os(iOS) || os(watchOS) || os(tvOS)
+#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS)
   import Darwin
 #elseif os(Linux) || os(FreeBSD) || os(PS4) || os(Android)
   import Glibc
diff --git a/test/Interpreter/SDK/objc_ns_enum.swift b/test/Interpreter/SDK/objc_ns_enum.swift
index e125436..b2c5d1d 100644
--- a/test/Interpreter/SDK/objc_ns_enum.swift
+++ b/test/Interpreter/SDK/objc_ns_enum.swift
@@ -8,7 +8,7 @@
 // strict checking if we get a guarantee that certain types don't have
 // hidden or future enumeration values.)
 
-#if os(OSX)
+#if os(macOS)
 import AppKit
 
 print(NSButtonType(rawValue: 20721)!.rawValue)
diff --git a/test/Migrator/no_duplicate_aarch64_use_tbi.swift b/test/Migrator/no_duplicate_aarch64_use_tbi.swift
index b2c648c..af356a1 100644
--- a/test/Migrator/no_duplicate_aarch64_use_tbi.swift
+++ b/test/Migrator/no_duplicate_aarch64_use_tbi.swift
@@ -2,14 +2,14 @@
 // REQUIRES: CPU=arm64
 // RUN: %target-swift-frontend -typecheck %s -swift-version 3
 // RUN: %empty-directory(%t)
-// RUN: cd %t && %swiftc_driver -c -update-code -target arm64-apple-ios10.3 -output-file-map %S/Inputs/no_duplicate_aarch64_use_tbi_ofm.json -swift-version 3 %s -v
-// RUN: cd %t && %swiftc_driver -c -update-code -target arm64-apple-ios10.3 -output-file-map %S/Inputs/no_duplicate_aarch64_use_tbi_ofm.json -swift-version 3 %s -### > %t/driver_actions.txt
+// RUN: cd %t && %target-swiftc_driver -c -update-code -output-file-map %S/Inputs/no_duplicate_aarch64_use_tbi_ofm.json -swift-version 3 %s -v
+// RUN: cd %t && %target-swiftc_driver -c -update-code -output-file-map %S/Inputs/no_duplicate_aarch64_use_tbi_ofm.json -swift-version 3 %s -### > %t/driver_actions.txt
 // RUN: %FileCheck --check-prefix=CHECK-REMAP %s < %t/no_duplicate_aarch64_use_tbi.remap
 // RUN: %FileCheck --check-prefix=CHECK-ACTIONS %s < %t/driver_actions.txt
 
 public func foo(_ f: (Void) -> ()) {}
 
-// CHECK-REMAP: "offset": 673,
+// CHECK-REMAP: "offset": 632,
 // CHECK-REMAP: "remove": 5,
 // CHECK-REMAP: "text": "("
 
diff --git a/test/Parse/ConditionalCompilation/basicIdentity.swift b/test/Parse/ConditionalCompilation/basicIdentity.swift
index 14072e7..a067063 100644
--- a/test/Parse/ConditionalCompilation/basicIdentity.swift
+++ b/test/Parse/ConditionalCompilation/basicIdentity.swift
@@ -63,3 +63,9 @@
 var w = Foo()
 #endif
 var x = w
+
+// Test os(macOS) as well
+#if os(macOS)
+var y = Foo()
+#endif
+var z = y
diff --git a/test/PrintAsObjC/accessibility.swift b/test/PrintAsObjC/accessibility.swift
index bbe7d07..e509860 100644
--- a/test/PrintAsObjC/accessibility.swift
+++ b/test/PrintAsObjC/accessibility.swift
@@ -37,7 +37,7 @@
 
 
 #if MAIN
-#if os(OSX)
+#if os(macOS)
 import AppKit
 
 @NSApplicationMain
diff --git a/test/Reflection/capture_descriptors.sil b/test/Reflection/capture_descriptors.sil
index 19580f8..5630624 100644
--- a/test/Reflection/capture_descriptors.sil
+++ b/test/Reflection/capture_descriptors.sil
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // REQUIRES: no_asan
 // RUN: %empty-directory(%t)
 // RUN: %target-build-swift %s -emit-module -emit-library -module-name capture_descriptors -o %t/capture_descriptors.%target-dylib-extension
diff --git a/test/Reflection/plus_zero_capture_descriptors.sil b/test/Reflection/plus_zero_capture_descriptors.sil
new file mode 100644
index 0000000..dab2c61
--- /dev/null
+++ b/test/Reflection/plus_zero_capture_descriptors.sil
@@ -0,0 +1,290 @@
+// REQUIRES: plus_zero_runtime
+// REQUIRES: no_asan
+// RUN: %empty-directory(%t)
+// RUN: %target-build-swift %s -emit-module -emit-library -module-name capture_descriptors -o %t/capture_descriptors.%target-dylib-extension
+// RUN: %target-swift-reflection-dump -binary-filename %t/capture_descriptors.%target-dylib-extension | %FileCheck %s
+
+sil_stage canonical
+
+import Builtin
+import Swift
+import SwiftShims
+
+// CHECK:      CAPTURE DESCRIPTORS:
+// CHECK-NEXT: ====================
+
+// Concrete caller and callee -- nothing interesting going on
+
+protocol P {}
+extension Int: P {}
+
+sil @concrete_callee1 : $@convention(thin) (Int, @owned <τ_0_0> { var τ_0_0 } <Int>, @thin Int.Type, @thick P.Type) -> () {
+bb0(%i: $Int, %b: $<τ_0_0> { var τ_0_0 } <Int>, %m: $@thin Int.Type, %p: $@thick P.Type):
+  %12 = tuple ()
+  return %12 : $()
+}
+
+sil @concrete_caller1 : $@convention(thin) (Int, @thick P.Type) -> @owned @callee_guaranteed () -> () {
+bb0(%i: $Int, %p: $@thick P.Type):
+  %f = function_ref @concrete_callee1 : $@convention(thin) (Int, @owned <τ_0_0> { var τ_0_0 } <Int>, @thin Int.Type, @thick P.Type) -> ()
+  %b = alloc_box $<τ_0_0> { var τ_0_0 } <Int>
+  %m = metatype $@thin Int.Type
+  %c = partial_apply [callee_guaranteed] %f(%i, %b, %m, %p) : $@convention(thin) (Int, @owned <τ_0_0> { var τ_0_0 } <Int>, @thin Int.Type, @thick P.Type) -> ()
+  return %c : $@callee_guaranteed () -> ()
+}
+
+// This is the descriptor for '<τ_0_0> { var τ_0_0 } <Int>' above
+
+// CHECK:      - Capture types:
+// CHECK-NEXT: (struct Swift.Int)
+// CHECK-NEXT: - Metadata sources:
+
+// CHECK:      - Capture types:
+// CHECK-NEXT: (struct Swift.Int)
+// CHECK-NEXT: (sil_box
+// CHECK-NEXT:   (struct Swift.Int))
+// CHECK-NEXT: (existential_metatype
+// CHECK-NEXT:   (protocol_composition
+// CHECK-NEXT:     (protocol capture_descriptors.P)))
+// CHECK-NEXT: - Metadata sources:
+
+
+// Concrete caller and generic callee -- capture types are fully substituted,
+// and there are no metadata bindings
+
+sil @generic_callee2 : $@convention(thin) <T, U> (@in T, @owned <τ_0_0> { var τ_0_0 } <U>) -> () {
+bb0(%i: $*T, %b: $<τ_0_0> { var τ_0_0 } <U>):
+  %12 = tuple ()
+  return %12 : $()
+}
+
+sil @concrete_caller2 : $@convention(thin) () -> @owned @callee_guaranteed () -> () {
+bb0:
+  %f = function_ref @generic_callee2 : $@convention(thin) <T, U> (@in T, @owned <τ_0_0> { var τ_0_0 } <U>) -> ()
+  %i = alloc_stack $Int
+  %b = alloc_box $<τ_0_0> { var τ_0_0 } <String>
+  %c = partial_apply [callee_guaranteed] %f<Int, String>(%i, %b) : $@convention(thin) <T, U> (@in T, @owned <τ_0_0> { var τ_0_0 } <U>) -> ()
+  dealloc_stack %i : $*Int
+  return %c : $@callee_guaranteed () -> ()
+}
+
+// This is the descriptor for '<τ_0_0> { var τ_0_0 } <String>' above
+
+// CHECK:      - Capture types:
+// CHECK-NEXT: (struct Swift.String)
+// CHECK-NEXT: - Metadata sources:
+
+// CHECK:      - Capture types:
+// CHECK-NEXT: (struct Swift.Int)
+// CHECK-NEXT: (sil_box
+// CHECK-NEXT:   (struct Swift.String))
+// CHECK-NEXT:   - Metadata sources:
+
+
+// Generic caller and generic callee -- capture types are written in terms of
+// the caller's generic parameters, and metadata bindings are present for
+// structural sub-terms of the callee's substituted generic parameters that
+// contain the caller's generic parameters.
+
+sil @generic_callee3 : $@convention(thin) <T, U> (@in_guaranteed T) -> () {
+bb0(%t: $*T):
+  %12 = tuple ()
+  return %12 : $()
+}
+
+sil @generic_caller3 : $@convention(thin) <A, B, C> () -> @owned @callee_guaranteed () -> () {
+bb0:
+  %f = function_ref @generic_callee3 : $@convention(thin) <T, U> (@in_guaranteed T) -> ()
+  %t = alloc_stack $Optional<@callee_guaranteed (@in_guaranteed A) -> @out B>
+  %c = partial_apply [callee_guaranteed] %f<Optional<(A) -> B>, (B, (C) -> Int)>(%t) : $@convention(thin) <T, U> (@in_guaranteed T) -> ()
+  dealloc_stack %t : $*Optional<@callee_guaranteed (@in_guaranteed A) -> @out B>
+  return %c : $@callee_guaranteed () -> ()
+}
+
+// CHECK:      - Capture types:
+// CHECK-NEXT: (bound_generic_enum Swift.Optional
+// CHECK-NEXT:   (function
+// CHECK-NEXT:     (parameters)
+// CHECK-NEXT:     (result
+// CHECK-NEXT:       (tuple)))
+// CHECK-NEXT: - Metadata sources:
+// CHECK-NEXT: (bound_generic_enum Swift.Optional
+// CHECK-NEXT:   (function
+// CHECK-NEXT:     (parameters
+// CHECK-NEXT:       (generic_type_parameter depth=0 index=0)
+// CHECK-NEXT:     (result
+// CHECK-NEXT:       (generic_type_parameter depth=0 index=1)))
+// CHECK-NEXT: (closure_binding index=0)
+// CHECK-NEXT: (generic_type_parameter depth=0 index=1)
+// CHECK-NEXT: (closure_binding index=1)
+// CHECK-NEXT: (generic_type_parameter depth=0 index=2)
+// CHECK-NEXT: (closure_binding index=2)
+
+
+// Generic caller and generic callee -- and one of the type parameters is
+// fulfilled by a thick metatype value.
+
+sil @generic_callee4 : $@convention(thin) <T, U> (@thick Optional<T>.Type) -> () {
+bb0(%t: $@thick Optional<T>.Type):
+  %12 = tuple ()
+  return %12 : $()
+}
+
+sil @generic_caller4 : $@convention(thin) <A, B, C> () -> @owned @callee_guaranteed () -> () {
+bb0:
+  %f = function_ref @generic_callee4 : $@convention(thin) <T, U> (@thick Optional<T>.Type) -> ()
+  %t = metatype $@thick Optional<(B) -> C>.Type
+  %c = partial_apply [callee_guaranteed] %f<(B) -> C, Int>(%t) : $@convention(thin) <T, U> (@thick Optional<T>.Type) -> ()
+  return %c : $@callee_guaranteed () -> ()
+}
+
+// CHECK:      - Capture types:
+// CHECK-NEXT: (metatype was_abstract
+// CHECK-NEXT:  (bound_generic_enum Swift.Optional
+// CHECK-NEXT:    (function
+// CHECK-NEXT:      (parameters
+// CHECK-NEXT:        (generic_type_parameter depth=0 index=1)
+// CHECK-NEXT:      (result
+// CHECK-NEXT:        (generic_type_parameter depth=0 index=2))))
+// CHECK-NEXT: - Metadata sources:
+// CHECK-NEXT: (function
+// CHECK-NEXT:   (parameters
+// CHECK-NEXT:     (generic_type_parameter depth=0 index=1)
+// CHECK-NEXT:   (result
+// CHECK-NEXT:     (generic_type_parameter depth=0 index=2))
+// CHECK-NEXT: (generic_argument index=0
+// CHECK-NEXT:   (metadata_capture index=0))
+
+
+// Generic caller and generic callee -- and one of the type parameters is
+// fulfilled by the isa pointer of a class instance.
+
+class GenericClass<T, U> {}
+
+sil @generic_callee5 : $@convention(thin) <T, U, V> (@owned GenericClass<T, U>) -> () {
+bb0(%t: $GenericClass<T, U>):
+  %12 = tuple ()
+  return %12 : $()
+}
+
+sil @generic_caller5 : $@convention(thin) <A, B, C> (@owned GenericClass<(A, B), (B, C)>) -> @owned @callee_guaranteed () -> () {
+bb0(%g: $GenericClass<(A, B), (B, C)>):
+  %f = function_ref @generic_callee5 : $@convention(thin) <T, U, V> (@owned GenericClass<T, U>) -> ()
+  %c = partial_apply [callee_guaranteed] %f<(A, B), (B, C), (C, A)>(%g) : $@convention(thin) <T, U, V> (@owned GenericClass<T, U>) -> ()
+  return %c : $@callee_guaranteed () -> ()
+}
+
+sil_vtable GenericClass {}
+
+// CHECK:      - Capture types:
+// CHECK-NEXT: (bound_generic_class capture_descriptors.GenericClass
+// CHECK-NEXT:   (tuple
+// CHECK-NEXT:     (generic_type_parameter depth=0 index=0)
+// CHECK-NEXT:     (generic_type_parameter depth=0 index=1))
+// CHECK-NEXT:   (tuple
+// CHECK-NEXT:     (generic_type_parameter depth=0 index=1)
+// CHECK-NEXT:     (generic_type_parameter depth=0 index=2)))
+// CHECK-NEXT: - Metadata sources:
+// CHECK-NEXT: (generic_type_parameter depth=0 index=2)
+// CHECK-NEXT: (closure_binding index=0)
+// CHECK-NEXT: (generic_type_parameter depth=0 index=0)
+// CHECK-NEXT: (closure_binding index=1)
+// CHECK-NEXT: (tuple
+// CHECK-NEXT:   (generic_type_parameter depth=0 index=0)
+// CHECK-NEXT:   (generic_type_parameter depth=0 index=1))
+// CHECK-NEXT: (generic_argument index=0
+// CHECK-NEXT:   (reference_capture index=0))
+// CHECK-NEXT: (tuple
+// CHECK-NEXT:   (generic_type_parameter depth=0 index=1)
+// CHECK-NEXT:   (generic_type_parameter depth=0 index=2))
+// CHECK-NEXT: (generic_argument index=1
+// CHECK-NEXT:   (reference_capture index=0))
+
+
+// Pseudogeneric caller and pseudogeneric callee -- type parameters are
+// erased at runtime.
+
+sil @pseudogeneric_callee : $@convention(thin) @pseudogeneric <T : AnyObject, U : AnyObject> (@owned T, @owned U) -> () {
+bb0(%t: $T, %u: $U):
+  %12 = tuple ()
+  return %12 : $()
+}
+
+sil @pseudogeneric_caller : $@convention(thin) @pseudogeneric <A : AnyObject, B : AnyObject, C : AnyObject> (@owned A, @owned B) -> @owned @pseudogeneric @callee_guaranteed () -> () {
+bb0(%a: $A, %b: $B):
+  %f = function_ref @pseudogeneric_callee : $@convention(thin) @pseudogeneric <T : AnyObject, U : AnyObject> (@owned T, @owned U) -> ()
+  %c = partial_apply [callee_guaranteed] %f<A, B>(%a, %b) : $@convention(thin) @pseudogeneric <A : AnyObject, B : AnyObject> (@owned A, @owned B) -> ()
+  return %c : $@pseudogeneric @callee_guaranteed () -> ()
+}
+
+// CHECK:      - Capture types:
+// CHECK-NEXT:   (protocol_composition any_object)
+// CHECK-NEXT:   (protocol_composition any_object)
+// CHECK-NEXT: - Metadata sources:
+
+
+// Capturing lowered function types
+
+sil @function_callee : $@convention(thin) (@convention(thin) () -> (), @convention(c) () -> (), @convention(block) () -> (), @convention(thick) () -> (), @convention(method) () -> (), @convention(witness_method: P) (Int) -> ()) -> () {
+bb0(%thin: $@convention(thin) () -> (), %c: $@convention(c) () -> (), %block: $@convention(block) () -> (), %thick: $@convention(thick) () -> (), %method: $@convention(method) () -> (), %witness_method: $@convention(witness_method: P) (Int) -> ()):
+  %12 = tuple ()
+  return %12 : $()
+}
+
+sil @function_caller : $@convention(thin) (@convention(thin) () -> (), @convention(c) () -> (), @convention(block) () -> (), @convention(thick) () -> (), @convention(method) () -> (), @convention(witness_method: P) (Int) -> ()) -> @owned @callee_guaranteed () -> () {
+bb0(%thin: $@convention(thin) () -> (), %c: $@convention(c) () -> (), %block: $@convention(block) () -> (), %thick: $@convention(thick) () -> (), %method: $@convention(method) () -> (), %witness_method: $@convention(witness_method: P) (Int) -> ()):
+  %f = function_ref @function_callee : $@convention(thin) (@convention(thin) () -> (), @convention(c) () -> (), @convention(block) () -> (), @convention(thick) () -> (), @convention(method) () -> (), @convention(witness_method: P) (Int) -> ()) -> ()
+  %result = partial_apply [callee_guaranteed] %f(%thin, %c, %block, %thick, %method, %witness_method) : $@convention(thin) (@convention(thin) () -> (), @convention(c) () -> (), @convention(block) () -> (), @convention(thick) () -> (), @convention(method) () -> (), @convention(witness_method: P) (Int) -> ()) -> ()
+  return %result : $@callee_guaranteed () -> ()
+}
+
+// CHECK:      - Capture types:
+// CHECK-NEXT: (function convention=thin
+// CHECK-NEXT:   (parameters)
+// CHECK-NEXT:   (result
+// CHECK-NEXT:     (tuple))
+// CHECK-NEXT: (function convention=c
+// CHECK-NEXT:   (parameters)
+// CHECK-NEXT:   (result
+// CHECK-NEXT:     (tuple))
+// CHECK-NEXT: (function convention=block
+// CHECK-NEXT:   (parameters)
+// CHECK-NEXT:   (result
+// CHECK-NEXT:     (tuple))
+// CHECK-NEXT: (function
+// CHECK-NEXT:   (parameters)
+// CHECK-NEXT:   (result
+// CHECK-NEXT:     (tuple))
+// CHECK-NEXT: (function convention=thin
+// CHECK-NEXT:   (parameters)
+// CHECK-NEXT:   (result
+// CHECK-NEXT:     (tuple))
+// CHECK-NEXT: (function convention=thin
+// CHECK-NEXT:   (parameters)
+// CHECK-NEXT:   (result
+// CHECK-NEXT:     (tuple))
+// CHECK-NEXT: - Metadata sources:
+
+// Capturing opened existentials
+//
+// Not supported yet -- make sure we bail out instead of crashing.
+//
+// FIXME: Eventually, we should emit a useful capture descriptor
+// for this case.
+
+sil @existential_callee : $@convention(thin) <τ_0_0 where τ_0_0 : P> () -> @out P {
+bb0(%0 : $*P):
+  unreachable
+}
+
+
+sil @existential_caller : $@convention(thin) (@in P) -> () {
+bb0(%0 : $*P):
+  %payload = open_existential_addr immutable_access %0 : $*P to $*@opened("2D7A8F84-2973-11E7-838D-34363BD08DA0") P
+  %f = function_ref @existential_callee : $@convention(thin) <τ_0_0 where τ_0_0 : P> () -> @out P
+  %result = partial_apply [callee_guaranteed] %f<@opened("2D7A8F84-2973-11E7-838D-34363BD08DA0") P>() : $@convention(thin) <τ_0_0 where τ_0_0 : P> () -> @out P
+  destroy_value %result : $@callee_guaranteed () -> @out P
+  destroy_addr %0 : $*P
+  %tuple = tuple ()
+  return %tuple : $()
+}
diff --git a/test/Runtime/linux-fatal-backtrace.swift b/test/Runtime/linux-fatal-backtrace.swift
index 6df5ec3..202983c 100644
--- a/test/Runtime/linux-fatal-backtrace.swift
+++ b/test/Runtime/linux-fatal-backtrace.swift
@@ -4,6 +4,7 @@
 // REQUIRES: executable_test
 // REQUIRES: OS=linux-gnu
 // REQUIRES: lldb
+// REQUIRES: rdar38181372
 
 // Backtraces are not emitted when optimizations are enabled. This test can not
 // run when optimizations are enabled.
diff --git a/test/SIL/Parser/apply_with_substitution.sil b/test/SIL/Parser/apply_with_substitution.sil
index 2991489..bce0544 100644
--- a/test/SIL/Parser/apply_with_substitution.sil
+++ b/test/SIL/Parser/apply_with_substitution.sil
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend %s -emit-silgen | %FileCheck %s
 
 // rdar://14443287
diff --git a/test/SIL/Parser/bound_generic.sil b/test/SIL/Parser/bound_generic.sil
index 87c0895..73e681b 100644
--- a/test/SIL/Parser/bound_generic.sil
+++ b/test/SIL/Parser/bound_generic.sil
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend %s -emit-silgen | %FileCheck %s
 
 // rdar://14443287
diff --git a/test/SIL/Parser/generic_signature_with_depth.swift b/test/SIL/Parser/generic_signature_with_depth.swift
index d1ba566..6dc1e51 100644
--- a/test/SIL/Parser/generic_signature_with_depth.swift
+++ b/test/SIL/Parser/generic_signature_with_depth.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend %s -emit-silgen | %target-sil-opt | %FileCheck %s
 
 protocol mmGeneratorType {
diff --git a/test/SIL/Parser/keypath.sil b/test/SIL/Parser/keypath.sil
index aeae6b2..f2dad3d 100644
--- a/test/SIL/Parser/keypath.sil
+++ b/test/SIL/Parser/keypath.sil
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-sil-opt %s | %target-sil-opt | %FileCheck %s
 
 sil_stage canonical
diff --git a/test/SIL/Parser/plus_zero_apply_with_substitution.sil b/test/SIL/Parser/plus_zero_apply_with_substitution.sil
new file mode 100644
index 0000000..a63e3c0
--- /dev/null
+++ b/test/SIL/Parser/plus_zero_apply_with_substitution.sil
@@ -0,0 +1,52 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend %s -emit-silgen | %FileCheck %s
+
+// rdar://14443287
+sil_stage raw
+
+import Builtin
+import Swift
+
+// CHECK-LABEL: sil @_TF4test3fooFT1fGSqFT_T___T_ : $@convention(thin) (@guaranteed Optional<@callee_guaranteed (@in_guaranteed ()) -> @out ()>) -> ()
+sil @_TF4test3fooFT1fGSqFT_T___T_ : $@convention(thin) (@guaranteed Optional<@callee_guaranteed (@in_guaranteed ()) -> @out ()>) -> () {
+bb0(%0 : $Optional<@callee_guaranteed (@in_guaranteed ()) -> @out ()>):
+  %1 = alloc_box $<τ_0_0> { var τ_0_0 } <Optional<@callee_guaranteed (@in_guaranteed ()) -> @out ()>>  // var f    // users: %2, %6, %32
+  %1a = project_box %1 : $<τ_0_0> { var τ_0_0 } <Optional<@callee_guaranteed (@in_guaranteed ()) -> @out ()>>, 0
+  store %0 to [init] %1a : $*Optional<@callee_guaranteed (@in_guaranteed ()) -> @out ()>         // id: %2
+  %3 = alloc_stack $Optional<()>                  // users: %22, %28, %30, %31
+  %4 = alloc_stack $()                            // users: %12, %22, %25
+  %5 = alloc_stack $Optional<@callee_guaranteed (@in_guaranteed ()) -> @out ()>            // users: %6, %8, %10, %11, %16, %24
+  copy_addr %1a to [initialization] %5 : $*Optional<@callee_guaranteed (@in_guaranteed ()) -> @out ()> // id: %6
+  %7 = function_ref @_TFs22_doesOptionalHaveValueU__FT1vRGSqQ___Bi1_ : $@convention(thin) <τ_0_0> (@inout Optional<τ_0_0>) -> Builtin.Int1 // user: %8
+  %8 = apply %7<() -> ()>(%5) : $@convention(thin) <τ_0_0> (@inout Optional<τ_0_0>) -> Builtin.Int1 // user: %9
+  br bb2                                          // id: %13
+
+bb2:                                              // Preds: bb0
+  %14 = function_ref @_TFs17_getOptionalValueU__FT1vGSqQ___Q_ : $@convention(thin) <τ_0_0> (@in_guaranteed Optional<τ_0_0>) -> @out τ_0_0 // user: %16
+  %15 = alloc_stack $@callee_guaranteed (@in_guaranteed ()) -> @out () // users: %16, %17, %23
+  // CHECK: apply %{{[0-9]+}}<() -> ()>(%{{[0-9]+}}, %{{[0-9]+}}) : $@convention(thin) <τ_0_0> (@in_guaranteed Optional<τ_0_0>) -> @out τ_0_0
+  %16 = apply %14<() -> ()>(%15, %5) : $@convention(thin) <τ_0_0> (@in_guaranteed Optional<τ_0_0>) -> @out τ_0_0
+  %17 = load [take] %15 : $*@callee_guaranteed (@in_guaranteed ()) -> @out () // user: %19
+  %18 = function_ref @_TTRXFo_iT__iT__XFo__dT__ : $@convention(thin) (@guaranteed @callee_guaranteed (@in_guaranteed ()) -> @out ()) -> () // user: %19
+  %19 = partial_apply [callee_guaranteed] %18(%17) : $@convention(thin) (@guaranteed @callee_guaranteed (@in_guaranteed ()) -> @out ()) -> () // user: %20
+  %20 = apply %19() : $@callee_guaranteed () -> ()
+  %21 = function_ref @_TFs24_injectValueIntoOptionalU__FT1vQ__GSqQ__ : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> @out Optional<τ_0_0> // user: %22
+  // CHECK: apply %{{[0-9]+}}<()>(%{{[0-9]+}}, %{{[0-9]+}}) : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> @out Optional<τ_0_0>
+  %22 = apply %21<()>(%3, %4) : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> @out Optional<τ_0_0>
+  dealloc_stack %15 : $*@callee_guaranteed (@in_guaranteed ()) -> @out () // id: %23
+  dealloc_stack %5 : $*Optional<@callee_guaranteed (@in_guaranteed ()) -> @out ()> // id: %24
+  dealloc_stack %4 : $*()        // id: %25
+  br bb4                                          // id: %26
+
+bb4:                                              // Preds: bb2 bb3
+  %30 = load [trivial] %3 : $*Optional<()>
+  dealloc_stack %3 : $*Optional<()> // id: %31
+  destroy_value %1 : $<τ_0_0> { var τ_0_0 } <Optional<@callee_guaranteed (@in_guaranteed ()) -> @out ()>>
+  %33 = tuple ()                                  // user: %34
+  return %33 : $()                                // id: %34
+}
+
+sil [transparent] @_TFs22_doesOptionalHaveValueU__FT1vRGSqQ___Bi1_ : $@convention(thin) <τ_0_0> (@inout Optional<τ_0_0>) -> Builtin.Int1
+sil [transparent] @_TFs17_getOptionalValueU__FT1vGSqQ___Q_ : $@convention(thin) <τ_0_0> (@in_guaranteed Optional<τ_0_0>) -> @out τ_0_0
+sil [transparent] @_TTRXFo_iT__iT__XFo__dT__ : $@convention(thin) (@guaranteed @callee_guaranteed (@in_guaranteed ()) -> @out ()) -> ()
+sil [transparent] @_TFs24_injectValueIntoOptionalU__FT1vQ__GSqQ__ : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> @out Optional<τ_0_0>
diff --git a/test/SIL/Parser/plus_zero_bound_generic.sil b/test/SIL/Parser/plus_zero_bound_generic.sil
new file mode 100644
index 0000000..c535ee7
--- /dev/null
+++ b/test/SIL/Parser/plus_zero_bound_generic.sil
@@ -0,0 +1,47 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend %s -emit-silgen | %FileCheck %s
+
+// rdar://14443287
+sil_stage raw
+
+import Builtin
+import Swift
+
+// CHECK-LABEL: sil @_TF9optional3fooFT1fGSqFT_T___T_ : $@convention(thin) (@guaranteed Optional<@callee_guaranteed (@in_guaranteed ()) -> @out ()>) -> ()
+sil @_TF9optional3fooFT1fGSqFT_T___T_ : $@convention(thin) (@guaranteed Optional<@callee_guaranteed (@in_guaranteed ()) -> (@out ())>) -> () {
+bb0(%0 : $Optional<@callee_guaranteed (@in_guaranteed ()) -> (@out ())>):
+  %1 = alloc_box $<τ_0_0> { var τ_0_0 } <Optional<@callee_guaranteed (@in_guaranteed ()) -> (@out ())>>
+  %1a = project_box %1 : $<τ_0_0> { var τ_0_0 } <Optional<@callee_guaranteed (@in_guaranteed ()) -> (@out ())>>, 0
+  store %0 to [init] %1a : $*Optional<@callee_guaranteed (@in_guaranteed ()) -> (@out ())>
+  %3 = alloc_stack $Optional<()>
+  %4 = alloc_stack $()
+  %5 = alloc_stack $Optional<@callee_guaranteed (@in_guaranteed ()) -> (@out ())>
+  copy_addr %1a to [initialization] %5 : $*Optional<@callee_guaranteed (@in_guaranteed ()) -> (@out ())>
+  // function_ref Swift._doesOptionalHaveValue <A>(v : @inout Swift.Optional<A>) -> Builtin.Int1
+  %7 = function_ref @_TFs22_doesOptionalHaveValueU__FT1vRGSqQ___Bi1_ : $@convention(thin) <τ_0_0> (@inout Optional<τ_0_0>) -> Builtin.Int1
+  // CHECK: apply %{{[0-9]+}}<() -> ()>(%{{[0-9]+}}) : $@convention(thin) <τ_0_0> (@inout Optional<τ_0_0>) -> Builtin.Int1
+  %8 = apply %7<() -> ()>(%5) : $@convention(thin) <τ_0_0> (@inout Optional<τ_0_0>) -> Builtin.Int1
+  br bb1
+
+bb1:
+  destroy_addr %5 : $*Optional<@callee_guaranteed (@in_guaranteed ()) -> (@out ())>
+  dealloc_stack %5 : $*Optional<@callee_guaranteed (@in_guaranteed ()) -> (@out ())>
+  dealloc_stack %4 : $*()
+  br bb3
+
+bb3:
+  %27 = function_ref @_TFs26_injectNothingIntoOptionalU__FT_GSqQ__ : $@convention(thin) <τ_0_0> () -> @out Optional<τ_0_0>
+  // CHECK: apply %{{[0-9]+}}<()>(%{{[0-9]+}}) : $@convention(thin) <τ_0_0> () -> @out Optional<τ_0_0>
+  %28 = apply %27<()>(%3) : $@convention(thin) <τ_0_0> () -> @out Optional<τ_0_0>
+  br bb4
+
+bb4:
+  %30 = load [trivial] %3 : $*Optional<()>
+  dealloc_stack %3 : $*Optional<()>
+  destroy_value %1 : $<τ_0_0> { var τ_0_0 } <Optional<@callee_guaranteed (@in_guaranteed ()) -> (@out ())>>
+  %33 = tuple ()
+  return %33 : $()
+}
+
+sil [transparent] @_TFs22_doesOptionalHaveValueU__FT1vRGSqQ___Bi1_ : $@convention(thin) <τ_0_0> (@inout Optional<τ_0_0>) -> Builtin.Int1
+sil [transparent] @_TFs26_injectNothingIntoOptionalU__FT_GSqQ__ : $@convention(thin) <τ_0_0> () -> @out Optional<τ_0_0>
diff --git a/test/SIL/Parser/plus_zero_generic_signature_with_depth.swift b/test/SIL/Parser/plus_zero_generic_signature_with_depth.swift
new file mode 100644
index 0000000..f25a2a4
--- /dev/null
+++ b/test/SIL/Parser/plus_zero_generic_signature_with_depth.swift
@@ -0,0 +1,35 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend %s -emit-silgen | %target-sil-opt | %FileCheck %s
+
+protocol mmGeneratorType {
+  associatedtype Element
+}
+
+protocol mmSequenceType {
+  associatedtype Generator : mmGeneratorType
+}
+
+protocol mmCollectionType : mmSequenceType {
+}
+
+protocol mmExt : mmCollectionType {
+ mutating func extend<
+     S : mmSequenceType
+     where S.Generator.Element == Self.Generator.Element
+ > (_ seq: S)
+}
+
+// CHECK-LABEL:  @$S28generic_signature_with_depth4testyxx_q_tAA5mmExtRzAaCR_9Generator_7ElementQY_AD_AERTzr0_lF : $@convention(thin) <EC1, EC2 where EC1 : mmExt, EC2 : mmExt, EC1.Generator.Element == EC2.Generator.Element> (@in_guaranteed EC1, @in_guaranteed EC2) -> @out EC1 {
+// CHECK: witness_method $EC1, #mmExt.extend!1 : {{.*}} : $@convention(witness_method: mmExt) <τ_0_0 where τ_0_0 : mmExt><τ_1_0 where τ_1_0 : mmSequenceType, τ_0_0.Generator.Element == τ_1_0.Generator.Element> (@in_guaranteed τ_1_0, @inout τ_0_0) -> ()
+// CHECK: apply {{%[0-9]+}}<EC1, EC2>({{%[0-9]+}}, {{%[0-9]+}}) : $@convention(witness_method: mmExt) <τ_0_0 where τ_0_0 : mmExt><τ_1_0 where τ_1_0 : mmSequenceType, τ_0_0.Generator.Element == τ_1_0.Generator.Element> (@in_guaranteed τ_1_0, @inout τ_0_0) -> ()
+
+func test<
+   EC1 : mmExt,
+   EC2 : mmExt
+   where EC1.Generator.Element == EC2.Generator.Element
+>
+(_ lhs: EC1, _ rhs: EC2) -> EC1 {
+ var lhs = lhs
+ lhs.extend(rhs)
+ return lhs
+}
diff --git a/test/SIL/Parser/plus_zero_keypath.sil b/test/SIL/Parser/plus_zero_keypath.sil
new file mode 100644
index 0000000..7c9b0a0
--- /dev/null
+++ b/test/SIL/Parser/plus_zero_keypath.sil
@@ -0,0 +1,184 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-sil-opt %s | %target-sil-opt | %FileCheck %s
+
+sil_stage canonical
+
+import Swift
+
+struct S: Hashable {
+  var x: Int
+  let y: String
+  var z: C
+
+  var hashValue: Int { get }
+  static func ==(x: S, y: S) -> Bool
+}
+class C: Hashable {
+  final var x: Int
+  final let y: String
+  final var z: S
+
+  init()
+  var overridable: Int {
+    get set
+  }
+
+  var hashValue: Int { get }
+  static func ==(x: C, y: C) -> Bool
+}
+
+protocol P {}
+protocol Q {}
+protocol R {}
+
+struct Gen<A: P, B: Q, C: R> {
+  var x: A
+  let y: B
+  var z: C
+}
+
+public struct External<T> {
+  var ro: T
+
+  subscript<U: Hashable>(ro _: U) -> T { get }
+}
+
+// CHECK-LABEL: sil shared @stored_properties
+sil shared @stored_properties : $@convention(thin) () -> () {
+entry:
+  // CHECK: keypath $WritableKeyPath<S, Int>, (root $S; stored_property #S.x : $Int)
+  %a = keypath $WritableKeyPath<S, Int>, (root $S; stored_property #S.x : $Int)
+  // CHECK: keypath $ReferenceWritableKeyPath<C, Int>, (root $C; stored_property #C.x : $Int)
+  %b = keypath $ReferenceWritableKeyPath<C, Int>, (root $C; stored_property #C.x : $Int)
+  // CHECK: keypath $KeyPath<S, String>, (root $S; stored_property #S.y : $String)
+  %c = keypath $KeyPath<S, String>, (root $S; stored_property #S.y : $String)
+  // CHECK: keypath $ReferenceWritableKeyPath<S, Int>, (root $S; stored_property #S.z : $C; stored_property #C.x : $Int)
+  %d = keypath $ReferenceWritableKeyPath<S, Int>, (root $S; stored_property #S.z : $C; stored_property #C.x : $Int)
+
+  return undef : $()
+}
+
+// CHECK-LABEL: sil shared @stored_properties_generic
+sil shared @stored_properties_generic : $@convention(thin) <D: P, E: Q, F: R> () -> () {
+entry:
+  // CHECK: keypath $WritableKeyPath<Gen<D, E, F>, D>, <τ_0_0, τ_0_1, τ_0_2 where {{.*}}> (root $Gen<τ_0_0, τ_0_1, τ_0_2>; stored_property #Gen.x : $τ_0_0) <D, E, F>
+  %a = keypath $WritableKeyPath<Gen<D,E,F>, D>, <G: P, H: Q, I: R> (root $Gen<G, H, I>; stored_property #Gen.x : $G) <D, E, F>
+  // CHECK: keypath $KeyPath<Gen<D, E, F>, E>, <τ_0_0, τ_0_1, τ_0_2 where {{.*}}> (root $Gen<τ_0_0, τ_0_1, τ_0_2>; stored_property #Gen.y : $τ_0_1) <D, E, F>
+  %b = keypath $KeyPath<Gen<D,E,F>, E>, <G: P, H: Q, I: R> (root $Gen<G, H, I>; stored_property #Gen.y : $H) <D, E, F>
+
+  return undef : $()
+}
+
+sil @id_a : $@convention(thin) () -> ()
+sil @get_s_int : $@convention(thin) (@in_guaranteed S) -> @out Int
+sil @set_s_int : $@convention(thin) (@in_guaranteed Int, @in_guaranteed S) -> ()
+sil @get_c_int : $@convention(thin) (@in_guaranteed C) -> @out Int
+sil @set_c_int : $@convention(thin) (@in_guaranteed Int, @in_guaranteed C) -> ()
+sil @get_fns_fnc : $@convention(thin) (@in_guaranteed @callee_guaranteed (@in_guaranteed S) -> @out S) -> @out @callee_guaranteed (@in_guaranteed C) -> @out C
+sil @set_fns_fnc : $@convention(thin) (@in_guaranteed @callee_guaranteed (@in_guaranteed C) -> @out C, @in_guaranteed @callee_guaranteed (@in_guaranteed S) -> @out S) -> ()
+sil @get_s_int_subs : $@convention(thin) (@in_guaranteed S, UnsafeRawPointer) -> @out Int
+sil @set_s_int_subs : $@convention(thin) (@in_guaranteed Int, @in_guaranteed S, UnsafeRawPointer) -> ()
+sil @subs_eq : $@convention(thin) (UnsafeRawPointer, UnsafeRawPointer) -> Bool
+sil @subs_hash : $@convention(thin) (UnsafeRawPointer) -> Int
+sil @get_gen_int_subs : $@convention(thin) <A: Hashable, B: Hashable, C: Hashable> (@in_guaranteed A, UnsafeRawPointer) -> @out C
+sil @set_gen_int_subs : $@convention(thin) <A: Hashable, B: Hashable, C: Hashable> (@in_guaranteed C, @in_guaranteed A, UnsafeRawPointer) -> ()
+sil @gen_subs_eq : $@convention(thin) <A: Hashable, B: Hashable, C: Hashable> (UnsafeRawPointer, UnsafeRawPointer) -> Bool
+sil @gen_subs_hash : $@convention(thin) <A: Hashable, B: Hashable, C: Hashable> (UnsafeRawPointer) -> Int
+
+
+// CHECK-LABEL: sil shared @computed_properties
+sil shared @computed_properties : $@convention(thin) () -> () {
+entry:
+  // CHECK: keypath $KeyPath<S, Int>, (root $S; gettable_property $Int, id @id_a : $@convention(thin) () -> (), getter @get_s_int : $@convention(thin) (@in_guaranteed S) -> @out Int)
+  %a = keypath $KeyPath<S, Int>, (root $S; gettable_property $Int, id @id_a : $@convention(thin) () -> (), getter @get_s_int : $@convention(thin) (@in_guaranteed S) -> @out Int)
+  // CHECK: keypath $WritableKeyPath<S, Int>, (root $S; settable_property $Int, id @id_a : $@convention(thin) () -> (), getter @get_s_int : $@convention(thin) (@in_guaranteed S) -> @out Int, setter @set_s_int : $@convention(thin) (@in_guaranteed Int, @in_guaranteed S) -> ())
+  %b = keypath $WritableKeyPath<S, Int>, (root $S; settable_property $Int, id @id_a : $@convention(thin) () -> (), getter @get_s_int : $@convention(thin) (@in_guaranteed S) -> @out Int, setter @set_s_int : $@convention(thin) (@in_guaranteed Int, @in_guaranteed S) -> ())
+  // CHECK: keypath $WritableKeyPath<(S) -> S, (C) -> C>, (root $(S) -> S; settable_property $(C) -> C, id @id_a : $@convention(thin) () -> (), getter @get_fns_fnc : $@convention(thin) (@in_guaranteed @callee_guaranteed (@in_guaranteed S) -> @out S) -> @out @callee_guaranteed (@in_guaranteed C) -> @out C, setter @set_fns_fnc : $@convention(thin) (@in_guaranteed @callee_guaranteed (@in_guaranteed C) -> @out C, @in_guaranteed @callee_guaranteed (@in_guaranteed S) -> @out S) -> ())
+  %c = keypath $WritableKeyPath<(S) -> S, (C) -> C>, (root $(S) -> S; settable_property $(C) -> C, id @id_a : $@convention(thin) () -> (), getter @get_fns_fnc : $@convention(thin) (@in_guaranteed @callee_guaranteed (@in_guaranteed S) -> @out S) -> @out @callee_guaranteed (@in_guaranteed C) -> @out C, setter @set_fns_fnc : $@convention(thin) (@in_guaranteed @callee_guaranteed (@in_guaranteed C) -> @out C, @in_guaranteed @callee_guaranteed (@in_guaranteed S) -> @out S) -> ())
+  // CHECK: keypath $WritableKeyPath<C, Int>, (root $C; settable_property $Int, id #C.overridable!getter.1 : (C) -> () -> Int, getter @get_c_int : $@convention(thin) (@in_guaranteed C) -> @out Int, setter @set_c_int : $@convention(thin) (@in_guaranteed Int, @in_guaranteed C) -> ())
+  %d = keypath $WritableKeyPath<C, Int>, (root $C; settable_property $Int, id #C.overridable!getter.1 : (C) -> () -> Int, getter @get_c_int : $@convention(thin) (@in_guaranteed C) -> @out Int, setter @set_c_int : $@convention(thin) (@in_guaranteed Int, @in_guaranteed C) -> ())
+
+  return undef : $()
+}
+
+sil @get_gen_a : $@convention(thin) <X1: P, Y1: Q, Z1: R> (@in_guaranteed Gen<X1, Y1, Z1>) -> @out X1
+sil @set_gen_a : $@convention(thin) <X2: P, Y2: Q, Z2: R> (@in_guaranteed X2, @in_guaranteed Gen<X2, Y2, Z2>) -> ()
+
+// CHECK-LABEL: sil shared @computed_properties_generic
+sil shared @computed_properties_generic : $@convention(thin) <D: P, E: Q, F: R> () -> () {
+entry:
+  // CHECK: keypath $KeyPath<Gen<D, E, F>, D>, <τ_0_0, τ_0_1, τ_0_2 where τ_0_0 : P, τ_0_1 : Q, τ_0_2 : R> (root $Gen<τ_0_0, τ_0_1, τ_0_2>; settable_property $τ_0_0, id @id_a : $@convention(thin) () -> (), getter @get_gen_a : $@convention(thin) <τ_0_0, τ_0_1, τ_0_2 where τ_0_0 : P, τ_0_1 : Q, τ_0_2 : R> (@in_guaranteed Gen<τ_0_0, τ_0_1, τ_0_2>) -> @out τ_0_0, setter @set_gen_a : $@convention(thin) <τ_0_0, τ_0_1, τ_0_2 where τ_0_0 : P, τ_0_1 : Q, τ_0_2 : R> (@in_guaranteed τ_0_0, @in_guaranteed Gen<τ_0_0, τ_0_1, τ_0_2>) -> ()) <D, E, F>
+  %a = keypath $KeyPath<Gen<D, E, F>, D>, <G: P, H: Q, I: R> (root $Gen<G, H, I>; settable_property $G, id @id_a : $@convention(thin) () -> (), getter @get_gen_a : $@convention(thin) <X3: P, Y3: Q, Z3: R> (@in_guaranteed Gen<X3, Y3, Z3>) -> @out X3, setter @set_gen_a : $@convention(thin) <X4: P, Y4: Q, Z4: R> (@in_guaranteed X4, @in_guaranteed Gen<X4, Y4, Z4>) -> ()) <D, E, F>
+
+  return undef : $()
+}
+
+// CHECK-LABEL: sil @optional
+sil @optional : $@convention(thin) () -> () {
+entry:
+  // CHECK: keypath $KeyPath<Optional<Int>, Optional<Int>>, (root $Optional<Int>; optional_chain : $Int; optional_wrap : $Optional<Int>)
+  %a = keypath $KeyPath<Optional<Int>, Optional<Int>>, (root $Optional<Int>; optional_chain : $Int; optional_wrap : $Optional<Int>)
+  // CHECK: keypath $KeyPath<Optional<Int>, Int>, (root $Optional<Int>; optional_force : $Int)
+  %b = keypath $KeyPath<Optional<Int>, Int>, (root $Optional<Int>; optional_force : $Int)
+
+  return undef : $()
+}
+
+// CHECK-LABEL: sil @indexes
+sil @indexes : $@convention(thin) (S, C) -> () {
+// CHECK: bb0([[S:%.*]] : $S, [[C:%.*]] : $C):
+entry(%s : $S, %c : $C):
+  // CHECK: keypath $KeyPath<S, Int>, (root $S; settable_property $Int, id @id_a : $@convention(thin) () -> (), getter @get_s_int_subs : $@convention(thin) (@in_guaranteed S, UnsafeRawPointer) -> @out Int, setter @set_s_int_subs : $@convention(thin) (@in_guaranteed Int, @in_guaranteed S, UnsafeRawPointer) -> (), indices [%$0 : $S : $S, %$1 : $C : $C], indices_equals @subs_eq : $@convention(thin) (UnsafeRawPointer, UnsafeRawPointer) -> Bool, indices_hash @subs_hash : $@convention(thin) (UnsafeRawPointer) -> Int) ([[S]], [[C]])
+  %a = keypath $KeyPath<S, Int>, (root $S; settable_property $Int, id @id_a : $@convention(thin) () -> (), getter @get_s_int_subs : $@convention(thin) (@in_guaranteed S, UnsafeRawPointer) -> @out Int, setter @set_s_int_subs : $@convention(thin) (@in_guaranteed Int, @in_guaranteed S, UnsafeRawPointer) -> (), indices [%$0 : $S : $S, %$1 : $C : $C], indices_equals @subs_eq : $@convention(thin) (UnsafeRawPointer, UnsafeRawPointer) -> Bool, indices_hash @subs_hash : $@convention(thin) (UnsafeRawPointer) -> Int) (%s, %c)
+  // CHECK: [[T:%.*]] = alloc_stack
+  %t = alloc_stack $S
+  // CHECK: [[D:%.*]] = alloc_stack
+  %d = alloc_stack $C
+  // CHECK: keypath $KeyPath<S, Int>, <τ_0_0, τ_0_1, τ_0_2 where τ_0_0 : Hashable, τ_0_1 : Hashable, τ_0_2 : Hashable> (root $τ_0_0; settable_property $τ_0_2, id @id_a : $@convention(thin) () -> (), getter @get_gen_int_subs : $@convention(thin) <τ_0_0, τ_0_1, τ_0_2 where τ_0_0 : Hashable, τ_0_1 : Hashable, τ_0_2 : Hashable> (@in_guaranteed τ_0_0, UnsafeRawPointer) -> @out τ_0_2, setter @set_gen_int_subs : $@convention(thin) <τ_0_0, τ_0_1, τ_0_2 where τ_0_0 : Hashable, τ_0_1 : Hashable, τ_0_2 : Hashable> (@in_guaranteed τ_0_2, @in_guaranteed τ_0_0, UnsafeRawPointer) -> (), indices [%$0 : $τ_0_0 : $*τ_0_0, %$1 : $τ_0_1 : $*τ_0_1], indices_equals @gen_subs_eq : $@convention(thin) <τ_0_0, τ_0_1, τ_0_2 where τ_0_0 : Hashable, τ_0_1 : Hashable, τ_0_2 : Hashable> (UnsafeRawPointer, UnsafeRawPointer) -> Bool, indices_hash @gen_subs_hash : $@convention(thin) <τ_0_0, τ_0_1, τ_0_2 where τ_0_0 : Hashable, τ_0_1 : Hashable, τ_0_2 : Hashable> (UnsafeRawPointer) -> Int) <S, C, Int> ([[T]], [[D]])
+  %b = keypath $KeyPath<S, Int>, <τ_0_0: Hashable, Y: Hashable, Z: Hashable> (root $τ_0_0; settable_property $Z, id @id_a : $@convention(thin) () -> (), getter @get_gen_int_subs : $@convention(thin) <A: Hashable, B: Hashable, C: Hashable> (@in_guaranteed A, UnsafeRawPointer) -> @out C, setter @set_gen_int_subs : $@convention(thin) <A: Hashable, B: Hashable, C: Hashable> (@in_guaranteed C, @in_guaranteed A, UnsafeRawPointer) -> (), indices [%$0 : $τ_0_0 : $*τ_0_0, %$1 : $Y : $*Y], indices_equals @gen_subs_eq : $@convention(thin) <A: Hashable, B: Hashable, C: Hashable> (UnsafeRawPointer, UnsafeRawPointer) -> Bool, indices_hash @gen_subs_hash : $@convention(thin) <A: Hashable, B: Hashable, C: Hashable> (UnsafeRawPointer) -> Int) <S, C, Int> (%t, %d)
+
+  dealloc_stack %d : $*C
+  dealloc_stack %t : $*S
+
+  return undef : $()
+}
+
+// CHECK-LABEL: sil @external
+sil @external : $@convention(thin) <A, B: Hashable> (@in_guaranteed B) -> () {
+entry(%z : $*B):
+  // CHECK: %1 = keypath $KeyPath<External<Int>, Int>, (root $External<Int>; external #External.ro<Int> : $Int)
+  %a = keypath $KeyPath<External<Int>, Int>, (root $External<Int>; external #External.ro<Int> : $Int)
+
+  // CHECK: %2 = keypath $KeyPath<External<A>, A>, <τ_0_0, τ_0_1, τ_0_2> (root $External<τ_0_2>; external #External.ro<τ_0_2> : $τ_0_2) <A, A, A>
+  %b = keypath $KeyPath<External<A>, A>, <C, D, E> (root $External<E>; external #External.ro <E> : $E) <A, A, A>
+
+  // CHECK: %3 = keypath $KeyPath<External<Int>, Int>, <τ_0_0> (root $External<τ_0_0>; external #External.ro<τ_0_0> : $τ_0_0) <Int>
+  %c = keypath $KeyPath<External<Int>, Int>, <F> (root $External<F>; external #External.ro <F> : $F) <Int>
+
+  // CHECK: %4 = keypath $KeyPath<External<A>, A>, <τ_0_0, τ_0_1 where τ_0_0 : Hashable> (root $External<τ_0_1>; external #External.subscript<τ_0_1, τ_0_0>[%$0 : $τ_0_0 : $*τ_0_0] : $τ_0_1) <B, A> (%0)
+  %d = keypath $KeyPath<External<A>, A>, <G: Hashable, H> (root $External<H>; external #External.subscript <H, G> [%$0 : $G : $*G] : $H) <B, A> (%z)
+
+  return undef : $()
+}
+
+sil @get_external_subscript : $@convention(thin) <T, U: Hashable> (@in_guaranteed External<T>, UnsafeRawPointer) -> @out T
+sil @equals_external_subscript : $@convention(thin) <T, U: Hashable> (UnsafeRawPointer, UnsafeRawPointer) -> Bool
+sil @hash_external_subscript : $@convention(thin) <T, U: Hashable> (UnsafeRawPointer) -> Int
+
+// CHECK-LABEL: sil_property #External.ro<τ_0_0> (stored_property #External.ro : $τ_0_0)
+sil_property #External.ro <T> (stored_property #External.ro : $T)
+
+// CHECK-LABEL: sil_property #External.subscript<τ_0_0><τ_1_0 where τ_1_0 : Hashable> (gettable_property $τ_0_0,
+// CHECK-SAME:   id @id_a : $@convention(thin) () -> (),
+// CHECK-SAME:   getter @get_external_subscript : $@convention(thin) <τ_0_0, τ_0_1 where τ_0_1 : Hashable> (@in_guaranteed External<τ_0_0>, UnsafeRawPointer) -> @out τ_0_0,
+// CHECK-SAME:   indices [%$0 : $τ_1_0 : $*τ_1_0],
+// CHECK-SAME:   indices_equals @equals_external_subscript : $@convention(thin) <τ_0_0, τ_0_1 where τ_0_1 : Hashable> (UnsafeRawPointer, UnsafeRawPointer) -> Bool,
+// CHECK-SAME:   indices_hash @hash_external_subscript : $@convention(thin) <τ_0_0, τ_0_1 where τ_0_1 : Hashable> (UnsafeRawPointer) -> Int)
+sil_property #External.subscript <T><U: Hashable> (gettable_property $T,
+  id @id_a : $@convention(thin) () -> (),
+  getter @get_external_subscript : $@convention(thin) <T, U: Hashable> (@in_guaranteed External<T>, UnsafeRawPointer) -> @out T,
+  indices [%$0 : $U : $*U],
+  indices_equals @equals_external_subscript : $@convention(thin) <T, U: Hashable> (UnsafeRawPointer, UnsafeRawPointer) -> Bool,
+  indices_hash @hash_external_subscript : $@convention(thin) <T, U: Hashable> (UnsafeRawPointer) -> Int)
+
+
diff --git a/test/SIL/Serialization/deserialize_generic.sil b/test/SIL/Serialization/deserialize_generic.sil
index bbd1533..4d22ac5 100644
--- a/test/SIL/Serialization/deserialize_generic.sil
+++ b/test/SIL/Serialization/deserialize_generic.sil
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %empty-directory(%t)
 // RUN: %target-swift-frontend -emit-module -o %t %S/Inputs/def_generic.swift
 // RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil -linker -I %t %s | %FileCheck %s
diff --git a/test/SIL/Serialization/deserialize_generic_marker.sil b/test/SIL/Serialization/deserialize_generic_marker.sil
index eebbde4..b63ef5c 100644
--- a/test/SIL/Serialization/deserialize_generic_marker.sil
+++ b/test/SIL/Serialization/deserialize_generic_marker.sil
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %empty-directory(%t)
 // RUN: %target-swift-frontend -emit-module -o %t %S/Inputs/def_generic_marker.swift
 // RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil -linker -I %t %s | %FileCheck %s
diff --git a/test/SIL/Serialization/keypath.sil b/test/SIL/Serialization/keypath.sil
index 684f57d..73a927d 100644
--- a/test/SIL/Serialization/keypath.sil
+++ b/test/SIL/Serialization/keypath.sil
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // First parse this and then emit a *.sib. Then read in the *.sib, then recreate
 // RUN: %empty-directory(%t)
 // RUN: %target-sil-opt %s -emit-sib -o %t/tmp.sib -module-name boxes
diff --git a/test/SIL/Serialization/plus_zero_deserialize_generic.sil b/test/SIL/Serialization/plus_zero_deserialize_generic.sil
new file mode 100644
index 0000000..d8aa071
--- /dev/null
+++ b/test/SIL/Serialization/plus_zero_deserialize_generic.sil
@@ -0,0 +1,26 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %empty-directory(%t)
+// RUN: %target-swift-frontend -emit-module -o %t %S/Inputs/def_generic.swift
+// RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil -linker -I %t %s | %FileCheck %s
+
+// Make sure that SILFunctionType with GenericSignature can match up with
+// SILFunctionType deserialized from module.
+
+sil_stage raw
+
+import def_generic
+import Builtin
+import Swift
+
+// CHECK-LABEL: sil @top_level_code
+// CHECK: function_ref @$S11def_generic1AC23convertFromArrayLiteralyACyxGxd_tF
+sil @top_level_code : $@convention(thin) () -> () {
+bb0:
+  %3 = function_ref @$S11def_generic1AC23convertFromArrayLiteralyACyxGxd_tF : $@convention(method) <T> (@guaranteed Array<T>, @guaranteed A<T>) -> @owned A<T>
+  %0 = tuple ()                                   // user: %1
+  return %0 : $()                                 // id: %1
+}
+
+// Make sure the function body is deserialized.
+// CHECK-LABEL: sil public_external [serialized] [canonical] @$S11def_generic1AC23convertFromArrayLiteralyACyxGxd_tF : $@convention(method) <T> (@guaranteed Array<T>, @guaranteed A<T>) -> @owned A<T> {
+sil @$S11def_generic1AC23convertFromArrayLiteralyACyxGxd_tF : $@convention(method) <T> (@guaranteed Array<T>, @guaranteed A<T>) -> @owned A<T>
diff --git a/test/SIL/Serialization/plus_zero_deserialize_generic_marker.sil b/test/SIL/Serialization/plus_zero_deserialize_generic_marker.sil
new file mode 100644
index 0000000..bb3984d
--- /dev/null
+++ b/test/SIL/Serialization/plus_zero_deserialize_generic_marker.sil
@@ -0,0 +1,24 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %empty-directory(%t)
+// RUN: %target-swift-frontend -emit-module -o %t %S/Inputs/def_generic_marker.swift
+// RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil -linker -I %t %s | %FileCheck %s
+
+// Make sure that SILFunctionType with GenericSignature can match up with
+// SILFunctionType deserialized from module.
+
+import def_generic_marker
+import Builtin
+import Swift
+
+// CHECK-LABEL: sil @top_level_code
+// CHECK: function_ref @$S18def_generic_marker4testyxx_q_tAA16mmCollectionTypeRzAaCR_9Generator_7ElementQY_AD_AERTzr0_lF : $@convention(thin) <τ_0_0, τ_0_1 where τ_0_0 : mmCollectionType, τ_0_1 : mmCollectionType, τ_0_0.Generator.Element == τ_0_1.Generator.Element> (@in_guaranteed τ_0_0, @in_guaranteed τ_0_1) -> @out τ_0_0
+sil @top_level_code : $@convention(thin) () -> () {
+bb0:
+  %43 = function_ref @$S18def_generic_marker4testyxx_q_tAA16mmCollectionTypeRzAaCR_9Generator_7ElementQY_AD_AERTzr0_lF : $@convention(thin) <EC1, EC2 where EC1 : mmCollectionType, EC2 : mmCollectionType, EC1.Generator.Element == EC2.Generator.Element> (@in_guaranteed EC1, @in_guaranteed EC2) -> @out EC1
+  %0 = tuple ()
+  return %0 : $()
+}
+
+// Make sure the function body is deserialized.
+// CHECK-LABEL: @$S18def_generic_marker4testyxx_q_tAA16mmCollectionTypeRzAaCR_9Generator_7ElementQY_AD_AERTzr0_lF : $@convention(thin) <EC1, EC2 where EC1 : mmCollectionType, EC2 : mmCollectionType, EC1.Generator.Element == EC2.Generator.Element> (@in_guaranteed EC1, @in_guaranteed EC2) -> @out EC1 {
+sil @$S18def_generic_marker4testyxx_q_tAA16mmCollectionTypeRzAaCR_9Generator_7ElementQY_AD_AERTzr0_lF : $@convention(thin) <EC1, EC2 where EC1 : mmCollectionType, EC2 : mmCollectionType, EC1.Generator.Element == EC2.Generator.Element> (@in_guaranteed EC1, @in_guaranteed EC2) -> @out EC1
diff --git a/test/SIL/Serialization/plus_zero_keypath.sil b/test/SIL/Serialization/plus_zero_keypath.sil
new file mode 100644
index 0000000..00a9747
--- /dev/null
+++ b/test/SIL/Serialization/plus_zero_keypath.sil
@@ -0,0 +1,200 @@
+// REQUIRES: plus_zero_runtime
+// First parse this and then emit a *.sib. Then read in the *.sib, then recreate
+// RUN: %empty-directory(%t)
+// RUN: %target-sil-opt %s -emit-sib -o %t/tmp.sib -module-name boxes
+// RUN: %target-sil-opt %t/tmp.sib -o %t/tmp.2.sib -module-name boxes
+// RUN: %target-sil-opt %t/tmp.2.sib -module-name boxes | %FileCheck %s
+
+sil_stage canonical
+
+import Swift
+
+struct S: Hashable {
+  var x: Int
+  let y: String
+  var z: C
+
+  var hashValue: Int { get }
+  static func ==(x: S, y: S) -> Bool
+}
+class C: Hashable {
+  final var x: Int
+  final let y: String
+  final var z: S
+
+  init()
+  var overridable: Int {
+    get set
+  }
+
+  var hashValue: Int { get }
+  static func ==(x: C, y: C) -> Bool
+}
+
+protocol P {}
+protocol Q {}
+protocol R {}
+
+struct Gen<A: P, B: Q, C: R> {
+  var x: A
+  let y: B
+  var z: C
+}
+
+public struct External<T> {
+  var ro: T { get }
+
+  subscript<U: Hashable>(ro _: U) -> T { get }
+}
+
+// CHECK-LABEL: sil shared [serialized] @stored_properties
+sil shared [serialized] @stored_properties : $@convention(thin) () -> () {
+entry:
+  // CHECK: keypath $WritableKeyPath<S, Int>, (root $S; stored_property #S.x : $Int)
+  %a = keypath $WritableKeyPath<S, Int>, (root $S; stored_property #S.x : $Int)
+  // CHECK: keypath $ReferenceWritableKeyPath<C, Int>, (root $C; stored_property #C.x : $Int)
+  %b = keypath $ReferenceWritableKeyPath<C, Int>, (root $C; stored_property #C.x : $Int)
+  // CHECK: keypath $KeyPath<S, String>, (root $S; stored_property #S.y : $String)
+  %c = keypath $KeyPath<S, String>, (root $S; stored_property #S.y : $String)
+  // CHECK: keypath $ReferenceWritableKeyPath<S, Int>, (root $S; stored_property #S.z : $C; stored_property #C.x : $Int)
+  %d = keypath $ReferenceWritableKeyPath<S, Int>, (root $S; stored_property #S.z : $C; stored_property #C.x : $Int)
+
+  return undef : $()
+}
+
+// CHECK-LABEL: sil shared [serialized] @stored_properties_generic
+sil shared [serialized] @stored_properties_generic : $@convention(thin) <D: P, E: Q, F: R> () -> () {
+entry:
+  // CHECK: keypath $WritableKeyPath<Gen<D, E, F>, D>, <τ_0_0, τ_0_1, τ_0_2 where {{.*}}> (root $Gen<τ_0_0, τ_0_1, τ_0_2>; stored_property #Gen.x : $τ_0_0) <D, E, F>
+  %a = keypath $WritableKeyPath<Gen<D,E,F>, D>, <G: P, H: Q, I: R> (root $Gen<G, H, I>; stored_property #Gen.x : $G) <D, E, F>
+  // CHECK: keypath $KeyPath<Gen<D, E, F>, E>, <τ_0_0, τ_0_1, τ_0_2 where {{.*}}> (root $Gen<τ_0_0, τ_0_1, τ_0_2>; stored_property #Gen.y : $τ_0_1) <D, E, F>
+  %b = keypath $KeyPath<Gen<D,E,F>, E>, <G: P, H: Q, I: R> (root $Gen<G, H, I>; stored_property #Gen.y : $H) <D, E, F>
+
+  return undef : $()
+}
+
+sil @id_a : $@convention(thin) () -> ()
+sil @get_s_int : $@convention(thin) (@in_guaranteed S) -> @out Int
+sil @set_s_int : $@convention(thin) (@in_guaranteed Int, @in_guaranteed S) -> ()
+sil @get_c_int : $@convention(thin) (@in_guaranteed C) -> @out Int
+sil @set_c_int : $@convention(thin) (@in_guaranteed Int, @in_guaranteed C) -> ()
+sil @get_fns_fnc : $@convention(thin) (@in_guaranteed @callee_guaranteed (@in_guaranteed S) -> @out S) -> @out @callee_guaranteed (@in_guaranteed C) -> @out C
+sil @set_fns_fnc : $@convention(thin) (@in_guaranteed @callee_guaranteed (@in_guaranteed C) -> @out C, @in_guaranteed @callee_guaranteed (@in_guaranteed S) -> @out S) -> ()
+sil @get_s_int_subs : $@convention(thin) (@in_guaranteed S, UnsafeRawPointer) -> @out Int
+sil @set_s_int_subs : $@convention(thin) (@in_guaranteed Int, @in_guaranteed S, UnsafeRawPointer) -> ()
+sil @subs_eq : $@convention(thin) (UnsafeRawPointer, UnsafeRawPointer) -> Bool
+sil @subs_hash : $@convention(thin) (UnsafeRawPointer) -> Int
+sil @get_gen_int_subs : $@convention(thin) <A: Hashable, B: Hashable, C: Hashable> (@in_guaranteed A, UnsafeRawPointer) -> @out C
+sil @set_gen_int_subs : $@convention(thin) <A: Hashable, B: Hashable, C: Hashable> (@in_guaranteed C, @in_guaranteed A, UnsafeRawPointer) -> ()
+sil @gen_subs_eq : $@convention(thin) <A: Hashable, B: Hashable, C: Hashable> (UnsafeRawPointer, UnsafeRawPointer) -> Bool
+sil @gen_subs_hash : $@convention(thin) <A: Hashable, B: Hashable, C: Hashable> (UnsafeRawPointer) -> Int
+
+// CHECK-LABEL: sil shared [serialized] @computed_properties
+sil shared [serialized] @computed_properties : $@convention(thin) () -> () {
+entry:
+  // CHECK: keypath $KeyPath<S, Int>, (root $S; gettable_property $Int, id @id_a : $@convention(thin) () -> (), getter @get_s_int : $@convention(thin) (@in_guaranteed S) -> @out Int)
+  %a = keypath $KeyPath<S, Int>, (root $S; gettable_property $Int, id @id_a : $@convention(thin) () -> (), getter @get_s_int : $@convention(thin) (@in_guaranteed S) -> @out Int)
+  // CHECK: keypath $WritableKeyPath<S, Int>, (root $S; settable_property $Int, id @id_a : $@convention(thin) () -> (), getter @get_s_int : $@convention(thin) (@in_guaranteed S) -> @out Int, setter @set_s_int : $@convention(thin) (@in_guaranteed Int, @in_guaranteed S) -> ())
+  %b = keypath $WritableKeyPath<S, Int>, (root $S; settable_property $Int, id @id_a : $@convention(thin) () -> (), getter @get_s_int : $@convention(thin) (@in_guaranteed S) -> @out Int, setter @set_s_int : $@convention(thin) (@in_guaranteed Int, @in_guaranteed S) -> ())
+  // CHECK: keypath $WritableKeyPath<(S) -> S, (C) -> C>, (root $(S) -> S; settable_property $(C) -> C, id @id_a : $@convention(thin) () -> (), getter @get_fns_fnc : $@convention(thin) (@in_guaranteed @callee_guaranteed (@in_guaranteed S) -> @out S) -> @out @callee_guaranteed (@in_guaranteed C) -> @out C, setter @set_fns_fnc : $@convention(thin) (@in_guaranteed @callee_guaranteed (@in_guaranteed C) -> @out C, @in_guaranteed @callee_guaranteed (@in_guaranteed S) -> @out S) -> ())
+  %c = keypath $WritableKeyPath<(S) -> S, (C) -> C>, (root $(S) -> S; settable_property $(C) -> C, id @id_a : $@convention(thin) () -> (), getter @get_fns_fnc : $@convention(thin) (@in_guaranteed @callee_guaranteed (@in_guaranteed S) -> @out S) -> @out @callee_guaranteed (@in_guaranteed C) -> @out C, setter @set_fns_fnc : $@convention(thin) (@in_guaranteed @callee_guaranteed (@in_guaranteed C) -> @out C, @in_guaranteed @callee_guaranteed (@in_guaranteed S) -> @out S) -> ())
+  // CHECK: keypath $WritableKeyPath<C, Int>, (root $C; settable_property $Int, id #C.overridable!getter.1 : (C) -> () -> Int, getter @get_c_int : $@convention(thin) (@in_guaranteed C) -> @out Int, setter @set_c_int : $@convention(thin) (@in_guaranteed Int, @in_guaranteed C) -> ())
+  %d = keypath $WritableKeyPath<C, Int>, (root $C; settable_property $Int, id #C.overridable!getter.1 : (C) -> () -> Int, getter @get_c_int : $@convention(thin) (@in_guaranteed C) -> @out Int, setter @set_c_int : $@convention(thin) (@in_guaranteed Int, @in_guaranteed C) -> ())
+
+  return undef : $()
+}
+
+sil @get_gen_a : $@convention(thin) <X1: P, Y1: Q, Z1: R> (@in_guaranteed Gen<X1, Y1, Z1>) -> @out X1
+sil @set_gen_a : $@convention(thin) <X2: P, Y2: Q, Z2: R> (@in_guaranteed X2, @in_guaranteed Gen<X2, Y2, Z2>) -> ()
+
+// CHECK-LABEL: sil shared [serialized] @computed_properties_generic
+sil shared [serialized] @computed_properties_generic : $@convention(thin) <D: P, E: Q, F: R> () -> () {
+entry:
+  // CHECK: keypath $KeyPath<Gen<D, E, F>, D>, <τ_0_0, τ_0_1, τ_0_2 where τ_0_0 : P, τ_0_1 : Q, τ_0_2 : R> (root $Gen<τ_0_0, τ_0_1, τ_0_2>; settable_property $τ_0_0, id @id_a : $@convention(thin) () -> (), getter @get_gen_a : $@convention(thin) <τ_0_0, τ_0_1, τ_0_2 where τ_0_0 : P, τ_0_1 : Q, τ_0_2 : R> (@in_guaranteed Gen<τ_0_0, τ_0_1, τ_0_2>) -> @out τ_0_0, setter @set_gen_a : $@convention(thin) <τ_0_0, τ_0_1, τ_0_2 where τ_0_0 : P, τ_0_1 : Q, τ_0_2 : R> (@in_guaranteed τ_0_0, @in_guaranteed Gen<τ_0_0, τ_0_1, τ_0_2>) -> ()) <D, E, F>
+  %a = keypath $KeyPath<Gen<D, E, F>, D>, <G: P, H: Q, I: R> (root $Gen<G, H, I>; settable_property $G, id @id_a : $@convention(thin) () -> (), getter @get_gen_a : $@convention(thin) <X3: P, Y3: Q, Z3: R> (@in_guaranteed Gen<X3, Y3, Z3>) -> @out X3, setter @set_gen_a : $@convention(thin) <X4: P, Y4: Q, Z4: R> (@in_guaranteed X4, @in_guaranteed Gen<X4, Y4, Z4>) -> ()) <D, E, F>
+
+  return undef : $()
+}
+
+// CHECK-LABEL: sil shared [serialized] @optional
+sil shared [serialized] @optional : $@convention(thin) () -> () {
+entry:
+  // CHECK: keypath $KeyPath<Optional<Int>, Optional<Int>>, (root $Optional<Int>; optional_chain : $Int; optional_wrap : $Optional<Int>)
+  %a = keypath $KeyPath<Optional<Int>, Optional<Int>>, (root $Optional<Int>; optional_chain : $Int; optional_wrap : $Optional<Int>)
+  // CHECK: keypath $KeyPath<Optional<Int>, Int>, (root $Optional<Int>; optional_force : $Int)
+  %b = keypath $KeyPath<Optional<Int>, Int>, (root $Optional<Int>; optional_force : $Int)
+
+  return undef : $()
+}
+
+// CHECK-LABEL: sil shared [serialized] @indexes
+sil shared [serialized] @indexes : $@convention(thin) (S, C) -> () {
+// CHECK: bb0([[S:%.*]] : $S, [[C:%.*]] : $C):
+entry(%s : $S, %c : $C):
+  // CHECK: keypath $KeyPath<S, Int>, (root $S; settable_property $Int, id @id_a : $@convention(thin) () -> (), getter @get_s_int_subs : $@convention(thin) (@in_guaranteed S, UnsafeRawPointer) -> @out Int, setter @set_s_int_subs : $@convention(thin) (@in_guaranteed Int, @in_guaranteed S, UnsafeRawPointer) -> (), indices [%$0 : $S : $S, %$1 : $C : $C], indices_equals @subs_eq : $@convention(thin) (UnsafeRawPointer, UnsafeRawPointer) -> Bool, indices_hash @subs_hash : $@convention(thin) (UnsafeRawPointer) -> Int) ([[S]], [[C]])
+  %a = keypath $KeyPath<S, Int>, (root $S; settable_property $Int, id @id_a : $@convention(thin) () -> (), getter @get_s_int_subs : $@convention(thin) (@in_guaranteed S, UnsafeRawPointer) -> @out Int, setter @set_s_int_subs : $@convention(thin) (@in_guaranteed Int, @in_guaranteed S, UnsafeRawPointer) -> (), indices [%$0 : $S : $S, %$1 : $C : $C], indices_equals @subs_eq : $@convention(thin) (UnsafeRawPointer, UnsafeRawPointer) -> Bool, indices_hash @subs_hash : $@convention(thin) (UnsafeRawPointer) -> Int) (%s, %c)
+  // CHECK: [[T:%.*]] = alloc_stack
+  %t = alloc_stack $S
+  // CHECK: [[D:%.*]] = alloc_stack
+  %d = alloc_stack $C
+  // CHECK: keypath $KeyPath<S, Int>, <τ_0_0, τ_0_1, τ_0_2 where τ_0_0 : Hashable, τ_0_1 : Hashable, τ_0_2 : Hashable> (root $τ_0_0; settable_property $τ_0_2, id @id_a : $@convention(thin) () -> (), getter @get_gen_int_subs : $@convention(thin) <τ_0_0, τ_0_1, τ_0_2 where τ_0_0 : Hashable, τ_0_1 : Hashable, τ_0_2 : Hashable> (@in_guaranteed τ_0_0, UnsafeRawPointer) -> @out τ_0_2, setter @set_gen_int_subs : $@convention(thin) <τ_0_0, τ_0_1, τ_0_2 where τ_0_0 : Hashable, τ_0_1 : Hashable, τ_0_2 : Hashable> (@in_guaranteed τ_0_2, @in_guaranteed τ_0_0, UnsafeRawPointer) -> (), indices [%$0 : $τ_0_0 : $*τ_0_0, %$1 : $τ_0_1 : $*τ_0_1], indices_equals @gen_subs_eq : $@convention(thin) <τ_0_0, τ_0_1, τ_0_2 where τ_0_0 : Hashable, τ_0_1 : Hashable, τ_0_2 : Hashable> (UnsafeRawPointer, UnsafeRawPointer) -> Bool, indices_hash @gen_subs_hash : $@convention(thin) <τ_0_0, τ_0_1, τ_0_2 where τ_0_0 : Hashable, τ_0_1 : Hashable, τ_0_2 : Hashable> (UnsafeRawPointer) -> Int) <S, C, Int> ([[T]], [[D]])
+  %b = keypath $KeyPath<S, Int>, <τ_0_0: Hashable, Y: Hashable, Z: Hashable> (root $τ_0_0; settable_property $Z, id @id_a : $@convention(thin) () -> (), getter @get_gen_int_subs : $@convention(thin) <A: Hashable, B: Hashable, C: Hashable> (@in_guaranteed A, UnsafeRawPointer) -> @out C, setter @set_gen_int_subs : $@convention(thin) <A: Hashable, B: Hashable, C: Hashable> (@in_guaranteed C, @in_guaranteed A, UnsafeRawPointer) -> (), indices [%$0 : $τ_0_0 : $*τ_0_0, %$1 : $Y : $*Y], indices_equals @gen_subs_eq : $@convention(thin) <A: Hashable, B: Hashable, C: Hashable> (UnsafeRawPointer, UnsafeRawPointer) -> Bool, indices_hash @gen_subs_hash : $@convention(thin) <A: Hashable, B: Hashable, C: Hashable> (UnsafeRawPointer) -> Int) <S, C, Int> (%t, %d)
+
+  dealloc_stack %d : $*C
+  dealloc_stack %t : $*S
+
+  return undef : $()
+}
+
+// CHECK-LABEL: sil shared [serialized] @external
+sil shared [serialized] @external : $@convention(thin) <A, B: Hashable> (@in_guaranteed B) -> () {
+entry(%z : $*B):
+  // CHECK: %1 = keypath $KeyPath<External<Int>, Int>, (root $External<Int>; external #External.ro<Int> : $Int)
+  %a = keypath $KeyPath<External<Int>, Int>, (root $External<Int>; external #External.ro<Int> : $Int)
+
+  // CHECK: %2 = keypath $KeyPath<External<A>, A>, <τ_0_0, τ_0_1, τ_0_2> (root $External<τ_0_2>; external #External.ro<τ_0_2> : $τ_0_2) <A, A, A>
+  %b = keypath $KeyPath<External<A>, A>, <C, D, E> (root $External<E>; external #External.ro <E> : $E) <A, A, A>
+
+  // CHECK: %3 = keypath $KeyPath<External<Int>, Int>, <τ_0_0> (root $External<τ_0_0>; external #External.ro<τ_0_0> : $τ_0_0) <Int>
+  %c = keypath $KeyPath<External<Int>, Int>, <F> (root $External<F>; external #External.ro <F> : $F) <Int>
+
+  // CHECK: %4 = keypath $KeyPath<External<A>, A>, <τ_0_0, τ_0_1 where τ_0_0 : Hashable> (root $External<τ_0_1>; external #External.subscript<τ_0_1, τ_0_0>[%$0 : $τ_0_0 : $*τ_0_0] : $τ_0_1) <B, A> (%0)
+  %d = keypath $KeyPath<External<A>, A>, <G: Hashable, H> (root $External<H>; external #External.subscript <H, G> [%$0 : $G : $*G] : $H) <B, A> (%z)
+
+  return undef : $()
+}
+
+sil [serialized] @serialize_all : $@convention(thin) () -> () {
+entry:
+  %0 = function_ref @stored_properties : $@convention(thin) () -> ()
+  %1 = function_ref @stored_properties_generic : $@convention(thin) <D: P, E: Q, F: R> () -> ()
+  %2 = function_ref @computed_properties : $@convention(thin) () -> ()
+  %3 = function_ref @computed_properties_generic : $@convention(thin) <D: P, E: Q, F: R> () -> ()
+  %4 = function_ref @optional : $@convention(thin) () -> ()
+  %5 = function_ref @indexes : $@convention(thin) (S, C) -> ()
+  %6 = function_ref @external : $@convention(thin) <A, B: Hashable> (@in_guaranteed B) -> ()
+
+  unreachable
+}
+
+sil [serialized] @get_external_subscript : $@convention(thin) <T, U: Hashable> (@in_guaranteed External<T>, UnsafeRawPointer) -> @out T
+sil [serialized] @equals_external_subscript : $@convention(thin) <T, U: Hashable> (UnsafeRawPointer, UnsafeRawPointer) -> Bool
+sil [serialized] @hash_external_subscript : $@convention(thin) <T, U: Hashable> (UnsafeRawPointer) -> Int
+
+// CHECK-LABEL: sil_property [serialized] #External.ro<τ_0_0> (stored_property #External.ro : $τ_0_0)
+sil_property [serialized] #External.ro <T> (stored_property #External.ro : $T)
+
+// CHECK-LABEL: sil_property [serialized] #External.subscript<τ_0_0><τ_1_0 where τ_1_0 : Hashable> (gettable_property $τ_0_0,
+// CHECK-SAME:   id @id_a : $@convention(thin) () -> (),
+// CHECK-SAME:   getter @get_external_subscript : $@convention(thin) <τ_0_0, τ_0_1 where τ_0_1 : Hashable> (@in_guaranteed External<τ_0_0>, UnsafeRawPointer) -> @out τ_0_0,
+// CHECK-SAME:   indices [%$0 : $τ_1_0 : $*τ_1_0],
+// CHECK-SAME:   indices_equals @equals_external_subscript : $@convention(thin) <τ_0_0, τ_0_1 where τ_0_1 : Hashable> (UnsafeRawPointer, UnsafeRawPointer) -> Bool,
+// CHECK-SAME:   indices_hash @hash_external_subscript : $@convention(thin) <τ_0_0, τ_0_1 where τ_0_1 : Hashable> (UnsafeRawPointer) -> Int)
+sil_property [serialized] #External.subscript <T><U: Hashable> (gettable_property $T,
+  id @id_a : $@convention(thin) () -> (),
+  getter @get_external_subscript : $@convention(thin) <T, U: Hashable> (@in_guaranteed External<T>, UnsafeRawPointer) -> @out T,
+  indices [%$0 : $U : $*U],
+  indices_equals @equals_external_subscript : $@convention(thin) <T, U: Hashable> (UnsafeRawPointer, UnsafeRawPointer) -> Bool,
+  indices_hash @hash_external_subscript : $@convention(thin) <T, U: Hashable> (UnsafeRawPointer) -> Int)
+
+
diff --git a/test/SILGen/access_marker_gen.swift b/test/SILGen/access_marker_gen.swift
index fff4558..974aa66 100644
--- a/test/SILGen/access_marker_gen.swift
+++ b/test/SILGen/access_marker_gen.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -parse-as-library -Xllvm -sil-full-demangle -enforce-exclusivity=checked -emit-silgen -enable-sil-ownership %s | %FileCheck %s
 
 func modify<T>(_ x: inout T) {}
diff --git a/test/SILGen/accessors.swift b/test/SILGen/accessors.swift
index 06982c9..5a85c8d 100644
--- a/test/SILGen/accessors.swift
+++ b/test/SILGen/accessors.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -Xllvm -sil-full-demangle -emit-silgen -enable-sil-ownership %s | %FileCheck %s
 
 // Hold a reference to do to magically become non-POD.
@@ -65,9 +66,8 @@
 // CHECK-NEXT: switch_enum [[OPT_CALLBACK]] : $Optional<Builtin.RawPointer>, case #Optional.some!enumelt.1: [[WRITEBACK:bb[0-9]+]], case #Optional.none!enumelt: [[CONT:bb[0-9]+]]
 
 // CHECK:    [[WRITEBACK]]([[CALLBACK_ADDR:%.*]] : @trivial $Builtin.RawPointer):
-// CHECK-NEXT: [[CALLBACK:%.*]] = pointer_to_thin_function [[CALLBACK_ADDR]] : $Builtin.RawPointer to $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout A, @thick A.Type) -> ()
+// CHECK-NEXT: [[CALLBACK:%.*]] = pointer_to_thin_function [[CALLBACK_ADDR]] : $Builtin.RawPointer to $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @in_guaranteed A, @thick A.Type) -> ()
 // CHECK-NEXT: [[TEMP2:%.*]] = alloc_stack $A
-// SEMANTIC SIL TODO: This is an issue caused by the callback for materializeForSet in the class case taking the value as @inout when it should really take it as @guaranteed.
 // CHECK-NEXT: store_borrow [[BORROWED_ARG_LHS]] to [[TEMP2]] : $*A
 // CHECK-NEXT: [[T0:%.*]] = metatype $@thick A.Type
 // CHECK-NEXT: [[T1:%.*]] = address_to_pointer [[ADDR]] : $*OrdinarySub to $Builtin.RawPointer
@@ -128,7 +128,7 @@
 // CHECK-NEXT: switch_enum [[OPT_CALLBACK]] : $Optional<Builtin.RawPointer>, case #Optional.some!enumelt.1: [[WRITEBACK:bb[0-9]+]], case #Optional.none!enumelt: [[CONT:bb[0-9]+]]
 //
 // CHECK:    [[WRITEBACK]]([[CALLBACK_ADDR:%.*]] : @trivial $Builtin.RawPointer):
-// CHECK-NEXT: [[CALLBACK:%.*]] = pointer_to_thin_function [[CALLBACK_ADDR]] : $Builtin.RawPointer to $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout B, @thick B.Type) -> ()
+// CHECK-NEXT: [[CALLBACK:%.*]] = pointer_to_thin_function [[CALLBACK_ADDR]] : $Builtin.RawPointer to $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @in_guaranteed B, @thick B.Type) -> ()
 // CHECK-NEXT: [[TEMP2:%.*]] = alloc_stack $B
 // CHECK-NEXT: store_borrow [[BORROWED_ARG_RHS]] to [[TEMP2]] : $*B
 // CHECK-NEXT: [[T0:%.*]] = metatype $@thick B.Type
@@ -154,7 +154,7 @@
 // CHECK-NEXT: switch_enum [[OPT_CALLBACK]] : $Optional<Builtin.RawPointer>, case #Optional.some!enumelt.1: [[WRITEBACK:bb[0-9]+]], case #Optional.none!enumelt: [[CONT:bb[0-9]+]]
 //
 // CHECK:    [[WRITEBACK]]([[CALLBACK_ADDR:%.*]] : @trivial $Builtin.RawPointer):
-// CHECK-NEXT: [[CALLBACK:%.*]] = pointer_to_thin_function [[CALLBACK_ADDR]] : $Builtin.RawPointer to $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout B, @thick B.Type) -> ()
+// CHECK-NEXT: [[CALLBACK:%.*]] = pointer_to_thin_function [[CALLBACK_ADDR]] : $Builtin.RawPointer to $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @in_guaranteed B, @thick B.Type) -> ()
 // CHECK-NEXT: [[TEMP2:%.*]] = alloc_stack $B
 // CHECK-NEXT: store_borrow [[BORROWED_ARG_LHS]] to [[TEMP2]] : $*B
 // CHECK-NEXT: [[T0:%.*]] = metatype $@thick B.Type
diff --git a/test/SILGen/address_only_types.swift b/test/SILGen/address_only_types.swift
index 3d771a8..bc02604 100644
--- a/test/SILGen/address_only_types.swift
+++ b/test/SILGen/address_only_types.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -enable-sil-ownership -parse-as-library -parse-stdlib -emit-silgen %s | %FileCheck %s
 
 precedencegroup AssignmentPrecedence { assignment: true }
diff --git a/test/SILGen/addressors.swift b/test/SILGen/addressors.swift
index 76fe58a..a1186cd 100644
--- a/test/SILGen/addressors.swift
+++ b/test/SILGen/addressors.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -enable-sil-ownership -parse-stdlib -emit-sil %s | %FileCheck %s
 // RUN: %target-swift-frontend -enable-sil-ownership -parse-stdlib -emit-silgen %s | %FileCheck %s -check-prefix=SILGEN
 // RUN: %target-swift-frontend -enable-sil-ownership -parse-stdlib -emit-ir %s
@@ -354,7 +355,7 @@
 // CHECK:   strong_release [[OWNER]] : $Builtin.NativeObject
 
 //   materializeForSet callback for G.value
-// CHECK-LABEL: sil private [transparent] @$S10addressors1GC5values5Int32VvmytfU_ : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout G, @thick G.Type) -> () {
+// CHECK-LABEL: sil private [transparent] @$S10addressors1GC5values5Int32VvmytfU_ : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @in_guaranteed G, @thick G.Type) -> () {
 // CHECK: bb0([[BUFFER:%0]] : $Builtin.RawPointer, [[STORAGE:%1]] : $*Builtin.UnsafeValueBuffer, [[SELF:%2]] : $*G, [[SELFTYPE:%3]] : $@thick G.Type):
 // CHECK:   [[T0:%.*]] = project_value_buffer $Builtin.NativeObject in [[STORAGE]] : $*Builtin.UnsafeValueBuffer
 // CHECK:   [[OWNER:%.*]] = load [[T0]]
@@ -475,7 +476,7 @@
 // CHECK:   strong_unpin [[OWNER]] : $Optional<Builtin.NativeObject>
 
 //   materializeForSet callback for I.value
-// CHECK-LABEL: sil private [transparent] @$S10addressors1IC5values5Int32VvmytfU_ : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout I, @thick I.Type) -> () {
+// CHECK-LABEL: sil private [transparent] @$S10addressors1IC5values5Int32VvmytfU_ : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @in_guaranteed I, @thick I.Type) -> () {
 // CHECK: bb0([[BUFFER:%0]] : $Builtin.RawPointer, [[STORAGE:%1]] : $*Builtin.UnsafeValueBuffer, [[SELF:%2]] : $*I, [[SELFTYPE:%3]] : $@thick I.Type):
 // CHECK:   [[T0:%.*]] = project_value_buffer $Optional<Builtin.NativeObject> in [[STORAGE]] : $*Builtin.UnsafeValueBuffer
 // CHECK:   [[OWNER:%.*]] = load [[T0]]
diff --git a/test/SILGen/apply_abstraction_nested.swift b/test/SILGen/apply_abstraction_nested.swift
index df737ad..6ea71bd 100644
--- a/test/SILGen/apply_abstraction_nested.swift
+++ b/test/SILGen/apply_abstraction_nested.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -enable-sil-ownership -emit-silgen %s | %FileCheck %s
 
 infix operator ~> { precedence 255 associativity left }
diff --git a/test/SILGen/argument_labels.swift b/test/SILGen/argument_labels.swift
index 629cb93..4702392 100644
--- a/test/SILGen/argument_labels.swift
+++ b/test/SILGen/argument_labels.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership %s | %FileCheck %s
 
 public struct X { }
diff --git a/test/SILGen/argument_shuffle_swift3.swift b/test/SILGen/argument_shuffle_swift3.swift
index 9a671c8..d28323c 100644
--- a/test/SILGen/argument_shuffle_swift3.swift
+++ b/test/SILGen/argument_shuffle_swift3.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership %s -swift-version 3 | %FileCheck %s
 
 func fn(_: Any) {}
diff --git a/test/SILGen/array_literal_abstraction.swift b/test/SILGen/array_literal_abstraction.swift
index 5a72c8f..074cf18 100644
--- a/test/SILGen/array_literal_abstraction.swift
+++ b/test/SILGen/array_literal_abstraction.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -emit-silgen %s | %FileCheck %s
 
 // Verify that reabstraction happens when forming container literals.
diff --git a/test/SILGen/auto_closures.swift b/test/SILGen/auto_closures.swift
index ae73d29..f87040c 100644
--- a/test/SILGen/auto_closures.swift
+++ b/test/SILGen/auto_closures.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -parse-stdlib -emit-silgen %s | %FileCheck %s
 
 struct Bool {}
diff --git a/test/SILGen/borrow.swift b/test/SILGen/borrow.swift
index 12789f0..35c3c73 100644
--- a/test/SILGen/borrow.swift
+++ b/test/SILGen/borrow.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -enable-sil-ownership -parse-stdlib -emit-silgen %s | %FileCheck %s
 
 import Swift
diff --git a/test/SILGen/boxed_existentials.swift b/test/SILGen/boxed_existentials.swift
index ae640f1..92210e8 100644
--- a/test/SILGen/boxed_existentials.swift
+++ b/test/SILGen/boxed_existentials.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -Xllvm -sil-full-demangle -enable-sil-ownership -emit-silgen %s | %FileCheck %s
 // RUN: %target-swift-frontend -Xllvm -sil-full-demangle -enable-sil-ownership -emit-silgen %s | %FileCheck %s --check-prefix=GUARANTEED
 
diff --git a/test/SILGen/call_chain_reabstraction.swift b/test/SILGen/call_chain_reabstraction.swift
index 22b8a82..bca5a66 100644
--- a/test/SILGen/call_chain_reabstraction.swift
+++ b/test/SILGen/call_chain_reabstraction.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership %s | %FileCheck %s
 
 struct A {
diff --git a/test/SILGen/capture_typed_boxes.swift b/test/SILGen/capture_typed_boxes.swift
index b19759f..50a806e 100644
--- a/test/SILGen/capture_typed_boxes.swift
+++ b/test/SILGen/capture_typed_boxes.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership %s | %FileCheck %s
 
 func foo(_ x: Int) -> () -> Int {
diff --git a/test/SILGen/casts.swift b/test/SILGen/casts.swift
index 8a429ea..74e7718 100644
--- a/test/SILGen/casts.swift
+++ b/test/SILGen/casts.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership %s | %FileCheck %s
 
 class B { }
diff --git a/test/SILGen/cf.swift b/test/SILGen/cf.swift
index aa4cb6a..ebc2c23 100644
--- a/test/SILGen/cf.swift
+++ b/test/SILGen/cf.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -import-cf-types -sdk %S/Inputs %s -emit-silgen -o - | %FileCheck %s
 
 // REQUIRES: objc_interop
diff --git a/test/SILGen/class_bound_protocols.swift b/test/SILGen/class_bound_protocols.swift
index bf9df67..b190ced 100644
--- a/test/SILGen/class_bound_protocols.swift
+++ b/test/SILGen/class_bound_protocols.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -parse-stdlib -parse-as-library -module-name Swift -emit-silgen %s | %FileCheck %s
 
 enum Optional<T> {
diff --git a/test/SILGen/class_resilience.swift b/test/SILGen/class_resilience.swift
index 8b91e2e..e821bc5 100644
--- a/test/SILGen/class_resilience.swift
+++ b/test/SILGen/class_resilience.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %empty-directory(%t)
 // RUN: %target-swift-frontend -emit-module -enable-resilience -emit-module-path=%t/resilient_struct.swiftmodule -module-name=resilient_struct %S/../Inputs/resilient_struct.swift
 // RUN: %target-swift-frontend -emit-module -enable-resilience -emit-module-path=%t/resilient_class.swiftmodule -module-name=resilient_class -I %t %S/../Inputs/resilient_class.swift
diff --git a/test/SILGen/closures.swift b/test/SILGen/closures.swift
index c90d81d..ca0d033 100644
--- a/test/SILGen/closures.swift
+++ b/test/SILGen/closures.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -enable-sil-ownership -parse-stdlib -parse-as-library -emit-silgen %s | %FileCheck %s
 // RUN: %target-swift-frontend -enable-sil-ownership -parse-stdlib -parse-as-library -emit-silgen  %s | %FileCheck %s --check-prefix=GUARANTEED
 
diff --git a/test/SILGen/collection_downcast.swift b/test/SILGen/collection_downcast.swift
index a6633f0..b3768d4 100644
--- a/test/SILGen/collection_downcast.swift
+++ b/test/SILGen/collection_downcast.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -emit-silgen -sdk %S/Inputs -I %S/Inputs -enable-source-import %s | %FileCheck %s
 
 // REQUIRES: objc_interop
diff --git a/test/SILGen/collection_subtype_downcast.swift b/test/SILGen/collection_subtype_downcast.swift
index ce47645..821115f 100644
--- a/test/SILGen/collection_subtype_downcast.swift
+++ b/test/SILGen/collection_subtype_downcast.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership -sdk %S/Inputs %s | %FileCheck %s
 
 struct S { var x, y: Int }
diff --git a/test/SILGen/collection_subtype_upcast.swift b/test/SILGen/collection_subtype_upcast.swift
index 6081663..d6d4ad9 100644
--- a/test/SILGen/collection_subtype_upcast.swift
+++ b/test/SILGen/collection_subtype_upcast.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership -sdk %S/Inputs %s | %FileCheck %s
 
 struct S { var x, y: Int }
diff --git a/test/SILGen/collection_upcast.swift b/test/SILGen/collection_upcast.swift
index ac73520..faecb5b 100644
--- a/test/SILGen/collection_upcast.swift
+++ b/test/SILGen/collection_upcast.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -emit-silgen -sdk %S/Inputs -I %S/Inputs -enable-source-import %s | %FileCheck %s
 
 // FIXME: rdar://problem/19648117 Needs splitting objc parts out
diff --git a/test/SILGen/constrained_extensions.swift b/test/SILGen/constrained_extensions.swift
index 2d1fd81..f6e8418 100644
--- a/test/SILGen/constrained_extensions.swift
+++ b/test/SILGen/constrained_extensions.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership -primary-file %s | %FileCheck %s
 // RUN: %target-swift-frontend -emit-sil -O -primary-file %s > /dev/null
 // RUN: %target-swift-frontend -emit-ir -primary-file %s > /dev/null
@@ -137,7 +138,7 @@
 extension GenericClass where Y == () {
   // CHECK-LABEL: sil @$S22constrained_extensions12GenericClassCAAytRs_rlE5valuexvg : $@convention(method) <X, Y where Y == ()> (@guaranteed GenericClass<X, ()>) -> @out X
   // CHECK-LABEL: sil @$S22constrained_extensions12GenericClassCAAytRs_rlE5valuexvs : $@convention(method) <X, Y where Y == ()> (@in X, @guaranteed GenericClass<X, ()>) -> ()
-  // CHECK-LABEL: sil shared [transparent] [serialized] @$S22constrained_extensions12GenericClassCAAytRs_rlE5valuexvmytfU_ : $@convention(method) <X, Y where Y == ()> (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout GenericClass<X, ()>, @thick GenericClass<X, ()>.Type) -> ()
+  // CHECK-LABEL: sil shared [transparent] [serialized] @$S22constrained_extensions12GenericClassCAAytRs_rlE5valuexvmytfU_ : $@convention(method) <X, Y where Y == ()> (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @in_guaranteed GenericClass<X, ()>, @thick GenericClass<X, ()>.Type) -> ()
   // CHECK-LABEL: sil [transparent] [serialized] @$S22constrained_extensions12GenericClassCAAytRs_rlE5valuexvm : $@convention(method) <X, Y where Y == ()> (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @guaranteed GenericClass<X, ()>) -> (Builtin.RawPointer, Optional<Builtin.RawPointer>)
   public var value: X {
     get { while true {} }
@@ -146,7 +147,7 @@
 
   // CHECK-LABEL: sil @$S22constrained_extensions12GenericClassCAAytRs_rlE5emptyytvg : $@convention(method) <X, Y where Y == ()> (@guaranteed GenericClass<X, ()>) -> ()
   // CHECK-LABEL: sil @$S22constrained_extensions12GenericClassCAAytRs_rlE5emptyytvs : $@convention(method) <X, Y where Y == ()> (@guaranteed GenericClass<X, ()>) -> ()
-  // CHECK-LABEL: sil shared [transparent] [serialized] @$S22constrained_extensions12GenericClassCAAytRs_rlE5emptyytvmytfU_ : $@convention(method) <X, Y where Y == ()> (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout GenericClass<X, ()>, @thick GenericClass<X, ()>.Type) -> ()
+  // CHECK-LABEL: sil shared [transparent] [serialized] @$S22constrained_extensions12GenericClassCAAytRs_rlE5emptyytvmytfU_ : $@convention(method) <X, Y where Y == ()> (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @in_guaranteed GenericClass<X, ()>, @thick GenericClass<X, ()>.Type) -> ()
   // CHECK-LABEL: sil [transparent] [serialized] @$S22constrained_extensions12GenericClassCAAytRs_rlE5emptyytvm : $@convention(method) <X, Y where Y == ()> (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @guaranteed GenericClass<X, ()>) -> (Builtin.RawPointer, Optional<Builtin.RawPointer>)
   public var empty: Y {
     get { return () }
@@ -155,7 +156,7 @@
 
   // CHECK-LABEL: sil @$S22constrained_extensions12GenericClassCAAytRs_rlEyxyt_tcig : $@convention(method) <X, Y where Y == ()> (@guaranteed GenericClass<X, ()>) -> @out X
   // CHECK-LABEL: sil @$S22constrained_extensions12GenericClassCAAytRs_rlEyxyt_tcis : $@convention(method) <X, Y where Y == ()> (@in X, @guaranteed GenericClass<X, ()>) -> ()
-  // CHECK-LABEL: sil shared [transparent] [serialized] @$S22constrained_extensions12GenericClassCAAytRs_rlEyxyt_tcimytfU_ : $@convention(method) <X, Y where Y == ()> (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout GenericClass<X, ()>, @thick GenericClass<X, ()>.Type) -> ()
+  // CHECK-LABEL: sil shared [transparent] [serialized] @$S22constrained_extensions12GenericClassCAAytRs_rlEyxyt_tcimytfU_ : $@convention(method) <X, Y where Y == ()> (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @in_guaranteed GenericClass<X, ()>, @thick GenericClass<X, ()>.Type) -> ()
   // CHECK-LABEL: sil [transparent] [serialized] @$S22constrained_extensions12GenericClassCAAytRs_rlEyxyt_tcim : $@convention(method) <X, Y where Y == ()> (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @guaranteed GenericClass<X, ()>) -> (Builtin.RawPointer, Optional<Builtin.RawPointer>)
   public subscript(_: Y) -> X {
     get { while true {} }
@@ -164,7 +165,7 @@
 
   // CHECK-LABEL: sil @$S22constrained_extensions12GenericClassCAAytRs_rlEyyxcig : $@convention(method) <X, Y where Y == ()> (@in X, @guaranteed GenericClass<X, ()>) -> ()
   // CHECK-LABEL: sil @$S22constrained_extensions12GenericClassCAAytRs_rlEyyxcis : $@convention(method) <X, Y where Y == ()> (@in X, @guaranteed GenericClass<X, ()>) -> ()
-  // CHECK-LABEL: sil shared [transparent] [serialized] @$S22constrained_extensions12GenericClassCAAytRs_rlEyyxcimytfU_ : $@convention(method) <X, Y where Y == ()> (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout GenericClass<X, ()>, @thick GenericClass<X, ()>.Type) -> ()
+  // CHECK-LABEL: sil shared [transparent] [serialized] @$S22constrained_extensions12GenericClassCAAytRs_rlEyyxcimytfU_ : $@convention(method) <X, Y where Y == ()> (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @in_guaranteed GenericClass<X, ()>, @thick GenericClass<X, ()>.Type) -> ()
   // CHECK-LABEL: sil [transparent] [serialized] @$S22constrained_extensions12GenericClassCAAytRs_rlEyyxcim : $@convention(method) <X, Y where Y == ()> (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @in X, @guaranteed GenericClass<X, ()>) -> (Builtin.RawPointer, Optional<Builtin.RawPointer>)
   public subscript(_: X) -> Y {
     get { while true {} }
diff --git a/test/SILGen/default_arguments.swift b/test/SILGen/default_arguments.swift
index 0059519..ad11d44 100644
--- a/test/SILGen/default_arguments.swift
+++ b/test/SILGen/default_arguments.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -Xllvm -sil-full-demangle -enable-sil-ownership -emit-silgen -swift-version 3 %s | %FileCheck %s
 // RUN: %target-swift-frontend -Xllvm -sil-full-demangle -enable-sil-ownership -emit-silgen -swift-version 3 %s | %FileCheck %s --check-prefix=NEGATIVE
 
diff --git a/test/SILGen/default_arguments_generic.swift b/test/SILGen/default_arguments_generic.swift
index 61297aa..4755f22 100644
--- a/test/SILGen/default_arguments_generic.swift
+++ b/test/SILGen/default_arguments_generic.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership -swift-version 3 %s | %FileCheck %s
 // RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership -swift-version 4 %s | %FileCheck %s
 
diff --git a/test/SILGen/default_arguments_serialized.swift b/test/SILGen/default_arguments_serialized.swift
index 0172a9c..2308dcd 100644
--- a/test/SILGen/default_arguments_serialized.swift
+++ b/test/SILGen/default_arguments_serialized.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %empty-directory(%t)
 // RUN: %target-swift-frontend -emit-module-path %t/default_arguments_other.swiftmodule -emit-module -swift-version 4 -primary-file %S/Inputs/default_arguments_other.swift
 
diff --git a/test/SILGen/dependent_member_lowering.swift b/test/SILGen/dependent_member_lowering.swift
index 218c589..86aad55 100644
--- a/test/SILGen/dependent_member_lowering.swift
+++ b/test/SILGen/dependent_member_lowering.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership %s | %FileCheck %s
 
 protocol P {
diff --git a/test/SILGen/downcast_reabstraction.swift b/test/SILGen/downcast_reabstraction.swift
index 191a90e..3a07b17 100644
--- a/test/SILGen/downcast_reabstraction.swift
+++ b/test/SILGen/downcast_reabstraction.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership %s | %FileCheck %s
 
 // CHECK-LABEL: sil hidden @$S22downcast_reabstraction19condFunctionFromAnyyyypF
diff --git a/test/SILGen/dynamic.swift b/test/SILGen/dynamic.swift
index 7d85d4e..49806ca 100644
--- a/test/SILGen/dynamic.swift
+++ b/test/SILGen/dynamic.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %empty-directory(%t)
 // RUN: %build-silgen-test-overlays
 
diff --git a/test/SILGen/dynamic_lookup.swift b/test/SILGen/dynamic_lookup.swift
index a0d85b3..b55f1f0 100644
--- a/test/SILGen/dynamic_lookup.swift
+++ b/test/SILGen/dynamic_lookup.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -parse-as-library -emit-silgen -disable-objc-attr-requires-foundation-module %s | %FileCheck %s
 // RUN: %target-swift-frontend -parse-as-library -emit-silgen -disable-objc-attr-requires-foundation-module  %s | %FileCheck %s --check-prefix=GUARANTEED
 
diff --git a/test/SILGen/dynamic_lookup_throws.swift b/test/SILGen/dynamic_lookup_throws.swift
index 67ac9b4..178909d 100644
--- a/test/SILGen/dynamic_lookup_throws.swift
+++ b/test/SILGen/dynamic_lookup_throws.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %empty-directory(%t)
 // RUN: %build-clang-importer-objc-overlays
 
diff --git a/test/SILGen/dynamic_self.swift b/test/SILGen/dynamic_self.swift
index a08e377..fc284ae 100644
--- a/test/SILGen/dynamic_self.swift
+++ b/test/SILGen/dynamic_self.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -emit-silgen %s -disable-objc-attr-requires-foundation-module | %FileCheck %s
 // RUN: %target-swift-frontend -emit-sil -O %s -disable-objc-attr-requires-foundation-module
 // RUN: %target-swift-frontend -emit-ir %s -disable-objc-attr-requires-foundation-module
diff --git a/test/SILGen/enum.swift b/test/SILGen/enum.swift
index af87a52..f16ea12 100644
--- a/test/SILGen/enum.swift
+++ b/test/SILGen/enum.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -parse-stdlib -parse-as-library -emit-silgen -enable-sil-ownership -module-name Swift %s | %FileCheck %s
 
 precedencegroup AssignmentPrecedence { assignment: true }
diff --git a/test/SILGen/enum_resilience.swift b/test/SILGen/enum_resilience.swift
index dbebe9c..d2f2145 100644
--- a/test/SILGen/enum_resilience.swift
+++ b/test/SILGen/enum_resilience.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %empty-directory(%t)
 // RUN: %target-swift-frontend -emit-module -enable-resilience -emit-module-path=%t/resilient_struct.swiftmodule -module-name=resilient_struct %S/../Inputs/resilient_struct.swift
 // RUN: %target-swift-frontend -emit-module -enable-resilience -emit-module-path=%t/resilient_enum.swiftmodule -module-name=resilient_enum -I %t %S/../Inputs/resilient_enum.swift
diff --git a/test/SILGen/erasure_reabstraction.swift b/test/SILGen/erasure_reabstraction.swift
index a63f65b..10c6e39 100644
--- a/test/SILGen/erasure_reabstraction.swift
+++ b/test/SILGen/erasure_reabstraction.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership %s | %FileCheck %s
 
 struct Foo {}
diff --git a/test/SILGen/existential_erasure.swift b/test/SILGen/existential_erasure.swift
index ead4724..15bf015 100644
--- a/test/SILGen/existential_erasure.swift
+++ b/test/SILGen/existential_erasure.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership %s | %FileCheck %s
 
 protocol P {
diff --git a/test/SILGen/expressions.swift b/test/SILGen/expressions.swift
index 5f91200..6de0dea 100644
--- a/test/SILGen/expressions.swift
+++ b/test/SILGen/expressions.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %empty-directory(%t)
 // RUN: echo "public var x = Int()" | %target-swift-frontend -module-name FooBar -emit-module -o %t -
 // RUN: %target-swift-frontend -parse-stdlib -emit-silgen -enable-sil-ownership %s -I%t -disable-access-control | %FileCheck %s
diff --git a/test/SILGen/extensions_objc.swift b/test/SILGen/extensions_objc.swift
index 36fce74..7015fa7 100644
--- a/test/SILGen/extensions_objc.swift
+++ b/test/SILGen/extensions_objc.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -sdk %S/Inputs %s -I %S/Inputs -enable-source-import -emit-silgen -enable-sil-ownership | %FileCheck %s
 //
 // REQUIRES: objc_interop
diff --git a/test/SILGen/external_definitions.swift b/test/SILGen/external_definitions.swift
index 6cff400..e7a1090 100644
--- a/test/SILGen/external_definitions.swift
+++ b/test/SILGen/external_definitions.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -sdk %S/Inputs %s -emit-silgen -enable-sil-ownership | %FileCheck %s
 
 // REQUIRES: objc_interop
diff --git a/test/SILGen/final.swift b/test/SILGen/final.swift
index 1538d5e..dd24729 100644
--- a/test/SILGen/final.swift
+++ b/test/SILGen/final.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership %s | %FileCheck %s
 
 class TestClass {
diff --git a/test/SILGen/force_cast_chained_optional.swift b/test/SILGen/force_cast_chained_optional.swift
index e84b241..2eae970 100644
--- a/test/SILGen/force_cast_chained_optional.swift
+++ b/test/SILGen/force_cast_chained_optional.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership %s | %FileCheck %s
 
 class Foo {
diff --git a/test/SILGen/foreach.swift b/test/SILGen/foreach.swift
index 745cb95..6dd219b 100644
--- a/test/SILGen/foreach.swift
+++ b/test/SILGen/foreach.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership %s | %FileCheck %s
 
 //////////////////
diff --git a/test/SILGen/foreign_errors.swift b/test/SILGen/foreign_errors.swift
index e3c45fe..65bc729 100644
--- a/test/SILGen/foreign_errors.swift
+++ b/test/SILGen/foreign_errors.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %empty-directory(%t)
 // RUN: %build-clang-importer-objc-overlays
 // RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk-nosource -I %t) -emit-silgen -parse-as-library %s | %FileCheck %s
diff --git a/test/SILGen/function_conversion.swift b/test/SILGen/function_conversion.swift
index 0fac5bc..2266959 100644
--- a/test/SILGen/function_conversion.swift
+++ b/test/SILGen/function_conversion.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership -primary-file %s | %FileCheck %s
 // RUN: %target-swift-frontend -emit-ir -enable-sil-ownership -primary-file %s
 
diff --git a/test/SILGen/function_conversion_objc.swift b/test/SILGen/function_conversion_objc.swift
index 0af62ed..fcd20ec 100644
--- a/test/SILGen/function_conversion_objc.swift
+++ b/test/SILGen/function_conversion_objc.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -sdk %S/Inputs %s -I %S/Inputs -enable-sil-ownership -enable-source-import -emit-silgen -verify | %FileCheck %s
 
 import Foundation
diff --git a/test/SILGen/functions.swift b/test/SILGen/functions.swift
index 36e943a..bc02381 100644
--- a/test/SILGen/functions.swift
+++ b/test/SILGen/functions.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -Xllvm -sil-full-demangle -parse-stdlib -parse-as-library -emit-silgen -enable-sil-ownership %s | %FileCheck %s
 
 import Swift // just for Optional
diff --git a/test/SILGen/generic_casts.swift b/test/SILGen/generic_casts.swift
index 6fe1f40..56d6d8d 100644
--- a/test/SILGen/generic_casts.swift
+++ b/test/SILGen/generic_casts.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -Xllvm -sil-full-demangle -emit-silgen -enable-sil-ownership %s | %FileCheck --check-prefix=CHECK --check-prefix=CHECK-%target-runtime %s
 
 protocol ClassBound : class {}
diff --git a/test/SILGen/generic_closures.swift b/test/SILGen/generic_closures.swift
index b3bddf9..7cabd10 100644
--- a/test/SILGen/generic_closures.swift
+++ b/test/SILGen/generic_closures.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -parse-stdlib -emit-silgen -enable-sil-ownership %s | %FileCheck %s
 
 import Swift
diff --git a/test/SILGen/generic_property_base_lifetime.swift b/test/SILGen/generic_property_base_lifetime.swift
index 9ccc903..7338fee 100644
--- a/test/SILGen/generic_property_base_lifetime.swift
+++ b/test/SILGen/generic_property_base_lifetime.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -emit-silgen %s -disable-objc-attr-requires-foundation-module -enable-sil-ownership | %FileCheck %s
 
 protocol ProtocolA: class {
diff --git a/test/SILGen/generic_tuples.swift b/test/SILGen/generic_tuples.swift
index 137bd18..c2330dd 100644
--- a/test/SILGen/generic_tuples.swift
+++ b/test/SILGen/generic_tuples.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -emit-silgen -parse-as-library -enable-sil-ownership %s | %FileCheck %s
 
 
diff --git a/test/SILGen/generic_witness.swift b/test/SILGen/generic_witness.swift
index 3b4a719..98dfffe 100644
--- a/test/SILGen/generic_witness.swift
+++ b/test/SILGen/generic_witness.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership %s | %FileCheck %s
 // RUN: %target-swift-frontend -emit-ir -enable-sil-ownership %s
 
diff --git a/test/SILGen/guaranteed_normal_args.swift b/test/SILGen/guaranteed_normal_args.swift
index a072527..250a763 100644
--- a/test/SILGen/guaranteed_normal_args.swift
+++ b/test/SILGen/guaranteed_normal_args.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -parse-as-library -module-name Swift -parse-stdlib -emit-silgen -enable-sil-ownership -enable-guaranteed-normal-arguments %s | %FileCheck %s
 
 // This test checks specific codegen related to normal arguments being passed at
diff --git a/test/SILGen/guaranteed_self.swift b/test/SILGen/guaranteed_self.swift
index b285f62..02e4524 100644
--- a/test/SILGen/guaranteed_self.swift
+++ b/test/SILGen/guaranteed_self.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -Xllvm -sil-full-demangle -emit-silgen %s -disable-objc-attr-requires-foundation-module -enable-sil-ownership | %FileCheck %s
 
 protocol Fooable {
diff --git a/test/SILGen/if_while_binding.swift b/test/SILGen/if_while_binding.swift
index c921e3e..9564b01 100644
--- a/test/SILGen/if_while_binding.swift
+++ b/test/SILGen/if_while_binding.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -Xllvm -sil-full-demangle -emit-silgen -enable-sil-ownership %s | %FileCheck %s
 
 func foo() -> String? { return "" }
diff --git a/test/SILGen/implicitly_unwrapped_optional.swift b/test/SILGen/implicitly_unwrapped_optional.swift
index 3273c3b..5307d7f 100644
--- a/test/SILGen/implicitly_unwrapped_optional.swift
+++ b/test/SILGen/implicitly_unwrapped_optional.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership %s | %FileCheck %s
 
 func foo(f f: (() -> ())!) {
diff --git a/test/SILGen/indirect_enum.swift b/test/SILGen/indirect_enum.swift
index bae2be1..b384995 100644
--- a/test/SILGen/indirect_enum.swift
+++ b/test/SILGen/indirect_enum.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -Xllvm -sil-print-debuginfo -emit-silgen %s | %FileCheck %s
 
 indirect enum TreeA<T> {
diff --git a/test/SILGen/inlineable_attribute.swift b/test/SILGen/inlineable_attribute.swift
index 564b5b5..747abcc 100644
--- a/test/SILGen/inlineable_attribute.swift
+++ b/test/SILGen/inlineable_attribute.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership -emit-verbose-sil %s | %FileCheck %s
 
 // CHECK-LABEL: sil [serialized] @$S20inlineable_attribute15fragileFunctionyyF : $@convention(thin) () -> ()
diff --git a/test/SILGen/inlineable_attribute_objc.swift b/test/SILGen/inlineable_attribute_objc.swift
index 8e36109..a7ff8d5 100644
--- a/test/SILGen/inlineable_attribute_objc.swift
+++ b/test/SILGen/inlineable_attribute_objc.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %empty-directory(%t)
 // RUN: %build-silgen-test-overlays
 
diff --git a/test/SILGen/keypath_application.swift b/test/SILGen/keypath_application.swift
index 88cd272..66a8fb7 100644
--- a/test/SILGen/keypath_application.swift
+++ b/test/SILGen/keypath_application.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership %s | %FileCheck %s
 
 class A {}
diff --git a/test/SILGen/keypaths.swift b/test/SILGen/keypaths.swift
index d028842..55fc6ab 100644
--- a/test/SILGen/keypaths.swift
+++ b/test/SILGen/keypaths.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership %s | %FileCheck %s
 
 struct S<T> {
diff --git a/test/SILGen/let_decls.swift b/test/SILGen/let_decls.swift
index 43e68654..493c2db 100644
--- a/test/SILGen/let_decls.swift
+++ b/test/SILGen/let_decls.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -Xllvm -sil-full-demangle -emit-silgen -enable-sil-ownership %s | %FileCheck %s
 
 func takeClosure(_ a : () -> Int) {}
diff --git a/test/SILGen/lifetime.swift b/test/SILGen/lifetime.swift
index 751f386..1700a7f 100644
--- a/test/SILGen/lifetime.swift
+++ b/test/SILGen/lifetime.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -Xllvm -sil-full-demangle -parse-as-library -emit-silgen -primary-file %s | %FileCheck %s
 
 struct Buh<T> {
@@ -389,7 +390,7 @@
   // CHECK: [[ADDR:%.*]] = pointer_to_address [[PTR]]
   // CHECK: [[MARKED_ADDR:%.*]] = mark_dependence [[ADDR]] : $*Aleph on [[R2]]
   // CHECK: {{.*}}([[CALLBACK_ADDR:%.*]] : 
-  // CHECK: [[CALLBACK:%.*]] = pointer_to_thin_function [[CALLBACK_ADDR]] : $Builtin.RawPointer to $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout RefWithProp, @thick RefWithProp.Type) -> ()
+  // CHECK: [[CALLBACK:%.*]] = pointer_to_thin_function [[CALLBACK_ADDR]] : $Builtin.RawPointer to $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @in_guaranteed RefWithProp, @thick RefWithProp.Type) -> ()
   // CHECK: [[TEMP:%.*]] = alloc_stack $RefWithProp
   // CHECK: store [[R2]] to [init] [[TEMP]]
   // CHECK: apply [[CALLBACK]]({{.*}}, [[STORAGE]], [[TEMP]], {{%.*}})
diff --git a/test/SILGen/mangling.swift b/test/SILGen/mangling.swift
index 0cb1dd2..6fffed4 100644
--- a/test/SILGen/mangling.swift
+++ b/test/SILGen/mangling.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -Xllvm -sil-full-demangle -sdk %S/Inputs -I %S/Inputs -enable-source-import %s -emit-silgen -enable-sil-ownership | %FileCheck %s
 
 // REQUIRES: objc_interop
diff --git a/test/SILGen/materializeForSet.swift b/test/SILGen/materializeForSet.swift
index 97adf6f..be4c1a4 100644
--- a/test/SILGen/materializeForSet.swift
+++ b/test/SILGen/materializeForSet.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -emit-silgen %s | %FileCheck %s
 // RUN: %target-swift-frontend -emit-silgen -enforce-exclusivity=unchecked %s | %FileCheck --check-prefix=UNCHECKED %s
 
@@ -22,7 +23,7 @@
 // UNCHECKED:   return [[T3]] : $(Builtin.RawPointer, Optional<Builtin.RawPointer>)
 // UNCHECKED: }
 
-// CHECK-LABEL: sil private [transparent] @$S17materializeForSet4BaseC8computedSivmytfU_ : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout Base, @thick Base.Type) -> () {
+// CHECK-LABEL: sil private [transparent] @$S17materializeForSet4BaseC8computedSivmytfU_ : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @in_guaranteed Base, @thick Base.Type) -> () {
 // CHECK: bb0([[BUFFER:%.*]] : $Builtin.RawPointer, [[STORAGE:%.*]] : $*Builtin.UnsafeValueBuffer, [[SELF:%.*]] : $*Base, [[SELFTYPE:%.*]] : $@thick Base.Type):
 // CHECK:   [[T0:%.*]] = load_borrow [[SELF]]
 // CHECK:   [[T1:%.*]] = pointer_to_address [[BUFFER]] : $Builtin.RawPointer to [strict] $*Int
@@ -37,7 +38,7 @@
 // CHECK:   [[T1:%.*]] = apply [[T0]]([[SELF]])
 // CHECK:   store [[T1]] to [trivial] [[ADDR]] : $*Int
 // CHECK:   [[BUFFER:%.*]] = address_to_pointer [[ADDR]]
-// CHECK:   [[T0:%.*]] = function_ref @$S17materializeForSet4BaseC8computedSivmytfU_ : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout Base, @thick Base.Type) -> ()
+// CHECK:   [[T0:%.*]] = function_ref @$S17materializeForSet4BaseC8computedSivmytfU_ : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @in_guaranteed Base, @thick Base.Type) -> ()
 // CHECK:   [[T2:%.*]] = thin_function_to_pointer [[T0]]
 // CHECK:   [[T3:%.*]] = enum $Optional<Builtin.RawPointer>, #Optional.some!enumelt.1, [[T2]] : $Builtin.RawPointer
 // CHECK:   [[T4:%.*]] = tuple ([[BUFFER]] : $Builtin.RawPointer, [[T3]] : $Optional<Builtin.RawPointer>)
@@ -76,7 +77,7 @@
 
 extension Derived : Abstractable {}
 
-// CHECK-LABEL: sil private [transparent] @$S17materializeForSet7DerivedCAA12AbstractableA2aDP14storedFunction6ResultQzycvmytfU_TW : $@convention(witness_method: Abstractable) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout Derived, @thick Derived.Type) -> ()
+// CHECK-LABEL: sil private [transparent] @$S17materializeForSet7DerivedCAA12AbstractableA2aDP14storedFunction6ResultQzycvmytfU_TW : $@convention(witness_method: Abstractable) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @in_guaranteed Derived, @thick Derived.Type) -> ()
 // CHECK: bb0(%0 : $Builtin.RawPointer, %1 : $*Builtin.UnsafeValueBuffer, %2 : $*Derived, %3 : $@thick Derived.Type):
 // CHECK-NEXT: [[T0:%.*]] = load_borrow %2 : $*Derived
 // CHECK-NEXT: [[SELF:%.*]] = upcast [[T0]] : $Derived to $Base
@@ -217,8 +218,8 @@
 // CHECK-NEXT: destroy_addr [[OUT]] : $*@callee_guaranteed () -> Int
 // CHECK-NEXT: store [[NEWVALUE]] to [init] [[RESULT_ADDR]] : $*@callee_guaranteed () -> @out Int
 // CHECK-NEXT: [[ADDR:%.*]] = address_to_pointer [[RESULT_ADDR]] : $*@callee_guaranteed () -> @out Int to $Builtin.RawPointer
-// CHECK:      [[CALLBACK_FN:%.*]] = function_ref @$S17materializeForSet7DerivedCAA12AbstractableA2aDP14staticFunction6ResultQzycvmZytfU_TW : $@convention(witness_method: Abstractable) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout @thick Derived.Type, @thick Derived.Type.Type) -> ()
-// CHECK-NEXT: [[CALLBACK_ADDR:%.*]] = thin_function_to_pointer [[CALLBACK_FN]] : $@convention(witness_method: Abstractable) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout @thick Derived.Type, @thick Derived.Type.Type) -> () to $Builtin.RawPointer
+// CHECK:      [[CALLBACK_FN:%.*]] = function_ref @$S17materializeForSet7DerivedCAA12AbstractableA2aDP14staticFunction6ResultQzycvmZytfU_TW : $@convention(witness_method: Abstractable) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @in_guaranteed @thick Derived.Type, @thick Derived.Type.Type) -> ()
+// CHECK-NEXT: [[CALLBACK_ADDR:%.*]] = thin_function_to_pointer [[CALLBACK_FN]] : $@convention(witness_method: Abstractable) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @in_guaranteed @thick Derived.Type, @thick Derived.Type.Type) -> () to $Builtin.RawPointer
 // CHECK-NEXT: [[CALLBACK:%.*]] = enum $Optional<Builtin.RawPointer>, #Optional.some!enumelt.1, [[CALLBACK_ADDR]] : $Builtin.RawPointer
 // CHECK-NEXT: [[RESULT:%.*]] = tuple ([[ADDR]] : $Builtin.RawPointer, [[CALLBACK]] : $Optional<Builtin.RawPointer>)
 // CHECK-NEXT: dealloc_stack [[OUT]] : $*@callee_guaranteed () -> Int
@@ -263,7 +264,7 @@
 // CHECK:   [[T1:%.*]] = apply [[T0]]([[SELF]])
 // CHECK:   store [[T1]] to [trivial] [[T2]] : $*Int
 // CHECK:   [[BUFFER:%.*]] = address_to_pointer [[T2]]
-// CHECK:   [[CALLBACK_FN:%.*]] = function_ref @$S17materializeForSet06HasDidC0C6storedSivmytfU_ : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout HasDidSet, @thick HasDidSet.Type) -> ()
+// CHECK:   [[CALLBACK_FN:%.*]] = function_ref @$S17materializeForSet06HasDidC0C6storedSivmytfU_ : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @in_guaranteed HasDidSet, @thick HasDidSet.Type) -> ()
 // CHECK:   [[CALLBACK_ADDR:%.*]] = thin_function_to_pointer [[CALLBACK_FN]]
 // CHECK:   [[CALLBACK:%.*]] = enum $Optional<Builtin.RawPointer>, #Optional.some!enumelt.1, [[CALLBACK_ADDR]]
 // CHECK:   [[T4:%.*]] = tuple ([[BUFFER]] : $Builtin.RawPointer, [[CALLBACK]] : $Optional<Builtin.RawPointer>)
@@ -282,7 +283,7 @@
 // CHECK:   [[T1:%.*]] = apply [[T0]]([[SELF]])
 // CHECK:   store [[T1]] to [trivial] [[T2]] : $*Int
 // CHECK:   [[BUFFER:%.*]] = address_to_pointer [[T2]]
-// CHECK:   [[CALLBACK_FN:%.*]] = function_ref @$S17materializeForSet06HasDidC0C8computedSivmytfU_ : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout HasDidSet, @thick HasDidSet.Type) -> ()
+// CHECK:   [[CALLBACK_FN:%.*]] = function_ref @$S17materializeForSet06HasDidC0C8computedSivmytfU_ : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @in_guaranteed HasDidSet, @thick HasDidSet.Type) -> ()
 // CHECK:   [[CALLBACK_ADDR:%.*]] = thin_function_to_pointer [[CALLBACK_FN]]
 // CHECK:   [[CALLBACK:%.*]] = enum $Optional<Builtin.RawPointer>, #Optional.some!enumelt.1, [[CALLBACK_ADDR]]
 // CHECK:   [[T4:%.*]] = tuple ([[BUFFER]] : $Builtin.RawPointer, [[CALLBACK]] : $Optional<Builtin.RawPointer>)
@@ -295,7 +296,7 @@
     didSet {}
   }
 
-// CHECK-LABEL: sil private [transparent] @$S17materializeForSet012HasStoredDidC0C6storedSivmytfU_ : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout HasStoredDidSet, @thick HasStoredDidSet.Type) -> () {
+// CHECK-LABEL: sil private [transparent] @$S17materializeForSet012HasStoredDidC0C6storedSivmytfU_ : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @in_guaranteed HasStoredDidSet, @thick HasStoredDidSet.Type) -> () {
 // CHECK: bb0([[BUFFER:%.*]] : $Builtin.RawPointer, [[STORAGE:%.*]] : $*Builtin.UnsafeValueBuffer, [[SELF:%.*]] : $*HasStoredDidSet, [[METATYPE:%.*]] : $@thick HasStoredDidSet.Type):
 // CHECK:   [[SELF_VALUE:%.*]] = load_borrow [[SELF]] : $*HasStoredDidSet
 // CHECK:   [[BUFFER_ADDR:%.*]] = pointer_to_address [[BUFFER]] : $Builtin.RawPointer to [strict] $*Int
@@ -312,7 +313,7 @@
 // CHECK:   [[T1:%.*]] = apply [[T0]]([[SELF]])
 // CHECK:   store [[T1]] to [trivial] [[T2]] : $*Int
 // CHECK:   [[BUFFER:%.*]] = address_to_pointer [[T2]]
-// CHECK:   [[CALLBACK_FN:%.*]] = function_ref @$S17materializeForSet012HasStoredDidC0C6storedSivmytfU_ : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout HasStoredDidSet, @thick HasStoredDidSet.Type) -> ()
+// CHECK:   [[CALLBACK_FN:%.*]] = function_ref @$S17materializeForSet012HasStoredDidC0C6storedSivmytfU_ : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @in_guaranteed HasStoredDidSet, @thick HasStoredDidSet.Type) -> ()
 // CHECK:   [[CALLBACK_ADDR:%.*]] = thin_function_to_pointer [[CALLBACK_FN]]
 // CHECK:   [[CALLBACK:%.*]] = enum $Optional<Builtin.RawPointer>, #Optional.some!enumelt.1, [[CALLBACK_ADDR]]
 // CHECK:   [[T4:%.*]] = tuple ([[BUFFER]] : $Builtin.RawPointer, [[CALLBACK]] : $Optional<Builtin.RawPointer>)
@@ -332,7 +333,7 @@
 // CHECK:   end_access [[READ]] : $*@sil_weak Optional<HasWeak>
 // CHECK:   store [[T1]] to [init] [[T2]] : $*Optional<HasWeak>
 // CHECK:   [[BUFFER:%.*]] = address_to_pointer [[T2]]
-// CHECK:   [[T0:%.*]] = function_ref @$S17materializeForSet7HasWeakC7weakvarACSgXwvmytfU_ : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout HasWeak, @thick HasWeak.Type) -> () 
+// CHECK:   [[T0:%.*]] = function_ref @$S17materializeForSet7HasWeakC7weakvarACSgXwvmytfU_ : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @in_guaranteed HasWeak, @thick HasWeak.Type) -> () 
 // CHECK:   [[T4:%.*]] = tuple ([[BUFFER]] : $Builtin.RawPointer, {{.*}} : $Optional<Builtin.RawPointer>)
 // CHECK:   return [[T4]] : $(Builtin.RawPointer, Optional<Builtin.RawPointer>)
 // CHECK: }
@@ -344,7 +345,7 @@
 // UNCHECKED:   [[T1:%.*]] = load_weak [[T0]] : $*@sil_weak Optional<HasWeak>
 // UNCHECKED:   store [[T1]] to [init] [[T2]] : $*Optional<HasWeak>
 // UNCHECKED:   [[BUFFER:%.*]] = address_to_pointer [[T2]]
-// UNCHECKED:   [[T0:%.*]] = function_ref @$S17materializeForSet7HasWeakC7weakvarACSgXwvmytfU_ : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout HasWeak, @thick HasWeak.Type) -> () 
+// UNCHECKED:   [[T0:%.*]] = function_ref @$S17materializeForSet7HasWeakC7weakvarACSgXwvmytfU_ : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @in_guaranteed HasWeak, @thick HasWeak.Type) -> () 
 // UNCHECKED:   [[T4:%.*]] = tuple ([[BUFFER]] : $Builtin.RawPointer, {{.*}} : $Optional<Builtin.RawPointer>)
 // UNCHECKED:   return [[T4]] : $(Builtin.RawPointer, Optional<Builtin.RawPointer>)
 // UNCHECKED: }
@@ -660,6 +661,25 @@
   f.computed = f.computed
 }
 
+// Odd corner case -- mutating getter, non-mutating setter
+protocol BackwardMutationProtocol {
+  var value: Int {
+    mutating get
+    nonmutating set
+  }
+}
+
+struct BackwardMutation : BackwardMutationProtocol {
+  var value: Int {
+    mutating get { return 0 }
+    nonmutating set { }
+  }
+}
+
+func doBackwardMutation(m: inout BackwardMutationProtocol) {
+  m.value += 1
+}
+
 // CHECK-LABEL: sil_vtable DerivedForOverride {
 // CHECK:   #BaseForOverride.valueStored!getter.1: (BaseForOverride) -> () -> Int : @$S17materializeForSet07DerivedB8OverrideC11valueStoredSivg
 // CHECK:   #BaseForOverride.valueStored!setter.1: (BaseForOverride) -> (Int) -> () : @$S17materializeForSet07DerivedB8OverrideC11valueStoredSivs
diff --git a/test/SILGen/metatype_abstraction.swift b/test/SILGen/metatype_abstraction.swift
index 7b701ec..1ee4e9d 100644
--- a/test/SILGen/metatype_abstraction.swift
+++ b/test/SILGen/metatype_abstraction.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership -module-name Swift -parse-stdlib %s | %FileCheck %s
 
 enum Optional<Wrapped> {
diff --git a/test/SILGen/multi_file.swift b/test/SILGen/multi_file.swift
index 9109af1..9be3c89 100644
--- a/test/SILGen/multi_file.swift
+++ b/test/SILGen/multi_file.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership -primary-file %s %S/Inputs/multi_file_helper.swift | %FileCheck %s
 
 func markUsed<T>(_ t: T) {}
diff --git a/test/SILGen/nested_generics.swift b/test/SILGen/nested_generics.swift
index d3f1460..b639d7d 100644
--- a/test/SILGen/nested_generics.swift
+++ b/test/SILGen/nested_generics.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -enable-sil-ownership -Xllvm -sil-full-demangle -emit-silgen  -parse-as-library %s | %FileCheck %s
 // RUN: %target-swift-frontend -enable-sil-ownership -Xllvm -sil-full-demangle -emit-sil -parse-as-library %s > /dev/null
 // RUN: %target-swift-frontend -enable-sil-ownership -Xllvm -sil-full-demangle -emit-sil -O -parse-as-library %s > /dev/null
diff --git a/test/SILGen/nested_types_referencing_nested_functions.swift b/test/SILGen/nested_types_referencing_nested_functions.swift
index db22276..d6a8d6d 100644
--- a/test/SILGen/nested_types_referencing_nested_functions.swift
+++ b/test/SILGen/nested_types_referencing_nested_functions.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership %s | %FileCheck %s
 
 do {
diff --git a/test/SILGen/newtype.swift b/test/SILGen/newtype.swift
index 7b80715..1f7b6f2 100644
--- a/test/SILGen/newtype.swift
+++ b/test/SILGen/newtype.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -emit-silgen -sdk %S/Inputs -I %S/Inputs -enable-source-import  %s | %FileCheck %s -check-prefix=CHECK-RAW
 
 // RUN: %target-swift-frontend -emit-sil -sdk %S/Inputs -I %S/Inputs -enable-source-import  %s | %FileCheck %s -check-prefix=CHECK-CANONICAL
diff --git a/test/SILGen/noescape_reabstraction.swift b/test/SILGen/noescape_reabstraction.swift
index 1958efd..4bfeb40 100644
--- a/test/SILGen/noescape_reabstraction.swift
+++ b/test/SILGen/noescape_reabstraction.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership %s | %FileCheck %s
 
 struct S {}
diff --git a/test/SILGen/objc_attr_NSManaged.swift b/test/SILGen/objc_attr_NSManaged.swift
index 8cb5e51..0a60635 100644
--- a/test/SILGen/objc_attr_NSManaged.swift
+++ b/test/SILGen/objc_attr_NSManaged.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -sdk %S/Inputs %s -I %S/Inputs -enable-source-import -emit-silgen -enable-sil-ownership | %FileCheck %s
 
 // REQUIRES: objc_interop
@@ -104,7 +105,7 @@
 	@NSManaged final var entityID: String
 }
 
-// CHECK-LABEL: sil private @$S19objc_attr_NSManaged11FinalEntityC8entityIDSSvmytfU_ : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout FinalEntity, @thick FinalEntity.Type) -> ()
+// CHECK-LABEL: sil private @$S19objc_attr_NSManaged11FinalEntityC8entityIDSSvmytfU_ : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @in_guaranteed FinalEntity, @thick FinalEntity.Type) -> ()
 // CHECK: objc_method {{.*}} : $FinalEntity, #FinalEntity.entityID!setter.1.foreign
 // CHECK: return
 
diff --git a/test/SILGen/objc_attr_NSManaged_multi.swift b/test/SILGen/objc_attr_NSManaged_multi.swift
index 5cce85e..9b4f085 100644
--- a/test/SILGen/objc_attr_NSManaged_multi.swift
+++ b/test/SILGen/objc_attr_NSManaged_multi.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -sdk %S/Inputs -primary-file %s %S/objc_attr_NSManaged.swift -I %S/Inputs -enable-source-import -emit-silgen -enable-sil-ownership | %FileCheck %s
 
 // REQUIRES: objc_interop
diff --git a/test/SILGen/objc_blocks_bridging.swift b/test/SILGen/objc_blocks_bridging.swift
index 50cc6e6..8984176 100644
--- a/test/SILGen/objc_blocks_bridging.swift
+++ b/test/SILGen/objc_blocks_bridging.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %empty-directory(%t)
 // RUN: %build-silgen-test-overlays
 // RUN: %target-swift-frontend(mock-sdk: -sdk %S/Inputs -I %t) -verify -emit-silgen -I %S/Inputs -disable-objc-attr-requires-foundation-module -enable-sil-ownership %s | %FileCheck %s
diff --git a/test/SILGen/objc_bridged_results.swift b/test/SILGen/objc_bridged_results.swift
index a0aaa6b..94c6cbb 100644
--- a/test/SILGen/objc_bridged_results.swift
+++ b/test/SILGen/objc_bridged_results.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %empty-directory(%t)
 // RUN: %build-silgen-test-overlays
 
diff --git a/test/SILGen/objc_bridging.swift b/test/SILGen/objc_bridging.swift
index 613a091..28b2ed6 100644
--- a/test/SILGen/objc_bridging.swift
+++ b/test/SILGen/objc_bridging.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %empty-directory(%t)
 // RUN: %build-silgen-test-overlays
 // RUN: %target-swift-frontend(mock-sdk: -sdk %S/Inputs -I %t) -emit-module -o %t -I %S/../Inputs/ObjCBridging %S/../Inputs/ObjCBridging/Appliances.swift
diff --git a/test/SILGen/objc_bridging_any.swift b/test/SILGen/objc_bridging_any.swift
index aa23de2..3ca525e 100644
--- a/test/SILGen/objc_bridging_any.swift
+++ b/test/SILGen/objc_bridging_any.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -Xllvm -sil-print-debuginfo -emit-silgen -enable-sil-ownership %s | %FileCheck %s
 // REQUIRES: objc_interop
 
@@ -757,4 +758,5 @@
 // CHECK-LABEL: sil_witness_table shared [serialized] GenericOption: Hashable module objc_generics {
 // CHECK-NEXT: base_protocol Equatable: GenericOption: Equatable module objc_generics
 // CHECK-NEXT: method #Hashable.hashValue!getter.1: {{.*}} : @$SSo13GenericOptionas8HashableSCsACP9hashValueSivgTW
+// CHECK-NEXT: method #Hashable._hash!1: {{.*}} : @$SSo13GenericOptionas8HashableSCsACP5_hash4intoys7_HasherVz_tFTW
 // CHECK-NEXT: }
diff --git a/test/SILGen/objc_bridging_peephole.swift b/test/SILGen/objc_bridging_peephole.swift
index 317aba5..09954bb 100644
--- a/test/SILGen/objc_bridging_peephole.swift
+++ b/test/SILGen/objc_bridging_peephole.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -emit-silgen -enable-sil-ownership %s | %FileCheck %s
 // REQUIRES: objc_interop
 
diff --git a/test/SILGen/objc_currying.swift b/test/SILGen/objc_currying.swift
index a22f54e..036ca8c 100644
--- a/test/SILGen/objc_currying.swift
+++ b/test/SILGen/objc_currying.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %empty-directory(%t)
 // RUN: %build-silgen-test-overlays
 // RUN: %target-swift-frontend(mock-sdk: -sdk %S/Inputs -I %t) -enable-sil-ownership -emit-silgen %s | %FileCheck %s
diff --git a/test/SILGen/objc_dictionary_bridging.swift b/test/SILGen/objc_dictionary_bridging.swift
index 421fc90..74dd95e 100644
--- a/test/SILGen/objc_dictionary_bridging.swift
+++ b/test/SILGen/objc_dictionary_bridging.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %empty-directory(%t)
 // RUN: %build-silgen-test-overlays
 
diff --git a/test/SILGen/objc_error.swift b/test/SILGen/objc_error.swift
index 1a40901..b9ee4d3 100644
--- a/test/SILGen/objc_error.swift
+++ b/test/SILGen/objc_error.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %empty-directory(%t)
 // RUN: %build-clang-importer-objc-overlays
 
diff --git a/test/SILGen/objc_extensions.swift b/test/SILGen/objc_extensions.swift
index b3f34bf..639b8aa 100644
--- a/test/SILGen/objc_extensions.swift
+++ b/test/SILGen/objc_extensions.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -enable-sil-ownership -emit-silgen -sdk %S/Inputs/ -I %S/Inputs -enable-source-import %s | %FileCheck %s
 
 // REQUIRES: objc_interop
diff --git a/test/SILGen/objc_imported_generic.swift b/test/SILGen/objc_imported_generic.swift
index 165e8dd..586aea6 100644
--- a/test/SILGen/objc_imported_generic.swift
+++ b/test/SILGen/objc_imported_generic.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -emit-silgen %s -enable-sil-ownership | %FileCheck %s
 // For integration testing, ensure we get through IRGen too.
 // RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -emit-ir -verify -DIRGEN_INTEGRATION_TEST %s
diff --git a/test/SILGen/objc_ownership_conventions.swift b/test/SILGen/objc_ownership_conventions.swift
index adc562a..ec991b6 100644
--- a/test/SILGen/objc_ownership_conventions.swift
+++ b/test/SILGen/objc_ownership_conventions.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -sdk %S/Inputs -I %S/Inputs -enable-source-import %s -emit-silgen -enable-sil-ownership | %FileCheck %s
 
 // REQUIRES: objc_interop
diff --git a/test/SILGen/objc_protocol_native_thunk.swift b/test/SILGen/objc_protocol_native_thunk.swift
index f5540bd..bde4e32 100644
--- a/test/SILGen/objc_protocol_native_thunk.swift
+++ b/test/SILGen/objc_protocol_native_thunk.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -emit-silgen -enable-sil-ownership %s | %FileCheck %s
 // REQUIRES: objc_interop
 
diff --git a/test/SILGen/objc_protocols.swift b/test/SILGen/objc_protocols.swift
index 2b91662..15a0ed2 100644
--- a/test/SILGen/objc_protocols.swift
+++ b/test/SILGen/objc_protocols.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -sdk %S/Inputs -I %S/Inputs -enable-source-import %s -emit-silgen -disable-objc-attr-requires-foundation-module -enable-sil-ownership | %FileCheck %s
 
 // REQUIRES: objc_interop
diff --git a/test/SILGen/objc_set_bridging.swift b/test/SILGen/objc_set_bridging.swift
index 617d9e8..5e79cfd 100644
--- a/test/SILGen/objc_set_bridging.swift
+++ b/test/SILGen/objc_set_bridging.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %empty-directory(%t)
 // RUN: %build-silgen-test-overlays
 
diff --git a/test/SILGen/objc_thunks.swift b/test/SILGen/objc_thunks.swift
index c0adf9d..f6f8d3f 100644
--- a/test/SILGen/objc_thunks.swift
+++ b/test/SILGen/objc_thunks.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -Xllvm -sil-full-demangle -Xllvm -sil-print-debuginfo -sdk %S/Inputs -I %S/Inputs -enable-source-import %s -emit-silgen -emit-verbose-sil -enable-sil-ownership | %FileCheck %s
 
 // REQUIRES: objc_interop
diff --git a/test/SILGen/objc_witnesses.swift b/test/SILGen/objc_witnesses.swift
index 9d754fc..333edae 100644
--- a/test/SILGen/objc_witnesses.swift
+++ b/test/SILGen/objc_witnesses.swift
@@ -100,7 +100,7 @@
   var valence: Int { get { return 1 } set { } }
 }
 
-// CHECK-LABEL: sil private @$SSo8NSObjectC14objc_witnessesE7valenceSivmytfU_ : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout NSObject, @thick NSObject.Type) -> () {
+// CHECK-LABEL: sil private @$SSo8NSObjectC14objc_witnessesE7valenceSivmytfU_ : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @in_guaranteed NSObject, @thick NSObject.Type) -> () {
 // CHECK: objc_method %4 : $NSObject, #NSObject.valence!setter.1.foreign
 // CHECK: }
 
diff --git a/test/SILGen/opaque_ownership.swift b/test/SILGen/opaque_ownership.swift
index d56c998..5fa51ce 100644
--- a/test/SILGen/opaque_ownership.swift
+++ b/test/SILGen/opaque_ownership.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -enable-sil-opaque-values -enable-sil-ownership -emit-sorted-sil -Xllvm -sil-full-demangle -emit-silgen -parse-stdlib -parse-as-library -module-name Swift %s | %FileCheck %s
 // RUN: %target-swift-frontend -target x86_64-apple-macosx10.9 -enable-sil-opaque-values -enable-sil-ownership -emit-sorted-sil -Xllvm -sil-full-demangle -emit-silgen -parse-stdlib -parse-as-library -module-name Swift %s | %FileCheck --check-prefix=CHECK-OSX %s
 
@@ -170,7 +171,7 @@
   case minus
 }
 
-#if os(OSX)
+#if os(macOS)
 // Test open_existential_value used in a conversion context.
 // (the actual bridging call is dropped because we don't import Swift).
 // ---
@@ -195,7 +196,7 @@
 
 public protocol Error {}
 
-#if os(OSX)
+#if os(macOS)
 // Test open_existential_box_value in a conversion context.
 // ---
 // CHECK-OSX-LABEL: sil @$Ss3foo1eys5Error_pSg_tF : $@convention(thin) (@owned Optional<Error>) -> () {
diff --git a/test/SILGen/opaque_values_silgen.swift b/test/SILGen/opaque_values_silgen.swift
index 1154d02..6c9931b 100644
--- a/test/SILGen/opaque_values_silgen.swift
+++ b/test/SILGen/opaque_values_silgen.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -enable-sil-opaque-values -emit-sorted-sil -Xllvm -sil-full-demangle -emit-silgen %s | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%target-runtime
 
 // UNSUPPORTED: resilient_stdlib
diff --git a/test/SILGen/opaque_values_silgen_lib.swift b/test/SILGen/opaque_values_silgen_lib.swift
index c7064d7..3d69099 100644
--- a/test/SILGen/opaque_values_silgen_lib.swift
+++ b/test/SILGen/opaque_values_silgen_lib.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -enable-sil-ownership -enable-sil-opaque-values -emit-sorted-sil -Xllvm -sil-full-demangle -parse-stdlib -parse-as-library -emit-silgen -module-name Swift %s | %FileCheck %s
 // UNSUPPORTED: resilient_stdlib
 
diff --git a/test/SILGen/optional-cast.swift b/test/SILGen/optional-cast.swift
index e5501cb..6a1c2f7 100644
--- a/test/SILGen/optional-cast.swift
+++ b/test/SILGen/optional-cast.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership %s | %FileCheck %s
 
 class A {}
diff --git a/test/SILGen/optional.swift b/test/SILGen/optional.swift
index 68b6c8a..3cc67b5 100644
--- a/test/SILGen/optional.swift
+++ b/test/SILGen/optional.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership %s | %FileCheck %s
 
 func testCall(_ f: (() -> ())?) {
diff --git a/test/SILGen/optional_lvalue.swift b/test/SILGen/optional_lvalue.swift
index a735e2c..153200f 100644
--- a/test/SILGen/optional_lvalue.swift
+++ b/test/SILGen/optional_lvalue.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership %s | %FileCheck %s
 
 // CHECK-LABEL: sil hidden @$S15optional_lvalue07assign_a1_B0yySiSgz_SitF
diff --git a/test/SILGen/partial_apply_generic.swift b/test/SILGen/partial_apply_generic.swift
index 9b1e736..94c032c 100644
--- a/test/SILGen/partial_apply_generic.swift
+++ b/test/SILGen/partial_apply_generic.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership %s | %FileCheck %s
 
 protocol Panda {
diff --git a/test/SILGen/partial_apply_protocol.swift b/test/SILGen/partial_apply_protocol.swift
index 902ce27..60e3e0d 100644
--- a/test/SILGen/partial_apply_protocol.swift
+++ b/test/SILGen/partial_apply_protocol.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -enable-sil-ownership -emit-silgen -primary-file %s | %FileCheck %s
 // RUN: %target-swift-frontend -enable-sil-ownership -emit-ir -primary-file %s
 
diff --git a/test/SILGen/partial_apply_protocol_class_refinement_method.swift b/test/SILGen/partial_apply_protocol_class_refinement_method.swift
index f69af05..ca2450c 100644
--- a/test/SILGen/partial_apply_protocol_class_refinement_method.swift
+++ b/test/SILGen/partial_apply_protocol_class_refinement_method.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership %s | %FileCheck %s
 
 protocol P { func foo() }
diff --git a/test/SILGen/partial_apply_super.swift b/test/SILGen/partial_apply_super.swift
index ae315df..685ee8c 100644
--- a/test/SILGen/partial_apply_super.swift
+++ b/test/SILGen/partial_apply_super.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %empty-directory(%t)
 // RUN: %target-swift-frontend -I %t -emit-module -emit-module-path=%t/resilient_struct.swiftmodule -module-name resilient_struct %S/../Inputs/resilient_struct.swift
 // RUN: %target-swift-frontend -I %t -emit-module -emit-module-path=%t/resilient_class.swiftmodule -module-name resilient_class %S/../Inputs/resilient_class.swift
diff --git a/test/SILGen/pgo_checked_cast.swift b/test/SILGen/pgo_checked_cast.swift
index f8ae4f9..41db5fd 100644
--- a/test/SILGen/pgo_checked_cast.swift
+++ b/test/SILGen/pgo_checked_cast.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %empty-directory(%t)
 // RUN: %target-build-swift %s -profile-generate -Xfrontend -disable-incremental-llvm-codegen -module-name pgo_checked_cast -o %t/main
 // RUN: env LLVM_PROFILE_FILE=%t/default.profraw %target-run %t/main
diff --git a/test/SILGen/pgo_switchenum.swift b/test/SILGen/pgo_switchenum.swift
index 6b9d940..9978fa6 100644
--- a/test/SILGen/pgo_switchenum.swift
+++ b/test/SILGen/pgo_switchenum.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %empty-directory(%t)
 // RUN: %target-build-swift %s -profile-generate -Xfrontend -disable-incremental-llvm-codegen -module-name pgo_switchenum -o %t/main
 // RUN: env LLVM_PROFILE_FILE=%t/default.profraw %target-run %t/main
diff --git a/test/SILGen/plus_zero_access_marker_gen.swift b/test/SILGen/plus_zero_access_marker_gen.swift
new file mode 100644
index 0000000..6781648
--- /dev/null
+++ b/test/SILGen/plus_zero_access_marker_gen.swift
@@ -0,0 +1,139 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -parse-as-library -Xllvm -sil-full-demangle -enforce-exclusivity=checked -emit-silgen -enable-sil-ownership %s | %FileCheck %s
+
+func modify<T>(_ x: inout T) {}
+
+public struct S {
+  var i: Int
+  var o: AnyObject?
+}
+
+// CHECK-LABEL: sil hidden [noinline] @$S17access_marker_gen5initSyAA1SVyXlSgF : $@convention(thin) (@guaranteed Optional<AnyObject>) -> @owned S {
+// CHECK: bb0(%0 : @guaranteed $Optional<AnyObject>):
+// CHECK: [[BOX:%.*]] = alloc_box ${ var S }, var, name "s"
+// CHECK: [[MARKED_BOX:%.*]] = mark_uninitialized [var] [[BOX]] : ${ var S }
+// CHECK: [[ADDR:%.*]] = project_box [[MARKED_BOX]] : ${ var S }, 0
+// CHECK: cond_br %{{.*}}, bb1, bb2
+// CHECK: bb1:
+// CHECK: [[ACCESS1:%.*]] = begin_access [modify] [unknown] [[ADDR]] : $*S
+// CHECK: assign %{{.*}} to [[ACCESS1]] : $*S
+// CHECK: end_access [[ACCESS1]] : $*S
+// CHECK: bb2:
+// CHECK: [[ACCESS2:%.*]] = begin_access [modify] [unknown] [[ADDR]] : $*S
+// CHECK: assign %{{.*}} to [[ACCESS2]] : $*S
+// CHECK: end_access [[ACCESS2]] : $*S
+// CHECK: bb3:
+// CHECK: [[ACCESS3:%.*]] = begin_access [read] [unknown] [[ADDR]] : $*S
+// CHECK: [[RET:%.*]] = load [copy] [[ACCESS3]] : $*S
+// CHECK: end_access [[ACCESS3]] : $*S
+// CHECK: return [[RET]] : $S
+// CHECK-LABEL: } // end sil function '$S17access_marker_gen5initSyAA1SVyXlSgF'
+@inline(never)
+func initS(_ o: AnyObject?) -> S {
+  var s: S
+  if o == nil {
+    s = S(i: 0, o: nil)
+  } else {
+    s = S(i: 1, o: o)
+  }
+  return s
+}
+
+@inline(never)
+func takeS(_ s: S) {}
+
+// CHECK-LABEL: sil @$S17access_marker_gen14modifyAndReadSyyF : $@convention(thin) () -> () {
+// CHECK: bb0:
+// CHECK: %[[BOX:.*]] = alloc_box ${ var S }, var, name "s"
+// CHECK: %[[ADDRS:.*]] = project_box %[[BOX]] : ${ var S }, 0
+// CHECK: %[[ACCESS1:.*]] = begin_access [modify] [unknown] %[[ADDRS]] : $*S
+// CHECK: %[[ADDRI:.*]] = struct_element_addr %[[ACCESS1]] : $*S, #S.i
+// CHECK: assign %{{.*}} to %[[ADDRI]] : $*Int
+// CHECK: end_access %[[ACCESS1]] : $*S
+// CHECK: %[[ACCESS2:.*]] = begin_access [read] [unknown] %[[ADDRS]] : $*S
+// CHECK: %{{.*}} = load [copy] %[[ACCESS2]] : $*S
+// CHECK: end_access %[[ACCESS2]] : $*S
+// CHECK-LABEL: } // end sil function '$S17access_marker_gen14modifyAndReadSyyF'
+public func modifyAndReadS() {
+  var s = initS(nil)
+  s.i = 42
+  takeS(s)
+}
+
+var global = S(i: 0, o: nil)
+
+func readGlobal() -> AnyObject? {
+  return global.o
+}
+
+// CHECK-LABEL: sil hidden @$S17access_marker_gen10readGlobalyXlSgyF
+// CHECK:         [[ADDRESSOR:%.*]] = function_ref @$S17access_marker_gen6globalAA1SVvau :
+// CHECK-NEXT:    [[T0:%.*]] = apply [[ADDRESSOR]]()
+// CHECK-NEXT:    [[T1:%.*]] = pointer_to_address [[T0]] : $Builtin.RawPointer to [strict] $*S
+// CHECK-NEXT:    [[T2:%.*]] = begin_access [read] [dynamic] [[T1]]
+// CHECK-NEXT:    [[T3:%.*]] = struct_element_addr [[T2]] : $*S, #S.o
+// CHECK-NEXT:    [[T4:%.*]] = load [copy] [[T3]]
+// CHECK-NEXT:    end_access [[T2]]
+// CHECK-NEXT:    return [[T4]]
+
+
+public struct HasTwoStoredProperties {
+  var f: Int = 7
+  var g: Int = 9
+
+// CHECK-LABEL: sil hidden @$S17access_marker_gen22HasTwoStoredPropertiesV027noOverlapOnAssignFromPropToM0yyF : $@convention(method) (@inout HasTwoStoredProperties) -> ()
+// CHECK:       [[ACCESS1:%.*]] = begin_access [read] [unknown] [[SELF_ADDR:%.*]] : $*HasTwoStoredProperties
+// CHECK-NEXT:  [[G_ADDR:%.*]] = struct_element_addr [[ACCESS1]] : $*HasTwoStoredProperties, #HasTwoStoredProperties.g
+// CHECK-NEXT:  [[G_VAL:%.*]] = load [trivial] [[G_ADDR]] : $*Int
+// CHECK-NEXT:  end_access [[ACCESS1]] : $*HasTwoStoredProperties
+// CHECK-NEXT:  [[ACCESS2:%.*]] = begin_access [modify] [unknown] [[SELF_ADDR]] : $*HasTwoStoredProperties
+// CHECK-NEXT:  [[F_ADDR:%.*]] = struct_element_addr [[ACCESS2]] : $*HasTwoStoredProperties, #HasTwoStoredProperties.f
+// CHECK-NEXT:  assign [[G_VAL]] to [[F_ADDR]] : $*Int
+// CHECK-NEXT:  end_access [[ACCESS2]] : $*HasTwoStoredProperties
+  mutating func noOverlapOnAssignFromPropToProp() {
+    f = g
+  }
+}
+
+class C {
+  final var x: Int = 0
+}
+
+func testClassInstanceProperties(c: C) {
+  let y = c.x
+  c.x = y
+}
+// CHECK-LABEL: sil hidden @$S17access_marker_gen27testClassInstanceProperties1cyAA1CC_tF :
+// CHECK: bb0([[C:%.*]] : @guaranteed $C
+// CHECK-NEXT:  debug_value
+// CHECK-NEXT:  [[CX:%.*]] = ref_element_addr [[C]] : $C, #C.x
+// CHECK-NEXT:  [[ACCESS:%.*]] = begin_access [read] [dynamic] [[CX]] : $*Int
+// CHECK-NEXT:  [[Y:%.*]] = load [trivial] [[ACCESS]]
+// CHECK-NEXT:  end_access [[ACCESS]]
+// CHECK-NEXT:  debug_value
+// CHECK-NEXT:  [[CX:%.*]] = ref_element_addr [[C]] : $C, #C.x
+// CHECK-NEXT:  [[ACCESS:%.*]] = begin_access [modify] [dynamic] [[CX]] : $*Int
+// CHECK-NEXT:  assign [[Y]] to [[ACCESS]]
+// CHECK-NEXT:  end_access [[ACCESS]]
+
+class D {
+  var x: Int = 0
+}
+//   materializeForSet callback
+// CHECK-LABEL: sil private [transparent] @$S17access_marker_gen1DC1xSivmytfU_
+// CHECK:       end_unpaired_access [dynamic] %1 : $*Builtin.UnsafeValueBuffer
+
+//   materializeForSet
+// CHECK-LABEL: sil hidden [transparent] @$S17access_marker_gen1DC1xSivm
+// CHECK:       [[T0:%.*]] = ref_element_addr %2 : $D, #D.x
+// CHECK-NEXT:  begin_unpaired_access [modify] [dynamic] [[T0]] : $*Int
+
+func testDispatchedClassInstanceProperty(d: D) {
+  modify(&d.x)
+}
+// CHECK-LABEL: sil hidden @$S17access_marker_gen35testDispatchedClassInstanceProperty1dyAA1DC_tF
+// CHECK:     bb0([[D:%.*]] : @guaranteed $D
+// CHECK:       [[METHOD:%.*]] = class_method [[D]] : $D, #D.x!materializeForSet.1
+// CHECK:       apply [[METHOD]]({{.*}}, [[D]])
+// CHECK-NOT:   begin_access
+
diff --git a/test/SILGen/plus_zero_accessors.swift b/test/SILGen/plus_zero_accessors.swift
new file mode 100644
index 0000000..47ebf94
--- /dev/null
+++ b/test/SILGen/plus_zero_accessors.swift
@@ -0,0 +1,235 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -Xllvm -sil-full-demangle -emit-silgen -enable-sil-ownership %s | %FileCheck %s
+
+// Hold a reference to do to magically become non-POD.
+class Reference {}
+
+// A struct with a non-mutating getter and a mutating setter.
+struct OrdinarySub {
+  var ptr = Reference()
+  subscript(value: Int) -> Int {
+    get { return value }
+    set {}
+  }
+}
+
+class A { var array = OrdinarySub() }
+
+func index0() -> Int { return 0 }
+func index1() -> Int { return 1 }
+
+func someValidPointer<T>() -> UnsafePointer<T> { fatalError() }
+func someValidPointer<T>() -> UnsafeMutablePointer<T> { fatalError() }
+
+// Verify that there is no unnecessary extra copy_value of ref.array.
+// rdar://19002913
+func test0(_ ref: A) {
+  ref.array[index0()] = ref.array[index1()]
+}
+// CHECK: sil hidden @$S9accessors5test0yyAA1ACF : $@convention(thin) (@guaranteed A) -> () {
+// CHECK: bb0([[ARG:%.*]] : @guaranteed $A):
+// CHECK-NEXT: debug_value
+//   Formal evaluation of LHS.
+// CHECK-NEXT: // function_ref accessors.index0() -> Swift.Int
+// CHECK-NEXT: [[T0:%.*]] = function_ref @$S9accessors6index0SiyF
+// CHECK-NEXT: [[INDEX0:%.*]] = apply [[T0]]()
+//   Formal evaluation of RHS.
+// CHECK-NEXT: // function_ref accessors.index1() -> Swift.Int
+// CHECK-NEXT: [[T0:%.*]] = function_ref @$S9accessors6index1SiyF
+// CHECK-NEXT: [[INDEX1:%.*]] = apply [[T0]]()
+//   Formal access to RHS.
+// CHECK-NEXT: [[TEMP:%.*]] = alloc_stack $OrdinarySub
+// CHECK-NEXT: [[T0:%.*]] = class_method [[ARG]] : $A, #A.array!getter.1
+// CHECK-NEXT: [[T1:%.*]] = apply [[T0]]([[ARG]])
+// CHECK-NEXT: store [[T1]] to [init] [[TEMP]]
+// CHECK-NEXT: [[T0:%.*]] = load_borrow [[TEMP]]
+// CHECK-NEXT: // function_ref accessors.OrdinarySub.subscript.getter : (Swift.Int) -> Swift.Int
+// CHECK-NEXT: [[T1:%.*]] = function_ref @$S9accessors11OrdinarySubVyS2icig
+// CHECK-NEXT: [[VALUE:%.*]] = apply [[T1]]([[INDEX1]], [[T0]])
+// CHECK-NEXT: end_borrow [[T0]] from [[TEMP]]
+// CHECK-NEXT: destroy_addr [[TEMP]]
+//   Formal access to LHS.
+// CHECK-NEXT: [[STORAGE:%.*]] = alloc_stack $Builtin.UnsafeValueBuffer
+// CHECK-NEXT: [[BUFFER:%.*]] = alloc_stack $OrdinarySub
+// CHECK-NEXT: [[T0:%.*]] = address_to_pointer [[BUFFER]]
+// CHECK-NEXT: [[T1:%.*]] = class_method [[ARG]] : $A, #A.array!materializeForSet.1
+// CHECK-NEXT: [[T2:%.*]] = apply [[T1]]([[T0]], [[STORAGE]], [[ARG]])
+// CHECK-NEXT: [[T3:%.*]] = tuple_extract [[T2]] {{.*}}, 0
+// CHECK-NEXT: [[OPT_CALLBACK:%.*]] = tuple_extract [[T2]] {{.*}}, 1
+// CHECK-NEXT: [[T4:%.*]] = pointer_to_address [[T3]]
+// CHECK-NEXT: [[ADDR:%.*]] = mark_dependence [[T4]] : $*OrdinarySub on [[ARG]] : $A
+// CHECK-NEXT: // function_ref accessors.OrdinarySub.subscript.setter : (Swift.Int) -> Swift.Int
+// CHECK-NEXT: [[SETTER:%.*]] = function_ref @$S9accessors11OrdinarySubVyS2icis
+// CHECK-NEXT: apply [[SETTER]]([[VALUE]], [[INDEX0]], [[ADDR]])
+// CHECK-NEXT: switch_enum [[OPT_CALLBACK]] : $Optional<Builtin.RawPointer>, case #Optional.some!enumelt.1: [[WRITEBACK:bb[0-9]+]], case #Optional.none!enumelt: [[CONT:bb[0-9]+]]
+
+// CHECK:    [[WRITEBACK]]([[CALLBACK_ADDR:%.*]] : @trivial $Builtin.RawPointer):
+// CHECK-NEXT: [[CALLBACK:%.*]] = pointer_to_thin_function [[CALLBACK_ADDR]] : $Builtin.RawPointer to $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout A, @thick A.Type) -> ()
+// CHECK-NEXT: [[TEMP2:%.*]] = alloc_stack $A
+// SEMANTIC SIL TODO: This is an issue caused by the callback for materializeForSet in the class case taking the value as @inout when it should really take it as @guaranteed.
+// CHECK-NEXT: store_borrow [[ARG]] to [[TEMP2]] : $*A
+// CHECK-NEXT: [[T0:%.*]] = metatype $@thick A.Type
+// CHECK-NEXT: [[T1:%.*]] = address_to_pointer [[ADDR]] : $*OrdinarySub to $Builtin.RawPointer
+// CHECK-NEXT: apply [[CALLBACK]]([[T1]], [[STORAGE]], [[TEMP2]], [[T0]])
+// CHECK-NEXT: dealloc_stack [[TEMP2]]
+// CHECK-NEXT: br [[CONT]]
+
+// CHECK:    [[CONT]]:
+// CHECK-NEXT: dealloc_stack [[BUFFER]]
+// CHECK-NEXT: dealloc_stack [[STORAGE]]
+// CHECK-NEXT: dealloc_stack [[TEMP]]
+// CHECK-NEXT: tuple ()
+// CHECK-NEXT: return
+
+// A struct with a mutating getter and a mutating setter.
+struct MutatingSub {
+  var ptr = Reference()
+  subscript(value: Int) -> Int {
+    mutating get { return value }
+    set {}
+  }
+}
+class B { var array = MutatingSub() }
+
+func test1(_ ref: B) {
+  ref.array[index0()] = ref.array[index1()]
+}
+// CHECK-LABEL: sil hidden @$S9accessors5test1yyAA1BCF : $@convention(thin) (@guaranteed B) -> () {
+// CHECK:    bb0([[ARG:%.*]] : @guaranteed $B):
+// CHECK-NEXT: debug_value
+//   Formal evaluation of LHS.
+// CHECK-NEXT: // function_ref accessors.index0() -> Swift.Int
+// CHECK-NEXT: [[T0:%.*]] = function_ref @$S9accessors6index0SiyF
+// CHECK-NEXT: [[INDEX0:%.*]] = apply [[T0]]()
+//   Formal evaluation of RHS.
+// CHECK-NEXT: // function_ref accessors.index1() -> Swift.Int
+// CHECK-NEXT: [[T0:%.*]] = function_ref @$S9accessors6index1SiyF
+// CHECK-NEXT: [[INDEX1:%.*]] = apply [[T0]]()
+//   Formal access to RHS.
+// CHECK-NEXT: [[STORAGE:%.*]] = alloc_stack $Builtin.UnsafeValueBuffer
+// CHECK-NEXT: [[BUFFER:%.*]] = alloc_stack $MutatingSub
+// CHECK-NEXT: [[T0:%.*]] = address_to_pointer [[BUFFER]]
+// CHECK-NEXT: [[T1:%.*]] = class_method [[ARG]] : $B, #B.array!materializeForSet.1
+// CHECK-NEXT: [[T2:%.*]] = apply [[T1]]([[T0]], [[STORAGE]], [[ARG]])
+// CHECK-NEXT: [[T3:%.*]] = tuple_extract [[T2]] {{.*}}, 0
+// CHECK-NEXT: [[OPT_CALLBACK:%.*]] = tuple_extract [[T2]] {{.*}}, 1
+// CHECK-NEXT: [[T4:%.*]] = pointer_to_address [[T3]]
+// CHECK-NEXT: [[ADDR:%.*]] = mark_dependence [[T4]] : $*MutatingSub on [[ARG]] : $B
+// CHECK-NEXT: // function_ref accessors.MutatingSub.subscript.getter : (Swift.Int) -> Swift.Int
+// CHECK-NEXT: [[T0:%.*]] = function_ref @$S9accessors11MutatingSubVyS2icig : $@convention(method) (Int, @inout MutatingSub) -> Int
+// CHECK-NEXT: [[VALUE:%.*]] = apply [[T0]]([[INDEX1]], [[ADDR]])
+// CHECK-NEXT: switch_enum [[OPT_CALLBACK]] : $Optional<Builtin.RawPointer>, case #Optional.some!enumelt.1: [[WRITEBACK:bb[0-9]+]], case #Optional.none!enumelt: [[CONT:bb[0-9]+]]
+//
+// CHECK:    [[WRITEBACK]]([[CALLBACK_ADDR:%.*]] : @trivial $Builtin.RawPointer):
+// CHECK-NEXT: [[CALLBACK:%.*]] = pointer_to_thin_function [[CALLBACK_ADDR]] : $Builtin.RawPointer to $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout B, @thick B.Type) -> ()
+// CHECK-NEXT: [[TEMP2:%.*]] = alloc_stack $B
+// CHECK-NEXT: store_borrow [[ARG]] to [[TEMP2]] : $*B
+// CHECK-NEXT: [[T0:%.*]] = metatype $@thick B.Type
+// CHECK-NEXT: [[T1:%.*]] = address_to_pointer [[ADDR]] : $*MutatingSub to $Builtin.RawPointer
+// CHECK-NEXT: apply [[CALLBACK]]([[T1]], [[STORAGE]], [[TEMP2]], [[T0]])
+// CHECK-NEXT: dealloc_stack [[TEMP2]]
+// CHECK-NEXT: br [[CONT]]
+//
+// CHECK:    [[CONT]]:
+//   Formal access to LHS.
+// CHECK-NEXT: [[STORAGE2:%.*]] = alloc_stack $Builtin.UnsafeValueBuffer
+// CHECK-NEXT: [[BUFFER2:%.*]] = alloc_stack $MutatingSub
+// CHECK-NEXT: [[T0:%.*]] = address_to_pointer [[BUFFER2]]
+// CHECK-NEXT: [[T1:%.*]] = class_method [[ARG]] : $B, #B.array!materializeForSet.1
+// CHECK-NEXT: [[T2:%.*]] = apply [[T1]]([[T0]], [[STORAGE2]], [[ARG]])
+// CHECK-NEXT: [[T3:%.*]] = tuple_extract [[T2]] {{.*}}, 0
+// CHECK-NEXT: [[OPT_CALLBACK:%.*]] = tuple_extract [[T2]] {{.*}}, 1
+// CHECK-NEXT: [[T4:%.*]] = pointer_to_address [[T3]]
+// CHECK-NEXT: [[ADDR:%.*]] = mark_dependence [[T4]] : $*MutatingSub on [[ARG]] : $B
+// CHECK-NEXT: // function_ref accessors.MutatingSub.subscript.setter : (Swift.Int) -> Swift.Int
+// CHECK-NEXT: [[SETTER:%.*]] = function_ref @$S9accessors11MutatingSubVyS2icis : $@convention(method) (Int, Int, @inout MutatingSub) -> ()
+// CHECK-NEXT: apply [[SETTER]]([[VALUE]], [[INDEX0]], [[ADDR]])
+// CHECK-NEXT: switch_enum [[OPT_CALLBACK]] : $Optional<Builtin.RawPointer>, case #Optional.some!enumelt.1: [[WRITEBACK:bb[0-9]+]], case #Optional.none!enumelt: [[CONT:bb[0-9]+]]
+//
+// CHECK:    [[WRITEBACK]]([[CALLBACK_ADDR:%.*]] : @trivial $Builtin.RawPointer):
+// CHECK-NEXT: [[CALLBACK:%.*]] = pointer_to_thin_function [[CALLBACK_ADDR]] : $Builtin.RawPointer to $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout B, @thick B.Type) -> ()
+// CHECK-NEXT: [[TEMP2:%.*]] = alloc_stack $B
+// CHECK-NEXT: store_borrow [[ARG]] to [[TEMP2]] : $*B
+// CHECK-NEXT: [[T0:%.*]] = metatype $@thick B.Type
+// CHECK-NEXT: [[T1:%.*]] = address_to_pointer [[ADDR]] : $*MutatingSub to $Builtin.RawPointer
+// CHECK-NEXT: apply [[CALLBACK]]([[T1]], [[STORAGE2]], [[TEMP2]], [[T0]])
+// CHECK-NEXT: dealloc_stack [[TEMP2]]
+// CHECK-NEXT: br [[CONT]]
+//
+// CHECK:    [[CONT]]:
+// CHECK-NEXT: dealloc_stack [[BUFFER2]]
+// CHECK-NEXT: dealloc_stack [[STORAGE2]]
+// CHECK-NEXT: dealloc_stack [[BUFFER]]
+// CHECK-NEXT: dealloc_stack [[STORAGE]]
+// CHECK-NEXT: tuple ()
+// CHECK-NEXT: return
+
+struct RecInner {
+  subscript(i: Int) -> Int {
+    get { return i }
+  }
+}
+struct RecOuter {
+  var inner : RecInner {
+    unsafeAddress { return someValidPointer() }
+    unsafeMutableAddress { return someValidPointer() }
+  }
+}
+func test_rec(_ outer: inout RecOuter) -> Int {
+  return outer.inner[0]
+}
+// This uses the immutable addressor.
+// CHECK: sil hidden @$S9accessors8test_recySiAA8RecOuterVzF : $@convention(thin) (@inout RecOuter) -> Int {
+// CHECK:   function_ref @$S9accessors8RecOuterV5innerAA0B5InnerVvlu : $@convention(method) (RecOuter) -> UnsafePointer<RecInner>
+
+struct Rec2Inner {
+  subscript(i: Int) -> Int {
+    mutating get { return i }
+  }
+}
+struct Rec2Outer {
+  var inner : Rec2Inner {
+    unsafeAddress { return someValidPointer() }
+    unsafeMutableAddress { return someValidPointer() }
+  }
+}
+func test_rec2(_ outer: inout Rec2Outer) -> Int {
+  return outer.inner[0]
+}
+// This uses the mutable addressor.
+// CHECK: sil hidden @$S9accessors9test_rec2ySiAA9Rec2OuterVzF : $@convention(thin) (@inout Rec2Outer) -> Int {
+// CHECK:   function_ref @$S9accessors9Rec2OuterV5innerAA0B5InnerVvau : $@convention(method) (@inout Rec2Outer) -> UnsafeMutablePointer<Rec2Inner>
+
+struct Foo {
+  private subscript(privateSubscript x: Void) -> Void {
+    // CHECK-DAG: sil private @$S9accessors3FooV16privateSubscriptyyt_tc33_D7F31B09EE737C687DC580B2014D759CLlig : $@convention(method) (Foo) -> () {
+    get {}
+  }
+  private(set) subscript(withPrivateSet x: Void) -> Void {
+    // CHECK-DAG: sil hidden @$S9accessors3FooV14withPrivateSetyyt_tcig : $@convention(method) (Foo) -> () {
+    get {}
+    // CHECK-DAG: sil private @$S9accessors3FooV14withPrivateSetyyt_tcis : $@convention(method) (@inout Foo) -> () {
+    set {}
+  }
+  subscript(withNestedClass x: Void) -> Void {
+    // Check for initializer of NestedClass
+    // CHECK-DAG: sil private @$S9accessors3FooV15withNestedClassyyt_tcig0dE0L_CAFycfc : $@convention(method) (@owned NestedClass) -> @owned NestedClass {
+    class NestedClass {}
+  }
+
+  // CHECK-DAG: sil private @$S9accessors3FooV15privateVariable33_D7F31B09EE737C687DC580B2014D759CLLytvg : $@convention(method) (Foo) -> () {
+  private var privateVariable: Void {
+    return
+  }
+  private(set) var variableWithPrivateSet: Void {
+    // CHECK-DAG: sil hidden @$S9accessors3FooV22variableWithPrivateSetytvg : $@convention(method) (Foo) -> () {
+    get {}
+    // CHECK-DAG: sil private @$S9accessors3FooV22variableWithPrivateSetytvs : $@convention(method) (@inout Foo) -> () {
+    set {}
+  }
+  var propertyWithNestedClass: Void {
+    // Check for initializer of NestedClass
+    // CHECK-DAG: sil private @$S9accessors3FooV23propertyWithNestedClassytvg0eF0L_CAFycfc : $@convention(method) (@owned NestedClass) -> @owned NestedClass {
+    class NestedClass {}
+  }
+}
diff --git a/test/SILGen/plus_zero_address_only_types.swift b/test/SILGen/plus_zero_address_only_types.swift
new file mode 100644
index 0000000..e270074
--- /dev/null
+++ b/test/SILGen/plus_zero_address_only_types.swift
@@ -0,0 +1,229 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -enable-sil-ownership -parse-as-library -parse-stdlib -emit-silgen %s | %FileCheck %s
+
+precedencegroup AssignmentPrecedence { assignment: true }
+
+typealias Int = Builtin.Int64
+
+enum Bool { case true_, false_ }
+
+protocol Unloadable {
+  func foo() -> Int
+  var address_only_prop : Unloadable { get }
+  var loadable_prop : Int { get }
+}
+
+// CHECK-LABEL: sil hidden @$S18address_only_types0a1_B9_argument{{[_0-9a-zA-Z]*}}F
+func address_only_argument(_ x: Unloadable) {
+  // CHECK: bb0([[XARG:%[0-9]+]] : @trivial $*Unloadable):
+  // CHECK: debug_value_addr [[XARG]]
+  // CHECK-NEXT: tuple
+  // CHECK-NEXT: return
+}
+
+// CHECK-LABEL: sil hidden @$S18address_only_types0a1_B17_ignored_argument{{[_0-9a-zA-Z]*}}F
+func address_only_ignored_argument(_: Unloadable) {
+  // CHECK: bb0([[XARG:%[0-9]+]] : @trivial $*Unloadable):
+  // CHECK-NOT: dealloc_stack {{.*}} [[XARG]]
+  // CHECK: return
+}
+
+// CHECK-LABEL: sil hidden @$S18address_only_types0a1_B7_return{{[_0-9a-zA-Z]*}}F
+func address_only_return(_ x: Unloadable, y: Int) -> Unloadable {
+  // CHECK: bb0([[RET:%[0-9]+]] : @trivial $*Unloadable, [[XARG:%[0-9]+]] : @trivial $*Unloadable, [[YARG:%[0-9]+]] : @trivial $Builtin.Int64):
+  // CHECK-NEXT: debug_value_addr [[XARG]] : $*Unloadable, let, name "x"
+  // CHECK-NEXT: debug_value [[YARG]] : $Builtin.Int64, let, name "y"
+  // CHECK-NEXT: copy_addr [[XARG]] to [initialization] [[RET]]
+  // CHECK-NEXT: [[VOID:%[0-9]+]] = tuple ()
+  // CHECK-NEXT: return [[VOID]]
+  return x
+}
+
+// CHECK-LABEL: sil hidden @$S18address_only_types0a1_B15_missing_return{{[_0-9a-zA-Z]*}}F
+func address_only_missing_return() -> Unloadable {
+  // CHECK: unreachable
+}
+
+// CHECK-LABEL: sil hidden @$S18address_only_types0a1_B27_conditional_missing_return{{[_0-9a-zA-Z]*}}F
+func address_only_conditional_missing_return(_ x: Unloadable) -> Unloadable {
+  // CHECK: bb0({{%.*}} : @trivial $*Unloadable, {{%.*}} : @trivial $*Unloadable):
+  // CHECK:   switch_enum {{%.*}}, case #Bool.true_!enumelt: [[TRUE:bb[0-9]+]], case #Bool.false_!enumelt: [[FALSE:bb[0-9]+]]
+  switch Bool.true_ {
+  case .true_:
+  // CHECK: [[TRUE]]:
+    // CHECK:   copy_addr %1 to [initialization] %0 : $*Unloadable
+  // CHECK:   return
+    return x
+  case .false_:
+    ()
+  }
+  // CHECK: [[FALSE]]:
+  // CHECK:   unreachable
+}
+
+// CHECK-LABEL: sil hidden @$S18address_only_types0a1_B29_conditional_missing_return_2
+func address_only_conditional_missing_return_2(_ x: Unloadable) -> Unloadable {
+  // CHECK: bb0({{%.*}} : @trivial $*Unloadable, {{%.*}} : @trivial $*Unloadable):
+  // CHECK:   switch_enum {{%.*}}, case #Bool.true_!enumelt: [[TRUE1:bb[0-9]+]], case #Bool.false_!enumelt: [[FALSE1:bb[0-9]+]]
+  switch Bool.true_ {
+  case .true_:
+    return x
+  case .false_:
+    ()
+  }
+  // CHECK: [[FALSE1]]:
+  // CHECK:   switch_enum {{%.*}}, case #Bool.true_!enumelt: [[TRUE2:bb[0-9]+]], case #Bool.false_!enumelt: [[FALSE2:bb[0-9]+]]
+  switch Bool.true_ {
+  case .true_:
+    return x
+  case .false_:
+    ()
+  }
+  // CHECK: [[FALSE2]]:
+  // CHECK:   unreachable
+
+  // CHECK: bb{{.*}}:
+  // CHECK:   return
+}
+
+var crap : Unloadable = some_address_only_function_1()
+func some_address_only_function_1() -> Unloadable { return crap }
+func some_address_only_function_2(_ x: Unloadable) -> () {}
+
+// CHECK-LABEL: sil hidden @$S18address_only_types0a1_B7_call_1
+func address_only_call_1() -> Unloadable {
+  // CHECK: bb0([[RET:%[0-9]+]] : @trivial $*Unloadable):
+  return some_address_only_function_1()
+  // FIXME emit into
+  // CHECK: [[FUNC:%[0-9]+]] = function_ref @$S18address_only_types05some_a1_B11_function_1AA10Unloadable_pyF
+  // CHECK: apply [[FUNC]]([[RET]])
+  // CHECK: return
+}
+
+// CHECK-LABEL: sil hidden @$S18address_only_types0a1_B21_call_1_ignore_returnyyF
+func address_only_call_1_ignore_return() {
+  // CHECK: bb0:
+  some_address_only_function_1()
+  // CHECK: [[TEMP:%[0-9]+]] = alloc_stack $Unloadable
+  // CHECK: [[FUNC:%[0-9]+]] = function_ref @$S18address_only_types05some_a1_B11_function_1AA10Unloadable_pyF
+  // CHECK: apply [[FUNC]]([[TEMP]])
+  // CHECK: destroy_addr [[TEMP]]
+  // CHECK: dealloc_stack [[TEMP]]
+  // CHECK: return
+}
+
+// CHECK-LABEL: sil hidden @$S18address_only_types0a1_B7_call_2{{[_0-9a-zA-Z]*}}F
+func address_only_call_2(_ x: Unloadable) {
+  // CHECK: bb0([[XARG:%[0-9]+]] : @trivial $*Unloadable):
+  // CHECK: debug_value_addr [[XARG]] : $*Unloadable
+  some_address_only_function_2(x)
+  // CHECK: [[FUNC:%[0-9]+]] = function_ref @$S18address_only_types05some_a1_B11_function_2{{[_0-9a-zA-Z]*}}F
+  // CHECK: apply [[FUNC]]([[XARG]])
+  // CHECK: return
+}
+
+// CHECK-LABEL: sil hidden @$S18address_only_types0a1_B12_call_1_in_2{{[_0-9a-zA-Z]*}}F
+func address_only_call_1_in_2() {
+  // CHECK: bb0:
+  some_address_only_function_2(some_address_only_function_1())
+  // CHECK: [[TEMP:%[0-9]+]] = alloc_stack $Unloadable
+  // CHECK: [[FUNC1:%[0-9]+]] = function_ref @$S18address_only_types05some_a1_B11_function_1{{[_0-9a-zA-Z]*}}F
+  // CHECK: apply [[FUNC1]]([[TEMP]])
+  // CHECK: [[FUNC2:%[0-9]+]] = function_ref @$S18address_only_types05some_a1_B11_function_2{{[_0-9a-zA-Z]*}}F
+  // CHECK: apply [[FUNC2]]([[TEMP]])
+  // CHECK: dealloc_stack [[TEMP]]
+  // CHECK: return
+}
+
+// CHECK-LABEL: sil hidden @$S18address_only_types0a1_B12_materialize{{[_0-9a-zA-Z]*}}F
+func address_only_materialize() -> Int {
+  // CHECK: bb0:
+  return some_address_only_function_1().foo()
+  // CHECK: [[TEMP:%[0-9]+]] = alloc_stack $Unloadable
+  // CHECK: [[FUNC:%[0-9]+]] = function_ref @$S18address_only_types05some_a1_B11_function_1{{[_0-9a-zA-Z]*}}F
+  // CHECK: apply [[FUNC]]([[TEMP]])
+  // CHECK: [[TEMP_PROJ:%[0-9]+]] = open_existential_addr immutable_access [[TEMP]] : $*Unloadable to $*[[OPENED:@opened(.*) Unloadable]]
+  // CHECK: [[FOO_METHOD:%[0-9]+]] = witness_method $[[OPENED]], #Unloadable.foo!1
+  // CHECK: [[RET:%[0-9]+]] = apply [[FOO_METHOD]]<[[OPENED]]>([[TEMP_PROJ]])
+  // CHECK: destroy_addr [[TEMP]]
+  // CHECK: dealloc_stack [[TEMP]]
+  // CHECK: return [[RET]]
+}
+
+// CHECK-LABEL: sil hidden @$S18address_only_types0a1_B21_assignment_from_temp{{[_0-9a-zA-Z]*}}F
+func address_only_assignment_from_temp(_ dest: inout Unloadable) {
+  // CHECK: bb0([[DEST:%[0-9]+]] : @trivial $*Unloadable):
+  dest = some_address_only_function_1()
+  // CHECK: [[TEMP:%[0-9]+]] = alloc_stack $Unloadable
+  // CHECK: %[[ACCESS:.*]] = begin_access [modify] [unknown] %0 :
+  // CHECK: copy_addr [take] [[TEMP]] to %[[ACCESS]] :
+  // CHECK-NOT: destroy_addr [[TEMP]]
+  // CHECK: dealloc_stack [[TEMP]]
+}
+
+// CHECK-LABEL: sil hidden @$S18address_only_types0a1_B19_assignment_from_lv{{[_0-9a-zA-Z]*}}F
+func address_only_assignment_from_lv(_ dest: inout Unloadable, v: Unloadable) {
+  var v = v
+  // CHECK: bb0([[DEST:%[0-9]+]] : @trivial $*Unloadable, [[VARG:%[0-9]+]] : @trivial $*Unloadable):
+  // CHECK: [[VBOX:%.*]] = alloc_box ${ var Unloadable }
+  // CHECK: [[PBOX:%[0-9]+]] = project_box [[VBOX]]
+  // CHECK: copy_addr [[VARG]] to [initialization] [[PBOX]] : $*Unloadable
+  dest = v
+  // CHECK: [[READBOX:%.*]] = begin_access [read] [unknown] [[PBOX]] :
+  // CHECK: [[TEMP:%[0-9]+]] = alloc_stack $Unloadable
+  // CHECK: copy_addr [[READBOX]] to [initialization] [[TEMP]] :
+  // CHECK: [[RET:%.*]] = begin_access [modify] [unknown] %0 :
+  // CHECK: copy_addr [take] [[TEMP]] to [[RET]] :
+  // CHECK: destroy_value [[VBOX]]
+}
+
+var global_prop : Unloadable {
+  get {
+    return crap
+  }
+  set {}
+}
+
+// CHECK-LABEL: sil hidden @$S18address_only_types0a1_B33_assignment_from_temp_to_property{{[_0-9a-zA-Z]*}}F
+func address_only_assignment_from_temp_to_property() {
+  // CHECK: bb0:
+  global_prop = some_address_only_function_1()
+  // CHECK: [[TEMP:%[0-9]+]] = alloc_stack $Unloadable
+  // CHECK: [[SETTER:%[0-9]+]] = function_ref @$S18address_only_types11global_propAA10Unloadable_pvs
+  // CHECK: apply [[SETTER]]([[TEMP]])
+  // CHECK: dealloc_stack [[TEMP]]
+}
+
+// CHECK-LABEL: sil hidden @$S18address_only_types0a1_B31_assignment_from_lv_to_property{{[_0-9a-zA-Z]*}}F
+func address_only_assignment_from_lv_to_property(_ v: Unloadable) {
+  // CHECK: bb0([[VARG:%[0-9]+]] : @trivial $*Unloadable):
+  // CHECK: debug_value_addr [[VARG]] : $*Unloadable
+  // CHECK: [[TEMP:%[0-9]+]] = alloc_stack $Unloadable
+  // CHECK: copy_addr [[VARG]] to [initialization] [[TEMP]]
+  // CHECK: [[SETTER:%[0-9]+]] = function_ref @$S18address_only_types11global_propAA10Unloadable_pvs
+  // CHECK: apply [[SETTER]]([[TEMP]])
+  // CHECK: dealloc_stack [[TEMP]]
+  global_prop = v
+}
+
+// CHECK-LABEL: sil hidden @$S18address_only_types0a1_B4_varAA10Unloadable_pyF
+func address_only_var() -> Unloadable {
+  // CHECK: bb0([[RET:%[0-9]+]] : @trivial $*Unloadable):
+  var x = some_address_only_function_1()
+  // CHECK: [[XBOX:%[0-9]+]] = alloc_box ${ var Unloadable }
+  // CHECK: [[XPB:%.*]] = project_box [[XBOX]]
+  // CHECK: apply {{%.*}}([[XPB]])
+  return x
+  // CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] [[XPB]] :
+  // CHECK: copy_addr [[ACCESS]] to [initialization] %0
+  // CHECK: destroy_value [[XBOX]]
+  // CHECK: return
+}
+
+func unloadable_to_unloadable(_ x: Unloadable) -> Unloadable { return x }
+var some_address_only_nontuple_arg_function : (Unloadable) -> Unloadable = unloadable_to_unloadable
+
+// CHECK-LABEL: sil hidden @$S18address_only_types05call_a1_B22_nontuple_arg_function{{[_0-9a-zA-Z]*}}F
+func call_address_only_nontuple_arg_function(_ x: Unloadable) {
+  some_address_only_nontuple_arg_function(x)
+}
diff --git a/test/SILGen/plus_zero_addressors.swift b/test/SILGen/plus_zero_addressors.swift
new file mode 100644
index 0000000..0a02140
--- /dev/null
+++ b/test/SILGen/plus_zero_addressors.swift
@@ -0,0 +1,582 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -enable-sil-ownership -parse-stdlib -emit-sil %s | %FileCheck %s
+// RUN: %target-swift-frontend -enable-sil-ownership -parse-stdlib -emit-silgen %s | %FileCheck %s -check-prefix=SILGEN
+// RUN: %target-swift-frontend -enable-sil-ownership -parse-stdlib -emit-ir %s
+
+// This test includes some calls to transparent stdlib functions.
+// We pattern match for the absence of access markers in the inlined code.
+// REQUIRES: optimized_stdlib
+
+import Swift
+
+func someValidPointer<T>() -> UnsafePointer<T> { fatalError() }
+func someValidPointer<T>() -> UnsafeMutablePointer<T> { fatalError() }
+
+struct A {
+  var base: UnsafeMutablePointer<Int32> = someValidPointer()
+
+  subscript(index: Int32) -> Int32 {
+    unsafeAddress {
+      return UnsafePointer(base)
+    }
+    unsafeMutableAddress {
+      return base
+    }
+  }
+
+  static var staticProp: Int32 {
+    unsafeAddress {
+      // Just don't trip up the verifier.
+      fatalError()
+    }
+  }
+}
+
+// CHECK-LABEL: sil hidden @$S10addressors1AVys5Int32VAEcilu : $@convention(method) (Int32, A) -> UnsafePointer<Int32>
+// CHECK: bb0([[INDEX:%.*]] : $Int32, [[SELF:%.*]] : $A):
+// CHECK:   [[BASE:%.*]] = struct_extract [[SELF]] : $A, #A.base
+// CHECK:   [[T0:%.*]] = struct_extract [[BASE]] : $UnsafeMutablePointer<Int32>, #UnsafeMutablePointer._rawValue
+// CHECK:   [[T1:%.*]] = struct $UnsafePointer<Int32> ([[T0]] : $Builtin.RawPointer)
+// CHECK:   return [[T1]] : $UnsafePointer<Int32>
+
+// CHECK-LABEL: sil hidden @$S10addressors1AVys5Int32VAEciau : $@convention(method) (Int32, @inout A) -> UnsafeMutablePointer<Int32>
+// CHECK: bb0([[INDEX:%.*]] : $Int32, [[SELF:%.*]] : $*A):
+// CHECK:   [[READ:%.*]] = begin_access [read] [static] [[SELF]] : $*A
+// CHECK:   [[T0:%.*]] = struct_element_addr [[READ]] : $*A, #A.base
+// CHECK:   [[BASE:%.*]] = load [[T0]] : $*UnsafeMutablePointer<Int32>
+// CHECK:   return [[BASE]] : $UnsafeMutablePointer<Int32>
+
+// CHECK-LABEL: sil hidden @$S10addressors5test0yyF : $@convention(thin) () -> () {
+func test0() {
+// CHECK: [[A:%.*]] = alloc_stack $A
+// CHECK: [[T1:%.*]] = metatype $@thin A.Type
+// CHECK: [[T0:%.*]] = function_ref @$S10addressors1AV{{[_0-9a-zA-Z]*}}fC
+// CHECK: [[AVAL:%.*]] = apply [[T0]]([[T1]]) 
+// CHECK: store [[AVAL]] to [[A]]
+  var a = A()
+
+// CHECK: [[T0:%.*]] = function_ref @$S10addressors1AVys5Int32VAEcilu :
+// CHECK: [[T1:%.*]] = apply [[T0]]({{%.*}}, [[AVAL]])
+// CHECK: [[T2:%.*]] = struct_extract [[T1]] : $UnsafePointer<Int32>, #UnsafePointer._rawValue
+// CHECK: [[T3:%.*]] = pointer_to_address [[T2]] : $Builtin.RawPointer to [strict] $*Int32
+// CHECK: [[Z:%.*]] = load [[T3]] : $*Int32
+  let z = a[10]
+
+// CHECK: [[WRITE:%.*]] = begin_access [modify] [static] [[A]] : $*A
+// CHECK: [[T0:%.*]] = function_ref @$S10addressors1AVys5Int32VAEciau :
+// CHECK: [[T1:%.*]] = apply [[T0]]({{%.*}}, [[WRITE]])
+// CHECK: [[T2:%.*]] = struct_extract [[T1]] : $UnsafeMutablePointer<Int32>, #UnsafeMutablePointer._rawValue
+// CHECK: [[T3:%.*]] = pointer_to_address [[T2]] : $Builtin.RawPointer to [strict] $*Int32
+// CHECK: load
+// CHECK: sadd_with_overflow_Int{{32|64}}
+// CHECK: store {{%.*}} to [[T3]]
+  a[5] += z
+
+// CHECK: [[WRITE:%.*]] = begin_access [modify] [static] [[A]] : $*A
+// CHECK: [[T0:%.*]] = function_ref @$S10addressors1AVys5Int32VAEciau :
+// CHECK: [[T1:%.*]] = apply [[T0]]({{%.*}}, [[WRITE]])
+// CHECK: [[T2:%.*]] = struct_extract [[T1]] : $UnsafeMutablePointer<Int32>, #UnsafeMutablePointer._rawValue
+// CHECK: [[T3:%.*]] = pointer_to_address [[T2]] : $Builtin.RawPointer to [strict] $*Int32
+// CHECK: store {{%.*}} to [[T3]]
+  a[3] = 6
+}
+
+// CHECK-LABEL: sil hidden @$S10addressors5test1s5Int32VyF : $@convention(thin) () -> Int32
+func test1() -> Int32 {
+// CHECK: [[T0:%.*]] = metatype $@thin A.Type
+// CHECK: [[CTOR:%.*]] = function_ref @$S10addressors1AV{{[_0-9a-zA-Z]*}}fC
+// CHECK: [[A:%.*]] = apply [[CTOR]]([[T0]]) : $@convention(method) (@thin A.Type) -> A
+// CHECK: [[ACCESSOR:%.*]] = function_ref @$S10addressors1AVys5Int32VAEcilu : $@convention(method) (Int32, A) -> UnsafePointer<Int32>
+// CHECK: [[PTR:%.*]] = apply [[ACCESSOR]]({{%.*}}, [[A]]) : $@convention(method) (Int32, A) -> UnsafePointer<Int32>
+// CHECK: [[T0:%.*]] = struct_extract [[PTR]] : $UnsafePointer<Int32>, #UnsafePointer._rawValue
+// CHECK: [[T1:%.*]] = pointer_to_address [[T0]] : $Builtin.RawPointer to [strict] $*Int32
+// CHECK: [[T2:%.*]] = load [[T1]] : $*Int32
+// CHECK: return [[T2]] : $Int32
+  return A()[0]
+}
+
+let uninitAddr = UnsafeMutablePointer<Int32>.allocate(capacity: 1)
+var global: Int32 {
+  unsafeAddress {
+    return UnsafePointer(uninitAddr)
+  }
+// CHECK: sil hidden @$S10addressors6globals5Int32Vvlu : $@convention(thin) () -> UnsafePointer<Int32> {
+// CHECK:   [[T0:%.*]] = global_addr @$S10addressors10uninitAddrSpys5Int32VGvp : $*UnsafeMutablePointer<Int32>
+// CHECK:   [[T1:%.*]] = load [[T0]] : $*UnsafeMutablePointer<Int32>
+// CHECK:   [[T2:%.*]] = struct_extract [[T1]] : $UnsafeMutablePointer<Int32>, #UnsafeMutablePointer._rawValue
+// CHECK:   [[T3:%.*]] = struct $UnsafePointer<Int32> ([[T2]] : $Builtin.RawPointer)
+// CHECK:   return [[T3]] : $UnsafePointer<Int32>
+}
+
+func test_global() -> Int32 {
+  return global
+}
+// CHECK-LABEL: sil hidden @$S10addressors11test_globals5Int32VyF : $@convention(thin) () -> Int32 {
+// CHECK:   [[T0:%.*]] = function_ref @$S10addressors6globals5Int32Vvlu : $@convention(thin) () -> UnsafePointer<Int32>
+// CHECK:   [[T1:%.*]] = apply [[T0]]() : $@convention(thin) () -> UnsafePointer<Int32>
+// CHECK:   [[T2:%.*]] = struct_extract [[T1]] : $UnsafePointer<Int32>, #UnsafePointer._rawValue
+// CHECK:   [[T3:%.*]] = pointer_to_address [[T2]] : $Builtin.RawPointer to [strict] $*Int32
+// CHECK:   [[T4:%.*]] = load [[T3]] : $*Int32
+// CHECK:   return [[T4]] : $Int32
+
+// Test that having generated trivial accessors for something because
+// of protocol conformance doesn't force us down inefficient access paths.
+protocol Subscriptable {
+  subscript(i: Int32) -> Int32 { get set }
+}
+
+struct B : Subscriptable {
+  subscript(i: Int32) -> Int32 {
+    unsafeAddress { return someValidPointer() }
+    unsafeMutableAddress { return someValidPointer() }
+  }
+}
+
+// CHECK-LABEL: sil hidden @$S10addressors6test_ByyAA1BVzF : $@convention(thin) (@inout B) -> () {
+// CHECK: bb0([[B:%.*]] : $*B):
+// CHECK:   [[T0:%.*]] = integer_literal $Builtin.Int32, 0
+// CHECK:   [[INDEX:%.*]] = struct $Int32 ([[T0]] : $Builtin.Int32)
+// CHECK:   [[RHS:%.*]] = integer_literal $Builtin.Int32, 7
+// CHECK:   [[WRITE:%.*]] = begin_access [modify] [static] [[B]] : $*B
+// CHECK:   [[T0:%.*]] = function_ref @$S10addressors1BVys5Int32VAEciau
+// CHECK:   [[PTR:%.*]] = apply [[T0]]([[INDEX]], [[WRITE]])
+// CHECK:   [[T0:%.*]] = struct_extract [[PTR]] : $UnsafeMutablePointer<Int32>,
+// CHECK:   [[ADDR:%.*]] = pointer_to_address [[T0]] : $Builtin.RawPointer to [strict] $*Int32
+// Accept either of struct_extract+load or load+struct_element_addr.
+// CHECK:   load
+// CHECK:   [[T1:%.*]] = builtin "or_Int32"
+// CHECK:   [[T2:%.*]] = struct $Int32 ([[T1]] : $Builtin.Int32)
+// CHECK:   store [[T2]] to [[ADDR]] : $*Int32
+func test_B(_ b: inout B) {
+  b[0] |= 7
+}
+
+// Test that we handle abstraction difference.
+struct CArray<T> {
+  var storage: UnsafeMutablePointer<T>
+  subscript(index: Int) -> T {
+    unsafeAddress { return UnsafePointer(storage) + index }
+    unsafeMutableAddress { return storage + index }
+  }
+}
+
+func id_int(_ i: Int32) -> Int32 { return i }
+
+// CHECK-LABEL: sil hidden @$S10addressors11test_carrayys5Int32VAA6CArrayVyA2DcGzF : $@convention(thin) (@inout CArray<(Int32) -> Int32>) -> Int32 {
+// CHECK: bb0([[ARRAY:%.*]] : $*CArray<(Int32) -> Int32>):
+func test_carray(_ array: inout CArray<(Int32) -> Int32>) -> Int32 {
+// CHECK:   [[WRITE:%.*]] = begin_access [modify] [static] [[ARRAY]] : $*CArray<(Int32) -> Int32>
+// CHECK:   [[T0:%.*]] = function_ref @$S10addressors6CArrayVyxSiciau :
+// CHECK:   [[T1:%.*]] = apply [[T0]]<(Int32) -> Int32>({{%.*}}, [[WRITE]])
+// CHECK:   [[T2:%.*]] = struct_extract [[T1]] : $UnsafeMutablePointer<(Int32) -> Int32>, #UnsafeMutablePointer._rawValue
+// CHECK:   [[T3:%.*]] = pointer_to_address [[T2]] : $Builtin.RawPointer to [strict] $*@callee_guaranteed (@in_guaranteed Int32) -> @out Int32
+// CHECK:   store {{%.*}} to [[T3]] :
+  array[0] = id_int
+
+// CHECK:   [[READ:%.*]] = begin_access [read] [static] [[ARRAY]] : $*CArray<(Int32) -> Int32>
+// CHECK:   [[T0:%.*]] = load [[READ]]
+// CHECK:   [[T1:%.*]] = function_ref @$S10addressors6CArrayVyxSicilu :
+// CHECK:   [[T2:%.*]] = apply [[T1]]<(Int32) -> Int32>({{%.*}}, [[T0]])
+// CHECK:   [[T3:%.*]] = struct_extract [[T2]] : $UnsafePointer<(Int32) -> Int32>, #UnsafePointer._rawValue
+// CHECK:   [[T4:%.*]] = pointer_to_address [[T3]] : $Builtin.RawPointer to [strict] $*@callee_guaranteed (@in_guaranteed Int32) -> @out Int32
+// CHECK:   [[T5:%.*]] = load [[T4]]
+  return array[1](5)
+}
+
+// rdar://17270560, redux
+struct D : Subscriptable {
+  subscript(i: Int32) -> Int32 {
+    get { return i }
+    unsafeMutableAddress { return someValidPointer() }
+  }
+}
+// Setter.
+// SILGEN-LABEL: sil hidden [transparent] @$S10addressors1DVys5Int32VAEcis
+// SILGEN: bb0([[VALUE:%.*]] : @trivial $Int32, [[I:%.*]] : @trivial $Int32, [[SELF:%.*]] : @trivial $*D):
+// SILGEN:   debug_value [[VALUE]] : $Int32
+// SILGEN:   debug_value [[I]] : $Int32
+// SILGEN:   debug_value_addr [[SELF]]
+// SILGEN:   [[ACCESS:%.*]] = begin_access [modify] [unknown] [[SELF]] : $*D   // users: %12, %8
+// SILGEN:   [[T0:%.*]] = function_ref @$S10addressors1DVys5Int32VAEciau{{.*}}
+// SILGEN:   [[PTR:%.*]] = apply [[T0]]([[I]], [[ACCESS]])
+// SILGEN:   [[T0:%.*]] = struct_extract [[PTR]] : $UnsafeMutablePointer<Int32>,
+// SILGEN:   [[ADDR:%.*]] = pointer_to_address [[T0]] : $Builtin.RawPointer to [strict] $*Int32
+// SILGEN:   assign [[VALUE]] to [[ADDR]] : $*Int32
+
+// materializeForSet.
+// SILGEN-LABEL: sil hidden [transparent] @$S10addressors1DVys5Int32VAEcim
+// SILGEN: bb0([[BUFFER:%.*]] : @trivial $Builtin.RawPointer, [[STORAGE:%.*]] : @trivial $*Builtin.UnsafeValueBuffer, [[I:%.*]] : @trivial $Int32, [[SELF:%.*]] : @trivial $*D):
+// SILGEN:   [[T0:%.*]] = function_ref @$S10addressors1DVys5Int32VAEciau
+// SILGEN:   [[PTR:%.*]] = apply [[T0]]([[I]], [[SELF]])
+// SILGEN:   [[ADDR_TMP:%.*]] = struct_extract [[PTR]] : $UnsafeMutablePointer<Int32>,
+// SILGEN:   [[ADDR:%.*]] = pointer_to_address [[ADDR_TMP]]
+// SILGEN:   [[PTR:%.*]] = address_to_pointer [[ADDR]]
+// SILGEN:   [[OPT:%.*]] = enum $Optional<Builtin.RawPointer>, #Optional.none!enumelt
+// SILGEN:   [[T2:%.*]] = tuple ([[PTR]] : $Builtin.RawPointer, [[OPT]] : $Optional<Builtin.RawPointer>)
+// SILGEN:   return [[T2]] :
+
+func make_int() -> Int32 { return 0 }
+func take_int_inout(_ value: inout Int32) {}
+
+// CHECK-LABEL: sil hidden @$S10addressors6test_dys5Int32VAA1DVzF : $@convention(thin) (@inout D) -> Int32
+// CHECK: bb0([[ARRAY:%.*]] : $*D):
+func test_d(_ array: inout D) -> Int32 {
+// CHECK:   [[T0:%.*]] = function_ref @$S10addressors8make_ints5Int32VyF
+// CHECK:   [[V:%.*]] = apply [[T0]]()
+// CHECK:   [[WRITE:%.*]] = begin_access [modify] [static] [[ARRAY]] : $*D
+// CHECK:   [[T0:%.*]] = function_ref @$S10addressors1DVys5Int32VAEciau
+// CHECK:   [[T1:%.*]] = apply [[T0]]({{%.*}}, [[WRITE]])
+// CHECK:   [[T2:%.*]] = struct_extract [[T1]] : $UnsafeMutablePointer<Int32>,
+// CHECK:   [[ADDR:%.*]] = pointer_to_address [[T2]] : $Builtin.RawPointer to [strict] $*Int32
+// CHECK:   store [[V]] to [[ADDR]] : $*Int32
+  array[0] = make_int()
+
+// CHECK:   [[WRITE:%.*]] = begin_access [modify] [static] [[ARRAY]] : $*D
+// CHECK:   [[T0:%.*]] = function_ref @$S10addressors1DVys5Int32VAEciau
+// CHECK:   [[T1:%.*]] = apply [[T0]]({{%.*}}, [[WRITE]])
+// CHECK:   [[T2:%.*]] = struct_extract [[T1]] : $UnsafeMutablePointer<Int32>,
+// CHECK:   [[ADDR:%.*]] = pointer_to_address [[T2]] : $Builtin.RawPointer to [strict] $*Int32
+// CHECK:   [[FN:%.*]] = function_ref @$S10addressors14take_int_inoutyys5Int32VzF
+// CHECK:   apply [[FN]]([[ADDR]])
+  take_int_inout(&array[1])
+
+// CHECK:   [[READ:%.*]] = begin_access [read] [static] [[ARRAY]] : $*D
+// CHECK:   [[T0:%.*]] = load [[READ]]
+// CHECK:   [[T1:%.*]] = function_ref @$S10addressors1DVys5Int32VAEcig
+// CHECK:   [[T2:%.*]] = apply [[T1]]({{%.*}}, [[T0]])
+// CHECK:   return [[T2]]
+  return array[2]
+}
+
+struct E {
+  var value: Int32 {
+    unsafeAddress { return someValidPointer() }
+    nonmutating unsafeMutableAddress { return someValidPointer() }
+  }
+}
+
+// CHECK-LABEL: sil hidden @$S10addressors6test_eyyAA1EVF
+// CHECK: bb0([[E:%.*]] : $E):
+// CHECK:   [[T0:%.*]] = function_ref @$S10addressors1EV5values5Int32Vvau
+// CHECK:   [[T1:%.*]] = apply [[T0]]([[E]])
+// CHECK:   [[T2:%.*]] = struct_extract [[T1]]
+// CHECK:   [[T3:%.*]] = pointer_to_address [[T2]]
+// CHECK:   store {{%.*}} to [[T3]] : $*Int32
+func test_e(_ e: E) {
+  e.value = 0
+}
+
+class F {
+  var data: UnsafeMutablePointer<Int32> = UnsafeMutablePointer.allocate(capacity: 100)
+
+  final var value: Int32 {
+    addressWithNativeOwner {
+      return (UnsafePointer(data), Builtin.castToNativeObject(self))
+    }
+    mutableAddressWithNativeOwner {
+      return (data, Builtin.castToNativeObject(self))
+    }
+  }
+}
+
+// CHECK-LABEL: sil hidden @$S10addressors1FC5values5Int32Vvlo : $@convention(method) (@guaranteed F) -> (UnsafePointer<Int32>, @owned Builtin.NativeObject) {
+// CHECK-LABEL: sil hidden @$S10addressors1FC5values5Int32Vvao : $@convention(method) (@guaranteed F) -> (UnsafeMutablePointer<Int32>, @owned Builtin.NativeObject) {
+
+func test_f0(_ f: F) -> Int32 {
+  return f.value
+}
+// CHECK-LABEL: sil hidden @$S10addressors7test_f0ys5Int32VAA1FCF : $@convention(thin) (@guaranteed F) -> Int32 {
+// CHECK: bb0([[SELF:%0]] : $F):
+// CHECK:   [[ADDRESSOR:%.*]] = function_ref @$S10addressors1FC5values5Int32Vvlo : $@convention(method) (@guaranteed F) -> (UnsafePointer<Int32>, @owned Builtin.NativeObject)
+// CHECK:   [[T0:%.*]] = apply [[ADDRESSOR]]([[SELF]])
+// CHECK:   [[PTR:%.*]] = tuple_extract [[T0]] : $(UnsafePointer<Int32>, Builtin.NativeObject), 0
+// CHECK:   [[OWNER:%.*]] = tuple_extract [[T0]] : $(UnsafePointer<Int32>, Builtin.NativeObject), 1
+// CHECK:   [[T0:%.*]] = struct_extract [[PTR]]
+// CHECK:   [[T1:%.*]] = pointer_to_address [[T0]] : $Builtin.RawPointer to [strict] $*Int32
+// CHECK:   [[T2:%.*]] = mark_dependence [[T1]] : $*Int32 on [[OWNER]] : $Builtin.NativeObject
+// CHECK:   [[VALUE:%.*]] = load [[T2]] : $*Int32
+// CHECK:   strong_release [[OWNER]] : $Builtin.NativeObject
+// CHECK-NOT:   strong_release [[SELF]] : $F
+// CHECK:   return [[VALUE]] : $Int32
+
+func test_f1(_ f: F) {
+  f.value = 14
+}
+// CHECK-LABEL: sil hidden @$S10addressors7test_f1yyAA1FCF : $@convention(thin) (@guaranteed F) -> () {
+// CHECK: bb0([[SELF:%0]] : $F):
+// CHECK:   [[T0:%.*]] = integer_literal $Builtin.Int32, 14
+// CHECK:   [[VALUE:%.*]] = struct $Int32 ([[T0]] : $Builtin.Int32)
+// CHECK:   [[ADDRESSOR:%.*]] = function_ref @$S10addressors1FC5values5Int32Vvao : $@convention(method) (@guaranteed F) -> (UnsafeMutablePointer<Int32>, @owned Builtin.NativeObject)
+// CHECK:   [[T0:%.*]] = apply [[ADDRESSOR]]([[SELF]])
+// CHECK:   [[PTR:%.*]] = tuple_extract [[T0]] : $(UnsafeMutablePointer<Int32>, Builtin.NativeObject), 0
+// CHECK:   [[OWNER:%.*]] = tuple_extract [[T0]] : $(UnsafeMutablePointer<Int32>, Builtin.NativeObject), 1
+// CHECK:   [[T0:%.*]] = struct_extract [[PTR]]
+// CHECK:   [[T1:%.*]] = pointer_to_address [[T0]] : $Builtin.RawPointer to [strict] $*Int32
+// CHECK:   [[T2:%.*]] = mark_dependence [[T1]] : $*Int32 on [[OWNER]] : $Builtin.NativeObject
+// CHECK:   store [[VALUE]] to [[T2]] : $*Int32
+// CHECK:   strong_release [[OWNER]] : $Builtin.NativeObject
+// CHECK-NOT:   strong_release [[SELF]] : $F
+
+class G {
+  var data: UnsafeMutablePointer<Int32> = UnsafeMutablePointer.allocate(capacity: 100)
+
+  var value: Int32 {
+    addressWithNativeOwner {
+      return (UnsafePointer(data), Builtin.castToNativeObject(self))
+    }
+    mutableAddressWithNativeOwner {
+      return (data, Builtin.castToNativeObject(self))
+    }
+  }
+}
+// CHECK-LABEL: sil hidden [transparent] @$S10addressors1GC5values5Int32Vvg : $@convention(method) (@guaranteed G) -> Int32 {
+// CHECK: bb0([[SELF:%0]] : $G):
+// CHECK:   [[ADDRESSOR:%.*]] = function_ref @$S10addressors1GC5values5Int32Vvlo : $@convention(method) (@guaranteed G) -> (UnsafePointer<Int32>, @owned Builtin.NativeObject)
+// CHECK:   [[T0:%.*]] = apply [[ADDRESSOR]]([[SELF]])
+// CHECK:   [[PTR:%.*]] = tuple_extract [[T0]] : $(UnsafePointer<Int32>, Builtin.NativeObject), 0
+// CHECK:   [[OWNER:%.*]] = tuple_extract [[T0]] : $(UnsafePointer<Int32>, Builtin.NativeObject), 1
+// CHECK:   [[T0:%.*]] = struct_extract [[PTR]]
+// CHECK:   [[T1:%.*]] = pointer_to_address [[T0]] : $Builtin.RawPointer to [strict] $*Int32
+// CHECK:   [[T2:%.*]] = mark_dependence [[T1]] : $*Int32 on [[OWNER]] : $Builtin.NativeObject
+// CHECK:   [[VALUE:%.*]] = load [[T2]] : $*Int32
+// CHECK:   strong_release [[OWNER]] : $Builtin.NativeObject
+// CHECK:   return [[VALUE]] : $Int32
+
+// CHECK-LABEL: sil hidden [transparent] @$S10addressors1GC5values5Int32Vvs : $@convention(method) (Int32, @guaranteed G) -> () {
+// CHECK: bb0([[VALUE:%0]] : $Int32, [[SELF:%1]] : $G):
+// CHECK:   [[ADDRESSOR:%.*]] = function_ref @$S10addressors1GC5values5Int32Vvao : $@convention(method) (@guaranteed G) -> (UnsafeMutablePointer<Int32>, @owned Builtin.NativeObject)
+// CHECK:   [[T0:%.*]] = apply [[ADDRESSOR]]([[SELF]])
+// CHECK:   [[PTR:%.*]] = tuple_extract [[T0]] : $(UnsafeMutablePointer<Int32>, Builtin.NativeObject), 0
+// CHECK:   [[OWNER:%.*]] = tuple_extract [[T0]] : $(UnsafeMutablePointer<Int32>, Builtin.NativeObject), 1
+// CHECK:   [[T0:%.*]] = struct_extract [[PTR]]
+// CHECK:   [[T1:%.*]] = pointer_to_address [[T0]] : $Builtin.RawPointer to [strict] $*Int32
+// CHECK:   [[T2:%.*]] = mark_dependence [[T1]] : $*Int32 on [[OWNER]] : $Builtin.NativeObject
+// CHECK:   store [[VALUE]] to [[T2]] : $*Int32
+// CHECK:   strong_release [[OWNER]] : $Builtin.NativeObject
+
+//   materializeForSet callback for G.value
+// CHECK-LABEL: sil private [transparent] @$S10addressors1GC5values5Int32VvmytfU_ : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout G, @thick G.Type) -> () {
+// CHECK: bb0([[BUFFER:%0]] : $Builtin.RawPointer, [[STORAGE:%1]] : $*Builtin.UnsafeValueBuffer, [[SELF:%2]] : $*G, [[SELFTYPE:%3]] : $@thick G.Type):
+// CHECK:   [[T0:%.*]] = project_value_buffer $Builtin.NativeObject in [[STORAGE]] : $*Builtin.UnsafeValueBuffer
+// CHECK:   [[OWNER:%.*]] = load [[T0]]
+// CHECK:   strong_release [[OWNER]] : $Builtin.NativeObject
+// CHECK:   dealloc_value_buffer $Builtin.NativeObject in [[STORAGE]] : $*Builtin.UnsafeValueBuffer
+
+//   materializeForSet for G.value
+// CHECK-LABEL: sil hidden [transparent] @$S10addressors1GC5values5Int32Vvm : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @guaranteed G) -> (Builtin.RawPointer, Optional<Builtin.RawPointer>) {
+// CHECK: bb0([[BUFFER:%0]] : $Builtin.RawPointer, [[STORAGE:%1]] : $*Builtin.UnsafeValueBuffer, [[SELF:%2]] : $G):
+//   Call the addressor.
+// CHECK:   [[ADDRESSOR:%.*]] = function_ref @$S10addressors1GC5values5Int32Vvao : $@convention(method) (@guaranteed G) -> (UnsafeMutablePointer<Int32>, @owned Builtin.NativeObject)
+// CHECK:   [[T0:%.*]] = apply [[ADDRESSOR]]([[SELF]])
+// CHECK:   [[T1:%.*]] = tuple_extract [[T0]] : $(UnsafeMutablePointer<Int32>, Builtin.NativeObject), 0
+// CHECK:   [[T2:%.*]] = tuple_extract [[T0]] : $(UnsafeMutablePointer<Int32>, Builtin.NativeObject), 1
+//   Get the address.
+// CHECK:   [[PTR:%.*]] = struct_extract [[T1]] : $UnsafeMutablePointer<Int32>, #UnsafeMutablePointer._rawValue
+// CHECK:   [[ADDR_TMP:%.*]] = pointer_to_address [[PTR]]
+// CHECK:   [[ADDR:%.*]] = mark_dependence [[ADDR_TMP]] : $*Int32 on [[T2]]
+//   Initialize the callback storage with the owner.
+// CHECK:   [[T0:%.*]] = alloc_value_buffer $Builtin.NativeObject in [[STORAGE]] : $*Builtin.UnsafeValueBuffer
+// CHECK:   store [[T2]] to [[T0]] : $*Builtin.NativeObject
+// CHECK:   [[PTR:%.*]] = address_to_pointer [[ADDR]]
+//   Set up the callback.
+// CHECK:   [[CALLBACK_FN:%.*]] = function_ref @$S10addressors1GC5values5Int32VvmytfU_ :
+// CHECK:   [[CALLBACK_ADDR:%.*]] = thin_function_to_pointer [[CALLBACK_FN]]
+// CHECK:   [[CALLBACK:%.*]] = enum $Optional<Builtin.RawPointer>, #Optional.some!enumelt.1, [[CALLBACK_ADDR]]
+//   Epilogue.
+// CHECK:   [[RESULT:%.*]] = tuple ([[PTR]] : $Builtin.RawPointer, [[CALLBACK]] : $Optional<Builtin.RawPointer>)
+// CHECK:   return [[RESULT]]
+
+class H {
+  var data: UnsafeMutablePointer<Int32> = UnsafeMutablePointer.allocate(capacity: 100)
+
+  final var value: Int32 {
+    addressWithPinnedNativeOwner {
+      return (UnsafePointer(data), Builtin.tryPin(Builtin.castToNativeObject(self)))
+    }
+    mutableAddressWithPinnedNativeOwner {
+      return (data, Builtin.tryPin(Builtin.castToNativeObject(self)))
+    }
+  }
+}
+
+// CHECK-LABEL: sil hidden @$S10addressors1HC5values5Int32Vvlp : $@convention(method) (@guaranteed H) -> (UnsafePointer<Int32>, @owned Optional<Builtin.NativeObject>) {
+// CHECK-LABEL: sil hidden @$S10addressors1HC5values5Int32VvaP : $@convention(method) (@guaranteed H) -> (UnsafeMutablePointer<Int32>, @owned Optional<Builtin.NativeObject>) {
+
+func test_h0(_ f: H) -> Int32 {
+  return f.value
+}
+// CHECK-LABEL: sil hidden @$S10addressors7test_h0ys5Int32VAA1HCF : $@convention(thin) (@guaranteed H) -> Int32 {
+// CHECK: bb0([[SELF:%0]] : $H):
+// CHECK:   [[ADDRESSOR:%.*]] = function_ref @$S10addressors1HC5values5Int32Vvlp : $@convention(method) (@guaranteed H) -> (UnsafePointer<Int32>, @owned Optional<Builtin.NativeObject>)
+
+// CHECK:   [[T0:%.*]] = apply [[ADDRESSOR]]([[SELF]])
+// CHECK:   [[PTR:%.*]] = tuple_extract [[T0]] : $(UnsafePointer<Int32>, Optional<Builtin.NativeObject>), 0
+// CHECK:   [[OWNER:%.*]] = tuple_extract [[T0]] : $(UnsafePointer<Int32>, Optional<Builtin.NativeObject>), 1
+// CHECK:   [[T0:%.*]] = struct_extract [[PTR]]
+// CHECK:   [[T1:%.*]] = pointer_to_address [[T0]] : $Builtin.RawPointer to [strict] $*Int32
+// CHECK:   [[T2:%.*]] = mark_dependence [[T1]] : $*Int32 on [[OWNER]] : $Optional<Builtin.NativeObject>
+// CHECK:   [[VALUE:%.*]] = load [[T2]] : $*Int32
+// CHECK:   strong_unpin [[OWNER]] : $Optional<Builtin.NativeObject>
+// CHECK-NOT:   strong_release [[SELF]] : $H
+// CHECK:   return [[VALUE]] : $Int32
+
+func test_h1(_ f: H) {
+  f.value = 14
+}
+// CHECK-LABEL: sil hidden @$S10addressors7test_h1yyAA1HCF : $@convention(thin) (@guaranteed H) -> () {
+// CHECK: bb0([[SELF:%0]] : $H):
+// CHECK:   [[T0:%.*]] = integer_literal $Builtin.Int32, 14
+// CHECK:   [[VALUE:%.*]] = struct $Int32 ([[T0]] : $Builtin.Int32)
+// CHECK:   [[ADDRESSOR:%.*]] = function_ref @$S10addressors1HC5values5Int32VvaP : $@convention(method) (@guaranteed H) -> (UnsafeMutablePointer<Int32>, @owned Optional<Builtin.NativeObject>)
+// CHECK:   [[T0:%.*]] = apply [[ADDRESSOR]]([[SELF]])
+// CHECK:   [[PTR:%.*]] = tuple_extract [[T0]] : $(UnsafeMutablePointer<Int32>, Optional<Builtin.NativeObject>), 0
+// CHECK:   [[OWNER:%.*]] = tuple_extract [[T0]] : $(UnsafeMutablePointer<Int32>, Optional<Builtin.NativeObject>), 1
+// CHECK:   [[T0:%.*]] = struct_extract [[PTR]]
+// CHECK:   [[T1:%.*]] = pointer_to_address [[T0]] : $Builtin.RawPointer to [strict] $*Int32
+// CHECK:   [[T2:%.*]] = mark_dependence [[T1]] : $*Int32 on [[OWNER]] : $Optional<Builtin.NativeObject>
+// CHECK:   store [[VALUE]] to [[T2]] : $*Int32
+// CHECK:   strong_unpin [[OWNER]] : $Optional<Builtin.NativeObject>
+// CHECK-NOT:   strong_release [[SELF]] : $H
+
+class I {
+  var data: UnsafeMutablePointer<Int32> = UnsafeMutablePointer.allocate(capacity: 100)
+
+  var value: Int32 {
+    addressWithPinnedNativeOwner {
+      return (UnsafePointer(data), Builtin.tryPin(Builtin.castToNativeObject(self)))
+    }
+    mutableAddressWithPinnedNativeOwner {
+      return (data, Builtin.tryPin(Builtin.castToNativeObject(self)))
+    }
+  }
+}
+// CHECK-LABEL: sil hidden [transparent] @$S10addressors1IC5values5Int32Vvg : $@convention(method) (@guaranteed I) -> Int32 {
+// CHECK: bb0([[SELF:%0]] : $I):
+// CHECK:   [[ADDRESSOR:%.*]] = function_ref @$S10addressors1IC5values5Int32Vvlp : $@convention(method) (@guaranteed I) -> (UnsafePointer<Int32>, @owned Optional<Builtin.NativeObject>)
+// CHECK:   [[T0:%.*]] = apply [[ADDRESSOR]]([[SELF]])
+// CHECK:   [[PTR:%.*]] = tuple_extract [[T0]] : $(UnsafePointer<Int32>, Optional<Builtin.NativeObject>), 0
+// CHECK:   [[OWNER:%.*]] = tuple_extract [[T0]] : $(UnsafePointer<Int32>, Optional<Builtin.NativeObject>), 1
+// CHECK:   [[T0:%.*]] = struct_extract [[PTR]]
+// CHECK:   [[T1:%.*]] = pointer_to_address [[T0]] : $Builtin.RawPointer to [strict] $*Int32
+// CHECK:   [[T2:%.*]] = mark_dependence [[T1]] : $*Int32 on [[OWNER]] : $Optional<Builtin.NativeObject>
+// CHECK:   [[VALUE:%.*]] = load [[T2]] : $*Int32
+// CHECK:   strong_unpin [[OWNER]] : $Optional<Builtin.NativeObject>
+// CHECK:   return [[VALUE]] : $Int32
+
+// CHECK-LABEL: sil hidden [transparent] @$S10addressors1IC5values5Int32Vvs : $@convention(method) (Int32, @guaranteed I) -> () {
+// CHECK: bb0([[VALUE:%0]] : $Int32, [[SELF:%1]] : $I):
+// CHECK:   [[ADDRESSOR:%.*]] = function_ref @$S10addressors1IC5values5Int32VvaP : $@convention(method) (@guaranteed I) -> (UnsafeMutablePointer<Int32>, @owned Optional<Builtin.NativeObject>)
+// CHECK:   [[T0:%.*]] = apply [[ADDRESSOR]]([[SELF]])
+// CHECK:   [[PTR:%.*]] = tuple_extract [[T0]] : $(UnsafeMutablePointer<Int32>, Optional<Builtin.NativeObject>), 0
+// CHECK:   [[OWNER:%.*]] = tuple_extract [[T0]] : $(UnsafeMutablePointer<Int32>, Optional<Builtin.NativeObject>), 1
+// CHECK:   [[T0:%.*]] = struct_extract [[PTR]]
+// CHECK:   [[T1:%.*]] = pointer_to_address [[T0]] : $Builtin.RawPointer to [strict] $*Int32
+// CHECK:   [[T2:%.*]] = mark_dependence [[T1]] : $*Int32 on [[OWNER]] : $Optional<Builtin.NativeObject>
+// CHECK:   store [[VALUE]] to [[T2]] : $*Int32
+// CHECK:   strong_unpin [[OWNER]] : $Optional<Builtin.NativeObject>
+
+//   materializeForSet callback for I.value
+// CHECK-LABEL: sil private [transparent] @$S10addressors1IC5values5Int32VvmytfU_ : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout I, @thick I.Type) -> () {
+// CHECK: bb0([[BUFFER:%0]] : $Builtin.RawPointer, [[STORAGE:%1]] : $*Builtin.UnsafeValueBuffer, [[SELF:%2]] : $*I, [[SELFTYPE:%3]] : $@thick I.Type):
+// CHECK:   [[T0:%.*]] = project_value_buffer $Optional<Builtin.NativeObject> in [[STORAGE]] : $*Builtin.UnsafeValueBuffer
+// CHECK:   [[OWNER:%.*]] = load [[T0]]
+// CHECK:   strong_unpin [[OWNER]] : $Optional<Builtin.NativeObject>
+// CHECK:   dealloc_value_buffer $Optional<Builtin.NativeObject> in [[STORAGE]] : $*Builtin.UnsafeValueBuffer
+
+// CHECK-LABEL: sil hidden [transparent] @$S10addressors1IC5values5Int32Vvm : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @guaranteed I) -> (Builtin.RawPointer, Optional<Builtin.RawPointer>) {
+// CHECK: bb0([[BUFFER:%0]] : $Builtin.RawPointer, [[STORAGE:%1]] : $*Builtin.UnsafeValueBuffer, [[SELF:%2]] : $I):
+//   Call the addressor.
+// CHECK:   [[ADDRESSOR:%.*]] = function_ref @$S10addressors1IC5values5Int32VvaP : $@convention(method) (@guaranteed I) -> (UnsafeMutablePointer<Int32>, @owned Optional<Builtin.NativeObject>)
+// CHECK:   [[T0:%.*]] = apply [[ADDRESSOR]]([[SELF]])
+// CHECK:   [[T1:%.*]] = tuple_extract [[T0]] : $(UnsafeMutablePointer<Int32>, Optional<Builtin.NativeObject>), 0
+// CHECK:   [[T2:%.*]] = tuple_extract [[T0]] : $(UnsafeMutablePointer<Int32>, Optional<Builtin.NativeObject>), 1
+//   Pull out the address.
+// CHECK:   [[PTR:%.*]] = struct_extract [[T1]] : $UnsafeMutablePointer<Int32>, #UnsafeMutablePointer._rawValue
+// CHECK:   [[ADDR_TMP:%.*]] = pointer_to_address [[PTR]]
+// CHECK:   [[ADDR:%.*]] = mark_dependence [[ADDR_TMP]] : $*Int32 on [[T2]]
+//   Initialize the callback storage with the owner.
+// CHECK:   [[T0:%.*]] = alloc_value_buffer $Optional<Builtin.NativeObject> in [[STORAGE]] : $*Builtin.UnsafeValueBuffer
+// CHECK:   store [[T2]] to [[T0]] : $*Optional<Builtin.NativeObject>
+// CHECK:   [[PTR:%.*]] = address_to_pointer [[ADDR]]
+//   Set up the callback.
+// CHECK:   [[CALLBACK_FN:%.*]] = function_ref @$S10addressors1IC5values5Int32VvmytfU_ :
+// CHECK:   [[CALLBACK_ADDR:%.*]] = thin_function_to_pointer [[CALLBACK_FN]]
+// CHECK:   [[CALLBACK:%.*]] = enum $Optional<Builtin.RawPointer>, #Optional.some!enumelt.1, [[CALLBACK_ADDR]] 
+//   Epilogue.
+// CHECK:   [[RESULT:%.*]] = tuple ([[PTR]] : $Builtin.RawPointer, [[CALLBACK]] : $Optional<Builtin.RawPointer>)
+// CHECK:   return [[RESULT]]
+
+struct RecInner {
+  subscript(i: Int32) -> Int32 {
+    mutating get { return i }
+  }
+}
+struct RecMiddle {
+  var inner: RecInner
+}
+class RecOuter {
+  var data: UnsafeMutablePointer<RecMiddle> = UnsafeMutablePointer.allocate(capacity: 100)
+  final var middle: RecMiddle {
+    addressWithPinnedNativeOwner {
+      return (UnsafePointer(data), Builtin.tryPin(Builtin.castToNativeObject(self)))
+    }
+    mutableAddressWithPinnedNativeOwner {
+      return (data, Builtin.tryPin(Builtin.castToNativeObject(self)))
+    }
+  }
+}
+func test_rec(_ outer: RecOuter) -> Int32 {
+  return outer.middle.inner[0]
+}
+// This uses the mutable addressor.
+// CHECK-LABEL: sil hidden @$S10addressors8test_recys5Int32VAA8RecOuterCF : $@convention(thin) (@guaranteed RecOuter) -> Int32 {
+// CHECK:   function_ref @$S10addressors8RecOuterC6middleAA0B6MiddleVvaP
+// CHECK:   struct_element_addr {{.*}} : $*RecMiddle, #RecMiddle.inner
+// CHECK:   function_ref @$S10addressors8RecInnerVys5Int32VAEcig
+
+class Base {
+  var data: UnsafeMutablePointer<Int32> = UnsafeMutablePointer.allocate(capacity: 100)
+
+  var value: Int32 {
+    addressWithNativeOwner {
+      return (UnsafePointer(data), Builtin.castToNativeObject(self))
+    }
+    mutableAddressWithNativeOwner {
+      return (data, Builtin.castToNativeObject(self))
+    }
+  }
+}
+
+class Sub : Base {
+  override var value: Int32 {
+    addressWithNativeOwner {
+      return (UnsafePointer(data), Builtin.castToNativeObject(self))
+    }
+    mutableAddressWithNativeOwner {
+      return (data, Builtin.castToNativeObject(self))
+    }
+  }
+}
+
+// Make sure addressors don't get vtable entries.
+// CHECK-LABEL: sil_vtable Base {
+// CHECK-NEXT: #Base.data!getter.1: (Base) -> () -> UnsafeMutablePointer<Int32> : @$S10addressors4BaseC4dataSpys5Int32VGvg
+// CHECK-NEXT: #Base.data!setter.1: (Base) -> (UnsafeMutablePointer<Int32>) -> () : @$S10addressors4BaseC4dataSpys5Int32VGvs
+// CHECK-NEXT: #Base.data!materializeForSet.1: (Base) -> (Builtin.RawPointer, inout Builtin.UnsafeValueBuffer) -> (Builtin.RawPointer, Builtin.RawPointer?) : @$S10addressors4BaseC4dataSpys5Int32VGvm
+// CHECK-NEXT: #Base.value!getter.1: (Base) -> () -> Int32 : @$S10addressors4BaseC5values5Int32Vvg
+// CHECK-NEXT: #Base.value!setter.1: (Base) -> (Int32) -> () : @$S10addressors4BaseC5values5Int32Vvs
+// CHECK-NEXT: #Base.value!materializeForSet.1: (Base) -> (Builtin.RawPointer, inout Builtin.UnsafeValueBuffer) -> (Builtin.RawPointer, Builtin.RawPointer?) : @$S10addressors4BaseC5values5Int32Vvm
+// CHECK-NEXT: #Base.init!initializer.1: (Base.Type) -> () -> Base : @$S10addressors4BaseCACycfc
+// CHECK-NEXT: #Base.deinit!deallocator: @$S10addressors4BaseCfD
+// CHECK-NEXT: }
+
+// CHECK-LABEL: sil_vtable Sub {
+// CHECK-NEXT: #Base.data!getter.1: (Base) -> () -> UnsafeMutablePointer<Int32> : @$S10addressors4BaseC4dataSpys5Int32VGvg
+// CHECK-NEXT: #Base.data!setter.1: (Base) -> (UnsafeMutablePointer<Int32>) -> () : @$S10addressors4BaseC4dataSpys5Int32VGvs
+// CHECK-NEXT: #Base.data!materializeForSet.1: (Base) -> (Builtin.RawPointer, inout Builtin.UnsafeValueBuffer) -> (Builtin.RawPointer, Builtin.RawPointer?) : @$S10addressors4BaseC4dataSpys5Int32VGvm
+// CHECK-NEXT: #Base.value!getter.1: (Base) -> () -> Int32 : @$S10addressors3SubC5values5Int32Vvg
+// CHECK-NEXT: #Base.value!setter.1: (Base) -> (Int32) -> () : @$S10addressors3SubC5values5Int32Vvs
+// CHECK-NEXT: #Base.value!materializeForSet.1: (Base) -> (Builtin.RawPointer, inout Builtin.UnsafeValueBuffer) -> (Builtin.RawPointer, Builtin.RawPointer?) : @$S10addressors3SubC5values5Int32Vvm
+// CHECK-NEXT: #Base.init!initializer.1: (Base.Type) -> () -> Base : @$S10addressors3SubCACycfc
+// CHECK-NEXT: #Sub.deinit!deallocator: @$S10addressors3SubCfD
+// CHECK-NEXT: }
diff --git a/test/SILGen/plus_zero_apply_abstraction_nested.swift b/test/SILGen/plus_zero_apply_abstraction_nested.swift
new file mode 100644
index 0000000..f1143d9
--- /dev/null
+++ b/test/SILGen/plus_zero_apply_abstraction_nested.swift
@@ -0,0 +1,27 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -enable-sil-ownership -emit-silgen %s | %FileCheck %s
+
+infix operator ~> { precedence 255 associativity left }
+
+protocol P { }
+
+func bar<T:P>(_: inout T) -> () -> () { return {_ in ()} }
+func baz<T:P>(_: inout T) -> (Int) -> () { return {_ in ()} }
+
+func ~> <T: P, Args, Result>(
+  x: inout T,
+  m: (_ x: inout T) -> ((Args) -> Result)
+) -> ((Args) -> Result) {
+  return m(&x)
+}
+
+struct X : P {}
+
+var a = X()
+(a~>bar)()
+
+// CHECK:  [[CHAINED_FUNC:%.*]] = apply {{%.*}}<X, (), ()>({{%.*}}, {{%.*}}) : $@convention(thin) <τ_0_0, τ_0_1, τ_0_2 where τ_0_0 : P> (@inout τ_0_0, @noescape @callee_guaranteed (@inout τ_0_0) -> @owned @callee_guaranteed (@in_guaranteed τ_0_1) -> @out τ_0_2) -> @owned @callee_guaranteed (@in_guaranteed τ_0_1) -> @out τ_0_2
+// CHECK:  [[REABSTRACT:%.*]] = function_ref @$SytytIegnr_Ieg_TR
+// CHECK:  [[CHAINED_FUNC_REABSTRACTED:%.*]] = partial_apply [callee_guaranteed] [[REABSTRACT]]([[CHAINED_FUNC]])
+// CHECK:  [[BORROW:%.*]] = begin_borrow [[CHAINED_FUNC_REABSTRACTED]]
+// CHECK:  apply [[BORROW]]() : $@callee_guaranteed () -> ()
diff --git a/test/SILGen/plus_zero_argument_labels.swift b/test/SILGen/plus_zero_argument_labels.swift
new file mode 100644
index 0000000..95bb1d6
--- /dev/null
+++ b/test/SILGen/plus_zero_argument_labels.swift
@@ -0,0 +1,21 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership %s | %FileCheck %s
+
+public struct X { }
+public struct Y { }
+
+public class Foo {
+  func doSomething(x: X, y: Y) { }
+  func doSomethingElse(x: X) { }
+}
+
+// CHECK-LABEL: sil hidden @$S15argument_labels7testFoo{{[_0-9a-zA-Z]*}}F
+// CHECK: bb0([[ARG0:%.*]] : @guaranteed $Foo,
+func testFoo(foo: Foo, x: X, y: Y) {
+  // CHECK: class_method [[ARG0]] : $Foo, #Foo.doSomething!1 : (Foo) -> (X, Y) -> ()
+  foo.doSomething(x: x, y: y)
+
+  // CHECK: class_method [[ARG0]] : $Foo, #Foo.doSomethingElse!1 : (Foo) -> (X) -> ()
+  foo.doSomethingElse(x: x)
+}
+
diff --git a/test/SILGen/plus_zero_argument_shuffle_swift3.swift b/test/SILGen/plus_zero_argument_shuffle_swift3.swift
new file mode 100644
index 0000000..d76bb29
--- /dev/null
+++ b/test/SILGen/plus_zero_argument_shuffle_swift3.swift
@@ -0,0 +1,26 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership %s -swift-version 3 | %FileCheck %s
+
+func fn(_: Any) {}
+
+enum HasAnyCase {
+  case any(_: Any)
+}
+
+// CHECK-LABEL: sil hidden @$S23argument_shuffle_swift31g1xyyp_tF : $@convention(thin) (@in_guaranteed Any) -> () {
+func g(x: Any) {
+  // CHECK: [[FN:%.*]] = function_ref @$S23argument_shuffle_swift32fnyyypF : $@convention(thin) (@in_guaranteed Any) -> ()
+  // CHECK: apply [[FN:%.*]]({{.*}}) : $@convention(thin) (@in_guaranteed Any) -> ()
+  fn(data: 123)
+  // CHECK: [[FN:%.*]] = function_ref @$S23argument_shuffle_swift32fnyyypF : $@convention(thin) (@in_guaranteed Any) -> ()
+  // CHECK: apply [[FN:%.*]]({{.*}}) : $@convention(thin) (@in_guaranteed Any) -> ()
+  fn(data: x)
+
+  // CHECK: inject_enum_addr {{.*}} : $*HasAnyCase, #HasAnyCase.any!enumelt.1
+  _ = HasAnyCase.any(123)
+
+  // CHECK: inject_enum_addr {{.*}} : $*HasAnyCase, #HasAnyCase.any!enumelt.1
+  _ = HasAnyCase.any(data: 123)
+
+  // CHECK: return
+}
diff --git a/test/SILGen/plus_zero_array_literal_abstraction.swift b/test/SILGen/plus_zero_array_literal_abstraction.swift
new file mode 100644
index 0000000..d7f1e36
--- /dev/null
+++ b/test/SILGen/plus_zero_array_literal_abstraction.swift
@@ -0,0 +1,25 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -emit-silgen %s | %FileCheck %s
+
+// Verify that reabstraction happens when forming container literals.
+// <rdar://problem/16039286>
+
+// CHECK-LABEL: sil hidden @$S25array_literal_abstraction0A9_of_funcsSayyycGyF
+// CHECK:         pointer_to_address {{.*}} $*@callee_guaranteed (@in_guaranteed ()) -> @out ()
+func array_of_funcs() -> [(() -> ())] {
+  return [{}, {}]
+}
+
+// CHECK-LABEL: sil hidden @$S25array_literal_abstraction13dict_of_funcss10DictionaryVySiyycGyF
+// CHECK:         pointer_to_address {{.*}} $*(Int, @callee_guaranteed (@in_guaranteed ()) -> @out ())
+func dict_of_funcs() -> Dictionary<Int, () -> ()> {
+  return [0: {}, 1: {}]
+}
+
+func vararg_funcs(_ fs: (() -> ())...) {}
+
+// CHECK-LABEL: sil hidden @$S25array_literal_abstraction17call_vararg_funcsyyF
+// CHECK:         pointer_to_address {{.*}} $*@callee_guaranteed (@in_guaranteed ()) -> @out ()
+func call_vararg_funcs() {
+  vararg_funcs({}, {})
+}
diff --git a/test/SILGen/plus_zero_auto_closures.swift b/test/SILGen/plus_zero_auto_closures.swift
new file mode 100644
index 0000000..0adc57e
--- /dev/null
+++ b/test/SILGen/plus_zero_auto_closures.swift
@@ -0,0 +1,73 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -parse-stdlib -emit-silgen -enable-sil-ownership %s | %FileCheck %s
+
+struct Bool {}
+var false_ = Bool()
+
+// CHECK-LABEL: sil hidden @$S13auto_closures05call_A8_closureyAA4BoolVADyXKF : $@convention(thin) (@noescape @callee_guaranteed () -> Bool) -> Bool
+func call_auto_closure(_ x: @autoclosure () -> Bool) -> Bool {
+  // CHECK: bb0([[CLOSURE:%.*]] : @trivial $@noescape @callee_guaranteed () -> Bool):
+  // CHECK: [[RET:%.*]] = apply [[CLOSURE]]()
+  // CHECK: return [[RET]]
+  return x()
+}
+
+// CHECK-LABEL: sil hidden @$S13auto_closures05test_A21_closure_with_capture{{[_0-9a-zA-Z]*}}F
+func test_auto_closure_with_capture(_ x: Bool) -> Bool {
+  // CHECK: [[CLOSURE:%.*]] = function_ref @$S13auto_closures05test_A21_closure_with_capture
+  // CHECK: [[WITHCAPTURE:%.*]] = partial_apply [callee_guaranteed] [[CLOSURE]](
+  // CHECK: [[CVT:%.*]] = convert_escape_to_noescape [[WITHCAPTURE]]
+  // CHECK: [[RET:%.*]] = apply {{%.*}}([[CVT]])
+  // CHECK: return [[RET]]
+  return call_auto_closure(x)
+}
+
+// CHECK-LABEL: sil hidden @$S13auto_closures05test_A24_closure_without_capture{{[_0-9a-zA-Z]*}}F
+func test_auto_closure_without_capture() -> Bool {
+  // CHECK: [[CLOSURE:%.*]] = function_ref @$S13auto_closures05test_A24_closure_without_capture
+  // CHECK: [[CVT:%.*]] = convert_function [[CLOSURE]]
+  // CHECK: [[THICK:%.*]] = thin_to_thick_function [[CVT]] : $@convention(thin) @noescape () -> Bool to $@noescape @callee_guaranteed () -> Bool
+  // CHECK: [[RET:%.*]] = apply {{%.*}}([[THICK]])
+  // CHECK: return [[RET]]
+  return call_auto_closure(false_)
+}
+
+public class Base {
+  var x: Bool { return false_ }
+}
+
+public class Sub : Base {
+  // CHECK-LABEL: sil hidden @$S13auto_closures3SubC1xAA4BoolVvg : $@convention(method) (@guaranteed Sub) -> Bool {
+  // CHECK: bb0([[SELF:%.*]] : @guaranteed $Sub):
+  // CHECK: [[AUTOCLOSURE_FUNC:%.*]] = function_ref @$S13auto_closures3SubC1xAA4BoolVvgAFyXKfu_ : $@convention(thin) (@guaranteed Sub) -> Bool
+  // CHECK: [[SELF_COPY:%.*]] = copy_value [[SELF]]
+  // CHECK: [[AUTOCLOSURE:%.*]] = partial_apply [callee_guaranteed] [[AUTOCLOSURE_FUNC]]([[SELF_COPY]])
+  // CHECK: [[CVT:%.*]] = convert_escape_to_noescape [[AUTOCLOSURE]]
+  // CHECK: [[AUTOCLOSURE_CONSUMER:%.*]] = function_ref @$S13auto_closures05call_A8_closureyAA4BoolVADyXKF : $@convention(thin)
+  // CHECK: [[RET:%.*]] = apply [[AUTOCLOSURE_CONSUMER]]([[CVT]])
+  // CHECK: return [[RET]] : $Bool
+  // CHECK: }
+
+  // CHECK-LABEL: sil private [transparent] @$S13auto_closures3SubC1xAA4BoolVvgAFyXKfu_ : $@convention(thin) (@guaranteed Sub) -> Bool {
+  // CHECK: [[SUPER:%[0-9]+]] = function_ref @$S13auto_closures4BaseC1xAA4BoolVvg : $@convention(method) (@guaranteed Base) -> Bool
+  // CHECK: [[RET:%.*]] = apply [[SUPER]]({{%.*}})
+  // CHECK: return [[RET]]
+  override var x: Bool { return call_auto_closure(super.x) }
+}
+
+// CHECK-LABEL: sil hidden @$S13auto_closures20closureInAutoclosureyAA4BoolVAD_ADtF : $@convention(thin) (Bool, Bool) -> Bool {
+// CHECK: }
+// CHECK-LABEL: sil private [transparent] @$S13auto_closures20closureInAutoclosureyAA4BoolVAD_ADtFADyXKfu_ : $@convention(thin) (Bool, Bool) -> Bool {
+// CHECK: }
+// CHECK-LABEL: sil private @$S13auto_closures20closureInAutoclosureyAA4BoolVAD_ADtFADyXKfu_A2DXEfU_ : $@convention(thin) (Bool, Bool) -> Bool {
+// CHECK: }
+func compareBool(_ lhs: Bool, _ rhs: Bool) -> Bool { return false_ }
+func testBool(_ x: Bool, _ pred: (Bool) -> Bool) -> Bool {
+  return pred(x)
+}
+func delayBool(_ fn: @autoclosure () -> Bool) -> Bool {
+  return fn()
+}
+func closureInAutoclosure(_ lhs: Bool, _ rhs: Bool) -> Bool {
+  return delayBool(testBool(lhs, { compareBool($0, rhs) }))
+}
diff --git a/test/SILGen/plus_zero_borrow.swift b/test/SILGen/plus_zero_borrow.swift
new file mode 100644
index 0000000..5dcec6f
--- /dev/null
+++ b/test/SILGen/plus_zero_borrow.swift
@@ -0,0 +1,36 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -enable-sil-ownership -parse-stdlib -emit-silgen %s | %FileCheck %s
+
+import Swift
+
+final class D {}
+
+// Make sure that we insert the borrow for a ref_element_addr lvalue in the
+// proper place.
+final class C {
+  var d: D = D()
+}
+
+func useD(_ d: D) {}
+
+// CHECK-LABEL: sil hidden @$S6borrow44lvalueBorrowShouldBeAtEndOfFormalAccessScope{{.*}} : $@convention(thin) () -> () {
+// CHECK: bb0:
+// CHECK:   [[BOX:%.*]] = alloc_box ${ var C }, var, name "c"
+// CHECK:   [[PB_BOX:%.*]] = project_box [[BOX]]
+// CHECK:   [[ACCESS:%.*]] = begin_access [read] [unknown] [[PB_BOX]] : $*C
+// CHECK:   [[CLASS:%.*]] = load [copy] [[ACCESS]]
+// CHECK:   [[BORROWED_CLASS:%.*]] = begin_borrow [[CLASS]]
+// CHECK:   [[OFFSET:%.*]] = ref_element_addr [[BORROWED_CLASS]]
+// CHECK:   [[ACCESS:%.*]] = begin_access [read] [dynamic] [[OFFSET]] : $*D
+// CHECK:   [[LOADED_VALUE:%.*]] = load [copy] [[ACCESS]]
+// CHECK:   end_borrow [[BORROWED_CLASS]] from [[CLASS]]
+// CHECK:   destroy_value [[CLASS]]
+// CHECK:   [[BORROWED_LOADED_VALUE:%.*]] = begin_borrow [[LOADED_VALUE]]
+// CHECK:   [[FUNC:%.*]] = function_ref @$S6borrow4useD{{.*}} : $@convention(thin) (@guaranteed D) -> ()
+// CHECK:   apply [[FUNC]]([[BORROWED_LOADED_VALUE]])
+// CHECK:   destroy_value [[BOX]]
+// CHECK: } // end sil function '$S6borrow44lvalueBorrowShouldBeAtEndOfFormalAccessScope{{.*}}'
+func lvalueBorrowShouldBeAtEndOfFormalAccessScope() {
+  var c = C()
+  useD(c.d)
+}
diff --git a/test/SILGen/plus_zero_boxed_existentials.swift b/test/SILGen/plus_zero_boxed_existentials.swift
new file mode 100644
index 0000000..70b4197
--- /dev/null
+++ b/test/SILGen/plus_zero_boxed_existentials.swift
@@ -0,0 +1,217 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -Xllvm -sil-full-demangle -enable-sil-ownership -emit-silgen %s | %FileCheck %s
+// RUN: %target-swift-frontend -Xllvm -sil-full-demangle -enable-sil-ownership -emit-silgen %s | %FileCheck %s --check-prefix=GUARANTEED
+
+func test_type_lowering(_ x: Error) { }
+// CHECK-LABEL: sil hidden @$S18boxed_existentials18test_type_loweringyys5Error_pF : $@convention(thin) (@guaranteed Error) -> () {
+// CHECK-NOT:         destroy_value %0 : $Error
+
+class Document {}
+
+enum ClericalError: Error {
+  case MisplacedDocument(Document)
+
+  var _domain: String { return "" }
+  var _code: Int { return 0 }
+}
+
+func test_concrete_erasure(_ x: ClericalError) -> Error {
+  return x
+}
+// CHECK-LABEL: sil hidden @$S18boxed_existentials21test_concrete_erasureys5Error_pAA08ClericalF0OF
+// CHECK:       bb0([[ARG:%.*]] : @guaranteed $ClericalError):
+// CHECK:         [[EXISTENTIAL:%.*]] = alloc_existential_box $Error, $ClericalError
+// CHECK:         [[ADDR:%.*]] = project_existential_box $ClericalError in [[EXISTENTIAL]] : $Error
+// CHECK:         [[ARG_COPY:%.*]] = copy_value [[ARG]]
+// CHECK:         store [[ARG_COPY]] to [init] [[ADDR]] : $*ClericalError
+// CHECK-NOT:         destroy_value [[ARG]]
+// CHECK:         return [[EXISTENTIAL]] : $Error
+
+protocol HairType {}
+
+func test_composition_erasure(_ x: HairType & Error) -> Error {
+  return x
+}
+// CHECK-LABEL: sil hidden @$S18boxed_existentials24test_composition_erasureys5Error_psAC_AA8HairTypepF
+// CHECK:         [[VALUE_ADDR:%.*]] = open_existential_addr immutable_access [[OLD_EXISTENTIAL:%.*]] : $*Error & HairType to $*[[VALUE_TYPE:@opened\(.*\) Error & HairType]]
+// CHECK:         [[NEW_EXISTENTIAL:%.*]] = alloc_existential_box $Error, $[[VALUE_TYPE]]
+// CHECK:         [[ADDR:%.*]] = project_existential_box $[[VALUE_TYPE]] in [[NEW_EXISTENTIAL]] : $Error
+// CHECK:         copy_addr [[VALUE_ADDR]] to [initialization] [[ADDR]]
+// CHECK-NOT:         destroy_addr [[OLD_EXISTENTIAL]]
+// CHECK:         return [[NEW_EXISTENTIAL]]
+
+protocol HairClass: class {}
+
+func test_class_composition_erasure(_ x: HairClass & Error) -> Error {
+  return x
+}
+// CHECK-LABEL: sil hidden @$S18boxed_existentials30test_class_composition_erasureys5Error_psAC_AA9HairClasspF
+// CHECK:         [[VALUE:%.*]] = open_existential_ref [[OLD_EXISTENTIAL:%.*]] : $Error & HairClass to $[[VALUE_TYPE:@opened\(.*\) Error & HairClass]]
+// CHECK:         [[NEW_EXISTENTIAL:%.*]] = alloc_existential_box $Error, $[[VALUE_TYPE]]
+// CHECK:         [[ADDR:%.*]] = project_existential_box $[[VALUE_TYPE]] in [[NEW_EXISTENTIAL]] : $Error
+// CHECK:         [[COPIED_VALUE:%.*]] = copy_value [[VALUE]]
+// CHECK:         store [[COPIED_VALUE]] to [init] [[ADDR]]
+// CHECK:         return [[NEW_EXISTENTIAL]]
+
+func test_property(_ x: Error) -> String {
+  return x._domain
+}
+// CHECK-LABEL: sil hidden @$S18boxed_existentials13test_propertyySSs5Error_pF
+// CHECK: bb0([[ARG:%.*]] : @guaranteed $Error):
+// CHECK:         [[VALUE:%.*]] = open_existential_box [[ARG]] : $Error to $*[[VALUE_TYPE:@opened\(.*\) Error]]
+// FIXME: Extraneous copy here
+// CHECK-NEXT:    [[COPY:%[0-9]+]] = alloc_stack $[[VALUE_TYPE]]
+// CHECK-NEXT:    copy_addr [[VALUE]] to [initialization] [[COPY]] : $*[[VALUE_TYPE]]
+// CHECK:         [[METHOD:%.*]] = witness_method $[[VALUE_TYPE]], #Error._domain!getter.1
+// -- self parameter of witness is @in_guaranteed; no need to copy since
+//    value in box is immutable and box is guaranteed
+// CHECK:         [[RESULT:%.*]] = apply [[METHOD]]<[[VALUE_TYPE]]>([[COPY]])
+// CHECK-NOT:         destroy_value [[ARG]]
+// CHECK:         return [[RESULT]]
+
+func test_property_of_lvalue(_ x: Error) -> String {
+  var x = x
+  return x._domain
+}
+
+// CHECK-LABEL: sil hidden @$S18boxed_existentials23test_property_of_lvalueySSs5Error_pF :
+// CHECK:       bb0([[ARG:%.*]] : @guaranteed $Error):
+// CHECK:         [[VAR:%.*]] = alloc_box ${ var Error }
+// CHECK:         [[PVAR:%.*]] = project_box [[VAR]]
+// CHECK:         [[ARG_COPY:%.*]] = copy_value [[ARG]] : $Error
+// CHECK:         store [[ARG_COPY]] to [init] [[PVAR]]
+// CHECK:         [[ACCESS:%.*]] = begin_access [read] [unknown] [[PVAR]] : $*Error
+// CHECK:         [[VALUE_BOX:%.*]] = load [copy] [[ACCESS]]
+// CHECK:         [[VALUE:%.*]] = open_existential_box [[VALUE_BOX]] : $Error to $*[[VALUE_TYPE:@opened\(.*\) Error]]
+// CHECK:         [[COPY:%.*]] = alloc_stack $[[VALUE_TYPE]]
+// CHECK:         copy_addr [[VALUE]] to [initialization] [[COPY]]
+// CHECK:         [[METHOD:%.*]] = witness_method $[[VALUE_TYPE]], #Error._domain!getter.1
+// CHECK:         [[RESULT:%.*]] = apply [[METHOD]]<[[VALUE_TYPE]]>([[COPY]])
+// CHECK:         destroy_addr [[COPY]]
+// CHECK:         dealloc_stack [[COPY]]
+// CHECK:         destroy_value [[VALUE_BOX]]
+// CHECK:         destroy_value [[VAR]]
+// CHECK-NOT:         destroy_value [[ARG]]
+// CHECK:         return [[RESULT]]
+// CHECK:      } // end sil function '$S18boxed_existentials23test_property_of_lvalueySSs5Error_pF'
+extension Error {
+  func extensionMethod() { }
+}
+
+// CHECK-LABEL: sil hidden @$S18boxed_existentials21test_extension_methodyys5Error_pF
+func test_extension_method(_ error: Error) {
+  // CHECK: bb0([[ARG:%.*]] : @guaranteed $Error):
+  // CHECK: [[VALUE:%.*]] = open_existential_box [[ARG]]
+  // CHECK: [[METHOD:%.*]] = function_ref
+  // CHECK-NOT: copy_addr
+  // CHECK: apply [[METHOD]]<{{.*}}>([[VALUE]])
+  // CHECK-NOT: destroy_addr [[COPY]]
+  // CHECK-NOT: destroy_addr [[VALUE]]
+  // CHECK-NOT: destroy_addr [[VALUE]]
+  // -- destroy_value the owned argument
+  // CHECK-NOT: destroy_value %0
+  error.extensionMethod()
+}
+
+func plusOneError() -> Error { }
+
+// CHECK-LABEL: sil hidden @$S18boxed_existentials31test_open_existential_semanticsyys5Error_p_sAC_ptF
+// GUARANTEED-LABEL: sil hidden @$S18boxed_existentials31test_open_existential_semanticsyys5Error_p_sAC_ptF
+// CHECK: bb0([[ARG0:%.*]]: @guaranteed $Error,
+// GUARANTEED: bb0([[ARG0:%.*]]: @guaranteed $Error,
+func test_open_existential_semantics(_ guaranteed: Error,
+                                     _ immediate: Error) {
+  var immediate = immediate
+  // CHECK: [[IMMEDIATE_BOX:%.*]] = alloc_box ${ var Error }
+  // CHECK: [[PB:%.*]] = project_box [[IMMEDIATE_BOX]]
+  // GUARANTEED: [[IMMEDIATE_BOX:%.*]] = alloc_box ${ var Error }
+  // GUARANTEED: [[PB:%.*]] = project_box [[IMMEDIATE_BOX]]
+
+  // CHECK-NOT: copy_value [[ARG0]]
+  // CHECK: [[VALUE:%.*]] = open_existential_box [[ARG0]]
+  // CHECK: [[METHOD:%.*]] = function_ref
+  // CHECK-NOT: copy_addr
+  // CHECK: apply [[METHOD]]<{{.*}}>([[VALUE]])
+  // CHECK-NOT: destroy_value [[ARG0]]
+
+  // GUARANTEED-NOT: copy_value [[ARG0]]
+  // GUARANTEED: [[VALUE:%.*]] = open_existential_box [[ARG0]]
+  // GUARANTEED: [[METHOD:%.*]] = function_ref
+  // GUARANTEED: apply [[METHOD]]<{{.*}}>([[VALUE]])
+  // GUARANTEED-NOT: destroy_addr [[VALUE]]
+  // GUARANTEED-NOT: destroy_value [[ARG0]]
+  guaranteed.extensionMethod()
+
+  // CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] [[PB]] : $*Error
+  // CHECK: [[IMMEDIATE:%.*]] = load [copy] [[ACCESS]]
+  // -- need a copy_value to guarantee
+  // CHECK: [[VALUE:%.*]] = open_existential_box [[IMMEDIATE]]
+  // CHECK: [[METHOD:%.*]] = function_ref
+  // CHECK-NOT: copy_addr
+  // CHECK: apply [[METHOD]]<{{.*}}>([[VALUE]])
+  // -- end the guarantee
+  // -- TODO: could in theory do this sooner, after the value's been copied
+  //    out.
+  // CHECK: destroy_value [[IMMEDIATE]]
+
+  // GUARANTEED: [[ACCESS:%.*]] = begin_access [read] [unknown] [[PB]] : $*Error
+  // GUARANTEED: [[IMMEDIATE:%.*]] = load [copy] [[ACCESS]]
+  // -- need a copy_value to guarantee
+  // GUARANTEED: [[VALUE:%.*]] = open_existential_box [[IMMEDIATE]]
+  // GUARANTEED: [[METHOD:%.*]] = function_ref
+  // GUARANTEED: apply [[METHOD]]<{{.*}}>([[VALUE]])
+  // GUARANTEED-NOT: destroy_addr [[VALUE]]
+  // -- end the guarantee
+  // GUARANTEED: destroy_value [[IMMEDIATE]]
+  immediate.extensionMethod()
+
+  // CHECK: [[F:%.*]] = function_ref {{.*}}plusOneError
+  // CHECK: [[PLUS_ONE:%.*]] = apply [[F]]()
+  // CHECK: [[VALUE:%.*]] = open_existential_box [[PLUS_ONE]]
+  // CHECK: [[METHOD:%.*]] = function_ref
+  // CHECK-NOT: copy_addr
+  // CHECK: apply [[METHOD]]<{{.*}}>([[VALUE]])
+  // CHECK: destroy_value [[PLUS_ONE]]
+
+  // GUARANTEED: [[F:%.*]] = function_ref {{.*}}plusOneError
+  // GUARANTEED: [[PLUS_ONE:%.*]] = apply [[F]]()
+  // GUARANTEED: [[VALUE:%.*]] = open_existential_box [[PLUS_ONE]]
+  // GUARANTEED: [[METHOD:%.*]] = function_ref
+  // GUARANTEED: apply [[METHOD]]<{{.*}}>([[VALUE]])
+  // GUARANTEED-NOT: destroy_addr [[VALUE]]
+  // GUARANTEED: destroy_value [[PLUS_ONE]]
+  plusOneError().extensionMethod()
+}
+
+// CHECK-LABEL: sil hidden @$S18boxed_existentials14erasure_to_anyyyps5Error_p_sAC_ptF
+// CHECK:       bb0([[OUT:%.*]] : @trivial $*Any, [[GUAR:%.*]] : @guaranteed $Error,
+func erasure_to_any(_ guaranteed: Error, _ immediate: Error) -> Any {
+  var immediate = immediate
+  // CHECK:       [[IMMEDIATE_BOX:%.*]] = alloc_box ${ var Error }
+  // CHECK:       [[PB:%.*]] = project_box [[IMMEDIATE_BOX]]
+  if true {
+    // CHECK-NOT: copy_value [[GUAR]]
+    // CHECK:     [[FROM_VALUE:%.*]] = open_existential_box [[GUAR:%.*]]
+    // CHECK:     [[TO_VALUE:%.*]] = init_existential_addr [[OUT]]
+    // CHECK:     copy_addr [[FROM_VALUE]] to [initialization] [[TO_VALUE]]
+    // CHECK-NOT: destroy_value [[GUAR]]
+    return guaranteed
+  } else if true {
+    // CHECK:     [[ACCESS:%.*]] = begin_access [read] [unknown] [[PB]]
+    // CHECK:     [[IMMEDIATE:%.*]] = load [copy] [[ACCESS]]
+    // CHECK:     [[FROM_VALUE:%.*]] = open_existential_box [[IMMEDIATE]]
+    // CHECK:     [[TO_VALUE:%.*]] = init_existential_addr [[OUT]]
+    // CHECK:     copy_addr [[FROM_VALUE]] to [initialization] [[TO_VALUE]]
+    // CHECK:     destroy_value [[IMMEDIATE]]
+    return immediate
+  } else if true {
+    // CHECK:     function_ref boxed_existentials.plusOneError
+    // CHECK:     [[PLUS_ONE:%.*]] = apply
+    // CHECK:     [[FROM_VALUE:%.*]] = open_existential_box [[PLUS_ONE]]
+    // CHECK:     [[TO_VALUE:%.*]] = init_existential_addr [[OUT]]
+    // CHECK:     copy_addr [[FROM_VALUE]] to [initialization] [[TO_VALUE]]
+    // CHECK:     destroy_value [[PLUS_ONE]]
+
+    return plusOneError()
+  }
+}
diff --git a/test/SILGen/plus_zero_call_chain_reabstraction.swift b/test/SILGen/plus_zero_call_chain_reabstraction.swift
new file mode 100644
index 0000000..123c453
--- /dev/null
+++ b/test/SILGen/plus_zero_call_chain_reabstraction.swift
@@ -0,0 +1,20 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership %s | %FileCheck %s
+
+struct A {
+        func g<U>(_ recur: (A, U) -> U) -> (A, U) -> U {
+                return { _, x in return x }
+        }
+        // CHECK-LABEL: sil hidden @$S24call_chain_reabstraction1AV1f{{[_0-9a-zA-Z]*}}F
+        // CHECK:         [[G:%.*]] = function_ref @$S24call_chain_reabstraction1AV1g{{[_0-9a-zA-Z]*}}F
+        // CHECK:         [[G2:%.*]] = apply [[G]]<A>
+        // CHECK:         [[REABSTRACT_THUNK:%.*]] = function_ref @$S24call_chain_reabstraction1AVA2CIegynr_A3CIegyyd_TR
+        // CHECK:         [[REABSTRACT:%.*]] = partial_apply [callee_guaranteed] [[REABSTRACT_THUNK]]([[G2]])
+        // CHECK:         [[BORROW:%.*]] = begin_borrow [[REABSTRACT]]
+        // CHECK:         apply [[BORROW]]([[SELF:%.*]], [[SELF]])
+        // CHECK:         destroy_value [[REABSTRACT]]
+        func f() {
+                let recur: (A, A) -> A = { c, x in x }
+                let b = g(recur)(self, self)
+        }
+}
diff --git a/test/SILGen/plus_zero_capture_typed_boxes.swift b/test/SILGen/plus_zero_capture_typed_boxes.swift
new file mode 100644
index 0000000..c33dad1
--- /dev/null
+++ b/test/SILGen/plus_zero_capture_typed_boxes.swift
@@ -0,0 +1,32 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership %s | %FileCheck %s
+
+func foo(_ x: Int) -> () -> Int {
+  var x = x
+  return { x }
+}
+// CHECK-LABEL: sil private @$S19capture_typed_boxes3fooySiycSiFSiycfU_ : $@convention(thin) (@guaranteed { var Int }) -> Int {
+// CHECK:       bb0(%0 : @guaranteed ${ var Int }):
+
+func closure(_ f: @escaping (Int) -> Int) -> Int {
+  var f = f
+  func bar(_ x: Int) -> Int {
+    return f(x)
+  }
+
+  return bar(0)
+}
+// CHECK-LABEL: sil private @$S19capture_typed_boxes7closureyS3icF3barL_yS2iF : $@convention(thin) (Int, @guaranteed { var @callee_guaranteed (Int) -> Int }) -> Int {
+// CHECK:       bb0(%0 : @trivial $Int, %1 : @guaranteed ${ var @callee_guaranteed (Int) -> Int }):
+
+func closure_generic<T>(_ f: @escaping (T) -> T, x: T) -> T {
+  var f = f
+  func bar(_ x: T) -> T {
+    return f(x)
+  }
+
+  return bar(x)
+}
+// CHECK-LABEL: sil private @$S19capture_typed_boxes15closure_generic{{.*}} : $@convention(thin) <T> (@in_guaranteed T, @guaranteed <τ_0_0> { var @callee_guaranteed (@in_guaranteed τ_0_0) -> @out τ_0_0 } <T>) -> @out T {
+// CHECK-LABEL: bb0(%0 : @trivial $*T, %1 : @trivial $*T, %2 : @guaranteed $<τ_0_0> { var @callee_guaranteed (@in_guaranteed τ_0_0) -> @out τ_0_0 } <T>):
+
diff --git a/test/SILGen/plus_zero_casts.swift b/test/SILGen/plus_zero_casts.swift
new file mode 100644
index 0000000..6944bbd
--- /dev/null
+++ b/test/SILGen/plus_zero_casts.swift
@@ -0,0 +1,103 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership %s | %FileCheck %s
+
+class B { }
+class D : B { }
+
+// CHECK-LABEL: sil hidden @$S5casts6upcast{{[_0-9a-zA-Z]*}}F
+func upcast(d: D) -> B {
+  // CHECK: {{%.*}} = upcast
+  return d
+}
+// CHECK-LABEL: sil hidden @$S5casts8downcast{{[_0-9a-zA-Z]*}}F
+func downcast(b: B) -> D {
+  // CHECK: {{%.*}} = unconditional_checked_cast
+  return b as! D
+}
+
+// CHECK-LABEL: sil hidden @$S5casts3isa{{[_0-9a-zA-Z]*}}F
+func isa(b: B) -> Bool {
+  // CHECK: bb0([[ARG:%.*]] : @guaranteed $B):
+  // CHECK:   [[COPIED_BORROWED_ARG:%.*]] = copy_value [[ARG]]
+  // CHECK:   checked_cast_br [[COPIED_BORROWED_ARG]] : $B to $D, [[YES:bb[0-9]+]], [[NO:bb[0-9]+]]
+  //
+  // CHECK: [[YES]]([[CASTED_VALUE:%.*]] : @owned $D):
+  // CHECK:   integer_literal {{.*}} -1
+  // CHECK:   destroy_value [[CASTED_VALUE]]
+  //
+  // CHECK: [[NO]]([[ORIGINAL_VALUE:%.*]] : @owned $B):
+  // CHECK:   destroy_value [[ORIGINAL_VALUE]]
+  // CHECK:   integer_literal {{.*}} 0
+  return b is D
+}
+
+// CHECK-LABEL: sil hidden @$S5casts16upcast_archetype{{[_0-9a-zA-Z]*}}F
+func upcast_archetype<T : B>(t: T) -> B {
+  // CHECK: {{%.*}} = upcast
+  return t
+}
+
+// CHECK-LABEL: sil hidden @$S5casts25upcast_archetype_metatype{{[_0-9a-zA-Z]*}}F
+func upcast_archetype_metatype<T : B>(t: T.Type) -> B.Type {
+  // CHECK: {{%.*}} = upcast
+  return t
+}
+
+// CHECK-LABEL: sil hidden @$S5casts18downcast_archetype{{[_0-9a-zA-Z]*}}F
+func downcast_archetype<T : B>(b: B) -> T {
+  // CHECK: {{%.*}} = unconditional_checked_cast
+  return b as! T
+}
+
+// This is making sure that we do not have the default propagating behavior in
+// the address case.
+//
+// CHECK-LABEL: sil hidden @$S5casts12is_archetype{{[_0-9a-zA-Z]*}}F
+func is_archetype<T : B>(b: B, _: T) -> Bool {
+  // CHECK: bb0([[ARG1:%.*]] : @guaranteed $B, [[ARG2:%.*]] : @guaranteed $T):
+  // CHECK:   checked_cast_br {{%.*}}, [[YES:bb[0-9]+]], [[NO:bb[0-9]+]]
+  // CHECK: [[YES]]([[CASTED_ARG:%.*]] : @owned $T):
+  // CHECK:   integer_literal {{.*}} -1
+  // CHECK:   destroy_value [[CASTED_ARG]]
+  // CHECK: [[NO]]([[ORIGINAL_VALUE:%.*]] : @owned $B):
+  // CHCEK:   destroy_value [[CASTED_ARG]]
+  // CHECK:   integer_literal {{.*}} 0
+  return b is T
+}
+// CHECK: } // end sil function '$S5casts12is_archetype{{[_0-9a-zA-Z]*}}F'
+
+// CHECK: sil hidden @$S5casts20downcast_conditional{{[_0-9a-zA-Z]*}}F
+// CHECK:   checked_cast_br {{%.*}} : $B to $D
+// CHECK:   bb{{[0-9]+}}({{.*}} : $Optional<D>)
+func downcast_conditional(b: B) -> D? {
+  return b as? D
+}
+
+protocol P {}
+struct S : P {}
+
+// CHECK: sil hidden @$S5casts32downcast_existential_conditional{{[_0-9a-zA-Z]*}}F
+// CHECK: bb0([[IN:%.*]] : @trivial $*P):
+// CHECK:   [[COPY:%.*]] = alloc_stack $P
+// CHECK:   copy_addr [[IN]] to [initialization] [[COPY]]
+// CHECK:   [[TMP:%.*]] = alloc_stack $S
+// CHECK:   checked_cast_addr_br take_always P in [[COPY]] : $*P to S in [[TMP]] : $*S, bb1, bb2
+//   Success block.
+// CHECK: bb1:
+// CHECK:   [[T0:%.*]] = load [trivial] [[TMP]] : $*S
+// CHECK:   [[T1:%.*]] = enum $Optional<S>, #Optional.some!enumelt.1, [[T0]] : $S
+// CHECK:   dealloc_stack [[TMP]]
+// CHECK:   br bb3([[T1]] : $Optional<S>)
+//   Failure block.
+// CHECK: bb2:
+// CHECK:   [[T0:%.*]] = enum $Optional<S>, #Optional.none!enumelt
+// CHECK:   dealloc_stack [[TMP]]
+// CHECK:   br bb3([[T0]] : $Optional<S>)
+//   Continuation block.
+// CHECK: bb3([[RESULT:%.*]] : @trivial $Optional<S>):
+// CHECK:   dealloc_stack [[COPY]]
+// CHECK:   return [[RESULT]]
+func downcast_existential_conditional(p: P) -> S? {
+  return p as? S
+}
+
diff --git a/test/SILGen/plus_zero_cf.swift b/test/SILGen/plus_zero_cf.swift
new file mode 100644
index 0000000..ac4e227
--- /dev/null
+++ b/test/SILGen/plus_zero_cf.swift
@@ -0,0 +1,83 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -import-cf-types -sdk %S/Inputs %s -emit-silgen -o - | %FileCheck %s
+
+// REQUIRES: objc_interop
+
+import CoreCooling
+
+// CHECK: sil hidden @$S2cf8useEmAllyySo16CCMagnetismModelCF :
+// CHECK: bb0([[ARG:%.*]] : $CCMagnetismModel):
+func useEmAll(_ model: CCMagnetismModel) {
+// CHECK: function_ref @CCPowerSupplyGetDefault : $@convention(c) () -> @autoreleased Optional<CCPowerSupply>
+  let power = CCPowerSupplyGetDefault()
+
+// CHECK: function_ref @CCRefrigeratorCreate : $@convention(c) (Optional<CCPowerSupply>) -> Optional<Unmanaged<CCRefrigerator>>
+  let unmanagedFridge = CCRefrigeratorCreate(power)
+
+// CHECK: function_ref @CCRefrigeratorSpawn : $@convention(c) (Optional<CCPowerSupply>) -> @owned Optional<CCRefrigerator>
+  let managedFridge = CCRefrigeratorSpawn(power)
+
+// CHECK: function_ref @CCRefrigeratorOpen : $@convention(c) (Optional<CCRefrigerator>) -> ()
+  CCRefrigeratorOpen(managedFridge)
+
+// CHECK: function_ref @CCRefrigeratorCopy : $@convention(c) (Optional<CCRefrigerator>) -> @owned Optional<CCRefrigerator>
+  let copy = CCRefrigeratorCopy(managedFridge)
+
+// CHECK: function_ref @CCRefrigeratorClone : $@convention(c) (Optional<CCRefrigerator>) -> @autoreleased Optional<CCRefrigerator>
+  let clone = CCRefrigeratorClone(managedFridge)
+
+// CHECK: function_ref @CCRefrigeratorDestroy : $@convention(c) (@owned Optional<CCRefrigerator>) -> ()
+  CCRefrigeratorDestroy(clone)
+
+// CHECK: objc_method [[ARG]] : $CCMagnetismModel, #CCMagnetismModel.refrigerator!1.foreign : (CCMagnetismModel) -> () -> Unmanaged<CCRefrigerator>?, $@convention(objc_method) (CCMagnetismModel) -> Optional<Unmanaged<CCRefrigerator>>
+  let f0 = model.refrigerator()
+
+// CHECK: objc_method [[ARG]] : $CCMagnetismModel, #CCMagnetismModel.getRefrigerator!1.foreign : (CCMagnetismModel) -> () -> CCRefrigerator?, $@convention(objc_method) (CCMagnetismModel) -> @autoreleased Optional<CCRefrigerator>
+  let f1 = model.getRefrigerator()
+
+// CHECK: objc_method [[ARG]] : $CCMagnetismModel, #CCMagnetismModel.takeRefrigerator!1.foreign : (CCMagnetismModel) -> () -> CCRefrigerator?, $@convention(objc_method) (CCMagnetismModel) -> @owned Optional<CCRefrigerator>
+  let f2 = model.takeRefrigerator()
+
+// CHECK: objc_method [[ARG]] : $CCMagnetismModel, #CCMagnetismModel.borrowRefrigerator!1.foreign : (CCMagnetismModel) -> () -> CCRefrigerator?, $@convention(objc_method) (CCMagnetismModel) -> @autoreleased Optional<CCRefrigerator>
+  let f3 = model.borrowRefrigerator()
+
+// CHECK: objc_method [[ARG]] : $CCMagnetismModel, #CCMagnetismModel.setRefrigerator!1.foreign : (CCMagnetismModel) -> (CCRefrigerator?) -> (), $@convention(objc_method) (Optional<CCRefrigerator>, CCMagnetismModel) -> ()
+  model.setRefrigerator(copy)
+
+// CHECK: objc_method [[ARG]] : $CCMagnetismModel, #CCMagnetismModel.giveRefrigerator!1.foreign : (CCMagnetismModel) -> (CCRefrigerator?) -> (), $@convention(objc_method) (@owned Optional<CCRefrigerator>, CCMagnetismModel) -> ()
+  model.giveRefrigerator(copy)
+
+  // rdar://16846555
+  let prop: CCRefrigerator = model.fridgeProp
+}
+
+// Ensure that accessors are emitted for fields used as protocol witnesses.
+protocol Impedance {
+  associatedtype Component
+  var real: Component { get }
+  var imag: Component { get }
+}
+
+extension CCImpedance: Impedance {}
+
+// CHECK-LABEL: sil private [transparent] [thunk] @$SSo11CCImpedanceV2cf9ImpedanceA2cDP4real9ComponentQzvgTW
+// CHECK-LABEL: sil shared [transparent] [serializable] @$SSo11CCImpedanceV4realSdvg
+// CHECK-LABEL: sil private [transparent] [thunk] @$SSo11CCImpedanceV2cf9ImpedanceA2cDP4imag9ComponentQzvgTW
+// CHECK-LABEL: sil shared [transparent] [serializable] @$SSo11CCImpedanceV4imagSdvg
+
+class MyMagnetism : CCMagnetismModel {
+  // CHECK-LABEL: sil hidden [thunk] @$S2cf11MyMagnetismC15getRefrigerator{{[_0-9a-zA-Z]*}}FTo : $@convention(objc_method) (MyMagnetism) -> @autoreleased CCRefrigerator
+  override func getRefrigerator() -> CCRefrigerator {
+    return super.getRefrigerator()
+  }
+
+  // CHECK-LABEL: sil hidden [thunk] @$S2cf11MyMagnetismC16takeRefrigerator{{[_0-9a-zA-Z]*}}FTo : $@convention(objc_method) (MyMagnetism) -> @owned CCRefrigerator
+  override func takeRefrigerator() -> CCRefrigerator {
+    return super.takeRefrigerator()
+  }
+
+  // CHECK-LABEL: sil hidden [thunk] @$S2cf11MyMagnetismC18borrowRefrigerator{{[_0-9a-zA-Z]*}}FTo : $@convention(objc_method) (MyMagnetism) -> @autoreleased CCRefrigerator
+  override func borrowRefrigerator() -> CCRefrigerator {
+    return super.borrowRefrigerator()
+  }
+}
diff --git a/test/SILGen/plus_zero_class_bound_protocols.swift b/test/SILGen/plus_zero_class_bound_protocols.swift
new file mode 100644
index 0000000..a6b66b8
--- /dev/null
+++ b/test/SILGen/plus_zero_class_bound_protocols.swift
@@ -0,0 +1,219 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -parse-stdlib -parse-as-library -module-name Swift -emit-silgen %s | %FileCheck %s
+
+enum Optional<T> {
+  case some(T)
+  case none
+}
+
+precedencegroup AssignmentPrecedence {}
+
+typealias AnyObject = Builtin.AnyObject
+
+// -- Class-bound archetypes and existentials are *not* address-only and can
+//    be manipulated using normal reference type value semantics.
+
+protocol NotClassBound {
+  func notClassBoundMethod()
+}
+protocol ClassBound : class {
+  func classBoundMethod()
+}
+
+protocol ClassBound2 : class {
+  func classBound2Method()
+}
+
+class ConcreteClass : NotClassBound, ClassBound, ClassBound2 {
+  func notClassBoundMethod() {}
+  func classBoundMethod() {}
+  func classBound2Method() {}
+}
+
+class ConcreteSubclass : ConcreteClass { }
+
+// CHECK-LABEL: sil hidden @$Ss19class_bound_generic{{[_0-9a-zA-Z]*}}F
+func class_bound_generic<T : ClassBound>(x: T) -> T {
+  var x = x
+  // CHECK: bb0([[X:%.*]] : $T):
+  // CHECK:   [[X_ADDR:%.*]] = alloc_box $<τ_0_0 where τ_0_0 : ClassBound> { var τ_0_0 } <T>
+  // CHECK:   [[PB:%.*]] = project_box [[X_ADDR]]
+  // CHECK:   [[X_COPY:%.*]] = copy_value [[X]]
+  // CHECK:   store [[X_COPY]] to [init] [[PB]]
+  return x
+  // CHECK:   [[READ:%.*]] = begin_access [read] [unknown] [[PB]] : $*T
+  // CHECK:   [[X1:%.*]] = load [copy] [[READ]]
+  // CHECK:   destroy_value [[X_ADDR]]
+  // CHECK:   return [[X1]]
+}
+
+// CHECK-LABEL: sil hidden @$Ss21class_bound_generic_2{{[_0-9a-zA-Z]*}}F
+func class_bound_generic_2<T : ClassBound & NotClassBound>(x: T) -> T {
+  var x = x
+  // CHECK: bb0([[X:%.*]] : $T):
+  // CHECK:   [[X_ADDR:%.*]] = alloc_box $<τ_0_0 where τ_0_0 : ClassBound, τ_0_0 : NotClassBound> { var τ_0_0 } <T>
+  // CHECK:   [[PB:%.*]] = project_box [[X_ADDR]]
+  // CHECK:   [[X_COPY:%.*]] = copy_value [[X]]
+  // CHECK:   store [[X_COPY]] to [init] [[PB]]
+  return x
+  // CHECK:   [[READ:%.*]] = begin_access [read] [unknown] [[PB]] : $*T
+  // CHECK:   [[X1:%.*]] = load [copy] [[READ]]
+  // CHECK:   return [[X1]]
+}
+
+// CHECK-LABEL: sil hidden @$Ss20class_bound_protocol{{[_0-9a-zA-Z]*}}F
+func class_bound_protocol(x: ClassBound) -> ClassBound {
+  var x = x
+  // CHECK: bb0([[X:%.*]] : $ClassBound):
+  // CHECK:   [[X_ADDR:%.*]] = alloc_box ${ var ClassBound }
+  // CHECK:   [[PB:%.*]] = project_box [[X_ADDR]]
+  // CHECK:   [[X_COPY:%.*]] = copy_value [[X]]
+  // CHECK:   store [[X_COPY]] to [init] [[PB]]
+  return x
+  // CHECK:   [[READ:%.*]] = begin_access [read] [unknown] [[PB]] : $*ClassBound
+  // CHECK:   [[X1:%.*]] = load [copy] [[READ]]
+  // CHECK:   return [[X1]]
+}
+
+// CHECK-LABEL: sil hidden @$Ss32class_bound_protocol_composition{{[_0-9a-zA-Z]*}}F
+func class_bound_protocol_composition(x: ClassBound & NotClassBound)
+-> ClassBound & NotClassBound {
+  var x = x
+  // CHECK: bb0([[X:%.*]] : $ClassBound & NotClassBound):
+  // CHECK:   [[X_ADDR:%.*]] = alloc_box ${ var ClassBound & NotClassBound }
+  // CHECK:   [[PB:%.*]] = project_box [[X_ADDR]]
+  // CHECK:   [[X_COPY:%.*]] = copy_value [[X]]
+  // CHECK:   store [[X_COPY]] to [init] [[PB]]
+  return x
+  // CHECK:   [[READ:%.*]] = begin_access [read] [unknown] [[PB]] : $*ClassBound & NotClassBound
+  // CHECK:   [[X1:%.*]] = load [copy] [[READ]]
+  // CHECK:   return [[X1]]
+}
+
+// CHECK-LABEL: sil hidden @$Ss19class_bound_erasure{{[_0-9a-zA-Z]*}}F
+func class_bound_erasure(x: ConcreteClass) -> ClassBound {
+  return x
+  // CHECK: [[PROTO:%.*]] = init_existential_ref {{%.*}} : $ConcreteClass, $ClassBound
+  // CHECK: return [[PROTO]]
+}
+
+// CHECK-LABEL: sil hidden @$Ss30class_bound_existential_upcast1xs10ClassBound_psAC_s0E6Bound2p_tF :
+func class_bound_existential_upcast(x: ClassBound & ClassBound2)
+-> ClassBound {
+  return x
+  // CHECK: bb0([[ARG:%.*]] : $ClassBound & ClassBound2):
+  // CHECK:   [[OPENED:%.*]] = open_existential_ref [[ARG]] : $ClassBound & ClassBound2 to [[OPENED_TYPE:\$@opened(.*) ClassBound & ClassBound2]]
+  // CHECK:   [[OPENED_COPY:%.*]] = copy_value [[OPENED]]
+  // CHECK:   [[PROTO:%.*]] = init_existential_ref [[OPENED_COPY]] : [[OPENED_TYPE]] : [[OPENED_TYPE]], $ClassBound
+  // CHECK:   return [[PROTO]]
+}
+// CHECK: } // end sil function '$Ss30class_bound_existential_upcast1xs10ClassBound_psAC_s0E6Bound2p_tF'
+
+// CHECK-LABEL: sil hidden @$Ss41class_bound_to_unbound_existential_upcast1xs13NotClassBound_ps0hI0_sACp_tF :
+// CHECK: bb0([[ARG0:%.*]] : $*NotClassBound, [[ARG1:%.*]] : $ClassBound & NotClassBound):
+// CHECK:   [[X_OPENED:%.*]] = open_existential_ref [[ARG1]] : $ClassBound & NotClassBound to [[OPENED_TYPE:\$@opened(.*) ClassBound & NotClassBound]]
+// CHECK:   [[PAYLOAD_ADDR:%.*]] = init_existential_addr [[ARG0]] : $*NotClassBound, [[OPENED_TYPE]]
+// CHECK:   [[X_OPENED_COPY:%.*]] = copy_value [[X_OPENED]]
+// CHECK:   store [[X_OPENED_COPY]] to [init] [[PAYLOAD_ADDR]]
+func class_bound_to_unbound_existential_upcast
+(x: ClassBound & NotClassBound) -> NotClassBound {
+  return x
+}
+
+// CHECK-LABEL: sil hidden @$Ss18class_bound_method1xys10ClassBound_p_tF :
+// CHECK: bb0([[ARG:%.*]] : $ClassBound):
+func class_bound_method(x: ClassBound) {
+  var x = x
+  x.classBoundMethod()
+  // CHECK: [[XBOX:%.*]] = alloc_box ${ var ClassBound }, var, name "x"
+  // CHECK: [[XBOX_PB:%.*]] = project_box [[XBOX]]
+  // CHECK: [[ARG_COPY:%.*]] = copy_value [[ARG]]
+  // CHECK: store [[ARG_COPY]] to [init] [[XBOX_PB]]
+  // CHECK: [[READ:%.*]] = begin_access [read] [unknown] [[XBOX_PB]] : $*ClassBound
+  // CHECK: [[X:%.*]] = load [copy] [[READ]] : $*ClassBound
+  // CHECK: [[PROJ:%.*]] = open_existential_ref [[X]] : $ClassBound to $[[OPENED:@opened(.*) ClassBound]]
+  // CHECK: [[METHOD:%.*]] = witness_method $[[OPENED]], #ClassBound.classBoundMethod!1
+  // CHECK: apply [[METHOD]]<[[OPENED]]>([[PROJ]])
+  // CHECK: destroy_value [[PROJ]]
+  // CHECK: destroy_value [[XBOX]]
+}
+// CHECK: } // end sil function '$Ss18class_bound_method1xys10ClassBound_p_tF'
+
+// rdar://problem/31858378
+struct Value {}
+
+protocol HasMutatingMethod {
+  mutating func mutateMe()
+  var mutatingCounter: Value { get set }
+  var nonMutatingCounter: Value { get nonmutating set }
+}
+
+protocol InheritsMutatingMethod : class, HasMutatingMethod {}
+
+func takesInOut<T>(_: inout T) {}
+
+// CHECK-LABEL: sil hidden @$Ss27takesInheritsMutatingMethod1x1yys0bcD0_pz_s5ValueVtF : $@convention(thin) (@inout InheritsMutatingMethod, Value) -> () {
+func takesInheritsMutatingMethod(x: inout InheritsMutatingMethod,
+                                 y: Value) {
+  // CHECK:      [[X_ADDR:%.*]] = begin_access [modify] [unknown] %0 : $*InheritsMutatingMethod
+  // CHECK-NEXT: [[X_VALUE:%.*]] = load [copy] [[X_ADDR]] : $*InheritsMutatingMethod
+  // CHECK-NEXT: [[X_PAYLOAD:%.*]] = open_existential_ref [[X_VALUE]] : $InheritsMutatingMethod to $@opened("{{.*}}") InheritsMutatingMethod
+  // CHECK-NEXT: [[TEMPORARY:%.*]] = alloc_stack $@opened("{{.*}}") InheritsMutatingMethod
+  // CHECK-NEXT: store [[X_PAYLOAD]] to [init] [[TEMPORARY]] : $*@opened("{{.*}}") InheritsMutatingMethod
+  // CHECK-NEXT: [[METHOD:%.*]] = witness_method $@opened("{{.*}}") InheritsMutatingMethod, #HasMutatingMethod.mutateMe!1 : <Self where Self : HasMutatingMethod> (inout Self) -> () -> (), [[X_PAYLOAD]] : $@opened("{{.*}}") InheritsMutatingMethod : $@convention(witness_method: HasMutatingMethod) <τ_0_0 where τ_0_0 : HasMutatingMethod> (@inout τ_0_0) -> ()
+  // CHECK-NEXT: apply [[METHOD]]<@opened("{{.*}}") InheritsMutatingMethod>([[TEMPORARY]]) : $@convention(witness_method: HasMutatingMethod) <τ_0_0 where τ_0_0 : HasMutatingMethod> (@inout τ_0_0) -> ()
+  // CHECK-NEXT: [[X_PAYLOAD:%.*]] = load [take] [[TEMPORARY]] : $*@opened("{{.*}}") InheritsMutatingMethod
+  // CHECK-NEXT: [[X_VALUE:%.*]] = init_existential_ref [[X_PAYLOAD]] : $@opened("{{.*}}") InheritsMutatingMethod : $@opened("{{.*}}") InheritsMutatingMethod, $InheritsMutatingMethod
+  // CHECK-NEXT: assign [[X_VALUE]] to [[X_ADDR]] : $*InheritsMutatingMethod
+  // CHECK-NEXT: end_access [[X_ADDR]] : $*InheritsMutatingMethod
+  // CHECK-NEXT: dealloc_stack [[TEMPORARY]] : $*@opened("{{.*}}") InheritsMutatingMethod
+  x.mutateMe()
+
+  // CHECK-NEXT: [[RESULT_BOX:%.*]] = alloc_stack $Value
+  // CHECK-NEXT: [[RESULT:%.*]] = mark_uninitialized [var] [[RESULT_BOX]] : $*Value
+  // CHECK-NEXT: [[X_ADDR:%.*]] = begin_access [read] [unknown] %0 : $*InheritsMutatingMethod
+  // CHECK-NEXT: [[X_VALUE:%.*]] = load [copy] [[X_ADDR]] : $*InheritsMutatingMethod
+  // CHECK-NEXT: [[X_PAYLOAD:%.*]] = open_existential_ref [[X_VALUE]] : $InheritsMutatingMethod to $@opened("{{.*}}") InheritsMutatingMethod
+  // CHECK-NEXT: [[TEMPORARY:%.*]] = alloc_stack $@opened("{{.*}}") InheritsMutatingMethod
+  // CHECK-NEXT: store [[X_PAYLOAD]] to [init] [[TEMPORARY]] : $*@opened("{{.*}}") InheritsMutatingMethod
+  // CHECK-NEXT: [[X_PAYLOAD_RELOADED:%.*]] = load_borrow [[TEMPORARY]]
+  //
+  // ** *NOTE* This extra copy is here since RValue invariants enforce that all
+  // ** loadable objects are actually loaded. So we form the RValue and
+  // ** load... only to then need to store the value back in a stack location to
+  // ** pass to an in_guaranteed method. PredictableMemOpts is able to handle this
+  // ** type of temporary codegen successfully.
+  // CHECK-NEXT: [[TEMPORARY_2:%.*]] = alloc_stack $@opened("{{.*}}") InheritsMutatingMethod
+  // CHECK-NEXT: store_borrow [[X_PAYLOAD_RELOADED:%.*]] to [[TEMPORARY_2]]
+  // 
+  // CHECK-NEXT: [[METHOD:%.*]] = witness_method $@opened("{{.*}}") InheritsMutatingMethod, #HasMutatingMethod.mutatingCounter!getter.1 : <Self where Self : HasMutatingMethod> (Self) -> () -> Value, [[X_PAYLOAD]] : $@opened("{{.*}}") InheritsMutatingMethod : $@convention(witness_method: HasMutatingMethod) <τ_0_0 where τ_0_0 : HasMutatingMethod> (@in_guaranteed τ_0_0) -> Value
+  // CHECK-NEXT: [[RESULT_VALUE:%.*]] = apply [[METHOD]]<@opened("{{.*}}") InheritsMutatingMethod>([[TEMPORARY_2]]) : $@convention(witness_method: HasMutatingMethod) <τ_0_0 where τ_0_0 : HasMutatingMethod> (@in_guaranteed τ_0_0) -> Value
+  // CHECK-NEXT: dealloc_stack  [[TEMPORARY_2]]
+  // CHECK-NEXT: end_borrow [[X_PAYLOAD_RELOADED]]
+  // CHECK-NEXT: assign [[RESULT_VALUE]] to [[RESULT]] : $*Value
+  // CHECK-NEXT: destroy_addr [[TEMPORARY]]
+  // CHECK-NEXT: end_access [[X_ADDR]]
+  // CHECK-NEXT: dealloc_stack [[TEMPORARY]] : $*@opened("{{.*}}") InheritsMutatingMethod
+  // CHECK-NEXT: dealloc_stack [[RESULT_BOX]] : $*Value
+  _ = x.mutatingCounter
+
+  // CHECK-NEXT: [[X_ADDR:%.*]] = begin_access [modify] [unknown] %0 : $*InheritsMutatingMethod
+  // CHECK-NEXT: [[X_VALUE:%.*]] = load [copy] [[X_ADDR]] : $*InheritsMutatingMethod
+  // CHECK-NEXT: [[X_PAYLOAD:%.*]] = open_existential_ref [[X_VALUE]] : $InheritsMutatingMethod to $@opened("{{.*}}") InheritsMutatingMethod
+  // CHECK-NEXT: [[TEMPORARY:%.*]] = alloc_stack $@opened("{{.*}}") InheritsMutatingMethod
+  // CHECK-NEXT: store [[X_PAYLOAD]] to [init] [[TEMPORARY]] : $*@opened("{{.*}}") InheritsMutatingMethod
+  // CHECK-NEXT: [[METHOD:%.*]] = witness_method $@opened("{{.*}}") InheritsMutatingMethod, #HasMutatingMethod.mutatingCounter!setter.1 : <Self where Self : HasMutatingMethod> (inout Self) -> (Value) -> (), [[X_PAYLOAD]] : $@opened("{{.*}}") InheritsMutatingMethod : $@convention(witness_method: HasMutatingMethod) <τ_0_0 where τ_0_0 : HasMutatingMethod> (Value, @inout τ_0_0) -> ()
+  // CHECK-NEXT: apply [[METHOD]]<@opened("{{.*}}") InheritsMutatingMethod>(%1, [[TEMPORARY]]) : $@convention(witness_method: HasMutatingMethod) <τ_0_0 where τ_0_0 : HasMutatingMethod> (Value, @inout τ_0_0) -> ()
+  // CHECK-NEXT: [[X_PAYLOAD:%.*]] = load [take] [[TEMPORARY]] : $*@opened("{{.*}}") InheritsMutatingMethod
+  // CHECK-NEXT: [[X_VALUE:%.*]] = init_existential_ref [[X_PAYLOAD]] : $@opened("{{.*}}") InheritsMutatingMethod : $@opened("{{.*}}") InheritsMutatingMethod, $InheritsMutatingMethod
+  // CHECK-NEXT: assign [[X_VALUE]] to [[X_ADDR]] : $*InheritsMutatingMethod
+  // CHECK-NEXT: end_access [[X_ADDR]] : $*InheritsMutatingMethod
+  // CHECK-NEXT: dealloc_stack [[TEMPORARY]] : $*@opened("{{.*}}") InheritsMutatingMethod
+  x.mutatingCounter = y
+
+  takesInOut(&x.mutatingCounter)
+
+  _ = x.nonMutatingCounter
+  x.nonMutatingCounter = y
+  takesInOut(&x.nonMutatingCounter)
+}
diff --git a/test/SILGen/plus_zero_class_resilience.swift b/test/SILGen/plus_zero_class_resilience.swift
new file mode 100644
index 0000000..5421688
--- /dev/null
+++ b/test/SILGen/plus_zero_class_resilience.swift
@@ -0,0 +1,48 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %empty-directory(%t)
+// RUN: %target-swift-frontend -emit-module -enable-resilience -emit-module-path=%t/resilient_struct.swiftmodule -module-name=resilient_struct %S/../Inputs/resilient_struct.swift
+// RUN: %target-swift-frontend -emit-module -enable-resilience -emit-module-path=%t/resilient_class.swiftmodule -module-name=resilient_class -I %t %S/../Inputs/resilient_class.swift
+// RUN: %target-swift-frontend -I %t -emit-silgen -enable-sil-ownership -enable-resilience %s | %FileCheck %s
+
+import resilient_class
+
+// Accessing final property of resilient class from different resilience domain
+// through accessor
+
+// CHECK-LABEL: sil @$S16class_resilience20finalPropertyOfOtheryy010resilient_A022ResilientOutsideParentCF
+// CHECK: function_ref @$S15resilient_class22ResilientOutsideParentC13finalPropertySSvg
+
+public func finalPropertyOfOther(_ other: ResilientOutsideParent) {
+  _ = other.finalProperty
+}
+
+public class MyResilientClass {
+  public final var finalProperty: String = "MyResilientClass.finalProperty"
+}
+
+// Accessing final property of resilient class from my resilience domain
+// directly
+
+// CHECK-LABEL: sil @$S16class_resilience19finalPropertyOfMineyyAA16MyResilientClassCF
+// CHECK: bb0([[ARG:%.*]] : @guaranteed $MyResilientClass):
+// CHECK:   ref_element_addr [[ARG]] : $MyResilientClass, #MyResilientClass.finalProperty
+// CHECK: } // end sil function '$S16class_resilience19finalPropertyOfMineyyAA16MyResilientClassCF'
+
+public func finalPropertyOfMine(_ other: MyResilientClass) {
+  _ = other.finalProperty
+}
+
+class SubclassOfOutsideChild : ResilientOutsideChild {
+  override func method() {}
+
+  func newMethod() {}
+}
+
+// Note: no entries for [inherited] methods
+
+// CHECK-LABEL: sil_vtable SubclassOfOutsideChild {
+// CHECK-NEXT:  #ResilientOutsideParent.init!initializer.1: (ResilientOutsideParent.Type) -> () -> ResilientOutsideParent : @$S16class_resilience22SubclassOfOutsideChildCACycfc [override]
+// CHECK-NEXT:  #ResilientOutsideParent.method!1: (ResilientOutsideParent) -> () -> () : @$S16class_resilience22SubclassOfOutsideChildC6methodyyF [override]
+// CHECK-NEXT:  #SubclassOfOutsideChild.newMethod!1: (SubclassOfOutsideChild) -> () -> () : @$S16class_resilience22SubclassOfOutsideChildC9newMethodyyF
+// CHECK-NEXT:  #SubclassOfOutsideChild.deinit!deallocator: @$S16class_resilience22SubclassOfOutsideChildCfD
+// CHECK-NEXT: }
diff --git a/test/SILGen/plus_zero_closures.swift b/test/SILGen/plus_zero_closures.swift
new file mode 100644
index 0000000..2442f4b
--- /dev/null
+++ b/test/SILGen/plus_zero_closures.swift
@@ -0,0 +1,792 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -enable-sil-ownership -parse-stdlib -parse-as-library -emit-silgen %s | %FileCheck %s
+// RUN: %target-swift-frontend -enable-sil-ownership -parse-stdlib -parse-as-library -emit-silgen  %s | %FileCheck %s --check-prefix=GUARANTEED
+
+import Swift
+
+var zero = 0
+
+// <rdar://problem/15921334>
+// CHECK-LABEL: sil hidden @$S8closures46return_local_generic_function_without_captures{{[_0-9a-zA-Z]*}}F : $@convention(thin) <A, R> () -> @owned @callee_guaranteed (@in_guaranteed A) -> @out R {
+func return_local_generic_function_without_captures<A, R>() -> (A) -> R {
+  func f(_: A) -> R {
+    Builtin.int_trap()
+  }
+  // CHECK:  [[FN:%.*]] = function_ref @$S8closures46return_local_generic_function_without_captures{{[_0-9a-zA-Z]*}} : $@convention(thin) <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1
+  // CHECK:  [[FN_WITH_GENERIC_PARAMS:%.*]] = partial_apply [callee_guaranteed] [[FN]]<A, R>() : $@convention(thin) <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1
+  // CHECK:  return [[FN_WITH_GENERIC_PARAMS]] : $@callee_guaranteed (@in_guaranteed A) -> @out R
+  return f
+}
+
+func return_local_generic_function_with_captures<A, R>(_ a: A) -> (A) -> R {
+  func f(_: A) -> R {
+    _ = a
+  }
+
+  return f
+}
+
+// CHECK-LABEL: sil hidden @$S8closures17read_only_captureyS2iF : $@convention(thin) (Int) -> Int {
+func read_only_capture(_ x: Int) -> Int {
+  var x = x
+  // CHECK: bb0([[X:%[0-9]+]] : @trivial $Int):
+  // CHECK:   [[XBOX:%[0-9]+]] = alloc_box ${ var Int }
+  // SEMANTIC ARC TODO: This is incorrect. We need to do the project_box on the copy.
+  // CHECK:   [[PROJECT:%.*]] = project_box [[XBOX]]
+  // CHECK:   store [[X]] to [trivial] [[PROJECT]]
+
+  func cap() -> Int {
+    return x
+  }
+
+  return cap()
+  // CHECK:   [[XBOX_BORROW:%.*]] = begin_borrow [[XBOX]]
+  // SEMANTIC ARC TODO: See above. This needs to happen on the copy_valued box.
+  // CHECK:   mark_function_escape [[PROJECT]]
+  // CHECK:   [[CAP:%[0-9]+]] = function_ref @[[CAP_NAME:\$S8closures17read_only_capture.*]] : $@convention(thin) (@guaranteed { var Int }) -> Int
+  // CHECK:   [[RET:%[0-9]+]] = apply [[CAP]]([[XBOX_BORROW]])
+  // CHECK:   end_borrow [[XBOX_BORROW]]
+  // CHECK:   destroy_value [[XBOX]]
+  // CHECK:   return [[RET]]
+}
+// CHECK:   } // end sil function '$S8closures17read_only_captureyS2iF'
+
+// CHECK: sil private @[[CAP_NAME]]
+// CHECK: bb0([[XBOX:%[0-9]+]] : @guaranteed ${ var Int }):
+// CHECK: [[XADDR:%[0-9]+]] = project_box [[XBOX]]
+// CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] [[XADDR]] : $*Int
+// CHECK: [[X:%[0-9]+]] = load [trivial] [[ACCESS]]
+// CHECK: return [[X]]
+// } // end sil function '[[CAP_NAME]]'
+
+// SEMANTIC ARC TODO: This is a place where we have again project_box too early.
+// CHECK-LABEL: sil hidden @$S8closures16write_to_captureyS2iF : $@convention(thin) (Int) -> Int {
+func write_to_capture(_ x: Int) -> Int {
+  var x = x
+  // CHECK: bb0([[X:%[0-9]+]] : @trivial $Int):
+  // CHECK:   [[XBOX:%[0-9]+]] = alloc_box ${ var Int }
+  // CHECK:   [[XBOX_PB:%.*]] = project_box [[XBOX]]
+  // CHECK:   store [[X]] to [trivial] [[XBOX_PB]]
+  // CHECK:   [[X2BOX:%[0-9]+]] = alloc_box ${ var Int }
+  // CHECK:   [[X2BOX_PB:%.*]] = project_box [[X2BOX]]
+  // CHECK:   [[ACCESS:%.*]] = begin_access [read] [unknown] [[XBOX_PB]] : $*Int
+  // CHECK:   copy_addr [[ACCESS]] to [initialization] [[X2BOX_PB]]
+  // CHECK:   [[X2BOX_BORROW:%.*]] = begin_borrow [[X2BOX]]
+  // SEMANTIC ARC TODO: This next mark_function_escape should be on a projection from X2BOX_BORROW.
+  // CHECK:   mark_function_escape [[X2BOX_PB]]
+  var x2 = x
+
+  func scribble() {
+    x2 = zero
+  }
+
+  scribble()
+  // CHECK:   [[SCRIB:%[0-9]+]] = function_ref @[[SCRIB_NAME:\$S8closures16write_to_capture.*]] : $@convention(thin) (@guaranteed { var Int }) -> ()
+  // CHECK:   apply [[SCRIB]]([[X2BOX_BORROW]])
+  // SEMANTIC ARC TODO: This should load from X2BOX_BORROW project. There is an
+  // issue here where after a copy_value, we need to reassign a projection in
+  // some way.
+  // CHECK:   [[ACCESS:%.*]] = begin_access [read] [unknown] [[X2BOX_PB]] : $*Int
+  // CHECK:   [[RET:%[0-9]+]] = load [trivial] [[ACCESS]]
+  // CHECK:   destroy_value [[X2BOX]]
+  // CHECK:   destroy_value [[XBOX]]
+  // CHECK:   return [[RET]]
+  return x2
+}
+// CHECK:  } // end sil function '$S8closures16write_to_captureyS2iF'
+
+// CHECK: sil private @[[SCRIB_NAME]]
+// CHECK: bb0([[XBOX:%[0-9]+]] : @guaranteed ${ var Int }):
+// CHECK:   [[XADDR:%[0-9]+]] = project_box [[XBOX]]
+// CHECK:   [[ACCESS:%.*]] = begin_access [modify] [unknown] [[XADDR]] : $*Int
+// CHECK:   assign {{%[0-9]+}} to [[ACCESS]]
+// CHECK:   return
+// CHECK: } // end sil function '[[SCRIB_NAME]]'
+
+// CHECK-LABEL: sil hidden @$S8closures21multiple_closure_refs{{[_0-9a-zA-Z]*}}F
+func multiple_closure_refs(_ x: Int) -> (() -> Int, () -> Int) {
+  var x = x
+  func cap() -> Int {
+    return x
+  }
+
+  return (cap, cap)
+  // CHECK: [[CAP:%[0-9]+]] = function_ref @[[CAP_NAME:\$S8closures21multiple_closure_refs.*]] : $@convention(thin) (@guaranteed { var Int }) -> Int
+  // CHECK: [[CAP_CLOSURE_1:%[0-9]+]] = partial_apply [callee_guaranteed] [[CAP]]
+  // CHECK: [[CAP:%[0-9]+]] = function_ref @[[CAP_NAME:\$S8closures21multiple_closure_refs.*]] : $@convention(thin) (@guaranteed { var Int }) -> Int
+  // CHECK: [[CAP_CLOSURE_2:%[0-9]+]] = partial_apply [callee_guaranteed] [[CAP]]
+  // CHECK: [[RET:%[0-9]+]] = tuple ([[CAP_CLOSURE_1]] : {{.*}}, [[CAP_CLOSURE_2]] : {{.*}})
+  // CHECK: return [[RET]]
+}
+
+// CHECK-LABEL: sil hidden @$S8closures18capture_local_funcySiycycSiF : $@convention(thin) (Int) -> @owned @callee_guaranteed () -> @owned @callee_guaranteed () -> Int {
+func capture_local_func(_ x: Int) -> () -> () -> Int {
+  // CHECK: bb0([[ARG:%.*]] : @trivial $Int):
+  var x = x
+  // CHECK:   [[XBOX:%[0-9]+]] = alloc_box ${ var Int }
+  // CHECK:   [[XBOX_PB:%.*]] = project_box [[XBOX]]
+  // CHECK:   store [[ARG]] to [trivial] [[XBOX_PB]]
+
+  func aleph() -> Int { return x }
+
+  func beth() -> () -> Int { return aleph }
+  // CHECK: [[BETH_REF:%.*]] = function_ref @[[BETH_NAME:\$S8closures18capture_local_funcySiycycSiF4bethL_SiycyF]] : $@convention(thin) (@guaranteed { var Int }) -> @owned @callee_guaranteed () -> Int
+  // CHECK: [[XBOX_COPY:%.*]] = copy_value [[XBOX]]
+  // SEMANTIC ARC TODO: This is incorrect. This should be a project_box from XBOX_COPY.
+  // CHECK: mark_function_escape [[XBOX_PB]]
+  // CHECK: [[BETH_CLOSURE:%[0-9]+]] = partial_apply [callee_guaranteed] [[BETH_REF]]([[XBOX_COPY]])
+
+  return beth
+  // CHECK: destroy_value [[XBOX]]
+  // CHECK: return [[BETH_CLOSURE]]
+}
+// CHECK: } // end sil function '$S8closures18capture_local_funcySiycycSiF'
+
+// CHECK: sil private @[[ALEPH_NAME:\$S8closures18capture_local_funcySiycycSiF5alephL_SiyF]] : $@convention(thin) (@guaranteed { var Int }) -> Int {
+// CHECK: bb0([[XBOX:%[0-9]+]] : @guaranteed ${ var Int }):
+
+// CHECK: sil private @[[BETH_NAME]] : $@convention(thin) (@guaranteed { var Int }) -> @owned @callee_guaranteed () -> Int {
+// CHECK: bb0([[XBOX:%[0-9]+]] : @guaranteed ${ var Int }):
+// CHECK:   [[XBOX_PB:%.*]] = project_box [[XBOX]]
+// CHECK:   [[ALEPH_REF:%[0-9]+]] = function_ref @[[ALEPH_NAME]] : $@convention(thin) (@guaranteed { var Int }) -> Int
+// CHECK:   [[XBOX_COPY:%.*]] = copy_value [[XBOX]]
+// SEMANTIC ARC TODO: This should be on a PB from XBOX_COPY.
+// CHECK:   mark_function_escape [[XBOX_PB]]
+// CHECK:   [[ALEPH_CLOSURE:%[0-9]+]] = partial_apply [callee_guaranteed] [[ALEPH_REF]]([[XBOX_COPY]])
+// CHECK:   return [[ALEPH_CLOSURE]]
+// CHECK: } // end sil function '[[BETH_NAME]]'
+
+// CHECK-LABEL: sil hidden @$S8closures22anon_read_only_capture{{[_0-9a-zA-Z]*}}F
+func anon_read_only_capture(_ x: Int) -> Int {
+  var x = x
+  // CHECK: bb0([[X:%[0-9]+]] : @trivial $Int):
+  // CHECK: [[XBOX:%[0-9]+]] = alloc_box ${ var Int }
+  // CHECK: [[PB:%.*]] = project_box [[XBOX]]
+
+  return ({ x })()
+  // -- func expression
+  // CHECK: [[ANON:%[0-9]+]] = function_ref @[[CLOSURE_NAME:\$S8closures22anon_read_only_capture[_0-9a-zA-Z]*]] : $@convention(thin) (@inout_aliasable Int) -> Int
+  // -- apply expression
+  // CHECK: [[RET:%[0-9]+]] = apply [[ANON]]([[PB]])
+  // -- cleanup
+  // CHECK: destroy_value [[XBOX]]
+  // CHECK: return [[RET]]
+}
+// CHECK: sil private @[[CLOSURE_NAME]]
+// CHECK: bb0([[XADDR:%[0-9]+]] : @trivial $*Int):
+// CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] [[XADDR]] : $*Int
+// CHECK: [[X:%[0-9]+]] = load [trivial] [[ACCESS]]
+// CHECK: return [[X]]
+
+// CHECK-LABEL: sil hidden @$S8closures21small_closure_capture{{[_0-9a-zA-Z]*}}F
+func small_closure_capture(_ x: Int) -> Int {
+  var x = x
+  // CHECK: bb0([[X:%[0-9]+]] : @trivial $Int):
+  // CHECK: [[XBOX:%[0-9]+]] = alloc_box ${ var Int }
+  // CHECK: [[PB:%.*]] = project_box [[XBOX]]
+
+  return { x }()
+  // -- func expression
+  // CHECK: [[ANON:%[0-9]+]] = function_ref @[[CLOSURE_NAME:\$S8closures21small_closure_capture[_0-9a-zA-Z]*]] : $@convention(thin) (@inout_aliasable Int) -> Int
+  // -- apply expression
+  // CHECK: [[RET:%[0-9]+]] = apply [[ANON]]([[PB]])
+  // -- cleanup
+  // CHECK: destroy_value [[XBOX]]
+  // CHECK: return [[RET]]
+}
+// CHECK: sil private @[[CLOSURE_NAME]]
+// CHECK: bb0([[XADDR:%[0-9]+]] : @trivial $*Int):
+// CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] [[XADDR]] : $*Int
+// CHECK: [[X:%[0-9]+]] = load [trivial] [[ACCESS]]
+// CHECK: return [[X]]
+
+
+// CHECK-LABEL: sil hidden @$S8closures35small_closure_capture_with_argument{{[_0-9a-zA-Z]*}}F
+func small_closure_capture_with_argument(_ x: Int) -> (_ y: Int) -> Int {
+  var x = x
+  // CHECK: [[XBOX:%[0-9]+]] = alloc_box ${ var Int }
+
+  return { x + $0 }
+  // -- func expression
+  // CHECK: [[ANON:%[0-9]+]] = function_ref @[[CLOSURE_NAME:\$S8closures35small_closure_capture_with_argument.*]] : $@convention(thin) (Int, @guaranteed { var Int }) -> Int
+  // CHECK: [[XBOX_COPY:%.*]] = copy_value [[XBOX]]
+  // CHECK: [[ANON_CLOSURE_APP:%[0-9]+]] = partial_apply [callee_guaranteed] [[ANON]]([[XBOX_COPY]])
+  // -- return
+  // CHECK: destroy_value [[XBOX]]
+  // CHECK: return [[ANON_CLOSURE_APP]]
+}
+// FIXME(integers): the following checks should be updated for the new way +
+// gets invoked. <rdar://problem/29939484>
+// XCHECK: sil private @[[CLOSURE_NAME]] : $@convention(thin) (Int, @guaranteed { var Int }) -> Int
+// XCHECK: bb0([[DOLLAR0:%[0-9]+]] : $Int, [[XBOX:%[0-9]+]] : ${ var Int }):
+// XCHECK: [[XADDR:%[0-9]+]] = project_box [[XBOX]]
+// XCHECK: [[PLUS:%[0-9]+]] = function_ref @$Ss1poiS2i_SitF{{.*}}
+// XCHECK: [[LHS:%[0-9]+]] = load [trivial] [[XADDR]]
+// XCHECK: [[RET:%[0-9]+]] = apply [[PLUS]]([[LHS]], [[DOLLAR0]])
+// XCHECK: destroy_value [[XBOX]]
+// XCHECK: return [[RET]]
+
+// CHECK-LABEL: sil hidden @$S8closures24small_closure_no_capture{{[_0-9a-zA-Z]*}}F
+func small_closure_no_capture() -> (_ y: Int) -> Int {
+  // CHECK:   [[ANON:%[0-9]+]] = function_ref @[[CLOSURE_NAME:\$S8closures24small_closure_no_captureS2icyFS2icfU_]] : $@convention(thin) (Int) -> Int
+  // CHECK:   [[ANON_THICK:%[0-9]+]] = thin_to_thick_function [[ANON]] : ${{.*}} to $@callee_guaranteed (Int) -> Int
+  // CHECK:   return [[ANON_THICK]]
+  return { $0 }
+}
+// CHECK: sil private @[[CLOSURE_NAME]] : $@convention(thin) (Int) -> Int
+// CHECK: bb0([[YARG:%[0-9]+]] : @trivial $Int):
+
+// CHECK-LABEL: sil hidden @$S8closures17uncaptured_locals{{[_0-9a-zA-Z]*}}F :
+func uncaptured_locals(_ x: Int) -> (Int, Int) {
+  var x = x
+  // -- locals without captures are stack-allocated
+  // CHECK: bb0([[XARG:%[0-9]+]] : @trivial $Int):
+  // CHECK:   [[XADDR:%[0-9]+]] = alloc_box ${ var Int }
+  // CHECK:   [[PB:%.*]] = project_box [[XADDR]]
+  // CHECK:   store [[XARG]] to [trivial] [[PB]]
+
+  var y = zero
+  // CHECK:   [[YADDR:%[0-9]+]] = alloc_box ${ var Int }
+  return (x, y)
+
+}
+
+class SomeClass {
+  var x : Int = zero
+
+  init() {
+    x = { self.x }()   // Closing over self.
+  }
+}
+
+// Closures within destructors <rdar://problem/15883734>
+class SomeGenericClass<T> {
+  deinit {
+    var i: Int = zero
+    // CHECK: [[C1REF:%[0-9]+]] = function_ref @$S8closures16SomeGenericClassCfdSiyXEfU_ : $@convention(thin) (@inout_aliasable Int) -> Int
+    // CHECK: apply [[C1REF]]([[IBOX:%[0-9]+]]) : $@convention(thin) (@inout_aliasable Int) -> Int
+    var x = { i + zero } ()
+
+    // CHECK: [[C2REF:%[0-9]+]] = function_ref @$S8closures16SomeGenericClassCfdSiyXEfU0_ : $@convention(thin) () -> Int
+    // CHECK: apply [[C2REF]]() : $@convention(thin) () -> Int
+    var y = { zero } ()
+
+    // CHECK: [[C3REF:%[0-9]+]] = function_ref @$S8closures16SomeGenericClassCfdyyXEfU1_ : $@convention(thin) <τ_0_0> () -> ()
+    // CHECK: apply [[C3REF]]<T>() : $@convention(thin) <τ_0_0> () -> ()
+    var z = { _ = T.self } ()
+  }
+
+  // CHECK-LABEL: sil private @$S8closures16SomeGenericClassCfdSiyXEfU_ : $@convention(thin) (@inout_aliasable Int) -> Int
+
+  // CHECK-LABEL: sil private @$S8closures16SomeGenericClassCfdSiyXEfU0_ : $@convention(thin) () -> Int
+
+  // CHECK-LABEL: sil private @$S8closures16SomeGenericClassCfdyyXEfU1_ : $@convention(thin) <T> () -> ()
+}
+
+// This is basically testing that the constraint system ranking
+// function conversions as worse than others, and therefore performs
+// the conversion within closures when possible.
+class SomeSpecificClass : SomeClass {}
+func takesSomeClassGenerator(_ fn : () -> SomeClass) {}
+func generateWithConstant(_ x : SomeSpecificClass) {
+  takesSomeClassGenerator({ x })
+}
+
+// CHECK-LABEL: sil private @$S8closures20generateWithConstantyyAA17SomeSpecificClassCFAA0eG0CyXEfU_ : $@convention(thin) (@guaranteed SomeSpecificClass) -> @owned SomeClass {
+// CHECK: bb0([[T0:%.*]] : @guaranteed $SomeSpecificClass):
+// CHECK:   debug_value [[T0]] : $SomeSpecificClass, let, name "x", argno 1
+// CHECK:   [[T0_COPY:%.*]] = copy_value [[T0]]
+// CHECK:   [[T0_COPY_CASTED:%.*]] = upcast [[T0_COPY]] : $SomeSpecificClass to $SomeClass
+// CHECK:   return [[T0_COPY_CASTED]]
+// CHECK: } // end sil function '$S8closures20generateWithConstantyyAA17SomeSpecificClassCFAA0eG0CyXEfU_'
+
+
+// Check the annoying case of capturing 'self' in a derived class 'init'
+// method. We allocate a mutable box to deal with 'self' potentially being
+// rebound by super.init, but 'self' is formally immutable and so is captured
+// by value. <rdar://problem/15599464>
+class Base {}
+
+class SelfCapturedInInit : Base {
+  var foo : () -> SelfCapturedInInit
+
+  // CHECK-LABEL: sil hidden @$S8closures18SelfCapturedInInitC{{[_0-9a-zA-Z]*}}fc : $@convention(method) (@owned SelfCapturedInInit) -> @owned SelfCapturedInInit {
+  // CHECK: bb0([[SELF:%.*]] : @owned $SelfCapturedInInit):
+  //
+  // First create our initial value for self.
+  // CHECK:   [[SELF_BOX:%.*]] = alloc_box ${ var SelfCapturedInInit }, let, name "self"
+  // CHECK:   [[UNINIT_SELF:%.*]] = mark_uninitialized [derivedself] [[SELF_BOX]]
+  // CHECK:   [[PB_SELF_BOX:%.*]] = project_box [[UNINIT_SELF]]
+  // CHECK:   store [[SELF]] to [init] [[PB_SELF_BOX]]
+  //
+  // Then perform the super init sequence.
+  // CHECK:   [[TAKEN_SELF:%.*]] = load [take] [[PB_SELF_BOX]]
+  // CHECK:   [[UPCAST_TAKEN_SELF:%.*]] = upcast [[TAKEN_SELF]]
+  // CHECK:   [[NEW_SELF:%.*]] = apply {{.*}}([[UPCAST_TAKEN_SELF]]) : $@convention(method) (@owned Base) -> @owned Base
+  // CHECK:   [[DOWNCAST_NEW_SELF:%.*]] = unchecked_ref_cast [[NEW_SELF]] : $Base to $SelfCapturedInInit
+  // CHECK:   store [[DOWNCAST_NEW_SELF]] to [init] [[PB_SELF_BOX]]
+  //
+  // Finally put self in the closure.
+  // CHECK:   [[BORROWED_SELF:%.*]] = load_borrow [[PB_SELF_BOX]]
+  // CHECK:   [[COPIED_SELF:%.*]] = load [copy] [[PB_SELF_BOX]]
+  // CHECK:   [[FOO_VALUE:%.*]] = partial_apply [callee_guaranteed] {{%.*}}([[COPIED_SELF]]) : $@convention(thin) (@guaranteed SelfCapturedInInit) -> @owned SelfCapturedInInit
+  // CHECK:   [[FOO_LOCATION:%.*]] = ref_element_addr [[BORROWED_SELF]]
+  // CHECK:   [[ACCESS:%.*]] = begin_access [modify] [dynamic] [[FOO_LOCATION]] : $*@callee_guaranteed () -> @owned SelfCapturedInInit
+  // CHECK:   assign [[FOO_VALUE]] to [[ACCESS]]
+  override init() {
+    super.init()
+    foo = { self }
+  }
+}
+
+func takeClosure(_ fn: () -> Int) -> Int { return fn() }
+
+class TestCaptureList {
+  var x = zero
+
+  func testUnowned() {
+    let aLet = self
+    takeClosure { aLet.x }
+    takeClosure { [unowned aLet] in aLet.x }
+    takeClosure { [weak aLet] in aLet!.x }
+
+    var aVar = self
+    takeClosure { aVar.x }
+    takeClosure { [unowned aVar] in aVar.x }
+    takeClosure { [weak aVar] in aVar!.x }
+
+    takeClosure { self.x }
+    takeClosure { [unowned self] in self.x }
+    takeClosure { [weak self] in self!.x }
+
+    takeClosure { [unowned newVal = TestCaptureList()] in newVal.x }
+    takeClosure { [weak newVal = TestCaptureList()] in newVal!.x }
+  }
+}
+
+class ClassWithIntProperty { final var x = 42 }
+
+func closeOverLetLValue() {
+  let a : ClassWithIntProperty
+  a = ClassWithIntProperty()
+  
+  takeClosure { a.x }
+}
+
+// The let property needs to be captured into a temporary stack slot so that it
+// is loadable even though we capture the value.
+// CHECK-LABEL: sil private @$S8closures18closeOverLetLValueyyFSiyXEfU_ : $@convention(thin) (@guaranteed ClassWithIntProperty) -> Int {
+// CHECK: bb0([[ARG:%.*]] : @guaranteed $ClassWithIntProperty):
+// CHECK:   [[TMP_CLASS_ADDR:%.*]] = alloc_stack $ClassWithIntProperty, let, name "a", argno 1
+// CHECK:   [[COPY_ARG:%.*]] = copy_value [[ARG]]
+// CHECK:   store [[COPY_ARG]] to [init] [[TMP_CLASS_ADDR]] : $*ClassWithIntProperty
+// CHECK:   [[LOADED_CLASS:%.*]] = load [copy] [[TMP_CLASS_ADDR]] : $*ClassWithIntProperty
+// CHECK:   [[BORROWED_LOADED_CLASS:%.*]] = begin_borrow [[LOADED_CLASS]]
+// CHECK:   [[INT_IN_CLASS_ADDR:%.*]] = ref_element_addr [[BORROWED_LOADED_CLASS]] : $ClassWithIntProperty, #ClassWithIntProperty.x
+// CHECK:   [[ACCESS:%.*]] = begin_access [read] [dynamic] [[INT_IN_CLASS_ADDR]] : $*Int
+// CHECK:   [[INT_IN_CLASS:%.*]] = load [trivial] [[ACCESS]] : $*Int
+// CHECK:   end_borrow [[BORROWED_LOADED_CLASS]] from [[LOADED_CLASS]]
+// CHECK:   destroy_value [[LOADED_CLASS]]
+// CHECK:   destroy_addr [[TMP_CLASS_ADDR]] : $*ClassWithIntProperty
+// CHECK:   dealloc_stack %1 : $*ClassWithIntProperty
+// CHECK:   return [[INT_IN_CLASS]]
+// CHECK: } // end sil function '$S8closures18closeOverLetLValueyyFSiyXEfU_'
+
+// GUARANTEED-LABEL: sil private @$S8closures18closeOverLetLValueyyFSiyXEfU_ : $@convention(thin) (@guaranteed ClassWithIntProperty) -> Int {
+// GUARANTEED: bb0(%0 : @guaranteed $ClassWithIntProperty):
+// GUARANTEED:   [[TMP:%.*]] = alloc_stack $ClassWithIntProperty
+// GUARANTEED:   [[COPY:%.*]] = copy_value %0 : $ClassWithIntProperty
+// GUARANTEED:   store [[COPY]] to [init] [[TMP]] : $*ClassWithIntProperty
+// GUARANTEED:   [[LOADED_COPY:%.*]] = load [copy] [[TMP]]
+// GUARANTEED:   [[BORROWED:%.*]] = begin_borrow [[LOADED_COPY]]
+// GUARANTEED:   end_borrow [[BORROWED]] from [[LOADED_COPY]]
+// GUARANTEED:   destroy_value [[LOADED_COPY]]
+// GUARANTEED:   destroy_addr [[TMP]]
+// GUARANTEED: } // end sil function '$S8closures18closeOverLetLValueyyFSiyXEfU_'
+
+
+// Use an external function so inout deshadowing cannot see its body.
+@_silgen_name("takesNoEscapeClosure")
+func takesNoEscapeClosure(fn : () -> Int)
+
+struct StructWithMutatingMethod {
+  var x = 42
+
+  mutating func mutatingMethod() {
+    // This should not capture the refcount of the self shadow.
+    takesNoEscapeClosure { x = 42; return x }
+  }
+}
+
+// Check that the address of self is passed in, but not the refcount pointer.
+
+// CHECK-LABEL: sil hidden @$S8closures24StructWithMutatingMethodV08mutatingE0{{[_0-9a-zA-Z]*}}F
+// CHECK: bb0(%0 : @trivial $*StructWithMutatingMethod):
+// CHECK: [[CLOSURE:%[0-9]+]] = function_ref @$S8closures24StructWithMutatingMethodV08mutatingE0{{.*}} : $@convention(thin) (@inout_aliasable StructWithMutatingMethod) -> Int
+// CHECK: partial_apply [callee_guaranteed] [[CLOSURE]](%0) : $@convention(thin) (@inout_aliasable StructWithMutatingMethod) -> Int
+
+// Check that the closure body only takes the pointer.
+// CHECK-LABEL: sil private @$S8closures24StructWithMutatingMethodV08mutatingE0{{.*}} : $@convention(thin) (@inout_aliasable StructWithMutatingMethod) -> Int {
+// CHECK:       bb0(%0 : @trivial $*StructWithMutatingMethod):
+
+class SuperBase {
+  func boom() {}
+}
+class SuperSub : SuperBase {
+  override func boom() {}
+
+  // CHECK-LABEL: sil hidden @$S8closures8SuperSubC1ayyF : $@convention(method) (@guaranteed SuperSub) -> () {
+  // CHECK: bb0([[SELF:%.*]] : @guaranteed $SuperSub):
+  // CHECK:   [[INNER:%.*]] = function_ref @[[INNER_FUNC_1:\$S8closures8SuperSubC1a[_0-9a-zA-Z]*]] : $@convention(thin) (@guaranteed SuperSub) -> ()
+  // CHECK:   apply [[INNER]]([[SELF]])
+  // CHECK: } // end sil function '$S8closures8SuperSubC1ayyF'
+  func a() {
+    // CHECK: sil private @[[INNER_FUNC_1]] : $@convention(thin) (@guaranteed SuperSub) -> () {
+    // CHECK: bb0([[ARG:%.*]] : @guaranteed $SuperSub):
+    // CHECK:   [[CLASS_METHOD:%.*]] = class_method [[ARG]] : $SuperSub, #SuperSub.boom!1
+    // CHECK:   = apply [[CLASS_METHOD]]([[ARG]])
+    // CHECK:   [[ARG_COPY:%.*]] = copy_value [[ARG]]
+    // CHECK:   [[ARG_COPY_SUPER:%.*]] = upcast [[ARG_COPY]] : $SuperSub to $SuperBase
+    // CHECK:   [[BORROWED_ARG_COPY_SUPER:%.*]] = begin_borrow [[ARG_COPY_SUPER]]
+    // CHECK:   [[SUPER_METHOD:%[0-9]+]] = function_ref @$S8closures9SuperBaseC4boomyyF : $@convention(method) (@guaranteed SuperBase) -> ()
+    // CHECK:   = apply [[SUPER_METHOD]]([[BORROWED_ARG_COPY_SUPER]])
+    // CHECK:   destroy_value [[ARG_COPY_SUPER]]
+    // CHECK: } // end sil function '[[INNER_FUNC_1]]'
+    func a1() {
+      self.boom()
+      super.boom()
+    }
+    a1()
+  }
+
+  // CHECK-LABEL: sil hidden @$S8closures8SuperSubC1byyF : $@convention(method) (@guaranteed SuperSub) -> () {
+  // CHECK: bb0([[SELF:%.*]] : @guaranteed $SuperSub):
+  // CHECK:   [[INNER:%.*]] = function_ref @[[INNER_FUNC_1:\$S8closures8SuperSubC1b[_0-9a-zA-Z]*]] : $@convention(thin) (@guaranteed SuperSub) -> ()
+  // CHECK:   = apply [[INNER]]([[SELF]])
+  // CHECK: } // end sil function '$S8closures8SuperSubC1byyF'
+  func b() {
+    // CHECK: sil private @[[INNER_FUNC_1]] : $@convention(thin) (@guaranteed SuperSub) -> () {
+    // CHECK: bb0([[ARG:%.*]] : @guaranteed $SuperSub):
+    // CHECK:   [[INNER:%.*]] = function_ref @[[INNER_FUNC_2:\$S8closures8SuperSubC1b.*]] : $@convention(thin) (@guaranteed SuperSub) -> ()
+    // CHECK:   = apply [[INNER]]([[ARG]])
+    // CHECK: } // end sil function '[[INNER_FUNC_1]]'
+    func b1() {
+      // CHECK: sil private @[[INNER_FUNC_2]] : $@convention(thin) (@guaranteed SuperSub) -> () {
+      // CHECK: bb0([[ARG:%.*]] : @guaranteed $SuperSub):
+      // CHECK:   [[CLASS_METHOD:%.*]] = class_method [[ARG]] : $SuperSub, #SuperSub.boom!1
+      // CHECK:   = apply [[CLASS_METHOD]]([[ARG]]) : $@convention(method) (@guaranteed SuperSub) -> ()
+      // CHECK:   [[ARG_COPY:%.*]] = copy_value [[ARG]]
+      // CHECK:   [[ARG_COPY_SUPER:%.*]] = upcast [[ARG_COPY]] : $SuperSub to $SuperBase
+      // CHECK:   [[BORROWED_ARG_COPY_SUPER:%.*]] = begin_borrow [[ARG_COPY_SUPER]]
+      // CHECK:   [[SUPER_METHOD:%.*]] = function_ref @$S8closures9SuperBaseC4boomyyF : $@convention(method) (@guaranteed SuperBase) -> ()
+      // CHECK:   = apply [[SUPER_METHOD]]([[BORROWED_ARG_COPY_SUPER]]) : $@convention(method) (@guaranteed SuperBase)
+      // CHECK:   destroy_value [[ARG_COPY_SUPER]]
+      // CHECK: } // end sil function '[[INNER_FUNC_2]]'
+      func b2() {
+        self.boom()
+        super.boom()
+      }
+      b2()
+    }
+    b1()
+  }
+
+  // CHECK-LABEL: sil hidden @$S8closures8SuperSubC1cyyF : $@convention(method) (@guaranteed SuperSub) -> () {
+  // CHECK: bb0([[SELF:%.*]] : @guaranteed $SuperSub):
+  // CHECK:   [[INNER:%.*]] = function_ref @[[INNER_FUNC_1:\$S8closures8SuperSubC1c[_0-9a-zA-Z]*]] : $@convention(thin) (@guaranteed SuperSub) -> ()
+  // CHECK:   [[SELF_COPY:%.*]] = copy_value [[SELF]]
+  // CHECK:   [[PA:%.*]] = partial_apply [callee_guaranteed] [[INNER]]([[SELF_COPY]])
+  // CHECK:   [[BORROWED_PA:%.*]] = begin_borrow [[PA]]
+  // CHECK:   [[PA_COPY:%.*]] = copy_value [[BORROWED_PA]]
+  // CHECK:   [[B:%.*]] = begin_borrow [[PA_COPY]]
+  // CHECK:   apply [[B]]()
+	// CHECK:   end_borrow [[B]]
+  // CHECK:   destroy_value [[PA_COPY]]
+  // CHECK:   end_borrow [[BORROWED_PA]] from [[PA]]
+  // CHECK:   destroy_value [[PA]]
+  // CHECK: } // end sil function '$S8closures8SuperSubC1cyyF'
+  func c() {
+    // CHECK: sil private @[[INNER_FUNC_1]] : $@convention(thin) (@guaranteed SuperSub) -> ()
+    // CHECK: bb0([[ARG:%.*]] : @guaranteed $SuperSub):
+    // CHECK:   [[CLASS_METHOD:%.*]] = class_method [[ARG]] : $SuperSub, #SuperSub.boom!1
+    // CHECK:   = apply [[CLASS_METHOD]]([[ARG]]) : $@convention(method) (@guaranteed SuperSub) -> ()
+    // CHECK:   [[ARG_COPY:%.*]] = copy_value [[ARG]]
+    // CHECK:   [[ARG_COPY_SUPER:%.*]] = upcast [[ARG_COPY]] : $SuperSub to $SuperBase
+    // CHECK:   [[BORROWED_ARG_COPY_SUPER:%.*]] = begin_borrow [[ARG_COPY_SUPER]]
+    // CHECK:   [[SUPER_METHOD:%[0-9]+]] = function_ref @$S8closures9SuperBaseC4boomyyF : $@convention(method) (@guaranteed SuperBase) -> ()
+    // CHECK:   = apply [[SUPER_METHOD]]([[BORROWED_ARG_COPY_SUPER]])
+    // CHECK:   destroy_value [[ARG_COPY_SUPER]]
+    // CHECK: } // end sil function '[[INNER_FUNC_1]]'
+    let c1 = { () -> Void in
+      self.boom()
+      super.boom()
+    }
+    c1()
+  }
+
+  // CHECK-LABEL: sil hidden @$S8closures8SuperSubC1dyyF : $@convention(method) (@guaranteed SuperSub) -> () {
+  // CHECK: bb0([[SELF:%.*]] : @guaranteed $SuperSub):
+  // CHECK:   [[INNER:%.*]] = function_ref @[[INNER_FUNC_1:\$S8closures8SuperSubC1d[_0-9a-zA-Z]*]] : $@convention(thin) (@guaranteed SuperSub) -> ()
+  // CHECK:   [[SELF_COPY:%.*]] = copy_value [[SELF]]
+  // CHECK:   [[PA:%.*]] = partial_apply [callee_guaranteed] [[INNER]]([[SELF_COPY]])
+  // CHECK:   [[BORROWED_PA:%.*]] = begin_borrow [[PA]]
+  // CHECK:   [[PA_COPY:%.*]] = copy_value [[BORROWED_PA]]
+  // CHECK:   [[B:%.*]] = begin_borrow [[PA_COPY]]
+  // CHECK:   apply [[B]]()
+  // CHECK:   end_borrow [[B]]
+  // CHECK:   destroy_value [[PA_COPY]]
+  // CHECK:   end_borrow [[BORROWED_PA]] from [[PA]]
+  // CHECK:   destroy_value [[PA]]
+  // CHECK: } // end sil function '$S8closures8SuperSubC1dyyF'
+  func d() {
+    // CHECK: sil private @[[INNER_FUNC_1]] : $@convention(thin) (@guaranteed SuperSub) -> () {
+    // CHECK: bb0([[ARG:%.*]] : @guaranteed $SuperSub):
+    // CHECK:   [[INNER:%.*]] = function_ref @[[INNER_FUNC_2:\$S8closures8SuperSubC1d.*]] : $@convention(thin) (@guaranteed SuperSub) -> ()
+    // CHECK:   = apply [[INNER]]([[ARG]])
+    // CHECK: } // end sil function '[[INNER_FUNC_1]]'
+    let d1 = { () -> Void in
+      // CHECK: sil private @[[INNER_FUNC_2]] : $@convention(thin) (@guaranteed SuperSub) -> () {
+      // CHECK: bb0([[ARG:%.*]] : @guaranteed $SuperSub):
+      // CHECK:   [[ARG_COPY:%.*]] = copy_value [[ARG]]
+      // CHECK:   [[ARG_COPY_SUPER:%.*]] = upcast [[ARG_COPY]] : $SuperSub to $SuperBase
+      // CHECK:   [[BORROWED_ARG_COPY_SUPER:%.*]] = begin_borrow [[ARG_COPY_SUPER]]
+      // CHECK:   [[SUPER_METHOD:%.*]] = function_ref @$S8closures9SuperBaseC4boomyyF : $@convention(method) (@guaranteed SuperBase) -> ()
+      // CHECK:   = apply [[SUPER_METHOD]]([[BORROWED_ARG_COPY_SUPER]])
+      // CHECK:   destroy_value [[ARG_COPY_SUPER]]
+      // CHECK: } // end sil function '[[INNER_FUNC_2]]'
+      func d2() {
+        super.boom()
+      }
+      d2()
+    }
+    d1()
+  }
+
+  // CHECK-LABEL: sil hidden @$S8closures8SuperSubC1eyyF : $@convention(method) (@guaranteed SuperSub) -> () {
+  // CHECK: bb0([[SELF:%.*]] : @guaranteed $SuperSub):
+  // CHECK: [[INNER:%.*]] = function_ref @[[INNER_FUNC_NAME1:\$S8closures8SuperSubC1e[_0-9a-zA-Z]*]] : $@convention(thin)
+  // CHECK: = apply [[INNER]]([[SELF]])
+  // CHECK: } // end sil function '$S8closures8SuperSubC1eyyF'
+  func e() {
+    // CHECK: sil private @[[INNER_FUNC_NAME1]] : $@convention(thin)
+    // CHECK: bb0([[ARG:%.*]] : @guaranteed $SuperSub):
+    // CHECK:   [[INNER:%.*]] = function_ref @[[INNER_FUNC_NAME2:\$S8closures8SuperSubC1e.*]] : $@convention(thin)
+    // CHECK:   [[ARG_COPY:%.*]] = copy_value [[ARG]]
+    // CHECK:   [[PA:%.*]] = partial_apply [callee_guaranteed] [[INNER]]([[ARG_COPY]])
+    // CHECK:   [[BORROWED_PA:%.*]] = begin_borrow [[PA]]
+    // CHECK:   [[PA_COPY:%.*]] = copy_value [[BORROWED_PA]]
+    // CHECK:   [[B:%.*]] = begin_borrow [[PA_COPY]]
+    // CHECK:   apply [[B]]() : $@callee_guaranteed () -> ()
+    // CHECK:   end_borrow [[B]]
+    // CHECK:   destroy_value [[PA_COPY]]
+    // CHECK:   end_borrow [[BORROWED_PA]] from [[PA]]
+    // CHECK:   destroy_value [[PA]]
+    // CHECK: } // end sil function '[[INNER_FUNC_NAME1]]'
+    func e1() {
+      // CHECK: sil private @[[INNER_FUNC_NAME2]] : $@convention(thin)
+      // CHECK: bb0([[ARG:%.*]] : @guaranteed $SuperSub):
+      // CHECK:   [[ARG_COPY:%.*]] = copy_value [[ARG]]
+      // CHECK:   [[ARG_COPY_SUPERCAST:%.*]] = upcast [[ARG_COPY]] : $SuperSub to $SuperBase
+      // CHECK:   [[BORROWED_ARG_COPY_SUPERCAST:%.*]] = begin_borrow [[ARG_COPY_SUPERCAST]]
+      // CHECK:   [[SUPER_METHOD:%.*]] = function_ref @$S8closures9SuperBaseC4boomyyF : $@convention(method) (@guaranteed SuperBase) -> ()
+      // CHECK:   = apply [[SUPER_METHOD]]([[BORROWED_ARG_COPY_SUPERCAST]])
+      // CHECK:   destroy_value [[ARG_COPY_SUPERCAST]]
+      // CHECK:   return
+      // CHECK: } // end sil function '[[INNER_FUNC_NAME2]]'
+      let e2 = {
+        super.boom()
+      }
+      e2()
+    }
+    e1()
+  }
+
+  // CHECK-LABEL: sil hidden @$S8closures8SuperSubC1fyyF : $@convention(method) (@guaranteed SuperSub) -> () {
+  // CHECK: bb0([[SELF:%.*]] : @guaranteed $SuperSub):
+  // CHECK:   [[INNER:%.*]] = function_ref @[[INNER_FUNC_1:\$S8closures8SuperSubC1fyyFyycfU_]] : $@convention(thin) (@guaranteed SuperSub) -> ()
+  // CHECK:   [[SELF_COPY:%.*]] = copy_value [[SELF]]
+  // CHECK:   [[PA:%.*]] = partial_apply [callee_guaranteed] [[INNER]]([[SELF_COPY]])
+  // CHECK:   destroy_value [[PA]]
+  // CHECK: } // end sil function '$S8closures8SuperSubC1fyyF'
+  func f() {
+    // CHECK: sil private @[[INNER_FUNC_1]] : $@convention(thin) (@guaranteed SuperSub) -> () {
+    // CHECK: bb0([[ARG:%.*]] : @guaranteed $SuperSub):
+    // CHECK:   [[INNER:%.*]] = function_ref @[[INNER_FUNC_2:\$S8closures8SuperSubC1fyyFyycfU_yyKXKfu_]] : $@convention(thin) (@guaranteed SuperSub) -> @error Error
+    // CHECK:   [[ARG_COPY:%.*]] = copy_value [[ARG]]
+    // CHECK:   [[PA:%.*]] = partial_apply [callee_guaranteed] [[INNER]]([[ARG_COPY]])
+    // CHECK:   [[CVT:%.*]] = convert_escape_to_noescape [[PA]]
+    // CHECK:   [[REABSTRACT_PA:%.*]] = partial_apply [callee_guaranteed] {{.*}}([[CVT]])
+    // CHECK:   [[REABSTRACT_CVT:%.*]] = convert_escape_to_noescape [[REABSTRACT_PA]]
+    // CHECK:   [[TRY_APPLY_AUTOCLOSURE:%.*]] = function_ref @$Ss2qqoiyxxSg_xyKXKtKlF : $@convention(thin) <τ_0_0> (@in_guaranteed Optional<τ_0_0>, @noescape @callee_guaranteed () -> (@out τ_0_0, @error Error)) -> (@out τ_0_0, @error Error)
+    // CHECK:   try_apply [[TRY_APPLY_AUTOCLOSURE]]<()>({{.*}}, {{.*}}, [[REABSTRACT_CVT]]) : $@convention(thin) <τ_0_0> (@in_guaranteed Optional<τ_0_0>, @noescape @callee_guaranteed () -> (@out τ_0_0, @error Error)) -> (@out τ_0_0, @error Error), normal [[NORMAL_BB:bb1]], error [[ERROR_BB:bb2]]
+    // CHECK: [[NORMAL_BB]]{{.*}}
+    // CHECK: } // end sil function '[[INNER_FUNC_1]]'
+    let f1 = {
+      // CHECK: sil private [transparent] @[[INNER_FUNC_2]]
+      // CHECK: bb0([[ARG:%.*]] : @guaranteed $SuperSub):
+      // CHECK:   [[ARG_COPY:%.*]] = copy_value [[ARG]]
+      // CHECK:   [[ARG_COPY_SUPER:%.*]] = upcast [[ARG_COPY]] : $SuperSub to $SuperBase
+      // CHECK:   [[BORROWED_ARG_COPY_SUPER:%.*]] = begin_borrow [[ARG_COPY_SUPER]]
+      // CHECK:   [[SUPER_METHOD:%.*]] = function_ref @$S8closures9SuperBaseC4boomyyF : $@convention(method) (@guaranteed SuperBase) -> ()
+      // CHECK:   = apply [[SUPER_METHOD]]([[BORROWED_ARG_COPY_SUPER]]) : $@convention(method) (@guaranteed SuperBase) -> ()
+      // CHECK:   destroy_value [[ARG_COPY_SUPER]]
+      // CHECK: } // end sil function '[[INNER_FUNC_2]]'
+      nil ?? super.boom()
+    }
+  }
+
+  // CHECK-LABEL: sil hidden @$S8closures8SuperSubC1gyyF : $@convention(method) (@guaranteed SuperSub) -> () {
+  // CHECK: bb0([[SELF:%.*]] : @guaranteed $SuperSub):
+  // CHECK:   [[INNER:%.*]] = function_ref @[[INNER_FUNC_1:\$S8closures8SuperSubC1g[_0-9a-zA-Z]*]] : $@convention(thin) (@guaranteed SuperSub) -> ()
+  // CHECK:   = apply [[INNER]]([[SELF]])
+  // CHECK: } // end sil function '$S8closures8SuperSubC1gyyF'
+  func g() {
+    // CHECK: sil private @[[INNER_FUNC_1]] : $@convention(thin) (@guaranteed SuperSub) -> ()
+    // CHECK: bb0([[ARG:%.*]] : @guaranteed $SuperSub):
+    // CHECK:   [[INNER:%.*]] = function_ref @[[INNER_FUNC_2:\$S8closures8SuperSubC1g.*]] : $@convention(thin) (@guaranteed SuperSub) -> @error Error
+    // CHECK:   [[ARG_COPY:%.*]] = copy_value [[ARG]]
+    // CHECK:   [[PA:%.*]] = partial_apply [callee_guaranteed] [[INNER]]([[ARG_COPY]])
+    // CHECK:   [[CVT:%.*]] = convert_escape_to_noescape [[PA]] : $@callee_guaranteed () -> @error Error to $@noescape @callee_guaranteed () -> @error Error
+    // CHECK:   [[REABSTRACT_PA:%.*]] = partial_apply [callee_guaranteed] {{%.*}}([[CVT]]) : $@convention(thin) (@noescape @callee_guaranteed () -> @error Error) -> (@out (), @error Error)
+    // CHECK:   [[REABSTRACT_CVT:%.*]] = convert_escape_to_noescape [[REABSTRACT_PA]]
+    // CHECK:   [[TRY_APPLY_FUNC:%.*]] = function_ref @$Ss2qqoiyxxSg_xyKXKtKlF : $@convention(thin) <τ_0_0> (@in_guaranteed Optional<τ_0_0>, @noescape @callee_guaranteed () -> (@out τ_0_0, @error Error)) -> (@out τ_0_0, @error Error)
+    // CHECK:   try_apply [[TRY_APPLY_FUNC]]<()>({{.*}}, {{.*}}, [[REABSTRACT_CVT]]) : $@convention(thin) <τ_0_0> (@in_guaranteed Optional<τ_0_0>, @noescape @callee_guaranteed () -> (@out τ_0_0, @error Error)) -> (@out τ_0_0, @error Error), normal [[NORMAL_BB:bb1]], error [[ERROR_BB:bb2]]
+    // CHECK: [[NORMAL_BB]]{{.*}}
+    // CHECK: } // end sil function '[[INNER_FUNC_1]]'
+    func g1() {
+      // CHECK: sil private [transparent] @[[INNER_FUNC_2]] : $@convention(thin) (@guaranteed SuperSub) -> @error Error {
+      // CHECK: bb0([[ARG:%.*]] : @guaranteed $SuperSub):
+      // CHECK:   [[ARG_COPY:%.*]] = copy_value [[ARG]]
+      // CHECK:   [[ARG_COPY_SUPER:%.*]] = upcast [[ARG_COPY]] : $SuperSub to $SuperBase
+      // CHECK:   [[BORROWED_ARG_COPY_SUPER:%.*]] = begin_borrow [[ARG_COPY_SUPER]]
+      // CHECK:   [[SUPER_METHOD:%.*]] = function_ref @$S8closures9SuperBaseC4boomyyF : $@convention(method) (@guaranteed SuperBase) -> ()
+      // CHECK:   = apply [[SUPER_METHOD]]([[BORROWED_ARG_COPY_SUPER]])
+      // CHECK:   destroy_value [[ARG_COPY_SUPER]]
+      // CHECK: } // end sil function '[[INNER_FUNC_2]]'
+      nil ?? super.boom()
+    }
+    g1()
+  }
+}
+
+// CHECK-LABEL: sil hidden @$S8closures24UnownedSelfNestedCaptureC06nestedE0{{[_0-9a-zA-Z]*}}F : $@convention(method) (@guaranteed UnownedSelfNestedCapture) -> ()
+// -- We enter with an assumed strong +1.
+// CHECK:  bb0([[SELF:%.*]] : @guaranteed $UnownedSelfNestedCapture):
+// CHECK:         [[OUTER_SELF_CAPTURE:%.*]] = alloc_box ${ var @sil_unowned UnownedSelfNestedCapture }
+// CHECK:         [[PB:%.*]] = project_box [[OUTER_SELF_CAPTURE]]
+// -- strong +2
+// CHECK:         [[SELF_COPY:%.*]] = copy_value [[SELF]]
+// CHECK:         [[UNOWNED_SELF:%.*]] = ref_to_unowned [[SELF_COPY]] :
+// -- TODO: A lot of fussy r/r traffic and owned/unowned conversions here.
+// -- strong +2, unowned +1
+// CHECK:         [[UNOWNED_SELF_COPY:%.*]] = copy_value [[UNOWNED_SELF]]
+// CHECK:         store [[UNOWNED_SELF_COPY]] to [init] [[PB]]
+// SEMANTIC ARC TODO: This destroy_value should probably be /after/ the load from PB on the next line.
+// CHECK:         destroy_value [[SELF_COPY]]
+// CHECK:         [[UNOWNED_SELF:%.*]] = load_borrow [[PB]]
+// -- strong +2, unowned +1
+// CHECK:         [[SELF:%.*]] = copy_unowned_value [[UNOWNED_SELF]]
+// CHECK:         end_borrow [[UNOWNED_SELF]] from [[PB]]
+// CHECK:         [[UNOWNED_SELF2:%.*]] = ref_to_unowned [[SELF]]
+// -- strong +2, unowned +2
+// CHECK:         [[UNOWNED_SELF2_COPY:%.*]] = copy_value [[UNOWNED_SELF2]]
+// -- strong +1, unowned +2
+// CHECK:         destroy_value [[SELF]]
+// -- closure takes unowned ownership
+// CHECK:         [[OUTER_CLOSURE:%.*]] = partial_apply [callee_guaranteed] {{%.*}}([[UNOWNED_SELF2_COPY]])
+// CHECK:         [[OUTER_CONVERT:%.*]] = convert_escape_to_noescape [[OUTER_CLOSURE]]
+// -- call consumes closure
+// -- strong +1, unowned +1
+// CHECK:         [[INNER_CLOSURE:%.*]] = apply [[OUTER_CONVERT]]
+// CHECK:         [[B:%.*]] = begin_borrow [[INNER_CLOSURE]]
+// CHECK:         [[CONSUMED_RESULT:%.*]] = apply [[B]]()
+// CHECK:         destroy_value [[CONSUMED_RESULT]]
+// CHECK:         destroy_value [[INNER_CLOSURE]]
+// -- destroy_values unowned self in box
+// -- strong +1, unowned +0
+// CHECK:         destroy_value [[OUTER_SELF_CAPTURE]]
+// -- strong +0, unowned +0
+// CHECK: } // end sil function '$S8closures24UnownedSelfNestedCaptureC06nestedE0{{[_0-9a-zA-Z]*}}F'
+
+// -- outer closure
+// -- strong +0, unowned +1
+// CHECK: sil private @[[OUTER_CLOSURE_FUN:\$S8closures24UnownedSelfNestedCaptureC06nestedE0yyFACycyXEfU_]] : $@convention(thin) (@guaranteed @sil_unowned UnownedSelfNestedCapture) -> @owned @callee_guaranteed () -> @owned UnownedSelfNestedCapture {
+// CHECK: bb0([[CAPTURED_SELF:%.*]] : @guaranteed $@sil_unowned UnownedSelfNestedCapture):
+// -- strong +0, unowned +2
+// CHECK:         [[CAPTURED_SELF_COPY:%.*]] = copy_value [[CAPTURED_SELF]] :
+// -- closure takes ownership of unowned ref
+// CHECK:         [[INNER_CLOSURE:%.*]] = partial_apply [callee_guaranteed] {{%.*}}([[CAPTURED_SELF_COPY]])
+// -- strong +0, unowned +1 (claimed by closure)
+// CHECK:         return [[INNER_CLOSURE]]
+// CHECK: } // end sil function '[[OUTER_CLOSURE_FUN]]'
+
+// -- inner closure
+// -- strong +0, unowned +1
+// CHECK: sil private @[[INNER_CLOSURE_FUN:\$S8closures24UnownedSelfNestedCaptureC06nestedE0yyFACycyXEfU_ACycfU_]] : $@convention(thin) (@guaranteed @sil_unowned UnownedSelfNestedCapture) -> @owned UnownedSelfNestedCapture {
+// CHECK: bb0([[CAPTURED_SELF:%.*]] : @guaranteed $@sil_unowned UnownedSelfNestedCapture):
+// -- strong +1, unowned +1
+// CHECK:         [[SELF:%.*]] = copy_unowned_value [[CAPTURED_SELF:%.*]] :
+// -- strong +1, unowned +0 (claimed by return)
+// CHECK:         return [[SELF]]
+// CHECK: } // end sil function '[[INNER_CLOSURE_FUN]]'
+class UnownedSelfNestedCapture {
+  func nestedCapture() {
+    {[unowned self] in { self } }()()
+  }
+}
+
+// Check that capturing 'self' via a 'super' call also captures the generic
+// signature if the base class is concrete and the derived class is generic
+
+class ConcreteBase {
+  func swim() {}
+}
+
+// CHECK-LABEL: sil private @$S8closures14GenericDerivedC4swimyyFyyXEfU_ : $@convention(thin) <Ocean> (@guaranteed GenericDerived<Ocean>) -> ()
+// CHECK: bb0([[ARG:%.*]] : @guaranteed $GenericDerived<Ocean>):
+// CHECK:   [[ARG_COPY:%.*]] = copy_value [[ARG]]
+// CHECK:   [[ARG_COPY_SUPER:%.*]] = upcast [[ARG_COPY]] : $GenericDerived<Ocean> to $ConcreteBase
+// CHECK:   [[BORROWED_ARG_COPY_SUPER:%.*]] = begin_borrow [[ARG_COPY_SUPER]]
+// CHECK:   [[METHOD:%.*]] = function_ref @$S8closures12ConcreteBaseC4swimyyF
+// CHECK:   apply [[METHOD]]([[BORROWED_ARG_COPY_SUPER]]) : $@convention(method) (@guaranteed ConcreteBase) -> ()
+// CHECK:   destroy_value [[ARG_COPY_SUPER]]
+// CHECK: } // end sil function '$S8closures14GenericDerivedC4swimyyFyyXEfU_'
+
+class GenericDerived<Ocean> : ConcreteBase {
+  override func swim() {
+    withFlotationAid {
+      super.swim()
+    }
+  }
+
+  func withFlotationAid(_ fn: () -> ()) {}
+}
+
+// Don't crash on this
+func r25993258_helper(_ fn: (inout Int, Int) -> ()) {}
+func r25993258() {
+  r25993258_helper { _ in () }
+}
+
+// rdar://29810997
+//
+// Using a let from a closure in an init was causing the type-checker
+// to produce invalid AST: 'self.fn' was an l-value, but 'self' was already
+// loaded to make an r-value.  This was ultimately because CSApply was
+// building the member reference correctly in the context of the closure,
+// where 'fn' is not settable, but CSGen / CSSimplify was processing it
+// in the general DC of the constraint system, i.e. the init, where
+// 'fn' *is* settable.
+func r29810997_helper(_ fn: (Int) -> Int) -> Int { return fn(0) }
+struct r29810997 {
+    private let fn: (Int) -> Int
+    private var x: Int
+
+    init(function: @escaping (Int) -> Int) {
+        fn = function
+        x = r29810997_helper { fn($0) }
+    }
+}
+
+//   DI will turn this into a direct capture of the specific stored property.
+// CHECK-LABEL: sil hidden @$S8closures16r29810997_helperyS3iXEF : $@convention(thin) (@noescape @callee_guaranteed (Int) -> Int) -> Int
diff --git a/test/SILGen/plus_zero_collection_downcast.swift b/test/SILGen/plus_zero_collection_downcast.swift
new file mode 100644
index 0000000..30f16af
--- /dev/null
+++ b/test/SILGen/plus_zero_collection_downcast.swift
@@ -0,0 +1,241 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -emit-silgen -sdk %S/Inputs -I %S/Inputs -enable-source-import %s | %FileCheck %s
+
+// REQUIRES: objc_interop
+
+import Foundation
+
+// FIXME: Should go into the standard library.
+public extension _ObjectiveCBridgeable {
+  static func _unconditionallyBridgeFromObjectiveC(_ source: _ObjectiveCType?)
+      -> Self {
+    var result: Self?
+    _forceBridgeFromObjectiveC(source!, result: &result)
+    return result!
+  }
+}
+
+class BridgedObjC : NSObject { }
+
+func == (x: BridgedObjC, y: BridgedObjC) -> Bool { return true }
+
+struct BridgedSwift : Hashable, _ObjectiveCBridgeable {
+  var hashValue: Int { return 0 }
+
+  func _bridgeToObjectiveC() -> BridgedObjC {
+    return BridgedObjC()
+  }
+
+  static func _forceBridgeFromObjectiveC(
+    _ x: BridgedObjC,
+    result: inout BridgedSwift?
+  ) {
+  }
+  static func _conditionallyBridgeFromObjectiveC(
+    _ x: BridgedObjC,
+    result: inout BridgedSwift?
+  ) -> Bool {
+    return true
+  }
+}
+
+func == (x: BridgedSwift, y: BridgedSwift) -> Bool { return true }
+
+// CHECK-LABEL: sil hidden @$S19collection_downcast17testArrayDowncast{{.*}}F
+// CHECK: bb0([[ARRAY:%[0-9]+]] : $Array<AnyObject>):
+func testArrayDowncast(_ array: [AnyObject]) -> [BridgedObjC] {
+  // CHECK: [[ARRAY_COPY:%.*]] = copy_value [[ARRAY]]
+  // CHECK: [[DOWNCAST_FN:%[0-9]+]] = function_ref @$Ss15_arrayForceCast{{.*}}F
+  // CHECK: apply [[DOWNCAST_FN]]<AnyObject, BridgedObjC>([[ARRAY_COPY]]) : $@convention(thin) <τ_0_0, τ_0_1> (@guaranteed Array<τ_0_0>) -> @owned Array<τ_0_1>
+  return array as! [BridgedObjC]
+}
+
+// CHECK-LABEL: sil hidden @$S19collection_downcast27testArrayDowncastFromObject{{.*}}F
+// CHECK: bb0([[OBJ:%[0-9]+]] : $AnyObject):
+func testArrayDowncastFromObject(_ obj: AnyObject) -> [BridgedObjC] {
+  // CHECK: unconditional_checked_cast_addr AnyObject in [[OBJECT_ALLOC:%[0-9]+]] : $*AnyObject to Array<BridgedObjC> in [[VALUE_ALLOC:%[0-9]+]] : $*Array<BridgedObjC>
+  return obj as! [BridgedObjC]
+}
+
+// CHECK-LABEL: sil hidden @$S19collection_downcast28testArrayDowncastFromNSArray{{.*}}F
+// CHECK: bb0([[NSARRAY_OBJ:%[0-9]+]] : $NSArray):
+func testArrayDowncastFromNSArray(_ obj: NSArray) -> [BridgedObjC] {
+  // CHECK: unconditional_checked_cast_addr NSArray in [[OBJECT_ALLOC:%[0-9]+]] : $*NSArray to Array<BridgedObjC> in [[VALUE_ALLOC:%[0-9]+]] : $*Array<BridgedObjC>
+  return obj as! [BridgedObjC]
+}
+
+// CHECK-LABEL: sil hidden @$S19collection_downcast28testArrayDowncastConditional{{.*}}F
+// CHECK: bb0([[ARRAY:%[0-9]+]] : $Array<AnyObject>):
+func testArrayDowncastConditional(_ array: [AnyObject]) -> [BridgedObjC]? {
+  // CHECK: [[ARRAY_COPY:%.*]] = copy_value [[ARRAY]]
+  // CHECK: [[DOWNCAST_FN:%[0-9]+]] = function_ref @$Ss21_arrayConditionalCast{{.*}}F
+  // CHECK: apply [[DOWNCAST_FN]]<AnyObject, BridgedObjC>([[ARRAY_COPY]]) : $@convention(thin) <τ_0_0, τ_0_1> (@guaranteed Array<τ_0_0>) -> @owned Optional<Array<τ_0_1>>
+  return array as? [BridgedObjC]
+}
+// CHECK: } // end sil function '$S19collection_downcast28testArrayDowncastConditional{{.*}}F'
+
+// CHECK-LABEL: sil hidden @$S19collection_downcast12testArrayIsa{{.*}}F
+// CHECK: bb0([[ARRAY:%[0-9]+]] : $Array<AnyObject>)
+func testArrayIsa(_ array: [AnyObject]) -> Bool {
+  // CHECK: [[ARRAY_COPY:%.*]] = copy_value [[ARRAY]]
+  // CHECK: [[DOWNCAST_FN:%[0-9]+]] = function_ref @$Ss21_arrayConditionalCast{{.*}}F
+  // CHECK: apply [[DOWNCAST_FN]]<AnyObject, BridgedObjC>([[ARRAY_COPY]]) : $@convention(thin) <τ_0_0, τ_0_1> (@guaranteed Array<τ_0_0>) -> @owned Optional<Array<τ_0_1>>
+  // CHECK-NOT: destroy_value [[ARRAY]]
+  return array is [BridgedObjC] ? true : false
+}
+
+// CHECK-LABEL: sil hidden @$S19collection_downcast24testArrayDowncastBridged{{.*}}F
+// CHECK: bb0([[ARRAY:%[0-9]+]] : $Array<AnyObject>):
+func testArrayDowncastBridged(_ array: [AnyObject]) -> [BridgedSwift] {
+  // CHECK: [[ARRAY_COPY:%.*]] = copy_value [[ARRAY]]
+  // CHECK: [[BRIDGE_FN:%[0-9]+]] = function_ref @$Ss15_arrayForceCast{{.*}}F
+  // CHECK: apply [[BRIDGE_FN]]<AnyObject, BridgedSwift>([[ARRAY_COPY]]) : $@convention(thin) <τ_0_0, τ_0_1> (@guaranteed Array<τ_0_0>) -> @owned Array<τ_0_1>
+  // CHECK-NOT: destroy_value [[ARRAY]]
+  return array as! [BridgedSwift]
+}
+
+// CHECK-LABEL: sil hidden @$S19collection_downcast35testArrayDowncastBridgedConditional{{.*}}F
+// CHECK: bb0([[ARRAY:%[0-9]+]] : $Array<AnyObject>):
+func testArrayDowncastBridgedConditional(_ array: [AnyObject]) -> [BridgedSwift]?{
+  // CHECK: [[ARRAY_COPY:%.*]] = copy_value [[ARRAY]]
+  // CHECK: [[BRIDGE_FN:%[0-9]+]] = function_ref @$Ss21_arrayConditionalCast{{.*}}F
+  // CHECK: apply [[BRIDGE_FN]]<AnyObject, BridgedSwift>([[ARRAY_COPY]]) : $@convention(thin) <τ_0_0, τ_0_1> (@guaranteed Array<τ_0_0>) -> @owned Optional<Array<τ_0_1>>
+  // CHECK-NOT: destroy_value [[ARRAY]]
+  return array as? [BridgedSwift]
+}
+
+// CHECK-LABEL: sil hidden @$S19collection_downcast19testArrayIsaBridged{{.*}}F
+// CHECK: bb0([[ARRAY:%[0-9]+]] : $Array<AnyObject>)
+func testArrayIsaBridged(_ array: [AnyObject]) -> Bool {
+  // CHECK: [[ARRAY_COPY:%.*]] = copy_value [[ARRAY]]
+  // CHECK: [[DOWNCAST_FN:%[0-9]+]] = function_ref @$Ss21_arrayConditionalCast{{.*}}F
+  // CHECK: apply [[DOWNCAST_FN]]<AnyObject, BridgedSwift>([[ARRAY_COPY]]) : $@convention(thin) <τ_0_0, τ_0_1> (@guaranteed Array<τ_0_0>) -> @owned Optional<Array<τ_0_1>>
+  // CHECK-NOT: destroy_value [[ARRAY]]
+  return array is [BridgedSwift] ? true : false
+}
+
+// CHECK-LABEL: sil hidden @$S19collection_downcast32testDictionaryDowncastFromObject{{.*}}F
+// CHECK: bb0([[OBJ:%[0-9]+]] : $AnyObject):
+func testDictionaryDowncastFromObject(_ obj: AnyObject) 
+       -> Dictionary<BridgedObjC, BridgedObjC> {
+  // CHECK: unconditional_checked_cast_addr AnyObject in [[OBJECT_ALLOC:%[0-9]+]] : $*AnyObject to Dictionary<BridgedObjC, BridgedObjC> in [[VALUE_ALLOC:%[0-9]+]] : $*Dictionary<BridgedObjC, BridgedObjC>
+  return obj as! Dictionary<BridgedObjC, BridgedObjC>
+}
+
+// CHECK-LABEL: sil hidden @$S19collection_downcast22testDictionaryDowncast{{.*}}F
+// CHECK: bb0([[DICT:%[0-9]+]] : $Dictionary<NSObject, AnyObject>)
+func testDictionaryDowncast(_ dict: Dictionary<NSObject, AnyObject>) 
+       -> Dictionary<BridgedObjC, BridgedObjC> {
+  // CHECK: [[DICT_COPY:%.*]] = copy_value [[DICT]]
+  // CHECK: [[DOWNCAST_FN:%[0-9]+]] = function_ref @$Ss19_dictionaryDownCast{{.*}}F
+  // CHECK: apply [[DOWNCAST_FN]]<NSObject, AnyObject, BridgedObjC, BridgedObjC>([[DICT_COPY]]) : $@convention(thin) <τ_0_0, τ_0_1, τ_0_2, τ_0_3 where τ_0_0 : Hashable, τ_0_2 : Hashable> (@guaranteed Dictionary<τ_0_0, τ_0_1>) -> @owned Dictionary<τ_0_2, τ_0_3>
+  // CHECK-NOT: destroy_value [[DICT]]
+  return dict as! Dictionary<BridgedObjC, BridgedObjC>
+}
+
+// CHECK-LABEL: sil hidden @$S19collection_downcast33testDictionaryDowncastConditional{{.*}}F
+// CHECK: bb0([[DICT:%[0-9]+]] : $Dictionary<NSObject, AnyObject>)
+func testDictionaryDowncastConditional(_ dict: Dictionary<NSObject, AnyObject>) 
+-> Dictionary<BridgedObjC, BridgedObjC>? {
+  // CHECK: [[DICT_COPY:%.*]] = copy_value [[DICT]]
+  // CHECK: [[DOWNCAST_FN:%[0-9]+]] = function_ref @$Ss30_dictionaryDownCastConditional{{.*}}F
+  // CHECK: apply [[DOWNCAST_FN]]<NSObject, AnyObject, BridgedObjC, BridgedObjC>([[DICT_COPY]]) : $@convention(thin) <τ_0_0, τ_0_1, τ_0_2, τ_0_3 where τ_0_0 : Hashable, τ_0_2 : Hashable> (@guaranteed Dictionary<τ_0_0, τ_0_1>) -> @owned Optional<Dictionary<τ_0_2, τ_0_3>>
+  // CHECK-NOT: destroy_value [[DICT]]
+  return dict as? Dictionary<BridgedObjC, BridgedObjC>
+}
+
+// CHECK-LABEL: sil hidden @$S19collection_downcast41testDictionaryDowncastBridgedVConditional{{.*}}F
+// CHECK: bb0([[DICT:%[0-9]+]] : $Dictionary<NSObject, AnyObject>)
+func testDictionaryDowncastBridgedVConditional(_ dict: Dictionary<NSObject, AnyObject>) 
+       -> Dictionary<BridgedObjC, BridgedSwift>? {
+  // CHECK: [[DICT_COPY:%.*]] = copy_value [[DICT]]
+  // CHECK: [[BRIDGE_FN:%[0-9]+]] = function_ref @$Ss30_dictionaryDownCastConditional{{.*}}F
+  // CHECK: apply [[BRIDGE_FN]]<NSObject, AnyObject, BridgedObjC, BridgedSwift>([[DICT_COPY]]) : $@convention(thin) <τ_0_0, τ_0_1, τ_0_2, τ_0_3 where τ_0_0 : Hashable, τ_0_2 : Hashable> (@guaranteed Dictionary<τ_0_0, τ_0_1>) -> @owned Optional<Dictionary<τ_0_2, τ_0_3>>{{.*}}
+  // CHECK-NOT: destroy_value [[DICT]]
+  return dict as? Dictionary<BridgedObjC, BridgedSwift>
+}
+
+// CHECK-LABEL: sil hidden @$S19collection_downcast41testDictionaryDowncastBridgedKConditional{{.*}}F
+// CHECK: bb0([[DICT:%[0-9]+]] : $Dictionary<NSObject, AnyObject>)
+func testDictionaryDowncastBridgedKConditional(_ dict: Dictionary<NSObject, AnyObject>) 
+-> Dictionary<BridgedSwift, BridgedObjC>? {
+  // CHECK: [[DICT_COPY:%.*]] = copy_value [[DICT]]
+  // CHECK: [[BRIDGE_FN:%[0-9]+]] = function_ref @$Ss30_dictionaryDownCastConditional{{.*}}F
+  // CHECK: apply [[BRIDGE_FN]]<NSObject, AnyObject, BridgedSwift, BridgedObjC>([[DICT_COPY]]) : $@convention(thin) <τ_0_0, τ_0_1, τ_0_2, τ_0_3 where τ_0_0 : Hashable, τ_0_2 : Hashable> (@guaranteed Dictionary<τ_0_0, τ_0_1>) -> @owned Optional<Dictionary<τ_0_2, τ_0_3>>
+  // CHECK-NOT: destroy_value [[DICT]]
+  return dict as? Dictionary<BridgedSwift, BridgedObjC>
+}
+
+// CHECK-LABEL: sil hidden @$S19collection_downcast31testDictionaryDowncastBridgedKV{{.*}}F
+// CHECK: bb0([[DICT:%[0-9]+]] : $Dictionary<NSObject, AnyObject>)
+func testDictionaryDowncastBridgedKV(_ dict: Dictionary<NSObject, AnyObject>) 
+-> Dictionary<BridgedSwift, BridgedSwift> {
+  // CHECK: [[DICT_COPY:%.*]] = copy_value [[DICT]]
+  // CHECK: [[BRIDGE_FN:%[0-9]+]] = function_ref @$Ss19_dictionaryDownCast{{.*}}F
+  // CHECK: apply [[BRIDGE_FN]]<NSObject, AnyObject, BridgedSwift, BridgedSwift>([[DICT_COPY]]) : $@convention(thin) <τ_0_0, τ_0_1, τ_0_2, τ_0_3 where τ_0_0 : Hashable, τ_0_2 : Hashable> (@guaranteed Dictionary<τ_0_0, τ_0_1>) -> @owned Dictionary<τ_0_2, τ_0_3>
+  // CHECK-NOT: destroy_value [[DICT]]
+  return dict as! Dictionary<BridgedSwift, BridgedSwift>
+}
+
+// CHECK-LABEL: sil hidden @$S19collection_downcast42testDictionaryDowncastBridgedKVConditional{{.*}}F
+// CHECK: bb0([[DICT:%[0-9]+]] : $Dictionary<NSObject, AnyObject>)
+func testDictionaryDowncastBridgedKVConditional(_ dict: Dictionary<NSObject, AnyObject>) 
+       -> Dictionary<BridgedSwift, BridgedSwift>? {
+  // CHECK: [[DICT_COPY:%.*]] = copy_value [[DICT]]
+  // CHECK: [[BRIDGE_FN:%[0-9]+]] = function_ref @$Ss30_dictionaryDownCastConditional{{.*}}F
+  // CHECK: apply [[BRIDGE_FN]]<NSObject, AnyObject, BridgedSwift, BridgedSwift>([[DICT_COPY]]) : $@convention(thin) <τ_0_0, τ_0_1, τ_0_2, τ_0_3 where τ_0_0 : Hashable, τ_0_2 : Hashable> (@guaranteed Dictionary<τ_0_0, τ_0_1>) -> @owned Optional<Dictionary<τ_0_2, τ_0_3>>
+  // CHECK-NOT: destroy_value [[DICT]]
+  return dict as? Dictionary<BridgedSwift, BridgedSwift>
+}
+
+// CHECK-LABEL: sil hidden @$S19collection_downcast25testSetDowncastFromObject{{.*}}F
+// CHECK: bb0([[OBJ:%[0-9]+]] : $AnyObject):
+func testSetDowncastFromObject(_ obj: AnyObject) 
+       -> Set<BridgedObjC> {
+  // CHECK: unconditional_checked_cast_addr AnyObject in [[OBJECT_ALLOC:%[0-9]+]] : $*AnyObject to Set<BridgedObjC> in [[VALUE_ALLOC:%[0-9]+]] : $*Set<BridgedObjC>
+  return obj as! Set<BridgedObjC>
+}
+
+// CHECK-LABEL: sil hidden @$S19collection_downcast15testSetDowncast{{.*}}F
+// CHECK: bb0([[SET:%[0-9]+]] : $Set<NSObject>)
+func testSetDowncast(_ dict: Set<NSObject>) 
+       -> Set<BridgedObjC> {
+  // CHECK: [[SET_COPY:%.*]] = copy_value [[SET]]
+  // CHECK: [[DOWNCAST_FN:%[0-9]+]] = function_ref @$Ss12_setDownCast{{.*}}F
+  // CHECK: apply [[DOWNCAST_FN]]<NSObject, BridgedObjC>([[SET_COPY]]) : $@convention(thin) <τ_0_0, τ_0_1 where τ_0_0 : Hashable, τ_0_1 : Hashable> (@guaranteed Set<τ_0_0>) -> @owned Set<τ_0_1>
+  // CHECK-NOT: destroy_value [[SET]]
+  return dict as! Set<BridgedObjC>
+}
+
+// CHECK-LABEL: sil hidden @$S19collection_downcast26testSetDowncastConditional{{.*}}F
+// CHECK: bb0([[SET:%[0-9]+]] : $Set<NSObject>)
+func testSetDowncastConditional(_ dict: Set<NSObject>) 
+       -> Set<BridgedObjC>? {
+  // CHECK: [[SET_COPY:%.*]] = copy_value [[SET]]
+  // CHECK: [[DOWNCAST_FN:%[0-9]+]] = function_ref @$Ss23_setDownCastConditional{{.*}}F
+  // CHECK: apply [[DOWNCAST_FN]]<NSObject, BridgedObjC>([[SET_COPY]]) : $@convention(thin) <τ_0_0, τ_0_1 where τ_0_0 : Hashable, τ_0_1 : Hashable> (@guaranteed Set<τ_0_0>) -> @owned Optional<Set<τ_0_1>>
+  // CHECK-NOT: destroy_value [[SET]]
+  return dict as? Set<BridgedObjC>
+}
+
+// CHECK-LABEL: sil hidden @$S19collection_downcast22testSetDowncastBridged{{.*}}F
+// CHECK: bb0([[SET:%[0-9]+]] : $Set<NSObject>)
+func testSetDowncastBridged(_ dict: Set<NSObject>) 
+       -> Set<BridgedSwift> {
+  // CHECK: [[SET_COPY:%.*]] = copy_value [[SET]]
+  // CHECK: [[DOWNCAST_FN:%[0-9]+]] = function_ref @$Ss12_setDownCast{{.*}}F
+  // CHECK: apply [[DOWNCAST_FN]]<NSObject, BridgedSwift>([[SET_COPY]]) : $@convention(thin) <τ_0_0, τ_0_1 where τ_0_0 : Hashable, τ_0_1 : Hashable> (@guaranteed Set<τ_0_0>) -> @owned Set<τ_0_1>
+  // CHECK-NOT: destroy_value [[SET]]
+  return dict as! Set<BridgedSwift>
+}
+
+// CHECK-LABEL: sil hidden @$S19collection_downcast33testSetDowncastBridgedConditional{{.*}}F
+// CHECK: bb0([[SET:%[0-9]+]] : $Set<NSObject>)
+func testSetDowncastBridgedConditional(_ dict: Set<NSObject>) 
+       -> Set<BridgedSwift>? {
+  // CHECK: [[SET_COPY:%.*]] = copy_value [[SET]]
+  // CHECK: [[DOWNCAST_FN:%[0-9]+]] = function_ref @$Ss23_setDownCastConditional{{.*}}F
+  // CHECK: apply [[DOWNCAST_FN]]<NSObject, BridgedSwift>([[SET_COPY]]) : $@convention(thin) <τ_0_0, τ_0_1 where τ_0_0 : Hashable, τ_0_1 : Hashable> (@guaranteed Set<τ_0_0>) -> @owned Optional<Set<τ_0_1>>
+  // CHECK-NOT: destroy_value [[SET]]
+  return dict as? Set<BridgedSwift>
+}
diff --git a/test/SILGen/plus_zero_collection_subtype_downcast.swift b/test/SILGen/plus_zero_collection_subtype_downcast.swift
new file mode 100644
index 0000000..251eb9e
--- /dev/null
+++ b/test/SILGen/plus_zero_collection_subtype_downcast.swift
@@ -0,0 +1,47 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership -sdk %S/Inputs %s | %FileCheck %s
+
+struct S { var x, y: Int }
+
+// CHECK-LABEL: sil hidden @$S27collection_subtype_downcast06array_C00D0SayAA1SVGSgSayypG_tF :
+// CHECK:    bb0([[ARG:%.*]] : @guaranteed $Array<Any>):
+// CHECK-NEXT: debug_value [[ARG]]
+// CHECK-NEXT: [[ARG_COPY:%.*]] = copy_value [[ARG]]
+// CHECK-NEXT: // function_ref
+// CHECK-NEXT: [[FN:%.*]] = function_ref @$Ss21_arrayConditionalCastySayq_GSgSayxGr0_lF
+// CHECK-NEXT: [[BORROWED_ARG_COPY:%.*]] = begin_borrow [[ARG_COPY]]
+// CHECK-NEXT: [[RESULT:%.*]] = apply [[FN]]<Any, S>([[BORROWED_ARG_COPY]]) : $@convention(thin) <τ_0_0, τ_0_1> (@guaranteed Array<τ_0_0>) -> @owned Optional<Array<τ_0_1>>
+// CHECK-NEXT: end_borrow
+// CHECK-NEXT: destroy_value [[ARG_COPY]]
+// CHECK-NEXT: return [[RESULT]]
+func array_downcast(array: [Any]) -> [S]? {
+  return array as? [S]
+}
+
+extension S : Hashable {
+  var hashValue : Int {
+    return x + y
+  }
+}
+func ==(lhs: S, rhs: S) -> Bool {
+  return true
+}
+
+// FIXME: This entrypoint name should not be bridging-specific
+// CHECK-LABEL:      sil hidden @$S27collection_subtype_downcast05dict_C00D0s10DictionaryVyAA1SVSiGSgAEyAGypG_tF :
+// CHECK:    bb0([[ARG:%.*]] : @guaranteed $Dictionary<S, Any>):
+// CHECK: debug_value [[ARG]]
+// CHECK: [[ARG_COPY:%.*]] = copy_value [[ARG]]
+// CHECK: // function_ref
+// CHECK: [[FN:%.*]] = function_ref @$Ss30_dictionaryDownCastConditionalys10DictionaryVyq0_q1_GSgACyxq_Gs8HashableRzsAGR0_r2_lF
+// CHECK: [[BORROWED_ARG_COPY:%.*]] = begin_borrow [[ARG_COPY]]
+// CHECK: [[RESULT:%.*]] = apply [[FN]]<S, Any, S, Int>([[BORROWED_ARG_COPY]]) : $@convention(thin) <τ_0_0, τ_0_1, τ_0_2, τ_0_3 where τ_0_0 : Hashable, τ_0_2 : Hashable> (@guaranteed Dictionary<τ_0_0, τ_0_1>) -> @owned Optional<Dictionary<τ_0_2, τ_0_3>>
+// CHECK: end_borrow [[BORROWED_ARG_COPY]] from [[ARG_COPY]]
+// CHECK: destroy_value [[ARG_COPY]]
+// CHECK: return [[RESULT]]
+func dict_downcast(dict: [S: Any]) -> [S: Int]? {
+  return dict as? [S: Int]
+}
+
+// It's not actually possible to test this for Sets independent of
+// the bridging rules.
diff --git a/test/SILGen/plus_zero_collection_subtype_upcast.swift b/test/SILGen/plus_zero_collection_subtype_upcast.swift
new file mode 100644
index 0000000..a0d1a13
--- /dev/null
+++ b/test/SILGen/plus_zero_collection_subtype_upcast.swift
@@ -0,0 +1,46 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership -sdk %S/Inputs %s | %FileCheck %s
+
+struct S { var x, y: Int }
+
+// CHECK-LABEL: sil hidden @$S25collection_subtype_upcast06array_C00D0SayypGSayAA1SVG_tF :
+// CHECK:    bb0([[ARG:%.*]] : @guaranteed $Array<S>):
+// CHECK: debug_value [[ARG]]
+// CHECK: [[ARG_COPY:%.*]] = copy_value [[ARG]]
+// CHECK: // function_ref
+// CHECK: [[FN:%.*]] = function_ref @$Ss15_arrayForceCastySayq_GSayxGr0_lF
+// CHECK: [[BORROWED_ARG_COPY:%.*]] = begin_borrow [[ARG_COPY]]
+// CHECK: [[RESULT:%.*]] = apply [[FN]]<S, Any>([[BORROWED_ARG_COPY]]) : $@convention(thin) <τ_0_0, τ_0_1> (@guaranteed Array<τ_0_0>) -> @owned Array<τ_0_1>
+// CHECK: end_borrow [[BORROWED_ARG_COPY]] from [[ARG_COPY]]
+// CHECK: destroy_value [[ARG_COPY]]
+// CHECK: return [[RESULT]]
+func array_upcast(array: [S]) -> [Any] {
+  return array
+}
+
+extension S : Hashable {
+  var hashValue : Int {
+    return x + y
+  }
+}
+func ==(lhs: S, rhs: S) -> Bool {
+  return true
+}
+
+// FIXME: This entrypoint name should not be bridging-specific
+// CHECK-LABEL:      sil hidden @$S25collection_subtype_upcast05dict_C00D0s10DictionaryVyAA1SVypGAEyAGSiG_tF :
+// CHECK:    bb0([[ARG:%.*]] : @guaranteed $Dictionary<S, Int>):
+// CHECK: debug_value [[ARG]]
+// CHECK: [[ARG_COPY:%.*]] = copy_value [[ARG]]
+// CHECK: // function_ref
+// CHECK: [[FN:%.*]] = function_ref @$Ss17_dictionaryUpCastys10DictionaryVyq0_q1_GACyxq_Gs8HashableRzsAFR0_r2_lF
+// CHECK: [[BORROWED_ARG_COPY:%.*]] = begin_borrow [[ARG_COPY]]
+// CHECK: [[RESULT:%.*]] = apply [[FN]]<S, Int, S, Any>([[BORROWED_ARG_COPY]]) : $@convention(thin) <τ_0_0, τ_0_1, τ_0_2, τ_0_3 where τ_0_0 : Hashable, τ_0_2 : Hashable> (@guaranteed Dictionary<τ_0_0, τ_0_1>) -> @owned Dictionary<τ_0_2, τ_0_3>
+// CHECK: destroy_value [[ARG_COPY]]
+// CHECK: return [[RESULT]]
+func dict_upcast(dict: [S: Int]) -> [S: Any] {
+  return dict
+}
+
+// It's not actually possible to test this for Sets independent of
+// the bridging rules.
diff --git a/test/SILGen/plus_zero_collection_upcast.swift b/test/SILGen/plus_zero_collection_upcast.swift
new file mode 100644
index 0000000..c0bb574
--- /dev/null
+++ b/test/SILGen/plus_zero_collection_upcast.swift
@@ -0,0 +1,111 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -emit-silgen -sdk %S/Inputs -I %S/Inputs -enable-source-import %s | %FileCheck %s
+
+// FIXME: rdar://problem/19648117 Needs splitting objc parts out
+// XFAIL: linux
+
+import Foundation
+
+// FIXME: Should go into the standard library.
+public extension _ObjectiveCBridgeable {
+  static func _unconditionallyBridgeFromObjectiveC(_ source: _ObjectiveCType?)
+      -> Self {
+    var result: Self?
+    _forceBridgeFromObjectiveC(source!, result: &result)
+    return result!
+  }
+}
+
+class BridgedObjC : NSObject { }
+
+func == (x: BridgedObjC, y: BridgedObjC) -> Bool { return true }
+
+struct BridgedSwift : Hashable, _ObjectiveCBridgeable {
+  var hashValue: Int { return 0 }
+
+  func _bridgeToObjectiveC() -> BridgedObjC {
+    return BridgedObjC()
+  }
+
+  static func _forceBridgeFromObjectiveC(
+    _ x: BridgedObjC,
+    result: inout BridgedSwift?
+  ) {
+  }
+  static func _conditionallyBridgeFromObjectiveC(
+    _ x: BridgedObjC,
+    result: inout BridgedSwift?
+  ) -> Bool {
+    return true
+  }
+}
+
+func == (x: BridgedSwift, y: BridgedSwift) -> Bool { return true }
+
+// CHECK-LABEL: sil hidden @$S17collection_upcast15testArrayUpcast{{.*}}F :
+// CHECK: bb0([[ARRAY:%[0-9]+]] : $Array<BridgedObjC>): 
+func testArrayUpcast(_ array: [BridgedObjC]) {
+  // CHECK: [[ARRAY_COPY:%.*]] = copy_value [[ARRAY]]
+  // CHECK: [[UPCAST_FN:%[0-9]+]] = function_ref @$Ss15_arrayForceCast{{.*}}F : $@convention(thin) <τ_0_0, τ_0_1> (@guaranteed Array<τ_0_0>) -> @owned Array<τ_0_1>
+  // CHECK: [[RESULT:%.*]] = apply [[UPCAST_FN]]<BridgedObjC, AnyObject>([[ARRAY_COPY]]) : $@convention(thin) <τ_0_0, τ_0_1> (@guaranteed Array<τ_0_0>) -> @owned Array<τ_0_1>
+  // CHECK: destroy_value [[RESULT]]
+  // CHECK-NOT: destroy_value [[ARRAY]]
+  let anyObjectArr: [AnyObject] = array
+}
+// CHECK: } // end sil function '$S17collection_upcast15testArrayUpcast{{.*}}F'
+
+// CHECK-LABEL: sil hidden @$S17collection_upcast22testArrayUpcastBridged{{.*}}F
+// CHECK: bb0([[ARRAY:%[0-9]+]] : $Array<BridgedSwift>):
+func testArrayUpcastBridged(_ array: [BridgedSwift]) {
+  // CHECK: [[ARRAY_COPY:%.*]] = copy_value [[ARRAY]]
+  // CHECK: [[BRIDGE_FN:%[0-9]+]] = function_ref @$Ss15_arrayForceCast{{.*}}F : $@convention(thin) <τ_0_0, τ_0_1> (@guaranteed Array<τ_0_0>) -> @owned Array<τ_0_1>
+  // CHECK: [[RESULT:%.*]] = apply [[BRIDGE_FN]]<BridgedSwift, AnyObject>([[ARRAY_COPY]]) : $@convention(thin) <τ_0_0, τ_0_1> (@guaranteed Array<τ_0_0>) -> @owned Array<τ_0_1>
+  // CHECK: destroy_value [[RESULT]]
+  // CHECK-NOT: destroy_value [[ARRAY]]
+  let anyObjectArr = array as [AnyObject]
+}
+// CHECK: } // end sil function '$S17collection_upcast22testArrayUpcastBridged{{.*}}F'
+
+// CHECK-LABEL: sil hidden @$S17collection_upcast20testDictionaryUpcast{{.*}}F
+// CHECK: bb0([[DICT:%[0-9]+]] : $Dictionary<BridgedObjC, BridgedObjC>):
+func testDictionaryUpcast(_ dict: Dictionary<BridgedObjC, BridgedObjC>) {
+  // CHECK: [[DICT_COPY:%.*]] = copy_value [[DICT]]
+  // CHECK: [[UPCAST_FN:%[0-9]+]] = function_ref @$Ss17_dictionaryUpCast{{.*}}F : $@convention(thin) <τ_0_0, τ_0_1, τ_0_2, τ_0_3 where τ_0_0 : Hashable, τ_0_2 : Hashable> (@guaranteed Dictionary<τ_0_0, τ_0_1>) -> @owned Dictionary<τ_0_2, τ_0_3>
+  // CHECK: [[RESULT:%.*]] = apply [[UPCAST_FN]]<BridgedObjC, BridgedObjC, NSObject, AnyObject>([[DICT_COPY]]) : $@convention(thin) <τ_0_0, τ_0_1, τ_0_2, τ_0_3 where τ_0_0 : Hashable, τ_0_2 : Hashable> (@guaranteed Dictionary<τ_0_0, τ_0_1>) -> @owned Dictionary<τ_0_2, τ_0_3>
+  // CHECK: destroy_value [[RESULT]]
+  // CHECK-NOT: destroy_value [[DICT]]
+  let anyObjectDict: Dictionary<NSObject, AnyObject> = dict
+}
+
+// CHECK-LABEL: sil hidden @$S17collection_upcast27testDictionaryUpcastBridged{{.*}}F
+// CHECK: bb0([[DICT:%[0-9]+]] : $Dictionary<BridgedSwift, BridgedSwift>):
+func testDictionaryUpcastBridged(_ dict: Dictionary<BridgedSwift, BridgedSwift>) {
+  // CHECK: [[DICT_COPY:%.*]] = copy_value [[DICT]]
+  // CHECK: [[BRIDGE_FN:%[0-9]+]] = function_ref @$Ss17_dictionaryUpCast{{.*}}F
+  // CHECK: [[RESULT:%.*]] = apply [[BRIDGE_FN]]<BridgedSwift, BridgedSwift, NSObject, AnyObject>([[DICT_COPY]]) : $@convention(thin) <τ_0_0, τ_0_1, τ_0_2, τ_0_3 where τ_0_0 : Hashable, τ_0_2 : Hashable> (@guaranteed Dictionary<τ_0_0, τ_0_1>) -> @owned Dictionary<τ_0_2, τ_0_3>
+  // CHECK: destroy_value [[RESULT]]
+  // CHECK-NOT: destroy_value [[DICT]]
+  let anyObjectDict = dict as Dictionary<NSObject, AnyObject>
+}
+
+// CHECK-LABEL: sil hidden @$S17collection_upcast13testSetUpcast{{.*}}F
+// CHECK: bb0([[SET:%[0-9]+]] : $Set<BridgedObjC>):
+func testSetUpcast(_ dict: Set<BridgedObjC>) {
+  // CHECK: [[SET_COPY:%.*]] = copy_value [[SET]]
+  // CHECK: [[BRIDGE_FN:%[0-9]+]] = function_ref @$Ss10_setUpCast{{.*}}F : $@convention(thin) <τ_0_0, τ_0_1 where τ_0_0 : Hashable, τ_0_1 : Hashable> (@guaranteed Set<τ_0_0>) -> @owned Set<τ_0_1>
+  // CHECK: [[RESULT:%.*]] = apply [[BRIDGE_FN]]<BridgedObjC, NSObject>([[SET_COPY]]) : $@convention(thin) <τ_0_0, τ_0_1 where τ_0_0 : Hashable, τ_0_1 : Hashable> (@guaranteed Set<τ_0_0>) -> @owned Set<τ_0_1>
+  // CHECK: destroy_value [[RESULT]]
+  // CHECK-NOT: destroy_value [[SET]]
+  let anyObjectSet: Set<NSObject> = dict
+}
+
+// CHECK-LABEL: sil hidden @$S17collection_upcast20testSetUpcastBridged{{.*}}F
+// CHECK: bb0([[SET:%.*]] : $Set<BridgedSwift>):
+func testSetUpcastBridged(_ set: Set<BridgedSwift>) {
+  // CHECK: [[SET_COPY:%.*]] = copy_value [[SET]]
+  // CHECK: [[BRIDGE_FN:%[0-9]+]] = function_ref @$Ss10_setUpCast{{.*}}F
+  // CHECK: [[RESULT:%.*]] = apply [[BRIDGE_FN]]<BridgedSwift, NSObject>([[SET_COPY]]) : $@convention(thin) <τ_0_0, τ_0_1 where τ_0_0 : Hashable, τ_0_1 : Hashable> (@guaranteed Set<τ_0_0>) -> @owned Set<τ_0_1>
+  // CHECK: destroy_value [[RESULT]]
+  // CHECK-NOT: destroy_value [[SET]]
+  let anyObjectSet = set as Set<NSObject>
+}
diff --git a/test/SILGen/plus_zero_constrained_extensions.swift b/test/SILGen/plus_zero_constrained_extensions.swift
new file mode 100644
index 0000000..c925a1e
--- /dev/null
+++ b/test/SILGen/plus_zero_constrained_extensions.swift
@@ -0,0 +1,226 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership -primary-file %s | %FileCheck %s
+// RUN: %target-swift-frontend -emit-sil -O -primary-file %s > /dev/null
+// RUN: %target-swift-frontend -emit-ir -primary-file %s > /dev/null
+
+extension Array where Element == Int {
+  // CHECK-LABEL: sil @$SSa22constrained_extensionsSiRszlE1xSaySiGyt_tcfC : $@convention(method) (@thin Array<Int>.Type) -> @owned Array<Int>
+  public init(x: ()) {
+    self.init()
+  }
+
+  // CHECK-LABEL: sil @$SSa22constrained_extensionsSiRszlE16instancePropertySivg : $@convention(method) (@guaranteed Array<Int>) -> Int
+  // CHECK-LABEL: sil @$SSa22constrained_extensionsSiRszlE16instancePropertySivs : $@convention(method) (Int, @inout Array<Int>) -> ()
+  // CHECK-LABEL: sil shared [transparent] [serialized] @$SSa22constrained_extensionsSiRszlE16instancePropertySivmytfU_ : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout Array<Int>, @thick Array<Int>.Type) -> ()
+  // CHECK-LABEL: sil [transparent] [serialized] @$SSa22constrained_extensionsSiRszlE16instancePropertySivm : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout Array<Int>) -> (Builtin.RawPointer, Optional<Builtin.RawPointer>)
+
+  public var instanceProperty: Element {
+    get {
+      return self[0]
+    }
+    set {
+      self[0] = newValue
+    }
+  }
+
+  // CHECK-LABEL: sil @$SSa22constrained_extensionsSiRszlE14instanceMethodSiyF : $@convention(method) (@guaranteed Array<Int>) -> Int
+  public func instanceMethod() -> Element {
+    return instanceProperty
+  }
+
+  // CHECK-LABEL: sil @$SSa22constrained_extensionsSiRszlE14instanceMethod1eS2i_tF : $@convention(method) (Int, @guaranteed Array<Int>) -> Int
+  public func instanceMethod(e: Element) -> Element {
+    return e
+  }
+
+  // CHECK-LABEL: sil @$SSa22constrained_extensionsSiRszlE14staticPropertySivgZ : $@convention(method) (@thin Array<Int>.Type) -> Int
+  public static var staticProperty: Element {
+    return Array(x: ()).instanceProperty
+  }
+
+  // CHECK-LABEL: sil @$SSa22constrained_extensionsSiRszlE12staticMethodSiyFZ : $@convention(method) (@thin Array<Int>.Type) -> Int
+  public static func staticMethod() -> Element {
+    return staticProperty
+  }
+
+  // CHECK-LABEL: sil @$SSa22constrained_extensionsSiRszlE12staticMethod1eS2iSg_tFZfA_ : $@convention(thin) () -> Optional<Int>
+  // CHECK-LABEL: sil @$SSa22constrained_extensionsSiRszlE12staticMethod1eS2iSg_tFZ : $@convention(method) (Optional<Int>, @thin Array<Int>.Type) -> Int
+  public static func staticMethod(e: Element? = nil) -> Element {
+    return e!
+  }
+
+  // CHECK-LABEL: sil @$SSa22constrained_extensionsSiRszlEySiyt_tcig : $@convention(method) (@guaranteed Array<Int>) -> Int
+  public subscript(i: ()) -> Element {
+    return self[0]
+  }
+
+  // CHECK-LABEL: sil @$SSa22constrained_extensionsSiRszlE21inoutAccessOfPropertyyyF : $@convention(method) (@inout Array<Int>) -> ()
+  public mutating func inoutAccessOfProperty() {
+    func increment(x: inout Element) {
+      x += 1
+    }
+
+    increment(x: &instanceProperty)
+  }
+}
+
+extension Dictionary where Key == Int {
+  // CHECK-LABEL: sil @$Ss10DictionaryV22constrained_extensionsSiRszrlE1xABySiq_Gyt_tcfC : $@convention(method) <Key, Value where Key == Int> (@thin Dictionary<Int, Value>.Type) -> @owned Dictionary<Int, Value> {
+  public init(x: ()) {
+    self.init()
+  }
+
+  // CHECK-LABEL: sil @$Ss10DictionaryV22constrained_extensionsSiRszrlE16instancePropertyq_vg : $@convention(method) <Key, Value where Key == Int> (@guaranteed Dictionary<Int, Value>) -> @out Value
+  // CHECK-LABEL: sil @$Ss10DictionaryV22constrained_extensionsSiRszrlE16instancePropertyq_vs : $@convention(method) <Key, Value where Key == Int> (@in Value, @inout Dictionary<Int, Value>) -> ()
+  // CHECK-LABEL: sil shared [transparent] [serialized] @$Ss10DictionaryV22constrained_extensionsSiRszrlE16instancePropertyq_vmytfU_ : $@convention(method) <Key, Value where Key == Int> (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout Dictionary<Int, Value>, @thick Dictionary<Int, Value>.Type) -> ()
+  // CHECK-LABEL: sil [transparent] [serialized] @$Ss10DictionaryV22constrained_extensionsSiRszrlE16instancePropertyq_vm : $@convention(method) <Key, Value where Key == Int> (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout Dictionary<Int, Value>) -> (Builtin.RawPointer, Optional<Builtin.RawPointer>)
+  public var instanceProperty: Value {
+    get {
+      return self[0]!
+    }
+    set {
+      self[0] = newValue
+    }
+  }
+
+  // CHECK-LABEL: sil @$Ss10DictionaryV22constrained_extensionsSiRszrlE14instanceMethodq_yF : $@convention(method) <Key, Value where Key == Int> (@guaranteed Dictionary<Int, Value>) -> @out Value
+  public func instanceMethod() -> Value {
+    return instanceProperty
+  }
+
+  // CHECK-LABEL: sil @$Ss10DictionaryV22constrained_extensionsSiRszrlE14instanceMethod1vq_q__tF : $@convention(method) <Key, Value where Key == Int> (@in_guaranteed Value, @guaranteed Dictionary<Int, Value>) -> @out Value
+  public func instanceMethod(v: Value) -> Value {
+    return v
+  }
+
+  // CHECK-LABEL: sil @$Ss10DictionaryV22constrained_extensionsSiRszrlE12staticMethodSiyFZ : $@convention(method) <Key, Value where Key == Int> (@thin Dictionary<Int, Value>.Type) -> Int
+  public static func staticMethod() -> Key {
+    return staticProperty
+  }
+
+  // CHECK-LABEL: sil @$Ss10DictionaryV22constrained_extensionsSiRszrlE14staticPropertySivgZ : $@convention(method) <Key, Value where Key == Int> (@thin Dictionary<Int, Value>.Type) -> Int
+  public static var staticProperty: Key {
+    return 0
+  }
+
+  // CHECK-LABEL: sil @$Ss10DictionaryV22constrained_extensionsSiRszrlE12staticMethod1k1vq_SiSg_q_SgtFZfA_ : $@convention(thin) <Key, Value where Key == Int> () -> Optional<Int>
+  // CHECK-LABEL: sil @$Ss10DictionaryV22constrained_extensionsSiRszrlE12staticMethod1k1vq_SiSg_q_SgtFZfA0_ : $@convention(thin) <Key, Value where Key == Int> () -> @out Optional<Value>
+  // CHECK-LABEL: sil @$Ss10DictionaryV22constrained_extensionsSiRszrlE12staticMethod1k1vq_SiSg_q_SgtFZ : $@convention(method) <Key, Value where Key == Int> (Optional<Int>, @in_guaranteed Optional<Value>, @thin Dictionary<Int, Value>.Type) -> @out Value
+  public static func staticMethod(k: Key? = nil, v: Value? = nil) -> Value {
+    return v!
+  }
+
+  // CHECK-LABEL: sil @$Ss10DictionaryV22constrained_extensionsSiRszrlE17callsStaticMethodq_yFZ : $@convention(method) <Key, Value where Key == Int> (@thin Dictionary<Int, Value>.Type) -> @out Value
+  public static func callsStaticMethod() -> Value {
+    return staticMethod()
+  }
+
+  // CHECK-LABEL: sil @$Ss10DictionaryV22constrained_extensionsSiRszrlE16callsConstructorq_yFZ : $@convention(method) <Key, Value where Key == Int> (@thin Dictionary<Int, Value>.Type) -> @out Value
+  public static func callsConstructor() -> Value {
+    return Dictionary(x: ()).instanceMethod()
+  }
+
+  // CHECK-LABEL: sil @$Ss10DictionaryV22constrained_extensionsSiRszrlEyq_yt_tcig : $@convention(method) <Key, Value where Key == Int> (@guaranteed Dictionary<Int, Value>) -> @out Value
+  public subscript(i: ()) -> Value {
+    return self[0]!
+  }
+
+  // CHECK-LABEL: sil @$Ss10DictionaryV22constrained_extensionsSiRszrlE21inoutAccessOfPropertyyyF : $@convention(method) <Key, Value where Key == Int> (@inout Dictionary<Int, Value>) -> ()
+  public mutating func inoutAccessOfProperty() {
+    func increment(x: inout Value) { }
+
+    increment(x: &instanceProperty)
+  }
+}
+
+public class GenericClass<X, Y> {}
+
+extension GenericClass where Y == () {
+  // CHECK-LABEL: sil @$S22constrained_extensions12GenericClassCAAytRs_rlE5valuexvg : $@convention(method) <X, Y where Y == ()> (@guaranteed GenericClass<X, ()>) -> @out X
+  // CHECK-LABEL: sil @$S22constrained_extensions12GenericClassCAAytRs_rlE5valuexvs : $@convention(method) <X, Y where Y == ()> (@in X, @guaranteed GenericClass<X, ()>) -> ()
+  // CHECK-LABEL: sil shared [transparent] [serialized] @$S22constrained_extensions12GenericClassCAAytRs_rlE5valuexvmytfU_ : $@convention(method) <X, Y where Y == ()> (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout GenericClass<X, ()>, @thick GenericClass<X, ()>.Type) -> ()
+  // CHECK-LABEL: sil [transparent] [serialized] @$S22constrained_extensions12GenericClassCAAytRs_rlE5valuexvm : $@convention(method) <X, Y where Y == ()> (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @guaranteed GenericClass<X, ()>) -> (Builtin.RawPointer, Optional<Builtin.RawPointer>)
+  public var value: X {
+    get { while true {} }
+    set {}
+  }
+
+  // CHECK-LABEL: sil @$S22constrained_extensions12GenericClassCAAytRs_rlE5emptyytvg : $@convention(method) <X, Y where Y == ()> (@guaranteed GenericClass<X, ()>) -> ()
+  // CHECK-LABEL: sil @$S22constrained_extensions12GenericClassCAAytRs_rlE5emptyytvs : $@convention(method) <X, Y where Y == ()> (@guaranteed GenericClass<X, ()>) -> ()
+  // CHECK-LABEL: sil shared [transparent] [serialized] @$S22constrained_extensions12GenericClassCAAytRs_rlE5emptyytvmytfU_ : $@convention(method) <X, Y where Y == ()> (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout GenericClass<X, ()>, @thick GenericClass<X, ()>.Type) -> ()
+  // CHECK-LABEL: sil [transparent] [serialized] @$S22constrained_extensions12GenericClassCAAytRs_rlE5emptyytvm : $@convention(method) <X, Y where Y == ()> (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @guaranteed GenericClass<X, ()>) -> (Builtin.RawPointer, Optional<Builtin.RawPointer>)
+  public var empty: Y {
+    get { return () }
+    set {}
+  }
+
+  // CHECK-LABEL: sil @$S22constrained_extensions12GenericClassCAAytRs_rlEyxyt_tcig : $@convention(method) <X, Y where Y == ()> (@guaranteed GenericClass<X, ()>) -> @out X
+  // CHECK-LABEL: sil @$S22constrained_extensions12GenericClassCAAytRs_rlEyxyt_tcis : $@convention(method) <X, Y where Y == ()> (@in X, @guaranteed GenericClass<X, ()>) -> ()
+  // CHECK-LABEL: sil shared [transparent] [serialized] @$S22constrained_extensions12GenericClassCAAytRs_rlEyxyt_tcimytfU_ : $@convention(method) <X, Y where Y == ()> (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout GenericClass<X, ()>, @thick GenericClass<X, ()>.Type) -> ()
+  // CHECK-LABEL: sil [transparent] [serialized] @$S22constrained_extensions12GenericClassCAAytRs_rlEyxyt_tcim : $@convention(method) <X, Y where Y == ()> (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @guaranteed GenericClass<X, ()>) -> (Builtin.RawPointer, Optional<Builtin.RawPointer>)
+  public subscript(_: Y) -> X {
+    get { while true {} }
+    set {}
+  }
+
+  // CHECK-LABEL: sil @$S22constrained_extensions12GenericClassCAAytRs_rlEyyxcig : $@convention(method) <X, Y where Y == ()> (@in_guaranteed X, @guaranteed GenericClass<X, ()>) -> ()
+  // CHECK-LABEL: sil @$S22constrained_extensions12GenericClassCAAytRs_rlEyyxcis : $@convention(method) <X, Y where Y == ()> (@in X, @guaranteed GenericClass<X, ()>) -> ()
+  // CHECK-LABEL: sil shared [transparent] [serialized] @$S22constrained_extensions12GenericClassCAAytRs_rlEyyxcimytfU_ : $@convention(method) <X, Y where Y == ()> (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout GenericClass<X, ()>, @thick GenericClass<X, ()>.Type) -> ()
+  // CHECK-LABEL: sil [transparent] [serialized] @$S22constrained_extensions12GenericClassCAAytRs_rlEyyxcim : $@convention(method) <X, Y where Y == ()> (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @in_guaranteed X, @guaranteed GenericClass<X, ()>) -> (Builtin.RawPointer, Optional<Builtin.RawPointer>)
+  public subscript(_: X) -> Y {
+    get { while true {} }
+    set {}
+  }
+}
+
+protocol VeryConstrained {}
+
+struct AnythingGoes<T> {
+  // CHECK-LABEL: sil hidden [transparent] @$S22constrained_extensions12AnythingGoesV13meaningOfLifexSgvpfi : $@convention(thin) <T> () -> @out Optional<T>
+  var meaningOfLife: T? = nil
+}
+
+extension AnythingGoes where T : VeryConstrained {
+  // CHECK-LABEL: sil hidden @$S22constrained_extensions12AnythingGoesVA2A15VeryConstrainedRzlE13fromExtensionACyxGyt_tcfC : $@convention(method) <T where T : VeryConstrained> (@thin AnythingGoes<T>.Type) -> @out AnythingGoes<T> {
+
+  // CHECK: [[INIT:%.*]] = function_ref @$S22constrained_extensions12AnythingGoesV13meaningOfLifexSgvpfi : $@convention(thin) <τ_0_0> () -> @out Optional<τ_0_0>
+  // CHECK: [[RESULT:%.*]] = alloc_stack $Optional<T>
+  // CHECK: apply [[INIT]]<T>([[RESULT]]) : $@convention(thin) <τ_0_0> () -> @out Optional<τ_0_0>
+  // CHECK: return
+  init(fromExtension: ()) {}
+}
+
+extension Array where Element == Int {
+  struct Nested {
+    // CHECK-LABEL: sil hidden [transparent] @$SSa22constrained_extensionsSiRszlE6NestedV1eSiSgvpfi : $@convention(thin) () -> Optional<Int>
+    var e: Element? = nil
+
+    // CHECK-LABEL: sil hidden @$SSa22constrained_extensionsSiRszlE6NestedV10hasDefault1eySiSg_tFfA_ : $@convention(thin) () -> Optional<Int>
+    // CHECK-LABEL: sil hidden @$SSa22constrained_extensionsSiRszlE6NestedV10hasDefault1eySiSg_tF : $@convention(method) (Optional<Int>, @inout Array<Int>.Nested) -> ()
+    mutating func hasDefault(e: Element? = nil) {
+      self.e = e
+    }
+  }
+}
+
+extension Array where Element == AnyObject {
+  class NestedClass {
+    // CHECK-LABEL: sil hidden @$SSa22constrained_extensionsyXlRszlE11NestedClassCfd : $@convention(method) (@guaranteed Array<AnyObject>.NestedClass) -> @owned Builtin.NativeObject
+    // CHECK-LABEL: sil hidden @$SSa22constrained_extensionsyXlRszlE11NestedClassCfD : $@convention(method) (@owned Array<AnyObject>.NestedClass) -> ()
+    deinit { }
+
+    // CHECK-LABEL: sil hidden @$SSa22constrained_extensionsyXlRszlE11NestedClassCACyyXl_GycfC : $@convention(method) (@thick Array<AnyObject>.NestedClass.Type) -> @owned Array<AnyObject>.NestedClass
+    // CHECK-LABEL: sil hidden @$SSa22constrained_extensionsyXlRszlE11NestedClassCACyyXl_Gycfc : $@convention(method) (@owned Array<AnyObject>.NestedClass) -> @owned Array<AnyObject>.NestedClass
+  }
+
+  class DerivedClass : NestedClass {
+    // CHECK-LABEL: sil hidden [transparent] @$SSa22constrained_extensionsyXlRszlE12DerivedClassC1eyXlSgvpfi : $@convention(thin) () -> @owned Optional<AnyObject>
+    // CHECK-LABEL: sil hidden @$SSa22constrained_extensionsyXlRszlE12DerivedClassCfE : $@convention(method) (@guaranteed Array<AnyObject>.DerivedClass) -> ()
+    var e: Element? = nil
+  }
+}
+
+func referenceNestedTypes() {
+  _ = Array<AnyObject>.NestedClass()
+  _ = Array<AnyObject>.DerivedClass()
+}
diff --git a/test/SILGen/plus_zero_default_arguments.swift b/test/SILGen/plus_zero_default_arguments.swift
new file mode 100644
index 0000000..ad5ff0e
--- /dev/null
+++ b/test/SILGen/plus_zero_default_arguments.swift
@@ -0,0 +1,378 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -Xllvm -sil-full-demangle -enable-sil-ownership -emit-silgen -swift-version 3 %s | %FileCheck %s
+// RUN: %target-swift-frontend -Xllvm -sil-full-demangle -enable-sil-ownership -emit-silgen -swift-version 3 %s | %FileCheck %s --check-prefix=NEGATIVE
+
+// RUN: %target-swift-frontend -Xllvm -sil-full-demangle -enable-sil-ownership -emit-silgen -swift-version 4 %s | %FileCheck %s
+// RUN: %target-swift-frontend -Xllvm -sil-full-demangle -enable-sil-ownership -emit-silgen -swift-version 4 %s | %FileCheck %s --check-prefix=NEGATIVE
+
+// __FUNCTION__ used as top-level parameter produces the module name.
+// CHECK-LABEL: sil @main
+// CHECK:         string_literal utf16 "default_arguments"
+
+// Default argument for first parameter.
+// CHECK-LABEL: sil hidden @$S17default_arguments7defarg11i1d1sySi_SdSStFfA_ : $@convention(thin) () -> Int
+// CHECK: [[INT:%[0-9]+]] = metatype $@thin Int.Type
+// CHECK: [[LIT:%[0-9]+]] = integer_literal $Builtin.Int2048, 17
+// CHECK: [[CVT:%[0-9]+]] = function_ref @$SSi22_builtinIntegerLiteralSiBi{{[_0-9]*}}__tcfC
+// CHECK: [[RESULT:%[0-9]+]] = apply [[CVT]]([[LIT]], [[INT]]) : $@convention(method) (Builtin.Int2048, @thin Int.Type) -> Int
+// CHECK: return [[RESULT]] : $Int
+
+// Default argument for third parameter.
+// CHECK-LABEL: sil hidden @$S17default_arguments7defarg11i1d1sySi_SdSStFfA1_ : $@convention(thin) () -> @owned String
+// CHECK: [[LIT:%[0-9]+]] = string_literal utf8 "Hello"
+// CHECK: [[LEN:%[0-9]+]] = integer_literal $Builtin.Word, 5
+// CHECK: [[STRING:%[0-9]+]] = metatype $@thin String.Type
+// CHECK: [[CVT:%[0-9]+]] = function_ref @$SSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC
+// CHECK: [[RESULT:%[0-9]+]] = apply [[CVT]]([[LIT]], [[LEN]], {{[^,]+}}, [[STRING]]) : $@convention(method)
+// CHECK: return [[RESULT]] : $String
+func defarg1(i: Int = 17, d: Double, s: String = "Hello") { }
+
+// CHECK-LABEL: sil hidden @$S17default_arguments15testDefaultArg1yyF
+func testDefaultArg1() {
+  // CHECK: [[FLOAT64:%[0-9]+]] = metatype $@thin Double.Type
+  // CHECK: [[FLOATLIT:%[0-9]+]] = float_literal $Builtin.FPIEEE{{64|80}}, {{0x4009000000000000|0x4000C800000000000000}}
+  // CHECK: [[LITFN:%[0-9]+]] = function_ref @$SSd20_builtinFloatLiteralSdBf{{[_0-9]*}}__tcfC
+  // CHECK: [[FLOATVAL:%[0-9]+]] = apply [[LITFN]]([[FLOATLIT]], [[FLOAT64]])
+  // CHECK: [[DEF0FN:%[0-9]+]] = function_ref @$S17default_arguments7defarg1{{.*}}A_
+  // CHECK: [[DEF0:%[0-9]+]] = apply [[DEF0FN]]()
+  // CHECK: [[DEF2FN:%[0-9]+]] = function_ref @$S17default_arguments7defarg1{{.*}}A1_
+  // CHECK: [[DEF2:%[0-9]+]] = apply [[DEF2FN]]()
+  // CHECK: [[BORROWED_DEF2:%.*]] = begin_borrow [[DEF2]]
+  // CHECK: [[FNREF:%[0-9]+]] = function_ref @$S17default_arguments7defarg1{{[_0-9a-zA-Z]*}}F
+  // CHECK: apply [[FNREF]]([[DEF0]], [[FLOATVAL]], [[BORROWED_DEF2]])
+  defarg1(d:3.125)
+}
+
+func defarg2(_ i: Int, d: Double = 3.125, s: String = "Hello") { }
+
+// CHECK-LABEL: sil hidden @$S17default_arguments15testDefaultArg2{{[_0-9a-zA-Z]*}}F
+func testDefaultArg2() {
+// CHECK:  [[INT64:%[0-9]+]] = metatype $@thin Int.Type
+// CHECK:  [[INTLIT:%[0-9]+]] = integer_literal $Builtin.Int2048, 5
+// CHECK:  [[LITFN:%[0-9]+]] = function_ref @$SSi22_builtinIntegerLiteralSiBi{{[_0-9]*}}__tcfC
+// CHECK:  [[I:%[0-9]+]] = apply [[LITFN]]([[INTLIT]], [[INT64]]) : $@convention(method) (Builtin.Int2048, @thin Int.Type) -> Int
+// CHECK:  [[DFN:%[0-9]+]] = function_ref @$S17default_arguments7defarg2{{.*}}A0_ : $@convention(thin) () -> Double
+// CHECK:  [[D:%[0-9]+]] = apply [[DFN]]() : $@convention(thin) () -> Double
+// CHECK:  [[SFN:%[0-9]+]] = function_ref @$S17default_arguments7defarg2{{.*}}A1_ : $@convention(thin) () -> @owned String
+// CHECK:  [[S:%[0-9]+]] = apply [[SFN]]() : $@convention(thin) () -> @owned String
+// CHECK:  [[BORROWED_S:%.*]] = begin_borrow [[S]]
+// CHECK:  [[FNREF:%[0-9]+]] = function_ref @$S17default_arguments7defarg2{{[_0-9a-zA-Z]*}}F : $@convention(thin) (Int, Double, @guaranteed String) -> ()
+// CHECK:  apply [[FNREF]]([[I]], [[D]], [[BORROWED_S]]) : $@convention(thin) (Int, Double, @guaranteed String) -> ()
+  defarg2(5)
+}
+
+func autocloseFile(x: @autoclosure () -> String = #file,
+                   y: @autoclosure () -> Int = #line) { }
+// CHECK-LABEL: sil hidden @$S17default_arguments17testAutocloseFileyyF
+func testAutocloseFile() {
+  // CHECK-LABEL: sil private [transparent] @$S17default_arguments17testAutocloseFileyyFSSyXKfu_ : $@convention(thin) () -> @owned String
+  // CHECK: string_literal utf16{{.*}}default_arguments.swift
+
+  // CHECK-LABEL: sil private [transparent] @$S17default_arguments17testAutocloseFileyyFSiyXKfu0_ : $@convention(thin) () -> Int
+  // CHECK: integer_literal $Builtin.Int2048, [[@LINE+1]]
+  autocloseFile()
+}
+
+func testMagicLiterals(file: String = #file,
+                       function: String = #function,
+                       line: Int = #line,
+                       column: Int = #column) {}
+
+// Check that default argument generator functions don't leak information about
+// user's source.
+//
+// NEGATIVE-NOT: sil hidden @$S17default_arguments17testMagicLiteralsySS4file_SS8functionSi4lineSi6columntFfA_
+//
+// NEGATIVE-NOT: sil hidden @$S17default_arguments17testMagicLiteralsySS4file_SS8functionSi4lineSi6columntFfA0_
+//
+// NEGATIVE-NOT: sil hidden @$S17default_arguments17testMagicLiteralsySS4file_SS8functionSi4lineSi6columntFfA1_
+//
+// NEGATIVE-NOT: sil hidden @$S17default_arguments17testMagicLiteralsySS4file_SS8functionSi4lineSi6columntFfA2_
+
+func closure(_: () -> ()) {}
+func autoclosure(_: @autoclosure () -> ()) {}
+
+// CHECK-LABEL: sil hidden @$S17default_arguments25testCallWithMagicLiteralsyyF
+// CHECK:         string_literal utf16 "testCallWithMagicLiterals()"
+// CHECK:         string_literal utf16 "testCallWithMagicLiterals()"
+// CHECK-LABEL: sil private @$S17default_arguments25testCallWithMagicLiteralsyyFyyXEfU_
+// CHECK:         string_literal utf16 "testCallWithMagicLiterals()"
+// CHECK-LABEL: sil private [transparent] @$S17default_arguments25testCallWithMagicLiteralsyyFyyXKfu_
+// CHECK:         string_literal utf16 "testCallWithMagicLiterals()"
+func testCallWithMagicLiterals() {
+  testMagicLiterals()
+  testMagicLiterals()
+  closure { testMagicLiterals() }
+  autoclosure(testMagicLiterals())
+}
+
+// CHECK-LABEL: sil hidden @$S17default_arguments25testPropWithMagicLiteralsSivg
+// CHECK:         string_literal utf16 "testPropWithMagicLiterals"
+var testPropWithMagicLiterals: Int {
+  testMagicLiterals()
+  closure { testMagicLiterals() }
+  autoclosure(testMagicLiterals())
+  return 0
+}
+
+class Foo {
+
+  // CHECK-LABEL: sil hidden @$S17default_arguments3FooC3int6stringACSi_SStcfc : $@convention(method) (Int, @owned String, @owned Foo) -> @owned Foo
+  // CHECK:         string_literal utf16 "init(int:string:)"
+  init(int: Int, string: String = #function) {
+    testMagicLiterals()
+    closure { testMagicLiterals() }
+    autoclosure(testMagicLiterals())
+  }
+
+  // CHECK-LABEL: sil hidden @$S17default_arguments3FooCfd
+  // CHECK:         string_literal utf16 "deinit"
+  deinit {
+    testMagicLiterals()
+    closure { testMagicLiterals() }
+    autoclosure(testMagicLiterals())
+  }
+
+  // CHECK-LABEL: sil hidden @$S17default_arguments3FooCyS2icig
+  // CHECK:         string_literal utf16 "subscript"
+  subscript(x: Int) -> Int {
+    testMagicLiterals()
+    closure { testMagicLiterals() }
+    autoclosure(testMagicLiterals())
+    return x
+  }
+ 
+  // CHECK-LABEL: sil private @globalinit_33_E52D764B1F2009F2390B2B8DF62DAEB8_func0
+  // CHECK:         string_literal utf16 "Foo" 
+  static let x = Foo(int:0)
+
+}
+
+// Test at top level.
+testMagicLiterals()
+closure { testMagicLiterals() }
+autoclosure(testMagicLiterals())
+
+// CHECK: string_literal utf16 "default_arguments"
+let y : String = #function 
+
+// CHECK-LABEL: sil hidden @$S17default_arguments16testSelectorCall_17withMagicLiteralsySi_SitF
+// CHECK:         string_literal utf16 "testSelectorCall(_:withMagicLiterals:)"
+func testSelectorCall(_ x: Int, withMagicLiterals y: Int) {
+  testMagicLiterals()
+}
+
+// CHECK-LABEL: sil hidden @$S17default_arguments32testSelectorCallWithUnnamedPieceyySi_SitF
+// CHECK:         string_literal utf16 "testSelectorCallWithUnnamedPiece"
+func testSelectorCallWithUnnamedPiece(_ x: Int, _ y: Int) {
+  testMagicLiterals()
+}
+
+// Test default arguments in an inherited subobject initializer
+class SuperDefArg {
+  init(int i: Int = 10) { }
+}
+
+// CHECK: sil hidden @$S17default_arguments11SuperDefArgC3intACSi_tcfcfA_ : $@convention(thin) () -> Int
+
+// CHECK-NOT: sil hidden @$S17default_arguments9SubDefArgCAC3intSi_tcfcfA_ : $@convention(thin) () -> Int
+
+class SubDefArg : SuperDefArg { }
+
+// CHECK: sil hidden @$S17default_arguments13testSubDefArgAA0deF0CyF : $@convention(thin) () -> @owned SubDefArg
+func testSubDefArg() -> SubDefArg {
+  // CHECK: function_ref @$S17default_arguments11SuperDefArgC3intACSi_tcfcfA_
+  // CHECK: function_ref @$S17default_arguments9SubDefArgC{{[_0-9a-zA-Z]*}}fC
+  // CHECK: return
+  return SubDefArg()
+}
+
+// CHECK-NOT: sil hidden @$S17default_arguments9SubDefArgCACSi3int_tcfcfA_ : $@convention(thin) () -> Int
+
+// <rdar://problem/17379550>
+func takeDefaultArgUnnamed(_ x: Int = 5) { }
+
+// CHECK-LABEL: sil hidden @$S17default_arguments25testTakeDefaultArgUnnamed{{[_0-9a-zA-Z]*}}F
+func testTakeDefaultArgUnnamed(_ i: Int) {
+  // CHECK: bb0([[I:%[0-9]+]] : @trivial $Int):
+  // CHECK:   [[FN:%[0-9]+]] = function_ref @$S17default_arguments21takeDefaultArgUnnamedyySiF : $@convention(thin) (Int) -> ()
+  // CHECK:   apply [[FN]]([[I]]) : $@convention(thin) (Int) -> ()
+  takeDefaultArgUnnamed(i)
+}
+
+func takeDSOHandle(_ handle: UnsafeRawPointer = #dsohandle) { }
+
+// CHECK-LABEL: sil hidden @$S17default_arguments13testDSOHandleyyF
+func testDSOHandle() {
+  // CHECK: [[DSO_HANDLE:%[0-9]+]] = global_addr @__dso_handle : $*Builtin.RawPointer
+  takeDSOHandle()
+}
+
+// Test __FUNCTION__ in an extension initializer. rdar://problem/19792181
+extension SuperDefArg {
+  static let extensionInitializerWithClosure: Int = { return 22 }()
+}
+
+
+// <rdar://problem/19086357> SILGen crashes reabstracting default argument closure in members
+class ReabstractDefaultArgument<T> {
+  init(a: (T, T) -> Bool = { _, _ in true }) {
+  }
+}
+
+// CHECK-LABEL: sil hidden @$S17default_arguments32testDefaultArgumentReabstractionyyF
+// function_ref default_arguments.ReabstractDefaultArgument.__allocating_init <A>(default_arguments.ReabstractDefaultArgument<A>.Type)(a : (A, A) -> Swift.Bool) -> default_arguments.ReabstractDefaultArgument<A>
+// CHECK: [[FN:%.*]] = function_ref @$S17default_arguments25ReabstractDefaultArgument{{.*}} : $@convention(thin) <τ_0_0> () -> @owned @callee_guaranteed (@in_guaranteed τ_0_0, @in_guaranteed τ_0_0) -> Bool
+// CHECK-NEXT: [[RESULT:%.*]] = apply [[FN]]<Int>() : $@convention(thin) <τ_0_0> () -> @owned @callee_guaranteed (@in_guaranteed τ_0_0, @in_guaranteed τ_0_0) -> Bool
+// CHECK-NEXT: function_ref reabstraction thunk helper from @escaping @callee_guaranteed (@in_guaranteed Swift.Int, @in_guaranteed Swift.Int) -> (@unowned Swift.Bool) to @escaping @callee_guaranteed (@unowned Swift.Int, @unowned Swift.Int) -> (@unowned Swift.Bool)
+// CHECK-NEXT: [[THUNK:%.*]] = function_ref @$SS2iSbIegnnd_S2iSbIegyyd_TR : $@convention(thin) (Int, Int, @guaranteed @callee_guaranteed (@in_guaranteed Int, @in_guaranteed Int) -> Bool) -> Bool
+// CHECK-NEXT: [[FN:%.*]] = partial_apply [callee_guaranteed] [[THUNK]]([[RESULT]]) : $@convention(thin) (Int, Int, @guaranteed @callee_guaranteed (@in_guaranteed Int, @in_guaranteed Int) -> Bool) -> Bool
+// CHECK-NEXT: [[CONV_FN:%.*]] = convert_escape_to_noescape [[FN]]
+// function_ref reabstraction thunk helper from @callee_guaranteed (@unowned Swift.Int, @unowned Swift.Int) -> (@unowned Swift.Bool) to @callee_guaranteed (@in_guaranteed Swift.Int, @in_guaranteed Swift.Int) -> (@unowned Swift.Bool)
+// CHECK: [[THUNK:%.*]] = function_ref @$SS2iSbIgyyd_S2iSbIegnnd_TR : $@convention(thin) (@in_guaranteed Int, @in_guaranteed Int, @noescape @callee_guaranteed (Int, Int) -> Bool) -> Bool
+// CHECK-NEXT: [[FN:%.*]] = partial_apply [callee_guaranteed] [[THUNK]]([[CONV_FN]]) : $@convention(thin) (@in_guaranteed Int, @in_guaranteed Int, @noescape @callee_guaranteed (Int, Int) -> Bool) -> Bool
+// CHECK-NEXT: [[CONV_FN:%.*]] = convert_escape_to_noescape [[FN]]
+// CHECK: [[INITFN:%[0-9]+]] = function_ref @$S17default_arguments25ReabstractDefaultArgumentC{{[_0-9a-zA-Z]*}}fC
+// CHECK-NEXT: apply [[INITFN]]<Int>([[CONV_FN]], 
+
+func testDefaultArgumentReabstraction() {
+  _ = ReabstractDefaultArgument<Int>()
+}
+
+// <rdar://problem/20494437> SILGen crash handling default arguments
+// CHECK-LABEL: sil hidden @$S17default_arguments18r20494437onSuccessyyAA25r20494437ExecutionContext_pF
+// CHECK: function_ref @$S17default_arguments19r20494437onCompleteyyAA25r20494437ExecutionContext_pF
+// <rdar://problem/20494437> SILGen crash handling default arguments
+protocol r20494437ExecutionContext {}
+let r20494437Default: r20494437ExecutionContext
+func r20494437onComplete(_ executionContext: r20494437ExecutionContext = r20494437Default) {}
+func r20494437onSuccess(_ a: r20494437ExecutionContext) {
+  r20494437onComplete(a)
+}
+
+// <rdar://problem/18400194> Parenthesized function expression crashes the compiler
+func r18400194(_ a: Int, x: Int = 97) {}
+
+// CHECK-LABEL: sil hidden @$S17default_arguments9r18400194_1xySi_SitFfA0_
+// CHECK: integer_literal $Builtin.Int2048, 97
+
+// CHECK-LABEL: sil hidden @$S17default_arguments14test_r18400194yyF
+// CHECK: integer_literal $Builtin.Int2048, 1
+// CHECK:  function_ref @$S17default_arguments9r18400194_1xySi_SitFfA0_ : $@convention(thin) () -> Int
+// CHECK: function_ref @$S17default_arguments9r18400194_1xySi_SitF : $@convention(thin) (Int, Int) -> (){{.*}}
+func test_r18400194() {
+  (r18400194)(1)
+}
+
+// rdar://24242783
+//   Don't add capture arguments to local default argument generators.
+func localFunctionWithDefaultArg() {
+  var z = 5
+  func bar(_ x: Int? = nil) {
+    z += 1
+  }
+  bar()
+}
+// CHECK-LABEL: sil private @$S17default_arguments27localFunctionWithDefaultArgyyF3barL_yySiSgFfA_
+// CHECK-SAME: $@convention(thin) () -> Optional<Int>
+
+// CHECK-LABEL: sil hidden @$S17default_arguments15throwingDefault7closureySbyKXE_tKFfA_ : $@convention(thin) () -> @owned @callee_guaranteed () -> (Bool, @error Error)
+func throwingDefault(closure: () throws -> Bool  = {  return true }) throws {
+  try _ = closure()
+}
+
+// CHECK-LABEL: sil hidden @$S17default_arguments26throwingAutoclosureDefault7closureySbyKXK_tKFfA_ : $@convention(thin) () -> @owned @callee_guaranteed () -> (Bool, @error Error)
+func throwingAutoclosureDefault(closure: @autoclosure () throws -> Bool  = true ) throws {
+  try _ = closure()
+}
+
+// CHECK-LABEL: sil hidden @$S17default_arguments0A3Arg7closureySbyXE_tFfA_ : $@convention(thin) () -> @owned @callee_guaranteed () -> Bool
+func defaultArg(closure: () -> Bool  = {  return true }) {
+  _ = closure()
+}
+
+// CHECK-LABEL: sil hidden @$S17default_arguments21autoclosureDefaultArg7closureySbyXK_tFfA_ : $@convention(thin) () -> @owned @callee_guaranteed () -> Bool
+func autoclosureDefaultArg(closure: @autoclosure () -> Bool  = true ) {
+  _ = closure()
+}
+
+// CHECK-LABEL: sil hidden @$S17default_arguments23throwingDefaultEscaping7closureySbyKc_tKFfA_ : $@convention(thin) () -> @owned @callee_guaranteed () -> (Bool, @error Error)
+func throwingDefaultEscaping(closure: @escaping () throws -> Bool  = {  return true }) throws {
+  try _ = closure()
+}
+
+// CHECK-LABEL: sil hidden @$S17default_arguments34throwingAutoclosureDefaultEscaping7closureySbyKXA_tKFfA_ : $@convention(thin) () -> @owned @callee_guaranteed () -> (Bool, @error Error)
+func throwingAutoclosureDefaultEscaping(closure: @escaping @autoclosure () throws -> Bool  = true ) throws {
+  try _ = closure()
+}
+
+// CHECK-LABEL: sil hidden @$S17default_arguments0A8Escaping7closureySbyc_tFfA_ : $@convention(thin) () -> @owned @callee_guaranteed () -> Bool
+func defaultEscaping(closure: @escaping () -> Bool  = {  return true }) {
+  _ = closure()
+}
+
+// CHECK-LABEL: sil hidden @$S17default_arguments26autoclosureDefaultEscaping7closureySbyXA_tFfA_ : $@convention(thin) () -> @owned @callee_guaranteed () -> Bool {
+func autoclosureDefaultEscaping(closure: @escaping @autoclosure () -> Bool  = true ) {
+  _ = closure()
+}
+
+// CHECK-LABEL: sil hidden @{{.*}}callThem{{.*}} : $@convention(thin) () -> @error Error
+
+// CHECK:  [[F:%.*]] = function_ref @$S17default_arguments15throwingDefault7closureySbyKXE_tKFfA_ : $@convention(thin) () -> @owned @callee_guaranteed () -> (Bool, @error Error)
+// CHECK:  [[C:%.*]] = apply [[F]]() : $@convention(thin) () -> @owned @callee_guaranteed () -> (Bool, @error Error)
+// CHECK:  [[E:%.*]] = convert_escape_to_noescape [[C]]
+// CHECK:  [[R:%.*]] = function_ref @$S17default_arguments15throwingDefault7closureySbyKXE_tKF : $@convention(thin) (@noescape @callee_guaranteed () -> (Bool, @error Error)) -> @error Error
+// CHECK:  try_apply [[R]]([[E]])
+
+// CHECK:  [[F:%.*]] = function_ref @$S17default_arguments26throwingAutoclosureDefault7closureySbyKXK_tKFfA_ : $@convention(thin) () -> @owned @callee_guaranteed () -> (Bool, @error Error)
+// CHECK:  [[C:%.*]] = apply [[F]]() : $@convention(thin) () -> @owned @callee_guaranteed () -> (Bool, @error Error)
+// CHECK:  [[E:%.*]] = convert_escape_to_noescape [[C]]
+// CHECK:  [[R:%.*]] = function_ref @$S17default_arguments26throwingAutoclosureDefault7closureySbyKXK_tKF : $@convention(thin) (@noescape @callee_guaranteed () -> (Bool, @error Error)) -> @error Error
+// CHECK:  try_apply [[R]]([[E]])
+
+// CHECK:   [[F:%.*]] = function_ref @$S17default_arguments0A3Arg7closureySbyXE_tFfA_ : $@convention(thin) () -> @owned @callee_guaranteed () -> Bool
+// CHECK:   [[C:%.*]] = apply [[F]]() : $@convention(thin) () -> @owned @callee_guaranteed () -> Bool
+// CHECK:   [[E:%.*]] = convert_escape_to_noescape [[C]]
+// CHECK:   [[R:%.*]] = function_ref @$S17default_arguments0A3Arg7closureySbyXE_tF : $@convention(thin) (@noescape @callee_guaranteed () -> Bool) -> ()
+// CHECK:   apply [[R]]([[E]])
+
+// CHECK:  [[F:%.*]] = function_ref @$S17default_arguments21autoclosureDefaultArg7closureySbyXK_tFfA_ : $@convention(thin) () -> @owned @callee_guaranteed () -> Boo
+// CHECK:  [[C:%.*]] = apply [[F]]() : $@convention(thin) () -> @owned @callee_guaranteed () -> Bool
+// CHECK:  [[E:%.*]] = convert_escape_to_noescape [[C]]
+// CHECK:  [[R:%.*]] = function_ref @$S17default_arguments21autoclosureDefaultArg7closureySbyXK_tF : $@convention(thin) (@noescape @callee_guaranteed () -> Bool) -> ()
+// CHECK:  apply [[R]]([[E]])
+
+// CHECK:  [[F:%.*]] = function_ref @$S17default_arguments23throwingDefaultEscaping7closureySbyKc_tKFfA_ : $@convention(thin) () -> @owned @callee_guaranteed () -> (Bool, @error Error)
+// CHECK:  [[E:%.*]] = apply [[F]]() : $@convention(thin) () -> @owned @callee_guaranteed () -> (Bool, @error Error)
+// CHECK:  [[BORROWED_E:%.*]] = begin_borrow [[E]]
+// CHECK:  [[R:%.*]] = function_ref @$S17default_arguments23throwingDefaultEscaping7closureySbyKc_tKF : $@convention(thin) (@guaranteed @callee_guaranteed () -> (Bool, @error Error)) -> @error Erro
+// CHECK:  try_apply [[R]]([[BORROWED_E]])
+
+// CHECK:  [[F:%.*]] = function_ref @$S17default_arguments34throwingAutoclosureDefaultEscaping7closureySbyKXA_tKFfA_ : $@convention(thin) () -> @owned @callee_guaranteed () -> (Bool, @error Error)
+// CHECK:  [[E:%.*]] = apply [[F]]() : $@convention(thin) () -> @owned @callee_guaranteed () -> (Bool, @error Error)
+// CHECK:  [[BORROWED_E:%.*]] = begin_borrow [[E]]
+// CHECK:  [[R:%.*]] = function_ref @$S17default_arguments34throwingAutoclosureDefaultEscaping7closureySbyKXA_tKF : $@convention(thin) (@guaranteed @callee_guaranteed () -> (Bool, @error Error)) -> @error Error
+// CHECK:  try_apply [[R]]([[BORROWED_E]])
+
+// CHECK:  [[F:%.*]] = function_ref @$S17default_arguments0A8Escaping7closureySbyc_tFfA_ : $@convention(thin) () -> @owned @callee_guaranteed () -> Bool
+// CHECK:  [[E:%.*]] = apply [[F]]() : $@convention(thin) () -> @owned @callee_guaranteed () -> Bool
+// CHECK:  [[BORROWED_E:%.*]] = begin_borrow [[E]]
+// CHECK:  [[R:%.*]] = function_ref @$S17default_arguments0A8Escaping7closureySbyc_tF : $@convention(thin) (@guaranteed @callee_guaranteed () -> Bool) -> ()
+// CHECK:  apply [[R]]([[BORROWED_E]])
+
+// CHECK:  [[F:%.*]] = function_ref @$S17default_arguments26autoclosureDefaultEscaping7closureySbyXA_tFfA_ : $@convention(thin) () -> @owned @callee_guaranteed () -> Bool
+// CHECK:  [[E:%.*]] = apply [[F]]() : $@convention(thin) () -> @owned @callee_guaranteed () -> Bool
+// CHECK:  [[BORROWED_E:%.*]] = begin_borrow [[E]]
+// CHECK:  [[R:%.*]] = function_ref @$S17default_arguments26autoclosureDefaultEscaping7closureySbyXA_tF : $@convention(thin) (@guaranteed @callee_guaranteed () -> Bool) -> ()
+// CHECK:  apply [[R]]([[BORROWED_E]])
+
+func callThem() throws {
+   try throwingDefault()
+   try throwingAutoclosureDefault()
+   defaultArg()
+   autoclosureDefaultArg()
+   try throwingDefaultEscaping()
+   try throwingAutoclosureDefaultEscaping()
+   defaultEscaping()
+   autoclosureDefaultEscaping()
+}
diff --git a/test/SILGen/plus_zero_default_arguments_generic.swift b/test/SILGen/plus_zero_default_arguments_generic.swift
new file mode 100644
index 0000000..b382f5b
--- /dev/null
+++ b/test/SILGen/plus_zero_default_arguments_generic.swift
@@ -0,0 +1,66 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership -swift-version 3 %s | %FileCheck %s
+// RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership -swift-version 4 %s | %FileCheck %s
+
+func foo<T: ExpressibleByIntegerLiteral>(_: T.Type, x: T = 0) { }
+
+struct Zim<T: ExpressibleByIntegerLiteral> {
+  init(x: T = 0) { }
+  init<U: ExpressibleByFloatLiteral>(_ x: T = 0, y: U = 0.5) { }
+
+  static func zim(x: T = 0) { }
+  static func zang<U: ExpressibleByFloatLiteral>(_: U.Type, _ x: T = 0, y: U = 0.5) { }
+}
+
+// CHECK-LABEL: sil hidden @$S25default_arguments_generic3baryyF : $@convention(thin) () -> () {
+func bar() {
+  // CHECK: [[FOO_DFLT:%.*]] = function_ref @$S25default_arguments_generic3foo
+  // CHECK: apply [[FOO_DFLT]]<Int>
+  foo(Int.self)
+  // CHECK: [[ZIM_DFLT:%.*]] = function_ref @$S25default_arguments_generic3ZimV3zim
+  // CHECK: apply [[ZIM_DFLT]]<Int>
+  Zim<Int>.zim()
+  // CHECK: [[ZANG_DFLT_0:%.*]] = function_ref @$S25default_arguments_generic3ZimV4zang{{.*}}A0_
+  // CHECK: apply [[ZANG_DFLT_0]]<Int, Double>
+  // CHECK: [[ZANG_DFLT_1:%.*]] = function_ref @$S25default_arguments_generic3ZimV4zang{{.*}}A1_
+  // CHECK: apply [[ZANG_DFLT_1]]<Int, Double>
+  Zim<Int>.zang(Double.self)
+  // CHECK: [[ZANG_DFLT_1:%.*]] = function_ref @$S25default_arguments_generic3ZimV4zang{{.*}}A1_
+  // CHECK: apply [[ZANG_DFLT_1]]<Int, Double>
+  Zim<Int>.zang(Double.self, 22)
+}
+
+protocol Initializable {
+  init()
+}
+struct Generic<T: Initializable> {
+  init(_ value: T = T()) {}
+}
+struct InitializableImpl: Initializable {
+  init() {}
+}
+// CHECK-LABEL: sil hidden @$S25default_arguments_generic17testInitializableyyF
+func testInitializable() {
+  // The ".init" is required to trigger the crash that used to happen.
+  _ = Generic<InitializableImpl>.init()
+  // CHECK: function_ref @$S25default_arguments_generic7GenericVyACyxGxcfcfA_ : $@convention(thin) <τ_0_0 where τ_0_0 : Initializable> () -> @out τ_0_0
+  // CHECK: [[INIT:%.+]] = function_ref @$S25default_arguments_generic7GenericVyACyxGxcfC
+  // CHECK: apply [[INIT]]<InitializableImpl>({{%.+}}, {{%.+}}) : $@convention(method) <τ_0_0 where τ_0_0 : Initializable> (@in τ_0_0, @thin Generic<τ_0_0>.Type) -> Generic<τ_0_0>
+} // CHECK: end sil function '$S25default_arguments_generic17testInitializableyyF'
+
+// Local generic functions with default arguments
+
+// CHECK-LABEL: sil hidden @$S25default_arguments_generic5outer1tyx_tlF : $@convention(thin) <T> (@in_guaranteed T) -> ()
+func outer<T>(t: T) {
+  func inner1(x: Int = 0) {}
+
+  // CHECK: [[ARG_GENERATOR:%.*]] = function_ref @$S25default_arguments_generic5outer1tyx_tlF6inner1L_1xySi_tlFfA_ : $@convention(thin) () -> Int
+  // CHECK: [[ARG:%.*]] = apply [[ARG_GENERATOR]]() : $@convention(thin) () -> Int
+  _ = inner1()
+
+  func inner2(x: Int = 0) { _ = T.self }
+
+  // CHECK: [[ARG_GENERATOR:%.*]] = function_ref @$S25default_arguments_generic5outer1tyx_tlF6inner2L_1xySi_tlFfA_ : $@convention(thin) <τ_0_0> () -> Int
+  // CHECK: [[ARG:%.*]] = apply [[ARG_GENERATOR]]<T>() : $@convention(thin) <τ_0_0> () -> Int
+  _ = inner2()
+}
diff --git a/test/SILGen/plus_zero_default_arguments_serialized.swift b/test/SILGen/plus_zero_default_arguments_serialized.swift
new file mode 100644
index 0000000..1472952
--- /dev/null
+++ b/test/SILGen/plus_zero_default_arguments_serialized.swift
@@ -0,0 +1,62 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %empty-directory(%t)
+// RUN: %target-swift-frontend -emit-module-path %t/default_arguments_other.swiftmodule -emit-module -swift-version 4 -primary-file %S/Inputs/default_arguments_other.swift
+
+// RUN: %target-swift-frontend -Xllvm -sil-full-demangle -enable-sil-ownership -emit-silgen -swift-version 3 -I %t %s | %FileCheck %s --check-prefix=SWIFT3 --check-prefix=CHECK
+// RUN: %target-swift-frontend -Xllvm -sil-full-demangle -enable-sil-ownership -emit-silgen -swift-version 4 -I %t %s | %FileCheck %s --check-prefix=SWIFT4 --check-prefix=CHECK
+
+// RUN: %target-swift-frontend -Xllvm -sil-full-demangle -enable-sil-ownership -emit-sil -O -swift-version 3 -I %t %s | %FileCheck %s --check-prefix=OPT
+// RUN: %target-swift-frontend -Xllvm -sil-full-demangle -enable-sil-ownership -emit-sil -O -swift-version 4 -I %t %s | %FileCheck %s --check-prefix=OPT
+
+// Check that default arguments are serialized in Swift 4 mode.
+
+import default_arguments_other
+
+// CHECK-LABEL: sil @$S28default_arguments_serialized0A6StringSSyF : $@convention(thin) () -> @owned String
+public func defaultString() -> String { return "hi" }
+
+// SWIFT3-LABEL: sil @$S28default_arguments_serialized19hasDefaultArguments1x1yySi_SStFfA_ : $@convention(thin) () -> Int
+// SWIFT4-LABEL: sil non_abi [serialized] @$S28default_arguments_serialized19hasDefaultArguments1x1yySi_SStFfA_ : $@convention(thin) () -> Int
+
+// SWIFT3-LABEL: sil @$S28default_arguments_serialized19hasDefaultArguments1x1yySi_SStFfA0_ : $@convention(thin) () -> @owned String
+// SWIFT4-LABEL: sil non_abi [serialized] @$S28default_arguments_serialized19hasDefaultArguments1x1yySi_SStFfA0_ : $@convention(thin) () -> @owned String
+
+public func hasDefaultArguments(x: Int = 0, y: String = defaultString()) {}
+
+// CHECK-LABEL: sil @$S28default_arguments_serialized21callsDefaultArgumentsyyF : $@convention(thin) () -> ()
+// CHECK: function_ref @$S28default_arguments_serialized19hasDefaultArguments1x1yySi_SStFfA_ : $@convention(thin) () -> Int
+// CHECK: function_ref @$S28default_arguments_serialized19hasDefaultArguments1x1yySi_SStFfA0_ : $@convention(thin) () -> @owned String
+// CHECK: function_ref @$S28default_arguments_serialized19hasDefaultArguments1x1yySi_SStF : $@convention(thin) (Int, @guaranteed String) -> ()
+// CHECK: apply
+// CHECK: return
+public func callsDefaultArguments() {
+  hasDefaultArguments()
+}
+
+// When calling a default argument generator for a function in another module
+// that was built in Swift 4 mode, we should always treat it as serialized,
+// even if *this* module is built in Swift 3 mode.
+
+// CHECK-LABEL: sil @$S28default_arguments_serialized26callsOtherDefaultArgumentsyyF : $@convention(thin) () -> ()
+// CHECK: function_ref @$S23default_arguments_other0C16DefaultArguments1xySi_tFfA_ : $@convention(thin) () -> Int
+// CHECK: function_ref @$S23default_arguments_other0C16DefaultArguments1xySi_tF : $@convention(thin) (Int) -> ()
+// CHECK: apply
+// CHECK: return
+
+// Make sure the optimizer inlines the default argument generator from the
+// other module.
+
+// OPT-LABEL: sil @$S28default_arguments_serialized26callsOtherDefaultArgumentsyyF : $@convention(thin) () -> ()
+// OPT: [[INT_VAL:%.*]] = integer_literal [[INT_TYPE:\$Builtin.Int(32|64)]], 0
+// OPT: [[INT:%.*]] = struct $Int ([[INT_VAL]] : [[INT_TYPE]]
+// OPT: [[FN:%.*]] = function_ref @$S23default_arguments_other0C16DefaultArguments1xySi_tF : $@convention(thin) (Int) -> ()
+// OPT: apply [[FN]]([[INT]]) : $@convention(thin) (Int) -> ()
+// OPT: return
+public func callsOtherDefaultArguments() {
+  otherDefaultArguments()
+}
+
+// CHECK-LABEL: sil hidden_external [serialized] @$S23default_arguments_other0C16DefaultArguments1xySi_tFfA_ : $@convention(thin) () -> Int
+
+// CHECK-LABEL: sil @$S23default_arguments_other0C16DefaultArguments1xySi_tF : $@convention(thin) (Int) -> ()
+
diff --git a/test/SILGen/plus_zero_dependent_member_lowering.swift b/test/SILGen/plus_zero_dependent_member_lowering.swift
new file mode 100644
index 0000000..be5785f
--- /dev/null
+++ b/test/SILGen/plus_zero_dependent_member_lowering.swift
@@ -0,0 +1,22 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership %s | %FileCheck %s
+
+protocol P {
+  associatedtype A
+
+  func f(_ x: A)
+}
+struct Foo<T>: P {
+  typealias A = T.Type
+
+  func f(_ t: T.Type) {}
+  // CHECK-LABEL: sil private [transparent] [thunk] @$S25dependent_member_lowering3FooVyxGAA1PA2aEP1fyy1AQzFTW : $@convention(witness_method: P) <τ_0_0> (@in_guaranteed @thick τ_0_0.Type, @in_guaranteed Foo<τ_0_0>) -> ()
+  // CHECK:       bb0(%0 : @trivial $*@thick τ_0_0.Type, %1 : @trivial $*Foo<τ_0_0>):
+}
+struct Bar<T>: P {
+  typealias A = (Int) -> T
+
+  func f(_ t: @escaping (Int) -> T) {}
+  // CHECK-LABEL: sil private [transparent] [thunk] @$S25dependent_member_lowering3BarVyxGAA1PA2aEP1fyy1AQzFTW : $@convention(witness_method: P) <τ_0_0> (@in_guaranteed @callee_guaranteed (@in_guaranteed Int) -> @out τ_0_0, @in_guaranteed Bar<τ_0_0>) -> ()
+  // CHECK:       bb0(%0 : @trivial $*@callee_guaranteed (@in_guaranteed Int) -> @out τ_0_0, %1 : @trivial $*Bar<τ_0_0>):
+}
diff --git a/test/SILGen/plus_zero_downcast_reabstraction.swift b/test/SILGen/plus_zero_downcast_reabstraction.swift
new file mode 100644
index 0000000..52608d2
--- /dev/null
+++ b/test/SILGen/plus_zero_downcast_reabstraction.swift
@@ -0,0 +1,28 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership %s | %FileCheck %s
+
+// CHECK-LABEL: sil hidden @$S22downcast_reabstraction19condFunctionFromAnyyyypF
+// CHECK:         checked_cast_addr_br take_always Any in [[IN:%.*]] : $*Any to () -> () in [[OUT:%.*]] : $*@callee_guaranteed (@in_guaranteed ()) -> @out (), [[YES:bb[0-9]+]], [[NO:bb[0-9]+]]
+// CHECK:       [[YES]]:
+// CHECK:         [[ORIG_VAL:%.*]] = load [take] [[OUT]]
+// CHECK:         [[REABSTRACT:%.*]] = function_ref @$SytytIegnr_Ieg_TR
+// CHECK:         [[SUBST_VAL:%.*]] = partial_apply [callee_guaranteed] [[REABSTRACT]]([[ORIG_VAL]])
+
+func condFunctionFromAny(_ x: Any) {
+  if let f = x as? () -> () {
+    f()
+  }
+}
+
+// CHECK-LABEL: sil hidden @$S22downcast_reabstraction21uncondFunctionFromAnyyyypF : $@convention(thin) (@in_guaranteed Any) -> () {
+// CHECK:         unconditional_checked_cast_addr Any in [[IN:%.*]] : $*Any to () -> () in [[OUT:%.*]] : $*@callee_guaranteed (@in_guaranteed ()) -> @out ()
+// CHECK:         [[ORIG_VAL:%.*]] = load [take] [[OUT]]
+// CHECK:         [[REABSTRACT:%.*]] = function_ref @$SytytIegnr_Ieg_TR
+// CHECK:         [[SUBST_VAL:%.*]] = partial_apply [callee_guaranteed] [[REABSTRACT]]([[ORIG_VAL]])
+// CHECK:         [[BORROW:%.*]] = begin_borrow [[SUBST_VAL]]
+// CHECK:         apply [[BORROW]]()
+// CHECK:         end_borrow [[BORROW]] from [[SUBST_VAL]]
+// CHECK:         destroy_value [[SUBST_VAL]]
+func uncondFunctionFromAny(_ x: Any) {
+  (x as! () -> ())()
+}
diff --git a/test/SILGen/plus_zero_dynamic.swift b/test/SILGen/plus_zero_dynamic.swift
new file mode 100644
index 0000000..2376ae7
--- /dev/null
+++ b/test/SILGen/plus_zero_dynamic.swift
@@ -0,0 +1,557 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %empty-directory(%t)
+// RUN: %build-silgen-test-overlays
+
+// RUN: %target-swift-frontend(mock-sdk: -sdk %S/Inputs -I %t) -Xllvm -sil-full-demangle -primary-file %s %S/Inputs/dynamic_other.swift -emit-silgen | %FileCheck %s
+// RUN: %target-swift-frontend(mock-sdk: -sdk %S/Inputs -I %t) -Xllvm -sil-full-demangle -primary-file %s %S/Inputs/dynamic_other.swift -emit-sil -verify
+
+// REQUIRES: objc_interop
+
+import Foundation
+import gizmo
+
+class Foo: Proto {
+  // Not objc or dynamic, so only a vtable entry
+  init(native: Int) {}
+  func nativeMethod() {}
+  var nativeProp: Int = 0
+  subscript(native native: Int) -> Int {
+    get { return native }
+    set {}
+  }
+
+  // @objc, so it has an ObjC entry point but can also be dispatched
+  // by vtable
+  @objc init(objc: Int) {}
+  @objc func objcMethod() {}
+  @objc var objcProp: Int = 0
+  @objc subscript(objc objc: AnyObject) -> Int {
+    get { return 0 }
+    set {}
+  }
+
+  // dynamic, so it has only an ObjC entry point
+  dynamic init(dynamic: Int) {}
+  dynamic func dynamicMethod() {}
+  dynamic var dynamicProp: Int = 0
+  dynamic subscript(dynamic dynamic: Int) -> Int {
+    get { return dynamic }
+    set {}
+  }
+
+  func overriddenByDynamic() {}
+
+  @NSManaged var managedProp: Int
+}
+
+protocol Proto {
+  func nativeMethod()
+  var nativeProp: Int { get set }
+  subscript(native native: Int) -> Int { get set }
+
+  func objcMethod()
+  var objcProp: Int { get set }
+  subscript(objc objc: AnyObject) -> Int { get set }
+
+  func dynamicMethod()
+  var dynamicProp: Int { get set }
+  subscript(dynamic dynamic: Int) -> Int { get set }
+}
+
+// ObjC entry points for @objc and dynamic entry points
+
+// normal and @objc initializing ctors can be statically dispatched
+// CHECK-LABEL: sil hidden @$S7dynamic3FooC{{.*}}tcfC
+// CHECK:         function_ref @$S7dynamic3FooC{{.*}}tcfc
+
+// CHECK-LABEL: sil hidden @$S7dynamic3FooC{{.*}}tcfC
+// CHECK:         function_ref @$S7dynamic3FooC{{.*}}tcfc
+
+// CHECK-LABEL: sil hidden [thunk] @$S7dynamic3{{[_0-9a-zA-Z]*}}fcTo
+// CHECK-LABEL: sil hidden [thunk] @$S7dynamic3FooC10objcMethod{{[_0-9a-zA-Z]*}}FTo
+// CHECK-LABEL: sil hidden [transparent] [thunk] @$S7dynamic3FooC8objcPropSivgTo
+// CHECK-LABEL: sil hidden [transparent] [thunk] @$S7dynamic3FooC8objcPropSivsTo
+// CHECK-LABEL: sil hidden [thunk] @$S7dynamic3FooC4objcSiyXl_tcigTo
+// CHECK-LABEL: sil hidden [thunk] @$S7dynamic3FooC4objcSiyXl_tcisTo
+
+// TODO: dynamic initializing ctor must be objc dispatched
+// CHECK-LABEL: sil hidden @$S7dynamic3{{[_0-9a-zA-Z]*}}fC
+// CHECK:         function_ref @$S7dynamic3{{[_0-9a-zA-Z]*}}fcTD
+// CHECK-LABEL: sil shared [transparent] [serializable] [thunk] @$S7dynamic3{{[_0-9a-zA-Z]*}}fcTD
+// CHECK:         objc_method {{%.*}} : $Foo, #Foo.init!initializer.1.foreign :
+
+// CHECK-LABEL: sil hidden [thunk] @$S7dynamic3{{[_0-9a-zA-Z]*}}fcTo
+// CHECK-LABEL: sil hidden [thunk] @$S7dynamic3FooC0A6Method{{[_0-9a-zA-Z]*}}FTo
+// CHECK-LABEL: sil hidden [transparent] [thunk] @$S7dynamic3FooC0A4PropSivgTo
+// CHECK-LABEL: sil hidden [transparent] [thunk] @$S7dynamic3FooC0A4PropSivsTo
+// CHECK-LABEL: sil hidden [thunk] @$S7dynamic3FooCAAS2i_tcigTo
+// CHECK-LABEL: sil hidden [thunk] @$S7dynamic3FooCAAS2i_tcisTo
+
+// Protocol witnesses use best appropriate dispatch
+
+// Native witnesses use vtable dispatch:
+// CHECK-LABEL: sil private [transparent] [thunk] @$S7dynamic3FooCAA5ProtoA2aDP12nativeMethod{{[_0-9a-zA-Z]*}}FTW
+// CHECK:         class_method {{%.*}} : $Foo, #Foo.nativeMethod!1 :
+// CHECK-LABEL: sil private [transparent] [thunk] @$S7dynamic3FooCAA5ProtoA2aDP10nativePropSivgTW
+// CHECK:         class_method {{%.*}} : $Foo, #Foo.nativeProp!getter.1 :
+// CHECK-LABEL: sil private [transparent] [thunk] @$S7dynamic3FooCAA5ProtoA2aDP10nativePropSivsTW
+// CHECK:         class_method {{%.*}} : $Foo, #Foo.nativeProp!setter.1 :
+// CHECK-LABEL: sil private [transparent] [thunk] @$S7dynamic3FooCAA5ProtoA2aDP6nativeS2i_tcigTW
+// CHECK:         class_method {{%.*}} : $Foo, #Foo.subscript!getter.1 :
+// CHECK-LABEL: sil private [transparent] [thunk] @$S7dynamic3FooCAA5ProtoA2aDP6nativeS2i_tcisTW
+// CHECK:         class_method {{%.*}} : $Foo, #Foo.subscript!setter.1 :
+
+// @objc witnesses use vtable dispatch:
+// CHECK-LABEL: sil private [transparent] [thunk] @$S7dynamic3FooCAA5ProtoA2aDP10objcMethod{{[_0-9a-zA-Z]*}}FTW
+// CHECK:         class_method {{%.*}} : $Foo, #Foo.objcMethod!1 :
+// CHECK-LABEL: sil private [transparent] [thunk] @$S7dynamic3FooCAA5ProtoA2aDP8objcPropSivgTW
+// CHECK:         class_method {{%.*}} : $Foo, #Foo.objcProp!getter.1 :
+// CHECK-LABEL: sil private [transparent] [thunk] @$S7dynamic3FooCAA5ProtoA2aDP8objcPropSivsTW
+// CHECK:         class_method {{%.*}} : $Foo, #Foo.objcProp!setter.1 :
+// CHECK-LABEL: sil private [transparent] [thunk] @$S7dynamic3FooCAA5ProtoA2aDP4objcSiyXl_tcigTW
+// CHECK:         class_method {{%.*}} : $Foo, #Foo.subscript!getter.1 :
+// CHECK-LABEL: sil private [transparent] [thunk] @$S7dynamic3FooCAA5ProtoA2aDP4objcSiyXl_tcisTW
+// CHECK:         class_method {{%.*}} : $Foo, #Foo.subscript!setter.1 :
+
+// Dynamic witnesses use objc dispatch:
+// CHECK-LABEL: sil private [transparent] [thunk] @$S7dynamic3FooCAA5ProtoA2aDP0A6Method{{[_0-9a-zA-Z]*}}FTW
+// CHECK:         function_ref @$S7dynamic3FooC0A6Method{{[_0-9a-zA-Z]*}}FTD
+// CHECK-LABEL: sil shared [transparent] [serializable] [thunk] @$S7dynamic3FooC0A6Method{{[_0-9a-zA-Z]*}}FTD
+// CHECK:         objc_method {{%.*}} : $Foo, #Foo.dynamicMethod!1.foreign :
+
+// CHECK-LABEL: sil private [transparent] [thunk] @$S7dynamic3FooCAA5ProtoA2aDP0A4PropSivgTW
+// CHECK:         function_ref @$S7dynamic3FooC0A4PropSivgTD
+// CHECK-LABEL: sil shared [transparent] [serializable] [thunk] @$S7dynamic3FooC0A4PropSivgTD
+// CHECK:         objc_method {{%.*}} : $Foo, #Foo.dynamicProp!getter.1.foreign :
+
+// CHECK-LABEL: sil private [transparent] [thunk] @$S7dynamic3FooCAA5ProtoA2aDP0A4PropSivsTW
+// CHECK:         function_ref @$S7dynamic3FooC0A4PropSivsTD
+// CHECK-LABEL: sil shared [transparent] [serializable] [thunk] @$S7dynamic3FooC0A4PropSivsTD
+// CHECK:         objc_method {{%.*}} : $Foo, #Foo.dynamicProp!setter.1.foreign :
+
+// CHECK-LABEL: sil private [transparent] [thunk] @$S7dynamic3FooCAA5ProtoA2aDPAAS2i_tcigTW
+// CHECK:         function_ref @$S7dynamic3FooCAAS2i_tcigTD
+// CHECK-LABEL: sil shared [transparent] [serializable] [thunk] @$S7dynamic3FooCAAS2i_tcigTD
+// CHECK:         objc_method {{%.*}} : $Foo, #Foo.subscript!getter.1.foreign :
+
+// CHECK-LABEL: sil private [transparent] [thunk] @$S7dynamic3FooCAA5ProtoA2aDPAAS2i_tcisTW
+// CHECK:         function_ref @$S7dynamic3FooCAAS2i_tcisTD
+// CHECK-LABEL: sil shared [transparent] [serializable] [thunk] @$S7dynamic3FooCAAS2i_tcisTD
+// CHECK:         objc_method {{%.*}} : $Foo, #Foo.subscript!setter.1.foreign :
+
+// Superclass dispatch
+class Subclass: Foo {
+  // Native and objc methods can directly reference super members
+  override init(native: Int) {
+    super.init(native: native)
+  }
+  // CHECK-LABEL: sil hidden @$S7dynamic8SubclassC{{[_0-9a-zA-Z]*}}fC
+  // CHECK:         function_ref @$S7dynamic8SubclassC{{[_0-9a-zA-Z]*}}fc
+
+  override func nativeMethod() {
+    super.nativeMethod()
+  }
+  // CHECK-LABEL: sil hidden @$S7dynamic8SubclassC12nativeMethod{{[_0-9a-zA-Z]*}}F
+  // CHECK:         function_ref @$S7dynamic3FooC12nativeMethodyyF : $@convention(method) (@guaranteed Foo) -> ()
+
+  override var nativeProp: Int {
+    get { return super.nativeProp }
+    // CHECK-LABEL: sil hidden @$S7dynamic8SubclassC10nativePropSivg
+    // CHECK:         function_ref @$S7dynamic3FooC10nativePropSivg : $@convention(method) (@guaranteed Foo) -> Int
+    set { super.nativeProp = newValue }
+    // CHECK-LABEL: sil hidden @$S7dynamic8SubclassC10nativePropSivs
+    // CHECK:         function_ref @$S7dynamic3FooC10nativePropSivs : $@convention(method) (Int, @guaranteed Foo) -> ()
+  }
+
+  override subscript(native native: Int) -> Int {
+    get { return super[native: native] }
+    // CHECK-LABEL: sil hidden @$S7dynamic8SubclassC6nativeS2i_tcig
+    // CHECK:         function_ref @$S7dynamic3FooC6nativeS2i_tcig : $@convention(method) (Int, @guaranteed Foo) -> Int
+    set { super[native: native] = newValue }
+    // CHECK-LABEL: sil hidden @$S7dynamic8SubclassC6nativeS2i_tcis
+    // CHECK:         function_ref @$S7dynamic3FooC6nativeS2i_tcis : $@convention(method) (Int, Int, @guaranteed Foo) -> ()
+  }
+
+  override init(objc: Int) {
+    super.init(objc: objc)
+  }
+  // CHECK-LABEL: sil hidden @$S7dynamic8SubclassC4objcACSi_tcfc
+  // CHECK:         function_ref @$S7dynamic3FooC4objcACSi_tcfc : $@convention(method) (Int, @owned Foo) -> @owned Foo
+
+  override func objcMethod() {
+    super.objcMethod()
+  }
+  // CHECK-LABEL: sil hidden @$S7dynamic8SubclassC10objcMethod{{[_0-9a-zA-Z]*}}F
+  // CHECK:         function_ref @$S7dynamic3FooC10objcMethodyyF : $@convention(method) (@guaranteed Foo) -> ()
+
+  override var objcProp: Int {
+    get { return super.objcProp }
+    // CHECK-LABEL: sil hidden @$S7dynamic8SubclassC8objcPropSivg
+    // CHECK:         function_ref @$S7dynamic3FooC8objcPropSivg : $@convention(method) (@guaranteed Foo) -> Int
+    set { super.objcProp = newValue }
+    // CHECK-LABEL: sil hidden @$S7dynamic8SubclassC8objcPropSivs
+    // CHECK:         function_ref @$S7dynamic3FooC8objcPropSivs : $@convention(method) (Int, @guaranteed Foo) -> ()
+  }
+
+  override subscript(objc objc: AnyObject) -> Int {
+    get { return super[objc: objc] }
+    // CHECK-LABEL: sil hidden @$S7dynamic8SubclassC4objcSiyXl_tcig
+    // CHECK:         function_ref @$S7dynamic3FooC4objcSiyXl_tcig : $@convention(method) (@guaranteed AnyObject, @guaranteed Foo) -> Int
+    set { super[objc: objc] = newValue }
+    // CHECK-LABEL: sil hidden @$S7dynamic8SubclassC4objcSiyXl_tcis
+    // CHECK:         function_ref @$S7dynamic3FooC4objcSiyXl_tcis : $@convention(method) (Int, @owned AnyObject, @guaranteed Foo) -> ()
+  }
+
+  // Dynamic methods are super-dispatched by objc_msgSend
+  override init(dynamic: Int) {
+    super.init(dynamic: dynamic)
+  }
+  // CHECK-LABEL: sil hidden @$S7dynamic8SubclassC{{[_0-9a-zA-Z]*}}fc
+  // CHECK:         objc_super_method {{%.*}} : $Subclass, #Foo.init!initializer.1.foreign :
+
+  override func dynamicMethod() {
+    super.dynamicMethod()
+  }
+  // CHECK-LABEL: sil hidden @$S7dynamic8SubclassC0A6Method{{[_0-9a-zA-Z]*}}F
+  // CHECK:         objc_super_method {{%.*}} : $Subclass, #Foo.dynamicMethod!1.foreign :
+
+  override var dynamicProp: Int {
+    get { return super.dynamicProp }
+    // CHECK-LABEL: sil hidden @$S7dynamic8SubclassC0A4PropSivg
+    // CHECK:         objc_super_method {{%.*}} : $Subclass, #Foo.dynamicProp!getter.1.foreign :
+    set { super.dynamicProp = newValue }
+    // CHECK-LABEL: sil hidden @$S7dynamic8SubclassC0A4PropSivs
+    // CHECK:         objc_super_method {{%.*}} : $Subclass, #Foo.dynamicProp!setter.1.foreign :
+  }
+
+  override subscript(dynamic dynamic: Int) -> Int {
+    get { return super[dynamic: dynamic] }
+    // CHECK-LABEL: sil hidden @$S7dynamic8SubclassCAAS2i_tcig
+    // CHECK:         objc_super_method {{%.*}} : $Subclass, #Foo.subscript!getter.1.foreign :
+    set { super[dynamic: dynamic] = newValue }
+    // CHECK-LABEL: sil hidden @$S7dynamic8SubclassCAAS2i_tcis
+    // CHECK:         objc_super_method {{%.*}} : $Subclass, #Foo.subscript!setter.1.foreign :
+  }
+
+  dynamic override func overriddenByDynamic() {}
+}
+
+class SubclassWithInheritedInits: Foo {
+  // CHECK-LABEL: sil hidden @$S7dynamic26SubclassWithInheritedInitsC{{[_0-9a-zA-Z]*}}fc
+  // CHECK:         objc_super_method {{%.*}} : $SubclassWithInheritedInits, #Foo.init!initializer.1.foreign :
+}
+class GrandchildWithInheritedInits: SubclassWithInheritedInits {
+  // CHECK-LABEL: sil hidden @$S7dynamic28GrandchildWithInheritedInitsC{{[_0-9a-zA-Z]*}}fc
+  // CHECK:         objc_super_method {{%.*}} : $GrandchildWithInheritedInits, #SubclassWithInheritedInits.init!initializer.1.foreign :
+}
+class GrandchildOfInheritedInits: SubclassWithInheritedInits {
+  // Dynamic methods are super-dispatched by objc_msgSend
+  override init(dynamic: Int) {
+    super.init(dynamic: dynamic)
+  }
+  // CHECK-LABEL: sil hidden @$S7dynamic26GrandchildOfInheritedInitsC{{[_0-9a-zA-Z]*}}fc
+  // CHECK:         objc_super_method {{%.*}} : $GrandchildOfInheritedInits, #SubclassWithInheritedInits.init!initializer.1.foreign :
+}
+
+// CHECK-LABEL: sil hidden @$S7dynamic20nativeMethodDispatchyyF : $@convention(thin) () -> ()
+func nativeMethodDispatch() {
+  // CHECK: function_ref @$S7dynamic3{{[_0-9a-zA-Z]*}}fC
+  let c = Foo(native: 0)
+  // CHECK: class_method {{%.*}} : $Foo, #Foo.nativeMethod!1 :
+  c.nativeMethod()
+  // CHECK: class_method {{%.*}} : $Foo, #Foo.nativeProp!getter.1 :
+  let x = c.nativeProp
+  // CHECK: class_method {{%.*}} : $Foo, #Foo.nativeProp!setter.1 :
+  c.nativeProp = x
+  // CHECK: class_method {{%.*}} : $Foo, #Foo.subscript!getter.1 :
+  let y = c[native: 0]
+  // CHECK: class_method {{%.*}} : $Foo, #Foo.subscript!setter.1 :
+  c[native: 0] = y
+}
+
+// CHECK-LABEL: sil hidden @$S7dynamic18objcMethodDispatchyyF : $@convention(thin) () -> ()
+func objcMethodDispatch() {
+  // CHECK: function_ref @$S7dynamic3{{[_0-9a-zA-Z]*}}fC
+  let c = Foo(objc: 0)
+  // CHECK: class_method {{%.*}} : $Foo, #Foo.objcMethod!1 :
+  c.objcMethod()
+  // CHECK: class_method {{%.*}} : $Foo, #Foo.objcProp!getter.1 :
+  let x = c.objcProp
+  // CHECK: class_method {{%.*}} : $Foo, #Foo.objcProp!setter.1 :
+  c.objcProp = x
+  // CHECK: class_method {{%.*}} : $Foo, #Foo.subscript!getter.1 :
+  let y = c[objc: 0 as NSNumber]
+  // CHECK: class_method {{%.*}} : $Foo, #Foo.subscript!setter.1 :
+  c[objc: 0 as NSNumber] = y
+}
+
+// CHECK-LABEL: sil hidden @$S7dynamic0A14MethodDispatchyyF : $@convention(thin) () -> ()
+func dynamicMethodDispatch() {
+  // CHECK: function_ref @$S7dynamic3{{[_0-9a-zA-Z]*}}fC
+  let c = Foo(dynamic: 0)
+  // CHECK: objc_method {{%.*}} : $Foo, #Foo.dynamicMethod!1.foreign 
+  c.dynamicMethod()
+  // CHECK: objc_method {{%.*}} : $Foo, #Foo.dynamicProp!getter.1.foreign
+  let x = c.dynamicProp
+  // CHECK: objc_method {{%.*}} : $Foo, #Foo.dynamicProp!setter.1.foreign
+  c.dynamicProp = x
+  // CHECK: objc_method {{%.*}} : $Foo, #Foo.subscript!getter.1.foreign
+  let y = c[dynamic: 0]
+  // CHECK: objc_method {{%.*}} : $Foo, #Foo.subscript!setter.1.foreign
+  c[dynamic: 0] = y
+}
+
+// CHECK-LABEL: sil hidden @$S7dynamic15managedDispatchyyAA3FooCF
+func managedDispatch(_ c: Foo) {
+  // CHECK: objc_method {{%.*}} : $Foo, #Foo.managedProp!getter.1.foreign 
+  let x = c.managedProp
+  // CHECK: objc_method {{%.*}} : $Foo, #Foo.managedProp!setter.1.foreign
+  c.managedProp = x
+}
+
+// CHECK-LABEL: sil hidden @$S7dynamic21foreignMethodDispatchyyF
+func foreignMethodDispatch() {
+  // CHECK: function_ref @$SSo9GuisemeauC{{[_0-9a-zA-Z]*}}fC
+  let g = Guisemeau()!
+  // CHECK: objc_method {{%.*}} : $Gizmo, #Gizmo.frob!1.foreign
+  g.frob()
+  // CHECK: objc_method {{%.*}} : $Gizmo, #Gizmo.count!getter.1.foreign
+  let x = g.count
+  // CHECK: objc_method {{%.*}} : $Gizmo, #Gizmo.count!setter.1.foreign
+  g.count = x
+  // CHECK: objc_method {{%.*}} : $Guisemeau, #Guisemeau.subscript!getter.1.foreign
+  let y: Any! = g[0]
+  // CHECK: objc_method {{%.*}} : $Guisemeau, #Guisemeau.subscript!setter.1.foreign
+  g[0] = y
+  // CHECK: objc_method {{%.*}} : $NSObject, #NSObject.description!getter.1.foreign
+  _ = g.description
+}
+
+extension Gizmo {
+  // CHECK-LABEL: sil hidden @$SSo5GizmoC7dynamicE{{[_0-9a-zA-Z]*}}fc
+  // CHECK:         objc_method {{%.*}} : $Gizmo, #Gizmo.init!initializer.1.foreign
+  convenience init(convenienceInExtension: Int) {
+    self.init(bellsOn: convenienceInExtension)
+  }
+
+  // CHECK-LABEL: sil hidden @$SSo5GizmoC7dynamicE{{[_0-9a-zA-Z]*}}fC
+  // CHECK:         objc_method {{%.*}} : $@objc_metatype Gizmo.Type, #Gizmo.init!allocator.1.foreign
+  convenience init(foreignClassFactory x: Int) {
+    self.init(stuff: x)
+  }
+
+  // CHECK-LABEL: sil hidden @$SSo5GizmoC7dynamicE{{[_0-9a-zA-Z]*}}fC
+  // CHECK:         objc_method {{%.*}} : $@objc_metatype Gizmo.Type, #Gizmo.init!allocator.1.foreign
+  convenience init(foreignClassExactFactory x: Int) {
+    self.init(exactlyStuff: x)
+  }
+
+  @objc func foreignObjCExtension() { }
+  dynamic func foreignDynamicExtension() { }
+}
+
+// CHECK-LABEL: sil hidden @$S7dynamic24foreignExtensionDispatchyySo5GizmoCF
+// CHECK: bb0([[ARG:%.*]] : $Gizmo):
+func foreignExtensionDispatch(_ g: Gizmo) {
+  // CHECK: objc_method [[ARG]] : $Gizmo, #Gizmo.foreignObjCExtension!1.foreign : (Gizmo)
+  g.foreignObjCExtension()
+  // CHECK: objc_method [[ARG]] : $Gizmo, #Gizmo.foreignDynamicExtension!1.foreign
+  g.foreignDynamicExtension()
+}
+
+
+// CHECK-LABEL: sil hidden @$S7dynamic33nativeMethodDispatchFromOtherFileyyF : $@convention(thin) () -> ()
+func nativeMethodDispatchFromOtherFile() {
+  // CHECK: function_ref @$S7dynamic13FromOtherFile{{[_0-9a-zA-Z]*}}fC
+  let c = FromOtherFile(native: 0)
+  // CHECK: class_method {{%.*}} : $FromOtherFile, #FromOtherFile.nativeMethod!1 :
+  c.nativeMethod()
+  // CHECK: class_method {{%.*}} : $FromOtherFile, #FromOtherFile.nativeProp!getter.1 :
+  let x = c.nativeProp
+  // CHECK: class_method {{%.*}} : $FromOtherFile, #FromOtherFile.nativeProp!setter.1 :
+  c.nativeProp = x
+  // CHECK: class_method {{%.*}} : $FromOtherFile, #FromOtherFile.subscript!getter.1 :
+  let y = c[native: 0]
+  // CHECK: class_method {{%.*}} : $FromOtherFile, #FromOtherFile.subscript!setter.1 :
+  c[native: 0] = y
+}
+
+// CHECK-LABEL: sil hidden @$S7dynamic31objcMethodDispatchFromOtherFileyyF : $@convention(thin) () -> ()
+func objcMethodDispatchFromOtherFile() {
+  // CHECK: function_ref @$S7dynamic13FromOtherFile{{[_0-9a-zA-Z]*}}fC
+  let c = FromOtherFile(objc: 0)
+  // CHECK: class_method {{%.*}} : $FromOtherFile, #FromOtherFile.objcMethod!1 :
+  c.objcMethod()
+  // CHECK: class_method {{%.*}} : $FromOtherFile, #FromOtherFile.objcProp!getter.1 :
+  let x = c.objcProp
+  // CHECK: class_method {{%.*}} : $FromOtherFile, #FromOtherFile.objcProp!setter.1 :
+  c.objcProp = x
+  // CHECK: class_method {{%.*}} : $FromOtherFile, #FromOtherFile.subscript!getter.1 :
+  let y = c[objc: 0]
+  // CHECK: class_method {{%.*}} : $FromOtherFile, #FromOtherFile.subscript!setter.1 :
+  c[objc: 0] = y
+}
+
+// CHECK-LABEL: sil hidden @$S7dynamic0A27MethodDispatchFromOtherFileyyF : $@convention(thin) () -> ()
+func dynamicMethodDispatchFromOtherFile() {
+  // CHECK: function_ref @$S7dynamic13FromOtherFile{{[_0-9a-zA-Z]*}}fC
+  let c = FromOtherFile(dynamic: 0)
+  // CHECK: objc_method {{%.*}} : $FromOtherFile, #FromOtherFile.dynamicMethod!1.foreign
+  c.dynamicMethod()
+  // CHECK: objc_method {{%.*}} : $FromOtherFile, #FromOtherFile.dynamicProp!getter.1.foreign
+  let x = c.dynamicProp
+  // CHECK: objc_method {{%.*}} : $FromOtherFile, #FromOtherFile.dynamicProp!setter.1.foreign
+  c.dynamicProp = x
+  // CHECK: objc_method {{%.*}} : $FromOtherFile, #FromOtherFile.subscript!getter.1.foreign
+  let y = c[dynamic: 0]
+  // CHECK: objc_method {{%.*}} : $FromOtherFile, #FromOtherFile.subscript!setter.1.foreign
+  c[dynamic: 0] = y
+}
+
+// CHECK-LABEL: sil hidden @$S7dynamic28managedDispatchFromOtherFileyyAA0deF0CF
+func managedDispatchFromOtherFile(_ c: FromOtherFile) {
+  // CHECK: objc_method {{%.*}} : $FromOtherFile, #FromOtherFile.managedProp!getter.1.foreign
+  let x = c.managedProp
+  // CHECK: objc_method {{%.*}} : $FromOtherFile, #FromOtherFile.managedProp!setter.1.foreign
+  c.managedProp = x
+}
+
+// CHECK-LABEL: sil hidden @$S7dynamic0A16ExtensionMethodsyyAA13ObjCOtherFileCF
+func dynamicExtensionMethods(_ obj: ObjCOtherFile) {
+  // CHECK: objc_method {{%.*}} : $ObjCOtherFile, #ObjCOtherFile.extensionMethod!1.foreign
+  obj.extensionMethod()
+  // CHECK: objc_method {{%.*}} : $ObjCOtherFile, #ObjCOtherFile.extensionProp!getter.1.foreign
+  _ = obj.extensionProp
+
+  // CHECK: thick_to_objc_metatype {{%.*}} : $@thick ObjCOtherFile.Type to $@objc_metatype ObjCOtherFile.Type
+  // CHECK-NEXT: objc_method {{%.*}} : $@objc_metatype ObjCOtherFile.Type, #ObjCOtherFile.extensionClassProp!getter.1.foreign
+  _ = type(of: obj).extensionClassProp
+
+  // CHECK: objc_method {{%.*}} : $ObjCOtherFile, #ObjCOtherFile.dynExtensionMethod!1.foreign
+  obj.dynExtensionMethod()
+  // CHECK: objc_method {{%.*}} : $ObjCOtherFile, #ObjCOtherFile.dynExtensionProp!getter.1.foreign
+  _ = obj.dynExtensionProp
+
+  // CHECK: thick_to_objc_metatype {{%.*}} : $@thick ObjCOtherFile.Type to $@objc_metatype ObjCOtherFile.Type
+  // CHECK-NEXT: objc_method {{%.*}} : $@objc_metatype ObjCOtherFile.Type, #ObjCOtherFile.dynExtensionClassProp!getter.1.foreign
+  _ = type(of: obj).dynExtensionClassProp
+}
+
+public class Base {
+  dynamic var x: Bool { return false }
+}
+
+public class Sub : Base {
+  // CHECK-LABEL: sil hidden @$S7dynamic3SubC1xSbvg : $@convention(method) (@guaranteed Sub) -> Bool {
+  // CHECK: bb0([[SELF:%.*]] : $Sub):
+  // CHECK:     [[AUTOCLOSURE:%.*]] = function_ref @$S7dynamic3SubC1xSbvgSbyKXKfu_ : $@convention(thin) (@guaranteed Sub) -> (Bool, @error Error)
+  // CHECK:     [[SELF_COPY:%.*]] = copy_value [[SELF]]
+  // CHECK:     = partial_apply [callee_guaranteed] [[AUTOCLOSURE]]([[SELF_COPY]])
+  // CHECK:     return {{%.*}} : $Bool
+  // CHECK: } // end sil function '$S7dynamic3SubC1xSbvg'
+
+  // CHECK-LABEL: sil private [transparent] @$S7dynamic3SubC1xSbvgSbyKXKfu_ : $@convention(thin) (@guaranteed Sub) -> (Bool, @error Error) {
+  // CHECK: bb0([[VALUE:%.*]] : $Sub):
+  // CHECK:     [[VALUE_COPY:%.*]] = copy_value [[VALUE]]
+  // CHECK:     [[CASTED_VALUE_COPY:%.*]] = upcast [[VALUE_COPY]]
+  // CHECK:     [[BORROWED_CASTED_VALUE_COPY:%.*]] = begin_borrow [[CASTED_VALUE_COPY]]
+  // CHECK:     [[DOWNCAST_FOR_SUPERMETHOD:%.*]] = unchecked_ref_cast [[BORROWED_CASTED_VALUE_COPY]]
+  // CHECK:     [[SUPER:%.*]] = objc_super_method [[DOWNCAST_FOR_SUPERMETHOD]] : $Sub, #Base.x!getter.1.foreign : (Base) -> () -> Bool, $@convention(objc_method) (Base) -> ObjCBool
+  // CHECK:     end_borrow [[BORROWED_CASTED_VALUE_COPY]]
+  // CHECK:     = apply [[SUPER]]([[CASTED_VALUE_COPY]])
+  // CHECK:     destroy_value [[CASTED_VALUE_COPY]]
+  // CHECK: } // end sil function '$S7dynamic3SubC1xSbvgSbyKXKfu_'
+  override var x: Bool { return false || super.x }
+}
+
+public class BaseExt : NSObject {}
+
+extension BaseExt {
+  @objc public var count: Int {
+    return 0
+  }
+}
+
+public class SubExt : BaseExt {
+  public override var count: Int {
+    return 1
+  }
+}
+
+public class GenericBase<T> {
+  public func method(_: T) {}
+}
+
+public class ConcreteDerived : GenericBase<Int> {
+  public override dynamic func method(_: Int) {}
+}
+
+// The dynamic override has a different calling convention than the base,
+// so after re-abstracting the signature we must dispatch to the dynamic
+// thunk.
+
+// CHECK-LABEL: sil private @$S7dynamic15ConcreteDerivedC6methodyySiFAA11GenericBaseCADyyxFTV : $@convention(method) (@in_guaranteed Int, @guaranteed ConcreteDerived) -> ()
+// CHECK: bb0(%0 : $*Int, %1 : $ConcreteDerived):
+// CHECK-NEXT:  [[VALUE:%.*]] = load [trivial] %0 : $*Int
+// CHECK:       [[DYNAMIC_THUNK:%.*]] = function_ref @$S7dynamic15ConcreteDerivedC6methodyySiFTD : $@convention(method) (Int, @guaranteed ConcreteDerived) -> ()
+// CHECK-NEXT:  apply [[DYNAMIC_THUNK]]([[VALUE]], %1) : $@convention(method) (Int, @guaranteed ConcreteDerived) -> ()
+// CHECK:       return
+
+// Vtable contains entries for native and @objc methods, but not dynamic ones
+// CHECK-LABEL: sil_vtable Foo {
+// CHECK-NEXT:   #Foo.init!initializer.1: {{.*}} :   @$S7dynamic3FooC6nativeACSi_tcfc
+// CHECK-NEXT:   #Foo.nativeMethod!1: {{.*}} :       @$S7dynamic3FooC12nativeMethodyyF
+// CHECK-NEXT:   #Foo.nativeProp!getter.1: {{.*}} :  @$S7dynamic3FooC10nativePropSivg     // dynamic.Foo.nativeProp.getter : Swift.Int
+// CHECK-NEXT:   #Foo.nativeProp!setter.1: {{.*}} :  @$S7dynamic3FooC10nativePropSivs     // dynamic.Foo.nativeProp.setter : Swift.Int
+// CHECK-NEXT:   #Foo.nativeProp!materializeForSet.1
+// CHECK-NEXT:   #Foo.subscript!getter.1: {{.*}} :   @$S7dynamic3FooC6nativeS2i_tcig    // dynamic.Foo.subscript.getter : (native: Swift.Int) -> Swift.Int
+// CHECK-NEXT:   #Foo.subscript!setter.1: {{.*}} :   @$S7dynamic3FooC6nativeS2i_tcis    // dynamic.Foo.subscript.setter : (native: Swift.Int) -> Swift.Int
+// CHECK-NEXT:   #Foo.subscript!materializeForSet.1
+// CHECK-NEXT:   #Foo.init!initializer.1: {{.*}} :   @$S7dynamic3FooC4objcACSi_tcfc
+// CHECK-NEXT:   #Foo.objcMethod!1: {{.*}} :         @$S7dynamic3FooC10objcMethodyyF
+// CHECK-NEXT:   #Foo.objcProp!getter.1: {{.*}} :    @$S7dynamic3FooC8objcPropSivg  // dynamic.Foo.objcProp.getter : Swift.Int
+// CHECK-NEXT:   #Foo.objcProp!setter.1: {{.*}} :    @$S7dynamic3FooC8objcPropSivs  // dynamic.Foo.objcProp.setter : Swift.Int
+// CHECK-NEXT:   #Foo.objcProp!materializeForSet.1
+// CHECK-NEXT:   #Foo.subscript!getter.1: {{.*}} : @$S7dynamic3FooC4objcSiyXl_tcig // dynamic.Foo.subscript.getter : (objc: Swift.AnyObject) -> Swift.Int
+// CHECK-NEXT:   #Foo.subscript!setter.1: {{.*}} : @$S7dynamic3FooC4objcSiyXl_tcis // dynamic.Foo.subscript.setter : (objc: Swift.AnyObject) -> Swift.Int
+// CHECK-NEXT:   #Foo.subscript!materializeForSet
+// CHECK-NEXT:   #Foo.overriddenByDynamic!1: {{.*}} : @$S7dynamic3FooC19overriddenByDynamic{{[_0-9a-zA-Z]*}}
+// CHECK-NEXT:   #Foo.deinit!deallocator: {{.*}}
+// CHECK-NEXT: }
+
+// Vtable uses a dynamic thunk for dynamic overrides
+// CHECK-LABEL: sil_vtable Subclass {
+// CHECK:   #Foo.overriddenByDynamic!1: {{.*}} : public @$S7dynamic8SubclassC19overriddenByDynamic{{[_0-9a-zA-Z]*}}FTD
+// CHECK: }
+
+// Check vtables for implicitly-inherited initializers
+// CHECK-LABEL: sil_vtable SubclassWithInheritedInits {
+// CHECK:   #Foo.init!initializer.1: (Foo.Type) -> (Int) -> Foo : @$S7dynamic26SubclassWithInheritedInitsC6nativeACSi_tcfc
+// CHECK:   #Foo.init!initializer.1: (Foo.Type) -> (Int) -> Foo : @$S7dynamic26SubclassWithInheritedInitsC4objcACSi_tcfc
+// CHECK-NOT: .init!
+// CHECK: }
+
+// CHECK-LABEL: sil_vtable GrandchildWithInheritedInits {
+// CHECK:   #Foo.init!initializer.1: (Foo.Type) -> (Int) -> Foo : @$S7dynamic28GrandchildWithInheritedInitsC6nativeACSi_tcfc
+// CHECK:   #Foo.init!initializer.1: (Foo.Type) -> (Int) -> Foo : @$S7dynamic28GrandchildWithInheritedInitsC4objcACSi_tcfc
+// CHECK-NOT: .init!
+// CHECK: }
+
+// CHECK-LABEL: sil_vtable GrandchildOfInheritedInits {
+// CHECK:   #Foo.init!initializer.1: (Foo.Type) -> (Int) -> Foo : @$S7dynamic26GrandchildOfInheritedInitsC6nativeACSi_tcfc
+// CHECK:   #Foo.init!initializer.1: (Foo.Type) -> (Int) -> Foo : @$S7dynamic26GrandchildOfInheritedInitsC4objcACSi_tcfc
+// CHECK-NOT: .init!
+// CHECK: }
+
+// No vtable entry for override of @objc extension property
+// CHECK-LABEL: sil_vtable [serialized] SubExt {
+// CHECK-NEXT: #BaseExt.init!initializer.1: (BaseExt.Type) -> () -> BaseExt : @$S7dynamic6SubExtCACycfc [override] // dynamic.SubExt.init() -> dynamic.SubExt
+// CHECK-NEXT: #SubExt.deinit!deallocator: @$S7dynamic6SubExtCfD // dynamic.SubExt.__deallocating_deinit
+// CHECK-NEXT: }
+
+// Dynamic thunk + vtable re-abstraction
+// CHECK-LABEL: sil_vtable [serialized] ConcreteDerived {
+// CHECK-NEXT: #GenericBase.method!1: <T> (GenericBase<T>) -> (T) -> () : public @$S7dynamic15ConcreteDerivedC6methodyySiFAA11GenericBaseCADyyxFTV [override]     // vtable thunk for dynamic.GenericBase.method(A) -> () dispatching to dynamic.ConcreteDerived.method(Swift.Int) -> ()
+// CHECK-NEXT: #GenericBase.init!initializer.1: <T> (GenericBase<T>.Type) -> () -> GenericBase<T> : @$S7dynamic15ConcreteDerivedCACycfc [override]      // dynamic.ConcreteDerived.init() -> dynamic.ConcreteDerived
+// CHECK-NEXT: #ConcreteDerived.deinit!deallocator: @$S7dynamic15ConcreteDerivedCfD  // dynamic.ConcreteDerived.__deallocating_deinit
+// CHECK-NEXT: }
diff --git a/test/SILGen/plus_zero_dynamic_lookup.swift b/test/SILGen/plus_zero_dynamic_lookup.swift
new file mode 100644
index 0000000..64062f5
--- /dev/null
+++ b/test/SILGen/plus_zero_dynamic_lookup.swift
@@ -0,0 +1,361 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -parse-as-library -emit-silgen -disable-objc-attr-requires-foundation-module %s | %FileCheck %s
+// RUN: %target-swift-frontend -parse-as-library -emit-silgen -disable-objc-attr-requires-foundation-module  %s | %FileCheck %s --check-prefix=GUARANTEED
+
+// REQUIRES: objc_interop
+
+class X {
+  @objc func f() { }
+  @objc class func staticF() { }
+  @objc var value: Int {
+    return 17
+  }
+
+  @objc subscript (i: Int) -> Int {
+    get {
+      return i
+    }
+    set {}
+  }
+}
+
+@objc protocol P {
+  func g()
+}
+
+// CHECK-LABEL: sil hidden @$S14dynamic_lookup15direct_to_class{{[_0-9a-zA-Z]*}}F
+func direct_to_class(_ obj: AnyObject) {
+  // CHECK: bb0([[ARG:%.*]] : $AnyObject):
+  // CHECK: [[OPENED_ARG:%[0-9]+]] = open_existential_ref [[ARG]] : $AnyObject to $@opened({{.*}}) AnyObject
+  // CHECK: [[OPENED_ARG_COPY:%.*]] = copy_value [[OPENED_ARG]]
+  // CHECK: [[METHOD:%[0-9]+]] = objc_method [[OPENED_ARG_COPY]] : $@opened({{.*}}) AnyObject, #X.f!1.foreign : (X) -> () -> (), $@convention(objc_method) (@opened({{.*}}) AnyObject) -> ()
+  // CHECK: apply [[METHOD]]([[OPENED_ARG_COPY]]) : $@convention(objc_method) (@opened({{.*}}) AnyObject) -> ()
+  // CHECK: destroy_value [[OPENED_ARG_COPY]]
+  obj.f!()
+}
+// CHECK: } // end sil function '$S14dynamic_lookup15direct_to_class{{[_0-9a-zA-Z]*}}F'
+
+// CHECK-LABEL: sil hidden @$S14dynamic_lookup18direct_to_protocol{{[_0-9a-zA-Z]*}}F
+func direct_to_protocol(_ obj: AnyObject) {
+  // CHECK: bb0([[ARG:%.*]] : $AnyObject):
+  // CHECK:   [[OPENED_ARG:%[0-9]+]] = open_existential_ref [[ARG]] : $AnyObject to $@opened({{.*}}) AnyObject
+  // CHECK:   [[OPENED_ARG_COPY:%.*]] = copy_value [[OPENED_ARG]]
+  // CHECK:   [[METHOD:%[0-9]+]] = objc_method [[OPENED_ARG_COPY]] : $@opened({{.*}}) AnyObject, #P.g!1.foreign : <Self where Self : P> (Self) -> () -> (), $@convention(objc_method) (@opened({{.*}}) AnyObject) -> ()
+  // CHECK:   apply [[METHOD]]([[OPENED_ARG_COPY]]) : $@convention(objc_method) (@opened({{.*}}) AnyObject) -> ()
+  // CHECK:   destroy_value [[OPENED_ARG_COPY]]
+  obj.g!()
+}
+// CHECK: } // end sil function '$S14dynamic_lookup18direct_to_protocol{{[_0-9a-zA-Z]*}}F'
+
+// CHECK-LABEL: sil hidden @$S14dynamic_lookup23direct_to_static_method{{[_0-9a-zA-Z]*}}F
+func direct_to_static_method(_ obj: AnyObject) {
+  // CHECK: bb0([[ARG:%.*]] : $AnyObject):
+  var obj = obj
+  // CHECK: [[OBJBOX:%[0-9]+]] = alloc_box ${ var AnyObject }
+  // CHECK-NEXT: [[PBOBJ:%[0-9]+]] = project_box [[OBJBOX]]
+  // CHECK: [[ARG_COPY:%.*]] = copy_value [[ARG]]
+  // CHECK: store [[ARG_COPY]] to [init] [[PBOBJ]] : $*AnyObject
+  // CHECK: [[READ:%.*]] = begin_access [read] [unknown] [[PBOBJ]]
+  // CHECK-NEXT: [[OBJCOPY:%[0-9]+]] = load [copy] [[READ]] : $*AnyObject
+  // CHECK: end_access [[READ]]
+  // CHECK-NEXT: [[OBJMETA:%[0-9]+]] = existential_metatype $@thick AnyObject.Type, [[OBJCOPY]] : $AnyObject
+  // CHECK-NEXT: [[OPENMETA:%[0-9]+]] = open_existential_metatype [[OBJMETA]] : $@thick AnyObject.Type to $@thick (@opened([[UUID:".*"]]) AnyObject).Type
+  // CHECK-NEXT: [[METHOD:%[0-9]+]] = objc_method [[OPENMETA]] : $@thick (@opened([[UUID]]) AnyObject).Type, #X.staticF!1.foreign : (X.Type) -> () -> (), $@convention(objc_method) (@thick (@opened([[UUID]]) AnyObject).Type) -> ()
+  // CHECK: apply [[METHOD]]([[OPENMETA]]) : $@convention(objc_method) (@thick (@opened([[UUID]]) AnyObject).Type) -> ()
+  // CHECK: destroy_value [[OBJBOX]]
+  type(of: obj).staticF!()
+}
+// } // end sil function '_TF14dynamic_lookup23direct_to_static_method{{.*}}'
+
+// CHECK-LABEL: sil hidden @$S14dynamic_lookup12opt_to_class{{[_0-9a-zA-Z]*}}F
+func opt_to_class(_ obj: AnyObject) {
+  // CHECK: bb0([[ARG:%.*]] : $AnyObject):
+  var obj = obj
+  // CHECK:   [[EXISTBOX:%[0-9]+]] = alloc_box ${ var AnyObject } 
+  // CHECK:   [[PBOBJ:%[0-9]+]] = project_box [[EXISTBOX]]
+  // CHECK:   [[ARG_COPY:%.*]] = copy_value [[ARG]]
+  // CHECK:   store [[ARG_COPY]] to [init] [[PBOBJ]]
+  // CHECK:   [[OPTBOX:%[0-9]+]] = alloc_box ${ var Optional<@callee_guaranteed () -> ()> }
+  // CHECK:   [[PBOPT:%.*]] = project_box [[OPTBOX]]
+  // CHECK:   [[READ:%.*]] = begin_access [read] [unknown] [[PBOBJ]]
+  // CHECK:   [[EXISTVAL:%[0-9]+]] = load [copy] [[READ]] : $*AnyObject
+  // CHECK:   [[OBJ_SELF:%[0-9]*]] = open_existential_ref [[EXISTVAL]]
+  // CHECK:   [[OPT_TMP:%.*]] = alloc_stack $Optional<@callee_guaranteed () -> ()>
+  // CHECK:   dynamic_method_br [[OBJ_SELF]] : $@opened({{.*}}) AnyObject, #X.f!1.foreign, [[HASBB:[a-zA-z0-9]+]], [[NOBB:[a-zA-z0-9]+]]
+
+  // Has method BB:
+  // CHECK: [[HASBB]]([[UNCURRIED:%[0-9]+]] : $@convention(objc_method) (@opened({{.*}}) AnyObject) -> ()):
+  // CHECK:   [[OBJ_SELF_COPY:%.*]] = copy_value [[OBJ_SELF]]
+  // CHECK:   [[PARTIAL:%[0-9]+]] = partial_apply [callee_guaranteed] [[UNCURRIED]]([[OBJ_SELF_COPY]]) : $@convention(objc_method) (@opened({{.*}}) AnyObject) -> ()
+  // CHECK:   [[THUNK_PAYLOAD:%.*]] = init_enum_data_addr [[OPT_TMP]]
+  // CHECK:   store [[PARTIAL]] to [init] [[THUNK_PAYLOAD]]
+  // CHECK:   inject_enum_addr [[OPT_TMP]] : $*Optional<@callee_guaranteed () -> ()>, #Optional.some!enumelt.1
+  // CHECK:   br [[CONTBB:[a-zA-Z0-9]+]]
+
+  // No method BB:
+  // CHECK: [[NOBB]]:
+  // CHECK:   inject_enum_addr [[OPT_TMP]] : {{.*}}, #Optional.none!enumelt
+  // CHECK:   br [[CONTBB]]
+
+  // Continuation block
+  // CHECK: [[CONTBB]]:
+  // CHECK:   [[OPT:%.*]] = load [take] [[OPT_TMP]]
+  // CHECK:   store [[OPT]] to [init] [[PBOPT]] : $*Optional<@callee_guaranteed () -> ()>
+  // CHECK:   dealloc_stack [[OPT_TMP]]
+  var of: (() -> ())! = obj.f
+
+  // Exit
+  // CHECK:   destroy_value [[OBJ_SELF]] : $@opened({{".*"}}) AnyObject
+  // CHECK:   destroy_value [[OPTBOX]] : ${ var Optional<@callee_guaranteed () -> ()> }
+  // CHECK:   destroy_value [[EXISTBOX]] : ${ var AnyObject }
+  // CHECK:   [[RESULT:%[0-9]+]] = tuple ()
+  // CHECK:   return [[RESULT]] : $()
+}
+
+// CHECK-LABEL: sil hidden @$S14dynamic_lookup20forced_without_outer{{[_0-9a-zA-Z]*}}F
+func forced_without_outer(_ obj: AnyObject) {
+  // CHECK: dynamic_method_br
+  var f = obj.f!
+}
+
+// CHECK-LABEL: sil hidden @$S14dynamic_lookup20opt_to_static_method{{[_0-9a-zA-Z]*}}F
+func opt_to_static_method(_ obj: AnyObject) {
+  var obj = obj
+  // CHECK: bb0([[OBJ:%[0-9]+]] : $AnyObject):
+  // CHECK:   [[OBJBOX:%[0-9]+]] = alloc_box ${ var AnyObject }
+  // CHECK:   [[PBOBJ:%[0-9]+]] = project_box [[OBJBOX]]
+  // CHECK:   [[OBJ_COPY:%.*]] = copy_value [[OBJ]]
+  // CHECK:   store [[OBJ_COPY]] to [init] [[PBOBJ]] : $*AnyObject
+  // CHECK:   [[OPTBOX:%[0-9]+]] = alloc_box ${ var Optional<@callee_guaranteed () -> ()> }
+  // CHECK:   [[PBO:%.*]] = project_box [[OPTBOX]]
+  // CHECK:   [[READ:%.*]] = begin_access [read] [unknown] [[PBOBJ]]
+  // CHECK:   [[OBJCOPY:%[0-9]+]] = load [copy] [[READ]] : $*AnyObject
+  // CHECK:   [[OBJMETA:%[0-9]+]] = existential_metatype $@thick AnyObject.Type, [[OBJCOPY]] : $AnyObject
+  // CHECK:   [[OPENMETA:%[0-9]+]] = open_existential_metatype [[OBJMETA]] : $@thick AnyObject.Type to $@thick (@opened
+  // CHECK:   [[OBJCMETA:%[0-9]+]] = thick_to_objc_metatype [[OPENMETA]]
+  // CHECK:   [[OPTTEMP:%.*]] = alloc_stack $Optional<@callee_guaranteed () -> ()>
+  // CHECK:   dynamic_method_br [[OBJCMETA]] : $@objc_metatype (@opened({{".*"}}) AnyObject).Type, #X.staticF!1.foreign, [[HASMETHOD:[A-Za-z0-9_]+]], [[NOMETHOD:[A-Za-z0-9_]+]]
+  var optF: (() -> ())! = type(of: obj).staticF
+}
+
+// CHECK-LABEL: sil hidden @$S14dynamic_lookup15opt_to_property{{[_0-9a-zA-Z]*}}F
+func opt_to_property(_ obj: AnyObject) {
+  var obj = obj
+  // CHECK: bb0([[OBJ:%[0-9]+]] : $AnyObject):
+  // CHECK:   [[OBJ_BOX:%[0-9]+]] = alloc_box ${ var AnyObject }
+  // CHECK:   [[PBOBJ:%[0-9]+]] = project_box [[OBJ_BOX]]
+  // CHECK:   [[OBJ_COPY:%.*]] = copy_value [[OBJ]]
+  // CHECK:   store [[OBJ_COPY]] to [init] [[PBOBJ]] : $*AnyObject
+  // CHECK:   [[INT_BOX:%[0-9]+]] = alloc_box ${ var Int }
+  // CHECK:   project_box [[INT_BOX]]
+  // CHECK:   [[READ:%.*]] = begin_access [read] [unknown] [[PBOBJ]]
+  // CHECK:   [[OBJ:%[0-9]+]] = load [copy] [[READ]] : $*AnyObject
+  // CHECK:   [[RAWOBJ_SELF:%[0-9]+]] = open_existential_ref [[OBJ]] : $AnyObject
+  // CHECK:   [[OPTTEMP:%.*]] = alloc_stack $Optional<Int>
+  // CHECK:   dynamic_method_br [[RAWOBJ_SELF]] : $@opened({{.*}}) AnyObject, #X.value!getter.1.foreign, bb1, bb2
+
+  // CHECK: bb1([[METHOD:%[0-9]+]] : $@convention(objc_method) (@opened({{.*}}) AnyObject) -> Int):
+  // CHECK:   [[RAWOBJ_SELF_COPY:%.*]] = copy_value [[RAWOBJ_SELF]]
+  // CHECK:   [[BOUND_METHOD:%[0-9]+]] = partial_apply [callee_guaranteed] [[METHOD]]([[RAWOBJ_SELF_COPY]]) : $@convention(objc_method) (@opened({{.*}}) AnyObject) -> Int
+  // CHECK:   [[B:%.*]] = begin_borrow [[BOUND_METHOD]]
+  // CHECK:   [[VALUE:%[0-9]+]] = apply [[B]]() : $@callee_guaranteed () -> Int
+  // CHECK:   end_borrow [[B]]
+  // CHECK:   [[VALUETEMP:%.*]] = init_enum_data_addr [[OPTTEMP]]
+  // CHECK:   store [[VALUE]] to [trivial] [[VALUETEMP]]
+  // CHECK:   inject_enum_addr [[OPTTEMP]]{{.*}}some
+  // CHECK:   destroy_value [[BOUND_METHOD]]
+  // CHECK:   br bb3
+  var i: Int = obj.value!
+}
+// CHECK: } // end sil function '$S14dynamic_lookup15opt_to_property{{[_0-9a-zA-Z]*}}F'
+
+// GUARANTEED-LABEL: sil hidden @$S14dynamic_lookup15opt_to_property{{[_0-9a-zA-Z]*}}F
+  // GUARANTEED: bb0([[OBJ:%[0-9]+]] : $AnyObject):
+  // GUARANTEED:   [[OBJ_BOX:%[0-9]+]] = alloc_box ${ var AnyObject }
+  // GUARANTEED:   [[PBOBJ:%[0-9]+]] = project_box [[OBJ_BOX]]
+  // GUARANTEED:   [[OBJ_COPY:%.*]] = copy_value [[OBJ]]
+  // GUARANTEED:   store [[OBJ_COPY]] to [init] [[PBOBJ]] : $*AnyObject
+  // GUARANTEED:   [[INT_BOX:%[0-9]+]] = alloc_box ${ var Int }
+  // GUARANTEED:   project_box [[INT_BOX]]
+  // GUARANTEED:   [[READ:%.*]] = begin_access [read] [unknown] [[PBOBJ]]
+  // GUARANTEED:   [[OBJ:%[0-9]+]] = load [copy] [[READ]] : $*AnyObject
+  // GUARANTEED:   [[RAWOBJ_SELF:%[0-9]+]] = open_existential_ref [[OBJ]] : $AnyObject
+  // GUARANTEED:   [[OPTTEMP:%.*]] = alloc_stack $Optional<Int>
+  // GUARANTEED:   dynamic_method_br [[RAWOBJ_SELF]] : $@opened({{.*}}) AnyObject, #X.value!getter.1.foreign, bb1, bb2
+
+  // GUARANTEED: bb1([[METHOD:%[0-9]+]] : $@convention(objc_method) (@opened({{.*}}) AnyObject) -> Int):
+  // GUARANTEED:   [[RAWOBJ_SELF_COPY:%.*]] = copy_value [[RAWOBJ_SELF]]
+  // GUARANTEED:   [[BOUND_METHOD:%[0-9]+]] = partial_apply [callee_guaranteed] [[METHOD]]([[RAWOBJ_SELF_COPY]])
+  // GUARANTEED:   [[BEGIN_BORROW:%.*]] = begin_borrow [[BOUND_METHOD]]
+  // GUARANTEED:   [[VALUE:%[0-9]+]] = apply [[BEGIN_BORROW]]
+  // GUARANTEED:   end_borrow [[BEGIN_BORROW]] from [[BOUND_METHOD]]
+  // GUARANTEED:   [[VALUETEMP:%.*]] = init_enum_data_addr [[OPTTEMP]]
+  // GUARANTEED:   store [[VALUE]] to [trivial] [[VALUETEMP]]
+  // GUARANTEED:   inject_enum_addr [[OPTTEMP]]{{.*}}some
+  // GUARANTEED:   destroy_value [[BOUND_METHOD]]
+  // GUARANTEED:   br bb3
+
+// CHECK-LABEL: sil hidden @$S14dynamic_lookup19direct_to_subscript{{[_0-9a-zA-Z]*}}F
+func direct_to_subscript(_ obj: AnyObject, i: Int) {
+  var obj = obj
+  var i = i
+  // CHECK: bb0([[OBJ:%[0-9]+]] : $AnyObject, [[I:%[0-9]+]] : $Int):
+  // CHECK:   [[OBJ_BOX:%[0-9]+]] = alloc_box ${ var AnyObject }
+  // CHECK:   [[PBOBJ:%[0-9]+]] = project_box [[OBJ_BOX]]
+  // CHECK:   [[OBJ_COPY:%.*]] = copy_value [[OBJ]]
+  // CHECK:   store [[OBJ_COPY]] to [init] [[PBOBJ]] : $*AnyObject
+  // CHECK:   [[I_BOX:%[0-9]+]] = alloc_box ${ var Int }
+  // CHECK:   [[PBI:%.*]] = project_box [[I_BOX]]
+  // CHECK:   store [[I]] to [trivial] [[PBI]] : $*Int
+  // CHECK:   alloc_box ${ var Int }
+  // CHECK:   project_box
+  // CHECK:   [[READ:%.*]] = begin_access [read] [unknown] [[PBOBJ]]
+  // CHECK:   [[OBJ:%[0-9]+]] = load [copy] [[READ]] : $*AnyObject
+  // CHECK:   [[OBJ_REF:%[0-9]+]] = open_existential_ref [[OBJ]] : $AnyObject to $@opened({{.*}}) AnyObject
+  // CHECK:   [[READ:%.*]] = begin_access [read] [unknown] [[PBI]]
+  // CHECK:   [[I:%[0-9]+]] = load [trivial] [[READ]] : $*Int
+  // CHECK:   [[OPTTEMP:%.*]] = alloc_stack $Optional<Int>
+  // CHECK:   dynamic_method_br [[OBJ_REF]] : $@opened({{.*}}) AnyObject, #X.subscript!getter.1.foreign, bb1, bb2
+
+  // CHECK: bb1([[GETTER:%[0-9]+]] : $@convention(objc_method) (Int, @opened({{.*}}) AnyObject) -> Int):
+  // CHECK:   [[OBJ_REF_COPY:%.*]] = copy_value [[OBJ_REF]]
+  // CHECK:   [[GETTER_WITH_SELF:%[0-9]+]] = partial_apply [callee_guaranteed] [[GETTER]]([[OBJ_REF_COPY]]) : $@convention(objc_method) (Int, @opened({{.*}}) AnyObject) -> Int
+  // CHECK:   [[B:%.*]] = begin_borrow [[GETTER_WITH_SELF]]
+  // CHECK:   [[RESULT:%[0-9]+]] = apply [[B]]([[I]]) : $@callee_guaranteed (Int) -> Int
+  // CHECK:   end_borrow [[B]]
+  // CHECK:   [[RESULTTEMP:%.*]] = init_enum_data_addr [[OPTTEMP]]
+  // CHECK:   store [[RESULT]] to [trivial] [[RESULTTEMP]]
+  // CHECK:   inject_enum_addr [[OPTTEMP]]{{.*}}some
+  // CHECK:   destroy_value [[GETTER_WITH_SELF]]
+  // CHECK:   br bb3
+  var x: Int = obj[i]!
+}
+// CHECK: } // end sil function '$S14dynamic_lookup19direct_to_subscript{{[_0-9a-zA-Z]*}}F'
+
+// GUARANTEED-LABEL: sil hidden @$S14dynamic_lookup19direct_to_subscript{{[_0-9a-zA-Z]*}}F
+  // GUARANTEED: bb0([[OBJ:%[0-9]+]] : $AnyObject, [[I:%[0-9]+]] : $Int):
+  // GUARANTEED:   [[OBJ_BOX:%[0-9]+]] = alloc_box ${ var AnyObject }
+  // GUARANTEED:   [[PBOBJ:%[0-9]+]] = project_box [[OBJ_BOX]]
+  // GUARANTEED:   [[OBJ_COPY:%.*]] = copy_value [[OBJ]]
+  // GUARANTEED:   store [[OBJ_COPY]] to [init] [[PBOBJ]] : $*AnyObject
+  // GUARANTEED:   [[I_BOX:%[0-9]+]] = alloc_box ${ var Int }
+  // GUARANTEED:   [[PBI:%.*]] = project_box [[I_BOX]]
+  // GUARANTEED:   store [[I]] to [trivial] [[PBI]] : $*Int
+  // GUARANTEED:   alloc_box ${ var Int }
+  // GUARANTEED:   project_box
+  // GUARANTEED:   [[READ:%.*]] = begin_access [read] [unknown] [[PBOBJ]]
+  // GUARANTEED:   [[OBJ:%[0-9]+]] = load [copy] [[READ]] : $*AnyObject
+  // GUARANTEED:   [[OBJ_REF:%[0-9]+]] = open_existential_ref [[OBJ]] : $AnyObject to $@opened({{.*}}) AnyObject
+  // GUARANTEED:   [[READ:%.*]] = begin_access [read] [unknown] [[PBI]]
+  // GUARANTEED:   [[I:%[0-9]+]] = load [trivial] [[READ]] : $*Int
+  // GUARANTEED:   [[OPTTEMP:%.*]] = alloc_stack $Optional<Int>
+  // GUARANTEED:   dynamic_method_br [[OBJ_REF]] : $@opened({{.*}}) AnyObject, #X.subscript!getter.1.foreign, bb1, bb2
+
+  // GUARANTEED: bb1([[GETTER:%[0-9]+]] : $@convention(objc_method) (Int, @opened({{.*}}) AnyObject) -> Int):
+  // GUARANTEED:   [[OBJ_REF_COPY:%.*]] = copy_value [[OBJ_REF]]
+  // GUARANTEED:   [[GETTER_WITH_SELF:%[0-9]+]] = partial_apply [callee_guaranteed] [[GETTER]]([[OBJ_REF_COPY]])
+  // GUARANTEED:   [[BORROW:%.*]] = begin_borrow [[GETTER_WITH_SELF]]
+  // GUARANTEED:   [[RESULT:%[0-9]+]] = apply [[BORROW]]([[I]])
+  // GUARANTEED:   end_borrow [[BORROW]] from [[GETTER_WITH_SELF]]
+  // GUARANTEED:   [[RESULTTEMP:%.*]] = init_enum_data_addr [[OPTTEMP]]
+  // GUARANTEED:   store [[RESULT]] to [trivial] [[RESULTTEMP]]
+  // GUARANTEED:   inject_enum_addr [[OPTTEMP]]{{.*}}some
+  // GUARANTEED:   destroy_value [[GETTER_WITH_SELF]]
+  // GUARANTEED:   br bb3
+
+// CHECK-LABEL: sil hidden @$S14dynamic_lookup16opt_to_subscript{{[_0-9a-zA-Z]*}}F
+func opt_to_subscript(_ obj: AnyObject, i: Int) {
+  var obj = obj
+  var i = i
+  // CHECK: bb0([[OBJ:%[0-9]+]] : $AnyObject, [[I:%[0-9]+]] : $Int):
+  // CHECK:   [[OBJ_BOX:%[0-9]+]] = alloc_box ${ var AnyObject }
+  // CHECK:   [[PBOBJ:%[0-9]+]] = project_box [[OBJ_BOX]]
+  // CHECK:   [[OBJ_COPY:%.*]] = copy_value [[OBJ]]
+  // CHECK:   store [[OBJ_COPY]] to [init] [[PBOBJ]] : $*AnyObject
+  // CHECK:   [[I_BOX:%[0-9]+]] = alloc_box ${ var Int }
+  // CHECK:   [[PBI:%.*]] = project_box [[I_BOX]]
+  // CHECK:   store [[I]] to [trivial] [[PBI]] : $*Int
+  // CHECK:   [[READ:%.*]] = begin_access [read] [unknown] [[PBOBJ]]
+  // CHECK:   [[OBJ:%[0-9]+]] = load [copy] [[READ]] : $*AnyObject
+  // CHECK:   [[OBJ_REF:%[0-9]+]] = open_existential_ref [[OBJ]] : $AnyObject to $@opened({{.*}}) AnyObject
+  // CHECK:   [[READ:%.*]] = begin_access [read] [unknown] [[PBI]]
+  // CHECK:   [[I:%[0-9]+]] = load [trivial] [[READ]] : $*Int
+  // CHECK:   [[OPTTEMP:%.*]] = alloc_stack $Optional<Int>
+  // CHECK:   dynamic_method_br [[OBJ_REF]] : $@opened({{.*}}) AnyObject, #X.subscript!getter.1.foreign, bb1, bb2
+
+  // CHECK: bb1([[GETTER:%[0-9]+]] : $@convention(objc_method) (Int, @opened({{.*}}) AnyObject) -> Int):
+  // CHECK:   [[OBJ_REF_COPY:%.*]] = copy_value [[OBJ_REF]]
+  // CHECK:   [[GETTER_WITH_SELF:%[0-9]+]] = partial_apply [callee_guaranteed] [[GETTER]]([[OBJ_REF_COPY]]) : $@convention(objc_method) (Int, @opened({{.*}}) AnyObject) -> Int
+  // CHECK:   [[B:%.*]] = begin_borrow [[GETTER_WITH_SELF]]
+  // CHECK:   [[RESULT:%[0-9]+]] = apply [[B]]([[I]]) : $@callee_guaranteed (Int) -> Int
+  // CHECK:   end_borrow [[B]]
+  // CHECK:   [[RESULTTEMP:%.*]] = init_enum_data_addr [[OPTTEMP]]
+  // CHECK:   store [[RESULT]] to [trivial] [[RESULTTEMP]]
+  // CHECK:   inject_enum_addr [[OPTTEMP]]
+  // CHECK:   destroy_value [[GETTER_WITH_SELF]]
+  // CHECK:   br bb3
+  obj[i]
+}
+
+// CHECK-LABEL: sil hidden @$S14dynamic_lookup8downcast{{[_0-9a-zA-Z]*}}F
+func downcast(_ obj: AnyObject) -> X {
+  var obj = obj
+  // CHECK: bb0([[OBJ:%[0-9]+]] : $AnyObject):
+  // CHECK:   [[OBJ_BOX:%[0-9]+]] = alloc_box ${ var AnyObject }
+  // CHECK:   [[PBOBJ:%[0-9]+]] = project_box [[OBJ_BOX]]
+  // CHECK:   [[OBJ_COPY:%.*]] = copy_value [[OBJ]]
+  // CHECK:   store [[OBJ_COPY]] to [init] [[PBOBJ]] : $*AnyObject
+  // CHECK:   [[READ:%.*]] = begin_access [read] [unknown] [[PBOBJ]]
+  // CHECK:   [[OBJ:%[0-9]+]] = load [copy] [[READ]] : $*AnyObject
+  // CHECK:   [[X:%[0-9]+]] = unconditional_checked_cast [[OBJ]] : $AnyObject to $X
+  // CHECK:   destroy_value [[OBJ_BOX]] : ${ var AnyObject }
+  // CHECK:   return [[X]] : $X
+  return obj as! X
+}
+
+@objc class Juice { }
+
+@objc protocol Fruit {
+  @objc optional var juice: Juice { get }
+}
+
+// CHECK-LABEL: sil hidden @$S14dynamic_lookup7consumeyyAA5Fruit_pF
+// CHECK: bb0(%0 : $Fruit):
+// CHECK:        [[BOX:%.*]] = alloc_stack $Optional<Juice>
+// CHECK:        dynamic_method_br [[SELF:%.*]] : $@opened("{{.*}}") Fruit, #Fruit.juice!getter.1.foreign, bb1, bb2
+
+// CHECK: bb1([[FN:%.*]] : $@convention(objc_method) (@opened("{{.*}}") Fruit) -> @autoreleased Juice):
+// CHECK:   [[SELF_COPY:%.*]] = copy_value [[SELF]]
+// CHECK:   [[METHOD:%.*]] = partial_apply [callee_guaranteed] [[FN]]([[SELF_COPY]]) : $@convention(objc_method) (@opened("{{.*}}") Fruit) -> @autoreleased Juice
+// CHECK:   [[B:%.*]] = begin_borrow [[METHOD]]
+// CHECK:   [[RESULT:%.*]] = apply [[B]]() : $@callee_guaranteed () -> @owned Juice
+// CHECK:   end_borrow [[B]]
+// CHECK:   [[PAYLOAD:%.*]] = init_enum_data_addr [[BOX]] : $*Optional<Juice>, #Optional.some!enumelt.1
+// CHECK:   store [[RESULT]] to [init] [[PAYLOAD]]
+// CHECK:   inject_enum_addr [[BOX]] : $*Optional<Juice>, #Optional.some!enumelt.1
+// CHECK:   destroy_value [[METHOD]]
+// CHECK:   br bb3
+
+// CHECK: bb2:
+// CHECK:        inject_enum_addr [[BOX]] : $*Optional<Juice>, #Optional.none!enumelt
+// CHECK:        br bb3
+
+// CHECK: bb3:
+// CHECK:        return
+
+func consume(_ fruit: Fruit) {
+  _ = fruit.juice
+}
+
+// rdar://problem/29249513 -- looking up an IUO member through AnyObject
+// produces a Foo!? type. The SIL verifier did not correctly consider Optional
+// to be the lowering of IUO (which is now eliminated by SIL lowering).
+
+@objc protocol IUORequirement {
+  var iuoProperty: AnyObject! { get }
+}
+
+func getIUOPropertyDynamically(x: AnyObject) -> Any {
+  return x.iuoProperty
+}
+
diff --git a/test/SILGen/plus_zero_dynamic_lookup_throws.swift b/test/SILGen/plus_zero_dynamic_lookup_throws.swift
new file mode 100644
index 0000000..6b2a455
--- /dev/null
+++ b/test/SILGen/plus_zero_dynamic_lookup_throws.swift
@@ -0,0 +1,30 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %empty-directory(%t)
+// RUN: %build-clang-importer-objc-overlays
+
+// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk-nosource -I %t) -emit-silgen -parse-as-library %s | %FileCheck %s
+
+// REQUIRES: objc_interop
+
+import Foundation
+
+class Blub : NSObject {
+   func blub() throws {}
+}
+
+// CHECK-LABEL: sil hidden @$S21dynamic_lookup_throws8testBlub1ayyXl_tKF : $@convention(thin) (@guaranteed AnyObject) -> @error Error
+// CHECK: bb0([[ARG:%.*]] : $AnyObject):
+func testBlub(a: AnyObject) throws {
+  // CHECK:   [[ANYOBJECT_REF:%.*]] = open_existential_ref [[ARG]] : $AnyObject to $@opened("[[OPENED:.*]]") AnyObject
+  // CHECK:   [[ANYOBJECT_REF_COPY:%.*]] = copy_value [[ANYOBJECT_REF]]
+  // CHECK:   objc_method [[ANYOBJECT_REF_COPY]] : $@opened("[[OPENED]]") AnyObject, #Blub.blub!1.foreign : (Blub) -> () throws -> (), $@convention(objc_method) (Optional<AutoreleasingUnsafeMutablePointer<Optional<NSError>>>, @opened("[[OPENED]]") AnyObject) -> ObjCBool
+  // CHECK:   cond_br {{%.*}}, bb1, bb2
+
+  // CHECK: bb1
+  // CHECK:   return
+
+  // CHECK: bb2
+  // CHECK:   function_ref @$S10Foundation22_convertNSErrorToErrorys0E0_pSo0C0CSgF
+  // CHECK:   throw {{%.*}} : $Error
+  try a.blub()
+}
diff --git a/test/SILGen/plus_zero_dynamic_self.swift b/test/SILGen/plus_zero_dynamic_self.swift
new file mode 100644
index 0000000..d02f276
--- /dev/null
+++ b/test/SILGen/plus_zero_dynamic_self.swift
@@ -0,0 +1,375 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership %s -disable-objc-attr-requires-foundation-module | %FileCheck %s
+// RUN: %target-swift-frontend -emit-sil -O %s -disable-objc-attr-requires-foundation-module
+// RUN: %target-swift-frontend -emit-ir %s -disable-objc-attr-requires-foundation-module
+
+protocol P {
+  func f() -> Self
+}
+
+protocol CP : class {
+  func f() -> Self
+}
+
+class X : P, CP {
+  required init(int i: Int) { }
+
+  // CHECK-LABEL: sil hidden @$S12dynamic_self1XC1f{{[_0-9a-zA-Z]*}}F : $@convention(method) (@guaranteed X) -> @owned
+  func f() -> Self { return self }
+
+  // CHECK-LABEL: sil hidden @$S12dynamic_self1XC7factory{{[_0-9a-zA-Z]*}}FZ : $@convention(method) (Int, @thick X.Type) -> @owned X
+  // CHECK: bb0([[I:%[0-9]+]] : @trivial $Int, [[SELF:%[0-9]+]] : @trivial $@thick X.Type):
+  // CHECK: [[DYNAMIC_SELF:%[0-9]+]] = unchecked_trivial_bit_cast [[SELF]] : $@thick X.Type to $@thick @dynamic_self X.Type
+  // CHECK: [[STATIC_SELF:%[0-9]+]] = upcast [[DYNAMIC_SELF]] : $@thick @dynamic_self X.Type to $@thick X.Type
+  // CHECK: [[CTOR:%[0-9]+]] = class_method [[STATIC_SELF]] : $@thick X.Type, #X.init!allocator.1 : (X.Type) -> (Int) -> X, $@convention(method) (Int, @thick X.Type) -> @owned X
+  // CHECK: apply [[CTOR]]([[I]], [[STATIC_SELF]]) : $@convention(method) (Int, @thick X.Type) -> @owned X
+  class func factory(i: Int) -> Self { return self.init(int: i) }
+}
+
+class Y : X { 
+  required init(int i: Int) {
+    super.init(int: i)
+  }
+}
+
+class GX<T> {
+  func f() -> Self { return self }
+}
+
+class GY<T> : GX<[T]> { }
+
+// CHECK-LABEL: sil hidden @$S12dynamic_self23testDynamicSelfDispatch{{[_0-9a-zA-Z]*}}F : $@convention(thin) (@guaranteed Y) -> ()
+// CHECK: bb0([[Y:%[0-9]+]] : @guaranteed $Y):
+// CHECK:   [[Y_AS_X:%[0-9]+]] = upcast [[Y]] : $Y to $X
+// CHECK:   [[X_F:%[0-9]+]] = class_method [[Y_AS_X]] : $X, #X.f!1 : (X) -> () -> @dynamic_self X, $@convention(method) (@guaranteed X) -> @owned X
+// CHECK:   [[X_RESULT:%[0-9]+]] = apply [[X_F]]([[Y_AS_X]]) : $@convention(method) (@guaranteed X) -> @owned X
+// CHECK:   [[Y_RESULT:%[0-9]+]] = unchecked_ref_cast [[X_RESULT]] : $X to $Y
+// CHECK:   destroy_value [[Y_RESULT]] : $Y
+func testDynamicSelfDispatch(y: Y) {
+  _ = y.f()
+}
+
+// CHECK-LABEL: sil hidden @$S12dynamic_self30testDynamicSelfDispatchGeneric{{[_0-9a-zA-Z]*}}F : $@convention(thin) (@guaranteed GY<Int>) -> ()
+func testDynamicSelfDispatchGeneric(gy: GY<Int>) {
+  // CHECK: bb0([[GY:%[0-9]+]] : @guaranteed $GY<Int>):
+  // CHECK:   [[GY_AS_GX:%[0-9]+]] = upcast [[GY]] : $GY<Int> to $GX<Array<Int>>
+  // CHECK:   [[GX_F:%[0-9]+]] = class_method [[GY_AS_GX]] : $GX<Array<Int>>, #GX.f!1 : <T> (GX<T>) -> () -> @dynamic_self GX<T>, $@convention(method) <τ_0_0> (@guaranteed GX<τ_0_0>) -> @owned GX<τ_0_0>
+  // CHECK:   [[GX_RESULT:%[0-9]+]] = apply [[GX_F]]<[Int]>([[GY_AS_GX]]) : $@convention(method) <τ_0_0> (@guaranteed GX<τ_0_0>) -> @owned GX<τ_0_0>
+  // CHECK:   [[GY_RESULT:%[0-9]+]] = unchecked_ref_cast [[GX_RESULT]] : $GX<Array<Int>> to $GY<Int>
+  // CHECK:   destroy_value [[GY_RESULT]] : $GY<Int>
+  _ = gy.f()
+}
+
+// CHECK-LABEL: sil hidden @$S12dynamic_self21testArchetypeDispatch{{[_0-9a-zA-Z]*}}F : $@convention(thin) <T where T : P> (@in_guaranteed T) -> ()
+func testArchetypeDispatch<T: P>(t: T) {
+  // CHECK: bb0([[T:%[0-9]+]] : @trivial $*T):
+  // CHECK:   [[T_RESULT:%[0-9]+]] = alloc_stack $T
+  // CHECK:   [[ARCHETYPE_F:%[0-9]+]] = witness_method $T, #P.f!1 : {{.*}} : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @out τ_0_0
+  // CHECK:   [[SELF_RESULT:%[0-9]+]] = apply [[ARCHETYPE_F]]<T>([[T_RESULT]], [[T]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @out τ_0_0
+  _ = t.f()
+}
+
+// CHECK-LABEL: sil hidden @$S12dynamic_self23testExistentialDispatch{{[_0-9a-zA-Z]*}}F
+func testExistentialDispatch(p: P) {
+// CHECK: bb0([[P:%[0-9]+]] : @trivial $*P):
+// CHECK:   [[PCOPY_ADDR:%[0-9]+]] = open_existential_addr immutable_access [[P]] : $*P to $*@opened([[N:".*"]]) P
+// CHECK:   [[P_RESULT:%[0-9]+]] = alloc_stack $P
+// CHECK:   [[P_RESULT_ADDR:%[0-9]+]] = init_existential_addr [[P_RESULT]] : $*P, $@opened([[N]]) P
+// CHECK:   [[P_F_METHOD:%[0-9]+]] = witness_method $@opened([[N]]) P, #P.f!1 : {{.*}}, [[PCOPY_ADDR]]{{.*}} : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @out τ_0_0
+// CHECK:   apply [[P_F_METHOD]]<@opened([[N]]) P>([[P_RESULT_ADDR]], [[PCOPY_ADDR]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @out τ_0_0
+// CHECK:   destroy_addr [[P_RESULT]] : $*P
+// CHECK:   dealloc_stack [[P_RESULT]] : $*P
+  _ = p.f()
+}
+
+// CHECK-LABEL: sil hidden @$S12dynamic_self28testExistentialDispatchClass{{[_0-9a-zA-Z]*}}F : $@convention(thin) (@guaranteed CP) -> ()
+// CHECK: bb0([[CP:%[0-9]+]] : @guaranteed $CP):
+// CHECK:   [[CP_ADDR:%[0-9]+]] = open_existential_ref [[CP]] : $CP to $@opened([[N:".*"]]) CP
+// CHECK:   [[CP_F:%[0-9]+]] = witness_method $@opened([[N]]) CP, #CP.f!1 : {{.*}}, [[CP_ADDR]]{{.*}} : $@convention(witness_method: CP) <τ_0_0 where τ_0_0 : CP> (@guaranteed τ_0_0) -> @owned τ_0_0
+// CHECK:   [[CP_F_RESULT:%[0-9]+]] = apply [[CP_F]]<@opened([[N]]) CP>([[CP_ADDR]]) : $@convention(witness_method: CP) <τ_0_0 where τ_0_0 : CP> (@guaranteed τ_0_0) -> @owned τ_0_0
+// CHECK:   [[RESULT_EXISTENTIAL:%[0-9]+]] = init_existential_ref [[CP_F_RESULT]] : $@opened([[N]]) CP : $@opened([[N]]) CP, $CP
+// CHECK:   destroy_value [[RESULT_EXISTENTIAL]]
+func testExistentialDispatchClass(cp: CP) {
+  _ = cp.f()
+}
+
+@objc class ObjC {
+  @objc func method() -> Self { return self }
+}
+
+// CHECK-LABEL: sil hidden @$S12dynamic_self21testAnyObjectDispatch1oyyXl_tF : $@convention(thin) (@guaranteed AnyObject) -> () {
+func testAnyObjectDispatch(o: AnyObject) {
+  // CHECK: dynamic_method_br [[O_OBJ:%[0-9]+]] : $@opened({{.*}}) AnyObject, #ObjC.method!1.foreign, bb1, bb2
+
+  // CHECK: bb1([[METHOD:%[0-9]+]] : @trivial $@convention(objc_method) (@opened({{.*}}) AnyObject) -> @autoreleased AnyObject):
+  // CHECK:   [[O_OBJ_COPY:%.*]] = copy_value [[O_OBJ]]
+  // CHECK:   [[VAR_9:%[0-9]+]] = partial_apply [callee_guaranteed] [[METHOD]]([[O_OBJ_COPY]]) : $@convention(objc_method) (@opened({{.*}}) AnyObject) -> @autoreleased AnyObject
+  var _ = o.method
+}
+// CHECK: } // end sil function '$S12dynamic_self21testAnyObjectDispatch1oyyXl_tF'
+
+
+// <rdar://problem/16270889> Dispatch through ObjC metatypes.
+class ObjCInit {
+  dynamic required init() { }
+}
+
+// CHECK-LABEL: sil hidden @$S12dynamic_self12testObjCInit{{[_0-9a-zA-Z]*}}F : $@convention(thin) (@thick ObjCInit.Type) -> ()
+func testObjCInit(meta: ObjCInit.Type) {
+// CHECK: bb0([[THICK_META:%[0-9]+]] : @trivial $@thick ObjCInit.Type):
+// CHECK:   [[OBJC_META:%[0-9]+]] = thick_to_objc_metatype [[THICK_META]] : $@thick ObjCInit.Type to $@objc_metatype ObjCInit.Type
+// CHECK:   [[OBJ:%[0-9]+]] = alloc_ref_dynamic [objc] [[OBJC_META]] : $@objc_metatype ObjCInit.Type, $ObjCInit
+// CHECK:   [[INIT:%[0-9]+]] = objc_method [[OBJ]] : $ObjCInit, #ObjCInit.init!initializer.1.foreign : (ObjCInit.Type) -> () -> ObjCInit, $@convention(objc_method) (@owned ObjCInit) -> @owned ObjCInit
+// CHECK:   [[RESULT_OBJ:%[0-9]+]] = apply [[INIT]]([[OBJ]]) : $@convention(objc_method) (@owned ObjCInit) -> @owned ObjCInit
+// CHECK:   [[RESULT:%[0-9]+]] = tuple ()
+// CHECK:   return [[RESULT]] : $()
+  _ = meta.init()
+}
+
+class OptionalResult {
+  func foo() -> Self? { return self }
+}
+
+// CHECK-LABEL: sil hidden @$S12dynamic_self14OptionalResultC3fooACXDSgyF : $@convention(method) (@guaranteed OptionalResult) -> @owned Optional<OptionalResult> {
+// CHECK: bb0([[SELF:%.*]] : @guaranteed $OptionalResult):
+// CHECK-NEXT: debug_value [[SELF]] : $OptionalResult
+// CHECK-NEXT: [[SELF_COPY:%.*]] = copy_value [[SELF]]
+// CHECK-NEXT: [[T0:%.*]] = enum $Optional<OptionalResult>, #Optional.some!enumelt.1, [[SELF_COPY]] : $OptionalResult
+// CHECK-NEXT: return [[T0]] : $Optional<OptionalResult>
+// CHECK: } // end sil function '$S12dynamic_self14OptionalResultC3fooACXDSgyF'
+
+class OptionalResultInheritor : OptionalResult {
+  func bar() {}
+}
+
+func testOptionalResult(v : OptionalResultInheritor) {
+  v.foo()?.bar()
+}
+
+// CHECK-LABEL: sil hidden @$S12dynamic_self18testOptionalResult1vyAA0dE9InheritorC_tF : $@convention(thin) (@guaranteed OptionalResultInheritor) -> () {
+// CHECK: bb0([[ARG:%.*]] : @guaranteed $OptionalResultInheritor):
+// CHECK:      [[CAST_ARG:%.*]] = upcast [[ARG]]
+// CHECK:      [[T0:%.*]] = class_method [[CAST_ARG]] : $OptionalResult, #OptionalResult.foo!1 : (OptionalResult) -> () -> @dynamic_self OptionalResult?, $@convention(method) (@guaranteed OptionalResult) -> @owned Optional<OptionalResult>
+// CHECK-NEXT: [[RES:%.*]] = apply [[T0]]([[CAST_ARG]])
+// CHECK-NEXT: [[T4:%.*]] = unchecked_ref_cast [[RES]] : $Optional<OptionalResult> to $Optional<OptionalResultInheritor>
+
+func id<T>(_ t: T) -> T { return t }
+
+class Z {
+
+  required init() {}
+
+  // CHECK-LABEL: sil hidden @$S12dynamic_self1ZC23testDynamicSelfCaptures1xACXDSi_tF : $@convention(method) (Int, @guaranteed Z) -> @owned Z {
+  func testDynamicSelfCaptures(x: Int) -> Self {
+    // CHECK: bb0({{.*}}, [[SELF:%.*]] : @guaranteed $Z):
+
+    // Single capture of 'self' type
+
+    // CHECK:      [[FN:%.*]] = function_ref @$S12dynamic_self1ZC23testDynamicSelfCaptures1xACXDSi_tFyycfU_ : $@convention(thin) (@guaranteed Z) -> ()
+    // CHECK-NEXT: [[SELF_COPY:%.*]] = copy_value [[SELF]] : $Z
+    // CHECK-NEXT: partial_apply [callee_guaranteed] [[FN]]([[SELF_COPY]])
+    let fn1 = { _ = self }
+    fn1()
+
+    // Capturing 'self', but it's not the last capture. Make sure it ends
+    // up at the end of the list anyway
+
+    // CHECK:      [[FN:%.*]] = function_ref @$S12dynamic_self1ZC23testDynamicSelfCaptures1xACXDSi_tFyycfU0_ : $@convention(thin) (Int, @guaranteed Z) -> ()
+    // CHECK-NEXT: [[SELF_COPY:%.*]] = copy_value [[SELF]] : $Z
+    // CHECK-NEXT: partial_apply [callee_guaranteed] [[FN]]({{.*}}, [[SELF_COPY]])
+    let fn2 = {
+      _ = self
+      _ = x
+    }
+    fn2()
+
+    // Capturing 'self' weak, so we have to pass in a metatype explicitly
+    // so that IRGen can recover metadata.
+
+    // CHECK:      [[WEAK_SELF:%.*]] = alloc_box ${ var @sil_weak Optional<Z> }
+    // CHECK:      [[FN:%.*]] = function_ref @$S12dynamic_self1ZC23testDynamicSelfCaptures1xACXDSi_tFyycfU1_ : $@convention(thin) (@guaranteed { var @sil_weak Optional<Z> }, @thick @dynamic_self Z.Type) -> ()
+    // CHECK:      [[WEAK_SELF_COPY:%.*]] = copy_value [[WEAK_SELF]] : ${ var @sil_weak Optional<Z> }
+    // CHECK-NEXT: [[DYNAMIC_SELF:%.*]] = metatype $@thick @dynamic_self Z.Type
+    // CHECK:      partial_apply [callee_guaranteed] [[FN]]([[WEAK_SELF_COPY]], [[DYNAMIC_SELF]]) : $@convention(thin) (@guaranteed { var @sil_weak Optional<Z> }, @thick @dynamic_self Z.Type) -> ()
+    let fn3 = {
+      [weak self] in
+      _ = self
+    }
+    fn3()
+
+    // Capturing a value with a complex type involving self
+
+    // CHECK:      [[FN:%.*]] = function_ref @$S12dynamic_self1ZC23testDynamicSelfCaptures1xACXDSi_tFyycfU2_ : $@convention(thin) (@guaranteed (Z, Z), @thick @dynamic_self Z.Type) -> ()
+    let xx = (self, self)
+    let fn4 = {
+      _ = xx
+    }
+    fn4()
+
+    return self
+  }
+
+  // Capturing metatype of dynamic self
+  static func testStaticMethodDynamicSelfCaptures() -> Self {
+    let fn0 = { _ = self; _ = { _ = self } }
+    fn0()
+
+    let x = self
+    let fn1 = { _ = x; _ = { _ = x } }
+    fn1()
+
+    let xx = (self, self)
+    let fn2 = { _ = xx; _ = { _ = xx } }
+    fn2()
+
+    return self.init()
+  }
+
+  // Make sure the actual self value has the same lowered type as the
+  // substituted result of a generic function call
+  func testDynamicSelfSubstitution(_ b: Bool) -> Self {
+    return b ? self : id(self)
+  }
+
+  // Same for metatype of self
+  static func testStaticMethodDynamicSelfSubstitution(_ b: Bool) -> Self {
+    _ = (b ? self : id(self))
+    return self.init()
+  }
+}
+
+// Unbound reference to a method returning Self.
+
+class Factory {
+  required init() {}
+
+  func newInstance() -> Self { return self }
+  class func classNewInstance() -> Self { return self.init() }
+  static func staticNewInstance() -> Self { return self.init() }
+}
+
+// CHECK-LABEL: sil hidden @$S12dynamic_self22partialApplySelfReturn1c1tyAA7FactoryC_AFmtF : $@convention(thin) (@guaranteed Factory, @thick Factory.Type) -> ()
+func partialApplySelfReturn(c: Factory, t: Factory.Type) {
+  // CHECK: function_ref @$S12dynamic_self7FactoryC11newInstanceACXDyFTc : $@convention(thin) (@guaranteed Factory) -> @owned @callee_guaranteed () -> @owned Factory
+  _ = c.newInstance
+  // CHECK: function_ref @$S12dynamic_self7FactoryC11newInstanceACXDyFTc : $@convention(thin) (@guaranteed Factory) -> @owned @callee_guaranteed () -> @owned Factory
+  _ = Factory.newInstance
+  // CHECK: function_ref @$S12dynamic_self7FactoryC11newInstanceACXDyFTc : $@convention(thin) (@guaranteed Factory) -> @owned @callee_guaranteed () -> @owned Factory
+  _ = t.newInstance
+  _ = type(of: c).newInstance
+
+  // CHECK: function_ref @$S12dynamic_self7FactoryC16classNewInstanceACXDyFZTc : $@convention(thin) (@thick Factory.Type) -> @owned @callee_guaranteed () -> @owned Factory
+  _ = t.classNewInstance
+  // CHECK: function_ref @$S12dynamic_self7FactoryC16classNewInstanceACXDyFZTc : $@convention(thin) (@thick Factory.Type) -> @owned @callee_guaranteed () -> @owned Factory
+  _ = type(of: c).classNewInstance
+  // CHECK: function_ref @$S12dynamic_self7FactoryC16classNewInstanceACXDyFZTc : $@convention(thin) (@thick Factory.Type) -> @owned @callee_guaranteed () -> @owned Factory
+  _ = Factory.classNewInstance
+
+  // CHECK: function_ref @$S12dynamic_self7FactoryC17staticNewInstanceACXDyFZTc : $@convention(thin) (@thick Factory.Type) -> @owned @callee_guaranteed () -> @owned Factory
+  _ = t.staticNewInstance
+  // CHECK: function_ref @$S12dynamic_self7FactoryC17staticNewInstanceACXDyFZTc : $@convention(thin) (@thick Factory.Type) -> @owned @callee_guaranteed () -> @owned Factory
+  _ = type(of: c).staticNewInstance
+  // CHECK: function_ref @$S12dynamic_self7FactoryC17staticNewInstanceACXDyFZTc : $@convention(thin) (@thick Factory.Type) -> @owned @callee_guaranteed () -> @owned Factory
+  _ = Factory.staticNewInstance
+}
+
+class FactoryFactory {
+
+  // CHECK-LABEL: sil hidden @$S12dynamic_self07FactoryC0C11newInstanceACXDyFZ : $@convention(method) (@thick FactoryFactory.Type) -> @owned FactoryFactory
+  static func newInstance() -> Self {
+    // CHECK: bb0(%0 : @trivial $@thick FactoryFactory.Type):
+
+    // CHECK: [[DYNAMIC_SELF:%.*]] = unchecked_trivial_bit_cast %0 : $@thick FactoryFactory.Type to $@thick @dynamic_self FactoryFactory.Type
+    // CHECK: [[METATYPE:%.*]] = value_metatype $@thick @dynamic_self FactoryFactory.Type.Type, [[DYNAMIC_SELF]] : $@thick @dynamic_self FactoryFactory.Type
+    // CHECK: [[ANY:%.*]] = init_existential_metatype [[METATYPE]] : $@thick @dynamic_self FactoryFactory.Type.Type, $@thick Any.Type
+    let _: Any.Type = type(of: self)
+
+    while true {}
+  }
+}
+
+// Super call to a method returning Self
+class Base {
+  required init() {}
+
+  func returnsSelf() -> Self {
+    return self
+  }
+
+  static func returnsSelfStatic() -> Self {
+    return self.init()
+  }
+}
+
+class Derived : Base {
+  // CHECK-LABEL: sil hidden @$S12dynamic_self7DerivedC9superCallyyF : $@convention(method) (@guaranteed Derived) -> ()
+  // CHECK: [[SELF:%.*]] = copy_value %0
+  // CHECK: [[SUPER:%.*]] = upcast [[SELF]] : $Derived to $Base
+  // CHECK: [[BORROWED_SUPER:%.*]] = begin_borrow [[SUPER]]
+  // CHECK: [[METHOD:%.*]] = function_ref @$S12dynamic_self4BaseC11returnsSelfACXDyF
+  // CHECK: apply [[METHOD]]([[BORROWED_SUPER]])
+  // CHECK: return
+  func superCall() {
+    _ = super.returnsSelf()
+  }
+
+  // CHECK-LABEL: sil hidden @$S12dynamic_self7DerivedC15superCallStaticyyFZ : $@convention(method) (@thick Derived.Type) -> ()
+  // CHECK: [[SUPER:%.*]] = upcast %0 : $@thick Derived.Type to $@thick Base.Type
+  // CHECK: [[METHOD:%.*]] = function_ref @$S12dynamic_self4BaseC17returnsSelfStaticACXDyFZ
+  // CHECK: apply [[METHOD]]([[SUPER]])
+  // CHECK: return
+  static func superCallStatic() {
+    _ = super.returnsSelfStatic()
+  }
+
+  // CHECK-LABEL: sil hidden @$S12dynamic_self7DerivedC32superCallFromMethodReturningSelfACXDyF : $@convention(method) (@guaranteed Derived) -> @owned Derived
+  // CHECK: [[SELF:%.*]] = copy_value %0
+  // CHECK: [[SUPER:%.*]] = upcast [[SELF]] : $Derived to $Base
+  // CHEcK: [[BORROWED_SUPER:%.*]] = begin_borrow [[SUPER]]
+  // CHECK: [[METHOD:%.*]] = function_ref @$S12dynamic_self4BaseC11returnsSelfACXDyF
+  // CHECK: apply [[METHOD]]([[BORROWED_SUPER]])
+  // CHECK: return
+  func superCallFromMethodReturningSelf() -> Self {
+    _ = super.returnsSelf()
+    return self
+  }
+
+  // CHECK-LABEL: sil hidden @$S12dynamic_self7DerivedC38superCallFromMethodReturningSelfStaticACXDyFZ : $@convention(method) (@thick Derived.Type) -> @owned Derived
+  // CHECK; [[DYNAMIC_SELF:%.*]] = unchecked_trivial_bit_cast %0 : $@thick Derived.Type to $@thick @synamic_self Derived.Type
+  // CHECK: [[SUPER:%.*]] = upcast [[DYNAMIC_SELF]] : $@thick @dynamic_self Derived.Type to $@thick Base.Type
+  // CHECK: [[METHOD:%.*]] = function_ref @$S12dynamic_self4BaseC17returnsSelfStaticACXDyFZ
+  // CHECK: apply [[METHOD]]([[SUPER]])
+  // CHECK: return
+  static func superCallFromMethodReturningSelfStatic() -> Self {
+    _ = super.returnsSelfStatic()
+    return self.init()
+  }
+}
+
+class Generic<T> {
+  // Examples where we have to add a special argument to capture Self's metadata
+  func t1() -> Self {
+    // CHECK-LABEL: sil private @$S12dynamic_self7GenericC2t1ACyxGXDyFAEXDSgycfU_ : $@convention(thin) <T> (@guaranteed <τ_0_0> { var @sil_weak Optional<Generic<τ_0_0>> } <T>, @thick @dynamic_self Generic<T>.Type) -> @owned Optional<Generic<T>>
+    _ = {[weak self] in self }
+    return self
+  }
+
+  func t2() -> Self {
+    // CHECK-LABEL: sil private @$S12dynamic_self7GenericC2t2ACyxGXDyFAEXD_AEXDtycfU_ : $@convention(thin) <T> (@guaranteed (Generic<T>, Generic<T>), @thick @dynamic_self Generic<T>.Type) -> (@owned Generic<T>, @owned Generic<T>)
+    let selves = (self, self)
+    _ = { selves }
+    return self
+  }
+
+  func t3() -> Self {
+    // CHECK-LABEL: sil private @$S12dynamic_self7GenericC2t3ACyxGXDyFAEXDycfU_ : $@convention(thin) <T> (@guaranteed @sil_unowned Generic<T>, @thick @dynamic_self Generic<T>.Type) -> @owned Generic<T> 
+    _ = {[unowned self] in self }
+    return self
+  }
+}
+
+// CHECK-LABEL: sil_witness_table hidden X: P module dynamic_self {
+// CHECK: method #P.f!1: {{.*}} : @$S12dynamic_self1XCAA1PA2aDP1f{{[_0-9a-zA-Z]*}}FTW
+
+// CHECK-LABEL: sil_witness_table hidden X: CP module dynamic_self {
+// CHECK: method #CP.f!1: {{.*}} : @$S12dynamic_self1XCAA2CPA2aDP1f{{[_0-9a-zA-Z]*}}FTW
diff --git a/test/SILGen/plus_zero_enum.swift b/test/SILGen/plus_zero_enum.swift
new file mode 100644
index 0000000..53a818c
--- /dev/null
+++ b/test/SILGen/plus_zero_enum.swift
@@ -0,0 +1,215 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -parse-stdlib -parse-as-library -emit-silgen -enable-sil-ownership -module-name Swift %s | %FileCheck %s
+
+precedencegroup AssignmentPrecedence { assignment: true }
+
+enum Optional<Wrapped> {
+  case none
+  case some(Wrapped)
+}
+
+enum Boolish {
+  case falsy
+  case truthy
+}
+
+// CHECK-LABEL: sil hidden @$Ss13Boolish_casesyyF
+func Boolish_cases() {
+  // CHECK:       [[BOOLISH:%[0-9]+]] = metatype $@thin Boolish.Type
+  // CHECK-NEXT:  [[FALSY:%[0-9]+]] = enum $Boolish, #Boolish.falsy!enumelt
+  _ = Boolish.falsy
+
+  // CHECK-NEXT:  [[BOOLISH:%[0-9]+]] = metatype $@thin Boolish.Type
+  // CHECK-NEXT:  [[TRUTHY:%[0-9]+]] = enum $Boolish, #Boolish.truthy!enumelt
+  _ = Boolish.truthy
+}
+
+struct Int {}
+
+enum Optionable {
+  case nought
+  case mere(Int)
+}
+
+// CHECK-LABEL: sil hidden @$Ss16Optionable_casesyySiF
+func Optionable_cases(_ x: Int) {
+
+  // CHECK:       [[METATYPE:%.*]] = metatype $@thin Optionable.Type
+  // CHECK:       [[FN:%.*]] = function_ref @$Ss10OptionableO4mereyABSicABmF
+  // CHECK-NEXT:  [[CTOR:%.*]] = apply [[FN]]([[METATYPE]])
+  // CHECK-NEXT:  destroy_value [[CTOR]]
+  _ = Optionable.mere
+
+  // CHECK-NEXT:  [[METATYPE:%.*]] = metatype $@thin Optionable.Type
+  // CHECK-NEXT:  [[RES:%.*]] = enum $Optionable, #Optionable.mere!enumelt.1, %0 : $Int
+  _ = Optionable.mere(x)
+}
+
+// CHECK-LABEL: sil shared [transparent] [thunk] @$Ss10OptionableO4mereyABSicABmF
+// CHECK:        [[FN:%.*]] = function_ref @$Ss10OptionableO4mereyABSicABmF
+// CHECK-NEXT:   [[METHOD:%.*]] = partial_apply [callee_guaranteed] [[FN]](%0)
+// CHECK-NEXT:   return [[METHOD]]
+// CHECK-NEXT: }
+
+// CHECK-LABEL: sil shared [transparent] @$Ss10OptionableO4mereyABSicABmF
+// CHECK:        [[RES:%.*]] = enum $Optionable, #Optionable.mere!enumelt.1, %0 : $Int
+// CHECK-NEXT:   return [[RES]] : $Optionable
+// CHECK-NEXT: }
+
+protocol P {}
+struct S : P {}
+
+enum AddressOnly {
+  case nought
+  case mere(P)
+  case phantom(S)
+}
+
+// CHECK-LABEL: sil hidden @$Ss17AddressOnly_casesyys1SVF
+func AddressOnly_cases(_ s: S) {
+
+  // CHECK:       [[METATYPE:%.*]] = metatype $@thin AddressOnly.Type
+  // CHECK:       [[FN:%.*]] = function_ref @$Ss11AddressOnlyO4mereyABs1P_pcABmF
+  // CHECK-NEXT:  [[CTOR:%.*]] = apply [[FN]]([[METATYPE]])
+  // CHECK-NEXT:  destroy_value [[CTOR]]
+  _ = AddressOnly.mere
+
+  // CHECK-NEXT:  [[METATYPE:%.*]] = metatype $@thin AddressOnly.Type
+  // CHECK-NEXT:  [[NOUGHT:%.*]] = alloc_stack $AddressOnly
+  // CHECK-NEXT:  inject_enum_addr [[NOUGHT]]
+  // CHECK-NEXT:  destroy_addr [[NOUGHT]]
+  // CHECK-NEXT:  dealloc_stack [[NOUGHT]]
+  _ = AddressOnly.nought
+
+  // CHECK-NEXT:  [[METATYPE:%.*]] = metatype $@thin AddressOnly.Type
+  // CHECK-NEXT:  [[MERE:%.*]] = alloc_stack $AddressOnly
+  // CHECK-NEXT:  [[PAYLOAD:%.*]] = init_enum_data_addr [[MERE]]
+  // CHECK-NEXT:  [[PAYLOAD_ADDR:%.*]] = init_existential_addr [[PAYLOAD]]
+  // CHECK-NEXT:  store %0 to [trivial] [[PAYLOAD_ADDR]]
+  // CHECK-NEXT:  inject_enum_addr [[MERE]]
+  // CHECK-NEXT:  destroy_addr [[MERE]]
+  // CHECK-NEXT:  dealloc_stack [[MERE]]
+  _ = AddressOnly.mere(s)
+
+  // Address-only enum vs loadable payload
+
+  // CHECK-NEXT:  [[METATYPE:%.*]] = metatype $@thin AddressOnly.Type
+  // CHECK-NEXT:  [[PHANTOM:%.*]] = alloc_stack $AddressOnly
+  // CHECK-NEXT:  [[PAYLOAD:%.*]] = init_enum_data_addr [[PHANTOM]] : $*AddressOnly, #AddressOnly.phantom!enumelt.1
+  // CHECK-NEXT:  store %0 to [trivial] [[PAYLOAD]]
+  // CHECK-NEXT:  inject_enum_addr [[PHANTOM]] : $*AddressOnly, #AddressOnly.phantom!enumelt.1
+  // CHECK-NEXT:  destroy_addr [[PHANTOM]]
+  // CHECK-NEXT:  dealloc_stack [[PHANTOM]]
+
+  _ = AddressOnly.phantom(s)
+  // CHECK:       return
+}
+
+// CHECK-LABEL: sil shared [transparent] [thunk] @$Ss11AddressOnlyO4mereyABs1P_pcABmF
+// CHECK:       [[FN:%.*]] = function_ref @$Ss11AddressOnlyO4mereyABs1P_pcABmF
+// CHECK-NEXT:  [[METHOD:%.*]] = partial_apply [callee_guaranteed] [[FN]](%0)
+// CHECK-NEXT:  // function_ref
+// CHECK-NEXT:  [[CANONICAL_THUNK_FN:%.*]] = function_ref @$Ss1P_ps11AddressOnlyOIegir_sAA_pACIegnr_TR : $@convention(thin) (@in_guaranteed P, @guaranteed @callee_guaranteed (@in P) -> @out AddressOnly) -> @out AddressOnly
+// CHECK-NEXT:  [[CANONICAL_THUNK:%.*]] = partial_apply [callee_guaranteed] [[CANONICAL_THUNK_FN]]([[METHOD]])
+// CHECK-NEXT:  return [[CANONICAL_THUNK]] : $@callee_guaranteed (@in_guaranteed P) -> @out AddressOnly
+// CHECK-NEXT: }
+
+// CHECK-LABEL: sil shared [transparent] @$Ss11AddressOnlyO4mereyABs1P_pcABmF : $@convention
+// CHECK: bb0([[ARG0:%.*]] : @trivial $*AddressOnly, [[ARG1:%.*]] : @trivial $*P, [[ARG2:%.*]] : @trivial $@thin AddressOnly.Type):
+// CHECK:        [[RET_DATA:%.*]] = init_enum_data_addr [[ARG0]] : $*AddressOnly, #AddressOnly.mere!enumelt.1
+// CHECK-NEXT:   copy_addr [take] [[ARG1]] to [initialization] [[RET_DATA]] : $*P
+// CHECK-NEXT:   inject_enum_addr [[ARG0]] : $*AddressOnly, #AddressOnly.mere!enumelt.1
+// CHECK:        return
+// CHECK-NEXT: } // end sil function '$Ss11AddressOnlyO4mereyABs1P_pcABmF'
+
+enum PolyOptionable<T> {
+  case nought
+  case mere(T)
+}
+
+// CHECK-LABEL: sil hidden @$Ss20PolyOptionable_casesyyxlF
+func PolyOptionable_cases<T>(_ t: T) {
+
+// CHECK:         [[METATYPE:%.*]] = metatype $@thin PolyOptionable<T>.Type
+// CHECK-NEXT:    [[NOUGHT:%.*]] = alloc_stack $PolyOptionable<T>
+// CHECK-NEXT:    inject_enum_addr [[NOUGHT]]
+// CHECK-NEXT:    destroy_addr [[NOUGHT]]
+// CHECK-NEXT:    dealloc_stack [[NOUGHT]]
+  _ = PolyOptionable<T>.nought
+
+// CHECK-NEXT:    [[METATYPE:%.*]] = metatype $@thin PolyOptionable<T>.Type
+// CHECK-NEXT:    [[MERE:%.*]] = alloc_stack $PolyOptionable<T>
+// CHECK-NEXT:    [[PAYLOAD:%.*]] = init_enum_data_addr [[MERE]]
+// CHECK-NEXT:    copy_addr %0 to [initialization] [[PAYLOAD]]
+// CHECK-NEXT:    inject_enum_addr [[MERE]]
+// CHECK-NEXT:    destroy_addr [[MERE]]
+// CHECK-NEXT:    dealloc_stack [[MERE]]
+
+  _ = PolyOptionable<T>.mere(t)
+
+// CHECK-NOT:    destroy_addr %0
+// CHECK:         return
+
+}
+
+// The substituted type is loadable and trivial here
+
+// CHECK-LABEL: sil hidden @$Ss32PolyOptionable_specialized_casesyySiF
+func PolyOptionable_specialized_cases(_ t: Int) {
+
+// CHECK:         [[METATYPE:%.*]] = metatype $@thin PolyOptionable<Int>.Type
+// CHECK-NEXT:    [[NOUGHT:%.*]] = enum $PolyOptionable<Int>, #PolyOptionable.nought!enumelt
+  _ = PolyOptionable<Int>.nought
+
+// CHECK-NEXT:    [[METATYPE:%.*]] = metatype $@thin PolyOptionable<Int>.Type
+// CHECK-NEXT:    [[NOUGHT:%.*]] = enum $PolyOptionable<Int>, #PolyOptionable.mere!enumelt.1, %0
+  _ = PolyOptionable<Int>.mere(t)
+
+// CHECK:         return
+
+}
+
+
+// Regression test for a bug where temporary allocations created as a result of
+// tuple implosion were not deallocated in enum constructors.
+struct String { var ptr: Builtin.NativeObject }
+
+enum Foo { case A(P, String) }
+
+// Curry Thunk for Foo.A(_:)
+//
+// CHECK-LABEL: sil shared [transparent] [thunk] @$Ss3FooO1AyABs1P_p_SStcABmF
+// CHECK:         [[FN:%.*]] = function_ref @$Ss3FooO1AyABs1P_p_SStcABmF
+// CHECK-NEXT:    [[METHOD:%.*]] = partial_apply [callee_guaranteed] [[FN]](%0)
+// CHECK-NEXT:    // function_ref
+// CHECK-NEXT:    [[CANONICAL_THUNK_FN:%.*]] = function_ref @$Ss1P_pSSs3FooOIegixr_sAA_pSSACIegngr_TR : $@convention(thin) (@in_guaranteed P, @guaranteed String, @guaranteed @callee_guaranteed (@in P, @owned String) -> @out Foo) -> @out Foo
+// CHECK-NEXT:    [[CANONICAL_THUNK:%.*]] = partial_apply [callee_guaranteed] [[CANONICAL_THUNK_FN]]([[METHOD]])
+// CHECK-NEXT:    return [[CANONICAL_THUNK]]
+// CHECK-NEXT:  }
+
+// Foo.A(_:)
+// CHECK-LABEL: sil shared [transparent] @$Ss3FooO1AyABs1P_p_SStcABmF
+// CHECK: bb0([[ARG0:%.*]] : @trivial $*Foo, [[ARG1:%.*]] : @trivial $*P, [[ARG2:%.*]] : @owned $String, [[ARG3:%.*]] : @trivial $@thin Foo.Type):
+// CHECK:         [[PAYLOAD:%.*]] = init_enum_data_addr [[ARG0]] : $*Foo, #Foo.A!enumelt.1
+// CHECK-NEXT:    [[LEFT:%.*]] = tuple_element_addr [[PAYLOAD]] : $*(P, String), 0
+// CHECK-NEXT:    [[RIGHT:%.*]] = tuple_element_addr [[PAYLOAD]] : $*(P, String), 1
+// CHECK-NEXT:    copy_addr [take] [[ARG1]] to [initialization] [[LEFT]] : $*P
+// CHECK-NEXT:    store [[ARG2]] to [init] [[RIGHT]]
+// CHECK-NEXT:    inject_enum_addr [[ARG0]] : $*Foo, #Foo.A!enumelt.1
+// CHECK:         return
+// CHECK-NEXT:  } // end sil function '$Ss3FooO1AyABs1P_p_SStcABmF'
+
+func Foo_cases() {
+  _ = Foo.A
+}
+
+enum Indirect<T> {
+  indirect case payload((T, other: T))
+  case none
+}
+// CHECK-LABEL: sil{{.*}} @{{.*}}makeIndirectEnum{{.*}} : $@convention(thin) <T> (@in_guaranteed T) -> @owned Indirect<T>
+// CHECK: [[BOX:%.*]] = alloc_box $<τ_0_0> { var (τ_0_0, other: τ_0_0) } <T>
+// CHECK: enum $Indirect<T>, #Indirect.payload!enumelt.1, [[BOX]] : $<τ_0_0> { var (τ_0_0, other: τ_0_0) } <T>
+func makeIndirectEnum<T>(_ payload: T) -> Indirect<T> {
+  return Indirect.payload((payload, other: payload))
+}
diff --git a/test/SILGen/plus_zero_enum_resilience.swift b/test/SILGen/plus_zero_enum_resilience.swift
new file mode 100644
index 0000000..7b5ac8a
--- /dev/null
+++ b/test/SILGen/plus_zero_enum_resilience.swift
@@ -0,0 +1,83 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %empty-directory(%t)
+// RUN: %target-swift-frontend -emit-module -enable-resilience -emit-module-path=%t/resilient_struct.swiftmodule -module-name=resilient_struct %S/../Inputs/resilient_struct.swift
+// RUN: %target-swift-frontend -emit-module -enable-resilience -emit-module-path=%t/resilient_enum.swiftmodule -module-name=resilient_enum -I %t %S/../Inputs/resilient_enum.swift
+// RUN: %target-swift-frontend -I %t -enable-sil-ownership -emit-silgen -enable-resilience %s | %FileCheck %s
+
+import resilient_enum
+
+// Resilient enums are always address-only, and switches must include
+// a default case
+
+// CHECK-LABEL: sil hidden @$S15enum_resilience15resilientSwitchyy0c1_A06MediumOF : $@convention(thin) (@in_guaranteed Medium) -> ()
+// CHECK:         [[BOX:%.*]] = alloc_stack $Medium
+// CHECK-NEXT:    copy_addr %0 to [initialization] [[BOX]]
+// CHECK-NEXT:    switch_enum_addr [[BOX]] : $*Medium, case #Medium.Paper!enumelt: bb1, case #Medium.Canvas!enumelt: bb2, case #Medium.Pamphlet!enumelt.1: bb3, case #Medium.Postcard!enumelt.1: bb4, default bb5
+// CHECK:       bb1:
+// CHECK-NEXT:    dealloc_stack [[BOX]]
+// CHECK-NEXT:    br bb6
+// CHECK:       bb2:
+// CHECK-NEXT:    dealloc_stack [[BOX]]
+// CHECK-NEXT:    br bb6
+// CHECK:       bb3:
+// CHECK-NEXT:    [[INDIRECT_ADDR:%.*]] = unchecked_take_enum_data_addr [[BOX]]
+// CHECK-NEXT:    [[INDIRECT:%.*]] = load [take] [[INDIRECT_ADDR]]
+// CHECK-NEXT:    [[PAYLOAD:%.*]] = project_box [[INDIRECT]]
+// CHECK-NEXT:    destroy_value [[INDIRECT]]
+// CHECK-NEXT:    dealloc_stack [[BOX]]
+// CHECK-NEXT:    br bb6
+// CHECK:       bb4:
+// CHECK-NEXT:    [[PAYLOAD_ADDR:%.*]] = unchecked_take_enum_data_addr [[BOX]]
+// CHECK-NEXT:    destroy_addr [[PAYLOAD_ADDR]]
+// CHECK-NEXT:    dealloc_stack [[BOX]]
+// CHECK-NEXT:    br bb6
+// CHECK:       bb5:
+// CHECK-NEXT:    builtin "int_trap"()
+// CHECK-NEXT:    unreachable
+// CHECK:       bb6:
+// CHECK-NOT:    destroy_addr %0
+// CHECK-NEXT:    [[RESULT:%.*]] = tuple ()
+// CHECK-NEXT:    return [[RESULT]]
+
+func resilientSwitch(_ m: Medium) {
+  switch m {
+    case .Paper: ()
+    case .Canvas: ()
+    case .Pamphlet: ()
+    case .Postcard: ()
+  }
+}
+
+// Indirect enums are still address-only, because the discriminator is stored
+// as part of the value, so we cannot resiliently make assumptions about the
+// enum's size
+
+// CHECK-LABEL: sil hidden @$S15enum_resilience21indirectResilientEnumyy010resilient_A016IndirectApproachOF : $@convention(thin) (@in_guaranteed IndirectApproach) -> ()
+func indirectResilientEnum(_ ia: IndirectApproach) {}
+
+public enum MyResilientEnum {
+  case kevin
+  case loki
+}
+
+// CHECK-LABEL: sil @$S15enum_resilience15resilientSwitchyyAA15MyResilientEnumOF : $@convention(thin) (@in_guaranteed MyResilientEnum) -> ()
+// CHECK:      switch_enum_addr %2 : $*MyResilientEnum, case #MyResilientEnum.kevin!enumelt: bb1, case #MyResilientEnum.loki!enumelt: bb2 //
+// CHECK:      return
+public func resilientSwitch(_ e: MyResilientEnum) {
+  switch e {
+  case .kevin: ()
+  case .loki: ()
+  }
+}
+
+// Inlineable functions must lower the switch as if it came from outside the module
+
+// CHECK-LABEL: sil [serialized] @$S15enum_resilience16inlineableSwitchyyAA15MyResilientEnumOF : $@convention(thin) (@in_guaranteed MyResilientEnum) -> ()
+// CHECK:      switch_enum_addr %2 : $*MyResilientEnum, case #MyResilientEnum.kevin!enumelt: bb1, case #MyResilientEnum.loki!enumelt: bb2, default bb3
+// CHECK:      return
+@_inlineable public func inlineableSwitch(_ e: MyResilientEnum) {
+  switch e {
+  case .kevin: ()
+  case .loki: ()
+  }
+}
diff --git a/test/SILGen/plus_zero_erasure_reabstraction.swift b/test/SILGen/plus_zero_erasure_reabstraction.swift
new file mode 100644
index 0000000..1c2c0eb
--- /dev/null
+++ b/test/SILGen/plus_zero_erasure_reabstraction.swift
@@ -0,0 +1,20 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership %s | %FileCheck %s
+
+struct Foo {}
+class Bar {}
+
+// CHECK: [[CONCRETE:%.*]] = init_existential_addr [[EXISTENTIAL:%.*]] : $*Any, $Foo.Type
+// CHECK: [[METATYPE:%.*]] = metatype $@thick Foo.Type
+// CHECK: store [[METATYPE]] to [trivial] [[CONCRETE]] : $*@thick Foo.Type
+let x: Any = Foo.self
+
+
+// CHECK: [[CONCRETE:%.*]] = init_existential_addr [[EXISTENTIAL:%.*]] : $*Any, $() -> ()
+// CHECK: [[CLOSURE:%.*]] = function_ref
+// CHECK: [[CLOSURE_THICK:%.*]] = thin_to_thick_function [[CLOSURE]]
+// CHECK: [[REABSTRACTION_THUNK:%.*]] = function_ref @$SIeg_ytytIegnr_TR
+// CHECK: [[CLOSURE_REABSTRACTED:%.*]] = partial_apply [callee_guaranteed] [[REABSTRACTION_THUNK]]([[CLOSURE_THICK]])
+// CHECK: store [[CLOSURE_REABSTRACTED]] to [init] [[CONCRETE]]
+let y: Any = {() -> () in ()}
+
diff --git a/test/SILGen/plus_zero_existential_erasure.swift b/test/SILGen/plus_zero_existential_erasure.swift
new file mode 100644
index 0000000..a60024f
--- /dev/null
+++ b/test/SILGen/plus_zero_existential_erasure.swift
@@ -0,0 +1,129 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership %s | %FileCheck %s
+
+protocol P {
+  func downgrade(_ m68k: Bool) -> Self
+  func upgrade() throws -> Self
+}
+protocol Q {}
+
+struct X: P, Q {
+  func downgrade(_ m68k: Bool) -> X {
+    return self
+  }
+
+  func upgrade() throws -> X {
+    return self
+  }
+}
+
+func makePQ() -> P & Q { return X() }
+
+func useP(_ x: P) { }
+
+func throwingFunc() throws -> Bool { return true }
+
+// CHECK-LABEL: sil hidden @$S19existential_erasure5PQtoPyyF : $@convention(thin) () -> () {
+func PQtoP() {
+  // CHECK: [[PQ_PAYLOAD:%.*]] = open_existential_addr immutable_access [[PQ:%.*]] : $*P & Q to $*[[OPENED_TYPE:@opened(.*) P & Q]]
+  // CHECK: [[P_PAYLOAD:%.*]] = init_existential_addr [[P:%.*]] : $*P, $[[OPENED_TYPE]]
+  // CHECK: copy_addr [[PQ_PAYLOAD]] to [initialization] [[P_PAYLOAD]]
+  // CHECK: destroy_addr [[PQ]]
+  // CHECK-NOT: destroy_addr [[P]]
+  // CHECK-NOT: destroy_addr [[P_PAYLOAD]]
+  // CHECK-NOT: deinit_existential_addr [[PQ]]
+  // CHECK-NOT: destroy_addr [[PQ_PAYLOAD]]
+  useP(makePQ())
+}
+
+// Make sure uninitialized existentials are properly deallocated when we
+// have an early return.
+
+// CHECK-LABEL: sil hidden @$S19existential_erasure19openExistentialToP1yyAA1P_pKF
+func openExistentialToP1(_ p: P) throws {
+// CHECK: bb0(%0 : @trivial $*P):
+// CHECK:   [[OPEN:%.*]] = open_existential_addr immutable_access %0 : $*P to $*[[OPEN_TYPE:@opened\(.*\) P]]
+// CHECK:   [[RESULT:%.*]] = alloc_stack $P
+// CHECK:   [[RESULT_ADDR:%.*]] = init_existential_addr [[RESULT]] : $*P, $[[OPEN_TYPE]]
+// CHECK:   [[FUNC:%.*]] = function_ref @$S19existential_erasure12throwingFuncSbyKF
+// CHECK:   try_apply [[FUNC]]()
+//
+// CHECK: bb1([[SUCCESS:%.*]] : @trivial $Bool):
+// CHECK:   [[METHOD:%.*]] = witness_method $[[OPEN_TYPE]], #P.downgrade!1 : {{.*}}, [[OPEN]]
+// CHECK:   apply [[METHOD]]<[[OPEN_TYPE]]>([[RESULT_ADDR]], [[SUCCESS]], [[OPEN]])
+// CHECK:   dealloc_stack [[RESULT]]
+// CHECK:   return
+//
+// CHECK: bb2([[FAILURE:%.*]] : @owned $Error):
+// CHECK:   deinit_existential_addr [[RESULT]]
+// CHECK:   dealloc_stack [[RESULT]]
+// CHECK:   throw [[FAILURE]]
+//
+  try useP(p.downgrade(throwingFunc()))
+}
+
+// CHECK-LABEL: sil hidden @$S19existential_erasure19openExistentialToP2yyAA1P_pKF
+func openExistentialToP2(_ p: P) throws {
+// CHECK: bb0(%0 : @trivial $*P):
+// CHECK:   [[OPEN:%.*]] = open_existential_addr immutable_access %0 : $*P to $*[[OPEN_TYPE:@opened\(.*\) P]]
+// CHECK:   [[RESULT:%.*]] = alloc_stack $P
+// CHECK:   [[RESULT_ADDR:%.*]] = init_existential_addr [[RESULT]] : $*P, $[[OPEN_TYPE]]
+// CHECK:   [[METHOD:%.*]] = witness_method $[[OPEN_TYPE]], #P.upgrade!1 : {{.*}}, [[OPEN]]
+// CHECK:   try_apply [[METHOD]]<[[OPEN_TYPE]]>([[RESULT_ADDR]], [[OPEN]])
+//
+// CHECK: bb1
+// CHECK:  dealloc_stack [[RESULT]]
+// CHECK:  return
+//
+// CHECK: bb2([[FAILURE:%.*]]: @owned $Error):
+// CHECK:  deinit_existential_addr [[RESULT]]
+// CHECK:  dealloc_stack [[RESULT]]
+// CHECK:  throw [[FAILURE]]
+//
+  try useP(p.upgrade())
+}
+
+// Same as above but for boxed existentials
+
+extension Error {
+  func returnOrThrowSelf() throws -> Self {
+    throw self
+  }
+}
+
+// CHECK-LABEL: sil hidden @$S19existential_erasure12errorHandlerys5Error_psAC_pKF
+func errorHandler(_ e: Error) throws -> Error {
+// CHECK: bb0([[ARG:%.*]] : @guaranteed $Error):
+// CHECK:  debug_value [[ARG]] : $Error
+// CHECK:  [[OPEN:%.*]] = open_existential_box [[ARG]] : $Error to $*[[OPEN_TYPE:@opened\(.*\) Error]]
+// CHECK:  [[RESULT:%.*]] = alloc_existential_box $Error, $[[OPEN_TYPE]]
+// CHECK:  [[ADDR:%.*]] = project_existential_box $[[OPEN_TYPE]] in [[RESULT]] : $Error
+// CHECK:  [[FUNC:%.*]] = function_ref @$Ss5ErrorP19existential_erasureE17returnOrThrowSelf{{[_0-9a-zA-Z]*}}F
+// CHECK:  try_apply [[FUNC]]<[[OPEN_TYPE]]>([[ADDR]], [[OPEN]])
+//
+// CHECK: bb1
+// CHECK:  return [[RESULT]] : $Error
+//
+// CHECK: bb2([[FAILURE:%.*]] : @owned $Error):
+// CHECK:  dealloc_existential_box [[RESULT]]
+// CHECK:  throw [[FAILURE]] : $Error
+//
+  return try e.returnOrThrowSelf()
+}
+
+
+// rdar://problem/22003864 -- SIL verifier crash when init_existential_addr
+// references dynamic Self type
+class EraseDynamicSelf {
+  required init() {}
+
+// CHECK-LABEL: sil hidden @$S19existential_erasure16EraseDynamicSelfC7factoryACXDyFZ : $@convention(method) (@thick EraseDynamicSelf.Type) -> @owned EraseDynamicSelf
+// CHECK:  [[ANY:%.*]] = alloc_stack $Any
+// CHECK:  init_existential_addr [[ANY]] : $*Any, $@dynamic_self EraseDynamicSelf
+//
+  class func factory() -> Self {
+    let instance = self.init()
+    let _: Any = instance
+    return instance
+  }
+}
diff --git a/test/SILGen/plus_zero_expressions.swift b/test/SILGen/plus_zero_expressions.swift
new file mode 100644
index 0000000..293c8fe
--- /dev/null
+++ b/test/SILGen/plus_zero_expressions.swift
@@ -0,0 +1,737 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %empty-directory(%t)
+// RUN: echo "public var x = Int()" | %target-swift-frontend -module-name FooBar -emit-module -o %t -
+// RUN: %target-swift-frontend -parse-stdlib -emit-silgen -enable-sil-ownership %s -I%t -disable-access-control | %FileCheck %s
+
+import Swift
+import FooBar
+
+struct SillyString : _ExpressibleByBuiltinStringLiteral, ExpressibleByStringLiteral {
+  init(_builtinUnicodeScalarLiteral value: Builtin.Int32) {}
+
+  init(unicodeScalarLiteral value: SillyString) { }
+
+  init(
+    _builtinExtendedGraphemeClusterLiteral start: Builtin.RawPointer,
+    utf8CodeUnitCount: Builtin.Word,
+    isASCII: Builtin.Int1
+  ) { 
+  }
+
+  init(extendedGraphemeClusterLiteral value: SillyString) { }
+
+  init(
+    _builtinStringLiteral start: Builtin.RawPointer,
+    utf8CodeUnitCount: Builtin.Word,
+    isASCII: Builtin.Int1) { 
+  }
+
+  init(stringLiteral value: SillyString) { }
+}
+
+struct SillyUTF16String : _ExpressibleByBuiltinUTF16StringLiteral, ExpressibleByStringLiteral {
+  init(_builtinUnicodeScalarLiteral value: Builtin.Int32) { }
+
+  init(unicodeScalarLiteral value: SillyString) { }
+
+  init(
+    _builtinExtendedGraphemeClusterLiteral start: Builtin.RawPointer,
+    utf8CodeUnitCount: Builtin.Word,
+    isASCII: Builtin.Int1
+  ) { 
+  }
+
+  init(extendedGraphemeClusterLiteral value: SillyString) { }
+
+  init(
+    _builtinStringLiteral start: Builtin.RawPointer,
+    utf8CodeUnitCount: Builtin.Word,
+    isASCII: Builtin.Int1
+  ) { }
+
+  init(
+    _builtinUTF16StringLiteral start: Builtin.RawPointer,
+    utf16CodeUnitCount: Builtin.Word
+  ) { 
+  }
+
+  init(stringLiteral value: SillyUTF16String) { }
+}
+
+struct SillyConstUTF16String : _ExpressibleByBuiltinConstUTF16StringLiteral, ExpressibleByStringLiteral {
+  init(_builtinUnicodeScalarLiteral value: Builtin.Int32) { }
+
+  init(unicodeScalarLiteral value: SillyString) { }
+
+  init(
+    _builtinExtendedGraphemeClusterLiteral start: Builtin.RawPointer,
+    utf8CodeUnitCount: Builtin.Word,
+    isASCII: Builtin.Int1
+  ) {
+  }
+
+  init(extendedGraphemeClusterLiteral value: SillyString) { }
+
+  init( _builtinConstStringLiteral start: Builtin.RawPointer) { }
+
+  init( _builtinConstUTF16StringLiteral start: Builtin.RawPointer) { }
+
+  init(stringLiteral value: SillyUTF16String) { }
+}
+
+func literals() {
+  var a = 1
+  var b = 1.25
+  var d = "foö"
+  var e:SillyString = "foo"
+
+  var f:SillyConstUTF16String = "foobar"
+  var non_ascii:SillyConstUTF16String = "foobarö"
+}
+// CHECK-LABEL: sil hidden @$S11expressions8literalsyyF
+// CHECK: integer_literal $Builtin.Int2048, 1
+// CHECK: float_literal $Builtin.FPIEEE{{64|80}}, {{0x3FF4000000000000|0x3FFFA000000000000000}}
+// CHECK: string_literal utf16 "foö"
+// CHECK: string_literal utf8 "foo"
+// CHECK: [[CONST_STRING_LIT:%.*]] = const_string_literal utf8 "foobar"
+// CHECK: [[METATYPE:%.*]] = metatype $@thin SillyConstUTF16String.Type
+// CHECK: [[FUN:%.*]] = function_ref @$S11expressions21SillyConstUTF16StringV08_builtincE7LiteralACBp_tcfC : $@convention(method) (Builtin.RawPointer, @thin SillyConstUTF16String.Type) -> SillyConstUTF16String
+// CHECK: apply [[FUN]]([[CONST_STRING_LIT]], [[METATYPE]]) : $@convention(method) (Builtin.RawPointer, @thin SillyConstUTF16String.Type) -> SillyConstUTF16String
+// CHECK: [[CONST_UTF16STRING_LIT:%.*]] = const_string_literal utf16 "foobarö"
+// CHECK: [[FUN:%.*]] = function_ref @$S11expressions21SillyConstUTF16StringV08_builtincdE7LiteralACBp_tcfC : $@convention(method) (Builtin.RawPointer, @thin SillyConstUTF16String.Type) -> SillyConstUTF16String
+// CHECK: apply [[FUN]]([[CONST_UTF16STRING_LIT]], {{.*}}) : $@convention(method) (Builtin.RawPointer, @thin SillyConstUTF16String.Type) -> SillyConstUTF16String
+
+func bar(_ x: Int) {}
+func bar(_ x: Int, _ y: Int) {}
+
+func call_one() {
+  bar(42);
+}
+
+// CHECK-LABEL: sil hidden @$S11expressions8call_oneyyF
+// CHECK: [[FORTYTWO:%[0-9]+]] = integer_literal {{.*}} 42
+// CHECK: [[FORTYTWO_CONVERTED:%[0-9]+]] = apply {{.*}}([[FORTYTWO]], {{.*}})
+// CHECK: [[BAR:%[0-9]+]] = function_ref @$S11expressions3bar{{[_0-9a-zA-Z]*}}F : $@convention(thin) (Int) -> ()
+// CHECK: apply [[BAR]]([[FORTYTWO_CONVERTED]])
+
+func call_two() {
+  bar(42, 219)
+}
+
+// CHECK-LABEL: sil hidden @$S11expressions8call_twoyyF
+// CHECK: [[FORTYTWO:%[0-9]+]] = integer_literal {{.*}} 42
+// CHECK: [[FORTYTWO_CONVERTED:%[0-9]+]] = apply {{.*}}([[FORTYTWO]], {{.*}})
+// CHECK: [[TWONINETEEN:%[0-9]+]] = integer_literal {{.*}} 219
+// CHECK: [[TWONINETEEN_CONVERTED:%[0-9]+]] = apply {{.*}}([[TWONINETEEN]], {{.*}})
+// CHECK: [[BAR:%[0-9]+]] = function_ref @$S11expressions3bar{{[_0-9a-zA-Z]*}}F : $@convention(thin) (Int, Int) -> ()
+// CHECK: apply [[BAR]]([[FORTYTWO_CONVERTED]], [[TWONINETEEN_CONVERTED]])
+
+func tuples() {
+  bar((4, 5).1)
+
+  var T1 : (a: Int16, b: Int) = (b : 42, a : 777)
+}
+
+// CHECK-LABEL: sil hidden @$S11expressions6tuplesyyF
+
+
+class C {
+  var chi:Int
+  init() {
+    chi = 219
+  }
+  init(x:Int) {
+    chi = x
+  }
+}
+
+// CHECK-LABEL: sil hidden @$S11expressions7classesyyF
+func classes() {
+  // CHECK: function_ref @$S11expressions1CC{{[_0-9a-zA-Z]*}}fC : $@convention(method) (@thick C.Type) -> @owned C
+  var a = C()
+  // CHECK: function_ref @$S11expressions1CC{{[_0-9a-zA-Z]*}}fC : $@convention(method) (Int, @thick C.Type) -> @owned C
+  var b = C(x: 0)
+}
+
+struct S {
+  var x:Int
+  init() {
+    x = 219
+  }
+  init(x: Int) {
+    self.x = x
+  }
+}
+
+// CHECK-LABEL: sil hidden @$S11expressions7structsyyF
+func structs() {
+  // CHECK: function_ref @$S11expressions1SV{{[_0-9a-zA-Z]*}}fC : $@convention(method) (@thin S.Type) -> S
+  var a = S()
+  // CHECK: function_ref @$S11expressions1SV{{[_0-9a-zA-Z]*}}fC : $@convention(method) (Int, @thin S.Type) -> S
+  var b = S(x: 0)
+}
+
+
+func inoutcallee(_ x: inout Int) {}
+func address_of_expr() {
+  var x: Int = 4
+  inoutcallee(&x)
+}
+
+
+
+func identity<T>(_ x: T) -> T {}
+
+struct SomeStruct {
+ mutating
+  func a() {}
+}
+
+// CHECK-LABEL: sil hidden @$S11expressions5callsyyF
+// CHECK: [[METHOD:%[0-9]+]] = function_ref @$S11expressions10SomeStructV1a{{[_0-9a-zA-Z]*}}F : $@convention(method) (@inout SomeStruct) -> ()
+// CHECK: apply [[METHOD]]({{.*}})
+func calls() {
+  var a : SomeStruct
+  a.a()
+}
+
+// CHECK-LABEL: sil hidden @$S11expressions11module_path{{[_0-9a-zA-Z]*}}F
+func module_path() -> Int {
+  return FooBar.x
+  // CHECK: [[x_GET:%[0-9]+]] = function_ref @$S6FooBar1xSivau
+  // CHECK-NEXT: apply [[x_GET]]()
+}
+
+func default_args(_ x: Int, y: Int = 219, z: Int = 20721) {}
+
+// CHECK-LABEL: sil hidden @$S11expressions19call_default_args_1{{[_0-9a-zA-Z]*}}F
+func call_default_args_1(_ x: Int) {
+  default_args(x)
+  // CHECK: [[YFUNC:%[0-9]+]] = function_ref @$S11expressions12default_args{{[_0-9a-zA-Z]*}}A0_
+  // CHECK: [[Y:%[0-9]+]] = apply [[YFUNC]]()
+  // CHECK: [[ZFUNC:%[0-9]+]] = function_ref @$S11expressions12default_args{{[_0-9a-zA-Z]*}}A1_
+  // CHECK: [[Z:%[0-9]+]] = apply [[ZFUNC]]()
+  // CHECK: [[FUNC:%[0-9]+]] = function_ref @$S11expressions12default_args{{[_0-9a-zA-Z]*}}F
+  // CHECK: apply [[FUNC]]({{.*}}, [[Y]], [[Z]])
+}
+
+// CHECK-LABEL: sil hidden @$S11expressions19call_default_args_2{{[_0-9a-zA-Z]*}}F
+func call_default_args_2(_ x: Int, z: Int) {
+  default_args(x, z:z)
+  // CHECK: [[DEFFN:%[0-9]+]] = function_ref @$S11expressions12default_args{{[_0-9a-zA-Z]*}}A0_
+  // CHECK-NEXT: [[C219:%[0-9]+]] = apply [[DEFFN]]()
+  // CHECK: [[FUNC:%[0-9]+]] = function_ref @$S11expressions12default_args{{[_0-9a-zA-Z]*}}F
+  // CHECK-NEXT: apply [[FUNC]]({{.*}}, [[C219]], {{.*}})
+}
+
+struct Generic<T> {
+  var mono_member:Int
+  var typevar_member:T
+
+  // CHECK-LABEL: sil hidden @$S11expressions7GenericV13type_variable{{[_0-9a-zA-Z]*}}F
+  mutating
+  func type_variable() -> T.Type {
+    return T.self
+    // CHECK: [[METATYPE:%[0-9]+]] = metatype $@thick T.Type
+    // CHECK: return [[METATYPE]]
+  }
+
+  // CHECK-LABEL: sil hidden @$S11expressions7GenericV19copy_typevar_member{{[_0-9a-zA-Z]*}}F
+  mutating
+  func copy_typevar_member(_ x: Generic<T>) {
+    typevar_member = x.typevar_member
+  }
+
+  // CHECK-LABEL: sil hidden @$S11expressions7GenericV12class_method{{[_0-9a-zA-Z]*}}FZ
+  static func class_method() {}
+}
+
+// CHECK-LABEL: sil hidden @$S11expressions18generic_member_ref{{[_0-9a-zA-Z]*}}F
+func generic_member_ref<T>(_ x: Generic<T>) -> Int {
+  // CHECK: bb0([[XADDR:%[0-9]+]] : @trivial $*Generic<T>):
+  return x.mono_member
+  // CHECK: [[MEMBER_ADDR:%[0-9]+]] = struct_element_addr {{.*}}, #Generic.mono_member
+  // CHECK: load [trivial] [[MEMBER_ADDR]]
+}
+
+// CHECK-LABEL: sil hidden @$S11expressions24bound_generic_member_ref{{[_0-9a-zA-Z]*}}F
+func bound_generic_member_ref(_ x: Generic<UnicodeScalar>) -> Int {
+  var x = x
+  // CHECK: bb0([[XADDR:%[0-9]+]] : @trivial $Generic<Unicode.Scalar>):
+  return x.mono_member
+  // CHECK: [[MEMBER_ADDR:%[0-9]+]] = struct_element_addr {{.*}}, #Generic.mono_member
+  // CHECK: load [trivial] [[MEMBER_ADDR]]
+}
+
+// CHECK-LABEL: sil hidden @$S11expressions6coerce{{[_0-9a-zA-Z]*}}F
+func coerce(_ x: Int32) -> Int64 {
+  return 0
+}
+
+class B {
+}
+
+class D : B {
+}
+
+// CHECK-LABEL: sil hidden @$S11expressions8downcast{{[_0-9a-zA-Z]*}}F
+func downcast(_ x: B) -> D {
+  return x as! D
+  // CHECK: unconditional_checked_cast %{{[0-9]+}} : {{.*}} to $D
+}
+
+// CHECK-LABEL: sil hidden @$S11expressions6upcast{{[_0-9a-zA-Z]*}}F
+func upcast(_ x: D) -> B {
+  return x
+  // CHECK: upcast %{{[0-9]+}} : ${{.*}} to $B
+}
+
+// CHECK-LABEL: sil hidden @$S11expressions14generic_upcast{{[_0-9a-zA-Z]*}}F
+func generic_upcast<T : B>(_ x: T) -> B {
+  return x
+  // CHECK: upcast %{{.*}} to $B
+  // CHECK: return
+}
+
+// CHECK-LABEL: sil hidden @$S11expressions16generic_downcast{{[_0-9a-zA-Z]*}}F
+func generic_downcast<T : B>(_ x: T, y: B) -> T {
+  return y as! T
+  // CHECK: unconditional_checked_cast %{{[0-9]+}} : {{.*}} to $T
+  // CHECK: return
+}
+
+// TODO: generic_downcast
+
+// CHECK-LABEL: sil hidden @$S11expressions15metatype_upcast{{[_0-9a-zA-Z]*}}F
+func metatype_upcast() -> B.Type {
+  return D.self
+  // CHECK: metatype $@thick D
+  // CHECK-NEXT: upcast
+}
+
+// CHECK-LABEL: sil hidden @$S11expressions19interpolated_string{{[_0-9a-zA-Z]*}}F
+func interpolated_string(_ x: Int, y: String) -> String {
+  return "The \(x) Million Dollar \(y)"
+}
+
+protocol Runcible {
+  associatedtype U
+  var free:Int { get }
+  var associated:U { get }
+
+  func free_method() -> Int
+  mutating func associated_method() -> U.Type
+  static func static_method()
+}
+
+protocol Mincible {
+  var free:Int { get }
+  func free_method() -> Int
+  static func static_method()
+}
+
+protocol Bendable { }
+protocol Wibbleable { }
+
+// CHECK-LABEL: sil hidden @$S11expressions20archetype_member_ref{{[_0-9a-zA-Z]*}}F
+func archetype_member_ref<T : Runcible>(_ x: T) {
+  var x = x
+  x.free_method()
+  // CHECK:      [[READ:%.*]] = begin_access [read] [unknown] [[X:%.*]]
+  // CHECK-NEXT: [[TEMP:%.*]] = alloc_stack $T
+  // CHECK-NEXT: copy_addr [[READ]] to [initialization] [[TEMP]]
+  // CHECK-NEXT: end_access [[READ]]
+  // CHECK-NEXT: witness_method $T, #Runcible.free_method!1
+  // CHECK-NEXT: apply
+  // CHECK-NEXT: destroy_addr [[TEMP]]
+  var u = x.associated_method()
+  // CHECK:      [[WRITE:%.*]] = begin_access [modify] [unknown]
+  // CHECK-NEXT: witness_method $T, #Runcible.associated_method!1
+  // CHECK-NEXT: apply
+  T.static_method()
+  // CHECK:      metatype $@thick T.Type
+  // CHECK-NEXT: witness_method $T, #Runcible.static_method!1
+  // CHECK-NEXT: apply
+}
+
+// CHECK-LABEL: sil hidden @$S11expressions22existential_member_ref{{[_0-9a-zA-Z]*}}F
+func existential_member_ref(_ x: Mincible) {
+  x.free_method()
+  // CHECK: open_existential_addr
+  // CHECK-NEXT: witness_method
+  // CHECK-NEXT: apply
+}
+
+/*TODO archetype and existential properties and subscripts
+func archetype_property_ref<T : Runcible>(_ x: T) -> (Int, T.U) {
+  x.free = x.free_method()
+  x.associated = x.associated_method()
+  return (x.free, x.associated)
+}
+
+func existential_property_ref<T : Runcible>(_ x: T) -> Int {
+  x.free = x.free_method()
+  return x.free
+}
+
+also archetype/existential subscripts
+*/
+
+struct Spoon : Runcible, Mincible {
+  typealias U = Float
+  var free: Int { return 4 }
+  var associated: Float { return 12 }
+
+  func free_method() -> Int {}
+  func associated_method() -> Float.Type {}
+  static func static_method() {}
+}
+
+struct Hat<T> : Runcible {
+  typealias U = [T]
+  var free: Int { return 1 }
+  var associated: U { get {} }
+
+  func free_method() -> Int {}
+
+  // CHECK-LABEL: sil hidden @$S11expressions3HatV17associated_method{{[_0-9a-zA-Z]*}}F
+  mutating
+  func associated_method() -> U.Type {
+    return U.self
+    // CHECK: [[META:%[0-9]+]] = metatype $@thin Array<T>.Type
+    // CHECK: return [[META]]
+  }
+
+  static func static_method() {}
+}
+
+// CHECK-LABEL: sil hidden @$S11expressions7erasure{{[_0-9a-zA-Z]*}}F
+func erasure(_ x: Spoon) -> Mincible {
+  return x
+  // CHECK: init_existential_addr
+  // CHECK: return
+}
+
+// CHECK-LABEL: sil hidden @$S11expressions19declref_to_metatypeAA5SpoonVmyF
+func declref_to_metatype() -> Spoon.Type {
+  return Spoon.self
+  // CHECK: metatype $@thin Spoon.Type
+}
+
+// CHECK-LABEL: sil hidden @$S11expressions27declref_to_generic_metatype{{[_0-9a-zA-Z]*}}F
+func declref_to_generic_metatype() -> Generic<UnicodeScalar>.Type {
+  // FIXME parsing of T<U> in expression context
+  typealias GenericChar = Generic<UnicodeScalar>
+  return GenericChar.self
+  // CHECK: metatype $@thin Generic<Unicode.Scalar>.Type
+}
+
+func int(_ x: Int) {}
+func float(_ x: Float) {}
+
+func tuple() -> (Int, Float) { return (1, 1.0) }
+
+// CHECK-LABEL: sil hidden @$S11expressions13tuple_element{{[_0-9a-zA-Z]*}}F
+func tuple_element(_ x: (Int, Float)) {
+  var x = x
+  // CHECK: [[XADDR:%.*]] = alloc_box ${ var (Int, Float) }
+  // CHECK: [[PB:%.*]] = project_box [[XADDR]]
+
+  int(x.0)
+  // CHECK: [[READ:%.*]] = begin_access [read] [unknown] [[PB]]
+  // CHECK: tuple_element_addr [[READ]] : {{.*}}, 0
+  // CHECK: apply
+
+  float(x.1)
+  // CHECK: [[READ:%.*]] = begin_access [read] [unknown] [[PB]]
+  // CHECK: tuple_element_addr [[READ]] : {{.*}}, 1
+  // CHECK: apply
+
+  int(tuple().0)
+  // CHECK: [[ZERO:%.*]] = tuple_extract {{%.*}} : {{.*}}, 0
+  // CHECK: apply {{.*}}([[ZERO]])
+
+  float(tuple().1)
+  // CHECK: [[ONE:%.*]] = tuple_extract {{%.*}} : {{.*}}, 1
+  // CHECK: apply {{.*}}([[ONE]])
+}
+
+// CHECK-LABEL: sil hidden @$S11expressions10containers{{[_0-9a-zA-Z]*}}F
+func containers() -> ([Int], Dictionary<String, Int>) {
+  return ([1, 2, 3], ["Ankeny": 1, "Burnside": 2, "Couch": 3])
+}
+
+// CHECK-LABEL: sil hidden @$S11expressions7if_expr{{[_0-9a-zA-Z]*}}F
+func if_expr(_ a: Bool, b: Bool, x: Int, y: Int, z: Int) -> Int {
+  var a = a
+  var b = b
+  var x = x
+  var y = y
+  var z = z
+  // CHECK: bb0({{.*}}):
+  // CHECK: [[AB:%[0-9]+]] = alloc_box ${ var Bool }
+  // CHECK: [[PBA:%.*]] = project_box [[AB]]
+  // CHECK: [[BB:%[0-9]+]] = alloc_box ${ var Bool }
+  // CHECK: [[PBB:%.*]] = project_box [[BB]]
+  // CHECK: [[XB:%[0-9]+]] = alloc_box ${ var Int }
+  // CHECK: [[PBX:%.*]] = project_box [[XB]]
+  // CHECK: [[YB:%[0-9]+]] = alloc_box ${ var Int }
+  // CHECK: [[PBY:%.*]] = project_box [[YB]]
+  // CHECK: [[ZB:%[0-9]+]] = alloc_box ${ var Int }
+  // CHECK: [[PBZ:%.*]] = project_box [[ZB]]
+
+  return a
+    ? x
+    : b
+    ? y
+    : z
+  // CHECK:   [[READ:%.*]] = begin_access [read] [unknown] [[PBA]]
+  // CHECK:   [[A:%[0-9]+]] = load [trivial] [[READ]]
+  // CHECK:   [[ACOND:%[0-9]+]] = apply {{.*}}([[A]])
+  // CHECK:   cond_br [[ACOND]], [[IF_A:bb[0-9]+]], [[ELSE_A:bb[0-9]+]]
+  // CHECK: [[IF_A]]:
+  // CHECK:   [[READ:%.*]] = begin_access [read] [unknown] [[PBX]]
+  // CHECK:   [[XVAL:%[0-9]+]] = load [trivial] [[READ]]
+  // CHECK:   br [[CONT_A:bb[0-9]+]]([[XVAL]] : $Int)
+  // CHECK: [[ELSE_A]]:
+  // CHECK:   [[READ:%.*]] = begin_access [read] [unknown] [[PBB]]
+  // CHECK:   [[B:%[0-9]+]] = load [trivial] [[READ]]
+  // CHECK:   [[BCOND:%[0-9]+]] = apply {{.*}}([[B]])
+  // CHECK:   cond_br [[BCOND]], [[IF_B:bb[0-9]+]], [[ELSE_B:bb[0-9]+]]
+  // CHECK: [[IF_B]]:
+  // CHECK:   [[READ:%.*]] = begin_access [read] [unknown] [[PBY]]
+  // CHECK:   [[YVAL:%[0-9]+]] = load [trivial] [[READ]]
+  // CHECK:   br [[CONT_B:bb[0-9]+]]([[YVAL]] : $Int)
+  // CHECK: [[ELSE_B]]:
+  // CHECK:   [[READ:%.*]] = begin_access [read] [unknown] [[PBZ]]
+  // CHECK:   [[ZVAL:%[0-9]+]] = load [trivial] [[READ]]
+  // CHECK:   br [[CONT_B:bb[0-9]+]]([[ZVAL]] : $Int)
+  // CHECK: [[CONT_B]]([[B_RES:%[0-9]+]] : @trivial $Int):
+  // CHECK:   br [[CONT_A:bb[0-9]+]]([[B_RES]] : $Int)
+  // CHECK: [[CONT_A]]([[A_RES:%[0-9]+]] : @trivial $Int):
+  // CHECK:   return [[A_RES]]
+}
+
+
+// Test that magic identifiers expand properly.  We test #column here because
+// it isn't affected as this testcase slides up and down the file over time.
+func magic_identifier_expansion(_ a: Int = #column) {
+  // CHECK-LABEL: sil hidden @{{.*}}magic_identifier_expansion
+  
+  // This should expand to the column number of the first _.
+  var tmp = #column
+  // CHECK: integer_literal $Builtin.Int2048, 13
+
+  // This should expand to the column number of the (, not to the column number
+  // of #column in the default argument list of this function.
+  // rdar://14315674
+  magic_identifier_expansion()
+  // CHECK: integer_literal $Builtin.Int2048, 29
+}
+
+func print_string() {
+  // CHECK-LABEL: print_string
+  var str = "\u{08}\u{09}\thello\r\n\0wörld\u{1e}\u{7f}"
+  // CHECK: string_literal utf16 "\u{08}\t\thello\r\n\0wörld\u{1E}\u{7F}"
+}
+
+
+
+// Test that we can silgen superclass calls that go farther than the immediate
+// superclass.
+class Super1 {
+  func funge() {}
+}
+class Super2 : Super1 {}
+class Super3 : Super2 {
+  override func funge() {
+    super.funge()
+  }
+}
+
+// <rdar://problem/16880240> SILGen crash assigning to _
+func testDiscardLValue() {
+  var a = 42
+  _ = a
+}
+
+
+func dynamicTypePlusZero(_ a: Super1) -> Super1.Type {
+  return type(of: a)
+}
+// CHECK-LABEL: dynamicTypePlusZero
+// CHECK: bb0([[ARG:%.*]] : @guaranteed $Super1):
+// CHECK-NOT: copy_value
+// CHECK: value_metatype  $@thick Super1.Type, [[ARG]] : $Super1
+
+struct NonTrivialStruct {
+  var c : Super1
+  var x: NonTrivialStruct? {
+    get { return nil }
+    set {}
+  }
+}
+
+func dontEmitIgnoredLoadExpr(_ a: NonTrivialStruct) -> NonTrivialStruct.Type {
+  return type(of: a)
+}
+// CHECK-LABEL: dontEmitIgnoredLoadExpr
+// CHECK: bb0(%0 : @guaranteed $NonTrivialStruct):
+// CHECK-NEXT: debug_value
+// CHECK-NEXT: [[RESULT:%.*]] = metatype $@thin NonTrivialStruct.Type
+// CHECK-NEXT: return [[RESULT]] : $@thin NonTrivialStruct.Type
+
+// Test that we evaluate the force unwrap to get its side effects (a potential trap),
+// but don't actually need to perform the load of its value.
+func dontLoadIgnoredLValueForceUnwrap(_ a: inout NonTrivialStruct?) -> NonTrivialStruct.Type {
+  return type(of: a!)
+}
+// CHECK-LABEL: dontLoadIgnoredLValueForceUnwrap
+// CHECK: bb0(%0 : @trivial $*Optional<NonTrivialStruct>):
+// CHECK-NEXT: debug_value_addr %0
+// CHECK-NEXT: [[READ:%[0-9]+]] = begin_access [read] [unknown] %0
+// CHECK-NEXT: switch_enum_addr [[READ]] : $*Optional<NonTrivialStruct>, case #Optional.some!enumelt.1: bb2, case #Optional.none!enumelt: bb1
+// CHECK: bb1:
+// CHECK: unreachable
+// CHECK: bb2:
+// CHECK-NEXT: unchecked_take_enum_data_addr [[READ]] : $*Optional<NonTrivialStruct>, #Optional.some!enumelt.1
+// CHECK-NEXT: end_access [[READ]]
+// CHECK-NEXT: [[METATYPE:%[0-9]+]] = metatype $@thin NonTrivialStruct.Type
+// CHECK-NEXT: return [[METATYPE]]
+
+func dontLoadIgnoredLValueDoubleForceUnwrap(_ a: inout NonTrivialStruct??) -> NonTrivialStruct.Type {
+  return type(of: a!!)
+}
+// CHECK-LABEL: dontLoadIgnoredLValueDoubleForceUnwrap
+// CHECK: bb0(%0 : @trivial $*Optional<Optional<NonTrivialStruct>>):
+// CHECK-NEXT: debug_value_addr %0
+// CHECK-NEXT: [[READ:%[0-9]+]] = begin_access [read] [unknown] %0
+// CHECK-NEXT: switch_enum_addr [[READ]] : $*Optional<Optional<NonTrivialStruct>>, case #Optional.some!enumelt.1: bb2, case #Optional.none!enumelt: bb1
+// CHECK: bb1:
+// CHECK: unreachable
+// CHECK: bb2:
+// CHECK-NEXT: [[UNWRAPPED:%[0-9]+]] = unchecked_take_enum_data_addr [[READ]] : $*Optional<Optional<NonTrivialStruct>>, #Optional.some!enumelt.1
+// CHECK-NEXT: switch_enum_addr [[UNWRAPPED]] : $*Optional<NonTrivialStruct>, case #Optional.some!enumelt.1: bb4, case #Optional.none!enumelt: bb3
+// CHECK: bb3:
+// CHECK: unreachable
+// CHECK: bb4:
+// CHECK-NEXT: unchecked_take_enum_data_addr [[UNWRAPPED]] : $*Optional<NonTrivialStruct>, #Optional.some!enumelt.1
+// CHECK-NEXT: end_access [[READ]]
+// CHECK-NEXT: [[METATYPE:%[0-9]+]] = metatype $@thin NonTrivialStruct.Type
+// CHECK-NEXT: return [[METATYPE]]
+
+func loadIgnoredLValueForceUnwrap(_ a: inout NonTrivialStruct) -> NonTrivialStruct.Type {
+  return type(of: a.x!)
+}
+// CHECK-LABEL: loadIgnoredLValueForceUnwrap
+// CHECK: bb0(%0 : @trivial $*NonTrivialStruct):
+// CHECK-NEXT: debug_value_addr %0
+// CHECK-NEXT: [[READ:%[0-9]+]] = begin_access [read] [unknown] %0
+// CHECK-NEXT: [[BORROW:%[0-9]+]] = load_borrow [[READ]]
+// CHECK-NEXT: // function_ref NonTrivialStruct.x.getter
+// CHECK-NEXT: [[GETTER:%[0-9]+]] = function_ref @$S{{[_0-9a-zA-Z]*}}vg : $@convention(method) (@guaranteed NonTrivialStruct) -> @owned Optional<NonTrivialStruct>
+// CHECK-NEXT: [[X:%[0-9]+]] = apply [[GETTER]]([[BORROW]])
+// CHECK-NEXT: end_borrow [[BORROW]] from [[READ]]
+// CHECK-NEXT: end_access [[READ]]
+// CHECK-NEXT: switch_enum [[X]] : $Optional<NonTrivialStruct>, case #Optional.some!enumelt.1: bb2, case #Optional.none!enumelt: bb1
+// CHECK: bb1:
+// CHECK: unreachable
+// CHECK: bb2([[UNWRAPPED_X:%[0-9]+]] : @owned $NonTrivialStruct):
+// CHECK-NEXT: destroy_value [[UNWRAPPED_X]]
+// CHECK-NEXT: [[METATYPE:%[0-9]+]] = metatype $@thin NonTrivialStruct.Type
+// CHECK-NEXT: return [[METATYPE]]
+
+func loadIgnoredLValueThroughForceUnwrap(_ a: inout NonTrivialStruct?) -> NonTrivialStruct.Type {
+  return type(of: a!.x!)
+}
+// CHECK-LABEL: loadIgnoredLValueThroughForceUnwrap
+// CHECK: bb0(%0 : @trivial $*Optional<NonTrivialStruct>):
+// CHECK-NEXT: debug_value_addr %0
+// CHECK-NEXT: [[READ:%[0-9]+]] = begin_access [read] [unknown] %0
+// CHECK-NEXT: switch_enum_addr [[READ]] : $*Optional<NonTrivialStruct>, case #Optional.some!enumelt.1: bb2, case #Optional.none!enumelt: bb1
+// CHECK: bb1:
+// CHECK: unreachable
+// CHECK: bb2:
+// CHECK-NEXT: [[UNWRAPPED:%[0-9]+]] = unchecked_take_enum_data_addr [[READ]] : $*Optional<NonTrivialStruct>, #Optional.some!enumelt.1
+// CHECK-NEXT: [[BORROW:%[0-9]+]] = load_borrow [[UNWRAPPED]]
+// CHECK-NEXT: // function_ref NonTrivialStruct.x.getter
+// CHECK-NEXT: [[GETTER:%[0-9]+]] = function_ref @$S{{[_0-9a-zA-Z]*}}vg : $@convention(method) (@guaranteed NonTrivialStruct) -> @owned Optional<NonTrivialStruct>
+// CHECK-NEXT: [[X:%[0-9]+]] = apply [[GETTER]]([[BORROW]])
+// CHECK-NEXT: end_borrow [[BORROW]] from [[UNWRAPPED]]
+// CHECK-NEXT: end_access [[READ]]
+// CHECK-NEXT: switch_enum [[X]] : $Optional<NonTrivialStruct>, case #Optional.some!enumelt.1: bb4, case #Optional.none!enumelt: bb3
+// CHECK: bb3:
+// CHECK: unreachable
+// CHECK: bb4([[UNWRAPPED_X:%[0-9]+]] : @owned $NonTrivialStruct):
+// CHECK-NEXT: destroy_value [[UNWRAPPED_X]]
+// CHECK-NEXT: [[METATYPE:%[0-9]+]] = metatype $@thin NonTrivialStruct.Type
+// CHECK-NEXT: return [[METATYPE]]
+
+func evaluateIgnoredKeyPathExpr(_ s: inout NonTrivialStruct, _ kp: WritableKeyPath<NonTrivialStruct, Int>) -> Int.Type {
+  return type(of: s[keyPath: kp])
+}
+// CHECK-LABEL: evaluateIgnoredKeyPathExpr
+// CHECK: bb0(%0 : @trivial $*NonTrivialStruct, %1 : @guaranteed $WritableKeyPath<NonTrivialStruct, Int>):
+// CHECK-NEXT: debug_value_addr %0
+// CHECK-NEXT: debug_value %1
+// CHECK-NEXT: [[S_READ:%[0-9]+]] = begin_access [read] [unknown] %0
+// CHECK-NEXT: [[S_TEMP:%[0-9]+]] = alloc_stack $NonTrivialStruct
+// CHECK-NEXT: copy_addr [[S_READ]] to [initialization] [[S_TEMP]]
+// CHECK-NEXT: [[KP_TEMP:%[0-9]+]] = copy_value %1
+// CHECK-NEXT: [[KP:%[0-9]+]] = upcast [[KP_TEMP]]
+// CHECK-NEXT: [[RESULT:%[0-9]+]] = alloc_stack $Int
+// CHECK-NEXT: // function_ref
+// CHECK-NEXT: [[PROJECT_FN:%[0-9]+]] = function_ref @$Ss23_projectKeyPathReadOnly{{[_0-9a-zA-Z]*}}F
+// CHECK-NEXT: [[KP_BORROW:%.*]] = begin_borrow [[KP]]
+// CHECK-NEXT: apply [[PROJECT_FN]]<NonTrivialStruct, Int>([[RESULT]], [[S_TEMP]], [[KP_BORROW]])
+// CHECK-NEXT: end_access [[S_READ]]
+// CHECK-NEXT: end_borrow [[KP_BORROW]]
+// CHECK-NEXT: dealloc_stack [[RESULT]]
+// CHECK-NEXT: destroy_value [[KP]]
+// CHECK-NEXT: destroy_addr [[S_TEMP]]
+// CHECK-NEXT: dealloc_stack [[S_TEMP]]
+// CHECK-NEXT: [[METATYPE:%[0-9]+]] = metatype $@thin Int.Type
+// CHECK-NOT: destroy_value %1
+// CHECK-NEXT: return [[METATYPE]]
+
+
+
+// <rdar://problem/18851497> Swiftc fails to compile nested destructuring tuple binding
+// CHECK-LABEL: sil hidden @$S11expressions21implodeRecursiveTupleyySi_Sit_SitSgF
+// CHECK: bb0(%0 : @trivial $Optional<((Int, Int), Int)>):
+func implodeRecursiveTuple(_ expr: ((Int, Int), Int)?) {
+
+  // CHECK: bb2([[WHOLE:%.*]] : @trivial $((Int, Int), Int)):
+  // CHECK-NEXT: [[X:%[0-9]+]] = tuple_extract [[WHOLE]] : $((Int, Int), Int), 0
+  // CHECK-NEXT: [[X0:%[0-9]+]] = tuple_extract [[X]] : $(Int, Int), 0
+  // CHECK-NEXT: [[X1:%[0-9]+]] = tuple_extract [[X]] : $(Int, Int), 1
+  // CHECK-NEXT: [[Y:%[0-9]+]] = tuple_extract [[WHOLE]] : $((Int, Int), Int), 1
+  // CHECK-NEXT: [[X:%[0-9]+]] = tuple ([[X0]] : $Int, [[X1]] : $Int)
+  // CHECK-NEXT: debug_value [[X]] : $(Int, Int), let, name "x"
+  // CHECK-NEXT: debug_value [[Y]] : $Int, let, name "y"
+
+  let (x, y) = expr!
+}
+
+func test20087517() {
+  class Color {
+    static func greenColor() -> Color { return Color() }
+  }
+  let x: (Color?, Int) = (.greenColor(), 1)
+}
+
+func test20596042() {
+  enum E {
+    case thing1
+    case thing2
+  }
+
+  func f() -> (E?, Int)? {
+    return (.thing1, 1)
+  }
+}
+
+func test21886435() {
+  () = ()
+}
+
diff --git a/test/SILGen/plus_zero_extensions_objc.swift b/test/SILGen/plus_zero_extensions_objc.swift
new file mode 100644
index 0000000..24a9cb7
--- /dev/null
+++ b/test/SILGen/plus_zero_extensions_objc.swift
@@ -0,0 +1,36 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -sdk %S/Inputs %s -I %S/Inputs -enable-source-import -emit-silgen -enable-sil-ownership | %FileCheck %s
+//
+// REQUIRES: objc_interop
+
+import Foundation
+
+class Foo {}
+
+extension Foo {
+  dynamic func kay() {}
+  dynamic var cox: Int { return 0 }
+}
+
+// CHECK-LABEL: sil hidden @$S15extensions_objc19extensionReferencesyyAA3FooCF
+// CHECK: bb0([[ARG:%.*]] : @guaranteed $Foo):
+func extensionReferences(_ x: Foo) {
+  // dynamic extension methods are still dynamically dispatched.
+  // CHECK: objc_method [[ARG]] : $Foo, #Foo.kay!1.foreign
+  x.kay()
+
+  // CHECK: objc_method [[ARG]] : $Foo, #Foo.cox!getter.1.foreign
+  _ = x.cox
+
+}
+
+func extensionMethodCurrying(_ x: Foo) {
+  _ = x.kay
+}
+
+// CHECK-LABEL: sil shared [thunk] @$S15extensions_objc3FooC3kayyyFTc
+// CHECK:         function_ref @$S15extensions_objc3FooC3kayyyFTD
+// CHECK-LABEL: sil shared [transparent] [serializable] [thunk] @$S15extensions_objc3FooC3kayyyFTD
+// CHECK:         bb0([[SELF:%.*]] : @guaranteed $Foo):
+// CHECK:           [[SELF_COPY:%.*]] = copy_value [[SELF]]
+// CHECK:           objc_method [[SELF_COPY]] : $Foo, #Foo.kay!1.foreign
diff --git a/test/SILGen/plus_zero_external_definitions.swift b/test/SILGen/plus_zero_external_definitions.swift
new file mode 100644
index 0000000..eed168f
--- /dev/null
+++ b/test/SILGen/plus_zero_external_definitions.swift
@@ -0,0 +1,46 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -sdk %S/Inputs %s -emit-silgen -enable-sil-ownership | %FileCheck %s
+
+// REQUIRES: objc_interop
+
+import ansible
+
+var a = NSAnse(Ansible(bellsOn: NSObject()))
+
+var anse = NSAnse
+
+hasNoPrototype()
+
+// CHECK-LABEL: sil @main
+// -- Foreign function is referenced with C calling conv and ownership semantics
+// CHECK:   [[NSOBJECT_CTOR:%.*]] = function_ref @$SSo8NSObjectC{{[_0-9a-zA-Z]*}}fC : $@convention(method) (@thick NSObject.Type) -> @owned NSObject
+// CHECK:   [[ANSIBLE_CTOR:%.*]] = function_ref @$SSo7AnsibleC{{[_0-9a-zA-Z]*}}fC
+// CHECK:   [[ANSIBLE:%.*]] = apply [[ANSIBLE_CTOR]]
+// CHECK:   [[NSANSE:%.*]] = function_ref @NSAnse : $@convention(c) (Optional<Ansible>) -> @autoreleased Optional<Ansible>
+// CHECK:   [[NSANSE_RESULT:%.*]] = apply [[NSANSE]]([[ANSIBLE]])
+// CHECK:   destroy_value [[ANSIBLE]] : $Optional<Ansible>
+// -- Referencing unapplied C function goes through a thunk
+// CHECK:   [[NSANSE:%.*]] = function_ref @$SSo6NSAnseySo7AnsibleCSgADFTO : $@convention(thin) (@guaranteed Optional<Ansible>) -> @owned Optional<Ansible>
+// -- Referencing unprototyped C function passes no parameters
+// CHECK:   [[NOPROTO:%.*]] = function_ref @hasNoPrototype : $@convention(c) () -> ()
+// CHECK:   apply [[NOPROTO]]()
+
+// -- Constructors for imported NSObject
+// CHECK-LABEL: sil shared [serializable] @$SSo8NSObjectC{{[_0-9a-zA-Z]*}}fC : $@convention(method) (@thick NSObject.Type) -> @owned NSObject
+
+// -- Constructors for imported Ansible
+// CHECK-LABEL: sil shared [serializable] @$SSo7AnsibleC{{[_0-9a-zA-Z]*}}fC : $@convention(method) (@in Optional<Any>, @thick Ansible.Type) -> @owned Optional<Ansible>
+
+// -- Native Swift thunk for NSAnse
+// CHECK: sil shared [serialized] [thunk] @$SSo6NSAnseySo7AnsibleCSgADFTO : $@convention(thin) (@guaranteed Optional<Ansible>) -> @owned Optional<Ansible> {
+// CHECK: bb0([[ARG0:%.*]] : @guaranteed $Optional<Ansible>):
+// CHECK:   [[ARG0_COPY:%.*]] = copy_value [[ARG0]]
+// CHECK:   [[FUNC:%.*]] = function_ref @NSAnse : $@convention(c) (Optional<Ansible>) -> @autoreleased Optional<Ansible>
+// CHECK:   [[RESULT:%.*]] = apply [[FUNC]]([[ARG0_COPY]]) : $@convention(c) (Optional<Ansible>) -> @autoreleased Optional<Ansible>
+// CHECK:   destroy_value [[ARG0_COPY]] : $Optional<Ansible>
+// CHECK:   return [[RESULT]] : $Optional<Ansible>
+// CHECK: }
+
+// -- Constructor for imported Ansible was unused, should not be emitted.
+// CHECK-NOT: sil {{.*}} @$SSo7AnsibleC{{[_0-9a-zA-Z]*}}fC : $@convention(method) (@thick Ansible.Type) -> @owned Ansible
+
diff --git a/test/SILGen/plus_zero_final.swift b/test/SILGen/plus_zero_final.swift
new file mode 100644
index 0000000..3e9133b
--- /dev/null
+++ b/test/SILGen/plus_zero_final.swift
@@ -0,0 +1,45 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership %s | %FileCheck %s
+
+class TestClass {
+
+  final
+  var finalProperty : Int { return 42 }
+
+  final
+  func finalMethod() -> Int { return 12 }
+
+
+  func baseMethod() {}
+}
+
+class TestDerived : TestClass {
+  final
+  override func baseMethod() {}
+}
+
+
+// CHECK-LABEL: sil hidden @{{.*}}testDirectDispatch{{.*}} : $@convention(thin) (@guaranteed TestClass) -> Int {
+// CHECK: bb0([[ARG:%.*]] : @guaranteed $TestClass):
+// CHECK: [[FINALMETH:%[0-9]+]] = function_ref @$S5final9TestClassC0A6Method{{[_0-9a-zA-Z]*}}F
+// CHECK: apply [[FINALMETH]]([[ARG]])
+// CHECK: [[FINALPROP:%[0-9]+]] = function_ref @$S5final9TestClassC0A8PropertySivg
+// CHECK: apply [[FINALPROP]]([[ARG]])
+func testDirectDispatch(c : TestClass) -> Int {
+  return c.finalMethod()+c.finalProperty
+}
+
+
+// Verify that the non-overriding final methods don't get emitted to the vtable.
+// CHECK-LABEL: sil_vtable TestClass {
+// CHECK-NEXT:  #TestClass.baseMethod!1: {{.*}} : @$S5final9TestClassC10baseMethod{{[_0-9a-zA-Z]*}}F
+// CHECK-NEXT:  #TestClass.init!initializer.1: {{.*}} : @$S5final9TestClassC{{[_0-9a-zA-Z]*}}fc
+// CHECK-NEXT:  #TestClass.deinit!
+// CHECK-NEXT: }
+
+// Verify that overriding final methods don't get emitted to the vtable.
+// CHECK-LABEL: sil_vtable TestDerived {
+// CHECK-NEXT:  #TestClass.baseMethod!1: {{.*}} : @$S5final11TestDerivedC10baseMethod{{[_0-9a-zA-Z]*}}F
+// CHECK-NEXT:  #TestClass.init!initializer.1: {{.*}} : @$S5final11TestDerivedC{{[_0-9a-zA-Z]*}}fc
+// CHECK-NEXT:  #TestDerived.deinit!
+// CHECK-NEXT: }
diff --git a/test/SILGen/plus_zero_force_cast_chained_optional.swift b/test/SILGen/plus_zero_force_cast_chained_optional.swift
new file mode 100644
index 0000000..d903e82
--- /dev/null
+++ b/test/SILGen/plus_zero_force_cast_chained_optional.swift
@@ -0,0 +1,37 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership %s | %FileCheck %s
+
+class Foo {
+  var bar: Bar!
+}
+
+class Bar {
+  var bas: C!
+}
+
+class C {}
+class D: C {}
+
+// CHECK-LABEL: sil hidden @$S27force_cast_chained_optional4testyAA1DCAA3FooCF
+// CHECK: bb0([[ARG:%.*]] : @guaranteed $Foo):
+// CHECK:   class_method [[ARG]] : $Foo, #Foo.bar!getter.1 : (Foo) -> () -> Bar?, $@convention(method) (@guaranteed Foo) ->
+// CHECK:   select_enum_addr
+// CHECK:   cond_br {{%.*}}, [[SOME_BAR:bb[0-9]+]], [[NO_BAR:bb[0-9]+]]
+//
+// CHECK: [[NO_BAR]]:
+// CHECK:   br [[TRAP:bb[0-9]+]]
+//
+// CHECK: [[SOME_BAR]]:
+// CHECK:   [[PAYLOAD_ADDR:%.*]] = unchecked_take_enum_data_addr {{%.*}} : $*Optional<Bar>
+// CHECK:   [[BAR:%.*]] = load [copy] [[PAYLOAD_ADDR]]
+// CHECK:   [[BORROWED_BAR:%.*]] = begin_borrow [[BAR]]
+// CHECK:   [[METHOD:%.*]] = class_method [[BORROWED_BAR]] : $Bar, #Bar.bas!getter.1 : (Bar) -> () -> C?, $@convention(method) (@guaranteed Bar) ->
+// CHECK:   apply [[METHOD]]([[BORROWED_BAR]])
+// CHECK:   end_borrow [[BORROWED_BAR]] from [[BAR]]
+// CHECK:   unconditional_checked_cast {{%.*}} : $C to $D
+//
+// CHECK: [[TRAP]]:
+// CHECK:   unreachable
+func test(_ x: Foo) -> D {
+  return x.bar?.bas as! D
+}
diff --git a/test/SILGen/plus_zero_foreach.swift b/test/SILGen/plus_zero_foreach.swift
new file mode 100644
index 0000000..7a3589b
--- /dev/null
+++ b/test/SILGen/plus_zero_foreach.swift
@@ -0,0 +1,642 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership %s | %FileCheck %s
+
+//////////////////
+// Declarations //
+//////////////////
+
+class C {}
+
+@_silgen_name("loopBodyEnd")
+func loopBodyEnd() -> ()
+
+@_silgen_name("condition")
+func condition() -> Bool
+
+@_silgen_name("loopContinueEnd")
+func loopContinueEnd() -> ()
+
+@_silgen_name("loopBreakEnd")
+func loopBreakEnd() -> ()
+
+@_silgen_name("funcEnd")
+func funcEnd() -> ()
+
+struct TrivialStruct {
+  var value: Int32
+}
+
+struct NonTrivialStruct {
+  var value: C
+}
+
+struct GenericStruct<T> {
+  var value: T
+  var value2: C
+}
+
+protocol P {}
+protocol ClassP : class {}
+
+protocol GenericCollection : Collection {
+
+}
+
+///////////
+// Tests //
+///////////
+
+//===----------------------------------------------------------------------===//
+// Trivial Struct
+//===----------------------------------------------------------------------===//
+
+// CHECK-LABEL: sil hidden @$S7foreach13trivialStructyySaySiGF : $@convention(thin) (@guaranteed Array<Int>) -> () {
+// CHECK: bb0([[ARRAY:%.*]] : @guaranteed $Array<Int>):
+// CHECK:   [[ITERATOR_BOX:%.*]] = alloc_box ${ var IndexingIterator<Array<Int>> }, var, name "$x$generator"
+// CHECK:   [[PROJECT_ITERATOR_BOX:%.*]] = project_box [[ITERATOR_BOX]]
+// CHECK:   br [[LOOP_DEST:bb[0-9]+]]
+//
+// CHECK: [[LOOP_DEST]]:
+// CHECK:   switch_enum [[IND_VAR:%.*]] : $Optional<Int>, case #Optional.some!enumelt.1: [[SOME_BB:bb[0-9]+]], case #Optional.none!enumelt: [[NONE_BB:bb[0-9]+]]
+//
+// CHECK: [[NONE_BB]]:
+// CHECK:   br [[CONT_BLOCK:bb[0-9]+]]
+//
+// CHECK: [[SOME_BB]]([[VAR:%.*]] : @trivial $Int):
+// CHECK:   [[LOOP_END_FUNC:%.*]] = function_ref @loopBodyEnd : $@convention(thin) () -> ()
+// CHECK:   apply [[LOOP_END_FUNC]]()
+// CHECK:   br [[LOOP_DEST]]
+//
+// CHECK: [[CONT_BLOCK]]:
+// CHECK:   destroy_value [[ITERATOR_BOX]]
+// CHECK:   [[FUNC_END_FUNC:%.*]] = function_ref @funcEnd : $@convention(thin) () -> ()
+// CHECK:   apply [[FUNC_END_FUNC]]()
+// CHECK: } // end sil function '$S7foreach13trivialStructyySaySiGF'
+func trivialStruct(_ xx: [Int]) {
+  for x in xx {
+    loopBodyEnd()
+  }
+  funcEnd()
+}
+
+// TODO: Write this test
+func trivialStructContinue(_ xx: [Int]) {
+  for x in xx {
+    if (condition()) {
+      loopContinueEnd()
+      continue
+    }
+    loopBodyEnd()
+  }
+
+  funcEnd()
+}
+
+// TODO: Write this test
+func trivialStructBreak(_ xx: [Int]) {
+  for x in xx {
+    if (condition()) {
+      loopBreakEnd()
+      break
+    }
+    loopBodyEnd()
+  }
+
+  funcEnd()
+}
+
+// CHECK-LABEL: sil hidden @$S7foreach26trivialStructContinueBreakyySaySiGF : $@convention(thin) (@guaranteed Array<Int>) -> () {
+// CHECK: bb0([[ARRAY:%.*]] : @guaranteed $Array<Int>):
+// CHECK:   [[ITERATOR_BOX:%.*]] = alloc_box ${ var IndexingIterator<Array<Int>> }, var, name "$x$generator"
+// CHECK:   [[PROJECT_ITERATOR_BOX:%.*]] = project_box [[ITERATOR_BOX]]
+// CHECK:   [[BORROWED_ARRAY_STACK:%.*]] = alloc_stack $Array<Int>
+// CHECK:   store_borrow [[ARRAY]] to [[BORROWED_ARRAY_STACK]]
+// CHECK:   [[MAKE_ITERATOR_FUNC:%.*]] = function_ref @$Ss10CollectionPss16IndexingIteratorVyxG0C0RtzrlE04makeC0AEyF : $@convention(method) <τ_0_0 where τ_0_0 : Collection, τ_0_0.Iterator == IndexingIterator<τ_0_0>> (@in_guaranteed τ_0_0) -> @out IndexingIterator<τ_0_0>
+// CHECK:   apply [[MAKE_ITERATOR_FUNC]]<[Int]>([[PROJECT_ITERATOR_BOX]], [[BORROWED_ARRAY_STACK]])
+// CHECK:   br [[LOOP_DEST:bb[0-9]+]]
+//
+// CHECK: [[LOOP_DEST]]:
+// CHECK:   [[GET_ELT_STACK:%.*]] = alloc_stack $Optional<Int>
+// CHECK:   [[WRITE:%.*]] = begin_access [modify] [unknown] [[PROJECT_ITERATOR_BOX]] : $*IndexingIterator<Array<Int>>
+// CHECK:   [[FUNC_REF:%.*]] = function_ref @$Ss16IndexingIteratorV4next7ElementQzSgyF : $@convention(method)
+// CHECK:   apply [[FUNC_REF]]<[Int]>([[GET_ELT_STACK]], [[WRITE]])
+// CHECK:   [[IND_VAR:%.*]] = load [trivial] [[GET_ELT_STACK]]
+// CHECK:   switch_enum [[IND_VAR]] : $Optional<Int>, case #Optional.some!enumelt.1: [[SOME_BB:bb[0-9]+]], case #Optional.none!enumelt: [[NONE_BB:bb[0-9]+]]
+//
+// CHECK: [[NONE_BB]]:
+// CHECK:   br [[CONT_BLOCK_JUMP:bb[0-9]+]]
+//
+// CHECK: [[SOME_BB]]([[VAR:%.*]] : @trivial $Int):
+// CHECK:   cond_br {{%.*}}, [[LOOP_BREAK_END_BLOCK:bb[0-9]+]], [[CONTINUE_CHECK_BLOCK:bb[0-9]+]]
+//
+// CHECK: [[LOOP_BREAK_END_BLOCK]]:
+// CHECK:   [[LOOP_BREAK_FUNC:%.*]] = function_ref @loopBreakEnd : $@convention(thin) () -> ()
+// CHECK:   apply [[LOOP_BREAK_FUNC]]()
+// CHECK:   br [[CONT_BLOCK:bb[0-9]+]]
+//
+// CHECK: [[CONTINUE_CHECK_BLOCK]]:
+// CHECK:   cond_br {{%.*}}, [[LOOP_CONTINUE_END:bb[0-9]+]], [[LOOP_END_BLOCK:bb[0-9]+]]
+//
+// CHECK: [[LOOP_CONTINUE_END]]:
+// CHECK:   [[LOOP_CONTINUE_FUNC:%.*]] = function_ref @loopContinueEnd : $@convention(thin) () -> ()
+// CHECK:   apply [[LOOP_CONTINUE_FUNC]]() : $@convention(thin) () -> ()
+// CHECK:   br [[LOOP_DEST]]
+//
+// CHECK: [[LOOP_END_BLOCK]]:
+// CHECK:   [[LOOP_BODY_FUNC:%.*]] = function_ref @loopBodyEnd : $@convention(thin) () -> ()
+// CHECK:   apply [[LOOP_BODY_FUNC]]()
+// CHECK:   br [[LOOP_DEST]]
+//
+// CHECK: [[CONT_BLOCK_JUMP]]:
+// CHECK:   br [[CONT_BLOCK]]
+//
+// CHECK: [[CONT_BLOCK]]
+// CHECK:   destroy_value [[ITERATOR_BOX]] : ${ var IndexingIterator<Array<Int>> }
+// CHECK:   [[FUNC_END_FUNC:%.*]] = function_ref @funcEnd : $@convention(thin) () -> ()
+// CHECK:   apply [[FUNC_END_FUNC]]()
+// CHECK: } // end sil function '$S7foreach26trivialStructContinueBreakyySaySiGF'
+func trivialStructContinueBreak(_ xx: [Int]) {
+  for x in xx {
+    if (condition()) {
+      loopBreakEnd()
+      break
+    }
+
+    if (condition()) {
+      loopContinueEnd()
+      continue
+    }
+    loopBodyEnd()
+  }
+
+  funcEnd()
+}
+
+
+//===----------------------------------------------------------------------===//
+// Existential
+//===----------------------------------------------------------------------===//
+
+func existential(_ xx: [P]) {
+  for x in xx {
+    loopBodyEnd()
+  }
+  funcEnd()
+}
+
+func existentialContinue(_ xx: [P]) {
+  for x in xx {
+    if (condition()) {
+      loopContinueEnd()
+      continue
+    }
+    loopBodyEnd()
+  }
+
+  funcEnd()
+}
+
+func existentialBreak(_ xx: [P]) {
+  for x in xx {
+    if (condition()) {
+      loopBreakEnd()
+      break
+    }
+    loopBodyEnd()
+  }
+
+  funcEnd()
+}
+
+// CHECK-LABEL: sil hidden @$S7foreach24existentialContinueBreakyySayAA1P_pGF : $@convention(thin) (@guaranteed Array<P>) -> () {
+// CHECK: bb0([[ARRAY:%.*]] : @guaranteed $Array<P>):
+// CHECK:   [[ITERATOR_BOX:%.*]] = alloc_box ${ var IndexingIterator<Array<P>> }, var, name "$x$generator"
+// CHECK:   [[PROJECT_ITERATOR_BOX:%.*]] = project_box [[ITERATOR_BOX]]
+// CHECK:   [[BORROWED_ARRAY_STACK:%.*]] = alloc_stack $Array<P>
+// CHECK:   store_borrow [[ARRAY]] to [[BORROWED_ARRAY_STACK]]
+// CHECK:   [[MAKE_ITERATOR_FUNC:%.*]] = function_ref @$Ss10CollectionPss16IndexingIteratorVyxG0C0RtzrlE04makeC0AEyF : $@convention(method) <τ_0_0 where τ_0_0 : Collection, τ_0_0.Iterator == IndexingIterator<τ_0_0>> (@in_guaranteed τ_0_0) -> @out IndexingIterator<τ_0_0>
+// CHECK:   apply [[MAKE_ITERATOR_FUNC]]<[P]>([[PROJECT_ITERATOR_BOX]], [[BORROWED_ARRAY_STACK]])
+// CHECK:   [[ELT_STACK:%.*]] = alloc_stack $Optional<P>
+// CHECK:   br [[LOOP_DEST:bb[0-9]+]]
+//
+// CHECK: [[LOOP_DEST]]:
+// CHECK:   [[WRITE:%.*]] = begin_access [modify] [unknown] [[PROJECT_ITERATOR_BOX]] : $*IndexingIterator<Array<P>>
+// CHECK:   [[FUNC_REF:%.*]] = function_ref @$Ss16IndexingIteratorV4next7ElementQzSgyF : $@convention(method)
+// CHECK:   apply [[FUNC_REF]]<[P]>([[ELT_STACK]], [[WRITE]])
+// CHECK:   switch_enum_addr [[ELT_STACK]] : $*Optional<P>, case #Optional.some!enumelt.1: [[SOME_BB:bb[0-9]+]], case #Optional.none!enumelt: [[NONE_BB:bb[0-9]+]]
+//
+// CHECK: [[NONE_BB]]:
+// CHECK:   br [[CONT_BLOCK_JUMP:bb[0-9]+]]
+//
+// CHECK: [[SOME_BB]]:
+// CHECK:   [[T0:%.*]] = alloc_stack $P, let, name "x"
+// CHECK:   [[ELT_STACK_TAKE:%.*]] = unchecked_take_enum_data_addr [[ELT_STACK]] : $*Optional<P>, #Optional.some!enumelt.1
+// CHECK:   copy_addr [take] [[ELT_STACK_TAKE]] to [initialization] [[T0]]
+// CHECK:   cond_br {{%.*}}, [[LOOP_BREAK_END_BLOCK:bb[0-9]+]], [[CONTINUE_CHECK_BLOCK:bb[0-9]+]]
+//
+// CHECK: [[LOOP_BREAK_END_BLOCK]]:
+// CHECK:   [[LOOP_BREAK_FUNC:%.*]] = function_ref @loopBreakEnd : $@convention(thin) () -> ()
+// CHECK:   apply [[LOOP_BREAK_FUNC]]()
+// CHECK:   destroy_addr [[T0]]
+// CHECK:   dealloc_stack [[T0]]
+// CHECK:   br [[CONT_BLOCK:bb[0-9]+]]
+//
+// CHECK: [[CONTINUE_CHECK_BLOCK]]:
+// CHECK:   cond_br {{%.*}}, [[LOOP_CONTINUE_END:bb[0-9]+]], [[LOOP_END_BLOCK:bb[0-9]+]]
+//
+// CHECK: [[LOOP_CONTINUE_END]]:
+// CHECK:   [[LOOP_CONTINUE_FUNC:%.*]] = function_ref @loopContinueEnd : $@convention(thin) () -> ()
+// CHECK:   apply [[LOOP_CONTINUE_FUNC]]() : $@convention(thin) () -> ()
+// CHECK:   destroy_addr [[T0]]
+// CHECK:   dealloc_stack [[T0]]
+// CHECK:   br [[LOOP_DEST]]
+//
+// CHECK: [[LOOP_END_BLOCK]]:
+// CHECK:   [[LOOP_BODY_FUNC:%.*]] = function_ref @loopBodyEnd : $@convention(thin) () -> ()
+// CHECK:   apply [[LOOP_BODY_FUNC]]()
+// CHECK:   destroy_addr [[T0]]
+// CHECK:   dealloc_stack [[T0]]
+// CHECK:   br [[LOOP_DEST]]
+//
+// CHECK: [[CONT_BLOCK_JUMP]]:
+// CHECK:   br [[CONT_BLOCK]]
+//
+// CHECK: [[CONT_BLOCK]]
+// CHECK:   dealloc_stack [[ELT_STACK]]
+// CHECK:   destroy_value [[ITERATOR_BOX]] : ${ var IndexingIterator<Array<P>> }
+// CHECK:   [[FUNC_END_FUNC:%.*]] = function_ref @funcEnd : $@convention(thin) () -> ()
+// CHECK:   apply [[FUNC_END_FUNC]]()
+// CHECK: } // end sil function '$S7foreach24existentialContinueBreakyySayAA1P_pGF'
+func existentialContinueBreak(_ xx: [P]) {
+  for x in xx {
+    if (condition()) {
+      loopBreakEnd()
+      break
+    }
+
+    if (condition()) {
+      loopContinueEnd()
+      continue
+    }
+    loopBodyEnd()
+  }
+
+  funcEnd()
+}
+
+//===----------------------------------------------------------------------===//
+// Class Constrainted Existential
+//===----------------------------------------------------------------------===//
+
+func existentialClass(_ xx: [ClassP]) {
+  for x in xx {
+    loopBodyEnd()
+  }
+  funcEnd()
+}
+
+func existentialClassContinue(_ xx: [ClassP]) {
+  for x in xx {
+    if (condition()) {
+      loopContinueEnd()
+      continue
+    }
+    loopBodyEnd()
+  }
+
+  funcEnd()
+}
+
+func existentialClassBreak(_ xx: [ClassP]) {
+  for x in xx {
+    if (condition()) {
+      loopBreakEnd()
+      break
+    }
+    loopBodyEnd()
+  }
+
+  funcEnd()
+}
+
+func existentialClassContinueBreak(_ xx: [ClassP]) {
+  for x in xx {
+    if (condition()) {
+      loopBreakEnd()
+      break
+    }
+
+    if (condition()) {
+      loopContinueEnd()
+      continue
+    }
+    loopBodyEnd()
+  }
+
+  funcEnd()
+}
+
+//===----------------------------------------------------------------------===//
+// Generic Struct
+//===----------------------------------------------------------------------===//
+
+func genericStruct<T>(_ xx: [GenericStruct<T>]) {
+  for x in xx {
+    loopBodyEnd()
+  }
+  funcEnd()
+}
+
+func genericStructContinue<T>(_ xx: [GenericStruct<T>]) {
+  for x in xx {
+    if (condition()) {
+      loopContinueEnd()
+      continue
+    }
+    loopBodyEnd()
+  }
+
+  funcEnd()
+}
+
+func genericStructBreak<T>(_ xx: [GenericStruct<T>]) {
+  for x in xx {
+    if (condition()) {
+      loopBreakEnd()
+      break
+    }
+    loopBodyEnd()
+  }
+
+  funcEnd()
+}
+
+// CHECK-LABEL: sil hidden @$S7foreach26genericStructContinueBreakyySayAA07GenericC0VyxGGlF : $@convention(thin) <T> (@guaranteed Array<GenericStruct<T>>) -> () {
+// CHECK: bb0([[ARRAY:%.*]] : @guaranteed $Array<GenericStruct<T>>):
+// CHECK:   [[ITERATOR_BOX:%.*]] = alloc_box $<τ_0_0> { var IndexingIterator<Array<GenericStruct<τ_0_0>>> } <T>, var, name "$x$generator"
+// CHECK:   [[PROJECT_ITERATOR_BOX:%.*]] = project_box [[ITERATOR_BOX]]
+// CHECK:   [[BORROWED_ARRAY_STACK:%.*]] = alloc_stack $Array<GenericStruct<T>>
+// CHECK:   store_borrow [[ARRAY]] to [[BORROWED_ARRAY_STACK]]
+// CHECK:   [[MAKE_ITERATOR_FUNC:%.*]] = function_ref @$Ss10CollectionPss16IndexingIteratorVyxG0C0RtzrlE04makeC0AEyF : $@convention(method) <τ_0_0 where τ_0_0 : Collection, τ_0_0.Iterator == IndexingIterator<τ_0_0>> (@in_guaranteed τ_0_0) -> @out IndexingIterator<τ_0_0>
+// CHECK:   apply [[MAKE_ITERATOR_FUNC]]<[GenericStruct<T>]>([[PROJECT_ITERATOR_BOX]], [[BORROWED_ARRAY_STACK]])
+// CHECK:   [[ELT_STACK:%.*]] = alloc_stack $Optional<GenericStruct<T>>
+// CHECK:   br [[LOOP_DEST:bb[0-9]+]]
+//
+// CHECK: [[LOOP_DEST]]:
+// CHECK:   [[WRITE:%.*]] = begin_access [modify] [unknown] [[PROJECT_ITERATOR_BOX]] : $*IndexingIterator<Array<GenericStruct<T>>>
+// CHECK:   [[FUNC_REF:%.*]] = function_ref @$Ss16IndexingIteratorV4next7ElementQzSgyF : $@convention(method)
+// CHECK:   apply [[FUNC_REF]]<[GenericStruct<T>]>([[ELT_STACK]], [[WRITE]])
+// CHECK:   switch_enum_addr [[ELT_STACK]] : $*Optional<GenericStruct<T>>, case #Optional.some!enumelt.1: [[SOME_BB:bb[0-9]+]], case #Optional.none!enumelt: [[NONE_BB:bb[0-9]+]]
+//
+// CHECK: [[NONE_BB]]:
+// CHECK:   br [[CONT_BLOCK_JUMP:bb[0-9]+]]
+//
+// CHECK: [[SOME_BB]]:
+// CHECK:   [[T0:%.*]] = alloc_stack $GenericStruct<T>, let, name "x"
+// CHECK:   [[ELT_STACK_TAKE:%.*]] = unchecked_take_enum_data_addr [[ELT_STACK]] : $*Optional<GenericStruct<T>>, #Optional.some!enumelt.1
+// CHECK:   copy_addr [take] [[ELT_STACK_TAKE]] to [initialization] [[T0]]
+// CHECK:   cond_br {{%.*}}, [[LOOP_BREAK_END_BLOCK:bb[0-9]+]], [[CONTINUE_CHECK_BLOCK:bb[0-9]+]]
+//
+// CHECK: [[LOOP_BREAK_END_BLOCK]]:
+// CHECK:   [[LOOP_BREAK_FUNC:%.*]] = function_ref @loopBreakEnd : $@convention(thin) () -> ()
+// CHECK:   apply [[LOOP_BREAK_FUNC]]()
+// CHECK:   destroy_addr [[T0]]
+// CHECK:   dealloc_stack [[T0]]
+// CHECK:   br [[CONT_BLOCK:bb[0-9]+]]
+//
+// CHECK: [[CONTINUE_CHECK_BLOCK]]:
+// CHECK:   cond_br {{%.*}}, [[LOOP_CONTINUE_END:bb[0-9]+]], [[LOOP_END_BLOCK:bb[0-9]+]]
+//
+// CHECK: [[LOOP_CONTINUE_END]]:
+// CHECK:   [[LOOP_CONTINUE_FUNC:%.*]] = function_ref @loopContinueEnd : $@convention(thin) () -> ()
+// CHECK:   apply [[LOOP_CONTINUE_FUNC]]() : $@convention(thin) () -> ()
+// CHECK:   destroy_addr [[T0]]
+// CHECK:   dealloc_stack [[T0]]
+// CHECK:   br [[LOOP_DEST]]
+//
+// CHECK: [[LOOP_END_BLOCK]]:
+// CHECK:   [[LOOP_BODY_FUNC:%.*]] = function_ref @loopBodyEnd : $@convention(thin) () -> ()
+// CHECK:   apply [[LOOP_BODY_FUNC]]()
+// CHECK:   destroy_addr [[T0]]
+// CHECK:   dealloc_stack [[T0]]
+// CHECK:   br [[LOOP_DEST]]
+//
+// CHECK: [[CONT_BLOCK_JUMP]]:
+// CHECK:   br [[CONT_BLOCK]]
+//
+// CHECK: [[CONT_BLOCK]]
+// CHECK:   dealloc_stack [[ELT_STACK]]
+// CHECK:   destroy_value [[ITERATOR_BOX]]
+// CHECK:   [[FUNC_END_FUNC:%.*]] = function_ref @funcEnd : $@convention(thin) () -> ()
+// CHECK:   apply [[FUNC_END_FUNC]]()
+// CHECK: } // end sil function '$S7foreach26genericStructContinueBreakyySayAA07GenericC0VyxGGlF'
+func genericStructContinueBreak<T>(_ xx: [GenericStruct<T>]) {
+  for x in xx {
+    if (condition()) {
+      loopBreakEnd()
+      break
+    }
+
+    if (condition()) {
+      loopContinueEnd()
+      continue
+    }
+    loopBodyEnd()
+  }
+
+  funcEnd()
+}
+
+//===----------------------------------------------------------------------===//
+// Fully Generic Collection
+//===----------------------------------------------------------------------===//
+
+func genericCollection<T : Collection>(_ xx: T) {
+  for x in xx {
+    loopBodyEnd()
+  }
+  funcEnd()
+}
+
+func genericCollectionContinue<T : Collection>(_ xx: T) {
+  for x in xx {
+    if (condition()) {
+      loopContinueEnd()
+      continue
+    }
+    loopBodyEnd()
+  }
+
+  funcEnd()
+}
+
+func genericCollectionBreak<T : Collection>(_ xx: T) {
+  for x in xx {
+    if (condition()) {
+      loopBreakEnd()
+      break
+    }
+    loopBodyEnd()
+  }
+
+  funcEnd()
+}
+
+// CHECK-LABEL: sil hidden @$S7foreach30genericCollectionContinueBreakyyxs0C0RzlF : $@convention(thin) <T where T : Collection> (@in_guaranteed T) -> () {
+// CHECK: bb0([[COLLECTION:%.*]] : @trivial $*T):
+// CHECK:   [[ITERATOR_BOX:%.*]] = alloc_box $<τ_0_0 where τ_0_0 : Collection> { var τ_0_0.Iterator } <T>, var, name "$x$generator"
+// CHECK:   [[PROJECT_ITERATOR_BOX:%.*]] = project_box [[ITERATOR_BOX]]
+// CHECK:   [[MAKE_ITERATOR_FUNC:%.*]] = witness_method $T, #Sequence.makeIterator!1 : <Self where Self : Sequence> (Self) -> () -> Self.Iterator : $@convention(witness_method: Sequence) <τ_0_0 where τ_0_0 : Sequence> (@in_guaranteed τ_0_0) -> @out τ_0_0.Iterator
+// CHECK:   apply [[MAKE_ITERATOR_FUNC]]<T>([[PROJECT_ITERATOR_BOX]], [[COLLECTION]])
+// CHECK:   [[ELT_STACK:%.*]] = alloc_stack $Optional<T.Element>
+// CHECK:   br [[LOOP_DEST:bb[0-9]+]]
+//
+// CHECK: [[LOOP_DEST]]:
+// CHECK:   [[WRITE:%.*]] = begin_access [modify] [unknown] [[PROJECT_ITERATOR_BOX]] : $*T.Iterator
+// CHECK:   [[GET_NEXT_FUNC:%.*]] = witness_method $T.Iterator, #IteratorProtocol.next!1 : <Self where Self : IteratorProtocol> (inout Self) -> () -> Self.Element? : $@convention(witness_method: IteratorProtocol) <τ_0_0 where τ_0_0 : IteratorProtocol> (@inout τ_0_0) -> @out Optional<τ_0_0.Element>
+// CHECK:   apply [[GET_NEXT_FUNC]]<T.Iterator>([[ELT_STACK]], [[WRITE]])
+// CHECK:   switch_enum_addr [[ELT_STACK]] : $*Optional<T.Element>, case #Optional.some!enumelt.1: [[SOME_BB:bb[0-9]+]], case #Optional.none!enumelt: [[NONE_BB:bb[0-9]+]]
+//
+// CHECK: [[NONE_BB]]:
+// CHECK:   br [[CONT_BLOCK_JUMP:bb[0-9]+]]
+//
+// CHECK: [[SOME_BB]]:
+// CHECK:   [[T0:%.*]] = alloc_stack $T.Element, let, name "x"
+// CHECK:   [[ELT_STACK_TAKE:%.*]] = unchecked_take_enum_data_addr [[ELT_STACK]] : $*Optional<T.Element>, #Optional.some!enumelt.1
+// CHECK:   copy_addr [take] [[ELT_STACK_TAKE]] to [initialization] [[T0]]
+// CHECK:   cond_br {{%.*}}, [[LOOP_BREAK_END_BLOCK:bb[0-9]+]], [[CONTINUE_CHECK_BLOCK:bb[0-9]+]]
+//
+// CHECK: [[LOOP_BREAK_END_BLOCK]]:
+// CHECK:   [[LOOP_BREAK_FUNC:%.*]] = function_ref @loopBreakEnd : $@convention(thin) () -> ()
+// CHECK:   apply [[LOOP_BREAK_FUNC]]()
+// CHECK:   destroy_addr [[T0]]
+// CHECK:   dealloc_stack [[T0]]
+// CHECK:   br [[CONT_BLOCK:bb[0-9]+]]
+//
+// CHECK: [[CONTINUE_CHECK_BLOCK]]:
+// CHECK:   cond_br {{%.*}}, [[LOOP_CONTINUE_END:bb[0-9]+]], [[LOOP_END_BLOCK:bb[0-9]+]]
+//
+// CHECK: [[LOOP_CONTINUE_END]]:
+// CHECK:   [[LOOP_CONTINUE_FUNC:%.*]] = function_ref @loopContinueEnd : $@convention(thin) () -> ()
+// CHECK:   apply [[LOOP_CONTINUE_FUNC]]() : $@convention(thin) () -> ()
+// CHECK:   destroy_addr [[T0]]
+// CHECK:   dealloc_stack [[T0]]
+// CHECK:   br [[LOOP_DEST]]
+//
+// CHECK: [[LOOP_END_BLOCK]]:
+// CHECK:   [[LOOP_BODY_FUNC:%.*]] = function_ref @loopBodyEnd : $@convention(thin) () -> ()
+// CHECK:   apply [[LOOP_BODY_FUNC]]()
+// CHECK:   destroy_addr [[T0]]
+// CHECK:   dealloc_stack [[T0]]
+// CHECK:   br [[LOOP_DEST]]
+//
+// CHECK: [[CONT_BLOCK_JUMP]]:
+// CHECK:   br [[CONT_BLOCK]]
+//
+// CHECK: [[CONT_BLOCK]]
+// CHECK:   dealloc_stack [[ELT_STACK]]
+// CHECK:   destroy_value [[ITERATOR_BOX]]
+// CHECK:   [[FUNC_END_FUNC:%.*]] = function_ref @funcEnd : $@convention(thin) () -> ()
+// CHECK:   apply [[FUNC_END_FUNC]]()
+// CHECK: } // end sil function '$S7foreach30genericCollectionContinueBreakyyxs0C0RzlF'
+func genericCollectionContinueBreak<T : Collection>(_ xx: T) {
+  for x in xx {
+    if (condition()) {
+      loopBreakEnd()
+      break
+    }
+
+    if (condition()) {
+      loopContinueEnd()
+      continue
+    }
+    loopBodyEnd()
+  }
+
+  funcEnd()
+}
+
+//===----------------------------------------------------------------------===//
+// Pattern Match Tests
+//===----------------------------------------------------------------------===//
+
+// CHECK-LABEL: sil hidden @$S7foreach13tupleElementsyySayAA1CC_ADtGF
+func tupleElements(_ xx: [(C, C)]) {
+  // CHECK: bb3([[PAYLOAD:%.*]] : @owned $(C, C)):
+  // CHECK: [[BORROWED_PAYLOAD:%.*]] = begin_borrow [[PAYLOAD]]
+  // CHECK: [[A:%.*]] = tuple_extract [[BORROWED_PAYLOAD]] : $(C, C), 0
+  // CHECK: [[COPY_A:%.*]] = copy_value [[A]]
+  // CHECK: [[B:%.*]] = tuple_extract [[BORROWED_PAYLOAD]] : $(C, C), 1
+  // CHECK: [[COPY_B:%.*]] = copy_value [[B]]
+  // CHECK: end_borrow [[BORROWED_PAYLOAD]] from [[PAYLOAD]]
+  // CHECK: destroy_value [[COPY_B]]
+  // CHECK: destroy_value [[COPY_A]]
+  // CHECK: destroy_value [[PAYLOAD]]
+  for (a, b) in xx {}
+  // CHECK: bb7([[PAYLOAD:%.*]] : @owned $(C, C)):
+  // CHECK: [[BORROWED_PAYLOAD:%.*]] = begin_borrow [[PAYLOAD]]
+  // CHECK: [[A:%.*]] = tuple_extract [[BORROWED_PAYLOAD]] : $(C, C), 0
+  // CHECK: [[COPY_A:%.*]] = copy_value [[A]]
+  // CHECK: [[B:%.*]] = tuple_extract [[BORROWED_PAYLOAD]] : $(C, C), 1
+  // CHECK: [[COPY_B:%.*]] = copy_value [[B]]
+  // CHECK: destroy_value [[COPY_B]]
+  // CHECK: end_borrow [[BORROWED_PAYLOAD]] from [[PAYLOAD]]
+  // CHECK: destroy_value [[COPY_A]]
+  // CHECK: destroy_value [[PAYLOAD]]
+  for (a, _) in xx {}
+  // CHECK: bb11([[PAYLOAD:%.*]] : @owned $(C, C)):
+  // CHECK: [[BORROWED_PAYLOAD:%.*]] = begin_borrow [[PAYLOAD]]
+  // CHECK: [[A:%.*]] = tuple_extract [[BORROWED_PAYLOAD]] : $(C, C), 0
+  // CHECK: [[COPY_A:%.*]] = copy_value [[A]]
+  // CHECK: [[B:%.*]] = tuple_extract [[BORROWED_PAYLOAD]] : $(C, C), 1
+  // CHECK: [[COPY_B:%.*]] = copy_value [[B]]
+  // CHECK: destroy_value [[COPY_A]]
+  // CHECK: end_borrow [[BORROWED_PAYLOAD]] from [[PAYLOAD]]
+  // CHECK: destroy_value [[COPY_B]]
+  // CHECK: destroy_value [[PAYLOAD]]
+  for (_, b) in xx {}
+  // CHECK: bb15([[PAYLOAD:%.*]] : @owned $(C, C)):
+  // CHECK: [[BORROWED_PAYLOAD:%.*]] = begin_borrow [[PAYLOAD]]
+  // CHECK: [[A:%.*]] = tuple_extract [[BORROWED_PAYLOAD]] : $(C, C), 0
+  // CHECK: [[COPY_A:%.*]] = copy_value [[A]]
+  // CHECK: [[B:%.*]] = tuple_extract [[BORROWED_PAYLOAD]] : $(C, C), 1
+  // CHECK: [[COPY_B:%.*]] = copy_value [[B]]
+  // CHECK: destroy_value [[COPY_B]]
+  // CHECK: destroy_value [[COPY_A]]
+  // CHECK: end_borrow [[BORROWED_PAYLOAD]] from [[PAYLOAD]]
+  // CHECK: destroy_value [[PAYLOAD]]
+  for (_, _) in xx {}
+  // CHECK: bb19([[PAYLOAD:%.*]] : @owned $(C, C)):
+  // CHECK: [[BORROWED_PAYLOAD:%.*]] = begin_borrow [[PAYLOAD]]
+  // CHECK: [[A:%.*]] = tuple_extract [[BORROWED_PAYLOAD]] : $(C, C), 0
+  // CHECK: [[COPY_A:%.*]] = copy_value [[A]]
+  // CHECK: [[B:%.*]] = tuple_extract [[BORROWED_PAYLOAD]] : $(C, C), 1
+  // CHECK: [[COPY_B:%.*]] = copy_value [[B]]
+  // CHECK: destroy_value [[COPY_B]]
+  // CHECK: destroy_value [[COPY_A]]
+  // CHECK: end_borrow [[BORROWED_PAYLOAD]] from [[PAYLOAD]]
+  // CHECK: destroy_value [[PAYLOAD]]
+  for  _     in xx {}
+}
+
+// Make sure that when we have an unused value, we properly iterate over the
+// loop rather than run through the loop once.
+//
+// CHECK-LABEL: sil hidden @$S7foreach16unusedArgPatternyySaySiGF : $@convention(thin) (@guaranteed Array<Int>) -> () {
+// CHECK: bb0([[ARG:%.*]] : @guaranteed $Array<Int>):
+// CHECK:   br [[LOOP_DEST:bb[0-9]+]]
+//
+// CHECK: [[LOOP_DEST]]:
+// CHECK:   switch_enum [[OPT_VAL:%.*]] : $Optional<Int>, case #Optional.some!enumelt.1: [[SOME_BB:bb[0-9]+]], case #Optional.none!enumelt: [[NONE_BB:bb[0-9]+]]
+//
+// CHECK: [[NONE_BB]]:
+// CHECK:   br [[CONT_BB:bb[0-9]+]]
+//
+// CHECK: [[SOME_BB]]([[VAL:%.*]]  : @trivial $Int):
+// CHECK:   [[LOOP_END_FUNC:%.*]] = function_ref @loopBodyEnd : $@convention(thin) () -> ()
+// CHECK:   apply [[LOOP_END_FUNC]]
+func unusedArgPattern(_ xx: [Int]) {
+  for _ in xx {
+    loopBodyEnd()
+  }
+}
diff --git a/test/SILGen/plus_zero_foreign_errors.swift b/test/SILGen/plus_zero_foreign_errors.swift
new file mode 100644
index 0000000..d004d8f
--- /dev/null
+++ b/test/SILGen/plus_zero_foreign_errors.swift
@@ -0,0 +1,311 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %empty-directory(%t)
+// RUN: %build-clang-importer-objc-overlays
+// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk-nosource -I %t) -emit-silgen -parse-as-library %s | %FileCheck %s
+
+// REQUIRES: objc_interop
+
+import Foundation
+import errors
+
+// CHECK-LABEL: sil hidden @$S14foreign_errors5test0yyKF : $@convention(thin) () -> @error Error
+func test0() throws {
+  //   Create a strong temporary holding nil before we perform any further parts of function emission.
+  // CHECK: [[ERR_TEMP0:%.*]] = alloc_stack $Optional<NSError>
+  // CHECK: inject_enum_addr [[ERR_TEMP0]] : $*Optional<NSError>, #Optional.none!enumelt
+
+  // CHECK: [[SELF:%.*]] = metatype $@objc_metatype ErrorProne.Type
+  // CHECK: [[METHOD:%.*]] = objc_method [[SELF]] : $@objc_metatype ErrorProne.Type, #ErrorProne.fail!1.foreign : (ErrorProne.Type) -> () throws -> (), $@convention(objc_method) (Optional<AutoreleasingUnsafeMutablePointer<Optional<NSError>>>, @objc_metatype ErrorProne.Type) -> ObjCBool
+
+  //   Create an unmanaged temporary, copy into it, and make a AutoreleasingUnsafeMutablePointer.
+  // CHECK: [[ERR_TEMP1:%.*]] = alloc_stack $@sil_unmanaged Optional<NSError>
+  // CHECK: [[T0:%.*]] = load_borrow [[ERR_TEMP0]]
+  // CHECK: [[T1:%.*]] = ref_to_unmanaged [[T0]]
+  // CHECK: store [[T1]] to [trivial] [[ERR_TEMP1]]
+  // CHECK: address_to_pointer [[ERR_TEMP1]]
+
+  //   Call the method.
+  // CHECK: [[RESULT:%.*]] = apply [[METHOD]]({{.*}}, [[SELF]])
+
+  //   Writeback to the first temporary.
+  // CHECK: [[T0:%.*]] = load [trivial] [[ERR_TEMP1]]
+  // CHECK: [[T1:%.*]] = unmanaged_to_ref [[T0]]
+  // CHECK: [[T1_COPY:%.*]] = copy_value [[T1]]
+  // CHECK: assign [[T1_COPY]] to [[ERR_TEMP0]]
+
+  //   Pull out the boolean value and compare it to zero.
+  // CHECK: [[BOOL_OR_INT:%.*]] = struct_extract [[RESULT]]
+  // CHECK: [[RAW_VALUE:%.*]] = struct_extract [[BOOL_OR_INT]]
+  //   On some platforms RAW_VALUE will be compared against 0; on others it's
+  //   already an i1 (bool) and those instructions will be skipped. Just do a
+  //   looser check.
+  // CHECK: cond_br {{%.+}}, [[NORMAL_BB:bb[0-9]+]], [[ERROR_BB:bb[0-9]+]]
+  try ErrorProne.fail()
+
+  //   Normal path: fall out and return.
+  // CHECK: [[NORMAL_BB]]:
+  // CHECK: return
+  
+  //   Error path: fall out and rethrow.
+  // CHECK: [[ERROR_BB]]:
+  // CHECK: [[T0:%.*]] = load [take] [[ERR_TEMP0]]
+  // CHECK: [[T1:%.*]] = function_ref @$S10Foundation22_convertNSErrorToErrorys0E0_pSo0C0CSgF : $@convention(thin) (@guaranteed Optional<NSError>) -> @owned Error
+  // CHECK: [[T2:%.*]] = apply [[T1]]([[T0]])
+  // CHECK: throw [[T2]] : $Error
+}
+
+extension NSObject {
+  @objc func abort() throws {
+    throw NSError(domain: "", code: 1, userInfo: [:])
+  }
+// CHECK-LABEL: sil hidden [thunk] @$SSo8NSObjectC14foreign_errorsE5abortyyKFTo : $@convention(objc_method) (Optional<AutoreleasingUnsafeMutablePointer<Optional<NSError>>>, NSObject) -> ObjCBool
+// CHECK: [[T0:%.*]] = function_ref @$SSo8NSObjectC14foreign_errorsE5abortyyKF : $@convention(method) (@guaranteed NSObject) -> @error Error
+// CHECK: try_apply [[T0]](
+// CHECK: bb1(
+// CHECK:   [[BITS:%.*]] = integer_literal $Builtin.Int{{[18]}}, {{1|-1}}
+// CHECK:   [[VALUE:%.*]] = struct ${{Bool|UInt8}} ([[BITS]] : $Builtin.Int{{[18]}})
+// CHECK:   [[BOOL:%.*]] = struct $ObjCBool ([[VALUE]] : ${{Bool|UInt8}})
+// CHECK:   br bb6([[BOOL]] : $ObjCBool)
+// CHECK: bb2([[ERR:%.*]] : $Error):
+// CHECK:   switch_enum %0 : $Optional<AutoreleasingUnsafeMutablePointer<Optional<NSError>>>, case #Optional.some!enumelt.1: bb3, case #Optional.none!enumelt: bb4
+// CHECK: bb3([[UNWRAPPED_OUT:%.+]] : $AutoreleasingUnsafeMutablePointer<Optional<NSError>>):
+// CHECK:   [[T0:%.*]] = function_ref @$S10Foundation22_convertErrorToNSErrorySo0E0Cs0C0_pF : $@convention(thin) (@guaranteed Error) -> @owned NSError
+// CHECK:   [[T1:%.*]] = apply [[T0]]([[ERR]])
+// CHECK:   [[OBJCERR:%.*]] = enum $Optional<NSError>, #Optional.some!enumelt.1, [[T1]] : $NSError
+// CHECK:   [[TEMP:%.*]] = alloc_stack $Optional<NSError>
+// CHECK:   store [[OBJCERR]] to [init] [[TEMP]]
+// CHECK:   [[SETTER:%.*]] = function_ref @$Ss33AutoreleasingUnsafeMutablePointerV7pointeexvs :
+// CHECK:   apply [[SETTER]]<Optional<NSError>>([[TEMP]], [[UNWRAPPED_OUT]])
+// CHECK:   dealloc_stack [[TEMP]]
+// CHECK:   br bb5
+// CHECK: bb4:
+// CHECK:   destroy_value [[ERR]] : $Error
+// CHECK:   br bb5
+// CHECK: bb5:
+// CHECK:   [[BITS:%.*]] = integer_literal $Builtin.Int{{[18]}}, 0
+// CHECK:   [[VALUE:%.*]] = struct ${{Bool|UInt8}} ([[BITS]] : $Builtin.Int{{[18]}})
+// CHECK:   [[BOOL:%.*]] = struct $ObjCBool ([[VALUE]] : ${{Bool|UInt8}})
+// CHECK:   br bb6([[BOOL]] : $ObjCBool)
+// CHECK: bb6([[BOOL:%.*]] : $ObjCBool):
+// CHECK:   return [[BOOL]] : $ObjCBool
+
+  @objc func badDescription() throws -> String {
+    throw NSError(domain: "", code: 1, userInfo: [:])
+  }
+// CHECK-LABEL: sil hidden [thunk] @$SSo8NSObjectC14foreign_errorsE14badDescriptionSSyKFTo : $@convention(objc_method) (Optional<AutoreleasingUnsafeMutablePointer<Optional<NSError>>>, NSObject) -> @autoreleased Optional<NSString> {
+// CHECK: bb0([[UNOWNED_ARG0:%.*]] : $Optional<AutoreleasingUnsafeMutablePointer<Optional<NSError>>>, [[UNOWNED_ARG1:%.*]] : $NSObject):
+// CHECK: [[ARG1:%.*]] = copy_value [[UNOWNED_ARG1]]
+// CHECK: [[BORROWED_ARG1:%.*]] = begin_borrow [[ARG1]]
+// CHECK: [[T0:%.*]] = function_ref @$SSo8NSObjectC14foreign_errorsE14badDescriptionSSyKF : $@convention(method) (@guaranteed NSObject) -> (@owned String, @error Error)
+// CHECK: try_apply [[T0]]([[BORROWED_ARG1]]) : $@convention(method) (@guaranteed NSObject) -> (@owned String, @error Error), normal [[NORMAL_BB:bb[0-9][0-9]*]], error [[ERROR_BB:bb[0-9][0-9]*]]
+//
+// CHECK: [[NORMAL_BB]]([[RESULT:%.*]] : $String):
+// CHECK:   [[T0:%.*]] = function_ref @$SSS10FoundationE19_bridgeToObjectiveCSo8NSStringCyF : $@convention(method) (@guaranteed String) -> @owned NSString
+// CHECK:   [[BORROWED_RESULT:%.*]] = begin_borrow [[RESULT]]
+// CHECK:   [[T1:%.*]] = apply [[T0]]([[BORROWED_RESULT]])
+// CHECK:   [[T2:%.*]] = enum $Optional<NSString>, #Optional.some!enumelt.1, [[T1]] : $NSString
+// CHECK:   end_borrow [[BORROWED_RESULT]] from [[RESULT]]
+// CHECK:   destroy_value [[RESULT]]  
+// CHECK:   br bb6([[T2]] : $Optional<NSString>)
+//
+// CHECK: [[ERROR_BB]]([[ERR:%.*]] : $Error):
+// CHECK:   switch_enum [[UNOWNED_ARG0]] : $Optional<AutoreleasingUnsafeMutablePointer<Optional<NSError>>>, case #Optional.some!enumelt.1: [[SOME_BB:bb[0-9][0-9]*]], case #Optional.none!enumelt: [[NONE_BB:bb[0-9][0-9]*]]
+//
+// CHECK: [[SOME_BB]]([[UNWRAPPED_OUT:%.+]] : $AutoreleasingUnsafeMutablePointer<Optional<NSError>>):
+// CHECK:   [[T0:%.*]] = function_ref @$S10Foundation22_convertErrorToNSErrorySo0E0Cs0C0_pF : $@convention(thin) (@guaranteed Error) -> @owned NSError
+// CHECK:   [[T1:%.*]] = apply [[T0]]([[ERR]])
+// CHECK:   [[OBJCERR:%.*]] = enum $Optional<NSError>, #Optional.some!enumelt.1, [[T1]] : $NSError
+// CHECK:   [[TEMP:%.*]] = alloc_stack $Optional<NSError>
+// CHECK:   store [[OBJCERR]] to [init] [[TEMP]]
+// CHECK:   [[SETTER:%.*]] = function_ref @$Ss33AutoreleasingUnsafeMutablePointerV7pointeexvs :
+// CHECK:   apply [[SETTER]]<Optional<NSError>>([[TEMP]], [[UNWRAPPED_OUT]])
+// CHECK:   dealloc_stack [[TEMP]]
+// CHECK:   br bb5
+//
+// CHECK: [[NONE_BB]]:
+// CHECK:   destroy_value [[ERR]] : $Error
+// CHECK:   br bb5
+//
+// CHECK: bb5:
+// CHECK:   [[T0:%.*]] = enum $Optional<NSString>, #Optional.none!enumelt
+// CHECK:   br bb6([[T0]] : $Optional<NSString>)
+//
+// CHECK: bb6([[T0:%.*]] : $Optional<NSString>):
+// CHECK:   end_borrow [[BORROWED_ARG1]] from [[ARG1]]
+// CHECK:   destroy_value [[ARG1]]
+// CHECK:   return [[T0]] : $Optional<NSString>
+
+// CHECK-LABEL: sil hidden [thunk] @$SSo8NSObjectC14foreign_errorsE7takeIntyySiKFTo : $@convention(objc_method) (Int, Optional<AutoreleasingUnsafeMutablePointer<Optional<NSError>>>, NSObject) -> ObjCBool
+// CHECK: bb0([[I:%[0-9]+]] : $Int, [[ERROR:%[0-9]+]] : $Optional<AutoreleasingUnsafeMutablePointer<Optional<NSError>>>, [[SELF:%[0-9]+]] : $NSObject)
+  @objc func takeInt(_ i: Int) throws { }
+
+// CHECK-LABEL: sil hidden [thunk] @$SSo8NSObjectC14foreign_errorsE10takeDouble_3int7closureySd_S3iXEtKFTo : $@convention(objc_method) (Double, Int, Optional<AutoreleasingUnsafeMutablePointer<Optional<NSError>>>, @convention(block) @noescape (Int) -> Int, NSObject) -> ObjCBool
+// CHECK: bb0([[D:%[0-9]+]] : $Double, [[INT:%[0-9]+]] : $Int, [[ERROR:%[0-9]+]] : $Optional<AutoreleasingUnsafeMutablePointer<Optional<NSError>>>, [[CLOSURE:%[0-9]+]] : $@convention(block) @noescape (Int) -> Int, [[SELF:%[0-9]+]] : $NSObject):
+  @objc func takeDouble(_ d: Double, int: Int, closure: (Int) -> Int) throws {
+    throw NSError(domain: "", code: 1, userInfo: [:])
+  }
+}
+
+let fn = ErrorProne.fail
+// CHECK-LABEL: sil shared [serializable] [thunk] @$SSo10ErrorProneC4failyyKFZTcTO : $@convention(thin) (@thick ErrorProne.Type) -> @owned @callee_guaranteed () -> @error Error
+// CHECK:      [[T0:%.*]] = function_ref @$SSo10ErrorProneC4failyyKFZTO : $@convention(method) (@thick ErrorProne.Type) -> @error Error
+// CHECK-NEXT: [[T1:%.*]] = partial_apply [callee_guaranteed] [[T0]](%0)
+// CHECK-NEXT: return [[T1]]
+
+// CHECK-LABEL: sil shared [serializable] [thunk] @$SSo10ErrorProneC4failyyKFZTO : $@convention(method) (@thick ErrorProne.Type) -> @error Error {
+// CHECK:      [[SELF:%.*]] = thick_to_objc_metatype %0 : $@thick ErrorProne.Type to $@objc_metatype ErrorProne.Type
+// CHECK:      [[METHOD:%.*]] = objc_method [[T0]] : $@objc_metatype ErrorProne.Type, #ErrorProne.fail!1.foreign : (ErrorProne.Type) -> () throws -> (), $@convention(objc_method) (Optional<AutoreleasingUnsafeMutablePointer<Optional<NSError>>>, @objc_metatype ErrorProne.Type) -> ObjCBool
+// CHECK:      [[TEMP:%.*]] = alloc_stack $Optional<NSError>
+// CHECK:      [[RESULT:%.*]] = apply [[METHOD]]({{%.*}}, [[SELF]])
+// CHECK:      cond_br
+// CHECK:      return
+// CHECK:      [[T0:%.*]] = load [take] [[TEMP]]
+// CHECK:      [[T1:%.*]] = apply {{%.*}}([[T0]])
+// CHECK:      throw [[T1]]
+
+func testArgs() throws {
+  try ErrorProne.consume(nil)
+}
+// CHECK-LABEL: sil hidden @$S14foreign_errors8testArgsyyKF : $@convention(thin) () -> @error Error
+// CHECK:   debug_value undef : $Error, var, name "$error", argno 1
+// CHECK:   objc_method {{.*}} : $@objc_metatype ErrorProne.Type, #ErrorProne.consume!1.foreign : (ErrorProne.Type) -> (Any?) throws -> (), $@convention(objc_method) (Optional<AnyObject>, Optional<AutoreleasingUnsafeMutablePointer<Optional<NSError>>>, @objc_metatype ErrorProne.Type) -> ObjCBool
+
+func testBridgedResult() throws {
+  let array = try ErrorProne.collection(withCount: 0)
+}
+// CHECK-LABEL: sil hidden @$S14foreign_errors17testBridgedResultyyKF : $@convention(thin) () -> @error Error {
+// CHECK:   debug_value undef : $Error, var, name "$error", argno 1
+// CHECK:   objc_method {{.*}} : $@objc_metatype ErrorProne.Type, #ErrorProne.collection!1.foreign : (ErrorProne.Type) -> (Int) throws -> [Any], $@convention(objc_method) (Int, Optional<AutoreleasingUnsafeMutablePointer<Optional<NSError>>>, @objc_metatype ErrorProne.Type) -> @autoreleased Optional<NSArray>
+
+// rdar://20861374
+// Clear out the self box before delegating.
+class VeryErrorProne : ErrorProne {
+  init(withTwo two: AnyObject?) throws {
+    try super.init(one: two)
+  }
+}
+
+// SEMANTIC SIL TODO: _TFC14foreign_errors14VeryErrorPronec has a lot more going
+// on than is being tested here, we should consider adding FileCheck tests for
+// it.
+
+// CHECK-LABEL:    sil hidden @$S14foreign_errors14VeryErrorProneC7withTwoACyXlSg_tKcfc
+// CHECK:    bb0([[ARG1:%.*]] : $Optional<AnyObject>, [[ARG2:%.*]] : $VeryErrorProne):
+// CHECK:      [[BOX:%.*]] = alloc_box ${ var VeryErrorProne }
+// CHECK:      [[MARKED_BOX:%.*]] = mark_uninitialized [derivedself] [[BOX]]
+// CHECK:      [[PB:%.*]] = project_box [[MARKED_BOX]]
+// CHECK:      store [[ARG2]] to [init] [[PB]]
+// CHECK:      [[T0:%.*]] = load [take] [[PB]]
+// CHECK-NEXT: [[T1:%.*]] = upcast [[T0]] : $VeryErrorProne to $ErrorProne
+// CHECK:      [[BORROWED_ARG1:%.*]] = begin_borrow [[ARG1]]
+// CHECK:      [[ARG1_COPY:%.*]] = copy_value [[BORROWED_ARG1]]
+// CHECK-NOT:  [[BOX]]{{^[0-9]}}
+// CHECK-NOT:  [[PB]]{{^[0-9]}}
+// CHECK: [[BORROWED_T1:%.*]] = begin_borrow [[T1]]
+// CHECK-NEXT: [[DOWNCAST_BORROWED_T1:%.*]] = unchecked_ref_cast [[BORROWED_T1]] : $ErrorProne to $VeryErrorProne
+// CHECK-NEXT: [[T2:%.*]] = objc_super_method [[DOWNCAST_BORROWED_T1]] : $VeryErrorProne, #ErrorProne.init!initializer.1.foreign : (ErrorProne.Type) -> (Any?) throws -> ErrorProne, $@convention(objc_method) (Optional<AnyObject>, Optional<AutoreleasingUnsafeMutablePointer<Optional<NSError>>>, @owned ErrorProne) -> @owned Optional<ErrorProne>
+// CHECK:      end_borrow [[BORROWED_T1]] from [[T1]]
+// CHECK:      apply [[T2]]([[ARG1_COPY]], {{%.*}}, [[T1]])
+
+// rdar://21051021
+// CHECK: sil hidden @$S14foreign_errors12testProtocolyySo010ErrorProneD0_pKF : $@convention(thin) (@guaranteed ErrorProneProtocol) -> @error Error
+// CHECK: bb0([[ARG0:%.*]] : $ErrorProneProtocol):
+func testProtocol(_ p: ErrorProneProtocol) throws {
+  // CHECK:   [[T0:%.*]] = open_existential_ref [[ARG0]] : $ErrorProneProtocol to $[[OPENED:@opened(.*) ErrorProneProtocol]]
+  // CHECK:   [[T1:%.*]] = objc_method [[T0]] : $[[OPENED]], #ErrorProneProtocol.obliterate!1.foreign : {{.*}}
+  // CHECK:   apply [[T1]]<[[OPENED]]>({{%.*}}, [[T0]]) : $@convention(objc_method) <τ_0_0 where τ_0_0 : ErrorProneProtocol> (Optional<AutoreleasingUnsafeMutablePointer<Optional<NSError>>>, τ_0_0) -> ObjCBool
+  try p.obliterate()
+
+  // CHECK:   [[T0:%.*]] = open_existential_ref [[ARG0]] : $ErrorProneProtocol to $[[OPENED:@opened(.*) ErrorProneProtocol]]
+  // CHECK:   [[T1:%.*]] = objc_method [[T0]] : $[[OPENED]], #ErrorProneProtocol.invigorate!1.foreign : {{.*}}
+  // CHECK:   apply [[T1]]<[[OPENED]]>({{%.*}}, {{%.*}}, [[T0]]) : $@convention(objc_method) <τ_0_0 where τ_0_0 : ErrorProneProtocol> (Optional<AutoreleasingUnsafeMutablePointer<Optional<NSError>>>, Optional<@convention(block) () -> ()>, τ_0_0) -> ObjCBool
+  try p.invigorate(callback: {})
+}
+
+// rdar://21144509 - Ensure that overrides of replace-with-() imports are possible.
+class ExtremelyErrorProne : ErrorProne {
+  override func conflict3(_ obj: Any, error: ()) throws {}
+}
+// CHECK-LABEL: sil hidden @$S14foreign_errors19ExtremelyErrorProneC9conflict3_5erroryyp_yttKF
+// CHECK-LABEL: sil hidden [thunk] @$S14foreign_errors19ExtremelyErrorProneC9conflict3_5erroryyp_yttKFTo : $@convention(objc_method) (AnyObject, Optional<AutoreleasingUnsafeMutablePointer<Optional<NSError>>>, ExtremelyErrorProne) -> ObjCBool
+
+// These conventions are usable because of swift_error. rdar://21715350
+func testNonNilError() throws -> Float {
+  return try ErrorProne.bounce()
+}
+// CHECK-LABEL: sil hidden @$S14foreign_errors15testNonNilErrorSfyKF :
+// CHECK:   [[OPTERR:%.*]] = alloc_stack $Optional<NSError>
+// CHECK:   [[T0:%.*]] = metatype $@objc_metatype ErrorProne.Type
+// CHECK:   [[T1:%.*]] = objc_method [[T0]] : $@objc_metatype ErrorProne.Type, #ErrorProne.bounce!1.foreign : (ErrorProne.Type) -> () throws -> Float, $@convention(objc_method) (Optional<AutoreleasingUnsafeMutablePointer<Optional<NSError>>>, @objc_metatype ErrorProne.Type) -> Float
+// CHECK:   [[RESULT:%.*]] = apply [[T1]](
+// CHECK:   assign {{%.*}} to [[OPTERR]]
+// CHECK:   [[T0:%.*]] = load [take] [[OPTERR]]
+// CHECK:   switch_enum [[T0]] : $Optional<NSError>, case #Optional.some!enumelt.1: [[ERROR_BB:bb[0-9]+]], case #Optional.none!enumelt: [[NORMAL_BB:bb[0-9]+]]
+// CHECK: [[NORMAL_BB]]:
+// CHECK-NOT: destroy_value
+// CHECK:   return [[RESULT]]
+// CHECK: [[ERROR_BB]]
+
+func testPreservedResult() throws -> CInt {
+  return try ErrorProne.ounce()
+}
+// CHECK-LABEL: sil hidden @$S14foreign_errors19testPreservedResults5Int32VyKF
+// CHECK:   [[OPTERR:%.*]] = alloc_stack $Optional<NSError>
+// CHECK:   [[T0:%.*]] = metatype $@objc_metatype ErrorProne.Type
+// CHECK:   [[T1:%.*]] = objc_method [[T0]] : $@objc_metatype ErrorProne.Type, #ErrorProne.ounce!1.foreign : (ErrorProne.Type) -> () throws -> Int32, $@convention(objc_method) (Optional<AutoreleasingUnsafeMutablePointer<Optional<NSError>>>, @objc_metatype ErrorProne.Type) -> Int32
+// CHECK:   [[RESULT:%.*]] = apply [[T1]](
+// CHECK:   [[T0:%.*]] = struct_extract [[RESULT]]
+// CHECK:   [[T1:%.*]] = integer_literal $[[PRIM:Builtin.Int[0-9]+]], 0
+// CHECK:   [[T2:%.*]] = builtin "cmp_ne_Int32"([[T0]] : $[[PRIM]], [[T1]] : $[[PRIM]])
+// CHECK:   cond_br [[T2]], [[NORMAL_BB:bb[0-9]+]], [[ERROR_BB:bb[0-9]+]]
+// CHECK: [[NORMAL_BB]]:
+// CHECK-NOT: destroy_value
+// CHECK:   return [[RESULT]]
+// CHECK: [[ERROR_BB]]
+
+func testPreservedResultBridged() throws -> Int {
+  return try ErrorProne.ounceWord()
+}
+
+// CHECK-LABEL: sil hidden @$S14foreign_errors26testPreservedResultBridgedSiyKF
+// CHECK:   [[OPTERR:%.*]] = alloc_stack $Optional<NSError>
+// CHECK:   [[T0:%.*]] = metatype $@objc_metatype ErrorProne.Type
+// CHECK:   [[T1:%.*]] = objc_method [[T0]] : $@objc_metatype ErrorProne.Type, #ErrorProne.ounceWord!1.foreign : (ErrorProne.Type) -> () throws -> Int, $@convention(objc_method) (Optional<AutoreleasingUnsafeMutablePointer<Optional<NSError>>>, @objc_metatype ErrorProne.Type) -> Int
+// CHECK:   [[RESULT:%.*]] = apply [[T1]](
+// CHECK:   [[T0:%.*]] = struct_extract [[RESULT]]
+// CHECK:   [[T1:%.*]] = integer_literal $[[PRIM:Builtin.Int[0-9]+]], 0
+// CHECK:   [[T2:%.*]] = builtin "cmp_ne_Int{{.*}}"([[T0]] : $[[PRIM]], [[T1]] : $[[PRIM]])
+// CHECK:   cond_br [[T2]], [[NORMAL_BB:bb[0-9]+]], [[ERROR_BB:bb[0-9]+]]
+// CHECK: [[NORMAL_BB]]:
+// CHECK-NOT: destroy_value
+// CHECK:   return [[RESULT]]
+// CHECK: [[ERROR_BB]]
+
+func testPreservedResultInverted() throws {
+  try ErrorProne.once()
+}
+
+// CHECK-LABEL: sil hidden @$S14foreign_errors27testPreservedResultInvertedyyKF
+// CHECK:   [[OPTERR:%.*]] = alloc_stack $Optional<NSError>
+// CHECK:   [[T0:%.*]] = metatype $@objc_metatype ErrorProne.Type
+// CHECK:   [[T1:%.*]] = objc_method [[T0]] : $@objc_metatype ErrorProne.Type, #ErrorProne.once!1.foreign : (ErrorProne.Type) -> () throws -> (), $@convention(objc_method) (Optional<AutoreleasingUnsafeMutablePointer<Optional<NSError>>>, @objc_metatype ErrorProne.Type) -> Int32
+// CHECK:   [[RESULT:%.*]] = apply [[T1]](
+// CHECK:   [[T0:%.*]] = struct_extract [[RESULT]]
+// CHECK:   [[T1:%.*]] = integer_literal $[[PRIM:Builtin.Int[0-9]+]], 0
+// CHECK:   [[T2:%.*]] = builtin "cmp_ne_Int32"([[T0]] : $[[PRIM]], [[T1]] : $[[PRIM]])
+// CHECK:   cond_br [[T2]], [[ERROR_BB:bb[0-9]+]], [[NORMAL_BB:bb[0-9]+]]
+// CHECK: [[NORMAL_BB]]:
+// CHECK-NOT: destroy_value
+// CHECK:   return {{%.+}} : $()
+// CHECK: [[ERROR_BB]]
+
+// Make sure that we do not crash when emitting the error value here.
+//
+// TODO: Add some additional filecheck tests.
+extension NSURL {
+  func resourceValue<T>(forKey key: String) -> T? {
+    var prop: AnyObject? = nil
+    _ = try? self.getResourceValue(&prop, forKey: key)
+    return prop as? T
+  }
+}
diff --git a/test/SILGen/plus_zero_function_conversion.swift b/test/SILGen/plus_zero_function_conversion.swift
new file mode 100644
index 0000000..a3dc163
--- /dev/null
+++ b/test/SILGen/plus_zero_function_conversion.swift
@@ -0,0 +1,643 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership -primary-file %s | %FileCheck %s
+// RUN: %target-swift-frontend -emit-ir -enable-sil-ownership -primary-file %s
+
+// Check SILGen against various FunctionConversionExprs emitted by Sema.
+
+// ==== Representation conversions
+
+// CHECK-LABEL: sil hidden @$S19function_conversion7cToFuncyS2icS2iXCF : $@convention(thin) (@convention(c) (Int) -> Int) -> @owned @callee_guaranteed (Int) -> Int
+// CHECK:         [[THUNK:%.*]] = function_ref @$SS2iIetCyd_S2iIegyd_TR
+// CHECK:         [[FUNC:%.*]] = partial_apply [callee_guaranteed] [[THUNK]](%0)
+// CHECK:         return [[FUNC]]
+func cToFunc(_ arg: @escaping @convention(c) (Int) -> Int) -> (Int) -> Int {
+  return arg
+}
+
+// CHECK-LABEL: sil hidden @$S19function_conversion8cToBlockyS2iXBS2iXCF : $@convention(thin) (@convention(c) (Int) -> Int) -> @owned @convention(block) (Int) -> Int
+// CHECK:         [[BLOCK_STORAGE:%.*]] = alloc_stack $@block_storage
+// CHECK:         [[BLOCK:%.*]] = init_block_storage_header [[BLOCK_STORAGE]]
+// CHECK:         [[COPY:%.*]] = copy_block [[BLOCK]] : $@convention(block) (Int) -> Int
+// CHECK:         return [[COPY]]
+func cToBlock(_ arg: @escaping @convention(c) (Int) -> Int) -> @convention(block) (Int) -> Int {
+  return arg
+}
+
+// ==== Throws variance
+
+// CHECK-LABEL: sil hidden @$S19function_conversion12funcToThrowsyyyKcyycF : $@convention(thin) (@guaranteed @callee_guaranteed () -> ()) -> @owned @callee_guaranteed () -> @error Error
+// CHECK: bb0([[ARG:%.*]] : @guaranteed $@callee_guaranteed () -> ()):
+// CHECK:   [[ARG_COPY:%.*]] = copy_value [[ARG]]
+// CHECK:   [[FUNC:%.*]] = convert_function [[ARG_COPY]] : $@callee_guaranteed () -> () to $@callee_guaranteed () -> @error Error
+// CHECK:   return [[FUNC]]
+// CHECK: } // end sil function '$S19function_conversion12funcToThrowsyyyKcyycF'
+func funcToThrows(_ x: @escaping () -> ()) -> () throws -> () {
+  return x
+}
+
+// CHECK-LABEL: sil hidden @$S19function_conversion12thinToThrowsyyyKXfyyXfF : $@convention(thin) (@convention(thin) () -> ()) -> @convention(thin) () -> @error Error
+// CHECK:         [[FUNC:%.*]] = convert_function %0 : $@convention(thin) () -> () to $@convention(thin) () -> @error Error
+// CHECK:         return [[FUNC]] : $@convention(thin) () -> @error Error
+func thinToThrows(_ x: @escaping @convention(thin) () -> ()) -> @convention(thin) () throws -> () {
+  return x
+}
+
+// FIXME: triggers an assert because we always do a thin to thick conversion on DeclRefExprs
+/*
+func thinFunc() {}
+
+func thinToThrows() {
+  let _: @convention(thin) () -> () = thinFunc
+}
+*/
+
+// ==== Class downcasts and upcasts
+
+class Feral {}
+class Domesticated : Feral {}
+
+// CHECK-LABEL: sil hidden @$S19function_conversion12funcToUpcastyAA5FeralCycAA12DomesticatedCycF : $@convention(thin) (@guaranteed @callee_guaranteed () -> @owned Domesticated) -> @owned @callee_guaranteed () -> @owned Feral {
+// CHECK: bb0([[ARG:%.*]] : @guaranteed $@callee_guaranteed () -> @owned Domesticated):
+// CHECK:   [[ARG_COPY:%.*]] = copy_value [[ARG]]
+// CHECK:   [[FUNC:%.*]] = convert_function [[ARG_COPY]] : $@callee_guaranteed () -> @owned Domesticated to $@callee_guaranteed () -> @owned Feral
+// CHECK:   return [[FUNC]]
+// CHECK: } // end sil function '$S19function_conversion12funcToUpcastyAA5FeralCycAA12DomesticatedCycF'
+func funcToUpcast(_ x: @escaping () -> Domesticated) -> () -> Feral {
+  return x
+}
+
+// CHECK-LABEL: sil hidden @$S19function_conversion12funcToUpcastyyAA12DomesticatedCcyAA5FeralCcF : $@convention(thin) (@guaranteed @callee_guaranteed (@guaranteed Feral) -> ()) -> @owned @callee_guaranteed (@guaranteed Domesticated) -> ()
+// CHECK: bb0([[ARG:%.*]] :
+// CHECK:   [[ARG_COPY:%.*]] = copy_value [[ARG]]
+// CHECK:   [[FUNC:%.*]] = convert_function [[ARG_COPY]] : $@callee_guaranteed (@guaranteed Feral) -> () to $@callee_guaranteed (@guaranteed Domesticated) -> (){{.*}}
+// CHECK:   return [[FUNC]]
+func funcToUpcast(_ x: @escaping (Feral) -> ()) -> (Domesticated) -> () {
+  return x
+}
+
+// ==== Optionals
+
+struct Trivial {
+  let n: Int8
+}
+
+class C {
+  let n: Int8
+
+  init(n: Int8) {
+    self.n = n
+  }
+}
+
+struct Loadable {
+  let c: C
+
+  var n: Int8 {
+    return c.n
+  }
+
+  init(n: Int8) {
+    c = C(n: n)
+  }
+}
+
+struct AddrOnly {
+  let a: Any
+
+  var n: Int8 {
+    return a as! Int8
+  }
+
+  init(n: Int8) {
+    a = n
+  }
+}
+
+// CHECK-LABEL: sil hidden @$S19function_conversion19convOptionalTrivialyyAA0E0VADSgcF
+func convOptionalTrivial(_ t1: @escaping (Trivial?) -> Trivial) {
+// CHECK:         function_ref @$S19function_conversion7TrivialVSgACIegyd_AcDIegyd_TR
+// CHECK:         partial_apply
+  let _: (Trivial) -> Trivial? = t1
+
+// CHECK:         function_ref @$S19function_conversion7TrivialVSgACIegyd_A2DIegyd_TR
+// CHECK:         partial_apply
+  let _: (Trivial?) -> Trivial? = t1
+}
+
+// CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] @$S19function_conversion7TrivialVSgACIegyd_AcDIegyd_TR : $@convention(thin) (Trivial, @guaranteed @callee_guaranteed (Optional<Trivial>) -> Trivial) -> Optional<Trivial>
+// CHECK:         [[ENUM:%.*]] = enum $Optional<Trivial>
+// CHECK-NEXT:    apply %1([[ENUM]])
+// CHECK-NEXT:    enum $Optional<Trivial>
+// CHECK-NEXT:    return
+
+// CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] @$S19function_conversion7TrivialVSgACIegyd_A2DIegyd_TR : $@convention(thin) (Optional<Trivial>, @guaranteed @callee_guaranteed (Optional<Trivial>) -> Trivial) -> Optional<Trivial>
+// CHECK:         apply %1(%0)
+// CHECK-NEXT:    enum $Optional<Trivial>
+// CHECK-NEXT:    return
+
+// CHECK-LABEL: sil hidden @$S19function_conversion20convOptionalLoadableyyAA0E0VADSgcF
+func convOptionalLoadable(_ l1: @escaping (Loadable?) -> Loadable) {
+// CHECK:         function_ref @$S19function_conversion8LoadableVSgACIeggo_AcDIeggo_TR
+// CHECK:         partial_apply
+  let _: (Loadable) -> Loadable? = l1
+
+// CHECK:         function_ref @$S19function_conversion8LoadableVSgACIeggo_A2DIeggo_TR
+// CHECK:         partial_apply
+  let _: (Loadable?) -> Loadable? = l1
+}
+
+// CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] @$S19function_conversion8LoadableVSgACIeggo_A2DIeggo_TR : $@convention(thin) (@guaranteed Optional<Loadable>, @guaranteed @callee_guaranteed (@guaranteed Optional<Loadable>) -> @owned Loadable) -> @owned Optional<Loadable>
+// CHECK:         apply %1(%0)
+// CHECK-NEXT:    enum $Optional<Loadable>
+// CHECK-NEXT:    return
+
+// CHECK-LABEL: sil hidden @$S19function_conversion20convOptionalAddrOnlyyyAA0eF0VADSgcF
+func convOptionalAddrOnly(_ a1: @escaping (AddrOnly?) -> AddrOnly) {
+// CHECK:         function_ref @$S19function_conversion8AddrOnlyVSgACIegnr_A2DIegnr_TR
+// CHECK:         partial_apply
+  let _: (AddrOnly?) -> AddrOnly? = a1
+}
+
+// CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] @$S19function_conversion8AddrOnlyVSgACIegnr_A2DIegnr_TR : $@convention(thin) (@in_guaranteed Optional<AddrOnly>, @guaranteed @callee_guaranteed (@in_guaranteed Optional<AddrOnly>) -> @out AddrOnly) -> @out Optional<AddrOnly>
+// CHECK:         [[TEMP:%.*]] = alloc_stack $AddrOnly
+// CHECK-NEXT:    apply %2([[TEMP]], %1)
+// CHECK-NEXT:    init_enum_data_addr %0 : $*Optional<AddrOnly>
+// CHECK-NEXT:    copy_addr [take] {{.*}} to [initialization] {{.*}} : $*AddrOnly
+// CHECK-NEXT:    inject_enum_addr %0 : $*Optional<AddrOnly>
+// CHECK-NEXT:    tuple ()
+// CHECK-NEXT:    dealloc_stack {{.*}} : $*AddrOnly
+// CHECK-NEXT:    return
+
+// ==== Existentials
+
+protocol Q {
+  var n: Int8 { get }
+}
+
+protocol P : Q {}
+
+extension Trivial : P {}
+extension Loadable : P {}
+extension AddrOnly : P {}
+
+// CHECK-LABEL: sil hidden @$S19function_conversion22convExistentialTrivial_2t3yAA0E0VAA1Q_pc_AeaF_pSgctF
+func convExistentialTrivial(_ t2: @escaping (Q) -> Trivial, t3: @escaping (Q?) -> Trivial) {
+// CHECK:         function_ref @$S19function_conversion1Q_pAA7TrivialVIegnd_AdA1P_pIegyr_TR
+// CHECK:         partial_apply
+  let _: (Trivial) -> P = t2
+
+// CHECK:         function_ref @$S19function_conversion1Q_pSgAA7TrivialVIegnd_AESgAA1P_pIegyr_TR
+// CHECK:         partial_apply
+  let _: (Trivial?) -> P = t3
+
+// CHECK:         function_ref @$S19function_conversion1Q_pAA7TrivialVIegnd_AA1P_pAaE_pIegnr_TR
+// CHECK:         partial_apply
+  let _: (P) -> P = t2
+}
+
+// CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] @$S19function_conversion1Q_pAA7TrivialVIegnd_AdA1P_pIegyr_TR : $@convention(thin) (Trivial, @guaranteed @callee_guaranteed (@in_guaranteed Q) -> Trivial) -> @out P
+// CHECK:         alloc_stack $Q
+// CHECK-NEXT:    init_existential_addr
+// CHECK-NEXT:    store
+// CHECK-NEXT:    apply
+// CHECK-NEXT:    init_existential_addr
+// CHECK-NEXT:    store
+// CHECK:         return
+
+// CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] @$S19function_conversion1Q_pSgAA7TrivialVIegnd_AESgAA1P_pIegyr_TR
+// CHECK:         switch_enum
+// CHECK: bb1([[TRIVIAL:%.*]] : @trivial $Trivial):
+// CHECK:         init_existential_addr
+// CHECK:         init_enum_data_addr
+// CHECK:         copy_addr
+// CHECK:         inject_enum_addr
+// CHECK: bb2:
+// CHECK:         inject_enum_addr
+// CHECK: bb3:
+// CHECK:         apply
+// CHECK:         init_existential_addr
+// CHECK:         store
+// CHECK:         return
+
+// CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] @$S19function_conversion1Q_pAA7TrivialVIegnd_AA1P_pAaE_pIegnr_TR : $@convention(thin) (@in_guaranteed P, @guaranteed @callee_guaranteed (@in_guaranteed Q) -> Trivial) -> @out P
+// CHECK:         [[TMP:%.*]] = alloc_stack $Q
+// CHECK-NEXT:    open_existential_addr immutable_access %1 : $*P
+// CHECK-NEXT:    init_existential_addr [[TMP]] : $*Q
+// CHECK-NEXT:    copy_addr {{.*}} to [initialization] {{.*}}
+// CHECK-NEXT:    apply
+// CHECK-NEXT:    init_existential_addr
+// CHECK-NEXT:    store
+// CHECK:         destroy_addr
+// CHECK:         return
+
+// ==== Existential metatypes
+
+// CHECK-LABEL: sil hidden @$S19function_conversion23convExistentialMetatypeyyAA7TrivialVmAA1Q_pXpSgcF
+func convExistentialMetatype(_ em: @escaping (Q.Type?) -> Trivial.Type) {
+// CHECK:         function_ref @$S19function_conversion1Q_pXmTSgAA7TrivialVXMtIegyd_AEXMtAA1P_pXmTIegyd_TR
+// CHECK:         partial_apply
+  let _: (Trivial.Type) -> P.Type = em
+
+// CHECK:         function_ref @$S19function_conversion1Q_pXmTSgAA7TrivialVXMtIegyd_AEXMtSgAA1P_pXmTIegyd_TR
+// CHECK:         partial_apply
+  let _: (Trivial.Type?) -> P.Type = em
+
+// CHECK:         function_ref @$S19function_conversion1Q_pXmTSgAA7TrivialVXMtIegyd_AA1P_pXmTAaF_pXmTIegyd_TR
+// CHECK:         partial_apply
+  let _: (P.Type) -> P.Type = em
+}
+
+// CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] @$S19function_conversion1Q_pXmTSgAA7TrivialVXMtIegyd_AEXMtAA1P_pXmTIegyd_TR : $@convention(thin) (@thin Trivial.Type, @guaranteed @callee_guaranteed (Optional<@thick Q.Type>) -> @thin Trivial.Type) -> @thick P.Type
+// CHECK:         [[META:%.*]] = metatype $@thick Trivial.Type
+// CHECK-NEXT:    init_existential_metatype [[META]] : $@thick Trivial.Type, $@thick Q.Type
+// CHECK-NEXT:    enum $Optional<@thick Q.Type>
+// CHECK-NEXT:    apply
+// CHECK-NEXT:    metatype $@thick Trivial.Type
+// CHECK-NEXT:    init_existential_metatype {{.*}} : $@thick Trivial.Type, $@thick P.Type
+// CHECK-NEXT:    return
+
+// CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] @$S19function_conversion1Q_pXmTSgAA7TrivialVXMtIegyd_AEXMtSgAA1P_pXmTIegyd_TR : $@convention(thin) (Optional<@thin Trivial.Type>, @guaranteed @callee_guaranteed (Optional<@thick Q.Type>) -> @thin Trivial.Type) -> @thick P.Type
+// CHECK:         switch_enum %0 : $Optional<@thin Trivial.Type>
+// CHECK: bb1([[META:%.*]] : @trivial $@thin Trivial.Type):
+// CHECK-NEXT:    metatype $@thick Trivial.Type
+// CHECK-NEXT:    init_existential_metatype {{.*}} : $@thick Trivial.Type, $@thick Q.Type
+// CHECK-NEXT:    enum $Optional<@thick Q.Type>
+// CHECK: bb2:
+// CHECK-NEXT:    enum $Optional<@thick Q.Type>
+// CHECK: bb3({{.*}}):
+// CHECK-NEXT:    apply
+// CHECK-NEXT:    metatype $@thick Trivial.Type
+// CHECK-NEXT:    init_existential_metatype {{.*}} : $@thick Trivial.Type, $@thick P.Type
+// CHECK-NEXT:    return
+
+// CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] @$S19function_conversion1Q_pXmTSgAA7TrivialVXMtIegyd_AA1P_pXmTAaF_pXmTIegyd_TR : $@convention(thin) (@thick P.Type, @guaranteed @callee_guaranteed (Optional<@thick Q.Type>) -> @thin Trivial.Type) -> @thick P.Type
+// CHECK:         open_existential_metatype %0 : $@thick P.Type to $@thick (@opened({{.*}}) P).Type
+// CHECK-NEXT:    init_existential_metatype %2 : $@thick (@opened({{.*}}) P).Type, $@thick Q.Type
+// CHECK-NEXT:    enum $Optional<@thick Q.Type>
+// CHECK-NEXT:    apply %1
+// CHECK-NEXT:    metatype $@thick Trivial.Type
+// CHECK-NEXT:    init_existential_metatype {{.*}} : $@thick Trivial.Type, $@thick P.Type
+// CHECK-NEXT:    return
+
+// ==== Class metatype upcasts
+
+class Parent {}
+class Child : Parent {}
+
+// Note: we add a Trivial => Trivial? conversion here to force a thunk
+// to be generated
+
+// CHECK-LABEL: sil hidden @$S19function_conversion18convUpcastMetatype_2c5yAA5ChildCmAA6ParentCm_AA7TrivialVSgtc_AEmAGmSg_AJtctF
+func convUpcastMetatype(_ c4: @escaping (Parent.Type, Trivial?) -> Child.Type,
+                        c5: @escaping (Parent.Type?, Trivial?) -> Child.Type) {
+// CHECK:         function_ref @$S19function_conversion6ParentCXMTAA7TrivialVSgAA5ChildCXMTIegyyd_AHXMTAeCXMTIegyyd_TR
+// CHECK:         partial_apply
+  let _: (Child.Type, Trivial) -> Parent.Type = c4
+
+// CHECK:         function_ref @$S19function_conversion6ParentCXMTSgAA7TrivialVSgAA5ChildCXMTIegyyd_AIXMTAfCXMTIegyyd_TR
+// CHECK:         partial_apply
+  let _: (Child.Type, Trivial) -> Parent.Type = c5
+
+// CHECK:         function_ref @$S19function_conversion6ParentCXMTSgAA7TrivialVSgAA5ChildCXMTIegyyd_AIXMTSgAfDIegyyd_TR
+// CHECK:         partial_apply
+  let _: (Child.Type?, Trivial) -> Parent.Type? = c5
+}
+
+// CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] @$S19function_conversion6ParentCXMTAA7TrivialVSgAA5ChildCXMTIegyyd_AHXMTAeCXMTIegyyd_TR : $@convention(thin) (@thick Child.Type, Trivial, @guaranteed @callee_guaranteed (@thick Parent.Type, Optional<Trivial>) -> @thick Child.Type) -> @thick Parent.Type
+// CHECK:         upcast %0 : $@thick Child.Type to $@thick Parent.Type
+// CHECK:         apply
+// CHECK:         upcast {{.*}} : $@thick Child.Type to $@thick Parent.Type
+// CHECK:         return
+
+// CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] @$S19function_conversion6ParentCXMTSgAA7TrivialVSgAA5ChildCXMTIegyyd_AIXMTAfCXMTIegyyd_TR : $@convention(thin) (@thick Child.Type, Trivial, @guaranteed @callee_guaranteed (Optional<@thick Parent.Type>, Optional<Trivial>) -> @thick Child.Type) -> @thick Parent.Type
+// CHECK:         upcast %0 : $@thick Child.Type to $@thick Parent.Type
+// CHECK:         enum $Optional<@thick Parent.Type>
+// CHECK:         apply
+// CHECK:         upcast {{.*}} : $@thick Child.Type to $@thick Parent.Type
+// CHECK:         return
+
+// CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] @$S19function_conversion6ParentCXMTSgAA7TrivialVSgAA5ChildCXMTIegyyd_AIXMTSgAfDIegyyd_TR : $@convention(thin) (Optional<@thick Child.Type>, Trivial, @guaranteed @callee_guaranteed (Optional<@thick Parent.Type>, Optional<Trivial>) -> @thick Child.Type) -> Optional<@thick Parent.Type>
+// CHECK:         unchecked_trivial_bit_cast %0 : $Optional<@thick Child.Type> to $Optional<@thick Parent.Type>
+// CHECK:         apply
+// CHECK:         upcast {{.*}} : $@thick Child.Type to $@thick Parent.Type
+// CHECK:         enum $Optional<@thick Parent.Type>
+// CHECK:         return
+
+// ==== Function to existential -- make sure we maximally abstract it
+
+// CHECK-LABEL: sil hidden @$S19function_conversion19convFuncExistentialyyS2icypcF : $@convention(thin) (@guaranteed @callee_guaranteed (@in_guaranteed Any) -> @owned @callee_guaranteed (Int) -> Int) -> ()
+// CHECK: bb0([[ARG:%.*]] :
+// CHECK:   [[ARG_COPY:%.*]] = copy_value [[ARG]]
+// CHECK:   [[REABSTRACT_THUNK:%.*]] = function_ref @$SypS2iIegyd_Iegno_S2iIgyd_ypIegyr_TR
+// CHECK:   [[PA:%.*]] = partial_apply [callee_guaranteed] [[REABSTRACT_THUNK]]([[ARG_COPY]])
+// CHECK:   destroy_value [[PA]]
+// CHECK: } // end sil function '$S19function_conversion19convFuncExistentialyyS2icypcF'
+func convFuncExistential(_ f1: @escaping (Any) -> (Int) -> Int) {
+  let _: ((Int) -> Int) -> Any = f1
+}
+
+// CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] @$SypS2iIegyd_Iegno_S2iIgyd_ypIegyr_TR : $@convention(thin) (@noescape @callee_guaranteed (Int) -> Int, @guaranteed @callee_guaranteed (@in_guaranteed Any) -> @owned @callee_guaranteed (Int) -> Int) -> @out Any
+// CHECK:         alloc_stack $Any
+// CHECK:         function_ref @$SS2iIgyd_S2iIegnr_TR
+// CHECK-NEXT:    partial_apply
+// CHECK-NEXT:    convert_escape_to_noescape
+// CHECK-NEXT:    init_existential_addr %3 : $*Any, $(Int) -> Int
+// CHECK-NEXT:    store
+// CHECK-NEXT:    apply
+// CHECK:         function_ref @$SS2iIegyd_S2iIegnr_TR
+// CHECK-NEXT:    partial_apply
+// CHECK-NEXT:    init_existential_addr %0 : $*Any, $(Int) -> Int
+// CHECK-NEXT:    store {{.*}} to {{.*}} : $*@callee_guaranteed (@in_guaranteed Int) -> @out Int
+// CHECK:         return
+
+// CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] @$SS2iIegyd_S2iIegnr_TR : $@convention(thin) (@in_guaranteed Int, @guaranteed @callee_guaranteed (Int) -> Int) -> @out Int
+// CHECK:         [[LOADED:%.*]] = load [trivial] %1 : $*Int
+// CHECK-NEXT:    apply %2([[LOADED]])
+// CHECK-NEXT:    store {{.*}} to [trivial] %0
+// CHECK-NEXT:    [[VOID:%.*]] = tuple ()
+// CHECK:         return [[VOID]]
+
+// ==== Class-bound archetype upcast
+
+// CHECK-LABEL: sil hidden @$S19function_conversion29convClassBoundArchetypeUpcast{{[_0-9a-zA-Z]*}}F
+func convClassBoundArchetypeUpcast<T : Parent>(_ f1: @escaping (Parent) -> (T, Trivial)) {
+// CHECK:         function_ref @$S19function_conversion6ParentCxAA7TrivialVIeggod_xAcESgIeggod_ACRbzlTR
+// CHECK:         partial_apply
+  let _: (T) -> (Parent, Trivial?) = f1
+}
+
+// CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] @$S19function_conversion6ParentCxAA7TrivialVIeggod_xAcESgIeggod_ACRbzlTR : $@convention(thin) <T where T : Parent> (@guaranteed T, @guaranteed @callee_guaranteed (@guaranteed Parent) -> (@owned T, Trivial)) -> (@owned Parent, Optional<Trivial>)
+// CHECK: bb0([[ARG:%.*]] : @guaranteed $T, [[CLOSURE:%.*]] : @guaranteed $@callee_guaranteed (@guaranteed Parent) -> (@owned T, Trivial)):
+// CHECK:    [[CASTED_ARG:%.*]] = upcast [[ARG]] : $T to $Parent
+// CHECK:    [[RESULT:%.*]] = apply %1([[CASTED_ARG]])
+// CHECK:    [[BORROWED_RESULT:%.*]] = begin_borrow [[RESULT]] : $(T, Trivial)
+// CHECK:    [[FIRST_RESULT:%.*]] = tuple_extract [[BORROWED_RESULT]] : $(T, Trivial), 0
+// CHECK:    [[COPIED_FIRST_RESULT:%.*]] = copy_value [[FIRST_RESULT]]
+// CHECK:    tuple_extract [[BORROWED_RESULT]] : $(T, Trivial), 1
+// CHECK:    destroy_value [[RESULT]]
+// CHECK:    [[CAST_COPIED_FIRST_RESULT:%.*]] = upcast [[COPIED_FIRST_RESULT]] : $T to $Parent
+// CHECK:    enum $Optional<Trivial>
+// CHECK:    [[RESULT:%.*]] = tuple ([[CAST_COPIED_FIRST_RESULT]] : $Parent, {{.*}} : $Optional<Trivial>)
+// CHECK:    return [[RESULT]]
+
+// CHECK-LABEL: sil hidden @$S19function_conversion37convClassBoundMetatypeArchetypeUpcast{{[_0-9a-zA-Z]*}}F
+func convClassBoundMetatypeArchetypeUpcast<T : Parent>(_ f1: @escaping (Parent.Type) -> (T.Type, Trivial)) {
+// CHECK:         function_ref @$S19function_conversion6ParentCXMTxXMTAA7TrivialVIegydd_xXMTACXMTAESgIegydd_ACRbzlTR
+// CHECK:         partial_apply
+  let _: (T.Type) -> (Parent.Type, Trivial?) = f1
+}
+
+// CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] @$S19function_conversion6ParentCXMTxXMTAA7TrivialVIegydd_xXMTACXMTAESgIegydd_ACRbzlTR : $@convention(thin) <T where T : Parent> (@thick T.Type, @guaranteed @callee_guaranteed (@thick Parent.Type) -> (@thick T.Type, Trivial)) -> (@thick Parent.Type, Optional<Trivial>)
+// CHECK:         upcast %0 : $@thick T.Type to $@thick Parent.Type
+// CHECK-NEXT:    apply
+// CHECK-NEXT:    tuple_extract
+// CHECK-NEXT:    tuple_extract
+// CHECK-NEXT:    upcast {{.*}} : $@thick T.Type to $@thick Parent.Type
+// CHECK-NEXT:    enum $Optional<Trivial>
+// CHECK-NEXT:    tuple
+// CHECK-NEXT:    return
+
+// ==== Make sure we destructure one-element tuples
+
+// CHECK-LABEL: sil hidden @$S19function_conversion15convTupleScalar_2f22f3yyAA1Q_pc_yAaE_pcySi_SitSgctF
+// CHECK:         function_ref @$S19function_conversion1Q_pIegn_AA1P_pIegn_TR
+// CHECK:         function_ref @$S19function_conversion1Q_pIegn_AA1P_pIegn_TR
+// CHECK:         function_ref @$SSi_SitSgIegy_S2iIegyy_TR
+
+// CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] @$S19function_conversion1Q_pIegn_AA1P_pIegn_TR : $@convention(thin) (@in_guaranteed P, @guaranteed @callee_guaranteed (@in_guaranteed Q) -> ()) -> ()
+
+// CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] @$SSi_SitSgIegy_S2iIegyy_TR : $@convention(thin) (Int, Int, @guaranteed @callee_guaranteed (Optional<(Int, Int)>) -> ()) -> ()
+
+func convTupleScalar(_ f1: @escaping (Q) -> (),
+                     f2: @escaping (_ parent: Q) -> (),
+                     f3: @escaping (_ tuple: (Int, Int)?) -> ()) {
+  let _: (P) -> () = f1
+  let _: (P) -> () = f2
+  let _: (Int, Int) -> () = f3
+}
+
+func convTupleScalarOpaque<T>(_ f: @escaping (T...) -> ()) -> ((_ args: T...) -> ())? {
+  return f
+}
+
+// CHECK-LABEL: sil hidden @$S19function_conversion25convTupleToOptionalDirectySi_SitSgSicSi_SitSicF : $@convention(thin) (@guaranteed @callee_guaranteed (Int) -> (Int, Int)) -> @owned @callee_guaranteed (Int) -> Optional<(Int, Int)>
+// CHECK:         bb0([[ARG:%.*]] : @guaranteed $@callee_guaranteed (Int) -> (Int, Int)):
+// CHECK:           [[FN:%.*]] = copy_value [[ARG]]
+// CHECK:           [[THUNK_FN:%.*]] = function_ref @$SS3iIegydd_S2i_SitSgIegyd_TR
+// CHECK-NEXT:      [[THUNK:%.*]] = partial_apply [callee_guaranteed] [[THUNK_FN]]([[FN]])
+// CHECK-NEXT:      return [[THUNK]]
+// CHECK-NEXT: } // end sil function '$S19function_conversion25convTupleToOptionalDirectySi_SitSgSicSi_SitSicF'
+
+// CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] @$SS3iIegydd_S2i_SitSgIegyd_TR : $@convention(thin) (Int, @guaranteed @callee_guaranteed (Int) -> (Int, Int)) -> Optional<(Int, Int)>
+// CHECK:         bb0(%0 : @trivial $Int, %1 : @guaranteed $@callee_guaranteed (Int) -> (Int, Int)):
+// CHECK:           [[RESULT:%.*]] = apply %1(%0)
+// CHECK-NEXT:      [[LEFT:%.*]] = tuple_extract [[RESULT]]
+// CHECK-NEXT:      [[RIGHT:%.*]] = tuple_extract [[RESULT]]
+// CHECK-NEXT:      [[RESULT:%.*]] = tuple ([[LEFT]] : $Int, [[RIGHT]] : $Int)
+// CHECK-NEXT:      [[OPTIONAL:%.*]] = enum $Optional<(Int, Int)>, #Optional.some!enumelt.1, [[RESULT]]
+// CHECK-NEXT:      return [[OPTIONAL]]
+
+func convTupleToOptionalDirect(_ f: @escaping (Int) -> (Int, Int)) -> (Int) -> (Int, Int)? {
+  return f
+}
+
+// CHECK-LABEL: sil hidden @$S19function_conversion27convTupleToOptionalIndirectyx_xtSgxcx_xtxclF : $@convention(thin) <T> (@guaranteed @callee_guaranteed (@in_guaranteed T) -> (@out T, @out T)) -> @owned @callee_guaranteed (@in_guaranteed T) -> @out Optional<(T, T)>
+// CHECK:       bb0([[ARG:%.*]] : @guaranteed $@callee_guaranteed (@in_guaranteed T) -> (@out T, @out T)):
+// CHECK:          [[FN:%.*]] = copy_value [[ARG]]
+// CHECK:          [[THUNK_FN:%.*]] = function_ref @$SxxxIegnrr_xx_xtSgIegnr_lTR
+// CHECK-NEXT:     [[THUNK:%.*]] = partial_apply [callee_guaranteed] [[THUNK_FN]]<T>([[FN]])
+// CHECK-NEXT:     return [[THUNK]]
+// CHECK-NEXT: } // end sil function '$S19function_conversion27convTupleToOptionalIndirectyx_xtSgxcx_xtxclF'
+
+// CHECK:       sil shared [transparent] [serializable] [reabstraction_thunk] @$SxxxIegnrr_xx_xtSgIegnr_lTR : $@convention(thin) <T> (@in_guaranteed T, @guaranteed @callee_guaranteed (@in_guaranteed T) -> (@out T, @out T)) -> @out Optional<(T, T)>
+// CHECK:       bb0(%0 : @trivial $*Optional<(T, T)>, %1 : @trivial $*T, %2 : @guaranteed $@callee_guaranteed (@in_guaranteed T) -> (@out T, @out T)):
+// CHECK:         [[OPTIONAL:%.*]] = init_enum_data_addr %0 : $*Optional<(T, T)>, #Optional.some!enumelt.1
+// CHECK-NEXT:    [[LEFT:%.*]] = tuple_element_addr [[OPTIONAL]] : $*(T, T), 0
+// CHECK-NEXT:    [[RIGHT:%.*]] = tuple_element_addr [[OPTIONAL]] : $*(T, T), 1
+// CHECK-NEXT:    apply %2([[LEFT]], [[RIGHT]], %1)
+// CHECK-NEXT:    inject_enum_addr %0 : $*Optional<(T, T)>, #Optional.some!enumelt.1
+// CHECK-NEXT:    [[VOID:%.*]] = tuple ()
+// CHECK:         return [[VOID]]
+
+func convTupleToOptionalIndirect<T>(_ f: @escaping (T) -> (T, T)) -> (T) -> (T, T)? {
+  return f
+}
+
+// ==== Make sure we support AnyHashable erasure
+
+// CHECK-LABEL: sil hidden @$S19function_conversion15convAnyHashable1tyx_ts0E0RzlF
+// CHECK:         function_ref @$S19function_conversion15convAnyHashable1tyx_ts0E0RzlFSbs0dE0V_AFtcfU_
+// CHECK:         function_ref @$Ss11AnyHashableVABSbIegnnd_xxSbIegnnd_s0B0RzlTR
+
+// CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] @$Ss11AnyHashableVABSbIegnnd_xxSbIegnnd_s0B0RzlTR : $@convention(thin) <T where T : Hashable> (@in_guaranteed T, @in_guaranteed T, @guaranteed @callee_guaranteed (@in_guaranteed AnyHashable, @in_guaranteed AnyHashable) -> Bool) -> Bool
+// CHECK:         alloc_stack $AnyHashable
+// CHECK:         function_ref @$Ss21_convertToAnyHashableys0cD0Vxs0D0RzlF
+// CHECK:         apply {{.*}}<T>
+// CHECK:         alloc_stack $AnyHashable
+// CHECK:         function_ref @$Ss21_convertToAnyHashableys0cD0Vxs0D0RzlF
+// CHECK:         apply {{.*}}<T>
+// CHECK:         return
+
+func convAnyHashable<T : Hashable>(t: T) {
+  let fn: (T, T) -> Bool = {
+    (x: AnyHashable, y: AnyHashable) in x == y
+  }
+}
+
+// ==== Convert exploded tuples to Any or Optional<Any>
+
+// CHECK-LABEL: sil hidden @$S19function_conversion12convTupleAnyyyyyc_Si_SitycyypcyypSgctF
+// CHECK:         function_ref @$SIeg_ypIegr_TR
+// CHECK:         partial_apply
+// CHECK:         function_ref @$SIeg_ypSgIegr_TR
+// CHECK:         partial_apply
+// CHECK:         function_ref @$SS2iIegdd_ypIegr_TR
+// CHECK:         partial_apply
+// CHECK:         function_ref @$SS2iIegdd_ypSgIegr_TR
+// CHECK:         partial_apply
+// CHECK:         function_ref @$SypIegn_S2iIegyy_TR
+// CHECK:         partial_apply
+// CHECK:         function_ref @$SypSgIegn_S2iIegyy_TR
+// CHECK:         partial_apply
+
+func convTupleAny(_ f1: @escaping () -> (),
+                  _ f2: @escaping () -> (Int, Int),
+                  _ f3: @escaping (Any) -> (),
+                  _ f4: @escaping (Any?) -> ()) {
+  let _: () -> Any = f1
+  let _: () -> Any? = f1
+
+  let _: () -> Any = f2
+  let _: () -> Any? = f2
+
+  let _: ((Int, Int)) -> () = f3
+
+  let _: ((Int, Int)) -> () = f4
+}
+
+// CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] @$SIeg_ypIegr_TR : $@convention(thin) (@guaranteed @callee_guaranteed () -> ()) -> @out Any
+// CHECK:         init_existential_addr %0 : $*Any, $()
+// CHECK-NEXT:    apply %1()
+// CHECK-NEXT:    tuple ()
+// CHECK-NEXT:    return
+
+// CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] @$SIeg_ypSgIegr_TR : $@convention(thin) (@guaranteed @callee_guaranteed () -> ()) -> @out Optional<Any>
+// CHECK:         [[ENUM_PAYLOAD:%.*]] = init_enum_data_addr %0 : $*Optional<Any>, #Optional.some!enumelt.1
+// CHECK-NEXT:    init_existential_addr [[ENUM_PAYLOAD]] : $*Any, $()
+// CHECK-NEXT:    apply %1()
+// CHECK-NEXT:    inject_enum_addr %0 : $*Optional<Any>, #Optional.some!enumelt.1
+// CHECK-NEXT:    tuple ()
+// CHECK-NEXT:    return
+
+// CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] @$SS2iIegdd_ypIegr_TR : $@convention(thin) (@guaranteed @callee_guaranteed () -> (Int, Int)) -> @out Any
+// CHECK:         [[ANY_PAYLOAD:%.*]] = init_existential_addr %0
+// CHECK-NEXT:    [[LEFT_ADDR:%.*]] = tuple_element_addr [[ANY_PAYLOAD]]
+// CHECK-NEXT:    [[RIGHT_ADDR:%.*]] = tuple_element_addr [[ANY_PAYLOAD]]
+// CHECK-NEXT:    [[RESULT:%.*]] = apply %1()
+// CHECK-NEXT:    [[LEFT:%.*]] = tuple_extract [[RESULT]]
+// CHECK-NEXT:    [[RIGHT:%.*]] = tuple_extract [[RESULT]]
+// CHECK-NEXT:    store [[LEFT:%.*]] to [trivial] [[LEFT_ADDR]]
+// CHECK-NEXT:    store [[RIGHT:%.*]] to [trivial] [[RIGHT_ADDR]]
+// CHECK-NEXT:    tuple ()
+// CHECK-NEXT:    return
+
+// CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] @$SS2iIegdd_ypSgIegr_TR : $@convention(thin) (@guaranteed @callee_guaranteed () -> (Int, Int)) -> @out Optional<Any> {
+// CHECK:         [[OPTIONAL_PAYLOAD:%.*]] = init_enum_data_addr %0
+// CHECK-NEXT:    [[ANY_PAYLOAD:%.*]] = init_existential_addr [[OPTIONAL_PAYLOAD]]
+// CHECK-NEXT:    [[LEFT_ADDR:%.*]] = tuple_element_addr [[ANY_PAYLOAD]]
+// CHECK-NEXT:    [[RIGHT_ADDR:%.*]] = tuple_element_addr [[ANY_PAYLOAD]]
+// CHECK-NEXT:    [[RESULT:%.*]] = apply %1()
+// CHECK-NEXT:    [[LEFT:%.*]] = tuple_extract [[RESULT]]
+// CHECK-NEXT:    [[RIGHT:%.*]] = tuple_extract [[RESULT]]
+// CHECK-NEXT:    store [[LEFT:%.*]] to [trivial] [[LEFT_ADDR]]
+// CHECK-NEXT:    store [[RIGHT:%.*]] to [trivial] [[RIGHT_ADDR]]
+// CHECK-NEXT:    inject_enum_addr %0
+// CHECK-NEXT:    tuple ()
+// CHECK-NEXT:    return
+
+// CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] @$SypIegn_S2iIegyy_TR : $@convention(thin) (Int, Int, @guaranteed @callee_guaranteed (@in_guaranteed Any) -> ()) -> ()
+// CHECK:         [[ANY_VALUE:%.*]] = alloc_stack $Any
+// CHECK-NEXT:    [[ANY_PAYLOAD:%.*]] = init_existential_addr [[ANY_VALUE]]
+// CHECK-NEXT:    [[LEFT_ADDR:%.*]] = tuple_element_addr [[ANY_PAYLOAD]]
+// CHECK-NEXT:    store %0 to [trivial] [[LEFT_ADDR]]
+// CHECK-NEXT:    [[RIGHT_ADDR:%.*]] = tuple_element_addr [[ANY_PAYLOAD]]
+// CHECK-NEXT:    store %1 to [trivial] [[RIGHT_ADDR]]
+// CHECK-NEXT:    apply %2([[ANY_VALUE]])
+// CHECK-NEXT:    tuple ()
+// CHECK-NEXT:    destroy_addr [[ANY_VALUE]]
+// CHECK-NEXT:    dealloc_stack [[ANY_VALUE]]
+// CHECK-NEXT:    return
+
+// CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] @$SypSgIegn_S2iIegyy_TR : $@convention(thin) (Int, Int, @guaranteed @callee_guaranteed (@in_guaranteed Optional<Any>) -> ()) -> ()
+// CHECK:         [[ANY_VALUE:%.*]] = alloc_stack $Any
+// CHECK-NEXT:    [[ANY_PAYLOAD:%.*]] = init_existential_addr [[ANY_VALUE]]
+// CHECK-NEXT:    [[LEFT_ADDR:%.*]] = tuple_element_addr [[ANY_PAYLOAD]]
+// CHECK-NEXT:    store %0 to [trivial] [[LEFT_ADDR]]
+// CHECK-NEXT:    [[RIGHT_ADDR:%.*]] = tuple_element_addr [[ANY_PAYLOAD]]
+// CHECK-NEXT:    store %1 to [trivial] [[RIGHT_ADDR]]
+// CHECK-NEXT:    [[OPTIONAL_VALUE:%.*]] = alloc_stack $Optional<Any>
+// CHECK-NEXT:    [[OPTIONAL_PAYLOAD:%.*]] = init_enum_data_addr [[OPTIONAL_VALUE]]
+// CHECK-NEXT:    copy_addr [take] [[ANY_VALUE]] to [initialization] [[OPTIONAL_PAYLOAD]]
+// CHECK-NEXT:    inject_enum_addr [[OPTIONAL_VALUE]]
+// CHECK-NEXT:    apply %2([[OPTIONAL_VALUE]])
+// CHECK-NEXT:    tuple ()
+// CHECK-NEXT:    destroy_addr [[OPTIONAL_VALUE]]
+// CHECK-NEXT:    dealloc_stack [[OPTIONAL_VALUE]]
+// CHECK-NEXT:    dealloc_stack [[ANY_VALUE]]
+// CHECK-NEXT:    return
+
+// ==== Support collection subtyping in function argument position
+
+protocol Z {}
+class A: Z {}
+
+func foo_arr<T: Z>(type: T.Type, _ fn: ([T]?) -> Void) {}
+func foo_map<T: Z>(type: T.Type, _ fn: ([Int: T]) -> Void) {}
+
+func rdar35702810() {
+  let fn_arr: ([Z]?) -> Void = { _ in }
+  let fn_map: ([Int: Z]) -> Void = { _ in }
+
+  // CHECK: function_ref @$Ss15_arrayForceCastySayq_GSayxGr0_lF : $@convention(thin) <τ_0_0, τ_0_1> (@guaranteed Array<τ_0_0>) -> @owned Array<τ_0_1>
+  // CHECK: apply %5<A, Z>(%6) : $@convention(thin) <τ_0_0, τ_0_1> (@guaranteed Array<τ_0_0>) -> @owned Array<τ_0_1>
+  foo_arr(type: A.self, fn_arr)
+
+  // CHECK: function_ref @$Ss17_dictionaryUpCastys10DictionaryVyq0_q1_GACyxq_Gs8HashableRzsAFR0_r2_lF : $@convention(thin) <τ_0_0, τ_0_1, τ_0_2, τ_0_3 where τ_0_0 : Hashable, τ_0_2 : Hashable> (@guaranteed Dictionary<τ_0_0, τ_0_1>) -> @owned Dictionary<τ_0_2, τ_0_3>
+  // CHECK: apply %2<Int, A, Int, Z>(%0) : $@convention(thin) <τ_0_0, τ_0_1, τ_0_2, τ_0_3 where τ_0_0 : Hashable, τ_0_2 : Hashable> (@guaranteed Dictionary<τ_0_0, τ_0_1>) -> @owned Dictionary<τ_0_2, τ_0_3>
+  // CHECK: apply %1(%4) : $@callee_guaranteed (@guaranteed Dictionary<Int, Z>) -> ()
+  foo_map(type: A.self, fn_map)
+}
+
+protocol X: Hashable {}
+class B: X {
+  var hashValue: Int { return 42 }
+  static func == (lhs: B, rhs: B) -> Bool {
+    return lhs.hashValue == rhs.hashValue
+  }
+}
+
+func bar_arr<T: X>(type: T.Type, _ fn: ([T]?) -> Void) {}
+func bar_map<T: X>(type: T.Type, _ fn: ([T: Int]) -> Void) {}
+func bar_set<T: X>(type: T.Type, _ fn: (Set<T>) -> Void) {}
+
+func rdar35702810_anyhashable() {
+  let fn_arr: ([AnyHashable]?) -> Void = { _ in }
+  let fn_map: ([AnyHashable: Int]) -> Void = { _ in }
+  let fn_set: (Set<AnyHashable>) -> Void = { _ in }
+
+
+  // CHECK: [[FN:%.*]] = function_ref @$SSays11AnyHashableVGSgIegg_Say19function_conversion1BCGSgIegg_TR : $@convention(thin) (@guaranteed Optional<Array<B>>, @guaranteed @callee_guaranteed (@guaranteed Optional<Array<AnyHashable>>) -> ()) -> ()
+  // CHECK: [[PA:%.*]] = partial_apply [callee_guaranteed] [[FN]](%{{[0-9]+}}) : $@convention(thin) (@guaranteed Optional<Array<B>>, @guaranteed @callee_guaranteed (@guaranteed Optional<Array<AnyHashable>>) -> ()) -> ()
+  // CHECK: convert_escape_to_noescape [[PA]] : $@callee_guaranteed (@guaranteed Optional<Array<B>>) -> () to $@noescape @callee_guaranteed (@guaranteed Optional<Array<B>>) -> ()
+  bar_arr(type: B.self, fn_arr)
+
+  // CHECK: [[FN:%.*]] = function_ref @$Ss10DictionaryVys11AnyHashableVSiGIegg_ABy19function_conversion1BCSiGIegg_TR : $@convention(thin) (@guaranteed Dictionary<B, Int>, @guaranteed @callee_guaranteed (@guaranteed Dictionary<AnyHashable, Int>) -> ()) -> ()
+  // CHECK: [[PA:%.*]] = partial_apply [callee_guaranteed] [[FN]](%{{[0-9]+}}) : $@convention(thin) (@guaranteed Dictionary<B, Int>, @guaranteed @callee_guaranteed (@guaranteed Dictionary<AnyHashable, Int>) -> ()) -> ()
+  // CHECK: convert_escape_to_noescape [[PA]] : $@callee_guaranteed (@guaranteed Dictionary<B, Int>) -> () to $@noescape @callee_guaranteed (@guaranteed Dictionary<B, Int>) -> ()
+  bar_map(type: B.self, fn_map)
+
+  // CHECK: [[FN:%.*]] = function_ref @$Ss3SetVys11AnyHashableVGIegg_ABy19function_conversion1BCGIegg_TR : $@convention(thin) (@guaranteed Set<B>, @guaranteed @callee_guaranteed (@guaranteed Set<AnyHashable>) -> ()) -> ()
+  // CHECK: [[PA:%.*]] = partial_apply [callee_guaranteed] [[FN]](%{{[0-9]+}}) : $@convention(thin) (@guaranteed Set<B>, @guaranteed @callee_guaranteed (@guaranteed Set<AnyHashable>) -> ()) -> ()
+  // CHECK: convert_escape_to_noescape [[PA]] : $@callee_guaranteed (@guaranteed Set<B>) -> () to $@noescape @callee_guaranteed (@guaranteed Set<B>) -> ()
+  bar_set(type: B.self, fn_set)
+}
diff --git a/test/SILGen/plus_zero_function_conversion_objc.swift b/test/SILGen/plus_zero_function_conversion_objc.swift
new file mode 100644
index 0000000..3314382
--- /dev/null
+++ b/test/SILGen/plus_zero_function_conversion_objc.swift
@@ -0,0 +1,118 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -sdk %S/Inputs %s -I %S/Inputs -enable-sil-ownership -enable-source-import -emit-silgen -verify | %FileCheck %s
+
+import Foundation
+
+// REQUIRES: objc_interop
+
+// ==== Metatype to object conversions
+
+// CHECK-LABEL: sil hidden @$S24function_conversion_objc20convMetatypeToObjectyySo8NSObjectCmADcF
+func convMetatypeToObject(_ f: @escaping (NSObject) -> NSObject.Type) {
+// CHECK:         function_ref @$SSo8NSObjectCABXMTIeggd_AByXlIeggo_TR
+// CHECK:         partial_apply
+  let _: (NSObject) -> AnyObject = f
+}
+
+// CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] @$SSo8NSObjectCABXMTIeggd_AByXlIeggo_TR : $@convention(thin) (@guaranteed NSObject, @guaranteed @callee_guaranteed (@guaranteed NSObject) -> @thick NSObject.Type) -> @owned AnyObject {
+// CHECK:         apply %1(%0)
+// CHECK:         thick_to_objc_metatype {{.*}} : $@thick NSObject.Type to $@objc_metatype NSObject.Type
+// CHECK:         objc_metatype_to_object {{.*}} : $@objc_metatype NSObject.Type to $AnyObject
+// CHECK:         return
+
+@objc protocol NSBurrito {}
+
+// CHECK-LABEL: sil hidden @$S24function_conversion_objc31convExistentialMetatypeToObjectyyAA9NSBurrito_pXpAaC_pcF
+func convExistentialMetatypeToObject(_ f: @escaping (NSBurrito) -> NSBurrito.Type) {
+// CHECK:         function_ref @$S24function_conversion_objc9NSBurrito_pAaB_pXmTIeggd_AaB_pyXlIeggo_TR
+// CHECK:         partial_apply
+  let _: (NSBurrito) -> AnyObject = f
+}
+
+// CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] @$S24function_conversion_objc9NSBurrito_pAaB_pXmTIeggd_AaB_pyXlIeggo_TR : $@convention(thin) (@guaranteed NSBurrito, @guaranteed @callee_guaranteed (@guaranteed NSBurrito) -> @thick NSBurrito.Type) -> @owned AnyObject
+// CHECK:         apply %1(%0)
+// CHECK:         thick_to_objc_metatype {{.*}} : $@thick NSBurrito.Type to $@objc_metatype NSBurrito.Type
+// CHECK:         objc_existential_metatype_to_object {{.*}} : $@objc_metatype NSBurrito.Type to $AnyObject
+// CHECK:         return
+
+// CHECK-LABEL: sil hidden @$S24function_conversion_objc28convProtocolMetatypeToObjectyyAA9NSBurrito_pmycF
+func convProtocolMetatypeToObject(_ f: @escaping () -> NSBurrito.Protocol) {
+// CHECK:         function_ref @$S24function_conversion_objc9NSBurrito_pXMtIegd_So8ProtocolCIego_TR
+// CHECK:         partial_apply
+  let _: () -> Protocol = f
+}
+
+// CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] @$S24function_conversion_objc9NSBurrito_pXMtIegd_So8ProtocolCIego_TR : $@convention(thin) (@guaranteed @callee_guaranteed () -> @thin NSBurrito.Protocol) -> @owned Protocol
+// CHECK:         apply %0() : $@callee_guaranteed () -> @thin NSBurrito.Protocol
+// CHECK:         objc_protocol #NSBurrito : $Protocol
+// CHECK:         copy_value
+// CHECK:         return
+
+// ==== Representation conversions
+
+// CHECK-LABEL: sil hidden @$S24function_conversion_objc11funcToBlockyyyXByycF : $@convention(thin) (@guaranteed @callee_guaranteed () -> ()) -> @owned @convention(block) () -> ()
+// CHECK:         [[BLOCK_STORAGE:%.*]] = alloc_stack $@block_storage
+// CHECK:         [[BLOCK:%.*]] = init_block_storage_header [[BLOCK_STORAGE]]
+// CHECK:         [[COPY:%.*]] = copy_block [[BLOCK]] : $@convention(block) () -> ()
+// CHECK:         return [[COPY]]
+func funcToBlock(_ x: @escaping () -> ()) -> @convention(block) () -> () {
+  return x
+}
+
+// CHECK-LABEL: sil hidden @$S24function_conversion_objc11blockToFuncyyycyyXBF : $@convention(thin) (@guaranteed @convention(block) () -> ()) -> @owned @callee_guaranteed () -> ()
+// CHECK: bb0([[ARG:%.*]] : @guaranteed $@convention(block) () -> ()):
+// CHECK:   [[COPIED:%.*]] = copy_block [[ARG]]
+// CHECK:   [[BORROWED_COPIED:%.*]] = begin_borrow [[COPIED]]
+// CHECK:   [[COPIED_2:%.*]] = copy_value [[BORROWED_COPIED]]
+// CHECK:   [[THUNK:%.*]] = function_ref @$SIeyB_Ieg_TR
+// CHECK:   [[FUNC:%.*]] = partial_apply [callee_guaranteed] [[THUNK]]([[COPIED_2]])
+// CHECK:   end_borrow [[BORROWED_COPIED]] from [[COPIED]]
+// CHECK:   destroy_value [[COPIED]]
+// CHECK-NOT:   destroy_value [[ARG]]
+// CHECK:   return [[FUNC]]
+func blockToFunc(_ x: @escaping @convention(block) () -> ()) -> () -> () {
+  return x
+}
+
+// ==== Representation change + function type conversion
+
+// CHECK-LABEL: sil hidden @$S24function_conversion_objc22blockToFuncExistentialyypycSiyXBF : $@convention(thin) (@guaranteed @convention(block) () -> Int) -> @owned @callee_guaranteed () -> @out Any
+// CHECK:         function_ref @$SSiIeyBd_SiIegd_TR
+// CHECK:         partial_apply
+// CHECK:         function_ref @$SSiIegd_ypIegr_TR
+// CHECK:         partial_apply
+// CHECK:         return
+func blockToFuncExistential(_ x: @escaping @convention(block) () -> Int) -> () -> Any {
+  return x
+}
+
+// CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] @$SSiIeyBd_SiIegd_TR : $@convention(thin) (@guaranteed @convention(block) () -> Int) -> Int
+
+// CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] @$SSiIegd_ypIegr_TR : $@convention(thin) (@guaranteed @callee_guaranteed () -> Int) -> @out Any
+
+// C function pointer conversions
+
+class A : NSObject {}
+class B : A {}
+
+// CHECK-LABEL: sil hidden @$S24function_conversion_objc18cFuncPtrConversionyyAA1BCXCyAA1ACXCF
+func cFuncPtrConversion(_ x: @escaping @convention(c) (A) -> ()) -> @convention(c) (B) -> () {
+// CHECK:         convert_function %0 : $@convention(c) (A) -> () to $@convention(c) (B) -> ()
+// CHECK:         return
+  return x
+}
+
+func cFuncPtr(_ a: A) {}
+
+// CHECK-LABEL: sil hidden @$S24function_conversion_objc19cFuncDeclConversionyAA1BCXCyF
+func cFuncDeclConversion() -> @convention(c) (B) -> () {
+// CHECK:         function_ref @$S24function_conversion_objc8cFuncPtryyAA1ACFTo : $@convention(c) (A) -> ()
+// CHECK:         convert_function %0 : $@convention(c) (A) -> () to $@convention(c) (B) -> ()
+// CHECK:         return
+  return cFuncPtr
+}
+
+func cFuncPtrConversionUnsupported(_ x: @escaping @convention(c) (@convention(block) () -> ()) -> ())
+    -> @convention(c) (@convention(c) () -> ()) -> () {
+  return x  // expected-error{{C function pointer signature '@convention(c) (@convention(block) () -> ()) -> ()' is not compatible with expected type '@convention(c) (@convention(c) () -> ()) -> ()'}}
+}
diff --git a/test/SILGen/plus_zero_functions.swift b/test/SILGen/plus_zero_functions.swift
new file mode 100644
index 0000000..e43048d
--- /dev/null
+++ b/test/SILGen/plus_zero_functions.swift
@@ -0,0 +1,592 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -Xllvm -sil-full-demangle -parse-stdlib -parse-as-library -emit-silgen -enable-sil-ownership %s | %FileCheck %s
+
+import Swift // just for Optional
+
+func markUsed<T>(_ t: T) {}
+
+typealias Int = Builtin.Int64
+typealias Int64 = Builtin.Int64
+typealias Bool = Builtin.Int1
+
+var zero = getInt()
+func getInt() -> Int { return zero }
+
+func standalone_function(_ x: Int, _ y: Int) -> Int {
+  return x
+}
+
+func higher_order_function(_ f: (_ x: Int, _ y: Int) -> Int, _ x: Int, _ y: Int) -> Int {
+  return f(x, y)
+}
+
+func higher_order_function2(_ f: (Int, Int) -> Int, _ x: Int, _ y: Int) -> Int {
+  return f(x, y)
+}
+
+struct SomeStruct {
+  // -- Constructors and methods are uncurried in 'self'
+  // -- Instance methods use 'method' cc
+
+  init(x:Int, y:Int) {}
+
+  mutating
+  func method(_ x: Int) {}
+
+  static func static_method(_ x: Int) {}
+
+  func generic_method<T>(_ x: T) {}
+}
+
+class SomeClass {
+  // -- Constructors and methods are uncurried in 'self'
+  // -- Instance methods use 'method' cc
+
+  // CHECK-LABEL: sil hidden @$S9functions9SomeClassC{{[_0-9a-zA-Z]*}}fC : $@convention(method) (Builtin.Int64, Builtin.Int64, @thick SomeClass.Type) -> @owned SomeClass
+  // CHECK: bb0(%0 : @trivial $Builtin.Int64, %1 : @trivial $Builtin.Int64, %2 : @trivial $@thick SomeClass.Type):
+
+  // CHECK-LABEL: sil hidden @$S9functions9SomeClassC{{[_0-9a-zA-Z]*}}fc : $@convention(method) (Builtin.Int64, Builtin.Int64, @owned SomeClass) -> @owned SomeClass
+  // CHECK: bb0(%0 : @trivial $Builtin.Int64, %1 : @trivial $Builtin.Int64, %2 : @owned $SomeClass):
+  init(x:Int, y:Int) {}
+
+  // CHECK-LABEL: sil hidden @$S9functions9SomeClassC6method{{[_0-9a-zA-Z]*}}F : $@convention(method) (Builtin.Int64, @guaranteed SomeClass) -> () 
+  // CHECK: bb0(%0 : @trivial $Builtin.Int64, %1 : @guaranteed $SomeClass):
+  func method(_ x: Int) {}
+
+  // CHECK-LABEL: sil hidden @$S9functions9SomeClassC13static_method{{[_0-9a-zA-Z]*}}FZ : $@convention(method) (Builtin.Int64, @thick SomeClass.Type) -> ()
+  // CHECK: bb0(%0 : @trivial $Builtin.Int64, %1 : @trivial $@thick SomeClass.Type):
+  class func static_method(_ x: Int) {}
+
+  var someProperty: Int {
+    get {
+      return zero
+    }
+    set {}
+  }
+
+  subscript(x:Int, y:Int) -> Int {
+    get {
+      return zero
+    }
+    set {}
+  }
+
+  func generic<T>(_ x: T) -> T {
+    return x
+  }
+}
+
+func SomeClassWithBenefits() -> SomeClass.Type {
+  return SomeClass.self
+}
+
+protocol SomeProtocol {
+  func method(_ x: Int)
+  static func static_method(_ x: Int)
+}
+
+struct ConformsToSomeProtocol : SomeProtocol {
+  func method(_ x: Int) { }
+  static func static_method(_ x: Int) { }
+}
+
+class SomeGeneric<T> {
+  init() { }
+  func method(_ x: T) -> T { return x }
+
+  func generic<U>(_ x: U) -> U { return x }
+}
+
+// CHECK-LABEL: sil hidden @$S9functions5calls{{[_0-9a-zA-Z]*}}F : $@convention(thin) (Builtin.Int64, Builtin.Int64, Builtin.Int64) -> ()
+func calls(_ i:Int, j:Int, k:Int) {
+  var i = i
+  var j = j
+  var k = k
+  // CHECK: bb0(%0 : @trivial $Builtin.Int64, %1 : @trivial $Builtin.Int64, %2 : @trivial $Builtin.Int64):
+  // CHECK: [[IBOX:%[0-9]+]] = alloc_box ${ var Builtin.Int64 }
+  // CHECK: [[IADDR:%.*]] = project_box [[IBOX]]
+  // CHECK: [[JBOX:%[0-9]+]] = alloc_box ${ var Builtin.Int64 }
+  // CHECK: [[JADDR:%.*]] = project_box [[JBOX]]
+  // CHECK: [[KBOX:%[0-9]+]] = alloc_box ${ var Builtin.Int64 }
+  // CHECK: [[KADDR:%.*]] = project_box [[KBOX]]
+
+  // CHECK: [[READI:%.*]] = begin_access [read] [unknown] [[IADDR]]
+  // CHECK: [[I:%[0-9]+]] = load [trivial] [[READI]]
+  // CHECK: [[READJ:%.*]] = begin_access [read] [unknown] [[JADDR]]
+  // CHECK: [[J:%[0-9]+]] = load [trivial] [[READJ]]
+  // CHECK: [[FUNC:%[0-9]+]] = function_ref @$S9functions19standalone_function{{[_0-9a-zA-Z]*}}F : $@convention(thin) (Builtin.Int64, Builtin.Int64) -> Builtin.Int64
+  // CHECK: apply [[FUNC]]([[I]], [[J]])
+  standalone_function(i, j)
+
+  // -- Curry 'self' onto struct method argument lists.
+
+  // CHECK: [[ST_ADDR:%.*]] = alloc_box ${ var SomeStruct }
+  // CHECK: [[METATYPE:%.*]] = metatype $@thin SomeStruct.Type
+  // CHECK: [[READI:%.*]] = begin_access [read] [unknown] [[IADDR]]
+  // CHECK: [[I:%.*]] = load [trivial] [[READI]]
+  // CHECK: [[READJ:%.*]] = begin_access [read] [unknown] [[JADDR]]
+  // CHECK: [[J:%.*]] = load [trivial] [[READJ]]
+  // CHECK: [[CTOR:%.*]] = function_ref @$S9functions10SomeStructV{{[_0-9a-zA-Z]*}}fC : $@convention(method) (Builtin.Int64, Builtin.Int64, @thin SomeStruct.Type) -> SomeStruct
+  // CHECK: apply [[CTOR]]([[I]], [[J]], [[METATYPE]]) : $@convention(method) (Builtin.Int64, Builtin.Int64, @thin SomeStruct.Type) -> SomeStruct
+  var st = SomeStruct(x: i, y: j)
+
+  // -- Use of unapplied struct methods as values.
+
+  // CHECK: [[THUNK:%.*]] = function_ref @$S9functions10SomeStructV6method{{[_0-9a-zA-Z]*}}F
+  // CHECK: [[THUNK_THICK:%.*]] = thin_to_thick_function [[THUNK]]
+  var stm1 = SomeStruct.method
+  stm1(&st)(i)
+
+  // -- Curry 'self' onto method argument lists dispatched using class_method.
+
+  // CHECK: [[CBOX:%[0-9]+]] = alloc_box ${ var SomeClass }
+  // CHECK: [[CADDR:%.*]] = project_box [[CBOX]]
+  // CHECK: [[META:%[0-9]+]] = metatype $@thick SomeClass.Type
+  // CHECK: [[READI:%.*]] = begin_access [read] [unknown] [[IADDR]]
+  // CHECK: [[I:%[0-9]+]] = load [trivial] [[READI]]
+  // CHECK: [[READJ:%.*]] = begin_access [read] [unknown] [[JADDR]]
+  // CHECK: [[J:%[0-9]+]] = load [trivial] [[READJ]]
+  // CHECK: [[FUNC:%[0-9]+]] = function_ref @$S9functions9SomeClassC{{[_0-9a-zA-Z]*}}fC : $@convention(method) (Builtin.Int64, Builtin.Int64, @thick SomeClass.Type) -> @owned SomeClass
+  // CHECK: [[C:%[0-9]+]] = apply [[FUNC]]([[I]], [[J]], [[META]])
+  var c = SomeClass(x: i, y: j)
+
+  // CHECK: [[READC:%.*]] = begin_access [read] [unknown] [[CADDR]]
+  // CHECK: [[C:%[0-9]+]] = load [copy] [[READC]]
+  // CHECK: [[BORROWED_C:%.*]] = begin_borrow [[C]]
+  // CHECK: [[READI:%.*]] = begin_access [read] [unknown] [[IADDR]]
+  // CHECK: [[I:%[0-9]+]] = load [trivial] [[READI]]
+  // CHECK: [[METHOD:%[0-9]+]] = class_method [[BORROWED_C]] : {{.*}}, #SomeClass.method!1
+  // CHECK: apply [[METHOD]]([[I]], [[BORROWED_C]])
+  // CHECK: end_borrow [[BORROWED_C]] from [[C]]
+  // CHECK: destroy_value [[C]]
+  c.method(i)
+
+  // -- Curry 'self' onto unapplied methods dispatched using class_method.
+  // CHECK: [[METHOD_CURRY_THUNK:%.*]] = function_ref @$S9functions9SomeClassC6method{{[_0-9a-zA-Z]*}}F
+  // CHECK: apply [[METHOD_CURRY_THUNK]]
+  var cm1 = SomeClass.method(c)
+  cm1(i)
+
+  // CHECK: [[READC:%.*]] = begin_access [read] [unknown] [[CADDR]]
+  // CHECK: [[C:%[0-9]+]] = load [copy] [[READC]]
+  // CHECK: [[BORROWED_C:%.*]] = begin_borrow [[C]]
+  // CHECK: [[READI:%.*]] = begin_access [read] [unknown] [[IADDR]]
+  // CHECK: [[I:%[0-9]+]] = load [trivial] [[READI]]
+  // CHECK: [[METHOD:%[0-9]+]] = class_method [[BORROWED_C]] : {{.*}}, #SomeClass.method!1
+  // CHECK: apply [[METHOD]]([[I]], [[BORROWED_C]])
+  // CHECK: end_borrow [[BORROWED_C]] from [[C]]
+  // CHECK: destroy_value [[C]]
+  SomeClass.method(c)(i)
+
+  // -- Curry the Type onto static method argument lists.
+  
+  // CHECK: [[READC:%.*]] = begin_access [read] [unknown] [[CADDR]]
+  // CHECK: [[C:%[0-9]+]] = load [copy] [[READC]]
+  // CHECK: [[META:%.*]] = value_metatype $@thick SomeClass.Type, [[C]]
+  // CHECK: [[READI:%.*]] = begin_access [read] [unknown] [[IADDR]]
+  // CHECK: [[I:%[0-9]+]] = load [trivial] [[READI]]
+  // CHECK: [[METHOD:%[0-9]+]] = class_method [[META]] : {{.*}}, #SomeClass.static_method!1
+  // CHECK: apply [[METHOD]]([[I]], [[META]])
+  type(of: c).static_method(i)
+
+  // -- Curry property accesses.
+
+  // -- FIXME: class_method-ify class getters.
+  // CHECK: [[READC:%.*]] = begin_access [read] [unknown] [[CADDR]]
+  // CHECK: [[C:%[0-9]+]] = load [copy] [[READC]]
+  // CHECK: [[BORROWED_C:%.*]] = begin_borrow [[C]]
+  // CHECK: [[GETTER:%[0-9]+]] = class_method {{.*}} : $SomeClass, #SomeClass.someProperty!getter.1
+  // CHECK: apply [[GETTER]]([[BORROWED_C]])
+  // CHECK: end_borrow [[BORROWED_C]] from [[C]]
+  // CHECK: destroy_value [[C]]
+  i = c.someProperty
+
+  // CHECK: [[READC:%.*]] = begin_access [read] [unknown] [[CADDR]]
+  // CHECK: [[C:%[0-9]+]] = load [copy] [[READC]]
+  // CHECK: [[READI:%.*]] = begin_access [read] [unknown] [[IADDR]]
+  // CHECK: [[I:%[0-9]+]] = load [trivial] [[READI]]
+  // CHECK: [[BORROWED_C:%.*]] = begin_borrow [[C]]
+  // CHECK: [[SETTER:%[0-9]+]] = class_method [[BORROWED_C]] : $SomeClass, #SomeClass.someProperty!setter.1 : (SomeClass) -> (Builtin.Int64) -> ()
+  // CHECK: apply [[SETTER]]([[I]], [[BORROWED_C]])
+  // CHECK: end_borrow [[BORROWED_C]] from [[C]]
+  // CHECK: destroy_value [[C]]
+  c.someProperty = i
+
+  // CHECK: [[READC:%.*]] = begin_access [read] [unknown] [[CADDR]]
+  // CHECK: [[C:%[0-9]+]] = load [copy] [[READC]]
+  // CHECK: [[READJ:%.*]] = begin_access [read] [unknown] [[JADDR]]
+  // CHECK: [[J:%[0-9]+]] = load [trivial] [[READJ]]
+  // CHECK: [[READK:%.*]] = begin_access [read] [unknown] [[KADDR]]
+  // CHECK: [[K:%[0-9]+]] = load [trivial] [[READK]]
+  // CHECK: [[BORROWED_C:%.*]] = begin_borrow [[C]]
+  // CHECK: [[GETTER:%[0-9]+]] = class_method [[BORROWED_C]] : $SomeClass, #SomeClass.subscript!getter.1 : (SomeClass) -> (Builtin.Int64, Builtin.Int64) -> Builtin.Int64, $@convention(method) (Builtin.Int64, Builtin.Int64, @guaranteed SomeClass) -> Builtin.Int64
+  // CHECK: apply [[GETTER]]([[J]], [[K]], [[BORROWED_C]])
+  // CHECK: end_borrow [[BORROWED_C]] from [[C]]
+  // CHECK: destroy_value [[C]]
+  i = c[j, k]
+
+  // CHECK: [[READC:%.*]] = begin_access [read] [unknown] [[CADDR]]
+  // CHECK: [[C:%[0-9]+]] = load [copy] [[READC]]
+  // CHECK: [[READI:%.*]] = begin_access [read] [unknown] [[IADDR]]
+  // CHECK: [[I:%[0-9]+]] = load [trivial] [[READI]]
+  // CHECK: [[READJ:%.*]] = begin_access [read] [unknown] [[JADDR]]
+  // CHECK: [[J:%[0-9]+]] = load [trivial] [[READJ]]
+  // CHECK: [[READK:%.*]] = begin_access [read] [unknown] [[KADDR]]
+  // CHECK: [[K:%[0-9]+]] = load [trivial] [[READK]]
+  // CHECK: [[BORROWED_C:%.*]] = begin_borrow [[C]]
+  // CHECK: [[SETTER:%[0-9]+]] = class_method [[BORROWED_C]] : $SomeClass, #SomeClass.subscript!setter.1 : (SomeClass) -> (Builtin.Int64, Builtin.Int64, Builtin.Int64) -> (), $@convention(method) (Builtin.Int64, Builtin.Int64, Builtin.Int64, @guaranteed SomeClass) -> ()
+  // CHECK: apply [[SETTER]]([[K]], [[I]], [[J]], [[BORROWED_C]])
+  // CHECK: end_borrow [[BORROWED_C]] from [[C]]
+  // CHECK: destroy_value [[C]]
+  c[i, j] = k
+
+  // -- Curry the projected concrete value in an existential (or its Type)
+  // -- onto protocol type methods dispatched using protocol_method.
+
+  // CHECK: [[PBOX:%[0-9]+]] = alloc_box ${ var SomeProtocol }
+  // CHECK: [[PADDR:%.*]] = project_box [[PBOX]]
+  var p : SomeProtocol = ConformsToSomeProtocol()
+
+  // CHECK: [[READ:%.*]] = begin_access [read] [unknown] [[PADDR]]
+  // CHECK: [[TEMP:%.*]] = alloc_stack $SomeProtocol
+  // CHECK: copy_addr [[READ]] to [initialization] [[TEMP]]
+  // CHECK: [[PVALUE:%[0-9]+]] = open_existential_addr immutable_access [[TEMP]] : $*SomeProtocol to $*[[OPENED:@opened(.*) SomeProtocol]]
+  // CHECK: [[READI:%.*]] = begin_access [read] [unknown] [[IADDR]]
+  // CHECK: [[I:%[0-9]+]] = load [trivial] [[READI]]
+  // CHECK: [[PMETHOD:%[0-9]+]] = witness_method $[[OPENED]], #SomeProtocol.method!1
+  // CHECK: apply [[PMETHOD]]<[[OPENED]]>([[I]], [[PVALUE]])
+  // CHECK: destroy_addr [[TEMP]]
+  // CHECK: dealloc_stack [[TEMP]]
+  p.method(i)
+
+  // CHECK: [[PVALUE:%[0-9]+]] = open_existential_addr immutable_access [[PADDR:%.*]] : $*SomeProtocol to $*[[OPENED:@opened(.*) SomeProtocol]]
+  // CHECK: [[READI:%.*]] = begin_access [read] [unknown] [[IADDR]]
+  // CHECK: [[I:%[0-9]+]] = load [trivial] [[READI]]
+  // CHECK: [[PMETHOD:%[0-9]+]] = witness_method $[[OPENED]], #SomeProtocol.method!1
+  // CHECK: apply [[PMETHOD]]<[[OPENED]]>([[I]], [[PVALUE]])
+  var sp : SomeProtocol = ConformsToSomeProtocol()
+  sp.method(i)
+
+  // FIXME: [[PMETHOD:%[0-9]+]] = witness_method $[[OPENED:@opened(.*) SomeProtocol]], #SomeProtocol.static_method!1
+  // FIXME: [[I:%[0-9]+]] = load [trivial] [[IADDR]]
+  // FIXME: apply [[PMETHOD]]([[I]], [[PMETA]])
+  // Needs existential metatypes
+  //type(of: p).static_method(i)
+
+  // -- Use an apply or partial_apply instruction to bind type parameters of a generic.
+
+  // CHECK: [[GBOX:%[0-9]+]] = alloc_box ${ var SomeGeneric<Builtin.Int64> }
+  // CHECK: [[GADDR:%.*]] = project_box [[GBOX]]
+  // CHECK: [[META:%[0-9]+]] = metatype $@thick SomeGeneric<Builtin.Int64>.Type
+  // CHECK: [[CTOR_GEN:%[0-9]+]] = function_ref @$S9functions11SomeGenericC{{[_0-9a-zA-Z]*}}fC : $@convention(method) <τ_0_0> (@thick SomeGeneric<τ_0_0>.Type) -> @owned SomeGeneric<τ_0_0>
+  // CHECK: apply [[CTOR_GEN]]<Builtin.Int64>([[META]])
+  var g = SomeGeneric<Builtin.Int64>()
+
+  // CHECK: [[TMPR:%.*]] = alloc_stack $Builtin.Int64
+  // CHECK: [[READG:%.*]] = begin_access [read] [unknown] [[GADDR]]
+  // CHECK: [[G:%[0-9]+]] = load [copy] [[READG]]
+  // CHECK: [[BORROWED_G:%.*]] = begin_borrow [[G]]
+  // CHECK: [[TMPI:%.*]] = alloc_stack $Builtin.Int64
+  // CHECK: [[METHOD_GEN:%[0-9]+]] = class_method [[BORROWED_G]] : {{.*}}, #SomeGeneric.method!1
+  // CHECK: apply [[METHOD_GEN]]<{{.*}}>([[TMPR]], [[TMPI]], [[BORROWED_G]])
+  // CHECK: end_borrow [[BORROWED_G]] from [[G]]
+  // CHECK: destroy_value [[G]]
+  g.method(i)
+
+  // CHECK: [[TMPR:%.*]] = alloc_stack $Builtin.Int64
+  // CHECK: [[READG:%.*]] = begin_access [read] [unknown] [[GADDR]]
+  // CHECK: [[G:%[0-9]+]] = load [copy] [[READG]]
+  // CHECK: [[BORROWED_G:%.*]] = begin_borrow [[G]]
+  // CHECK: [[TMPJ:%.*]] = alloc_stack $Builtin.Int64
+  // CHECK: [[METHOD_GEN:%[0-9]+]] = class_method [[BORROWED_G]] : {{.*}}, #SomeGeneric.generic!1
+  // CHECK: apply [[METHOD_GEN]]<{{.*}}>([[TMPR]], [[TMPJ]], [[BORROWED_G]])
+  // CHECK: end_borrow [[BORROWED_G]] from [[G]]
+  // CHECK: destroy_value [[G]]
+  g.generic(j)
+
+  // CHECK: [[TMPR:%.*]] = alloc_stack $Builtin.Int64
+  // CHECK: [[READC:%.*]] = begin_access [read] [unknown] [[CADDR]]
+  // CHECK: [[C:%[0-9]+]] = load [copy] [[READC]]
+  // CHECK: [[BORROWED_C:%.*]] = begin_borrow [[C]]
+  // CHECK: [[TMPK:%.*]] = alloc_stack $Builtin.Int64
+  // CHECK: [[METHOD_GEN:%[0-9]+]] = class_method [[BORROWED_C]] : {{.*}}, #SomeClass.generic!1
+  // CHECK: apply [[METHOD_GEN]]<{{.*}}>([[TMPR]], [[TMPK]], [[BORROWED_C]])
+  // CHECK: end_borrow [[BORROWED_C]] from [[C]]
+  // CHECK: destroy_value [[C]]
+  c.generic(k)
+
+  // FIXME: curried generic entry points
+  //var gm1 = g.method
+  //gm1(i)
+
+  //var gg1 : (Int) -> Int = g.generic
+  //gg1(j)
+
+  //var cg1 : (Int) -> Int = c.generic
+  //cg1(k)
+
+  // SIL-level "thin" function values need to be able to convert to
+  // "thick" function values when stored, returned, or passed as arguments.
+
+  // CHECK: [[FBOX:%[0-9]+]] = alloc_box ${ var @callee_guaranteed (Builtin.Int64, Builtin.Int64) -> Builtin.Int64 }
+  // CHECK: [[FADDR:%.*]] = project_box [[FBOX]]
+  // CHECK: [[FUNC_THIN:%[0-9]+]] = function_ref @$S9functions19standalone_function{{[_0-9a-zA-Z]*}}F : $@convention(thin) (Builtin.Int64, Builtin.Int64) -> Builtin.Int64
+  // CHECK: [[FUNC_THICK:%[0-9]+]] = thin_to_thick_function [[FUNC_THIN]]
+  // CHECK: store [[FUNC_THICK]] to [init] [[FADDR]]
+  var f = standalone_function
+  // CHECK: [[READF:%.*]] = begin_access [read] [unknown] [[FADDR]]
+  // CHECK: [[F:%[0-9]+]] = load [copy] [[READF]]
+  // CHECK: [[READI:%.*]] = begin_access [read] [unknown] [[IADDR]]
+  // CHECK: [[I:%[0-9]+]] = load [trivial] [[READI]]
+  // CHECK: [[READJ:%.*]] = begin_access [read] [unknown] [[JADDR]]
+  // CHECK: [[J:%[0-9]+]] = load [trivial] [[READJ]]
+  // CHECK: [[BORROW:%.*]] =  begin_borrow [[F]]
+  // CHECK: apply [[BORROW]]([[I]], [[J]])
+  // CHECK: end_borrow [[BORROW]]
+  // CHECK: destroy_value [[F]]
+  f(i, j)
+
+  // CHECK: [[FUNC_THIN:%[0-9]+]] = function_ref @$S9functions19standalone_function{{[_0-9a-zA-Z]*}}F : $@convention(thin) (Builtin.Int64, Builtin.Int64) -> Builtin.Int64
+  // CHECK: [[FUNC_THICK:%[0-9]+]] = thin_to_thick_function [[FUNC_THIN]]
+  // CHECK: [[CONVERT:%.*]] = convert_escape_to_noescape [[FUNC_THICK]]
+  // CHECK: [[READI:%.*]] = begin_access [read] [unknown] [[IADDR]]
+  // CHECK: [[I:%[0-9]+]] = load [trivial] [[READI]]
+  // CHECK: [[READJ:%.*]] = begin_access [read] [unknown] [[JADDR]]
+  // CHECK: [[J:%[0-9]+]] = load [trivial] [[READJ]]
+  // CHECK: [[HOF:%[0-9]+]] = function_ref @$S9functions21higher_order_function{{[_0-9a-zA-Z]*}}F : $@convention(thin) {{.*}}
+  // CHECK: apply [[HOF]]([[CONVERT]], [[I]], [[J]])
+  higher_order_function(standalone_function, i, j)
+
+  // CHECK: [[FUNC_THIN:%[0-9]+]] = function_ref @$S9functions19standalone_function{{[_0-9a-zA-Z]*}}F : $@convention(thin) (Builtin.Int64, Builtin.Int64) -> Builtin.Int64
+  // CHECK: [[FUNC_THICK:%.*]] = thin_to_thick_function [[FUNC_THIN]]
+  // CHECK: [[CONVERT:%.*]] = convert_escape_to_noescape [[FUNC_THICK]]
+  // CHECK: [[READI:%.*]] = begin_access [read] [unknown] [[IADDR]]
+  // CHECK: [[I:%[0-9]+]] = load [trivial] [[READI]]
+  // CHECK: [[READJ:%.*]] = begin_access [read] [unknown] [[JADDR]]
+  // CHECK: [[J:%[0-9]+]] = load [trivial] [[READJ]]
+  // CHECK: [[HOF2:%[0-9]+]] = function_ref @$S9functions22higher_order_function2{{[_0-9a-zA-Z]*}}F : $@convention(thin) {{.*}}
+  // CHECK: apply [[HOF2]]([[CONVERT]], [[I]], [[J]])
+  higher_order_function2(standalone_function, i, j)
+}
+
+// -- Curried entry points
+// CHECK-LABEL: sil shared [thunk] @$S9functions10SomeStructV6method{{[_0-9a-zA-Z]*}}FTc : $@convention(thin) (@inout SomeStruct) -> @owned @callee_guaranteed (Builtin.Int64) -> () {
+// CHECK:   [[UNCURRIED:%.*]] = function_ref @$S9functions10SomeStructV6method{{[_0-9a-zA-Z]*}}F : $@convention(method) (Builtin.Int64, @inout SomeStruct) -> (){{.*}} // user: %2
+// CHECK:   [[CURRIED:%.*]] = partial_apply [callee_guaranteed] [[UNCURRIED]]
+// CHECK:   return [[CURRIED]]
+
+// CHECK-LABEL: sil shared [thunk] @$S9functions9SomeClassC6method{{[_0-9a-zA-Z]*}}FTc : $@convention(thin) (@guaranteed SomeClass) -> @owned @callee_guaranteed (Builtin.Int64) -> ()
+// CHECK: bb0(%0 : @guaranteed $SomeClass):
+// CHECK:   class_method %0 : $SomeClass, #SomeClass.method!1 : (SomeClass) -> (Builtin.Int64) -> ()
+// CHECK:   %2 = copy_value %0 : $SomeClass
+// CHECK:   %3 = partial_apply [callee_guaranteed] %1(%2)
+// CHECK:   return %3
+
+func return_func() -> (_ x: Builtin.Int64, _ y: Builtin.Int64) -> Builtin.Int64 {
+  // CHECK: [[FUNC_THIN:%[0-9]+]] = function_ref @$S9functions19standalone_function{{[_0-9a-zA-Z]*}}F : $@convention(thin) (Builtin.Int64, Builtin.Int64) -> Builtin.Int64
+  // CHECK: [[FUNC_THICK:%[0-9]+]] = thin_to_thick_function [[FUNC_THIN]]
+  // CHECK: return [[FUNC_THICK]]
+  return standalone_function
+}
+
+func standalone_generic<T>(_ x: T, y: T) -> T { return x }
+
+// CHECK-LABEL: sil hidden @$S9functions14return_genericBi64_Bi64__Bi64_tcyF
+func return_generic() -> (_ x:Builtin.Int64, _ y:Builtin.Int64) -> Builtin.Int64 {
+  // CHECK: [[GEN:%.*]] = function_ref @$S9functions18standalone_generic{{[_0-9a-zA-Z]*}}F : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0, @in_guaranteed τ_0_0) -> @out τ_0_0
+  // CHECK: [[SPEC:%.*]] = partial_apply [callee_guaranteed] [[GEN]]<Builtin.Int64>()
+  // CHECK: [[THUNK:%.*]] = function_ref  @{{.*}} : $@convention(thin) (Builtin.Int64, Builtin.Int64, @guaranteed @callee_guaranteed (@in_guaranteed Builtin.Int64, @in_guaranteed Builtin.Int64) -> @out Builtin.Int64) -> Builtin.Int64
+  // CHECK: [[T0:%.*]] = partial_apply [callee_guaranteed] [[THUNK]]([[SPEC]])
+  // CHECK: return [[T0]]
+  return standalone_generic
+}
+
+// CHECK-LABEL: sil hidden @$S9functions20return_generic_tuple{{[_0-9a-zA-Z]*}}F
+func return_generic_tuple()
+-> (_ x: (Builtin.Int64, Builtin.Int64), _ y: (Builtin.Int64, Builtin.Int64)) -> (Builtin.Int64, Builtin.Int64) {
+  // CHECK: [[GEN:%.*]] = function_ref @$S9functions18standalone_generic{{[_0-9a-zA-Z]*}}F  : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0, @in_guaranteed τ_0_0) -> @out τ_0_0
+  // CHECK: [[SPEC:%.*]] = partial_apply [callee_guaranteed] [[GEN]]<(Builtin.Int64, Builtin.Int64)>()
+  // CHECK: [[THUNK:%.*]] = function_ref @{{.*}} : $@convention(thin) (Builtin.Int64, Builtin.Int64, Builtin.Int64, Builtin.Int64, @guaranteed @callee_guaranteed (@in_guaranteed (Builtin.Int64, Builtin.Int64), @in_guaranteed (Builtin.Int64, Builtin.Int64)) -> @out (Builtin.Int64, Builtin.Int64)) -> (Builtin.Int64, Builtin.Int64)
+  // CHECK: [[T0:%.*]] = partial_apply [callee_guaranteed] [[THUNK]]([[SPEC]])
+  // CHECK: return [[T0]]
+  return standalone_generic
+}
+
+// CHECK-LABEL: sil hidden @$S9functions16testNoReturnAttrs5NeverOyF : $@convention(thin) () -> Never
+func testNoReturnAttr() -> Never {}
+// CHECK-LABEL: sil hidden @$S9functions20testNoReturnAttrPoly{{[_0-9a-zA-Z]*}}F : $@convention(thin) <T> (@in_guaranteed T) -> Never
+func testNoReturnAttrPoly<T>(_ x: T) -> Never {}
+
+// CHECK-LABEL: sil hidden @$S9functions21testNoReturnAttrParam{{[_0-9a-zA-Z]*}}F : $@convention(thin) (@noescape @callee_guaranteed () -> Never) -> ()
+func testNoReturnAttrParam(_ fptr: () -> Never) -> () {}
+
+// CHECK-LABEL: sil hidden [transparent] @$S9functions15testTransparent{{[_0-9a-zA-Z]*}}F : $@convention(thin) (Builtin.Int1) -> Builtin.Int1
+@_transparent func testTransparent(_ x: Bool) -> Bool {
+  return x
+}
+
+// CHECK-LABEL: sil hidden @$S9functions16applyTransparent{{[_0-9a-zA-Z]*}}F : $@convention(thin) (Builtin.Int1) -> Builtin.Int1 {
+func applyTransparent(_ x: Bool) -> Bool {
+  // CHECK: [[FUNC:%[0-9]+]] = function_ref @$S9functions15testTransparent{{[_0-9a-zA-Z]*}}F : $@convention(thin) (Builtin.Int1) -> Builtin.Int1
+  // CHECK: apply [[FUNC]]({{%[0-9]+}}) : $@convention(thin) (Builtin.Int1) -> Builtin.Int1
+  return testTransparent(x)
+}
+
+// CHECK-LABEL: sil hidden [noinline] @$S9functions15noinline_calleeyyF : $@convention(thin) () -> ()
+@inline(never)
+func noinline_callee() {}
+
+// CHECK-LABEL: sil hidden [always_inline] @$S9functions20always_inline_calleeyyF : $@convention(thin) () -> ()
+@inline(__always)
+func always_inline_callee() {}
+
+// CHECK-LABEL: sil [serialized] [always_inline] @$S9functions27public_always_inline_calleeyyF : $@convention(thin) () -> ()
+@inline(__always)
+public func public_always_inline_callee() {}
+
+protocol AlwaysInline {
+  func alwaysInlined()
+}
+
+// CHECK-LABEL: sil hidden [always_inline] @$S9functions19AlwaysInlinedMemberV06alwaysC0{{[_0-9a-zA-Z]*}}F : $@convention(method) (AlwaysInlinedMember) -> () {
+
+// protocol witness for functions.AlwaysInline.alwaysInlined <A : functions.AlwaysInline>(functions.AlwaysInline.Self)() -> () in conformance functions.AlwaysInlinedMember : functions.AlwaysInline in functions
+// CHECK-LABEL: sil private [transparent] [thunk] [always_inline] @$S9functions19AlwaysInlinedMemberVAA0B6InlineA2aDP06alwaysC0{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method: AlwaysInline) (@in_guaranteed AlwaysInlinedMember) -> () {
+struct AlwaysInlinedMember : AlwaysInline {
+  @inline(__always)
+  func alwaysInlined() {}
+}
+
+// CHECK-LABEL: sil hidden [Onone] @$S9functions10onone_funcyyF : $@convention(thin) () -> ()
+@_optimize(none)
+func onone_func() {}
+
+// CHECK-LABEL: sil hidden [Ospeed] @$S9functions11ospeed_funcyyF : $@convention(thin) () -> ()
+@_optimize(speed)
+func ospeed_func() {}
+
+// CHECK-LABEL: sil hidden [Osize] @$S9functions10osize_funcyyF : $@convention(thin) () -> ()
+@_optimize(size)
+func osize_func() {}
+
+struct OptmodeTestStruct {
+
+  // CHECK-LABEL: sil hidden [Ospeed] @$S9functions17OptmodeTestStructV3fooyyF :
+  @_optimize(speed)
+  func foo() { }
+
+  // CHECK-LABEL: sil hidden [Ospeed] @$S9functions17OptmodeTestStructVACycfC :
+  @_optimize(speed)
+  init() { }
+
+  // CHECK-LABEL: sil hidden [Ospeed] @$S9functions17OptmodeTestStructV1xBi64_vg :
+  @_optimize(speed)
+  var x: Int { return getInt() }
+
+  // CHECK-LABEL: sil hidden [Ospeed] @$S9functions17OptmodeTestStructVyBi64_Bi64_cig :
+  @_optimize(speed)
+  subscript(l: Int) -> Int { return getInt() }
+}
+
+// CHECK-LABEL: sil hidden [_semantics "foo"] @$S9functions9semanticsyyF : $@convention(thin) () -> ()
+@_semantics("foo")
+func semantics() {}
+
+
+// <rdar://problem/17828355> curried final method on a class crashes in irgen
+final class r17828355Class {
+  func method(_ x : Int) {
+    var a : r17828355Class
+    var fn = a.method  // currying a final method.
+  }
+}
+
+// The curry thunk for the method should not include a class_method instruction.
+// CHECK-LABEL: sil shared [thunk] @$S9functions14r17828355ClassC6method
+// CHECK: bb0(%0 : @guaranteed $r17828355Class):
+// CHECK-NEXT: // function_ref functions.r17828355Class.method(Builtin.Int64) -> ()
+// CHECK-NEXT:  %1 = function_ref @$S9functions14r17828355ClassC6method{{[_0-9a-zA-Z]*}}F : $@convention(method) (Builtin.Int64, @guaranteed r17828355Class) -> ()
+// CHECK-NEXT:  %2 = copy_value %0
+// CHECK-NEXT:  partial_apply [callee_guaranteed] %1(%2) : $@convention(method) (Builtin.Int64, @guaranteed r17828355Class) -> ()
+// CHECK-NEXT:  return
+
+
+
+// <rdar://problem/19981118> Swift 1.2 beta 2: Closures nested in closures copy, rather than reference, captured vars.
+func noescapefunc(f: () -> ()) {}
+func escapefunc(_ f : @escaping () -> ()) {}
+
+func testNoescape() {
+  // "a" must be captured by-box into noescapefunc because the inner closure
+  // could escape it.
+  var a = 0
+  noescapefunc {
+    escapefunc { a = 42 }
+  }
+  markUsed(a)
+}
+
+// CHECK-LABEL: functions.testNoescape() -> ()
+// CHECK-NEXT: sil hidden @$S9functions12testNoescapeyyF : $@convention(thin) () -> ()
+// CHECK: function_ref closure #1 () -> () in functions.testNoescape() -> ()
+// CHECK-NEXT: function_ref @$S9functions12testNoescapeyyFyyXEfU_ : $@convention(thin) (@guaranteed { var Int }) -> ()
+
+// Despite being a noescape closure, this needs to capture 'a' by-box so it can
+// be passed to the capturing closure.closure
+// CHECK: closure #1 () -> () in functions.testNoescape() -> ()
+// CHECK-NEXT: sil private @$S9functions12testNoescapeyyFyyXEfU_ : $@convention(thin) (@guaranteed { var Int }) -> () {
+
+
+
+func testNoescape2() {
+  // "a" must be captured by-box into noescapefunc because the inner closure
+  // could escape it.  This also checks for when the outer closure captures it
+  // in a way that could be used with escape: the union of the two requirements
+  // doesn't allow a by-address capture.
+  var a = 0
+  noescapefunc {
+    escapefunc { a = 42 }
+    markUsed(a)
+  }
+  markUsed(a)
+}
+
+// CHECK-LABEL: sil hidden @$S9functions13testNoescape2yyF : $@convention(thin) () -> () {
+
+// CHECK: // closure #1 () -> () in functions.testNoescape2() -> ()
+// CHECK-NEXT: sil private @$S9functions13testNoescape2yyFyyXEfU_ : $@convention(thin) (@guaranteed { var Int }) -> () {
+
+// CHECK: // closure #1 () -> () in closure #1 () -> () in functions.testNoescape2() -> ()
+// CHECK-NEXT: sil private @$S9functions13testNoescape2yyFyyXEfU_yycfU_ : $@convention(thin) (@guaranteed { var Int }) -> () {
+
+enum PartialApplyEnumPayload<T, U> {
+  case Left(T)
+  case Right(U)
+}
+
+struct S {}
+struct C {}
+
+func partialApplyEnumCases(_ x: S, y: C) {
+  let left = PartialApplyEnumPayload<S, C>.Left
+  let left2 = left(S())
+
+  let right = PartialApplyEnumPayload<S, C>.Right
+  let right2 = right(C())
+}
+
+// CHECK-LABEL: sil shared [transparent] [thunk] @$S9functions23PartialApplyEnumPayloadO4Left{{[_0-9a-zA-Z]*}}F
+// CHECK:         [[UNCURRIED:%.*]] = function_ref @$S9functions23PartialApplyEnumPayloadO4Left{{[_0-9a-zA-Z]*}}F
+// CHECK:         [[CLOSURE:%.*]] = partial_apply [callee_guaranteed] [[UNCURRIED]]<T, U>(%0)
+// CHECK:         [[CANONICAL_THUNK:%.*]] = function_ref @$Sx9functions23PartialApplyEnumPayloadOyxq_GIegir_xADIegnr_r0_lTR : $@convention(thin) <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0, @guaranteed @callee_guaranteed (@in τ_0_0) -> @out PartialApplyEnumPayload<τ_0_0, τ_0_1>) -> @out PartialApplyEnumPayload<τ_0_0, τ_0_1>
+// CHECK:         [[THUNKED_CLOSURE:%.*]] = partial_apply [callee_guaranteed] [[CANONICAL_THUNK]]<T, U>([[CLOSURE]])
+// CHECK:         return [[THUNKED_CLOSURE]]
+// CHECK: } // end sil function '$S9functions23PartialApplyEnumPayloadO4Left{{[_0-9a-zA-Z]*}}F'
+
+// CHECK-LABEL: sil shared [transparent] [thunk] @$S9functions23PartialApplyEnumPayloadO5Right{{[_0-9a-zA-Z]*}}F
+// CHECK:         [[UNCURRIED:%.*]] = function_ref @$S9functions23PartialApplyEnumPayloadO5Right{{[_0-9a-zA-Z]*}}F
+// CHECK:         [[CLOSURE:%.*]] = partial_apply [callee_guaranteed] [[UNCURRIED]]<T, U>(%0)
+// CHECK:         [[CANONICAL_THUNK:%.*]] = function_ref @$Sq_9functions23PartialApplyEnumPayloadOyxq_GIegir_q_ADIegnr_r0_lTR : $@convention(thin) <τ_0_0, τ_0_1> (@in_guaranteed τ_0_1, @guaranteed @callee_guaranteed (@in τ_0_1) -> @out PartialApplyEnumPayload<τ_0_0, τ_0_1>) -> @out PartialApplyEnumPayload<τ_0_0, τ_0_1>
+// CHECK:         [[THUNKED_CLOSURE:%.*]] = partial_apply [callee_guaranteed] [[CANONICAL_THUNK]]<T, U>([[CLOSURE]])
+// CHECK:         return [[THUNKED_CLOSURE]]
+// CHECK: } // end sil function '$S9functions23PartialApplyEnumPayloadO5Right{{[_0-9a-zA-Z]*}}F'
diff --git a/test/SILGen/plus_zero_generic_casts.swift b/test/SILGen/plus_zero_generic_casts.swift
new file mode 100644
index 0000000..1f857b0
--- /dev/null
+++ b/test/SILGen/plus_zero_generic_casts.swift
@@ -0,0 +1,290 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -Xllvm -sil-full-demangle -emit-silgen -enable-sil-ownership %s | %FileCheck --check-prefix=CHECK --check-prefix=CHECK-%target-runtime %s
+
+protocol ClassBound : class {}
+protocol NotClassBound {}
+
+class C : ClassBound, NotClassBound {}
+struct S : NotClassBound {}
+struct Unloadable : NotClassBound { var x : NotClassBound }
+
+// CHECK-LABEL: sil hidden @$S13generic_casts020opaque_archetype_to_c1_D0{{[_0-9a-zA-Z]*}}F
+func opaque_archetype_to_opaque_archetype
+<T:NotClassBound, U>(_ t:T) -> U {
+  return t as! U
+  // CHECK: bb0([[RET:%.*]] : @trivial $*U, {{%.*}}: @trivial $*T):
+  // CHECK:   unconditional_checked_cast_addr T in {{%.*}} : $*T to U in [[RET]] : $*U
+}
+
+// CHECK-LABEL: sil hidden @$S13generic_casts020opaque_archetype_is_c1_D0{{[_0-9a-zA-Z]*}}F
+func opaque_archetype_is_opaque_archetype
+<T:NotClassBound, U>(_ t:T, u:U.Type) -> Bool {
+  return t is U
+  // CHECK:   checked_cast_addr_br take_always T in [[VAL:%.*]] : $*T to U in [[DEST:%.*]] : $*U, [[YES:bb[0-9]+]], [[NO:bb[0-9]+]]
+  // CHECK: [[YES]]:
+  // CHECK:   [[Y:%.*]] = integer_literal $Builtin.Int1, -1
+  // CHECK:   destroy_addr [[DEST]]
+  // CHECK:   br [[CONT:bb[0-9]+]]([[Y]] : $Builtin.Int1)
+  // CHECK: [[NO]]:
+  // CHECK:   [[N:%.*]] = integer_literal $Builtin.Int1, 0
+  // CHECK:   br [[CONT]]([[N]] : $Builtin.Int1)
+  // CHECK: [[CONT]]([[I1:%.*]] : @trivial $Builtin.Int1):
+  // -- apply the _getBool library fn
+  // CHECK-NEXT:  function_ref Swift._getBool
+  // CHECK-NEXT:  [[GETBOOL:%.*]] = function_ref @$Ss8_getBoolySbBi1_F :
+  // CHECK-NEXT:  [[RES:%.*]] = apply [[GETBOOL]]([[I1]])
+  // -- we don't consume the checked value
+  // CHECK:   return [[RES]] : $Bool
+}
+
+// CHECK-LABEL: sil hidden @$S13generic_casts026opaque_archetype_to_class_D0{{[_0-9a-zA-Z]*}}F
+func opaque_archetype_to_class_archetype
+<T:NotClassBound, U:ClassBound> (_ t:T) -> U {
+  return t as! U
+  // CHECK: unconditional_checked_cast_addr T in {{%.*}} : $*T to U in [[DOWNCAST_ADDR:%.*]] : $*U
+  // CHECK: [[DOWNCAST:%.*]] = load [take] [[DOWNCAST_ADDR]] : $*U
+  // CHECK: return [[DOWNCAST]] : $U
+}
+
+// CHECK-LABEL: sil hidden @$S13generic_casts026opaque_archetype_is_class_D0{{[_0-9a-zA-Z]*}}F
+func opaque_archetype_is_class_archetype
+<T:NotClassBound, U:ClassBound> (_ t:T, u:U.Type) -> Bool {
+  return t is U
+  // CHECK: copy_addr {{.*}} : $*T
+  // CHECK: checked_cast_addr_br take_always T in [[VAL:%.*]] : {{.*}} to U
+}
+
+// CHECK-LABEL: sil hidden @$S13generic_casts019class_archetype_to_c1_D0{{[_0-9a-zA-Z]*}}F
+func class_archetype_to_class_archetype
+<T:ClassBound, U:ClassBound>(_ t:T) -> U {
+  return t as! U
+  // Error bridging can change the identity of class-constrained archetypes.
+  // CHECK-objc: unconditional_checked_cast_addr T in {{%.*}} : $*T to U in [[DOWNCAST_ADDR:%.*]] : $*U
+  // CHECK-objc: [[DOWNCAST:%.*]] = load [take] [[DOWNCAST_ADDR]]
+  // CHECK-objc: return [[DOWNCAST]] : $U
+
+  // CHECK-native: [[DOWNCAST:%.*]] = unconditional_checked_cast {{.*}} : $T to $U
+}
+
+// CHECK-LABEL: sil hidden @$S13generic_casts019class_archetype_is_c1_D0{{[_0-9a-zA-Z]*}}F
+func class_archetype_is_class_archetype
+<T:ClassBound, U:ClassBound>(_ t:T, u:U.Type) -> Bool {
+  return t is U
+  // Error bridging can change the identity of class-constrained archetypes.
+  // CHECK-objc: checked_cast_addr_br {{.*}} T in {{%.*}} : $*T to U in {{%.*}} : $*U
+  // CHECK-native: checked_cast_br {{.*}} : $T to $U
+}
+
+// CHECK-LABEL: sil hidden @$S13generic_casts38opaque_archetype_to_addr_only_concrete{{[_0-9a-zA-Z]*}}F
+func opaque_archetype_to_addr_only_concrete
+<T:NotClassBound> (_ t:T) -> Unloadable {
+  return t as! Unloadable
+  // CHECK: bb0([[RET:%.*]] : @trivial $*Unloadable, {{%.*}}: @trivial $*T):
+  // CHECK:   unconditional_checked_cast_addr T in {{%.*}} : $*T to Unloadable in [[RET]] : $*Unloadable
+}
+
+// CHECK-LABEL: sil hidden @$S13generic_casts38opaque_archetype_is_addr_only_concrete{{[_0-9a-zA-Z]*}}F
+func opaque_archetype_is_addr_only_concrete
+<T:NotClassBound> (_ t:T) -> Bool {
+  return t is Unloadable
+  // CHECK: checked_cast_addr_br take_always T in [[VAL:%.*]] : {{.*}} to Unloadable in
+}
+
+// CHECK-LABEL: sil hidden @$S13generic_casts37opaque_archetype_to_loadable_concrete{{[_0-9a-zA-Z]*}}F
+func opaque_archetype_to_loadable_concrete
+<T:NotClassBound>(_ t:T) -> S {
+  return t as! S
+  // CHECK: unconditional_checked_cast_addr T in {{%.*}} : $*T to S in [[DOWNCAST_ADDR:%.*]] : $*S
+  // CHECK: [[DOWNCAST:%.*]] = load [trivial] [[DOWNCAST_ADDR]] : $*S
+  // CHECK: return [[DOWNCAST]] : $S
+}
+
+// CHECK-LABEL: sil hidden @$S13generic_casts37opaque_archetype_is_loadable_concrete{{[_0-9a-zA-Z]*}}F
+func opaque_archetype_is_loadable_concrete
+<T:NotClassBound>(_ t:T) -> Bool {
+  return t is S
+  // CHECK: checked_cast_addr_br take_always T in {{%.*}} : $*T to S in
+}
+
+// CHECK-LABEL: sil hidden @$S13generic_casts019class_archetype_to_C0{{[_0-9a-zA-Z]*}}F
+func class_archetype_to_class
+<T:ClassBound>(_ t:T) -> C {
+  return t as! C
+  // CHECK: [[DOWNCAST:%.*]] = unconditional_checked_cast {{%.*}} to $C
+  // CHECK: return [[DOWNCAST]] : $C
+}
+
+// CHECK-LABEL: sil hidden @$S13generic_casts019class_archetype_is_C0{{[_0-9a-zA-Z]*}}F
+func class_archetype_is_class
+<T:ClassBound>(_ t:T) -> Bool {
+  return t is C
+  // CHECK: checked_cast_br {{%.*}} to $C
+}
+
+// CHECK-LABEL: sil hidden @$S13generic_casts022opaque_existential_to_C10_archetype{{[_0-9a-zA-Z]*}}F
+func opaque_existential_to_opaque_archetype
+<T:NotClassBound>(_ p:NotClassBound) -> T {
+  return p as! T
+  // CHECK: bb0([[RET:%.*]] : @trivial $*T, [[ARG:%.*]] : @trivial $*NotClassBound):
+  // CHECK:      [[TEMP:%.*]] = alloc_stack $NotClassBound
+  // CHECK-NEXT: copy_addr [[ARG]] to [initialization] [[TEMP]]
+  // CHECK-NEXT: unconditional_checked_cast_addr NotClassBound in [[TEMP]] : $*NotClassBound to T in [[RET]] : $*T
+  // CHECK-NEXT: dealloc_stack [[TEMP]]
+  // CHECK-NEXT: [[T0:%.*]] = tuple ()
+  // CHECK-NEXT: return [[T0]]
+}
+
+// CHECK-LABEL: sil hidden @$S13generic_casts022opaque_existential_is_C10_archetype{{[_0-9a-zA-Z]*}}F
+func opaque_existential_is_opaque_archetype
+<T:NotClassBound>(_ p:NotClassBound, _: T) -> Bool {
+  return p is T
+  // CHECK:   checked_cast_addr_br take_always NotClassBound in [[CONTAINER:%.*]] : {{.*}} to T in
+}
+
+// CHECK-LABEL: sil hidden @$S13generic_casts37opaque_existential_to_class_archetype{{[_0-9a-zA-Z]*}}F
+func opaque_existential_to_class_archetype
+<T:ClassBound>(_ p:NotClassBound) -> T {
+  return p as! T
+  // CHECK: unconditional_checked_cast_addr NotClassBound in {{%.*}} : $*NotClassBound to T in [[DOWNCAST_ADDR:%.*]] : $*T
+  // CHECK: [[DOWNCAST:%.*]] = load [take] [[DOWNCAST_ADDR]] : $*T
+  // CHECK: return [[DOWNCAST]] : $T
+}
+
+// CHECK-LABEL: sil hidden @$S13generic_casts37opaque_existential_is_class_archetype{{[_0-9a-zA-Z]*}}F
+func opaque_existential_is_class_archetype
+<T:ClassBound>(_ p:NotClassBound, _: T) -> Bool {
+  return p is T
+  // CHECK: checked_cast_addr_br take_always NotClassBound in {{%.*}} : $*NotClassBound to T in
+}
+
+// CHECK-LABEL: sil hidden @$S13generic_casts021class_existential_to_C10_archetype{{[_0-9a-zA-Z]*}}F
+func class_existential_to_class_archetype
+<T:ClassBound>(_ p:ClassBound) -> T {
+  return p as! T
+  // CHECK-objc: unconditional_checked_cast_addr ClassBound in {{%.*}} : $*ClassBound to T in [[DOWNCAST_ADDR:%.*]] : $*T
+  // CHECK-objc: [[DOWNCAST:%.*]] = load [take] [[DOWNCAST_ADDR]]
+  // CHECK-objc: return [[DOWNCAST]] : $T
+
+  // CHECK-native: [[DOWNCAST:%.*]] = unconditional_checked_cast {{.*}} : $ClassBound to $T
+}
+
+// CHECK-LABEL: sil hidden @$S13generic_casts021class_existential_is_C10_archetype{{[_0-9a-zA-Z]*}}F
+func class_existential_is_class_archetype
+<T:ClassBound>(_ p:ClassBound, _: T) -> Bool {
+  return p is T
+  // CHECK-objc: checked_cast_addr_br {{.*}} ClassBound in {{%.*}} : $*ClassBound to T in {{%.*}} : $*T
+  // CHECK-native: checked_cast_br {{.*}} : $ClassBound to $T
+}
+
+// CHECK-LABEL: sil hidden @$S13generic_casts40opaque_existential_to_addr_only_concrete{{[_0-9a-zA-Z]*}}F
+func opaque_existential_to_addr_only_concrete(_ p: NotClassBound) -> Unloadable {
+  return p as! Unloadable
+  // CHECK: bb0([[RET:%.*]] : @trivial $*Unloadable, {{%.*}}: @trivial $*NotClassBound):
+  // CHECK:   unconditional_checked_cast_addr NotClassBound in {{%.*}} : $*NotClassBound to Unloadable in [[RET]] : $*Unloadable
+}
+
+// CHECK-LABEL: sil hidden @$S13generic_casts40opaque_existential_is_addr_only_concrete{{[_0-9a-zA-Z]*}}F
+func opaque_existential_is_addr_only_concrete(_ p: NotClassBound) -> Bool {
+  return p is Unloadable
+  // CHECK:   checked_cast_addr_br take_always NotClassBound in {{%.*}} : $*NotClassBound to Unloadable in
+}
+
+// CHECK-LABEL: sil hidden @$S13generic_casts39opaque_existential_to_loadable_concrete{{[_0-9a-zA-Z]*}}F
+func opaque_existential_to_loadable_concrete(_ p: NotClassBound) -> S {
+  return p as! S
+  // CHECK:   unconditional_checked_cast_addr NotClassBound in {{%.*}} : $*NotClassBound to S in [[DOWNCAST_ADDR:%.*]] : $*S
+  // CHECK: [[DOWNCAST:%.*]] = load [trivial] [[DOWNCAST_ADDR]] : $*S
+  // CHECK: return [[DOWNCAST]] : $S
+}
+
+// CHECK-LABEL: sil hidden @$S13generic_casts39opaque_existential_is_loadable_concrete{{[_0-9a-zA-Z]*}}F
+func opaque_existential_is_loadable_concrete(_ p: NotClassBound) -> Bool {
+  return p is S
+  // CHECK: checked_cast_addr_br take_always NotClassBound in {{%.*}} : $*NotClassBound to S in
+}
+
+// CHECK-LABEL: sil hidden @$S13generic_casts021class_existential_to_C0{{[_0-9a-zA-Z]*}}F
+func class_existential_to_class(_ p: ClassBound) -> C {
+  return p as! C
+  // CHECK: [[DOWNCAST:%.*]] = unconditional_checked_cast {{%.*}} to $C
+  // CHECK: return [[DOWNCAST]] : $C
+}
+
+// CHECK-LABEL: sil hidden @$S13generic_casts021class_existential_is_C0{{[_0-9a-zA-Z]*}}F
+func class_existential_is_class(_ p: ClassBound) -> Bool {
+  return p is C
+  // CHECK: checked_cast_br {{%.*}} to $C
+}
+
+// CHECK-LABEL: sil hidden @$S13generic_casts27optional_anyobject_to_classyAA1CCSgyXlSgF
+func optional_anyobject_to_class(_ p: AnyObject?) -> C? {
+  return p as? C
+  // CHECK: checked_cast_br {{%.*}} : $AnyObject to $C
+}
+
+// The below tests are to ensure we don't dig into an optional operand when
+// casting to a non-class archetype, as it could dynamically be an optional type.
+
+// CHECK-LABEL: sil hidden @$S13generic_casts32optional_any_to_opaque_archetype{{[_0-9a-zA-Z]*}}F
+func optional_any_to_opaque_archetype<T>(_ x: Any?) -> T {
+  return x as! T
+  // CHECK: bb0([[RET:%.*]] : @trivial $*T, {{%.*}} : @trivial $*Optional<Any>):
+  // CHECK: unconditional_checked_cast_addr Optional<Any> in {{%.*}} : $*Optional<Any> to T in [[RET]] : $*T
+}
+
+// CHECK-LABEL: sil hidden @$S13generic_casts46optional_any_conditionally_to_opaque_archetype{{[_0-9a-zA-Z]*}}F
+func optional_any_conditionally_to_opaque_archetype<T>(_ x: Any?) -> T? {
+  return x as? T
+  // CHECK: checked_cast_addr_br take_always Optional<Any> in {{%.*}} : $*Optional<Any> to T in {{%.*}} : $*T
+}
+
+// CHECK-LABEL: sil hidden @$S13generic_casts32optional_any_is_opaque_archetype{{[_0-9a-zA-Z]*}}F
+func optional_any_is_opaque_archetype<T>(_ x: Any?, _: T) -> Bool {
+  return x is T
+  // CHECK: checked_cast_addr_br take_always Optional<Any> in {{%.*}} : $*Optional<Any> to T in {{%.*}} : $*T
+}
+
+// But we can dig into at most one layer of the operand if it's
+// an optional archetype...
+
+// CHECK-LABEL: sil hidden @$S13generic_casts016optional_any_to_C17_opaque_archetype{{[_0-9a-zA-Z]*}}F
+func optional_any_to_optional_opaque_archetype<T>(_ x: Any?) -> T? {
+  return x as! T?
+  // CHECK: unconditional_checked_cast_addr Any in {{%.*}} : $*Any to T in {{%.*}} : $*T
+}
+
+// CHECK-LABEL: sil hidden @$S13generic_casts030optional_any_conditionally_to_C17_opaque_archetype{{[_0-9a-zA-Z]*}}F
+func optional_any_conditionally_to_optional_opaque_archetype<T>(_ x: Any?) -> T?? {
+  return x as? T?
+  // CHECK: checked_cast_addr_br take_always Any in {{%.*}} : $*Any to T in {{%.*}} : $*T
+}
+
+// CHECK-LABEL: sil hidden @$S13generic_casts016optional_any_is_C17_opaque_archetype{{[_0-9a-zA-Z]*}}F
+func optional_any_is_optional_opaque_archetype<T>(_ x: Any?, _: T) -> Bool {
+  return x is T?
+  //   Because the levels of optional are the same, 'is' doesn't transform into an 'as?',
+  //   so we just cast directly without digging into the optional operand.
+  // CHECK: checked_cast_addr_br take_always Optional<Any> in {{%.*}} : $*Optional<Any> to Optional<T> in {{%.*}} : $*Optional<T>
+}
+
+// And we can dig into the operand when casting to a class archetype, as it
+// cannot dynamically be optional...
+
+// CHECK-LABEL: sil hidden @$S13generic_casts31optional_any_to_class_archetype{{[_0-9a-zA-Z]*}}F
+func optional_any_to_class_archetype<T : AnyObject>(_ x: Any?) -> T {
+  return x as! T
+  // CHECK: unconditional_checked_cast_addr Any in {{%.*}} : $*Any to T in {{%.*}} : $*T
+}
+
+// CHECK-LABEL: sil hidden @$S13generic_casts45optional_any_conditionally_to_class_archetype{{[_0-9a-zA-Z]*}}F
+func optional_any_conditionally_to_class_archetype<T : AnyObject>(_ x: Any?) -> T? {
+  return x as? T
+  // CHECK: checked_cast_addr_br take_always Any in {{%.*}} : $*Any to T in {{%.*}} : $*T
+}
+
+// CHECK-LABEL: sil hidden @$S13generic_casts31optional_any_is_class_archetype{{[_0-9a-zA-Z]*}}F
+func optional_any_is_class_archetype<T : AnyObject>(_ x: Any?, _: T) -> Bool {
+  return x is T
+  // CHECK: checked_cast_addr_br take_always Any in {{%.*}} : $*Any to T in {{%.*}} : $*T
+}
+
diff --git a/test/SILGen/plus_zero_generic_closures.swift b/test/SILGen/plus_zero_generic_closures.swift
new file mode 100644
index 0000000..174912d
--- /dev/null
+++ b/test/SILGen/plus_zero_generic_closures.swift
@@ -0,0 +1,336 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -parse-stdlib -emit-silgen -enable-sil-ownership %s | %FileCheck %s
+
+import Swift
+
+var zero: Int
+
+// CHECK-LABEL: sil hidden @$S16generic_closures0A21_nondependent_context{{[_0-9a-zA-Z]*}}F
+func generic_nondependent_context<T>(_ x: T, y: Int) -> Int {
+  func foo() -> Int { return y }
+
+  func bar() -> Int { return y }
+
+  // CHECK: [[FOO:%.*]] = function_ref @$S16generic_closures0A21_nondependent_context{{.*}} : $@convention(thin) (Int) -> Int
+  // CHECK: [[FOO_CLOSURE:%.*]] = partial_apply [callee_guaranteed] [[FOO]](%1)
+  // CHECK: destroy_value [[FOO_CLOSURE]]
+  let _ = foo
+
+  // CHECK: [[BAR:%.*]] = function_ref @$S16generic_closures0A21_nondependent_context{{.*}} : $@convention(thin) (Int) -> Int
+  // CHECK: [[BAR_CLOSURE:%.*]] = partial_apply [callee_guaranteed] [[BAR]](%1)
+  // CHECK: destroy_value [[BAR_CLOSURE]]
+  let _ = bar
+
+  // CHECK: [[FOO:%.*]] = function_ref @$S16generic_closures0A21_nondependent_context{{.*}} : $@convention(thin) (Int) -> Int
+  // CHECK: [[FOO_CLOSURE:%.*]] = apply [[FOO]]
+  _ = foo()
+
+  // CHECK: [[BAR:%.*]] = function_ref @$S16generic_closures0A21_nondependent_context{{.*}} : $@convention(thin) (Int) -> Int
+  // CHECK: [[BAR_CLOSURE:%.*]] = apply [[BAR]]
+
+  // CHECK: [[BAR_CLOSURE]]
+  return bar()
+}
+
+// CHECK-LABEL: sil hidden @$S16generic_closures0A8_capture{{[_0-9a-zA-Z]*}}F
+func generic_capture<T>(_ x: T) -> Any.Type {
+  func foo() -> Any.Type { return T.self }
+
+  // CHECK: [[FOO:%.*]] = function_ref @$S16generic_closures0A8_capture{{.*}} : $@convention(thin) <τ_0_0> () -> @thick Any.Type
+  // CHECK: [[FOO_CLOSURE:%.*]] = partial_apply [callee_guaranteed] [[FOO]]<T>()
+  // CHECK: destroy_value [[FOO_CLOSURE]]
+  let _ = foo
+
+  // CHECK: [[FOO:%.*]] = function_ref @$S16generic_closures0A8_capture{{.*}} : $@convention(thin) <τ_0_0> () -> @thick Any.Type
+  // CHECK: [[FOO_CLOSURE:%.*]] = apply [[FOO]]<T>()
+
+  // CHECK: return [[FOO_CLOSURE]]
+  return foo()
+}
+
+// CHECK-LABEL: sil hidden @$S16generic_closures0A13_capture_cast{{[_0-9a-zA-Z]*}}F
+func generic_capture_cast<T>(_ x: T, y: Any) -> Bool {
+  func foo(_ a: Any) -> Bool { return a is T }
+
+  // CHECK: [[FOO:%.*]] = function_ref @$S16generic_closures0A13_capture_cast{{.*}} : $@convention(thin) <τ_0_0> (@in_guaranteed Any) -> Bool
+  // CHECK: [[FOO_CLOSURE:%.*]] = partial_apply [callee_guaranteed] [[FOO]]<T>()
+  // CHECK: destroy_value [[FOO_CLOSURE]]
+  let _ = foo
+
+  // CHECK: [[FOO:%.*]] = function_ref @$S16generic_closures0A13_capture_cast{{.*}} : $@convention(thin) <τ_0_0> (@in_guaranteed Any) -> Bool
+  // CHECK: [[FOO_CLOSURE:%.*]] = apply [[FOO]]<T>([[ARG:%.*]])
+
+  // CHECK: return [[FOO_CLOSURE]]
+  return foo(y)
+}
+
+protocol Concept {
+  var sensical: Bool { get }
+}
+
+// CHECK-LABEL: sil hidden @$S16generic_closures0A22_nocapture_existential{{[_0-9a-zA-Z]*}}F
+func generic_nocapture_existential<T>(_ x: T, y: Concept) -> Bool {
+  func foo(_ a: Concept) -> Bool { return a.sensical }
+
+  // CHECK: [[FOO:%.*]] = function_ref @$S16generic_closures0A22_nocapture_existential{{.*}} : $@convention(thin) (@in_guaranteed Concept) -> Bool
+  // CHECK: [[FOO_CLOSURE:%.*]] = thin_to_thick_function [[FOO]]
+  // CHECK: destroy_value [[FOO_CLOSURE]]
+  let _ = foo
+
+  // CHECK: [[FOO:%.*]] = function_ref @$S16generic_closures0A22_nocapture_existential{{.*}} : $@convention(thin) (@in_guaranteed Concept) -> Bool
+  // CHECK: [[FOO_CLOSURE:%.*]] = apply [[FOO]]([[ARG:%.*]])
+
+  // CHECK: return [[FOO_CLOSURE]]
+  return foo(y)
+}
+
+// CHECK-LABEL: sil hidden @$S16generic_closures0A18_dependent_context{{[_0-9a-zA-Z]*}}F
+func generic_dependent_context<T>(_ x: T, y: Int) -> T {
+  func foo() -> T { return x }
+
+  // CHECK: [[FOO:%.*]] = function_ref @$S16generic_closures0A18_dependent_context{{.*}} : $@convention(thin) <τ_0_0> (@guaranteed <τ_0_0> { var τ_0_0 } <τ_0_0>) -> @out τ_0_0
+  // CHECK: [[FOO_CLOSURE:%.*]] = partial_apply [callee_guaranteed] [[FOO]]<T>([[BOX:%.*]])
+  // CHECK: destroy_value [[FOO_CLOSURE]]
+  let _ = foo
+
+  // CHECK: [[FOO:%.*]] = function_ref @$S16generic_closures0A18_dependent_context{{.*}} : $@convention(thin) <τ_0_0> (@guaranteed <τ_0_0> { var τ_0_0 } <τ_0_0>) -> @out τ_0_0
+  // CHECK: [[FOO_CLOSURE:%.*]] = apply [[FOO]]<T>
+
+  // CHECK: return
+  return foo()
+}
+
+enum Optionable<Wrapped> {
+  case none
+  case some(Wrapped)
+}
+
+class NestedGeneric<U> {
+  class func generic_nondependent_context<T>(_ x: T, y: Int, z: U) -> Int {
+    func foo() -> Int { return y }
+    let _ = foo
+    return foo()
+  }
+
+  class func generic_dependent_inner_context<T>(_ x: T, y: Int, z: U) -> T {
+    func foo() -> T { return x }
+    let _ = foo
+    return foo()
+  }
+
+  class func generic_dependent_outer_context<T>(_ x: T, y: Int, z: U) -> U {
+    func foo() -> U { return z }
+    let _ = foo
+    return foo()
+  }
+
+  class func generic_dependent_both_contexts<T>(_ x: T, y: Int, z: U) -> (T, U) {
+    func foo() -> (T, U) { return (x, z) }
+    let _ = foo
+    return foo()
+  }
+
+  // CHECK-LABEL: sil hidden @$S16generic_closures13NestedGenericC20nested_reabstraction{{[_0-9a-zA-Z]*}}F
+  //   CHECK:       [[REABSTRACT:%.*]] = function_ref @$SIeg_ytytIegnr_TR
+  //   CHECK:       partial_apply [callee_guaranteed] [[REABSTRACT]]
+  func nested_reabstraction<T>(_ x: T) -> Optionable<() -> ()> {
+    return .some({})
+  }
+}
+
+// <rdar://problem/15417773>
+// Ensure that nested closures capture the generic parameters of their nested
+// context.
+
+// CHECK: sil hidden @$S16generic_closures018nested_closure_in_A0yxxlF : $@convention(thin) <T> (@in_guaranteed T) -> @out T
+// CHECK:   function_ref [[OUTER_CLOSURE:@\$S16generic_closures018nested_closure_in_A0yxxlFxyXEfU_]]
+// CHECK: sil private [[OUTER_CLOSURE]] : $@convention(thin) <T> (@inout_aliasable T) -> @out T
+// CHECK:   function_ref [[INNER_CLOSURE:@\$S16generic_closures018nested_closure_in_A0yxxlFxyXEfU_xyXEfU_]]
+// CHECK: sil private [[INNER_CLOSURE]] : $@convention(thin) <T> (@inout_aliasable T) -> @out T {
+func nested_closure_in_generic<T>(_ x:T) -> T {
+  return { { x }() }()
+}
+
+// CHECK-LABEL: sil hidden @$S16generic_closures16local_properties{{[_0-9a-zA-Z]*}}F
+func local_properties<T>(_ t: inout T) {
+  var prop: T {
+    get {
+      return t
+    }
+    set {
+      t = newValue
+    }
+  }
+
+  // CHECK: [[GETTER_REF:%[0-9]+]] = function_ref [[GETTER_CLOSURE:@\$S16generic_closures16local_properties[_0-9a-zA-Z]*]] : $@convention(thin) <τ_0_0> (@inout_aliasable τ_0_0) -> @out τ_0_0
+  // CHECK: apply [[GETTER_REF]]
+  t = prop
+
+  // CHECK: [[SETTER_REF:%[0-9]+]] = function_ref [[SETTER_CLOSURE:@\$S16generic_closures16local_properties[_0-9a-zA-Z]*]] : $@convention(thin) <τ_0_0> (@in τ_0_0, @inout_aliasable τ_0_0) -> ()
+  // CHECK: apply [[SETTER_REF]]
+  prop = t
+
+  var prop2: T {
+    get {
+      return t
+    }
+    set {
+      // doesn't capture anything
+    }
+  }
+
+  // CHECK: [[GETTER2_REF:%[0-9]+]] = function_ref [[GETTER2_CLOSURE:@\$S16generic_closures16local_properties[_0-9a-zA-Z]*]] : $@convention(thin) <τ_0_0> (@inout_aliasable τ_0_0) -> @out τ_0_0
+  // CHECK: apply [[GETTER2_REF]]
+  t = prop2
+
+  // CHECK: [[SETTER2_REF:%[0-9]+]] = function_ref [[SETTER2_CLOSURE:@\$S16generic_closures16local_properties[_0-9a-zA-Z]*]] : $@convention(thin) <τ_0_0> (@in τ_0_0) -> ()
+  // CHECK: apply [[SETTER2_REF]]
+  prop2 = t
+}
+
+protocol Fooable {
+  static func foo() -> Bool
+}
+
+// <rdar://problem/16399018>
+func shmassert(_ f: @autoclosure () -> Bool) {}
+
+// CHECK-LABEL: sil hidden @$S16generic_closures08capture_A6_param{{[_0-9a-zA-Z]*}}F
+func capture_generic_param<A: Fooable>(_ x: A) {
+  shmassert(A.foo())
+}
+
+// Make sure we use the correct convention when capturing class-constrained
+// member types: <rdar://problem/24470533>
+class Class {}
+
+protocol HasClassAssoc { associatedtype Assoc : Class }
+
+// CHECK-LABEL: sil hidden @$S16generic_closures027captures_class_constrained_A0_1fyx_5AssocQzAEctAA08HasClassF0RzlF
+// CHECK: bb0([[ARG1:%.*]] : @trivial $*T, [[ARG2:%.*]] : @guaranteed $@callee_guaranteed (@guaranteed T.Assoc) -> @owned T.Assoc):
+// CHECK: [[GENERIC_FN:%.*]] = function_ref @$S16generic_closures027captures_class_constrained_A0_1fyx_5AssocQzAEctAA08HasClassF0RzlFA2EcycfU_
+// CHECK: [[ARG2_COPY:%.*]] = copy_value [[ARG2]]
+// CHECK: [[CONCRETE_FN:%.*]] = partial_apply [callee_guaranteed] [[GENERIC_FN]]<T>([[ARG2_COPY]])
+
+func captures_class_constrained_generic<T : HasClassAssoc>(_ x: T, f: @escaping (T.Assoc) -> T.Assoc) {
+  let _: () -> (T.Assoc) -> T.Assoc = { f }
+}
+
+// Make sure local generic functions can have captures
+
+// CHECK-LABEL: sil hidden @$S16generic_closures06outer_A01t1iyx_SitlF : $@convention(thin) <T> (@in_guaranteed T, Int) -> ()
+func outer_generic<T>(t: T, i: Int) {
+  func inner_generic_nocapture<U>(u: U) -> U {
+    return u
+  }
+
+  func inner_generic1<U>(u: U) -> Int {
+    return i
+  }
+
+  func inner_generic2<U>(u: U) -> T {
+    return t
+  }
+
+  let _: () -> () = inner_generic_nocapture
+  // CHECK: [[FN:%.*]] = function_ref @$S16generic_closures06outer_A01t1iyx_SitlF06inner_A10_nocaptureL_1uqd__qd___tr__lF : $@convention(thin) <τ_0_0><τ_1_0> (@in_guaranteed τ_1_0) -> @out τ_1_0
+  // CHECK: [[CLOSURE:%.*]] = partial_apply [callee_guaranteed] [[FN]]<T, ()>() : $@convention(thin) <τ_0_0><τ_1_0> (@in_guaranteed τ_1_0) -> @out τ_1_0
+  // CHECK: [[THUNK:%.*]] = function_ref @$SytytIegnr_Ieg_TR
+  // CHECK: [[THUNK_CLOSURE:%.*]] = partial_apply [callee_guaranteed] [[THUNK]]([[CLOSURE]])
+  // CHECK: destroy_value [[THUNK_CLOSURE]]
+
+  // CHECK: [[FN:%.*]] = function_ref @$S16generic_closures06outer_A01t1iyx_SitlF06inner_A10_nocaptureL_1uqd__qd___tr__lF : $@convention(thin) <τ_0_0><τ_1_0> (@in_guaranteed τ_1_0) -> @out τ_1_0
+  // CHECK: [[RESULT:%.*]] = apply [[FN]]<T, T>({{.*}}) : $@convention(thin) <τ_0_0><τ_1_0> (@in_guaranteed τ_1_0) -> @out τ_1_0
+  _ = inner_generic_nocapture(u: t)
+
+  // CHECK: [[FN:%.*]] = function_ref @$S16generic_closures06outer_A01t1iyx_SitlF14inner_generic1L_1uSiqd___tr__lF : $@convention(thin) <τ_0_0><τ_1_0> (@in_guaranteed τ_1_0, Int) -> Int
+  // CHECK: [[CLOSURE:%.*]] = partial_apply [callee_guaranteed] [[FN]]<T, ()>(%1) : $@convention(thin) <τ_0_0><τ_1_0> (@in_guaranteed τ_1_0, Int) -> Int
+  // CHECK: [[THUNK:%.*]] = function_ref @$SytSiIegnd_SiIegd_TR
+  // CHECK: [[THUNK_CLOSURE:%.*]] = partial_apply [callee_guaranteed] [[THUNK]]([[CLOSURE]])
+  // CHECK: destroy_value [[THUNK_CLOSURE]]
+  let _: () -> Int = inner_generic1
+
+  // CHECK: [[FN:%.*]] = function_ref @$S16generic_closures06outer_A01t1iyx_SitlF14inner_generic1L_1uSiqd___tr__lF : $@convention(thin) <τ_0_0><τ_1_0> (@in_guaranteed τ_1_0, Int) -> Int
+  // CHECK: [[RESULT:%.*]] = apply [[FN]]<T, T>({{.*}}) : $@convention(thin) <τ_0_0><τ_1_0> (@in_guaranteed τ_1_0, Int) -> Int
+  _ = inner_generic1(u: t)
+
+  // CHECK: [[FN:%.*]] = function_ref @$S16generic_closures06outer_A01t1iyx_SitlF14inner_generic2L_1uxqd___tr__lF : $@convention(thin) <τ_0_0><τ_1_0> (@in_guaranteed τ_1_0, @guaranteed <τ_0_0> { var τ_0_0 } <τ_0_0>) -> @out τ_0_0
+  // CHECK: [[CLOSURE:%.*]] = partial_apply [callee_guaranteed] [[FN]]<T, ()>([[ARG:%.*]]) : $@convention(thin) <τ_0_0><τ_1_0> (@in_guaranteed τ_1_0, @guaranteed <τ_0_0> { var τ_0_0 } <τ_0_0>) -> @out τ_0_0
+  // CHECK: [[THUNK:%.*]] = function_ref @$SytxIegnr_xIegr_lTR
+  // CHECK: [[THUNK_CLOSURE:%.*]] = partial_apply [callee_guaranteed] [[THUNK]]<T>([[CLOSURE]])
+  // CHECK: destroy_value [[THUNK_CLOSURE]]
+  let _: () -> T = inner_generic2
+
+  // CHECK: [[FN:%.*]] = function_ref @$S16generic_closures06outer_A01t1iyx_SitlF14inner_generic2L_1uxqd___tr__lF : $@convention(thin) <τ_0_0><τ_1_0> (@in_guaranteed τ_1_0, @guaranteed <τ_0_0> { var τ_0_0 } <τ_0_0>) -> @out τ_0_0
+  // CHECK: [[RESULT:%.*]] = apply [[FN]]<T, T>({{.*}}) : $@convention(thin) <τ_0_0><τ_1_0> (@in_guaranteed τ_1_0, @guaranteed <τ_0_0> { var τ_0_0 } <τ_0_0>) -> @out τ_0_0
+  _ = inner_generic2(u: t)
+}
+
+// CHECK-LABEL: sil hidden @$S16generic_closures14outer_concrete1iySi_tF : $@convention(thin) (Int) -> ()
+func outer_concrete(i: Int) {
+  func inner_generic_nocapture<U>(u: U) -> U {
+    return u
+  }
+
+  func inner_generic<U>(u: U) -> Int {
+    return i
+  }
+
+  // CHECK: [[FN:%.*]] = function_ref @$S16generic_closures14outer_concrete1iySi_tF06inner_A10_nocaptureL_1uxx_tlF : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> @out τ_0_0
+  // CHECK: [[CLOSURE:%.*]] = partial_apply [callee_guaranteed] [[FN]]<()>() : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> @out τ_0_0
+  // CHECK: [[THUNK:%.*]] = function_ref @$SytytIegnr_Ieg_TR
+  // CHECK: [[THUNK_CLOSURE:%.*]] = partial_apply [callee_guaranteed] [[THUNK]]([[CLOSURE]])
+  // CHECK: destroy_value [[THUNK_CLOSURE]]
+  let _: () -> () = inner_generic_nocapture
+
+  // CHECK: [[FN:%.*]] = function_ref @$S16generic_closures14outer_concrete1iySi_tF06inner_A10_nocaptureL_1uxx_tlF : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> @out τ_0_0
+  // CHECK: [[RESULT:%.*]] = apply [[FN]]<Int>({{.*}}) : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> @out τ_0_0
+  _ = inner_generic_nocapture(u: i)
+
+  // CHECK: [[FN:%.*]] = function_ref @$S16generic_closures14outer_concrete1iySi_tF06inner_A0L_1uSix_tlF : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0, Int) -> Int
+  // CHECK: [[CLOSURE:%.*]] = partial_apply [callee_guaranteed] [[FN]]<()>(%0) : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0, Int) -> Int
+  // CHECK: [[THUNK:%.*]] = function_ref @$SytSiIegnd_SiIegd_TR
+  // CHECK: [[THUNK_CLOSURE:%.*]] = partial_apply [callee_guaranteed] [[THUNK]]([[CLOSURE]])
+  // CHECK: destroy_value [[THUNK_CLOSURE]]
+  let _: () -> Int = inner_generic
+
+  // CHECK: [[FN:%.*]] = function_ref @$S16generic_closures14outer_concrete1iySi_tF06inner_A0L_1uSix_tlF : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0, Int) -> Int
+  // CHECK: [[RESULT:%.*]] = apply [[FN]]<Int>({{.*}}) : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0, Int) -> Int
+  _ = inner_generic(u: i)
+}
+
+// CHECK-LABEL: sil hidden @$S16generic_closures06mixed_A19_nongeneric_nesting1tyx_tlF : $@convention(thin) <T> (@in_guaranteed T) -> ()
+func mixed_generic_nongeneric_nesting<T>(t: T) {
+  func outer() {
+    func middle<U>(u: U) {
+      func inner() -> U {
+        return u
+      }
+      inner()
+    }
+    middle(u: 11)
+  }
+  outer()
+}
+
+// CHECK-LABEL: sil private @$S16generic_closures06mixed_A19_nongeneric_nesting1tyx_tlF5outerL_yylF : $@convention(thin) <T> () -> ()
+// CHECK-LABEL: sil private @$S16generic_closures06mixed_A19_nongeneric_nesting1tyx_tlF5outerL_yylF6middleL_1uyqd___tr__lF : $@convention(thin) <T><U> (@in_guaranteed U) -> ()
+// CHECK-LABEL: sil private @$S16generic_closures06mixed_A19_nongeneric_nesting1tyx_tlF5outerL_yylF6middleL_1uyqd___tr__lF5innerL_qd__yr__lF : $@convention(thin) <T><U> (@guaranteed <τ_0_0><τ_1_0> { var τ_1_0 } <T, U>) -> @out U
+
+protocol Doge {
+  associatedtype Nose : NoseProtocol
+}
+
+protocol NoseProtocol {
+  associatedtype Squeegee
+}
+
+protocol Doggo {}
+
+struct DogSnacks<A : Doggo> {}
+
+func capture_same_type_representative<Daisy: Doge, Roo: Doggo>(slobber: Roo, daisy: Daisy)
+    where Roo == Daisy.Nose.Squeegee {
+  var s = DogSnacks<Daisy.Nose.Squeegee>()
+  _ = { _ = s }
+}
diff --git a/test/SILGen/plus_zero_generic_property_base_lifetime.swift b/test/SILGen/plus_zero_generic_property_base_lifetime.swift
new file mode 100644
index 0000000..17f3823
--- /dev/null
+++ b/test/SILGen/plus_zero_generic_property_base_lifetime.swift
@@ -0,0 +1,118 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -emit-silgen %s -disable-objc-attr-requires-foundation-module -enable-sil-ownership | %FileCheck %s
+
+protocol ProtocolA: class {
+    var intProp: Int { get set }
+}
+
+protocol ProtocolB {
+    var intProp: Int { get }
+}
+
+@objc protocol ProtocolO: class {
+    var intProp: Int { get set }
+}
+
+
+// CHECK-LABEL: sil hidden @$S30generic_property_base_lifetime21getIntPropExistentialySiAA9ProtocolA_pF : $@convention(thin) (@guaranteed ProtocolA) -> Int {
+// CHECK: bb0([[ARG:%.*]] : @guaranteed $ProtocolA):
+// CHECK:   [[PROJECTION:%.*]] = open_existential_ref [[ARG]]
+// CHECK:   [[PROJECTION_COPY:%.*]] = copy_value [[PROJECTION]]
+// CHECK:   [[BORROWED_PROJECTION_COPY:%.*]] = begin_borrow [[PROJECTION_COPY]]
+// CHECK:   [[WITNESS_METHOD:%.*]] = witness_method $@opened({{.*}}) ProtocolA, #ProtocolA.intProp!getter.1 : {{.*}}, [[PROJECTION]]
+// CHECK:   [[RESULT:%.*]] = apply [[WITNESS_METHOD]]<@opened{{.*}}>([[BORROWED_PROJECTION_COPY]])
+// CHECK:   end_borrow [[BORROWED_PROJECTION_COPY]] from [[PROJECTION_COPY]]
+// CHECK:   destroy_value [[PROJECTION_COPY]]
+// CHECK:   return [[RESULT]]
+// CHECK: } // end sil function '$S30generic_property_base_lifetime21getIntPropExistentialySiAA9ProtocolA_pF'
+func getIntPropExistential(_ a: ProtocolA) -> Int {
+  return a.intProp
+}
+
+// CHECK-LABEL: sil hidden @$S30generic_property_base_lifetime21setIntPropExistentialyyAA9ProtocolA_pF : $@convention(thin) (@guaranteed ProtocolA) -> () {
+// CHECK: bb0([[ARG:%.*]] : @guaranteed $ProtocolA):
+// CHECK:   [[PROJECTION:%.*]] = open_existential_ref [[ARG]]
+// CHECK:   [[PROJECTION_COPY:%.*]] = copy_value [[PROJECTION]]
+// CHECK:   [[BORROWED_PROJECTION_COPY:%.*]] = begin_borrow [[PROJECTION_COPY]]
+// CHECK:   [[WITNESS_METHOD:%.*]] = witness_method $@opened({{.*}}) ProtocolA, #ProtocolA.intProp!setter.1 : {{.*}}, [[PROJECTION]]
+// CHECK:   apply [[WITNESS_METHOD]]<@opened{{.*}}>({{%.*}}, [[BORROWED_PROJECTION_COPY]])
+// CHECK:   end_borrow [[BORROWED_PROJECTION_COPY]] from [[PROJECTION_COPY]]
+// CHECK:   destroy_value [[PROJECTION_COPY]]
+// CHECK: } // end sil function '$S30generic_property_base_lifetime21setIntPropExistentialyyAA9ProtocolA_pF'
+func setIntPropExistential(_ a: ProtocolA) {
+  a.intProp = 0
+}
+
+// CHECK-LABEL: sil hidden @$S30generic_property_base_lifetime17getIntPropGeneric{{[_0-9a-zA-Z]*}}F
+// CHECK: bb0([[ARG:%.*]] : @guaranteed $T):
+// CHECK:    apply {{%.*}}<T>([[ARG]])
+// CHECK: } // end sil function '$S30generic_property_base_lifetime17getIntPropGeneric{{[_0-9a-zA-Z]*}}F'
+func getIntPropGeneric<T: ProtocolA>(_ a: T) -> Int {
+  return a.intProp
+}
+
+// CHECK-LABEL: sil hidden @$S30generic_property_base_lifetime17setIntPropGeneric{{[_0-9a-zA-Z]*}}F
+// CHECK: bb0([[ARG:%.*]] : @guaranteed $T):
+// CHECK:   apply {{%.*}}<T>({{%.*}}, [[ARG]])
+func setIntPropGeneric<T: ProtocolA>(_ a: T) {
+  a.intProp = 0
+}
+
+// CHECK-LABEL: sil hidden @$S30generic_property_base_lifetime21getIntPropExistentialySiAA9ProtocolB_pF
+// CHECK:         [[PROJECTION:%.*]] = open_existential_addr immutable_access %0
+// CHECK:         [[STACK:%[0-9]+]] = alloc_stack $@opened({{".*"}}) ProtocolB
+// CHECK:         copy_addr [[PROJECTION]] to [initialization] [[STACK]]
+// CHECK:         apply {{%.*}}([[STACK]])
+// CHECK:         destroy_addr [[STACK]]
+// CHECK:         dealloc_stack [[STACK]]
+func getIntPropExistential(_ a: ProtocolB) -> Int {
+  return a.intProp
+}
+
+// CHECK-LABEL: sil hidden @$S30generic_property_base_lifetime17getIntPropGeneric{{[_0-9a-zA-Z]*}}F
+// CHECK:         [[STACK:%[0-9]+]] = alloc_stack $T
+// CHECK:         copy_addr %0 to [initialization] [[STACK]]
+// CHECK:         apply {{%.*}}<T>([[STACK]])
+// CHECK:         destroy_addr [[STACK]]
+// CHECK:         dealloc_stack [[STACK]]
+func getIntPropGeneric<T: ProtocolB>(_ a: T) -> Int {
+  return a.intProp
+}
+
+// CHECK-LABEL: sil hidden @$S30generic_property_base_lifetime21getIntPropExistentialySiAA9ProtocolO_pF : $@convention(thin) (@guaranteed ProtocolO) -> Int {
+// CHECK: bb0([[ARG:%.*]] : @guaranteed $ProtocolO):
+// CHECK:  [[PROJECTION:%.*]] = open_existential_ref [[ARG]]
+// CHECK:  [[PROJECTION_COPY:%.*]] = copy_value [[PROJECTION]]
+// CHECK:  [[METHOD:%.*]] = objc_method [[PROJECTION_COPY]] : $@opened({{.*}}) ProtocolO, #ProtocolO.intProp!getter.1.foreign : {{.*}}
+// CHECK:  apply [[METHOD]]<@opened{{.*}}>([[PROJECTION_COPY]])
+// CHECK:  destroy_value [[PROJECTION_COPY]]
+// CHECK: } // end sil function '$S30generic_property_base_lifetime21getIntPropExistentialySiAA9ProtocolO_pF'
+func getIntPropExistential(_ a: ProtocolO) -> Int {
+  return a.intProp
+}
+
+// CHECK-LABEL: sil hidden @$S30generic_property_base_lifetime21setIntPropExistentialyyAA9ProtocolO_pF : $@convention(thin) (@guaranteed ProtocolO) -> () {
+// CHECK: bb0([[ARG:%.*]] : @guaranteed $ProtocolO):
+// CHECK:   [[PROJECTION:%.*]] = open_existential_ref [[ARG]]
+// CHECK:   [[PROJECTION_COPY:%.*]] = copy_value [[PROJECTION]]
+// CHECK:   [[METHOD:%.*]] = objc_method [[PROJECTION_COPY]] : $@opened({{.*}}) ProtocolO, #ProtocolO.intProp!setter.1.foreign : {{.*}}
+// CHECK:   apply [[METHOD]]<@opened{{.*}}>({{.*}}, [[PROJECTION_COPY]])
+// CHECK:   destroy_value [[PROJECTION_COPY]]
+// CHECK: } // end sil function '$S30generic_property_base_lifetime21setIntPropExistentialyyAA9ProtocolO_pF'
+func setIntPropExistential(_ a: ProtocolO) {
+  a.intProp = 0
+}
+
+// CHECK-LABEL: sil hidden @$S30generic_property_base_lifetime17getIntPropGeneric{{[_0-9a-zA-Z]*}}F
+// CHECK: bb0([[ARG:%.*]] : @guaranteed $T):
+// CHECK:   apply {{%.*}}<T>([[ARG]])
+func getIntPropGeneric<T: ProtocolO>(_ a: T) -> Int {
+  return a.intProp
+}
+
+// CHECK-LABEL: sil hidden @$S30generic_property_base_lifetime17setIntPropGeneric{{[_0-9a-zA-Z]*}}F
+// CHECK: bb0([[ARG:%.*]] : @guaranteed $T):
+// CHECK:   apply {{%.*}}<T>({{%.*}}, [[ARG]])
+func setIntPropGeneric<T: ProtocolO>(_ a: T) {
+  a.intProp = 0
+}
diff --git a/test/SILGen/plus_zero_generic_tuples.swift b/test/SILGen/plus_zero_generic_tuples.swift
new file mode 100644
index 0000000..d3053a1
--- /dev/null
+++ b/test/SILGen/plus_zero_generic_tuples.swift
@@ -0,0 +1,39 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -emit-silgen -parse-as-library -enable-sil-ownership %s | %FileCheck %s
+
+
+func dup<T>(_ x: T) -> (T, T) { return (x,x) }
+// CHECK-LABEL:      sil hidden @$S14generic_tuples3dup{{[_0-9a-zA-Z]*}}F
+// CHECK:      ([[RESULT_0:%.*]] : @trivial $*T, [[RESULT_1:%.*]] : @trivial $*T, [[XVAR:%.*]] : @trivial $*T):
+// CHECK-NEXT: debug_value_addr [[XVAR]] : $*T, let, name "x"
+// CHECK-NEXT: copy_addr [[XVAR]] to [initialization] [[RESULT_0]]
+// CHECK-NEXT: copy_addr [[XVAR]] to [initialization] [[RESULT_1]]
+// CHECK-NEXT: [[T0:%.*]] = tuple ()
+// CHECK-NEXT: return [[T0]]
+
+// <rdar://problem/13822463>
+// Specializing a generic function on a tuple type changes the number of
+// SIL parameters, which caused a failure in the ownership conventions code.
+
+struct Blub {}
+// CHECK-LABEL: sil hidden @$S14generic_tuples3foo{{[_0-9a-zA-Z]*}}F
+func foo<T>(_ x: T) {}
+// CHECK-LABEL: sil hidden @$S14generic_tuples3bar{{[_0-9a-zA-Z]*}}F
+func bar(_ x: (Blub, Blub)) { foo(x) }
+
+
+// rdar://26279628
+//   A type parameter constrained to be a concrete type must be handled
+//   as that concrete type throughout SILGen.  That's especially true
+//   if it's constrained to be a tuple.
+
+protocol HasAssoc {
+  associatedtype A
+}
+extension HasAssoc where A == (Int, Int) {
+  func returnTupleAlias() -> A {
+    return (0, 0)
+  }
+}
+// CHECK-LABEL: sil hidden @$S14generic_tuples8HasAssocPAASi_Sit1ARtzrlE16returnTupleAliasSi_SityF : $@convention(method) <Self where Self : HasAssoc, Self.A == (Int, Int)> (@in_guaranteed Self) -> (Int, Int) {
+// CHECK:       return {{.*}} : $(Int, Int)
diff --git a/test/SILGen/plus_zero_generic_witness.swift b/test/SILGen/plus_zero_generic_witness.swift
new file mode 100644
index 0000000..a450270
--- /dev/null
+++ b/test/SILGen/plus_zero_generic_witness.swift
@@ -0,0 +1,57 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership %s | %FileCheck %s
+// RUN: %target-swift-frontend -emit-ir -enable-sil-ownership %s
+
+protocol Runcible {
+  func runce<A>(_ x: A)
+}
+
+// CHECK-LABEL: sil hidden @$S15generic_witness3foo{{[_0-9a-zA-Z]*}}F : $@convention(thin) <B where B : Runcible> (@in_guaranteed B) -> () {
+
+func foo<B : Runcible>(_ x: B) {
+  // CHECK: [[METHOD:%.*]] = witness_method $B, #Runcible.runce!1 : {{.*}} : $@convention(witness_method: Runcible) <τ_0_0 where τ_0_0 : Runcible><τ_1_0> (@in_guaranteed τ_1_0, @in_guaranteed τ_0_0) -> ()
+  // CHECK: apply [[METHOD]]<B, Int>
+  x.runce(5)
+}
+
+// CHECK-LABEL: sil hidden @$S15generic_witness3bar{{[_0-9a-zA-Z]*}}F : $@convention(thin) (@in_guaranteed Runcible) -> ()
+func bar(_ x: Runcible) {
+  var x = x
+  // CHECK: [[BOX:%.*]] = alloc_box ${ var Runcible }
+  // CHECK: [[TEMP:%.*]] = alloc_stack $Runcible
+  // CHECK: [[EXIST:%.*]] = open_existential_addr immutable_access [[TEMP]] : $*Runcible to $*[[OPENED:@opened(.*) Runcible]]
+  // CHECK: [[METHOD:%.*]] = witness_method $[[OPENED]], #Runcible.runce!1
+  // CHECK: apply [[METHOD]]<[[OPENED]], Int>
+  x.runce(5)
+}
+
+protocol Color {}
+
+protocol Ink {
+    associatedtype Paint
+}
+
+protocol Pen {}
+
+protocol Pencil : Pen {
+    associatedtype Stroke : Pen
+}
+
+protocol Medium {
+    associatedtype Texture : Ink
+
+    func draw<P : Pencil>(paint: Texture.Paint, pencil: P) where P.Stroke == Texture.Paint
+}
+
+struct Canvas<I : Ink> where I.Paint : Pen {
+    typealias Texture = I
+
+    func draw<P : Pencil>(paint: I.Paint, pencil: P) where P.Stroke == Texture.Paint { }
+}
+
+extension Canvas : Medium {}
+
+// CHECK-LABEL: sil private [transparent] [thunk] @$S15generic_witness6CanvasVyxGAA6MediumA2aEP4draw5paint6pencily6StrokeQyd___qd__tAA6PencilRd__7Texture_5PaintQZAKRSlFTW : $@convention(witness_method: Medium) <τ_0_0 where τ_0_0 : Ink><τ_1_0 where τ_1_0 : Pencil, τ_0_0.Paint == τ_1_0.Stroke> (@in_guaranteed τ_0_0.Paint, @in_guaranteed τ_1_0, @in_guaranteed Canvas<τ_0_0>) -> () {
+// CHECK: [[FN:%.*]] = function_ref @$S15generic_witness6CanvasV4draw5paint6pencily5PaintQz_qd__tAA6PencilRd__6StrokeQyd__AHRSlF : $@convention(method) <τ_0_0 where τ_0_0 : Ink><τ_1_0 where τ_1_0 : Pencil, τ_0_0.Paint == τ_1_0.Stroke> (@in_guaranteed τ_0_0.Paint, @in_guaranteed τ_1_0, Canvas<τ_0_0>) -> ()
+// CHECK: apply [[FN]]<τ_0_0, τ_1_0>({{.*}}) : $@convention(method) <τ_0_0 where τ_0_0 : Ink><τ_1_0 where τ_1_0 : Pencil, τ_0_0.Paint == τ_1_0.Stroke> (@in_guaranteed τ_0_0.Paint, @in_guaranteed τ_1_0, Canvas<τ_0_0>) -> ()
+// CHECK: }
diff --git a/test/SILGen/plus_zero_guaranteed_normal_args.swift b/test/SILGen/plus_zero_guaranteed_normal_args.swift
new file mode 100644
index 0000000..fdcec6c
--- /dev/null
+++ b/test/SILGen/plus_zero_guaranteed_normal_args.swift
@@ -0,0 +1,233 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -parse-as-library -module-name Swift -parse-stdlib -emit-silgen -enable-sil-ownership -enable-guaranteed-normal-arguments %s | %FileCheck %s
+
+// This test checks specific codegen related to normal arguments being passed at
+// +0. Eventually, it should be merged into normal SILGen tests.
+
+/////////////////
+// Fake Stdlib //
+/////////////////
+
+precedencegroup AssignmentPrecedence {
+  assignment: true
+}
+
+public protocol ExpressibleByNilLiteral {
+  init(nilLiteral: ())
+}
+
+protocol IteratorProtocol {
+  associatedtype Element
+  mutating func next() ->  Element?
+}
+
+protocol Sequence {
+  associatedtype Element
+  associatedtype Iterator : IteratorProtocol where Iterator.Element == Element
+
+  func makeIterator() -> Iterator
+}
+
+enum Optional<T> {
+case none
+case some(T)
+}
+
+extension Optional : ExpressibleByNilLiteral {
+  public init(nilLiteral: ()) {
+    self = .none
+  }
+}
+
+func _diagnoseUnexpectedNilOptional(_filenameStart: Builtin.RawPointer,
+                                    _filenameLength: Builtin.Word,
+                                    _filenameIsASCII: Builtin.Int1,
+                                    _line: Builtin.Word) {
+  // This would usually contain an assert, but we don't need one since we are
+  // just emitting SILGen.
+}
+
+class Klass {
+  init() {}
+}
+
+struct Buffer {
+  var k: Klass
+  init(inK: Klass) {
+    k = inK
+  }
+}
+
+public typealias AnyObject = Builtin.AnyObject
+
+protocol Protocol {
+  associatedtype AssocType
+  static func useInput(_ input: Builtin.Int32, into processInput: (AssocType) -> ())
+}
+
+struct FakeArray<Element> {
+  // Just to make this type non-trivial
+  var k: Klass
+
+  // We are only interested in this being called. We are not interested in its
+  // implementation.
+  mutating func append(_ t: Element) {}
+}
+
+struct FakeDictionary<Key, Value> {
+}
+
+struct FakeDictionaryIterator<Key, Value> {
+  var dictionary: FakeDictionary<Key, Value>?
+
+  init(_ newDictionary: FakeDictionary<Key, Value>) {
+    dictionary = newDictionary
+  }
+}
+
+extension FakeDictionaryIterator : IteratorProtocol {
+  public typealias Element = (Key, Value)
+  public mutating func next() -> Element? {
+    return .none
+  }
+}
+
+extension FakeDictionary : Sequence {
+  public typealias Element = (Key, Value)
+  public typealias Iterator = FakeDictionaryIterator<Key, Value>
+  public func makeIterator() -> FakeDictionaryIterator<Key, Value> {
+    return FakeDictionaryIterator(self)
+  }
+}
+
+public struct Unmanaged<Instance : AnyObject> {
+  internal unowned(unsafe) var _value: Instance
+}
+
+///////////
+// Tests //
+///////////
+
+class KlassWithBuffer {
+  var buffer: Buffer
+
+  // Make sure that the allocating init forwards into the initializing init at +1.
+  // CHECK-LABEL: sil hidden @$Ss15KlassWithBufferC3inKABs0A0C_tcfC : $@convention(method) (@owned Klass, @thick KlassWithBuffer.Type) -> @owned KlassWithBuffer {
+  // CHECK: bb0([[ARG:%.*]] : @owned $Klass,
+  // CHECK:   [[INITIALIZING_INIT:%.*]] = function_ref @$Ss15KlassWithBufferC3inKABs0A0C_tcfc : $@convention(method) (@owned Klass, @owned KlassWithBuffer) -> @owned KlassWithBuffer
+  // CHECK:   apply [[INITIALIZING_INIT]]([[ARG]],
+  // CHECK: } // end sil function '$Ss15KlassWithBufferC3inKABs0A0C_tcfC'
+  init(inK: Klass = Klass()) {
+    buffer = Buffer(inK: inK)
+  }
+
+  // This test makes sure that we:
+  //
+  // 1. Are able to propagate a +0 value value buffer.k into a +0 value and that
+  // we then copy that +0 value into a +1 value, before we begin the epilog and
+  // then return that value.
+  // CHECK-LABEL: sil hidden @$Ss15KlassWithBufferC03getC14AsNativeObjectBoyF : $@convention(method) (@guaranteed KlassWithBuffer) -> @owned Builtin.NativeObject {
+  // CHECK: bb0([[SELF:%.*]] : @guaranteed $KlassWithBuffer):
+  // CHECK:   [[BUF_BOX:%.*]] = alloc_stack $Buffer
+  // CHECK:   [[METHOD:%.*]] = class_method [[SELF]] : $KlassWithBuffer, #KlassWithBuffer.buffer!getter.1
+  // CHECK:   [[BUF:%.*]] = apply [[METHOD]]([[SELF]])
+  // CHECK:   store [[BUF]] to [init] [[BUF_BOX]]
+  // CHECK:   [[GEP:%.*]] = struct_element_addr [[BUF_BOX]] : $*Buffer, #Buffer.k
+  // CHECK:   [[BUF_KLASS:%.*]] = load [copy] [[GEP]]
+  // CHECK:   destroy_addr [[BUF_BOX]]
+  // CHECK:   [[BORROWED_BUF_KLASS:%.*]] = begin_borrow [[BUF_KLASS]]
+  // CHECK:   [[CASTED_BORROWED_BUF_KLASS:%.*]] = unchecked_ref_cast [[BORROWED_BUF_KLASS]]
+  // CHECK:   [[COPY_CASTED_BORROWED_BUF_KLASS:%.*]] = copy_value [[CASTED_BORROWED_BUF_KLASS]]
+  // CHECK:   end_borrow [[BORROWED_BUF_KLASS]]
+  // CHECK:   destroy_value [[BUF_KLASS]]
+  // CHECK:   return [[COPY_CASTED_BORROWED_BUF_KLASS]]
+  // CHECK: } // end sil function '$Ss15KlassWithBufferC03getC14AsNativeObjectBoyF'
+  func getBufferAsNativeObject() -> Builtin.NativeObject {
+    return Builtin.unsafeCastToNativeObject(buffer.k)
+  }
+}
+
+struct StructContainingBridgeObject {
+  var rawValue: Builtin.BridgeObject
+
+  // CHECK-LABEL: sil hidden @$Ss28StructContainingBridgeObjectV8swiftObjAByXl_tcfC : $@convention(method) (@owned AnyObject, @thin StructContainingBridgeObject.Type) -> @owned StructContainingBridgeObject {
+  // CHECK: bb0([[ARG:%.*]] : @owned $AnyObject,
+  // CHECK:   [[BORROWED_ARG:%.*]] = begin_borrow [[ARG]]
+  // CHECK:   [[CASTED_ARG:%.*]] = unchecked_ref_cast [[BORROWED_ARG]] : $AnyObject to $Builtin.BridgeObject
+  // CHECK:   [[COPY_CASTED_ARG:%.*]] = copy_value [[CASTED_ARG]]
+  // CHECK:   assign [[COPY_CASTED_ARG]] to
+  // CHECK: } // end sil function '$Ss28StructContainingBridgeObjectV8swiftObjAByXl_tcfC'
+  init(swiftObj: AnyObject) {
+    rawValue = Builtin.reinterpretCast(swiftObj)
+  }
+}
+
+struct ReabstractionThunkTest : Protocol {
+  typealias AssocType = Builtin.Int32
+
+  static func useInput(_ input: Builtin.Int32, into processInput: (AssocType) -> ()) {
+    processInput(input)
+  }
+}
+
+// Make sure that we provide a cleanup to x properly before we pass it to
+// result.
+extension FakeDictionary {
+  // CHECK-LABEL: sil hidden @$Ss14FakeDictionaryV20makeSureToCopyTuplesyyF : $@convention(method) <Key, Value> (FakeDictionary<Key, Value>) -> () {
+  // CHECK:   [[X:%.*]] = alloc_stack $(Key, Value), let, name "x"
+  // CHECK:   [[INDUCTION_VAR:%.*]] = unchecked_take_enum_data_addr {{%.*}} : $*Optional<(Key, Value)>, #Optional.some!enumelt.1
+  // CHECK:   [[INDUCTION_VAR_0:%.*]] = tuple_element_addr [[INDUCTION_VAR]] : $*(Key, Value), 0
+  // CHECK:   [[INDUCTION_VAR_1:%.*]] = tuple_element_addr [[INDUCTION_VAR]] : $*(Key, Value), 1
+  // CHECK:   [[X_0:%.*]] = tuple_element_addr [[X]] : $*(Key, Value), 0
+  // CHECK:   [[X_1:%.*]] = tuple_element_addr [[X]] : $*(Key, Value), 1
+  // CHECK:   copy_addr [take] [[INDUCTION_VAR_0]] to [initialization] [[X_0]]
+  // CHECK:   copy_addr [take] [[INDUCTION_VAR_1]] to [initialization] [[X_1]]
+  // CHECK:   [[X_0:%.*]] = tuple_element_addr [[X]] : $*(Key, Value), 0
+  // CHECK:   [[X_1:%.*]] = tuple_element_addr [[X]] : $*(Key, Value), 1
+  // CHECK:   [[TMP_X:%.*]] = alloc_stack $(Key, Value)
+  // CHECK:   [[TMP_X_0:%.*]] = tuple_element_addr [[TMP_X]] : $*(Key, Value), 0
+  // CHECK:   [[TMP_X_1:%.*]] = tuple_element_addr [[TMP_X]] : $*(Key, Value), 1
+  // CHECK:   [[TMP_0:%.*]] = alloc_stack $Key
+  // CHECK:   copy_addr [[X_0]] to [initialization] [[TMP_0]]
+  // CHECK:   copy_addr [take] [[TMP_0]] to [initialization] [[TMP_X_0]]
+  // CHECK:   [[TMP_1:%.*]] = alloc_stack $Value
+  // CHECK:   copy_addr [[X_1]] to [initialization] [[TMP_1]]
+  // CHECK:   copy_addr [take] [[TMP_1]] to [initialization] [[TMP_X_1]]
+  // CHECK:   [[FUNC:%.*]] = function_ref @$Ss9FakeArrayV6appendyyxF : $@convention(method) <τ_0_0> (@in_guaranteed τ_0_0, @inout FakeArray<τ_0_0>) -> ()
+  // CHECK:   apply [[FUNC]]<(Key, Value)>([[TMP_X]],
+  // CHECK: } // end sil function '$Ss14FakeDictionaryV20makeSureToCopyTuplesyyF'
+  func makeSureToCopyTuples() {
+    var result = FakeArray<Element>(k: Klass())
+    for x in self {
+      result.append(x)
+    }
+  }
+}
+
+extension Unmanaged {
+  // Just make sure that we do not crash on this.
+  func unsafeGuaranteedTest<Result>(
+    _ body: (Instance) -> Result
+  ) -> Result {
+    let (guaranteedInstance, token) = Builtin.unsafeGuaranteed(_value)
+    let result = body(guaranteedInstance)
+    Builtin.unsafeGuaranteedEnd(token)
+    return result
+  }
+}
+
+// Make sure that we properly forward x into memory and don't crash.
+public func forwardIntoMemory(fromNative x: AnyObject, y: Builtin.Word) -> Builtin.BridgeObject {
+  // y would normally be 0._builtinWordValue. We don't want to define that
+  // conformance.
+  let object = Builtin.castToBridgeObject(x, y)
+  return object
+}
+
+public struct StructWithOptionalAddressOnlyField<T> {
+  public let newValue: T?
+}
+
+func useStructWithOptionalAddressOnlyField<T>(t: T) -> StructWithOptionalAddressOnlyField<T> {
+  return StructWithOptionalAddressOnlyField<T>(newValue: t)
+}
diff --git a/test/SILGen/plus_zero_guaranteed_self.swift b/test/SILGen/plus_zero_guaranteed_self.swift
new file mode 100644
index 0000000..f8f4faa
--- /dev/null
+++ b/test/SILGen/plus_zero_guaranteed_self.swift
@@ -0,0 +1,557 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -Xllvm -sil-full-demangle -emit-silgen %s -disable-objc-attr-requires-foundation-module -enable-sil-ownership | %FileCheck %s
+
+protocol Fooable {
+  init()
+  func foo(_ x: Int)
+  mutating func bar()
+  mutating func bas()
+
+  var prop1: Int { get set }
+  var prop2: Int { get set }
+  var prop3: Int { get nonmutating set }
+}
+
+protocol Barrable: class {
+  init()
+  func foo(_ x: Int)
+  func bar()
+  func bas()
+
+  var prop1: Int { get set }
+  var prop2: Int { get set }
+  var prop3: Int { get set }
+}
+
+struct S: Fooable {
+  var x: C? // Make the type nontrivial, so +0/+1 is observable.
+
+  // CHECK-LABEL: sil hidden @$S15guaranteed_self1SV{{[_0-9a-zA-Z]*}}fC : $@convention(method) (@thin S.Type) -> @owned S
+  init() {}
+  // TODO: Way too many redundant r/r pairs here. Should use +0 rvalues.
+  // CHECK-LABEL: sil hidden @$S15guaranteed_self1SV3foo{{[_0-9a-zA-Z]*}}F : $@convention(method) (Int, @guaranteed S) -> () {
+  // CHECK:       bb0({{.*}} [[SELF:%.*]] : @guaranteed $S):
+  // CHECK-NOT:     copy_value [[SELF]]
+  // CHECK-NOT:     destroy_value [[SELF]]
+  func foo(_ x: Int) {
+    self.foo(x)
+  }
+
+  func foooo(_ x: (Int, Bool)) {
+    self.foooo(x)
+  }
+
+  // CHECK-LABEL: sil hidden @$S15guaranteed_self1SV3bar{{[_0-9a-zA-Z]*}}F : $@convention(method) (@inout S) -> ()
+  // CHECK:       bb0([[SELF:%.*]] : @trivial $*S):
+  // CHECK-NOT:     destroy_addr [[SELF]]
+  mutating func bar() {
+    self.bar()
+  }
+  // CHECK-LABEL: sil hidden @$S15guaranteed_self1SV3bas{{[_0-9a-zA-Z]*}}F : $@convention(method) (@guaranteed S) -> ()
+  // CHECK:       bb0([[SELF:%.*]] : @guaranteed $S):
+  // CHECK-NOT:     copy_value [[SELF]]
+  // CHECK-NOT:     destroy_value [[SELF]]
+  func bas() {
+    self.bas()
+  }
+
+  var prop1: Int = 0
+
+  // Getter for prop1
+  // CHECK-LABEL: sil hidden [transparent] @$S15guaranteed_self1SV5prop1Sivg : $@convention(method) (@guaranteed S) -> Int
+  // CHECK:       bb0([[SELF:%.*]] : @guaranteed $S):
+  // CHECK-NOT:     destroy_value [[SELF]]
+
+  // Setter for prop1
+  // CHECK-LABEL: sil hidden [transparent] @$S15guaranteed_self1SV5prop1Sivs : $@convention(method) (Int, @inout S) -> ()
+  // CHECK:       bb0({{.*}} [[SELF_ADDR:%.*]] : @trivial $*S):
+  // CHECK-NOT:     load [[SELF_ADDR]]
+  // CHECK-NOT:     destroy_addr [[SELF_ADDR]]
+
+  // materializeForSet for prop1
+  // CHECK-LABEL: sil hidden [transparent] @$S15guaranteed_self1SV5prop1Sivm : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout S) -> (Builtin.RawPointer, Optional<Builtin.RawPointer>)
+  // CHECK:       bb0({{.*}} [[SELF_ADDR:%.*]] : @trivial $*S):
+  // CHECK-NOT:     load [[SELF_ADDR]]
+  // CHECK-NOT:     destroy_addr [[SELF_ADDR]]
+
+  var prop2: Int {
+    // CHECK-LABEL: sil hidden @$S15guaranteed_self1SV5prop2Sivg : $@convention(method) (@guaranteed S) -> Int
+    // CHECK:       bb0([[SELF:%.*]] : @guaranteed $S):
+    // CHECK-NOT:     destroy_value [[SELF]]
+    get { return 0 }
+    // CHECK-LABEL: sil hidden @$S15guaranteed_self1SV5prop2Sivs : $@convention(method) (Int, @inout S) -> ()
+    // CHECK-LABEL: sil hidden [transparent] @$S15guaranteed_self1SV5prop2Sivm : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout S) -> (Builtin.RawPointer, Optional<Builtin.RawPointer>)
+    set { }
+  }
+
+  var prop3: Int {
+    // CHECK-LABEL: sil hidden @$S15guaranteed_self1SV5prop3Sivg : $@convention(method) (@guaranteed S) -> Int
+    // CHECK:       bb0([[SELF:%.*]] : @guaranteed $S):
+    // CHECK-NOT:     destroy_value [[SELF]]
+    get { return 0 }
+    // CHECK-LABEL: sil hidden @$S15guaranteed_self1SV5prop3Sivs : $@convention(method) (Int, @guaranteed S) -> ()
+    // CHECK:       bb0({{.*}} [[SELF:%.*]] : @guaranteed $S):
+    // CHECK-NOT:     destroy_value [[SELF]]
+    // CHECK-LABEL: sil hidden [transparent] @$S15guaranteed_self1SV5prop3Sivm : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @guaranteed S) -> (Builtin.RawPointer, Optional<Builtin.RawPointer>)
+    // CHECK:       bb0({{.*}} [[SELF:%.*]] : @guaranteed $S):
+    // CHECK-NOT:     destroy_value [[SELF]]
+    nonmutating set { }
+  }
+}
+
+// Witness thunk for nonmutating 'foo'
+// CHECK-LABEL: sil private [transparent] [thunk] @$S15guaranteed_self1SVAA7FooableA2aDP3foo{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method: Fooable) (Int, @in_guaranteed S) -> () {
+// CHECK:       bb0({{.*}} [[SELF_ADDR:%.*]] : @trivial $*S):
+// CHECK:         [[SELF:%.*]] = load_borrow [[SELF_ADDR]]
+// CHECK-NOT:     destroy_value [[SELF]]
+// CHECK-NOT:     destroy_addr [[SELF_ADDR]]
+
+// Witness thunk for mutating 'bar'
+// CHECK-LABEL: sil private [transparent] [thunk] @$S15guaranteed_self1SVAA7FooableA2aDP3bar{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method: Fooable) (@inout S) -> () {
+// CHECK:       bb0([[SELF_ADDR:%.*]] : @trivial $*S):
+// CHECK-NOT:     load [[SELF_ADDR]]
+// CHECK-NOT:     destroy_addr [[SELF_ADDR]]
+
+// Witness thunk for 'bas', which is mutating in the protocol, but nonmutating
+// in the implementation
+// CHECK-LABEL: sil private [transparent] [thunk] @$S15guaranteed_self1SVAA7FooableA2aDP3bas{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method: Fooable) (@inout S) -> ()
+// CHECK:       bb0([[SELF_ADDR:%.*]] : @trivial $*S):
+// CHECK:         [[SELF:%.*]] = load_borrow [[SELF_ADDR]]
+// CHECK:         end_borrow [[SELF]]
+// CHECK-NOT:     destroy_value [[SELF]]
+
+// Witness thunk for prop1 getter
+// CHECK-LABEL: sil private [transparent] [thunk] @$S15guaranteed_self1SVAA7FooableA2aDP5prop1SivgTW : $@convention(witness_method: Fooable) (@in_guaranteed S) -> Int
+// CHECK:       bb0([[SELF_ADDR:%.*]] : @trivial $*S):
+// CHECK:         [[SELF:%.*]] = load_borrow [[SELF_ADDR]]
+// CHECK-NOT:     destroy_value [[SELF]]
+// CHECK-NOT:     destroy_value [[SELF]]
+
+// Witness thunk for prop1 setter
+// CHECK-LABEL: sil private [transparent] [thunk] @$S15guaranteed_self1SVAA7FooableA2aDP5prop1SivsTW : $@convention(witness_method: Fooable) (Int, @inout S) -> () {
+// CHECK:       bb0({{.*}} [[SELF_ADDR:%.*]] : @trivial $*S):
+// CHECK-NOT:     destroy_addr [[SELF_ADDR]]
+
+// Witness thunk for prop1 materializeForSet
+// CHECK-LABEL: sil private [transparent] [thunk] @$S15guaranteed_self1SVAA7FooableA2aDP5prop1SivmTW : $@convention(witness_method: Fooable) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout S) -> (Builtin.RawPointer, Optional<Builtin.RawPointer>) {
+// CHECK:       bb0({{.*}} [[SELF_ADDR:%.*]] : @trivial $*S):
+// CHECK-NOT:     destroy_addr [[SELF_ADDR]]
+
+// Witness thunk for prop2 getter
+// CHECK-LABEL: sil private [transparent] [thunk] @$S15guaranteed_self1SVAA7FooableA2aDP5prop2SivgTW : $@convention(witness_method: Fooable) (@in_guaranteed S) -> Int
+// CHECK:       bb0([[SELF_ADDR:%.*]] : @trivial $*S):
+// CHECK:         [[SELF:%.*]] = load_borrow [[SELF_ADDR]]
+// CHECK-NOT:     destroy_value [[SELF]]
+// CHECK-NOT:     destroy_addr [[SELF_ADDR]]
+
+// Witness thunk for prop2 setter
+// CHECK-LABEL: sil private [transparent] [thunk] @$S15guaranteed_self1SVAA7FooableA2aDP5prop2SivsTW : $@convention(witness_method: Fooable) (Int, @inout S) -> () {
+// CHECK:       bb0({{.*}} [[SELF_ADDR:%.*]] : @trivial $*S):
+// CHECK-NOT:     destroy_addr [[SELF_ADDR]]
+
+// Witness thunk for prop2 materializeForSet
+// CHECK-LABEL: sil private [transparent] [thunk] @$S15guaranteed_self1SVAA7FooableA2aDP5prop2SivmTW : $@convention(witness_method: Fooable) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout S) -> (Builtin.RawPointer, Optional<Builtin.RawPointer>) {
+// CHECK:       bb0({{.*}} [[SELF_ADDR:%.*]] : @trivial $*S):
+// CHECK-NOT:     destroy_addr [[SELF_ADDR]]
+
+// Witness thunk for prop3 getter
+// CHECK-LABEL: sil private [transparent] [thunk] @$S15guaranteed_self1SVAA7FooableA2aDP5prop3SivgTW : $@convention(witness_method: Fooable) (@in_guaranteed S) -> Int
+// CHECK:       bb0([[SELF_ADDR:%.*]] : @trivial $*S):
+// CHECK:         [[SELF:%.*]] = load_borrow [[SELF_ADDR]]
+// CHECK-NOT:     destroy_value [[SELF]]
+// CHECK-NOT:     destroy_addr [[SELF_ADDR]]
+
+// Witness thunk for prop3 nonmutating setter
+// CHECK-LABEL: sil private [transparent] [thunk] @$S15guaranteed_self1SVAA7FooableA2aDP5prop3SivsTW : $@convention(witness_method: Fooable) (Int, @in_guaranteed S) -> ()
+// CHECK:       bb0({{.*}} [[SELF_ADDR:%.*]] : @trivial $*S):
+// CHECK:         [[SELF:%.*]] = load_borrow [[SELF_ADDR]]
+// CHECK-NOT:     destroy_value [[SELF]]
+// CHECK-NOT:     destroy_addr [[SELF_ADDR]]
+
+// Witness thunk for prop3 nonmutating materializeForSet
+// CHECK-LABEL: sil private [transparent] [thunk] @$S15guaranteed_self1SVAA7FooableA2aDP5prop3SivmTW : $@convention(witness_method: Fooable) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @in_guaranteed S) -> (Builtin.RawPointer, Optional<Builtin.RawPointer>)
+// CHECK:       bb0({{.*}} [[SELF_ADDR:%.*]] : @trivial $*S):
+// CHECK:         [[SELF:%.*]] = load_borrow [[SELF_ADDR]]
+// CHECK-NOT:     destroy_value [[SELF]]
+// CHECK-NOT:     destroy_addr [[SELF_ADDR]]
+// CHECK:       } // end sil function '$S15guaranteed_self1SVAA7FooableA2aDP5prop3SivmTW'
+
+//
+// TODO: Expected output for the other cases
+//
+
+struct AO<T>: Fooable {
+  var x: T?
+
+  init() {}
+  // CHECK-LABEL: sil hidden @$S15guaranteed_self2AOV3foo{{[_0-9a-zA-Z]*}}F : $@convention(method) <T> (Int, @in_guaranteed AO<T>) -> ()
+  // CHECK:       bb0({{.*}} [[SELF_ADDR:%.*]] : @trivial $*AO<T>):
+  // CHECK:         apply {{.*}} [[SELF_ADDR]]
+  // CHECK-NOT:     destroy_addr [[SELF_ADDR]]
+  // CHECK:       }
+  func foo(_ x: Int) {
+    self.foo(x)
+  }
+  mutating func bar() {
+    self.bar()
+  }
+  // CHECK-LABEL: sil hidden @$S15guaranteed_self2AOV3bas{{[_0-9a-zA-Z]*}}F : $@convention(method) <T> (@in_guaranteed AO<T>) -> ()
+  // CHECK:       bb0([[SELF_ADDR:%.*]] : @trivial $*AO<T>):
+  // CHECK-NOT:     destroy_addr [[SELF_ADDR]]
+  func bas() {
+    self.bas()
+  }
+
+
+  var prop1: Int = 0
+  var prop2: Int {
+    // CHECK-LABEL: sil hidden @$S15guaranteed_self2AOV5prop2Sivg : $@convention(method) <T> (@in_guaranteed AO<T>) -> Int {
+    // CHECK:       bb0([[SELF_ADDR:%.*]] : @trivial $*AO<T>):
+    // CHECK-NOT:     destroy_addr [[SELF_ADDR]]
+    get { return 0 }
+    set { }
+  }
+  var prop3: Int {
+    // CHECK-LABEL: sil hidden @$S15guaranteed_self2AOV5prop3Sivg : $@convention(method) <T> (@in_guaranteed AO<T>) -> Int
+    // CHECK:       bb0([[SELF_ADDR:%.*]] : @trivial $*AO<T>):
+    // CHECK-NOT:     destroy_addr [[SELF_ADDR]]
+    get { return 0 }
+    // CHECK-LABEL: sil hidden @$S15guaranteed_self2AOV5prop3Sivs : $@convention(method) <T> (Int, @in_guaranteed AO<T>) -> ()
+    // CHECK:       bb0({{.*}} [[SELF_ADDR:%.*]] : @trivial $*AO<T>):
+    // CHECK-NOT:     destroy_addr [[SELF_ADDR]]
+    // CHECK-LABEL: sil hidden [transparent] @$S15guaranteed_self2AOV5prop3Sivm : $@convention(method) <T> (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @in_guaranteed AO<T>) -> (Builtin.RawPointer, Optional<Builtin.RawPointer>)
+    // CHECK:       bb0({{.*}} [[SELF_ADDR:%.*]] : @trivial $*AO<T>):
+    // CHECK-NOT:     destroy_addr [[SELF_ADDR]]
+    // CHECK:       }
+    nonmutating set { }
+  }
+}
+
+// Witness for nonmutating 'foo'
+// CHECK-LABEL: sil private [transparent] [thunk] @$S15guaranteed_self2AOVyxGAA7FooableA2aEP3foo{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method: Fooable) <τ_0_0> (Int, @in_guaranteed AO<τ_0_0>) -> ()
+// CHECK:       bb0({{.*}} [[SELF_ADDR:%.*]] : @trivial $*AO<τ_0_0>):
+// CHECK:         apply {{.*}} [[SELF_ADDR]]
+// CHECK-NOT:     destroy_addr [[SELF_ADDR]]
+
+// Witness for 'bar', which is mutating in protocol but nonmutating in impl
+// CHECK-LABEL: sil private [transparent] [thunk] @$S15guaranteed_self2AOVyxGAA7FooableA2aEP3bar{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method: Fooable) <τ_0_0> (@inout AO<τ_0_0>) -> ()
+// CHECK:       bb0([[SELF_ADDR:%.*]] : @trivial $*AO<τ_0_0>):
+// -- NB: This copy is not necessary, since we're willing to assume an inout
+//        parameter is not mutably aliased.
+// CHECK:         apply {{.*}}([[SELF_ADDR]])
+// CHECK-NOT:     destroy_addr [[SELF_ADDR]]
+
+class C: Fooable, Barrable {
+  // Allocating initializer
+  // CHECK-LABEL: sil hidden @$S15guaranteed_self1CC{{[_0-9a-zA-Z]*}}fC : $@convention(method) (@thick C.Type) -> @owned C
+  // CHECK:         [[SELF1:%.*]] = alloc_ref $C
+  // CHECK-NOT:     [[SELF1]]
+  // CHECK:         [[SELF2:%.*]] = apply {{.*}}([[SELF1]])
+  // CHECK-NOT:     [[SELF2]]
+  // CHECK:         return [[SELF2]]
+
+  // Initializing constructors still have the +1 in, +1 out convention.
+  // CHECK-LABEL: sil hidden @$S15guaranteed_self1CC{{[_0-9a-zA-Z]*}}fc : $@convention(method) (@owned C) -> @owned C {
+  // CHECK:       bb0([[SELF:%.*]] : @owned $C):
+  // CHECK:         [[MARKED_SELF:%.*]] = mark_uninitialized [rootself] [[SELF]]
+  // CHECK:         [[MARKED_SELF_RESULT:%.*]] = copy_value [[MARKED_SELF]]
+  // CHECK:         destroy_value [[MARKED_SELF]]
+  // CHECK:         return [[MARKED_SELF_RESULT]]
+  // CHECK:       } // end sil function '$S15guaranteed_self1CC{{[_0-9a-zA-Z]*}}fc'
+
+  // @objc thunk for initializing constructor
+  // CHECK-LABEL: sil hidden [thunk] @$S15guaranteed_self1CC{{[_0-9a-zA-Z]*}}fcTo : $@convention(objc_method) (@owned C) -> @owned C
+  // CHECK:       bb0([[SELF:%.*]] : @owned $C):
+  // CHECK-NOT:     copy_value [[SELF]]
+  // CHECK:         [[SELF2:%.*]] = apply {{%.*}}([[SELF]])
+  // CHECK-NOT:     destroy_value [[SELF]]
+  // CHECK-NOT:     destroy_value [[SELF2]]
+  // CHECK:         return [[SELF2]]
+  // CHECK: } // end sil function '$S15guaranteed_self1CC{{[_0-9a-zA-Z]*}}fcTo'
+  @objc required init() {}
+
+
+  // CHECK-LABEL: sil hidden @$S15guaranteed_self1CC3foo{{[_0-9a-zA-Z]*}}F : $@convention(method) (Int, @guaranteed C) -> ()
+  // CHECK:       bb0({{.*}} [[SELF:%.*]] : @guaranteed $C):
+  // CHECK-NOT:     copy_value
+  // CHECK-NOT:     destroy_value
+  // CHECK:       } // end sil function '$S15guaranteed_self1CC3foo{{[_0-9a-zA-Z]*}}F'
+
+  // CHECK-LABEL: sil hidden [thunk] @$S15guaranteed_self1CC3foo{{[_0-9a-zA-Z]*}}FTo : $@convention(objc_method) (Int, C) -> () {
+  // CHECK:       bb0({{.*}} [[SELF:%.*]] : @unowned $C):
+  // CHECK:         [[SELF_COPY:%.*]] = copy_value [[SELF]]
+  // CHECK:         [[BORROWED_SELF_COPY:%.*]] = begin_borrow [[SELF_COPY]]
+  // CHECK:         apply {{.*}}({{.*}}, [[BORROWED_SELF_COPY]])
+  // CHECK:         end_borrow [[BORROWED_SELF_COPY]] from [[SELF_COPY]]
+  // CHECK:         destroy_value [[SELF_COPY]]
+  // CHECK-NOT:     destroy_value [[SELF_COPY]]
+  // CHECK-NOT:     destroy_value [[SELF]]
+  // CHECK:       } // end sil function '$S15guaranteed_self1CC3foo{{[_0-9a-zA-Z]*}}FTo'
+  @objc func foo(_ x: Int) {
+    self.foo(x)
+  }
+  @objc func bar() {
+    self.bar()
+  }
+  @objc func bas() {
+    self.bas()
+  }
+
+  // CHECK-LABEL: sil hidden [transparent] [thunk] @$S15guaranteed_self1CC5prop1SivgTo : $@convention(objc_method) (C) -> Int
+  // CHECK:       bb0([[SELF:%.*]] : @unowned $C):
+  // CHECK:         [[SELF_COPY:%.*]] = copy_value [[SELF]]
+  // CHECK:         [[BORROWED_SELF_COPY:%.*]] = begin_borrow [[SELF_COPY]]
+  // CHECK:         apply {{.*}}([[BORROWED_SELF_COPY]])
+  // CHECK:         end_borrow [[BORROWED_SELF_COPY]] from [[SELF_COPY]]
+  // CHECK:         destroy_value [[SELF_COPY]]
+  // CHECK-NOT:     destroy_value [[SELF]]
+  // CHECK-NOT:     destroy_value [[SELF_COPY]]
+
+  // CHECK-LABEL: sil hidden [transparent] [thunk] @$S15guaranteed_self1CC5prop1SivsTo : $@convention(objc_method) (Int, C) -> ()
+  // CHECK:       bb0({{.*}} [[SELF:%.*]] : @unowned $C):
+  // CHECK:         [[SELF_COPY:%.*]] = copy_value [[SELF]]
+  // CHECK:         [[BORROWED_SELF_COPY:%.*]] = begin_borrow [[SELF_COPY]]
+  // CHECK:         apply {{.*}} [[BORROWED_SELF_COPY]]
+  // CHECK:         end_borrow [[BORROWED_SELF_COPY]] from [[SELF_COPY]]
+  // CHECK:         destroy_value [[SELF_COPY]]
+  // CHECK-NOT:     destroy_value [[SELF_COPY]]
+  // CHECK-NOT:     destroy_value [[SELF]]
+  // CHECK:       }
+  @objc var prop1: Int = 0
+  @objc var prop2: Int {
+    get { return 0 }
+    set {}
+  }
+  @objc var prop3: Int {
+    get { return 0 }
+    set {}
+  }
+
+}
+
+class D: C {
+  // CHECK-LABEL: sil hidden @$S15guaranteed_self1DC{{[_0-9a-zA-Z]*}}fC : $@convention(method) (@thick D.Type) -> @owned D
+  // CHECK:         [[SELF1:%.*]] = alloc_ref $D
+  // CHECK-NOT:     [[SELF1]]
+  // CHECK:         [[SELF2:%.*]] = apply {{.*}}([[SELF1]])
+  // CHECK-NOT:     [[SELF1]]
+  // CHECK-NOT:     [[SELF2]]
+  // CHECK:         return [[SELF2]]
+
+  // CHECK-LABEL: sil hidden @$S15guaranteed_self1DC{{[_0-9a-zA-Z]*}}fc : $@convention(method) (@owned D) -> @owned D
+  // CHECK:       bb0([[SELF:%.*]] : @owned $D):
+  // CHECK:         [[SELF_BOX:%.*]] = alloc_box ${ var D }
+  // CHECK-NEXT:    [[MARKED_SELF_BOX:%.*]] = mark_uninitialized [derivedself] [[SELF_BOX]]
+  // CHECK-NEXT:    [[PB:%.*]] = project_box [[MARKED_SELF_BOX]]
+  // CHECK-NEXT:    store [[SELF]] to [init] [[PB]]
+  // CHECK-NOT:     [[PB]]
+  // CHECK:         [[SELF1:%.*]] = load [take] [[PB]]
+  // CHECK-NEXT:    [[SUPER1:%.*]] = upcast [[SELF1]]
+  // CHECK-NOT:     [[PB]]
+  // CHECK:         [[SUPER2:%.*]] = apply {{.*}}([[SUPER1]])
+  // CHECK-NEXT:    [[SELF2:%.*]] = unchecked_ref_cast [[SUPER2]]
+  // CHECK-NEXT:    store [[SELF2]] to [init] [[PB]]
+  // CHECK-NOT:     [[PB]]
+  // CHECK-NOT:     [[SELF1]]
+  // CHECK-NOT:     [[SUPER1]]
+  // CHECK-NOT:     [[SELF2]]
+  // CHECK-NOT:     [[SUPER2]]
+  // CHECK:         [[SELF_FINAL:%.*]] = load [copy] [[PB]]
+  // CHECK-NEXT:    destroy_value [[MARKED_SELF_BOX]]
+  // CHECK-NEXT:    return [[SELF_FINAL]]
+  required init() {
+    super.init()
+  }
+
+  // CHECK-LABEL: sil shared [transparent] [serializable] [thunk] @$S15guaranteed_self1DC3foo{{[_0-9a-zA-Z]*}}FTD : $@convention(method) (Int, @guaranteed D) -> ()
+  // CHECK:       bb0({{.*}} [[SELF:%.*]] : @guaranteed $D):
+  // CHECK:         [[SELF_COPY:%.*]] = copy_value [[SELF]]
+  // CHECK:         destroy_value [[SELF_COPY]]
+  // CHECK-NOT:     destroy_value [[SELF_COPY]]
+  // CHECK-NOT:     destroy_value [[SELF]]
+  // CHECK:       }
+  dynamic override func foo(_ x: Int) {
+    self.foo(x)
+  }
+}
+
+func S_curryThunk(_ s: S) -> ((S) -> (Int) -> ()/*, Int -> ()*/) {
+  return (S.foo /*, s.foo*/)
+}
+
+func AO_curryThunk<T>(_ ao: AO<T>) -> ((AO<T>) -> (Int) -> ()/*, Int -> ()*/) {
+  return (AO.foo /*, ao.foo*/)
+}
+
+// ----------------------------------------------------------------------------
+// Make sure that we properly translate in_guaranteed parameters
+// correctly if we are asked to.
+// ----------------------------------------------------------------------------
+
+
+// CHECK-LABEL: sil shared [transparent] [serialized] [thunk] @$S15guaranteed_self9FakeArrayVAA8SequenceA2aDP17_constrainElement{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method: Sequence) (@in_guaranteed FakeElement, @in_guaranteed FakeArray) -> () {
+// CHECK: bb0([[ARG0_PTR:%.*]] : @trivial $*FakeElement, [[ARG1_PTR:%.*]] : @trivial $*FakeArray):
+// CHECK: [[ARG0:%.*]] = load [trivial] [[ARG0_PTR]]
+// CHECK: function_ref (extension in guaranteed_self):guaranteed_self.SequenceDefaults._constrainElement
+// CHECK: [[FUN:%.*]] = function_ref @{{.*}}
+// CHECK: apply [[FUN]]<FakeArray>([[ARG0]], [[ARG1_PTR]])
+
+class Z {}
+
+public struct FakeGenerator {}
+public struct FakeArray {
+  var z = Z()
+}
+public struct FakeElement {}
+
+public protocol FakeGeneratorProtocol {
+  associatedtype Element
+}
+
+extension FakeGenerator : FakeGeneratorProtocol {
+  public typealias Element = FakeElement
+}
+
+public protocol SequenceDefaults {
+  associatedtype Element
+  associatedtype Generator : FakeGeneratorProtocol
+}
+
+extension SequenceDefaults {
+  public func _constrainElement(_: FakeGenerator.Element) {}
+}
+
+public protocol Sequence : SequenceDefaults {
+  func _constrainElement(_: Element)
+}
+
+
+extension FakeArray : Sequence {
+  public typealias Element = FakeElement
+  public typealias Generator = FakeGenerator
+
+  func _containsElement(_: Element) {}
+}
+
+// -----------------------------------------------------------------------------
+// Make sure that we do not emit extra copy_values when accessing let fields of
+// guaranteed parameters.
+// -----------------------------------------------------------------------------
+
+class Kraken {
+  func enrage() {}
+}
+
+func destroyShip(_ k: Kraken) {}
+
+class LetFieldClass {
+  let letk = Kraken()
+  var vark = Kraken()
+
+  // CHECK-LABEL: sil hidden @$S15guaranteed_self13LetFieldClassC10letkMethod{{[_0-9a-zA-Z]*}}F : $@convention(method) (@guaranteed LetFieldClass) -> () {
+  // CHECK: bb0([[CLS:%.*]] : @guaranteed $LetFieldClass):
+  // CHECK: [[KRAKEN_ADDR:%.*]] = ref_element_addr [[CLS]] : $LetFieldClass, #LetFieldClass.letk
+  // CHECK-NEXT: [[WRITE:%.*]] = begin_access [read] [dynamic] [[KRAKEN_ADDR]] : $*Kraken
+  // CHECK-NEXT: [[KRAKEN:%.*]] = load_borrow [[WRITE]]
+  // CHECK-NEXT: end_access [[WRITE]] : $*Kraken
+  // CHECK-NEXT: [[KRAKEN_METH:%.*]] = class_method [[KRAKEN]]
+  // CHECK-NEXT: apply [[KRAKEN_METH]]([[KRAKEN]])
+  // CHECK-NEXT: end_borrow [[KRAKEN]] from [[WRITE]]
+  // CHECK-NEXT: [[KRAKEN_ADDR:%.*]] = ref_element_addr [[CLS]] : $LetFieldClass, #LetFieldClass.letk
+  // CHECK: [[READ:%.*]] = begin_access [read] [dynamic] [[KRAKEN_ADDR]] : $*Kraken
+  // CHECK-NEXT: [[KRAKEN:%.*]] = load [copy] [[READ]]
+  // CHECK-NEXT: end_access [[READ]] : $*Kraken
+  // CHECK:      [[BORROWED_KRAKEN:%.*]] = begin_borrow [[KRAKEN]]
+  // CHECK: [[DESTROY_SHIP_FUN:%.*]] = function_ref @$S15guaranteed_self11destroyShipyyAA6KrakenCF : $@convention(thin) (@guaranteed Kraken) -> ()
+  // CHECK-NEXT: apply [[DESTROY_SHIP_FUN]]([[BORROWED_KRAKEN]])
+  // CHECK-NEXT: end_borrow [[BORROWED_KRAKEN]] from [[KRAKEN]]
+  // CHECK-NEXT: [[KRAKEN_BOX:%.*]] = alloc_box ${ var Kraken }
+  // CHECK-NEXT: [[PB:%.*]] = project_box [[KRAKEN_BOX]]
+  // CHECK-NEXT: [[KRAKEN_ADDR:%.*]] = ref_element_addr [[CLS]] : $LetFieldClass, #LetFieldClass.letk
+  // CHECK-NEXT: [[READ:%.*]] = begin_access [read] [dynamic] [[KRAKEN_ADDR]] : $*Kraken
+  // CHECK-NEXT: [[KRAKEN2:%.*]] = load [copy] [[READ]]
+  // CHECK-NEXT: end_access [[READ]] : $*Kraken
+  // CHECK-NEXT: store [[KRAKEN2]] to [init] [[PB]]
+  // CHECK-NEXT: [[READ:%.*]] = begin_access [read] [unknown] [[PB]] : $*Kraken
+  // CHECK-NEXT: [[KRAKEN_COPY:%.*]] = load [copy] [[READ]]
+  // CHECK-NEXT: end_access [[READ]] : $*Kraken
+  // CHECK-NEXT: [[BORROWED_KRAKEN_COPY:%.*]] = begin_borrow [[KRAKEN_COPY]]
+  // CHECK: [[DESTROY_SHIP_FUN:%.*]] = function_ref @$S15guaranteed_self11destroyShipyyAA6KrakenCF : $@convention(thin) (@guaranteed Kraken) -> ()
+  // CHECK-NEXT: apply [[DESTROY_SHIP_FUN]]([[BORROWED_KRAKEN_COPY]])
+  // CHECK-NEXT: end_borrow [[BORROWED_KRAKEN_COPY]]
+  // CHECK-NEXT: destroy_value [[KRAKEN_COPY]]
+  // CHECK-NEXT: destroy_value [[KRAKEN_BOX]]
+  // CHECK-NEXT: destroy_value [[KRAKEN]]
+  // CHECK-NEXT: tuple
+  // CHECK-NEXT: return
+  func letkMethod() {
+    letk.enrage()
+    let ll = letk
+    destroyShip(ll)
+    var lv = letk
+    destroyShip(lv)
+  }
+
+  // CHECK-LABEL: sil hidden @$S15guaranteed_self13LetFieldClassC10varkMethod{{[_0-9a-zA-Z]*}}F : $@convention(method) (@guaranteed LetFieldClass) -> () {
+  // CHECK: bb0([[CLS:%.*]] : @guaranteed $LetFieldClass):
+  // CHECK: [[KRAKEN_GETTER_FUN:%.*]] = class_method [[CLS]] : $LetFieldClass, #LetFieldClass.vark!getter.1 : (LetFieldClass) -> () -> Kraken, $@convention(method) (@guaranteed LetFieldClass) -> @owned Kraken
+  // CHECK-NEXT: [[KRAKEN:%.*]] = apply [[KRAKEN_GETTER_FUN]]([[CLS]])
+  // CHECK-NEXT: [[BORROWED_KRAKEN:%.*]] = begin_borrow [[KRAKEN]]
+  // CHECK-NEXT: [[KRAKEN_METH:%.*]] = class_method [[BORROWED_KRAKEN]]
+  // CHECK-NEXT: apply [[KRAKEN_METH]]([[BORROWED_KRAKEN]])
+  // CHECK-NEXT: end_borrow [[BORROWED_KRAKEN]] from [[KRAKEN]]
+  // CHECK-NEXT: destroy_value [[KRAKEN]]
+  // CHECK-NEXT: [[KRAKEN_GETTER_FUN:%.*]] = class_method [[CLS]] : $LetFieldClass, #LetFieldClass.vark!getter.1 : (LetFieldClass) -> () -> Kraken, $@convention(method) (@guaranteed LetFieldClass) -> @owned Kraken
+  // CHECK-NEXT: [[KRAKEN:%.*]] = apply [[KRAKEN_GETTER_FUN]]([[CLS]])
+  // CHECK:      [[BORROWED_KRAKEN:%.*]] = begin_borrow [[KRAKEN]]
+  // CHECK: [[DESTROY_SHIP_FUN:%.*]] = function_ref @$S15guaranteed_self11destroyShipyyAA6KrakenCF : $@convention(thin) (@guaranteed Kraken) -> ()
+  // CHECK-NEXT: apply [[DESTROY_SHIP_FUN]]([[BORROWED_KRAKEN]])
+  // CHECK-NEXT: end_borrow [[BORROWED_KRAKEN]] from [[KRAKEN]]
+  // CHECK-NEXT: [[KRAKEN_BOX:%.*]] = alloc_box ${ var Kraken }
+  // CHECK-NEXT: [[PB:%.*]] = project_box [[KRAKEN_BOX]]
+  // CHECK-NEXT: [[KRAKEN_GETTER_FUN:%.*]] = class_method [[CLS]] : $LetFieldClass, #LetFieldClass.vark!getter.1 : (LetFieldClass) -> () -> Kraken, $@convention(method) (@guaranteed LetFieldClass) -> @owned Kraken
+  // CHECK-NEXT: [[KRAKEN2:%.*]] = apply [[KRAKEN_GETTER_FUN]]([[CLS]])
+  // CHECK-NEXT: store [[KRAKEN2]] to [init] [[PB]]
+  // CHECK-NEXT: [[WRITE:%.*]] = begin_access [read] [unknown] [[PB]] : $*Kraken
+  // CHECK-NEXT: [[KRAKEN_COPY:%.*]] = load [copy] [[WRITE]]
+  // CHECK-NEXT: end_access [[WRITE]] : $*Kraken
+  // CHECK-NEXT: [[BORROWED_KRAKEN_COPY:%.*]] = begin_borrow [[KRAKEN_COPY]]
+  // CHECK: [[DESTROY_SHIP_FUN:%.*]] = function_ref @$S15guaranteed_self11destroyShipyyAA6KrakenCF : $@convention(thin) (@guaranteed Kraken) -> ()
+  // CHECK-NEXT: apply [[DESTROY_SHIP_FUN]]([[BORROWED_KRAKEN_COPY]])
+  // CHECK-NEXT: end_borrow [[BORROWED_KRAKEN_COPY]]
+  // CHECK-NEXT: destroy_value [[KRAKEN_COPY]]
+  // CHECK-NEXT: destroy_value [[KRAKEN_BOX]]
+  // CHECK-NEXT: destroy_value [[KRAKEN]]
+  // CHECK-NEXT: tuple
+  // CHECK-NEXT: return
+  func varkMethod() {
+    vark.enrage()
+    let vl = vark
+    destroyShip(vl)
+    var vv = vark
+    destroyShip(vv)
+  }
+}
+
+// -----------------------------------------------------------------------------
+// Make sure that in all of the following cases find has only one copy_value in it.
+// -----------------------------------------------------------------------------
+
+class ClassIntTreeNode {
+  let value : Int
+  let left, right : ClassIntTreeNode
+
+  init() {}
+
+  // CHECK-LABEL: sil hidden @$S15guaranteed_self16ClassIntTreeNodeC4find{{[_0-9a-zA-Z]*}}F : $@convention(method) (Int, @guaranteed ClassIntTreeNode) -> @owned ClassIntTreeNode {
+  // CHECK-NOT: destroy_value
+  // CHECK: copy_value
+  // CHECK-NOT: copy_value
+  // CHECK-NOT: destroy_value
+  // CHECK: return
+  func find(_ v : Int) -> ClassIntTreeNode {
+    if v == value { return self }
+    if v < value { return left.find(v) }
+    return right.find(v)
+  }
+}
diff --git a/test/SILGen/plus_zero_if_while_binding.swift b/test/SILGen/plus_zero_if_while_binding.swift
new file mode 100644
index 0000000..4152501
--- /dev/null
+++ b/test/SILGen/plus_zero_if_while_binding.swift
@@ -0,0 +1,405 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -Xllvm -sil-full-demangle -emit-silgen -enable-sil-ownership %s | %FileCheck %s
+
+func foo() -> String? { return "" }
+func bar() -> String? { return "" }
+
+func a(_ x: String) {}
+func b(_ x: String) {}
+func c(_ x: String) {}
+
+func marker_1() {}
+func marker_2() {}
+func marker_3() {}
+
+
+// CHECK-LABEL: sil hidden @$S16if_while_binding0A8_no_else{{[_0-9a-zA-Z]*}}F
+func if_no_else() {
+  // CHECK:   [[FOO:%.*]] = function_ref @$S16if_while_binding3fooSSSgyF
+  // CHECK:   [[OPT_RES:%.*]] = apply [[FOO]]()
+  // CHECK:   switch_enum [[OPT_RES]] : $Optional<String>, case #Optional.some!enumelt.1: [[YES:bb[0-9]+]], case #Optional.none!enumelt: [[NO:bb[0-9]+]]
+  //
+  // CHECK: [[NO]]:
+  // CHECK:  br [[CONT:bb[0-9]+]]
+  if let x = foo() {
+  // CHECK: [[YES]]([[VAL:%[0-9]+]] : @owned $String):
+  // CHECK:   [[BORROWED_VAL:%.*]] = begin_borrow [[VAL]]
+  // CHECK:   [[A:%.*]] = function_ref @$S16if_while_binding1a
+  // CHECK:   apply [[A]]([[BORROWED_VAL]])
+  // CHECK:   end_borrow [[BORROWED_VAL]] from [[VAL]]
+  // CHECK:   destroy_value [[VAL]]
+  // CHECK:   br [[CONT]]
+    a(x)
+  }
+  // CHECK: [[CONT]]:
+  // CHECK-NEXT:   tuple ()
+}
+// CHECK: } // end sil function '$S16if_while_binding0A8_no_else{{[_0-9a-zA-Z]*}}F'
+
+// CHECK-LABEL: sil hidden @$S16if_while_binding0A11_else_chainyyF : $@convention(thin) () -> () {
+func if_else_chain() {
+  // CHECK:   [[FOO:%.*]] = function_ref @$S16if_while_binding3foo{{[_0-9a-zA-Z]*}}F
+  // CHECK-NEXT:   [[OPT_RES:%.*]] = apply [[FOO]]()
+  // CHECK-NEXT:   switch_enum [[OPT_RES]] : $Optional<String>, case #Optional.some!enumelt.1: [[YESX:bb[0-9]+]], case #Optional.none!enumelt: [[NOX:bb[0-9]+]]
+  if let x = foo() {
+  // CHECK: [[NOX]]:
+  // CHECK:   br [[FAILURE_DESTX:bb[0-9]+]]
+  //
+  // CHECK: [[YESX]]([[VAL:%[0-9]+]] : @owned $String):
+  // CHECK:   debug_value [[VAL]] : $String, let, name "x"
+  // CHECK:   [[BORROWED_VAL:%.*]] = begin_borrow [[VAL]]
+  // CHECK:   [[A:%.*]] = function_ref @$S16if_while_binding1a
+  // CHECK:   apply [[A]]([[BORROWED_VAL]])
+  // CHECK:   end_borrow [[BORROWED_VAL]] from [[VAL]]
+  // CHECK:   destroy_value [[VAL]]
+  // CHECK:   br [[CONT_X:bb[0-9]+]]
+    a(x)
+  //
+  // CHECK: [[FAILURE_DESTX]]:
+  // CHECK:   alloc_box ${ var String }, var, name "y"
+  // CHECK:   switch_enum {{.*}} : $Optional<String>, case #Optional.some!enumelt.1: [[YESY:bb[0-9]+]], case #Optional.none!enumelt: [[ELSE1:bb[0-9]+]]
+    // CHECK: [[ELSE1]]:
+    // CHECK:   dealloc_box {{.*}} ${ var String }
+    // CHECK:   br [[ELSE:bb[0-9]+]]
+  } else if var y = bar() {
+  // CHECK: [[YESY]]([[VAL:%[0-9]+]] : @owned $String):
+  // CHECK:   br [[CONT_Y:bb[0-9]+]]
+  // CHECK: [[CONT_Y]]:
+  // CHECK:   br [[CONT_Y2:bb[0-9]+]]
+    b(y)
+  } else {
+    // CHECK: [[ELSE]]:
+    // CHECK: function_ref if_while_binding.c
+    c("")
+    // CHECK:   br [[CONT_Y2]]
+  }
+
+  // CHECK: [[CONT_Y2]]:
+  //   br [[CONT_X]]
+  // CHECK: [[CONT_X]]:
+}
+
+// CHECK-LABEL: sil hidden @$S16if_while_binding0B5_loopyyF : $@convention(thin) () -> () {
+func while_loop() {
+  // CHECK:   br [[LOOP_ENTRY:bb[0-9]+]]
+  //
+  // CHECK: [[LOOP_ENTRY]]:
+  // CHECK:   switch_enum {{.*}} : $Optional<String>, case #Optional.some!enumelt.1: [[LOOP_BODY:bb[0-9]+]], case #Optional.none!enumelt: [[NO_TRAMPOLINE:bb[0-9]+]]
+  //
+  // CHECK: [[NO_TRAMPOLINE]]:
+  // CHECK:   br [[LOOP_EXIT:bb[0-9]+]]
+  while let x = foo() {
+  // CHECK: [[LOOP_BODY]]([[X:%[0-9]+]] : @owned $String):
+  // CHECK:   switch_enum {{.*}} : $Optional<String>, case #Optional.some!enumelt.1: [[YES:bb[0-9]+]], case #Optional.none!enumelt: [[NO_TRAMPOLINE_2:bb[0-9]+]]
+  //
+  // CHECK: [[NO_TRAMPOLINE_2]]:
+  // CHECK:   br [[FAILURE_DEST_2:bb[0-9]+]]
+    if let y = bar() {
+  // CHECK: [[YES]]([[Y:%[0-9]+]] : @owned $String):
+      a(y)
+      break
+      // CHECK: destroy_value [[Y]]
+      // CHECK: destroy_value [[X]]
+      // CHECK:     br [[LOOP_EXIT]]
+    }
+  // CHECK: [[FAILURE_DEST_2]]:
+  // CHECK:   destroy_value [[X]]
+  // CHECK:   br [[LOOP_ENTRY]]
+  }
+  // CHECK: [[LOOP_EXIT]]:
+  // CHECK-NEXT:   tuple ()
+  // CHECK-NEXT:   return
+}
+
+// Don't leak alloc_stacks for address-only conditional bindings in 'while'.
+// <rdar://problem/16202294>
+// CHECK-LABEL: sil hidden @$S16if_while_binding0B13_loop_generic{{[_0-9a-zA-Z]*}}F
+// CHECK:         br [[COND:bb[0-9]+]]
+// CHECK:       [[COND]]:
+// CHECK:         [[X:%.*]] = alloc_stack $T, let, name "x"
+// CHECK:         [[OPTBUF:%[0-9]+]] = alloc_stack $Optional<T>
+// CHECK:         switch_enum_addr {{.*}}, case #Optional.some!enumelt.1: [[LOOPBODY:bb.*]], case #Optional.none!enumelt: [[OUT:bb[0-9]+]]
+// CHECK:       [[OUT]]:
+// CHECK:         dealloc_stack [[OPTBUF]]
+// CHECK:         dealloc_stack [[X]]
+// CHECK:         br [[DONE:bb[0-9]+]]
+// CHECK:       [[LOOPBODY]]:
+// CHECK:         [[ENUMVAL:%.*]] = unchecked_take_enum_data_addr
+// CHECK:         copy_addr [take] [[ENUMVAL]] to [initialization] [[X]]
+// CHECK:         destroy_addr [[X]]
+// CHECK:         dealloc_stack [[X]]
+// CHECK:         br [[COND]]
+// CHECK:       [[DONE]]:
+// CHECK:         return
+// CHECK: } // end sil function '$S16if_while_binding0B13_loop_generic{{[_0-9a-zA-Z]*}}F'
+func while_loop_generic<T>(_ source: () -> T?) {
+  while let x = source() {
+  }
+}
+
+// <rdar://problem/19382942> Improve 'if let' to avoid optional pyramid of doom
+// CHECK-LABEL: sil hidden @$S16if_while_binding0B11_loop_multiyyF
+func while_loop_multi() {
+  // CHECK:   br [[LOOP_ENTRY:bb[0-9]+]]
+  // CHECK: [[LOOP_ENTRY]]:
+  // CHECK:         switch_enum {{.*}}, case #Optional.some!enumelt.1: [[CHECKBUF2:bb.*]], case #Optional.none!enumelt: [[NONE_TRAMPOLINE:bb[0-9]+]]
+  //
+  // CHECK: [[NONE_TRAMPOLINE]]:
+  // CHECK:   br [[LOOP_EXIT0:bb[0-9]+]]
+
+  // CHECK: [[CHECKBUF2]]([[A:%[0-9]+]] : @owned $String):
+  // CHECK:   debug_value [[A]] : $String, let, name "a"
+
+  // CHECK:   switch_enum {{.*}}, case #Optional.some!enumelt.1: [[LOOP_BODY:bb.*]], case #Optional.none!enumelt: [[LOOP_EXIT2a:bb[0-9]+]]
+
+  // CHECK: [[LOOP_EXIT2a]]:
+  // CHECK: destroy_value [[A]]
+  // CHECK: br [[LOOP_EXIT0]]
+
+  // CHECK: [[LOOP_BODY]]([[B:%[0-9]+]] : @owned $String):
+  while let a = foo(), let b = bar() {
+    // CHECK:   debug_value [[B]] : $String, let, name "b"
+    // CHECK:   [[BORROWED_A:%.*]] = begin_borrow [[A]]
+    // CHECK:   [[A_COPY:%.*]] = copy_value [[BORROWED_A]]
+    // CHECK:   debug_value [[A_COPY]] : $String, let, name "c"
+    // CHECK:   end_borrow [[BORROWED_A]] from [[A]]
+    // CHECK:   destroy_value [[A_COPY]]
+    // CHECK:   destroy_value [[B]]
+    // CHECK:   destroy_value [[A]]
+    // CHECK:   br [[LOOP_ENTRY]]
+    let c = a
+  }
+  // CHECK: [[LOOP_EXIT0]]:
+  // CHECK-NEXT:   tuple ()
+  // CHECK-NEXT:   return
+}
+
+// CHECK-LABEL: sil hidden @$S16if_while_binding0A6_multiyyF
+func if_multi() {
+  // CHECK:   switch_enum {{.*}}, case #Optional.some!enumelt.1: [[CHECKBUF2:bb.*]], case #Optional.none!enumelt: [[NONE_TRAMPOLINE:bb[0-9]+]]
+  //
+  // CHECK: [[NONE_TRAMPOLINE]]:
+  // CHECK:   br [[IF_DONE:bb[0-9]+]]
+
+  // CHECK: [[CHECKBUF2]]([[A:%[0-9]+]] : @owned $String):
+  // CHECK:   debug_value [[A]] : $String, let, name "a"
+  // CHECK:   [[B:%[0-9]+]] = alloc_box ${ var String }, var, name "b"
+  // CHECK:   [[PB:%[0-9]+]] = project_box [[B]]
+  // CHECK:   switch_enum {{.*}}, case #Optional.some!enumelt.1: [[IF_BODY:bb.*]], case #Optional.none!enumelt: [[IF_EXIT1a:bb[0-9]+]]
+
+  // CHECK: [[IF_EXIT1a]]:
+  // CHECK:   dealloc_box {{.*}} ${ var String }
+  // CHECK:   destroy_value [[A]]
+  // CHECK:   br [[IF_DONE]]
+
+  // CHECK: [[IF_BODY]]([[BVAL:%[0-9]+]] : @owned $String):
+  if let a = foo(), var b = bar() {
+    // CHECK:   store [[BVAL]] to [init] [[PB]] : $*String
+    // CHECK:   debug_value {{.*}} : $String, let, name "c"
+    // CHECK:   destroy_value [[B]]
+    // CHECK:   destroy_value [[A]]
+    // CHECK:   br [[IF_DONE]]
+    let c = a
+  }
+  // CHECK: [[IF_DONE]]:
+  // CHECK-NEXT:   tuple ()
+  // CHECK-NEXT:   return
+}
+
+// CHECK-LABEL: sil hidden @$S16if_while_binding0A11_multi_elseyyF
+func if_multi_else() {
+  // CHECK:   switch_enum {{.*}}, case #Optional.some!enumelt.1: [[CHECKBUF2:bb.*]], case #Optional.none!enumelt: [[NONE_TRAMPOLINE:bb[0-9]+]]
+  //
+  // CHECK: [[NONE_TRAMPOLINE]]:
+  // CHECK:   br [[ELSE:bb[0-9]+]]
+  // CHECK: [[CHECKBUF2]]([[A:%[0-9]+]] : @owned $String):
+  // CHECK:   debug_value [[A]] : $String, let, name "a"
+  // CHECK:   [[B:%[0-9]+]] = alloc_box ${ var String }, var, name "b"
+  // CHECK:   [[PB:%[0-9]+]] = project_box [[B]]
+  // CHECK:   switch_enum {{.*}}, case #Optional.some!enumelt.1: [[IF_BODY:bb.*]], case #Optional.none!enumelt: [[IF_EXIT1a:bb[0-9]+]]
+  
+    // CHECK: [[IF_EXIT1a]]:
+    // CHECK:   dealloc_box {{.*}} ${ var String }
+    // CHECK:   destroy_value [[A]]
+    // CHECK:   br [[ELSE]]
+
+  // CHECK: [[IF_BODY]]([[BVAL:%[0-9]+]] : @owned $String):
+  if let a = foo(), var b = bar() {
+    // CHECK:   store [[BVAL]] to [init] [[PB]] : $*String
+    // CHECK:   debug_value {{.*}} : $String, let, name "c"
+    // CHECK:   destroy_value [[B]]
+    // CHECK:   destroy_value [[A]]
+    // CHECK:   br [[IF_DONE:bb[0-9]+]]
+    let c = a
+  } else {
+    let d = 0
+    // CHECK: [[ELSE]]:
+    // CHECK:   debug_value {{.*}} : $Int, let, name "d"
+    // CHECK:   br [[IF_DONE]]
+ }
+  // CHECK: [[IF_DONE]]:
+  // CHECK-NEXT:   tuple ()
+  // CHECK-NEXT:   return
+}
+
+// CHECK-LABEL: sil hidden @$S16if_while_binding0A12_multi_whereyyF
+func if_multi_where() {
+  // CHECK:   switch_enum {{.*}}, case #Optional.some!enumelt.1: [[CHECKBUF2:bb.*]], case #Optional.none!enumelt: [[NONE_TRAMPOLINE:bb[0-9]+]]
+  //
+  // CHECK: [[NONE_TRAMPOLINE]]:
+  // CHECK:   br [[ELSE:bb[0-9]+]]
+  // CHECK: [[CHECKBUF2]]([[A:%[0-9]+]] : @owned $String):
+  // CHECK:   debug_value [[A]] : $String, let, name "a"
+  // CHECK:   [[BBOX:%[0-9]+]] = alloc_box ${ var String }, var, name "b"
+  // CHECK:   [[PB:%[0-9]+]] = project_box [[BBOX]]
+  // CHECK:   switch_enum {{.*}}, case #Optional.some!enumelt.1: [[CHECK_WHERE:bb.*]], case #Optional.none!enumelt: [[IF_EXIT1a:bb[0-9]+]]
+  // CHECK: [[IF_EXIT1a]]:
+  // CHECK:   dealloc_box {{.*}} ${ var String }
+  // CHECK:   destroy_value [[A]]
+  // CHECK:   br [[ELSE]]
+
+  // CHECK: [[CHECK_WHERE]]([[B:%[0-9]+]] : @owned $String):
+  // CHECK:   function_ref Swift.Bool._getBuiltinLogicValue() -> Builtin.Int1
+  // CHECK:   cond_br {{.*}}, [[IF_BODY:bb[0-9]+]], [[IF_EXIT3:bb[0-9]+]]
+  // CHECK: [[IF_EXIT3]]:
+  // CHECK:   destroy_value [[BBOX]]
+  // CHECK:   destroy_value [[A]]
+  // CHECK:   br [[IF_DONE:bb[0-9]+]]
+  if let a = foo(), var b = bar(), a == b {
+    // CHECK: [[IF_BODY]]:
+    // CHECK:   destroy_value [[BBOX]]
+    // CHECK:   destroy_value [[A]]
+    // CHECK:   br [[IF_DONE]]
+    let c = a
+  }
+  // CHECK: [[IF_DONE]]:
+  // CHECK-NEXT:   tuple ()
+  // CHECK-NEXT:   return
+}
+
+
+// <rdar://problem/19797158> Swift 1.2's "if" has 2 behaviors. They could be unified.
+// CHECK-LABEL: sil hidden @$S16if_while_binding0A16_leading_booleanyySiF
+func if_leading_boolean(_ a : Int) {
+  // Test the boolean condition.
+  
+  // CHECK: debug_value %0 : $Int, let, name "a"
+  // CHECK: [[EQRESULT:%[0-9]+]] = apply {{.*}}(%0, %0{{.*}}) : $@convention({{.*}}) (Int, Int{{.*}}) -> Bool
+
+  // CHECK:      [[FN:%.*]] = function_ref {{.*}}
+  // CHECK-NEXT: [[EQRESULTI1:%[0-9]+]] = apply [[FN:%.*]]([[EQRESULT]]) : $@convention(method) (Bool) -> Builtin.Int1
+  // CHECK-NEXT: cond_br [[EQRESULTI1]], [[CHECKFOO:bb[0-9]+]], [[IFDONE:bb[0-9]+]]
+
+  // Call Foo and test for the optional being present.
+// CHECK: [[CHECKFOO]]:
+  // CHECK: [[OPTRESULT:%[0-9]+]] = apply {{.*}}() : $@convention(thin) () -> @owned Optional<String>
+  
+  // CHECK:   switch_enum [[OPTRESULT]] : $Optional<String>, case #Optional.some!enumelt.1: [[SUCCESS:bb.*]], case #Optional.none!enumelt: [[IF_DONE:bb[0-9]+]]
+
+// CHECK: [[SUCCESS]]([[B:%[0-9]+]] : @owned $String):
+  // CHECK:   debug_value [[B]] : $String, let, name "b"
+  // CHECK:   [[BORROWED_B:%.*]] = begin_borrow [[B]]
+  // CHECK:   [[B_COPY:%.*]] = copy_value [[BORROWED_B]]
+  // CHECK:   debug_value [[B_COPY]] : $String, let, name "c"
+  // CHECK:   end_borrow [[BORROWED_B]] from [[B]]
+  // CHECK:   destroy_value [[B_COPY]]
+  // CHECK:   destroy_value [[B]]
+  // CHECK:   br [[IFDONE]]
+  if a == a, let b = foo() {
+    let c = b
+  }
+  // CHECK: [[IFDONE]]:
+  // CHECK-NEXT: tuple ()
+
+}
+
+
+/// <rdar://problem/20364869> Assertion failure when using 'as' pattern in 'if let'
+class BaseClass {}
+class DerivedClass : BaseClass {}
+
+// CHECK-LABEL: sil hidden @$S16if_while_binding20testAsPatternInIfLetyyAA9BaseClassCSgF
+func testAsPatternInIfLet(_ a : BaseClass?) {
+  // CHECK: bb0([[ARG:%.*]] : @guaranteed $Optional<BaseClass>):
+  // CHECK:   debug_value [[ARG]] : $Optional<BaseClass>, let, name "a"
+  // CHECK:   [[ARG_COPY:%.*]] = copy_value [[ARG]] : $Optional<BaseClass>
+  // CHECK:   switch_enum [[ARG_COPY]] : $Optional<BaseClass>, case #Optional.some!enumelt.1: [[OPTPRESENTBB:bb[0-9]+]], case #Optional.none!enumelt: [[NILBB:bb[0-9]+]]
+
+  // CHECK: [[NILBB]]:
+  // CHECK:   br [[EXITBB:bb[0-9]+]]
+
+  // CHECK: [[OPTPRESENTBB]]([[CLS:%.*]] : @owned $BaseClass):
+  // CHECK:   checked_cast_br [[CLS]] : $BaseClass to $DerivedClass, [[ISDERIVEDBB:bb[0-9]+]], [[ISBASEBB:bb[0-9]+]]
+
+  // CHECK: [[ISDERIVEDBB]]([[DERIVED_CLS:%.*]] : @owned $DerivedClass):
+  // CHECK:   [[DERIVED_CLS_SOME:%.*]] = enum $Optional<DerivedClass>, #Optional.some!enumelt.1, [[DERIVED_CLS]] : $DerivedClass
+  // CHECK:   br [[MERGE:bb[0-9]+]]([[DERIVED_CLS_SOME]] : $Optional<DerivedClass>)
+
+  // CHECK: [[ISBASEBB]]([[BASECLASS:%.*]] : @owned $BaseClass):
+  // CHECK:   destroy_value [[BASECLASS]] : $BaseClass
+  // CHECK:   = enum $Optional<DerivedClass>, #Optional.none!enumelt
+  // CHECK:   br [[MERGE]](
+
+  // CHECK: [[MERGE]]([[OPTVAL:%[0-9]+]] : @owned $Optional<DerivedClass>):
+  // CHECK:    switch_enum [[OPTVAL]] : $Optional<DerivedClass>, case #Optional.some!enumelt.1: [[ISDERIVEDBB:bb[0-9]+]], case #Optional.none!enumelt: [[NILBB:bb[0-9]+]]
+
+  // CHECK: [[ISDERIVEDBB]]([[DERIVEDVAL:%[0-9]+]] : @owned $DerivedClass):
+  // CHECK:   debug_value [[DERIVEDVAL]] : $DerivedClass
+  // => SEMANTIC SIL TODO: This is benign, but scoping wise, this end borrow should be after derived val.
+  // CHECK:   destroy_value [[DERIVEDVAL]] : $DerivedClass
+  // CHECK:   br [[EXITBB]]
+  
+  // CHECK: [[EXITBB]]:
+  // CHECK:   tuple ()
+  // CHECK:   return
+  if case let b as DerivedClass = a {
+
+  }
+}
+
+// <rdar://problem/22312114> if case crashes swift - bools not supported in let/else yet
+// CHECK-LABEL: sil hidden @$S16if_while_binding12testCaseBoolyySbSgF
+func testCaseBool(_ value : Bool?) {
+  // CHECK: bb0([[ARG:%.*]] : @trivial $Optional<Bool>):
+  // CHECK: switch_enum [[ARG]] : $Optional<Bool>, case #Optional.some!enumelt.1: [[SOME_BB:bb[0-9]+]], case #Optional.none!enumelt: [[NONE_TRAMPOLINE:bb[0-9]+]]
+  //
+  // CHECK: [[NONE_TRAMPOLINE]]:
+  // CHECK:   br [[CONT_BB:bb[0-9]+]]
+  //
+  // CHECK: [[SOME_BB]]([[PAYLOAD:%.*]] : @trivial $Bool):
+  // CHECK:   [[ISTRUE:%[0-9]+]] = struct_extract [[PAYLOAD]] : $Bool, #Bool._value
+  // CHECK:   cond_br [[ISTRUE]], [[TRUE_TRAMPOLINE_BB:bb[0-9]+]], [[CONT_BB]]
+  //
+  // CHECK: [[TRUE_TRAMPOLINE_BB:bb[0-9]+]]
+  // CHECK:   br [[TRUE_BB:bb[0-9]+]]
+  //
+  // CHECK: [[TRUE_BB]]:
+  // CHECK:   function_ref @$S16if_while_binding8marker_1yyF
+  // CHECK:   br [[CONT_BB]]
+  if case true? = value {
+    marker_1()
+  }
+
+  // CHECK: [[CONT_BB]]:
+  // CHECK:   switch_enum [[ARG]] : $Optional<Bool>, case #Optional.some!enumelt.1: [[SUCC_BB_2:bb[0-9]+]], case #Optional.none!enumelt: [[NO_TRAMPOLINE_2:bb[0-9]+]]
+
+  // CHECK: [[NO_TRAMPOLINE_2]]:
+  // CHECK:   br [[EPILOG_BB:bb[0-9]+]]
+
+  // CHECK: [[SUCC_BB_2]]([[PAYLOAD2:%.*]] : @trivial $Bool):
+  // CHECK:   [[ISTRUE:%[0-9]+]] = struct_extract [[PAYLOAD2]] : $Bool, #Bool._value
+  // CHECK:   cond_br [[ISTRUE]], [[EPILOG_BB]], [[FALSE2_TRAMPOLINE_BB:bb[0-9]+]]
+
+  // CHECK: [[FALSE2_TRAMPOLINE_BB]]:
+  // CHECK:   br [[FALSE2_BB:bb[0-9]+]]
+  //
+  // CHECK: [[FALSE2_BB]]:
+  // CHECK:   function_ref @$S16if_while_binding8marker_2yyF
+  // CHECK:   br [[EPILOG_BB]]
+
+  // CHECK: [[EPILOG_BB]]:
+  // CHECK:   return
+  if case false? = value {
+    marker_2()
+  }
+}
diff --git a/test/SILGen/plus_zero_implicitly_unwrapped_optional.swift b/test/SILGen/plus_zero_implicitly_unwrapped_optional.swift
new file mode 100644
index 0000000..55f3112
--- /dev/null
+++ b/test/SILGen/plus_zero_implicitly_unwrapped_optional.swift
@@ -0,0 +1,81 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership %s | %FileCheck %s
+
+func foo(f f: (() -> ())!) {
+  var f: (() -> ())! = f
+  f?()
+}
+// CHECK: sil hidden @{{.*}}foo{{.*}} : $@convention(thin) (@guaranteed Optional<@callee_guaranteed () -> ()>) -> () {
+// CHECK: bb0([[T0:%.*]] : @guaranteed $Optional<@callee_guaranteed () -> ()>):
+// CHECK:   [[F:%.*]] = alloc_box ${ var Optional<@callee_guaranteed () -> ()> }
+// CHECK:   [[PF:%.*]] = project_box [[F]]
+// CHECK:   [[T0_COPY:%.*]] = copy_value [[T0]]
+// CHECK:   store [[T0_COPY]] to [init] [[PF]]
+// CHECK:   [[READ:%.*]] = begin_access [read] [unknown] [[PF]] : $*Optional<@callee_guaranteed () -> ()>
+// CHECK:   [[T1:%.*]] = select_enum_addr [[READ]]
+// CHECK:   cond_br [[T1]], bb2, bb1
+//   If it does, project and load the value out of the implicitly unwrapped
+//   optional...
+// CHECK:    bb2:
+// CHECK-NEXT: [[FN0_ADDR:%.*]] = unchecked_take_enum_data_addr [[READ]]
+// CHECK-NEXT: [[FN0:%.*]] = load [copy] [[FN0_ADDR]]
+//   .... then call it
+// CHECK:   [[B:%.*]] = begin_borrow [[FN0]]
+// CHECK:   apply [[B]]() : $@callee_guaranteed () -> ()
+// CHECK:   end_borrow [[B]]
+// CHECK:   br bb3
+// CHECK: bb3(
+// CHECK:   destroy_value [[F]]
+// CHECK:   return
+// CHECK: bb4:
+// CHECK:   enum $Optional<()>, #Optional.none!enumelt
+// CHECK:   br bb3
+//   The rest of this is tested in optional.swift
+// } // end sil function '{{.*}}foo{{.*}}'
+
+func wrap<T>(x x: T) -> T! { return x }
+
+// CHECK-LABEL: sil hidden @$S29implicitly_unwrapped_optional16wrap_then_unwrap{{[_0-9a-zA-Z]*}}F
+func wrap_then_unwrap<T>(x x: T) -> T {
+  // CHECK:   switch_enum_addr {{%.*}}, case #Optional.some!enumelt.1: [[OK:bb[0-9]+]], case #Optional.none!enumelt: [[FAIL:bb[0-9]+]]
+  // CHECK: [[FAIL]]:
+  // CHECK:   unreachable
+  // CHECK: [[OK]]:
+  return wrap(x: x)!
+}
+
+// CHECK-LABEL: sil hidden @$S29implicitly_unwrapped_optional10tuple_bind1xSSSgSi_SStSg_tF : $@convention(thin) (@guaranteed Optional<(Int, String)>) -> @owned Optional<String> {
+func tuple_bind(x x: (Int, String)!) -> String? {
+  return x?.1
+  // CHECK:   cond_br {{%.*}}, [[NONNULL:bb[0-9]+]], [[NULL:bb[0-9]+]]
+  // CHECK: [[NONNULL]]:
+  // CHECK:   [[STRING:%.*]] = tuple_extract {{%.*}} : $(Int, String), 1
+  // CHECK-NOT: destroy_value [[STRING]]
+}
+
+// CHECK-LABEL: sil hidden @$S29implicitly_unwrapped_optional011tuple_bind_a1_B01xSSSi_SStSg_tF
+func tuple_bind_implicitly_unwrapped(x x: (Int, String)!) -> String {
+  return x.1
+}
+
+func return_any() -> AnyObject! { return nil }
+func bind_any() {
+  let object : AnyObject? = return_any()
+}
+
+// CHECK-LABEL: sil hidden @$S29implicitly_unwrapped_optional6sr3758yyF
+func sr3758() {
+  // Verify that there are no additional reabstractions introduced.
+  // CHECK: [[CLOSURE:%.+]] = function_ref @$S29implicitly_unwrapped_optional6sr3758yyFyypSgcfU_ : $@convention(thin) (@in_guaranteed Optional<Any>) -> ()
+  // CHECK: [[F:%.+]] = thin_to_thick_function [[CLOSURE]] : $@convention(thin) (@in_guaranteed Optional<Any>) -> () to $@callee_guaranteed (@in_guaranteed Optional<Any>) -> ()
+  // CHECK: [[BORROWED_F:%.*]] = begin_borrow [[F]]
+  // CHECK: [[CALLEE:%.+]] = copy_value [[BORROWED_F]] : $@callee_guaranteed (@in_guaranteed Optional<Any>) -> ()
+  // CHECK: [[BORROWED_CALLEE:%.*]] = begin_borrow [[CALLEE]]
+  // CHECK: = apply [[BORROWED_CALLEE]]({{%.+}}) : $@callee_guaranteed (@in_guaranteed Optional<Any>) -> ()
+  // CHECK: end_borrow [[BORROWED_CALLEE]]
+  // destroy_value [[CALLEE]]
+  // CHECK: end_borrow [[BORROWED_F]] from [[F]]
+  // CHECK: destroy_value [[F]]
+  let f: ((Any?) -> Void) = { (arg: Any!) in }
+  f(nil)
+} // CHECK: end sil function '$S29implicitly_unwrapped_optional6sr3758yyF'
diff --git a/test/SILGen/plus_zero_indirect_enum.swift b/test/SILGen/plus_zero_indirect_enum.swift
new file mode 100644
index 0000000..2d609f0
--- /dev/null
+++ b/test/SILGen/plus_zero_indirect_enum.swift
@@ -0,0 +1,518 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -Xllvm -sil-print-debuginfo -emit-silgen %s | %FileCheck %s
+
+indirect enum TreeA<T> {
+  case Nil
+  case Leaf(T)
+  case Branch(left: TreeA<T>, right: TreeA<T>)
+}
+
+// CHECK-LABEL: sil hidden @$S13indirect_enum11TreeA_cases_1l1ryx_AA0C1AOyxGAGtlF : $@convention(thin) <T> (@in_guaranteed T, @guaranteed TreeA<T>, @guaranteed TreeA<T>) -> () {
+func TreeA_cases<T>(_ t: T, l: TreeA<T>, r: TreeA<T>) {
+// CHECK: bb0([[ARG1:%.*]] : $*T, [[ARG2:%.*]] : $TreeA<T>, [[ARG3:%.*]] : $TreeA<T>):
+// CHECK:         [[METATYPE:%.*]] = metatype $@thin TreeA<T>.Type
+// CHECK-NEXT:    [[NIL:%.*]] = enum $TreeA<T>, #TreeA.Nil!enumelt
+// CHECK-NOT:     destroy_value [[NIL]]
+  let _ = TreeA<T>.Nil
+
+// CHECK-NEXT:    [[METATYPE:%.*]] = metatype $@thin TreeA<T>.Type
+// CHECK-NEXT:    [[BOX:%.*]] = alloc_box $<τ_0_0> { var τ_0_0 } <T>
+// CHECK-NEXT:    [[PB:%.*]] = project_box [[BOX]]
+// CHECK-NEXT:    copy_addr [[ARG1]] to [initialization] [[PB]]
+// CHECK-NEXT:    [[LEAF:%.*]] = enum $TreeA<T>, #TreeA.Leaf!enumelt.1, [[BOX]]
+// CHECK-NEXT:    destroy_value [[LEAF]]
+  let _ = TreeA<T>.Leaf(t)
+
+// CHECK-NEXT:    [[METATYPE:%.*]] = metatype $@thin TreeA<T>.Type
+// CHECK-NEXT:    [[BOX:%.*]] = alloc_box $<τ_0_0> { var (left: TreeA<τ_0_0>, right: TreeA<τ_0_0>) } <T>
+// CHECK-NEXT:    [[PB:%.*]] = project_box [[BOX]]
+// CHECK-NEXT:    [[LEFT:%.*]] = tuple_element_addr [[PB]] : $*(left: TreeA<T>, right: TreeA<T>), 0
+// CHECK-NEXT:    [[RIGHT:%.*]] = tuple_element_addr [[PB]] : $*(left: TreeA<T>, right: TreeA<T>), 1
+// CHECK-NEXT:    [[ARG2_COPY:%.*]] = copy_value [[ARG2]]
+// CHECK-NEXT:    store [[ARG2_COPY]] to [init] [[LEFT]]
+// CHECK-NEXT:    [[ARG3_COPY:%.*]] = copy_value [[ARG3]]
+// CHECK-NEXT:    store [[ARG3_COPY]] to [init] [[RIGHT]]
+// CHECK-NEXT:    [[BRANCH:%.*]] = enum $TreeA<T>, #TreeA.Branch!enumelt.1, [[BOX]]
+// CHECK-NEXT:    destroy_value [[BRANCH]]
+  let _ = TreeA<T>.Branch(left: l, right: r)
+
+}
+// CHECK: // end sil function '$S13indirect_enum11TreeA_cases_1l1ryx_AA0C1AOyxGAGtlF'
+
+
+// CHECK-LABEL: sil hidden @$S13indirect_enum16TreeA_reabstractyyS2icF : $@convention(thin) (@guaranteed @callee_guaranteed (Int) -> Int) -> () {
+func TreeA_reabstract(_ f: @escaping (Int) -> Int) {
+// CHECK: bb0([[ARG:%.*]] : $@callee_guaranteed (Int) -> Int):
+// CHECK:         [[METATYPE:%.*]] = metatype $@thin TreeA<(Int) -> Int>.Type
+// CHECK-NEXT:    [[BOX:%.*]] = alloc_box $<τ_0_0> { var τ_0_0 } <(Int) -> Int>
+// CHECK-NEXT:    [[PB:%.*]] = project_box [[BOX]]
+// CHECK-NEXT:    [[ARG_COPY:%.*]] = copy_value [[ARG]]
+// CHECK:         [[THUNK:%.*]] = function_ref @$SS2iIegyd_S2iIegnr_TR
+// CHECK-NEXT:    [[FN:%.*]] = partial_apply [callee_guaranteed] [[THUNK]]([[ARG_COPY]])
+// CHECK-NEXT:    store [[FN]] to [init] [[PB]]
+// CHECK-NEXT:    [[LEAF:%.*]] = enum $TreeA<(Int) -> Int>, #TreeA.Leaf!enumelt.1, [[BOX]]
+// CHECK-NEXT:    destroy_value [[LEAF]]
+// CHECK: return
+  let _ = TreeA<(Int) -> Int>.Leaf(f)
+}
+// CHECK: } // end sil function '$S13indirect_enum16TreeA_reabstractyyS2icF'
+
+enum TreeB<T> {
+  case Nil
+  case Leaf(T)
+  indirect case Branch(left: TreeB<T>, right: TreeB<T>)
+}
+
+// CHECK-LABEL: sil hidden @$S13indirect_enum11TreeB_cases_1l1ryx_AA0C1BOyxGAGtlF
+func TreeB_cases<T>(_ t: T, l: TreeB<T>, r: TreeB<T>) {
+
+// CHECK:         [[METATYPE:%.*]] = metatype $@thin TreeB<T>.Type
+// CHECK:         [[NIL:%.*]] = alloc_stack $TreeB<T>
+// CHECK-NEXT:    inject_enum_addr [[NIL]] : $*TreeB<T>, #TreeB.Nil!enumelt
+// CHECK-NEXT:    destroy_addr [[NIL]]
+// CHECK-NEXT:    dealloc_stack [[NIL]]
+  let _ = TreeB<T>.Nil
+
+// CHECK-NEXT:    [[METATYPE:%.*]] = metatype $@thin TreeB<T>.Type
+// CHECK-NEXT:    [[LEAF:%.*]] = alloc_stack $TreeB<T>
+// CHECK-NEXT:    [[PAYLOAD:%.*]] = init_enum_data_addr [[LEAF]] : $*TreeB<T>, #TreeB.Leaf!enumelt.1
+// CHECK-NEXT:    copy_addr %0 to [initialization] [[PAYLOAD]]
+// CHECK-NEXT:    inject_enum_addr [[LEAF]] : $*TreeB<T>, #TreeB.Leaf!enumelt
+// CHECK-NEXT:    destroy_addr [[LEAF]]
+// CHECK-NEXT:    dealloc_stack [[LEAF]]
+  let _ = TreeB<T>.Leaf(t)
+
+// CHECK-NEXT:    [[METATYPE:%.*]] = metatype $@thin TreeB<T>.Type
+// CHECK-NEXT:    [[BOX:%.*]] = alloc_box $<τ_0_0> { var (left: TreeB<τ_0_0>, right: TreeB<τ_0_0>) } <T>
+// CHECK-NEXT:    [[PB:%.*]] = project_box [[BOX]]
+// CHECK-NEXT:    [[LEFT:%.*]] = tuple_element_addr [[PB]]
+// CHECK-NEXT:    [[RIGHT:%.*]] = tuple_element_addr [[PB]]
+// CHECK-NEXT:    copy_addr %1 to [initialization] [[LEFT]] : $*TreeB<T>
+// CHECK-NEXT:    copy_addr %2 to [initialization] [[RIGHT]] : $*TreeB<T>
+// CHECK-NEXT:    [[BRANCH:%.*]] = alloc_stack $TreeB<T>
+// CHECK-NEXT:    [[PAYLOAD:%.*]] = init_enum_data_addr [[BRANCH]]
+// CHECK-NEXT:    store [[BOX]] to [init] [[PAYLOAD]]
+// CHECK-NEXT:    inject_enum_addr [[BRANCH]] : $*TreeB<T>, #TreeB.Branch!enumelt.1
+// CHECK-NEXT:    destroy_addr [[BRANCH]]
+// CHECK-NEXT:    dealloc_stack [[BRANCH]]
+  let _ = TreeB<T>.Branch(left: l, right: r)
+
+// CHECK:         return
+
+}
+
+// CHECK-LABEL: sil hidden @$S13indirect_enum13TreeInt_cases_1l1rySi_AA0cD0OAFtF : $@convention(thin) (Int, @guaranteed TreeInt, @guaranteed TreeInt) -> ()
+func TreeInt_cases(_ t: Int, l: TreeInt, r: TreeInt) {
+// CHECK: bb0([[ARG1:%.*]] : $Int, [[ARG2:%.*]] : $TreeInt, [[ARG3:%.*]] : $TreeInt):
+// CHECK:         [[METATYPE:%.*]] = metatype $@thin TreeInt.Type
+// CHECK-NEXT:    [[NIL:%.*]] = enum $TreeInt, #TreeInt.Nil!enumelt
+// CHECK-NOT:     destroy_value [[NIL]]
+  let _ = TreeInt.Nil
+
+// CHECK-NEXT:    [[METATYPE:%.*]] = metatype $@thin TreeInt.Type
+// CHECK-NEXT:    [[LEAF:%.*]] = enum $TreeInt, #TreeInt.Leaf!enumelt.1, [[ARG1]]
+// CHECK-NOT:     destroy_value [[LEAF]]
+  let _ = TreeInt.Leaf(t)
+
+// CHECK-NEXT:    [[METATYPE:%.*]] = metatype $@thin TreeInt.Type
+// CHECK-NEXT:    [[BOX:%.*]] = alloc_box ${ var (left: TreeInt, right: TreeInt) }
+// CHECK-NEXT:    [[PB:%.*]] = project_box [[BOX]]
+// CHECK-NEXT:    [[LEFT:%.*]] = tuple_element_addr [[PB]]
+// CHECK-NEXT:    [[RIGHT:%.*]] = tuple_element_addr [[PB]]
+// CHECK-NEXT:    [[ARG2_COPY:%.*]] = copy_value [[ARG2]]
+// CHECK-NEXT:    store [[ARG2_COPY]] to [init] [[LEFT]]
+// CHECK-NEXT:    [[ARG3_COPY:%.*]] = copy_value [[ARG3]]
+// CHECK-NEXT:    store [[ARG3_COPY]] to [init] [[RIGHT]]
+// CHECK-NEXT:    [[BRANCH:%.*]] = enum $TreeInt, #TreeInt.Branch!enumelt.1, [[BOX]]
+// CHECK-NEXT:    destroy_value [[BRANCH]]
+  let _ = TreeInt.Branch(left: l, right: r)
+}
+// CHECK: } // end sil function '$S13indirect_enum13TreeInt_cases_1l1rySi_AA0cD0OAFtF'
+
+enum TreeInt {
+  case Nil
+  case Leaf(Int)
+  indirect case Branch(left: TreeInt, right: TreeInt)
+}
+
+
+enum TrivialButIndirect {
+  case Direct(Int)
+  indirect case Indirect(Int)
+}
+
+func a() {}
+func b<T>(_ x: T) {}
+func c<T>(_ x: T, _ y: T) {}
+func d() {}
+
+// CHECK-LABEL: sil hidden @$S13indirect_enum11switchTreeAyyAA0D1AOyxGlF : $@convention(thin) <T> (@guaranteed TreeA<T>) -> () {
+func switchTreeA<T>(_ x: TreeA<T>) {
+  // CHECK: bb0([[ARG:%.*]] : $TreeA<T>):
+  // --           x +2
+  // CHECK:       [[ARG_COPY:%.*]] = copy_value [[ARG]]
+  // CHECK:       switch_enum [[ARG_COPY]] : $TreeA<T>,
+  // CHECK:          case #TreeA.Nil!enumelt: [[NIL_CASE:bb1]],
+  // CHECK:          case #TreeA.Leaf!enumelt.1: [[LEAF_CASE:bb2]],
+  // CHECK:          case #TreeA.Branch!enumelt.1: [[BRANCH_CASE:bb3]],
+  switch x {
+  // CHECK:     [[NIL_CASE]]:
+  // CHECK:       function_ref @$S13indirect_enum1ayyF
+  // CHECK:       br [[OUTER_CONT:bb[0-9]+]]
+  case .Nil:
+    a()
+  // CHECK:     [[LEAF_CASE]]([[LEAF_BOX:%.*]] : $<τ_0_0> { var τ_0_0 } <T>):
+  // CHECK:       [[VALUE:%.*]] = project_box [[LEAF_BOX]]
+  // CHECK:       copy_addr [[VALUE]] to [initialization] [[X:%.*]] : $*T
+  // CHECK:       function_ref @$S13indirect_enum1b{{[_0-9a-zA-Z]*}}F
+  // CHECK:       destroy_addr [[X]]
+  // CHECK:       dealloc_stack [[X]]
+  // --           x +1
+  // CHECK:       destroy_value [[LEAF_BOX]]
+  // CHECK:       br [[OUTER_CONT]]
+  case .Leaf(let x):
+    b(x)
+
+  // CHECK:     [[BRANCH_CASE]]([[NODE_BOX:%.*]] : $<τ_0_0> { var (left: TreeA<τ_0_0>, right: TreeA<τ_0_0>) } <T>):
+  // CHECK:       [[TUPLE_ADDR:%.*]] = project_box [[NODE_BOX]]
+  // CHECK:       [[TUPLE:%.*]] = load_borrow [[TUPLE_ADDR]]
+  // CHECK:       [[LEFT:%.*]] = tuple_extract [[TUPLE]] {{.*}}, 0
+  // CHECK:       [[RIGHT:%.*]] = tuple_extract [[TUPLE]] {{.*}}, 1
+  // CHECK:       switch_enum [[LEFT]] : $TreeA<T>,
+  // CHECK:          case #TreeA.Leaf!enumelt.1: [[LEAF_CASE_LEFT:bb[0-9]+]],
+  // CHECK:          default [[FAIL_LEFT:bb[0-9]+]]
+
+  // CHECK:     [[LEAF_CASE_LEFT]]([[LEFT_LEAF_BOX:%.*]] : $<τ_0_0> { var τ_0_0 } <T>):
+  // CHECK:       [[LEFT_LEAF_VALUE:%.*]] = project_box [[LEFT_LEAF_BOX]]
+  // CHECK:       switch_enum [[RIGHT]] : $TreeA<T>,
+  // CHECK:          case #TreeA.Leaf!enumelt.1: [[LEAF_CASE_RIGHT:bb[0-9]+]],
+  // CHECK:          default [[FAIL_RIGHT:bb[0-9]+]]
+
+  // CHECK:     [[LEAF_CASE_RIGHT]]([[RIGHT_LEAF_BOX:%.*]] : $<τ_0_0> { var τ_0_0 } <T>):
+  // CHECK:       [[RIGHT_LEAF_VALUE:%.*]] = project_box [[RIGHT_LEAF_BOX]]
+  // CHECK:       copy_addr [[LEFT_LEAF_VALUE]]
+  // CHECK:       copy_addr [[RIGHT_LEAF_VALUE]]
+  // --           x +1
+  // CHECK:       destroy_value [[NODE_BOX]]
+  // CHECK:       br [[OUTER_CONT]]
+
+  // CHECK:     [[FAIL_RIGHT]]:
+  // CHECK:       br [[DEFAULT:bb[0-9]+]]
+
+  // CHECK:     [[FAIL_LEFT]]:
+  // CHECK:       br [[DEFAULT]]
+
+  case .Branch(.Leaf(let x), .Leaf(let y)):
+    c(x, y)
+
+  // CHECK:     [[DEFAULT]]:
+  // --           x +1
+  // CHECK:       destroy_value [[ARG_COPY]]
+  default:
+    d()
+  }
+
+  // CHECK:     [[OUTER_CONT:%.*]]:
+  // --           x +0
+}
+// CHECK: } // end sil function '$S13indirect_enum11switchTreeAyyAA0D1AOyxGlF'
+
+// CHECK-LABEL: sil hidden @$S13indirect_enum11switchTreeB{{[_0-9a-zA-Z]*}}F
+func switchTreeB<T>(_ x: TreeB<T>) {
+  // CHECK:       copy_addr %0 to [initialization] [[SCRATCH:%.*]] :
+  // CHECK:       switch_enum_addr [[SCRATCH]]
+  switch x {
+
+  // CHECK:     bb{{.*}}:
+  // CHECK:       destroy_addr [[SCRATCH]]
+  // CHECK:       dealloc_stack [[SCRATCH]]
+  // CHECK:       function_ref @$S13indirect_enum1ayyF
+  // CHECK:       br [[OUTER_CONT:bb[0-9]+]]
+  case .Nil:
+    a()
+
+  // CHECK:     bb{{.*}}:
+  // CHECK:       copy_addr [[SCRATCH]] to [initialization] [[LEAF_COPY:%.*]] :
+  // CHECK:       [[LEAF_ADDR:%.*]] = unchecked_take_enum_data_addr [[LEAF_COPY]]
+  // CHECK:       copy_addr [take] [[LEAF_ADDR]] to [initialization] [[LEAF:%.*]] :
+  // CHECK:       function_ref @$S13indirect_enum1b{{[_0-9a-zA-Z]*}}F
+  // CHECK:       destroy_addr [[LEAF]]
+  // CHECK:       dealloc_stack [[LEAF]]
+  // CHECK-NOT:   destroy_addr [[LEAF_COPY]]
+  // CHECK:       dealloc_stack [[LEAF_COPY]]
+  // CHECK:       destroy_addr [[SCRATCH]]
+  // CHECK:       dealloc_stack [[SCRATCH]]
+  // CHECK:       br [[OUTER_CONT]]
+  case .Leaf(let x):
+    b(x)
+
+  // CHECK:     bb{{.*}}:
+  // CHECK:       copy_addr [[SCRATCH]] to [initialization] [[TREE_COPY:%.*]] :
+  // CHECK:       [[TREE_ADDR:%.*]] = unchecked_take_enum_data_addr [[TREE_COPY]]
+  // --           box +1 immutable
+  // CHECK:       [[BOX:%.*]] = load [take] [[TREE_ADDR]]
+  // CHECK:       [[TUPLE:%.*]] = project_box [[BOX]]
+  // CHECK:       [[LEFT:%.*]] = tuple_element_addr [[TUPLE]]
+  // CHECK:       [[RIGHT:%.*]] = tuple_element_addr [[TUPLE]]
+  // CHECK:       switch_enum_addr [[LEFT]] {{.*}}, default [[LEFT_FAIL:bb[0-9]+]]
+
+  // CHECK:     bb{{.*}}:
+  // CHECK:       copy_addr [[LEFT]] to [initialization] [[LEFT_COPY:%.*]] :
+  // CHECK:       [[LEFT_LEAF:%.*]] = unchecked_take_enum_data_addr [[LEFT_COPY]] : $*TreeB<T>, #TreeB.Leaf
+  // CHECK:       switch_enum_addr [[RIGHT]] {{.*}}, default [[RIGHT_FAIL:bb[0-9]+]]
+
+  // CHECK:     bb{{.*}}:
+  // CHECK:       copy_addr [[RIGHT]] to [initialization] [[RIGHT_COPY:%.*]] :
+  // CHECK:       [[RIGHT_LEAF:%.*]] = unchecked_take_enum_data_addr [[RIGHT_COPY]] : $*TreeB<T>, #TreeB.Leaf
+  // CHECK:       copy_addr [take] [[LEFT_LEAF]] to [initialization] [[X:%.*]] :
+  // CHECK:       copy_addr [take] [[RIGHT_LEAF]] to [initialization] [[Y:%.*]] :
+  // CHECK:       function_ref @$S13indirect_enum1c{{[_0-9a-zA-Z]*}}F
+  // CHECK:       destroy_addr [[Y]]
+  // CHECK:       dealloc_stack [[Y]]
+  // CHECK:       destroy_addr [[X]]
+  // CHECK:       dealloc_stack [[X]]
+  // CHECK-NOT:   destroy_addr [[RIGHT_COPY]]
+  // CHECK:       dealloc_stack [[RIGHT_COPY]]
+  // CHECK-NOT:   destroy_addr [[LEFT_COPY]]
+  // CHECK:       dealloc_stack [[LEFT_COPY]]
+  // --           box +0
+  // CHECK:       destroy_value [[BOX]]
+  // CHECK-NOT:   destroy_addr [[TREE_COPY]]
+  // CHECK:       dealloc_stack [[TREE_COPY]]
+  // CHECK:       destroy_addr [[SCRATCH]]
+  // CHECK:       dealloc_stack [[SCRATCH]]
+  case .Branch(.Leaf(let x), .Leaf(let y)):
+    c(x, y)
+
+  // CHECK:     [[RIGHT_FAIL]]:
+  // CHECK:       destroy_addr [[LEFT_LEAF]]
+  // CHECK-NOT:   destroy_addr [[LEFT_COPY]]
+  // CHECK:       dealloc_stack [[LEFT_COPY]]
+  // CHECK:       destroy_value [[BOX]]
+  // CHECK-NOT:   destroy_addr [[TREE_COPY]]
+  // CHECK:       dealloc_stack [[TREE_COPY]]
+  // CHECK:       br [[INNER_CONT:bb[0-9]+]]
+
+  // CHECK:     [[LEFT_FAIL]]:
+  // CHECK:       destroy_value [[BOX]]
+  // CHECK-NOT:   destroy_addr [[TREE_COPY]]
+  // CHECK:       dealloc_stack [[TREE_COPY]]
+  // CHECK:       br [[INNER_CONT:bb[0-9]+]]
+
+  // CHECK:     [[INNER_CONT]]:
+  // CHECK:       destroy_addr [[SCRATCH]]
+  // CHECK:       dealloc_stack [[SCRATCH]]
+  // CHECK:       function_ref @$S13indirect_enum1dyyF
+  // CHECK:       br [[OUTER_CONT]]
+  default:
+    d()
+  }
+  // CHECK:     [[OUTER_CONT]]:
+  // CHECK:       return
+}
+
+// CHECK-LABEL: sil hidden @$S13indirect_enum10guardTreeA{{[_0-9a-zA-Z]*}}F
+func guardTreeA<T>(_ tree: TreeA<T>) {
+  // CHECK: bb0([[ARG:%.*]] : $TreeA<T>):
+  do {
+    // CHECK:   [[ARG_COPY:%.*]] = copy_value [[ARG]]
+    // CHECK:   switch_enum [[ARG_COPY]] : $TreeA<T>, case #TreeA.Nil!enumelt: [[YES:bb[0-9]+]], default [[NO:bb[0-9]+]]
+    // CHECK: [[NO]]([[ORIGINAL_VALUE:%.*]] : $TreeA<T>):
+    // CHECK:   destroy_value [[ORIGINAL_VALUE]]
+    // CHECK: [[YES]]:
+    guard case .Nil = tree else { return }
+
+    // CHECK:   [[X:%.*]] = alloc_stack $T
+    // CHECK:   [[ARG_COPY:%.*]] = copy_value [[ARG]]
+    // CHECK:   switch_enum [[ARG_COPY]] : $TreeA<T>, case #TreeA.Leaf!enumelt.1: [[YES:bb[0-9]+]], default [[NO:bb[0-9]+]]
+    // CHECK: [[NO]]([[ORIGINAL_VALUE:%.*]] : $TreeA<T>):
+    // CHECK:   destroy_value [[ORIGINAL_VALUE]]
+    // CHECK: [[YES]]([[BOX:%.*]] : $<τ_0_0> { var τ_0_0 } <T>):
+    // CHECK:   [[VALUE_ADDR:%.*]] = project_box [[BOX]]
+    // CHECK:   [[TMP:%.*]] = alloc_stack
+    // CHECK:   copy_addr [[VALUE_ADDR]] to [initialization] [[TMP]]
+    // CHECK:   copy_addr [take] [[TMP]] to [initialization] [[X]]
+    // CHECK:   destroy_value [[BOX]]
+    guard case .Leaf(let x) = tree else { return }
+
+    // CHECK:   [[ARG_COPY:%.*]] = copy_value [[ARG]]
+    // CHECK:   switch_enum [[ARG_COPY]] : $TreeA<T>, case #TreeA.Branch!enumelt.1: [[YES:bb[0-9]+]], default [[NO:bb[0-9]+]]
+    // CHECK: [[NO]]([[ORIGINAL_VALUE:%.*]] : $TreeA<T>):
+    // CHECK:   destroy_value [[ORIGINAL_VALUE]]
+    // CHECK: [[YES]]([[BOX:%.*]] : $<τ_0_0> { var (left: TreeA<τ_0_0>, right: TreeA<τ_0_0>) } <T>):
+    // CHECK:   [[VALUE_ADDR:%.*]] = project_box [[BOX]]
+    // CHECK:   [[TUPLE:%.*]] = load [take] [[VALUE_ADDR]]
+    // CHECK:   [[TUPLE_COPY:%.*]] = copy_value [[TUPLE]]
+    // CHECK:   [[BORROWED_TUPLE_COPY:%.*]] = begin_borrow [[TUPLE_COPY]]
+    // CHECK:   [[L:%.*]] = tuple_extract [[BORROWED_TUPLE_COPY]]
+    // CHECK:   [[COPY_L:%.*]] = copy_value [[L]]
+    // CHECK:   [[R:%.*]] = tuple_extract [[BORROWED_TUPLE_COPY]]
+    // CHECK:   [[COPY_R:%.*]] = copy_value [[R]]
+    // CHECK:   end_borrow [[BORROWED_TUPLE_COPY]] from [[TUPLE_COPY]]
+    // CHECK:   destroy_value [[TUPLE_COPY]]
+    // CHECK:   destroy_value [[BOX]]
+    guard case .Branch(left: let l, right: let r) = tree else { return }
+
+    // CHECK:   destroy_value [[COPY_R]]
+    // CHECK:   destroy_value [[COPY_L]]
+    // CHECK:   destroy_addr [[X]]
+  }
+
+  do {
+    // CHECK:   [[ARG_COPY:%.*]] = copy_value [[ARG]]
+    // CHECK:   switch_enum [[ARG_COPY]] : $TreeA<T>, case #TreeA.Nil!enumelt: [[YES:bb[0-9]+]], default [[NO:bb[0-9]+]]
+    // CHECK: [[NO]]([[ORIGINAL_VALUE:%.*]] : $TreeA<T>):
+    // CHECK:   destroy_value [[ORIGINAL_VALUE]]
+    // CHECK: [[YES]]:
+    // CHECK:   br
+    if case .Nil = tree { }
+
+    // CHECK:   [[X:%.*]] = alloc_stack $T
+    // CHECK:   [[ARG_COPY:%.*]] = copy_value [[ARG]]
+    // CHECK:   switch_enum [[ARG_COPY]] : $TreeA<T>, case #TreeA.Leaf!enumelt.1: [[YES:bb[0-9]+]], default [[NO:bb[0-9]+]]
+    // CHECK: [[NO]]([[ORIGINAL_VALUE:%.*]] : $TreeA<T>):
+    // CHECK:   destroy_value [[ORIGINAL_VALUE]]
+    // CHECK: [[YES]]([[BOX:%.*]] : $<τ_0_0> { var τ_0_0 } <T>):
+    // CHECK:   [[VALUE_ADDR:%.*]] = project_box [[BOX]]
+    // CHECK:   [[TMP:%.*]] = alloc_stack
+    // CHECK:   copy_addr [[VALUE_ADDR]] to [initialization] [[TMP]]
+    // CHECK:   copy_addr [take] [[TMP]] to [initialization] [[X]]
+    // CHECK:   destroy_value [[BOX]]
+    // CHECK:   destroy_addr [[X]]
+    if case .Leaf(let x) = tree { }
+
+
+    // CHECK:   [[ARG_COPY:%.*]] = copy_value [[ARG]]
+    // CHECK:   switch_enum [[ARG_COPY]] : $TreeA<T>, case #TreeA.Branch!enumelt.1: [[YES:bb[0-9]+]], default [[NO:bb[0-9]+]]
+    // CHECK: [[NO]]([[ORIGINAL_VALUE:%.*]] : $TreeA<T>):
+    // CHECK:   destroy_value [[ORIGINAL_VALUE]]
+    // CHECK: [[YES]]([[BOX:%.*]] : $<τ_0_0> { var (left: TreeA<τ_0_0>, right: TreeA<τ_0_0>) } <T>):
+    // CHECK:   [[VALUE_ADDR:%.*]] = project_box [[BOX]]
+    // CHECK:   [[TUPLE:%.*]] = load [take] [[VALUE_ADDR]]
+    // CHECK:   [[TUPLE_COPY:%.*]] = copy_value [[TUPLE]]
+    // CHECK:   [[BORROWED_TUPLE_COPY:%.*]] = begin_borrow [[TUPLE_COPY]]
+    // CHECK:   [[L:%.*]] = tuple_extract [[BORROWED_TUPLE_COPY]]
+    // CHECK:   [[COPY_L:%.*]] = copy_value [[L]]
+    // CHECK:   [[R:%.*]] = tuple_extract [[BORROWED_TUPLE_COPY]]
+    // CHECK:   [[COPY_R:%.*]] = copy_value [[R]]
+    // CHECK:   end_borrow [[BORROWED_TUPLE_COPY]] from [[TUPLE_COPY]]
+    // CHECK:   destroy_value [[TUPLE_COPY]]
+    // CHECK:   destroy_value [[BOX]]
+    // CHECK:   destroy_value [[COPY_R]]
+    // CHECK:   destroy_value [[COPY_L]]
+    if case .Branch(left: let l, right: let r) = tree { }
+  }
+}
+
+// CHECK-LABEL: sil hidden @$S13indirect_enum10guardTreeB{{[_0-9a-zA-Z]*}}F
+func guardTreeB<T>(_ tree: TreeB<T>) {
+  do {
+    // CHECK:   copy_addr %0 to [initialization] [[TMP:%.*]] :
+    // CHECK:   switch_enum_addr [[TMP]] : $*TreeB<T>, case #TreeB.Nil!enumelt: [[YES:bb[0-9]+]], default [[NO:bb[0-9]+]]
+    // CHECK: [[NO]]:
+    // CHECK:   destroy_addr [[TMP]]
+    // CHECK: [[YES]]:
+    // CHECK:   destroy_addr [[TMP]]
+    guard case .Nil = tree else { return }
+
+    // CHECK:   [[X:%.*]] = alloc_stack $T
+    // CHECK:   copy_addr %0 to [initialization] [[TMP:%.*]] :
+    // CHECK:   switch_enum_addr [[TMP]] : $*TreeB<T>, case #TreeB.Leaf!enumelt.1: [[YES:bb[0-9]+]], default [[NO:bb[0-9]+]]
+    // CHECK: [[NO]]:
+    // CHECK:   destroy_addr [[TMP]]
+    // CHECK: [[YES]]:
+    // CHECK:   [[VALUE:%.*]] = unchecked_take_enum_data_addr [[TMP]]
+    // CHECK:   copy_addr [take] [[VALUE]] to [initialization] [[X]]
+    // CHECK:   dealloc_stack [[TMP]]
+    guard case .Leaf(let x) = tree else { return }
+
+    // CHECK:   [[L:%.*]] = alloc_stack $TreeB
+    // CHECK:   [[R:%.*]] = alloc_stack $TreeB
+    // CHECK:   copy_addr %0 to [initialization] [[TMP:%.*]] :
+    // CHECK:   switch_enum_addr [[TMP]] : $*TreeB<T>, case #TreeB.Branch!enumelt.1: [[YES:bb[0-9]+]], default [[NO:bb[0-9]+]]
+    // CHECK: [[NO]]:
+    // CHECK:   destroy_addr [[TMP]]
+    // CHECK: [[YES]]:
+    // CHECK:   [[BOX_ADDR:%.*]] = unchecked_take_enum_data_addr [[TMP]]
+    // CHECK:   [[BOX:%.*]] = load [take] [[BOX_ADDR]]
+    // CHECK:   [[TUPLE_ADDR:%.*]] = project_box [[BOX]]
+    // CHECK:   copy_addr [[TUPLE_ADDR]] to [initialization] [[TUPLE_COPY:%.*]] :
+    // CHECK:   [[L_COPY:%.*]] = tuple_element_addr [[TUPLE_COPY]]
+    // CHECK:   copy_addr [take] [[L_COPY]] to [initialization] [[L]]
+    // CHECK:   [[R_COPY:%.*]] = tuple_element_addr [[TUPLE_COPY]]
+    // CHECK:   copy_addr [take] [[R_COPY]] to [initialization] [[R]]
+    // CHECK:   destroy_value [[BOX]]
+    guard case .Branch(left: let l, right: let r) = tree else { return }
+
+    // CHECK:   destroy_addr [[R]]
+    // CHECK:   destroy_addr [[L]]
+    // CHECK:   destroy_addr [[X]]
+  }
+
+  do {
+    // CHECK:   copy_addr %0 to [initialization] [[TMP:%.*]] :
+    // CHECK:   switch_enum_addr [[TMP]] : $*TreeB<T>, case #TreeB.Nil!enumelt: [[YES:bb[0-9]+]], default [[NO:bb[0-9]+]]
+    // CHECK: [[NO]]:
+    // CHECK:   destroy_addr [[TMP]]
+    // CHECK: [[YES]]:
+    // CHECK:   destroy_addr [[TMP]]
+    if case .Nil = tree { }
+
+    // CHECK:   [[X:%.*]] = alloc_stack $T
+    // CHECK:   copy_addr %0 to [initialization] [[TMP:%.*]] :
+    // CHECK:   switch_enum_addr [[TMP]] : $*TreeB<T>, case #TreeB.Leaf!enumelt.1: [[YES:bb[0-9]+]], default [[NO:bb[0-9]+]]
+    // CHECK: [[NO]]:
+    // CHECK:   destroy_addr [[TMP]]
+    // CHECK: [[YES]]:
+    // CHECK:   [[VALUE:%.*]] = unchecked_take_enum_data_addr [[TMP]]
+    // CHECK:   copy_addr [take] [[VALUE]] to [initialization] [[X]]
+    // CHECK:   dealloc_stack [[TMP]]
+    // CHECK:   destroy_addr [[X]]
+    if case .Leaf(let x) = tree { }
+
+    // CHECK:   [[L:%.*]] = alloc_stack $TreeB
+    // CHECK:   [[R:%.*]] = alloc_stack $TreeB
+    // CHECK:   copy_addr %0 to [initialization] [[TMP:%.*]] :
+    // CHECK:   switch_enum_addr [[TMP]] : $*TreeB<T>, case #TreeB.Branch!enumelt.1: [[YES:bb[0-9]+]], default [[NO:bb[0-9]+]]
+    // CHECK: [[NO]]:
+    // CHECK:   destroy_addr [[TMP]]
+    // CHECK: [[YES]]:
+    // CHECK:   [[BOX_ADDR:%.*]] = unchecked_take_enum_data_addr [[TMP]]
+    // CHECK:   [[BOX:%.*]] = load [take] [[BOX_ADDR]]
+    // CHECK:   [[TUPLE_ADDR:%.*]] = project_box [[BOX]]
+    // CHECK:   copy_addr [[TUPLE_ADDR]] to [initialization] [[TUPLE_COPY:%.*]] :
+    // CHECK:   [[L_COPY:%.*]] = tuple_element_addr [[TUPLE_COPY]]
+    // CHECK:   copy_addr [take] [[L_COPY]] to [initialization] [[L]]
+    // CHECK:   [[R_COPY:%.*]] = tuple_element_addr [[TUPLE_COPY]]
+    // CHECK:   copy_addr [take] [[R_COPY]] to [initialization] [[R]]
+    // CHECK:   destroy_value [[BOX]]
+    // CHECK:   destroy_addr [[R]]
+    // CHECK:   destroy_addr [[L]]
+    if case .Branch(left: let l, right: let r) = tree { }
+  }
+}
+
+// SEMANTIC ARC TODO: This test needs to be made far more comprehensive.
+// CHECK-LABEL: sil hidden @$S13indirect_enum35dontDisableCleanupOfIndirectPayloadyyAA010TrivialButG0OF : $@convention(thin) (@guaranteed TrivialButIndirect) -> () {
+func dontDisableCleanupOfIndirectPayload(_ x: TrivialButIndirect) {
+  // CHECK: bb0([[ARG:%.*]] : $TrivialButIndirect):
+  // CHECK:   [[ARG_COPY:%.*]] = copy_value [[ARG]]
+  // CHECK:   switch_enum [[ARG_COPY]] : $TrivialButIndirect, case #TrivialButIndirect.Direct!enumelt.1:  [[YES:bb[0-9]+]], case #TrivialButIndirect.Indirect!enumelt.1: [[NO:bb[0-9]+]]
+  //
+  // CHECK: [[NO]]([[PAYLOAD:%.*]] : ${ var Int }):
+  // CHECK:   destroy_value [[PAYLOAD]]
+  guard case .Direct(let foo) = x else { return }
+
+  // CHECK: [[YES]]({{%.*}} : $Int):
+  // CHECK:   [[ARG_COPY:%.*]] = copy_value [[ARG]]
+  // CHECK:   switch_enum [[ARG_COPY]] : $TrivialButIndirect, case #TrivialButIndirect.Indirect!enumelt.1:  [[YES:bb[0-9]+]], case #TrivialButIndirect.Direct!enumelt.1: [[NO:bb[0-9]+]]
+
+  // CHECK: [[NO]]({{%.*}} : $Int):
+  // CHECK-NOT: destroy_value
+
+  // CHECK: [[YES]]([[BOX:%.*]] : ${ var Int }):
+  // CHECK:   destroy_value [[BOX]]
+
+  guard case .Indirect(let bar) = x else { return }
+}
+// CHECK: } // end sil function '$S13indirect_enum35dontDisableCleanupOfIndirectPayloadyyAA010TrivialButG0OF'
diff --git a/test/SILGen/plus_zero_inlineable_attribute.swift b/test/SILGen/plus_zero_inlineable_attribute.swift
new file mode 100644
index 0000000..097ea60
--- /dev/null
+++ b/test/SILGen/plus_zero_inlineable_attribute.swift
@@ -0,0 +1,101 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership -emit-verbose-sil %s | %FileCheck %s
+
+// CHECK-LABEL: sil [serialized] @$S20inlineable_attribute15fragileFunctionyyF : $@convention(thin) () -> ()
+@_inlineable public func fragileFunction() {
+
+}
+
+public struct MySt {
+  // CHECK-LABEL: sil [serialized] @$S20inlineable_attribute4MyStV6methodyyF : $@convention(method) (MySt) -> ()
+  @_inlineable public func method() {}
+
+  // CHECK-LABEL: sil [serialized] @$S20inlineable_attribute4MyStV8propertySivg : $@convention(method) (MySt) -> Int
+  @_inlineable public var property: Int {
+    return 5
+  }
+
+  // CHECK-LABEL: sil [serialized] @$S20inlineable_attribute4MyStVyS2icig : $@convention(method) (Int, MySt) -> Int
+  @_inlineable public subscript(x: Int) -> Int {
+    return x
+  }
+}
+
+public class MyCls {
+  // CHECK-LABEL: sil [serialized] @$S20inlineable_attribute5MyClsCfD : $@convention(method) (@owned MyCls) -> ()
+  @_inlineable deinit {}
+
+  // Allocating entry point is [serialized]
+
+  // CHECK-LABEL: sil [serialized] @$S20inlineable_attribute5MyClsC14designatedInitACyt_tcfC : $@convention(method) (@thick MyCls.Type) -> @owned MyCls
+  public init(designatedInit: ()) {}
+
+  // Note -- convenience init is intentionally not [serialized]
+
+  // CHECK-LABEL: sil @$S20inlineable_attribute5MyClsC15convenienceInitACyt_tcfC : $@convention(method) (@thick MyCls.Type) -> @owned MyCls
+  public convenience init(convenienceInit: ()) {
+    self.init(designatedInit: ())
+  }
+}
+
+// Make sure enum case constructors for public and versioned enums are
+// [serialized].
+@_versioned enum MyEnum {
+  case c(MySt)
+}
+
+// CHECK-LABEL: sil shared [transparent] [serialized] [thunk] @$S20inlineable_attribute6MyEnumO1cyAcA0C2StVcACmFTc : $@convention(thin) (@thin MyEnum.Type) -> @owned @callee_guaranteed (MySt) -> MyEnum
+
+@_inlineable public func referencesMyEnum() {
+  _ = MyEnum.c
+}
+
+// CHECK-LABEL: sil non_abi [transparent] [serialized] @$S20inlineable_attribute15HasInitializersV1xSivpfi : $@convention(thin) () -> Int
+// CHECK-LABEL: sil non_abi [transparent] [serialized] @$S20inlineable_attribute15HasInitializersV1ySivpfi : $@convention(thin) () -> Int
+
+@_fixed_layout
+public struct HasInitializers {
+  public let x = 1234
+  internal let y = 4321
+
+  @_inlineable public init() {}
+}
+
+public class Horse {
+  public func gallop() {}
+}
+
+// CHECK-LABEL: sil [serialized] @$S20inlineable_attribute15talkAboutAHorse1hyAA5HorseC_tF : $@convention(thin) (@guaranteed Horse) -> () {
+// CHECK: function_ref @$S20inlineable_attribute5HorseC6gallopyyFTc
+// CHECK: return
+// CHECK: }
+
+// CHECK-LABEL: sil shared [serializable] [thunk] @$S20inlineable_attribute5HorseC6gallopyyFTc : $@convention(thin) (@guaranteed Horse) -> @owned @callee_guaranteed () -> () {
+// CHECK: class_method
+// CHECK: return
+// CHECK: }
+
+@_inlineable public func talkAboutAHorse(h: Horse) {
+  _ = h.gallop
+}
+
+@_versioned
+@_fixed_layout
+class Base {
+  @_versioned
+  @_inlineable
+  init(horse: Horse) {}
+}
+
+// CHECK-LABEL: sil [serialized] @$S20inlineable_attribute7DerivedCfd : $@convention(method) (@guaranteed Derived) -> @owned Builtin.NativeObject
+// CHECK-LABEL: sil [serialized] @$S20inlineable_attribute7DerivedCfD : $@convention(method) (@owned Derived) -> ()
+
+// Make sure the synthesized delegating initializer is inlineable also
+
+// CHECK-LABEL: sil [serialized] @$S20inlineable_attribute7DerivedC5horseAcA5HorseC_tcfc : $@convention(method) (@owned Horse, @owned Derived) -> @owned Derived
+@_versioned
+@_fixed_layout
+class Derived : Base {
+  // Allow @_inlineable deinits
+  @_inlineable deinit {}
+}
diff --git a/test/SILGen/plus_zero_inlineable_attribute_objc.swift b/test/SILGen/plus_zero_inlineable_attribute_objc.swift
new file mode 100644
index 0000000..a963567
--- /dev/null
+++ b/test/SILGen/plus_zero_inlineable_attribute_objc.swift
@@ -0,0 +1,35 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %empty-directory(%t)
+// RUN: %build-silgen-test-overlays
+
+// RUN: %target-swift-frontend(mock-sdk: -sdk %S/Inputs -I %t) -Xllvm -sil-full-demangle -primary-file %s -emit-silgen | %FileCheck %s
+
+// REQUIRES: objc_interop
+
+import Foundation
+
+public class Horse : NSObject {
+  public dynamic func gallop() {}
+}
+
+// Make sure we can reference dynamic thunks and curry thunks
+// from inlineable scopes
+
+// CHECK-LABEL: sil [serialized] @$S25inlineable_attribute_objc15talkAboutAHorse1hyAA5HorseC_tF : $@convention(thin) (@guaranteed Horse) -> () {
+// CHECK: function_ref @$S25inlineable_attribute_objc5HorseC6gallopyyFTc : $@convention(thin) (@guaranteed Horse) -> @owned @callee_guaranteed () -> ()
+// CHECK: return
+// CHECK: }
+
+// CHECK-LABEL: sil shared [serializable] [thunk] @$S25inlineable_attribute_objc5HorseC6gallopyyFTc : $@convention(thin) (@guaranteed Horse) -> @owned @callee_guaranteed () -> ()
+// CHECK:   %1 = function_ref @$S25inlineable_attribute_objc5HorseC6gallopyyFTD
+// CHECK: return
+// CHECK: }
+
+// CHECK-LABEL: sil shared [transparent] [serializable] [thunk] @$S25inlineable_attribute_objc5HorseC6gallopyyFTD : $@convention(method) (@guaranteed Horse) -> ()
+// CHECK: objc_method
+// CHECK: return
+// CHECK: }
+
+@_inlineable public func talkAboutAHorse(h: Horse) {
+  _ = h.gallop
+}
diff --git a/test/SILGen/plus_zero_keypath_application.swift b/test/SILGen/plus_zero_keypath_application.swift
new file mode 100644
index 0000000..1dbd44e
--- /dev/null
+++ b/test/SILGen/plus_zero_keypath_application.swift
@@ -0,0 +1,124 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership %s | %FileCheck %s
+
+class A {}
+class B {}
+protocol P {}
+protocol Q {}
+
+// CHECK-LABEL: sil hidden @{{.*}}loadable
+func loadable(readonly: A, writable: inout A,
+              value: B,
+              kp: KeyPath<A, B>,
+              wkp: WritableKeyPath<A, B>,
+              rkp: ReferenceWritableKeyPath<A, B>) {
+  // CHECK: [[ROOT_TMP:%.*]] = alloc_stack $A
+  // CHECK: [[ROOT_COPY:%.*]] = copy_value %0
+  // CHECK: store [[ROOT_COPY]] to [init] [[ROOT_TMP]]
+  // CHECK: [[KP_COPY:%.*]] = copy_value %3
+  // CHECK: [[PROJECT:%.*]] = function_ref @{{.*}}_projectKeyPathReadOnly
+  // CHECK: [[BORROWED_KP_COPY:%.*]] = begin_borrow [[KP_COPY]]
+  // CHECK: [[RESULT_TMP:%.*]] = alloc_stack $B
+  // CHECK: apply [[PROJECT]]<A, B>([[RESULT_TMP]], [[ROOT_TMP]], [[BORROWED_KP_COPY]])
+  // CHECK: [[RESULT:%.*]] = load [take] [[RESULT_TMP]]
+  // CHECK: destroy_value [[RESULT]]
+  _ = readonly[keyPath: kp]
+  _ = writable[keyPath: kp]
+  _ = readonly[keyPath: wkp]
+
+  // CHECK: function_ref @{{.*}}_projectKeyPathReadOnly
+  _ = writable[keyPath: wkp]
+
+  // CHECK: function_ref @{{.*}}_projectKeyPathReadOnly
+  _ = readonly[keyPath: rkp]
+  // CHECK: function_ref @{{.*}}_projectKeyPathReadOnly
+  _ = writable[keyPath: rkp]
+
+  // CHECK: function_ref @{{.*}}_projectKeyPathWritable
+  writable[keyPath: wkp] = value
+  // CHECK: function_ref @{{.*}}_projectKeyPathReferenceWritable
+  readonly[keyPath: rkp] = value
+  // CHECK: function_ref @{{.*}}_projectKeyPathReferenceWritable
+  writable[keyPath: rkp] = value
+}
+
+// CHECK-LABEL: sil hidden @{{.*}}addressOnly
+func addressOnly(readonly: P, writable: inout P,
+                 value: Q,
+                 kp: KeyPath<P, Q>,
+                 wkp: WritableKeyPath<P, Q>,
+                 rkp: ReferenceWritableKeyPath<P, Q>) {
+  // CHECK: function_ref @{{.*}}_projectKeyPathReadOnly
+  _ = readonly[keyPath: kp]
+  // CHECK: function_ref @{{.*}}_projectKeyPathReadOnly
+  _ = writable[keyPath: kp]
+  // CHECK: function_ref @{{.*}}_projectKeyPathReadOnly
+  _ = readonly[keyPath: wkp]
+
+  // CHECK: function_ref @{{.*}}_projectKeyPathReadOnly
+  _ = writable[keyPath: wkp]
+
+  // CHECK: function_ref @{{.*}}_projectKeyPathReadOnly
+  _ = readonly[keyPath: rkp]
+  // CHECK: function_ref @{{.*}}_projectKeyPathReadOnly
+  _ = writable[keyPath: rkp]
+
+  // CHECK: function_ref @{{.*}}_projectKeyPathWritable
+  writable[keyPath: wkp] = value
+  // CHECK: function_ref @{{.*}}_projectKeyPathReferenceWritable
+  readonly[keyPath: rkp] = value
+  // CHECK: function_ref @{{.*}}_projectKeyPathReferenceWritable
+  writable[keyPath: rkp] = value
+}
+
+// CHECK-LABEL: sil hidden @{{.*}}reabstracted
+func reabstracted(readonly: @escaping () -> (),
+                  writable: inout () -> (),
+                  value: @escaping (A) -> B,
+                  kp: KeyPath<() -> (), (A) -> B>,
+                  wkp: WritableKeyPath<() -> (), (A) -> B>,
+                  rkp: ReferenceWritableKeyPath<() -> (), (A) -> B>) {
+  // CHECK: [[PROJECT:%.*]] = function_ref @{{.*}}_projectKeyPathReadOnly
+  _ = readonly[keyPath: kp]
+  // CHECK: [[PROJECT:%.*]] = function_ref @{{.*}}_projectKeyPathReadOnly
+  _ = writable[keyPath: kp]
+  // CHECK: [[PROJECT:%.*]] = function_ref @{{.*}}_projectKeyPathReadOnly
+  _ = readonly[keyPath: wkp]
+
+  // CHECK: [[PROJECT:%.*]] = function_ref @{{.*}}_projectKeyPathReadOnly
+  _ = writable[keyPath: wkp]
+
+  // CHECK: [[PROJECT:%.*]] = function_ref @{{.*}}_projectKeyPathReadOnly
+  _ = readonly[keyPath: rkp]
+  // CHECK: [[PROJECT:%.*]] = function_ref @{{.*}}_projectKeyPathReadOnly
+  _ = writable[keyPath: rkp]
+
+  // CHECK: [[PROJECT:%.*]] = function_ref @{{.*}}_projectKeyPathWritable
+  writable[keyPath: wkp] = value
+  // CHECK: [[PROJECT:%.*]] = function_ref @{{.*}}_projectKeyPathReferenceWritable
+  readonly[keyPath: rkp] = value
+  // CHECK: [[PROJECT:%.*]] = function_ref @{{.*}}_projectKeyPathReferenceWritable
+  writable[keyPath: rkp] = value
+}
+
+// CHECK-LABEL: sil hidden @{{.*}}partial
+func partial<A>(valueA: A,
+                valueB: Int,
+                pkpA: PartialKeyPath<A>,
+                pkpB: PartialKeyPath<Int>,
+                akp: AnyKeyPath) {
+  // CHECK: [[PROJECT:%.*]] = function_ref @{{.*}}projectKeyPathAny
+  // CHECK: apply [[PROJECT]]<A>
+  _ = valueA[keyPath: akp]
+  // CHECK: [[PROJECT:%.*]] = function_ref @{{.*}}projectKeyPathPartial
+  // CHECK: apply [[PROJECT]]<A>
+  _ = valueA[keyPath: pkpA]
+
+  // CHECK: [[PROJECT:%.*]] = function_ref @{{.*}}projectKeyPathAny
+  // CHECK: apply [[PROJECT]]<Int>
+  _ = valueB[keyPath: akp]
+  // CHECK: [[PROJECT:%.*]] = function_ref @{{.*}}projectKeyPathPartial
+  // CHECK: apply [[PROJECT]]<Int>
+  _ = valueB[keyPath: pkpB]
+}
+
diff --git a/test/SILGen/plus_zero_keypaths.swift b/test/SILGen/plus_zero_keypaths.swift
new file mode 100644
index 0000000..db06785
--- /dev/null
+++ b/test/SILGen/plus_zero_keypaths.swift
@@ -0,0 +1,339 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership %s | %FileCheck %s
+
+struct S<T> {
+  var x: T
+  let y: String
+  var z: C<T>
+
+  var computed: C<T> { fatalError() }
+  var observed: C<T> { didSet { fatalError() } }
+  var reabstracted: () -> ()
+}
+class C<T> {
+  final var x: T
+  final let y: String
+  final var z: S<T>
+
+  var nonfinal: S<T>
+  var computed: S<T> { fatalError() }
+  var observed: S<T> { didSet { fatalError() } }
+  final var reabstracted: () -> ()
+
+  init() { fatalError() }
+}
+
+protocol P {
+  var x: Int { get }
+  var y: String { get set }
+}
+
+extension P {
+  var z: String {
+    return y
+  }
+  var w: String {
+    get { return "" }
+    nonmutating set { }
+  }
+}
+
+// CHECK-LABEL: sil hidden @{{.*}}storedProperties
+func storedProperties<T>(_: T) {
+  // CHECK: keypath $WritableKeyPath<S<T>, T>, <τ_0_0> (root $S<τ_0_0>; stored_property #S.x : $τ_0_0) <T>
+  _ = \S<T>.x
+  // CHECK: keypath $KeyPath<S<T>, String>, <τ_0_0> (root $S<τ_0_0>; stored_property #S.y : $String) <T>
+  _ = \S<T>.y
+  // CHECK: keypath $ReferenceWritableKeyPath<S<T>, T>, <τ_0_0> (root $S<τ_0_0>; stored_property #S.z : $C<τ_0_0>; stored_property #C.x : $τ_0_0) <T>
+  _ = \S<T>.z.x
+  // CHECK: keypath $ReferenceWritableKeyPath<C<T>, T>, <τ_0_0> (root $C<τ_0_0>; stored_property #C.x : $τ_0_0) <T>
+  _ = \C<T>.x
+  // CHECK: keypath $KeyPath<C<T>, String>, <τ_0_0> (root $C<τ_0_0>; stored_property #C.y : $String) <T>
+  _ = \C<T>.y
+  // CHECK: keypath $ReferenceWritableKeyPath<C<T>, T>, <τ_0_0> (root $C<τ_0_0>; stored_property #C.z : $S<τ_0_0>; stored_property #S.x : $τ_0_0) <T>
+  _ = \C<T>.z.x
+  // CHECK: keypath $KeyPath<C<T>, String>, <τ_0_0> (root $C<τ_0_0>; stored_property #C.z : $S<τ_0_0>; stored_property #S.z : $C<τ_0_0>; stored_property #C.y : $String) <T>
+  _ = \C<T>.z.z.y
+}
+
+// CHECK-LABEL: sil hidden @{{.*}}computedProperties
+func computedProperties<T: P>(_: T) {
+  // CHECK: keypath $ReferenceWritableKeyPath<C<T>, S<T>>, <τ_0_0 where τ_0_0 : P> (
+  // CHECK-SAME: root $C<τ_0_0>;
+  // CHECK-SAME: settable_property $S<τ_0_0>, 
+  // CHECK-SAME:   id #C.nonfinal!getter.1 : <T> (C<T>) -> () -> S<T>,
+  // CHECK-SAME:   getter @$S8keypaths1CC8nonfinalAA1SVyxGvpAA1PRzlACyxGTK : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@in_guaranteed C<τ_0_0>) -> @out S<τ_0_0>,
+  // CHECK-SAME:   setter @$S8keypaths1CC8nonfinalAA1SVyxGvpAA1PRzlACyxGTk : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@in_guaranteed S<τ_0_0>, @in_guaranteed C<τ_0_0>) -> ()
+  // CHECK-SAME: ) <T>
+  _ = \C<T>.nonfinal
+
+  // CHECK: keypath $KeyPath<C<T>, S<T>>, <τ_0_0 where τ_0_0 : P> (
+  // CHECK-SAME: root $C<τ_0_0>;
+  // CHECK-SAME: gettable_property $S<τ_0_0>,
+  // CHECK-SAME:   id #C.computed!getter.1 : <T> (C<T>) -> () -> S<T>,
+  // CHECK-SAME:   getter @$S8keypaths1CC8computedAA1SVyxGvpAA1PRzlACyxGTK : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@in_guaranteed C<τ_0_0>) -> @out S<τ_0_0>
+  // CHECK-SAME: ) <T>
+  _ = \C<T>.computed
+
+  // CHECK: keypath $ReferenceWritableKeyPath<C<T>, S<T>>, <τ_0_0 where τ_0_0 : P> (
+  // CHECK-SAME: root $C<τ_0_0>;
+  // CHECK-SAME: settable_property $S<τ_0_0>, 
+  // CHECK-SAME:   id #C.observed!getter.1 : <T> (C<T>) -> () -> S<T>,
+  // CHECK-SAME:   getter @$S8keypaths1CC8observedAA1SVyxGvpAA1PRzlACyxGTK : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@in_guaranteed C<τ_0_0>) -> @out S<τ_0_0>,
+  // CHECK-SAME:   setter @$S8keypaths1CC8observedAA1SVyxGvpAA1PRzlACyxGTk : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@in_guaranteed S<τ_0_0>, @in_guaranteed C<τ_0_0>) -> ()
+  // CHECK-SAME: ) <T>
+  _ = \C<T>.observed
+
+  _ = \C<T>.nonfinal.x
+  _ = \C<T>.computed.x
+  _ = \C<T>.observed.x
+  _ = \C<T>.z.computed
+  _ = \C<T>.z.observed
+  _ = \C<T>.observed.x
+
+  // CHECK: keypath $ReferenceWritableKeyPath<C<T>, () -> ()>, <τ_0_0 where τ_0_0 : P> (
+  // CHECK-SAME: root $C<τ_0_0>;
+  // CHECK-SAME: settable_property $() -> (), 
+  // CHECK-SAME:   id ##C.reabstracted,
+  // CHECK-SAME:   getter @$S8keypaths1CC12reabstractedyycvpAA1PRzlACyxGTK : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@in_guaranteed C<τ_0_0>) -> @out @callee_guaranteed (@in_guaranteed ()) -> @out (),
+  // CHECK-SAME:   setter @$S8keypaths1CC12reabstractedyycvpAA1PRzlACyxGTk : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@in_guaranteed @callee_guaranteed (@in_guaranteed ()) -> @out (), @in_guaranteed C<τ_0_0>) -> ()
+  // CHECK-SAME: ) <T>
+  _ = \C<T>.reabstracted
+
+  // CHECK: keypath $KeyPath<S<T>, C<T>>, <τ_0_0 where τ_0_0 : P> (
+  // CHECK-SAME: root $S<τ_0_0>; gettable_property $C<τ_0_0>,
+  // CHECK-SAME: id @$S8keypaths1SV8computedAA1CCyxGvg : $@convention(method) <τ_0_0> (@in_guaranteed S<τ_0_0>) -> @owned C<τ_0_0>,
+  // CHECK-SAME:   getter @$S8keypaths1SV8computedAA1CCyxGvpAA1PRzlACyxGTK : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@in_guaranteed S<τ_0_0>) -> @out C<τ_0_0>
+  // CHECK-SAME: ) <T>
+  _ = \S<T>.computed
+
+  // CHECK: keypath $WritableKeyPath<S<T>, C<T>>, <τ_0_0 where τ_0_0 : P> (
+  // CHECK-SAME: root $S<τ_0_0>;
+  // CHECK-SAME: settable_property $C<τ_0_0>,
+  // CHECK-SAME:   id @$S8keypaths1SV8observedAA1CCyxGvg : $@convention(method) <τ_0_0> (@in_guaranteed S<τ_0_0>) -> @owned C<τ_0_0>,
+  // CHECK-SAME:   getter @$S8keypaths1SV8observedAA1CCyxGvpAA1PRzlACyxGTK : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@in_guaranteed S<τ_0_0>) -> @out C<τ_0_0>,
+  // CHECK-SAME:   setter @$S8keypaths1SV8observedAA1CCyxGvpAA1PRzlACyxGTk : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@in_guaranteed C<τ_0_0>, @inout S<τ_0_0>) -> ()
+  // CHECK-SAME: ) <T>
+  _ = \S<T>.observed
+  _ = \S<T>.z.nonfinal
+  _ = \S<T>.z.computed
+  _ = \S<T>.z.observed
+  _ = \S<T>.computed.x
+  _ = \S<T>.computed.y
+  // CHECK: keypath $WritableKeyPath<S<T>, () -> ()>, <τ_0_0 where τ_0_0 : P> (
+  // CHECK-SAME:  root $S<τ_0_0>;
+  // CHECK-SAME:  settable_property $() -> (),
+  // CHECK-SAME:    id ##S.reabstracted,
+  // CHECK-SAME:    getter @$S8keypaths1SV12reabstractedyycvpAA1PRzlACyxGTK : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@in_guaranteed S<τ_0_0>) -> @out @callee_guaranteed (@in_guaranteed ()) -> @out (),
+  // CHECK-SAME:    setter @$S8keypaths1SV12reabstractedyycvpAA1PRzlACyxGTk : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@in_guaranteed @callee_guaranteed (@in_guaranteed ()) -> @out (), @inout S<τ_0_0>) -> ()
+  // CHECK-SAME: ) <T>
+  _ = \S<T>.reabstracted
+
+  // CHECK: keypath $KeyPath<T, Int>, <τ_0_0 where τ_0_0 : P> (
+  // CHECK-SAME: root $τ_0_0;
+  // CHECK-SAME: gettable_property $Int, 
+  // CHECK-SAME:   id #P.x!getter.1 : <Self where Self : P> (Self) -> () -> Int,
+  // CHECK-SAME:   getter @$S8keypaths1PP1xSivpAaBRzlxTK : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @out Int
+  // CHECK-SAME: ) <T>
+  _ = \T.x
+  // CHECK: keypath $WritableKeyPath<T, String>, <τ_0_0 where τ_0_0 : P> (
+  // CHECK-SAME: root $τ_0_0;
+  // CHECK-SAME: settable_property $String,
+  // CHECK-SAME:   id #P.y!getter.1 : <Self where Self : P> (Self) -> () -> String,
+  // CHECK-SAME:   getter @$S8keypaths1PP1ySSvpAaBRzlxTK : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @out String,
+  // CHECK-SAME:   setter @$S8keypaths1PP1ySSvpAaBRzlxTk : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@in_guaranteed String, @inout τ_0_0) -> ()
+  // CHECK-SAME: ) <T>
+  _ = \T.y
+
+  // CHECK: keypath $KeyPath<T, String>, <τ_0_0 where τ_0_0 : P> (
+  // CHECK-SAME: root $τ_0_0;
+  // CHECK-SAME: gettable_property $String,
+  // CHECK-SAME:   id @$S8keypaths1PPAAE1zSSvg
+  _ = \T.z
+}
+
+struct Concrete: P {
+  var x: Int
+  var y: String
+}
+
+// CHECK-LABEL: sil hidden @$S8keypaths35keyPathsWithSpecificGenericInstanceyyF
+func keyPathsWithSpecificGenericInstance() {
+  // CHECK: keypath $KeyPath<Concrete, String>, (
+  // CHECK-SAME: gettable_property $String,
+  // CHECK-SAME:   id @$S8keypaths1PPAAE1zSSvg
+  // CHECK-SAME:   getter @$S8keypaths1PPAAE1zSSvpAA8ConcreteVTK : $@convention(thin) (@in_guaranteed Concrete) -> @out String
+  _ = \Concrete.z
+  _ = \S<Concrete>.computed
+}
+
+class AA<T> {
+  var a: Int { get { return 0 } set { } }
+}
+class BB<U, V>: AA<V> {
+}
+
+func keyPathForInheritedMember() {
+  _ = \BB<Int, String>.a
+}
+
+func keyPathForExistentialMember() {
+  _ = \P.x
+  _ = \P.y
+  _ = \P.z
+  _ = \P.w
+}
+
+struct OptionalFields {
+  var x: S<Int>?
+}
+struct OptionalFields2 {
+  var y: OptionalFields?
+}
+
+// CHECK-LABEL: sil hidden @$S8keypaths18keyPathForOptionalyyF
+func keyPathForOptional() {
+  // CHECK: keypath $WritableKeyPath<OptionalFields, S<Int>>, (
+  // CHECK-SAME:   stored_property #OptionalFields.x : $Optional<S<Int>>;
+  // CHECK-SAME:   optional_force : $S<Int>)
+  _ = \OptionalFields.x!
+  // CHECK: keypath $KeyPath<OptionalFields, Optional<String>>, (
+  // CHECK-SAME:   stored_property #OptionalFields.x : $Optional<S<Int>>;
+  // CHECK-SAME:   optional_chain : $S<Int>;
+  // CHECK-SAME:   stored_property #S.y : $String;
+  // CHECK-SAME:   optional_wrap : $Optional<String>)
+  _ = \OptionalFields.x?.y
+  // CHECK: keypath $KeyPath<OptionalFields2, Optional<S<Int>>>, (
+  // CHECK-SAME:   root $OptionalFields2;
+  // CHECK-SAME:   stored_property #OptionalFields2.y : $Optional<OptionalFields>;
+  // CHECK-SAME:   optional_chain : $OptionalFields;
+  // CHECK-SAME:   stored_property #OptionalFields.x : $Optional<S<Int>>)
+  _ = \OptionalFields2.y?.x
+}
+
+class StorageQualified {
+  weak var tooWeak: StorageQualified?
+  unowned var disowned: StorageQualified
+  
+  init() { fatalError() }
+}
+
+final class FinalStorageQualified {
+  weak var tooWeak: StorageQualified?
+  unowned var disowned: StorageQualified
+  
+  init() { fatalError() }
+}
+
+// CHECK-LABEL: sil hidden @{{.*}}keyPathForStorageQualified
+func keyPathForStorageQualified() {
+  // CHECK: = keypath $ReferenceWritableKeyPath<StorageQualified, Optional<StorageQualified>>,
+  // CHECK-SAME: settable_property $Optional<StorageQualified>, id #StorageQualified.tooWeak!getter.1
+  _ = \StorageQualified.tooWeak
+  // CHECK: = keypath $ReferenceWritableKeyPath<StorageQualified, StorageQualified>,
+  // CHECK-SAME: settable_property $StorageQualified, id #StorageQualified.disowned!getter.1
+  _ = \StorageQualified.disowned
+
+  // CHECK: = keypath $ReferenceWritableKeyPath<FinalStorageQualified, Optional<StorageQualified>>,
+  // CHECK-SAME: settable_property $Optional<StorageQualified>, id ##FinalStorageQualified.tooWeak
+  _ = \FinalStorageQualified.tooWeak
+  // CHECK: = keypath $ReferenceWritableKeyPath<FinalStorageQualified, StorageQualified>,
+  // CHECK-SAME: settable_property $StorageQualified, id ##FinalStorageQualified.disowned
+  _ = \FinalStorageQualified.disowned
+}
+
+struct IUOProperty {
+  var iuo: IUOBlob!
+}
+
+struct IUOBlob {
+  var x: Int
+  subscript(y: String) -> String {
+    get { return y }
+    set {}
+  }
+}
+
+// CHECK-LABEL: sil hidden @{{.*}}11iuoKeyPaths
+func iuoKeyPaths() {
+  // CHECK: = keypath $WritableKeyPath<IUOProperty, Int>,
+  // CHECK-SAME: stored_property #IUOProperty.iuo
+  // CHECK-SAME: optional_force
+  // CHECK-SAME: stored_property #IUOBlob.x
+  _ = \IUOProperty.iuo.x
+  // CHECK: = keypath $WritableKeyPath<IUOProperty, Int>,
+  // CHECK-SAME: stored_property #IUOProperty.iuo
+  // CHECK-SAME: optional_force
+  // CHECK-SAME: stored_property #IUOBlob.x
+  _ = \IUOProperty.iuo!.x
+}
+
+class Bass: Hashable {
+  static func ==(_: Bass, _: Bass) -> Bool { return false }
+  var hashValue: Int { return 0 }
+}
+
+class Treble: Bass { }
+
+struct Subscripts<T> {
+  subscript() -> T {
+    get { fatalError() }
+    set { fatalError() }
+  }
+  subscript(generic x: T) -> T {
+    get { fatalError() }
+    set { fatalError() }
+  }
+  subscript(concrete x: String) -> String {
+    get { fatalError() }
+    set { fatalError() }
+  }
+  subscript(x: String, y: String) -> String {
+    get { fatalError() }
+    set { fatalError() }
+  }
+  subscript<U>(subGeneric z: U) -> U {
+    get { fatalError() }
+    set { fatalError() }
+  }
+  subscript(mutable x: T) -> T {
+    get { fatalError() }
+    set { fatalError() }
+  }
+  subscript(bass: Bass) -> Bass {
+    get { return bass }
+    set { }
+  }
+}
+
+// CHECK-LABEL: sil hidden @{{.*}}10subscripts
+func subscripts<T: Hashable, U: Hashable>(x: T, y: U, s: String) {
+  _ = \Subscripts<T>.[]
+  _ = \Subscripts<T>.[generic: x]
+  _ = \Subscripts<T>.[concrete: s]
+  _ = \Subscripts<T>.[s, s]
+  _ = \Subscripts<T>.[subGeneric: s]
+  _ = \Subscripts<T>.[subGeneric: x]
+  _ = \Subscripts<T>.[subGeneric: y]
+
+  _ = \Subscripts<U>.[]
+  _ = \Subscripts<U>.[generic: y]
+  _ = \Subscripts<U>.[concrete: s]
+  _ = \Subscripts<U>.[s, s]
+  _ = \Subscripts<U>.[subGeneric: s]
+  _ = \Subscripts<U>.[subGeneric: x]
+  _ = \Subscripts<U>.[subGeneric: y]
+
+  _ = \Subscripts<String>.[]
+  _ = \Subscripts<String>.[generic: s]
+  _ = \Subscripts<String>.[concrete: s]
+  _ = \Subscripts<String>.[s, s]
+  _ = \Subscripts<String>.[subGeneric: s]
+  _ = \Subscripts<String>.[subGeneric: x]
+  _ = \Subscripts<String>.[subGeneric: y]
+
+  _ = \Subscripts<T>.[s, s].count
+
+  _ = \Subscripts<T>.[Bass()]
+  _ = \Subscripts<T>.[Treble()]
+}
diff --git a/test/SILGen/plus_zero_let_decls.swift b/test/SILGen/plus_zero_let_decls.swift
new file mode 100644
index 0000000..d0f7379
--- /dev/null
+++ b/test/SILGen/plus_zero_let_decls.swift
@@ -0,0 +1,518 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -Xllvm -sil-full-demangle -emit-silgen -enable-sil-ownership %s | %FileCheck %s
+
+func takeClosure(_ a : () -> Int) {}
+
+// Let decls don't get boxes for trivial types.
+//
+// CHECK-LABEL: sil hidden @{{.*}}test1
+func test1(_ a : Int) -> Int {
+  // CHECK-NOT: alloc_box
+  // FIXME(integers): the following check should be updated for the new way +
+  // gets invoked. <rdar://problem/29939484>
+  // XCHECK-NOT: alloc_stack
+
+  let (b,c) = (a, 32)
+
+  return b+c
+  
+  // CHECK: return
+}
+
+// rdar://15716277
+// CHECK: @{{.*}}_destructuring
+func let_destructuring() -> Int {
+  let (a, b) = ((1,2), 5)
+  return a.1+a.0+b
+}
+
+// Let decls being closed over.
+//
+// CHECK-LABEL: sil hidden @{{.*}}test2
+func test2() {
+  // No allocations.
+  // CHECK-NOT: alloc_box
+  // CHECK-NOT: alloc_stack
+
+  let x = 42
+
+  takeClosure({x})
+
+
+  // CHECK: return
+}
+
+// The closure just returns its value, which it captured directly.
+
+// CHECK: sil private @$S9let_decls5test2yyFSiyXEfU_ : $@convention(thin) (Int) -> Int
+// CHECK: bb0(%0 : @trivial $Int):
+// CHECK:  return %0 : $Int
+
+// Verify that we can close over let decls of tuple type.
+struct RegularStruct {
+  var a: Int
+}
+func testTupleLetCapture() {
+  let t = (RegularStruct(a: 41), 42)
+
+  takeClosure( { t.0.a })
+}
+
+
+
+func getAString() -> String { return "" }
+func useAString(_ a : String) {}
+
+// rdar://15689514 - Verify that the cleanup for the let decl runs at the end of
+// the 'let' lifetime, not at the end of the initializing expression.
+//
+// CHECK-LABEL: sil hidden @{{.*}}test3
+func test3() {
+  // CHECK: [[GETFN:%[0-9]+]] = function_ref{{.*}}getAString
+  // CHECK-NEXT: [[STR:%[0-9]+]] = apply [[GETFN]]()
+  let o = getAString()
+
+  // CHECK-NEXT: debug_value
+  // CHECK-NOT: destroy_value
+
+  // CHECK-NEXT: [[STR_BORROW:%.*]] = begin_borrow [[STR]]
+  // CHECK: [[USEFN:%[0-9]+]] = function_ref{{.*}}useAString
+  // CHECK-NEXT: [[USE:%[0-9]+]] = apply [[USEFN]]([[STR_BORROW]])
+  useAString(o)
+  
+  // CHECK: destroy_value [[STR]]
+}
+// CHECK: } // end sil function '{{.*}}test3{{.*}}'
+
+
+
+struct AddressOnlyStruct<T> {
+  var elt : T
+  var str : String
+}
+
+func produceAddressOnlyStruct<T>(_ x : T) -> AddressOnlyStruct<T> {}
+
+// CHECK-LABEL: sil hidden @{{.*}}testAddressOnlyStructString
+// CHECK: bb0([[FUNC_ARG:%.*]] : @trivial $*T):
+func testAddressOnlyStructString<T>(_ a : T) -> String {
+  return produceAddressOnlyStruct(a).str
+  
+  // CHECK: [[TMPSTRUCT:%[0-9]+]] = alloc_stack $AddressOnlyStruct<T>
+  // CHECK: [[PRODFN:%[0-9]+]] = function_ref @{{.*}}produceAddressOnlyStruct
+  // CHECK: apply [[PRODFN]]<T>([[TMPSTRUCT]], [[FUNC_ARG]])
+  // CHECK-NEXT: [[STRADDR:%[0-9]+]] = struct_element_addr [[TMPSTRUCT]] : $*AddressOnlyStruct<T>, #AddressOnlyStruct.str
+  // CHECK-NEXT: [[STRVAL:%[0-9]+]] = load [copy] [[STRADDR]]
+  // CHECK-NEXT: destroy_addr [[TMPSTRUCT]]
+  // CHECK-NEXT: dealloc_stack [[TMPSTRUCT]]
+  // CHECK: return [[STRVAL]]
+}
+
+// CHECK-LABEL: sil hidden @{{.*}}testAddressOnlyStructElt
+func testAddressOnlyStructElt<T>(_ a : T) -> T {
+  return produceAddressOnlyStruct(a).elt
+  // CHECK: bb0([[ARG0:%.*]] : @trivial $*T, [[ARG1:%.*]] : @trivial $*T):
+  // CHECK: [[TMPSTRUCT:%[0-9]+]] = alloc_stack $AddressOnlyStruct<T>
+  // CHECK: [[PRODFN:%[0-9]+]] = function_ref @{{.*}}produceAddressOnlyStruct
+  // CHECK: apply [[PRODFN]]<T>([[TMPSTRUCT]], [[ARG1]])
+  // CHECK-NEXT: [[ELTADDR:%[0-9]+]] = struct_element_addr [[TMPSTRUCT]] : $*AddressOnlyStruct<T>, #AddressOnlyStruct.elt
+  // CHECK-NEXT: copy_addr [[ELTADDR]] to [initialization] %0 : $*T
+  // CHECK-NEXT: destroy_addr [[TMPSTRUCT]]
+}
+
+
+
+// rdar://15717123 - let decls of address-only type.
+
+// CHECK-LABEL: sil hidden @{{.*}}testAddressOnlyLet
+func testAddressOnlyLet<T>(_ a : T) {
+  let x = produceAddressOnlyStruct(a)
+}
+
+
+func produceSubscriptableRValue() -> [String] {}
+
+// CHECK-LABEL: sil hidden @{{.*}}subscriptRValue
+func subscriptRValue() {
+  var a = produceSubscriptableRValue()[0]
+}
+
+
+struct GetOnlySubscriptStruct {
+  // get-only subscript
+  subscript (i : Int) -> Int { get {} }
+}
+
+
+// CHECK-LABEL: sil hidden @{{.*}}testGetOnlySubscript
+func testGetOnlySubscript(_ x : GetOnlySubscriptStruct, idx : Int) -> Int {
+  return x[idx]
+  
+  // CHECK: [[SUBFN:%[0-9]+]] = function_ref @{{.*}}i
+  // CHECK-NEXT: [[CALL:%[0-9]+]] = apply [[SUBFN]](
+  // CHECK: return [[CALL]]
+}
+
+// Address-only let's get captured by box.
+extension Optional {
+  func getLV() -> Int { }
+}
+struct CloseOverAddressOnlyConstant<T> {
+  func isError() {
+    let AOV: T?
+    takeClosure({ AOV.getLV() })
+  }
+  
+}
+
+// CHECK-LABEL: sil hidden @{{.*}}callThroughLet
+func callThroughLet(_ predicate: @escaping (Int, Int) -> Bool) {
+  let p = predicate
+  if p(1, 2) {
+  }
+}
+
+
+// Verify that we can emit address-only rvalues directly into the result slot in
+// chained calls.
+struct GenericTestStruct<T> {
+   func pass_address_only_rvalue_result(_ i: Int) -> T {
+     return self[i]
+   }
+   subscript (i : Int) -> T {
+   get {}
+   set {}
+   }
+}
+
+// CHECK-LABEL: sil hidden @{{.*}}pass_address_only_rvalue_result
+// CHECK: bb0(%0 : @trivial $*T,
+// CHECK: [[FN:%[0-9]+]] = function_ref @{{.*}}GenericTestStructV{{.*}}ig
+// CHECK: apply [[FN]]<T>(%0,
+
+
+struct NonMutableSubscriptable {
+  subscript(x : Int) -> Int {
+    get {}
+    nonmutating
+    set {}
+  }
+}
+
+func produceNMSubscriptableRValue() -> NonMutableSubscriptable {}
+
+
+// CHECK-LABEL: sil hidden @{{.*}}test_nm_subscript_get
+// CHECK: bb0(%0 : @trivial $Int):
+// CHECK: [[FR1:%[0-9]+]] = function_ref @{{.*}}produceNMSubscriptableRValue
+// CHECK-NEXT: [[RES:%[0-9]+]] = apply [[FR1]]()
+// CHECK: [[GETFN:%[0-9]+]] = function_ref @$S9let_decls23NonMutableSubscriptableV{{[_0-9a-zA-Z]*}}ig
+// CHECK-NEXT: [[RES2:%[0-9]+]] = apply [[GETFN]](%0, [[RES]])
+// CHECK-NEXT: return [[RES2]]
+func test_nm_subscript_get(_ a : Int) -> Int {
+  return produceNMSubscriptableRValue()[a]
+}
+
+// CHECK-LABEL: sil hidden @{{.*}}test_nm_subscript_set
+// CHECK: bb0(%0 : @trivial $Int):
+// CHECK: [[FR1:%[0-9]+]] = function_ref @{{.*}}produceNMSubscriptableRValue
+// CHECK-NEXT: [[RES:%[0-9]+]] = apply [[FR1]]()
+// CHECK: [[SETFN:%[0-9]+]] = function_ref @$S9let_decls23NonMutableSubscriptableV{{[_0-9a-zA-Z]*}}is
+// CHECK-NEXT: [[RES2:%[0-9]+]] = apply [[SETFN]](%0, %0, [[RES]])
+func test_nm_subscript_set(_ a : Int) {
+  produceNMSubscriptableRValue()[a] = a
+}
+
+struct WeirdPropertyTest {
+  // This property has a mutating getter and !mutating setter.
+  var p : Int {
+  mutating
+  get {}
+  nonmutating
+  set {}
+  }
+}
+
+// CHECK-LABEL: sil hidden @{{.*}}test_weird_property
+func test_weird_property(_ v : WeirdPropertyTest, i : Int) -> Int {
+  var v = v
+  // CHECK: [[VBOX:%[0-9]+]] = alloc_box ${ var WeirdPropertyTest }
+  // CHECK: [[PB:%.*]] = project_box [[VBOX]]
+  // CHECK: store %0 to [trivial] [[PB]]
+
+  // The setter isn't mutating, so we need to load the box.
+  // CHECK: [[READ:%.*]] = begin_access [read] [unknown] [[PB]]
+  // CHECK: [[VVAL:%[0-9]+]] = load [trivial] [[READ]]
+  // CHECK: [[SETFN:%[0-9]+]] = function_ref @$S9let_decls17WeirdPropertyTestV1pSivs
+  // CHECK: apply [[SETFN]](%1, [[VVAL]])
+  v.p = i
+  
+  // The getter is mutating, so it takes the box address.
+  // CHECK: [[WRITE:%.*]] = begin_access [modify] [unknown] [[PB]]
+  // CHECK: [[GETFN:%[0-9]+]] = function_ref @$S9let_decls17WeirdPropertyTestV1pSivg
+  // CHECK-NEXT: [[RES:%[0-9]+]] = apply [[GETFN]]([[WRITE]])
+  // CHECK: return [[RES]]
+  return v.p
+}
+
+
+// CHECK-LABEL: sil hidden @{{.*}}generic_identity
+// CHECK: bb0(%0 : @trivial $*T, %1 : @trivial $*T):
+// CHECK-NEXT: debug_value_addr %1 : $*T
+// CHECK-NEXT: copy_addr %1 to [initialization] %0 : $*T
+// CHECK-NOT: destroy_addr %1
+// CHECK: } // end sil function '{{.*}}generic_identity{{.*}}'
+func generic_identity<T>(_ a : T) -> T {
+  // Should be a single copy_addr, with no temporary.
+  return a
+}
+
+struct StaticLetMember {
+  static let x = 5
+}
+
+// CHECK-LABEL: sil hidden @{{.*}}testStaticLetMember
+func testStaticLetMember() -> Int {
+
+  // CHECK: function_ref @{{.*}}StaticLetMemberV1xSi
+  // CHECK: load {{.*}} : $*Int
+  // CHECK-NEXT: return
+  return StaticLetMember.x
+}
+
+protocol SimpleProtocol {
+  func doSomethingGreat()
+}
+
+// Verify that no temporaries+copies are produced when calling non-@mutable
+// methods on protocol and archetypes calls.
+
+// CHECK-LABEL: sil hidden @{{.*}}testLetProtocolBases
+// CHECK: bb0(%0 : @trivial $*SimpleProtocol):
+func testLetProtocolBases(_ p : SimpleProtocol) {
+  // CHECK-NEXT: debug_value_addr
+  // CHECK-NEXT: open_existential_addr
+  // CHECK-NEXT: witness_method
+  // CHECK-NEXT: apply
+  p.doSomethingGreat()
+
+  // CHECK-NEXT: open_existential_addr
+  // CHECK-NEXT: witness_method
+  // CHECK-NEXT: apply
+  p.doSomethingGreat()
+  
+  // CHECK-NOT: destroy_addr %0
+  // CHECK-NEXT: tuple
+  // CHECK-NEXT: return
+}
+
+// CHECK-LABEL: sil hidden @{{.*}}testLetArchetypeBases
+// CHECK: bb0(%0 : @trivial $*T):
+func testLetArchetypeBases<T : SimpleProtocol>(_ p : T) {
+  // CHECK-NEXT: debug_value_addr
+  // CHECK-NEXT: witness_method $T
+  // CHECK-NEXT: apply
+  p.doSomethingGreat()
+  // CHECK-NEXT: witness_method $T
+  // CHECK-NEXT: apply
+  p.doSomethingGreat()
+
+  // CHECK-NOT: destroy_addr %0
+  // CHECK-NEXT: tuple
+  // CHECK-NEXT: return
+}
+
+// CHECK-LABEL: sil hidden @{{.*}}testDebugValue
+// CHECK: bb0(%0 : @trivial $Int, %1 : @trivial $*SimpleProtocol):
+// CHECK-NEXT: debug_value %0 : $Int, let, name "a"
+// CHECK-NEXT: debug_value_addr %1 : $*SimpleProtocol, let, name "b"
+func testDebugValue(_ a : Int, b : SimpleProtocol) -> Int {
+
+  // CHECK-NEXT: debug_value %0 : $Int, let, name "x"
+  let x = a
+
+  // CHECK: apply
+  b.doSomethingGreat()
+  
+  // CHECK-NOT: destroy_addr
+
+  // CHECK: return %0
+  return x
+}
+
+
+// CHECK-LABEL: sil hidden @{{.*}}testAddressOnlyTupleArgument
+func testAddressOnlyTupleArgument(_ bounds: (start: SimpleProtocol, pastEnd: Int)) {
+// CHECK:       bb0(%0 : @trivial $*SimpleProtocol, %1 : @trivial $Int):
+// CHECK-NEXT:    %2 = alloc_stack $(start: SimpleProtocol, pastEnd: Int), let, name "bounds"
+// CHECK-NEXT:    %3 = tuple_element_addr %2 : $*(start: SimpleProtocol, pastEnd: Int), 0
+// CHECK-NEXT:    copy_addr %0 to [initialization] %3 : $*SimpleProtocol
+// CHECK-NEXT:    %5 = tuple_element_addr %2 : $*(start: SimpleProtocol, pastEnd: Int), 1
+// CHECK-NEXT:    store %1 to [trivial] %5 : $*Int
+// CHECK-NEXT:    debug_value_addr %2
+// CHECK-NEXT:    destroy_addr %2 : $*(start: SimpleProtocol, pastEnd: Int)
+// CHECK-NEXT:    dealloc_stack %2 : $*(start: SimpleProtocol, pastEnd: Int)
+}
+
+
+func address_only_let_closure<T>(_ x:T) -> T {
+  return { { x }() }()
+}
+
+struct GenericFunctionStruct<T, U> {
+  var f: (T) -> U
+}
+
+
+// CHECK-LABEL: sil hidden @{{.*}}member_ref_abstraction_change
+// CHECK: function_ref reabstraction thunk helper
+// CHECK: return
+func member_ref_abstraction_change(_ x: GenericFunctionStruct<Int, Int>) -> (Int) -> Int {
+  return x.f
+}
+
+// CHECK-LABEL: sil hidden @{{.*}}call_auto_closure
+// CHECK: bb0([[CLOSURE:%.*]] : @trivial $@noescape @callee_guaranteed () -> Bool):
+// CHECK:   apply [[CLOSURE]]() : $@noescape @callee_guaranteed () -> Bool
+// CHECK: } // end sil function '{{.*}}call_auto_closure{{.*}}'
+func call_auto_closure(x: @autoclosure () -> Bool) -> Bool {
+  return x()  // Calls of autoclosures should be marked transparent.
+}
+
+
+class SomeClass {}
+
+struct AnotherStruct {
+  var i : Int
+  var c : SomeClass
+}
+
+struct StructMemberTest {
+  var c : SomeClass
+  var i = 42
+  var s : AnotherStruct
+  var t : (Int, AnotherStruct)
+
+  // rdar://15867140 - Accessing the int member here should not copy_value the
+  // whole struct.
+  func testIntMemberLoad() -> Int {
+    return i
+  }
+  // CHECK-LABEL: sil hidden @$S9let_decls16StructMemberTestV07testIntD4LoadSiyF : $@convention(method) (@guaranteed StructMemberTest)
+  // CHECK: bb0([[ARG:%.*]] : @guaranteed $StructMemberTest):
+  // CHECK:  debug_value [[ARG]] : $StructMemberTest, let, name "self"
+  // CHECK:  [[TRIVIAL_VALUE:%.*]] = struct_extract [[ARG]] : $StructMemberTest, #StructMemberTest.i
+  // CHECK-NOT:  destroy_value [[ARG]] : $StructMemberTest
+  // CHECK-NOT:  destroy_value [[BORROWED_ARG]] : $StructMemberTest
+  // CHECK:  return [[TRIVIAL_VALUE]] : $Int
+
+  // Accessing the int member in s should not copy_value the whole struct.
+  func testRecursiveIntMemberLoad() -> Int {
+    return s.i
+  }
+  // CHECK-LABEL: sil hidden @$S9let_decls16StructMemberTestV016testRecursiveIntD4LoadSiyF : $@convention(method) (@guaranteed StructMemberTest)
+  // CHECK: bb0([[ARG:%.*]] : @guaranteed $StructMemberTest):
+  // CHECK:  debug_value %0 : $StructMemberTest, let, name "self"
+  // CHECK:  %2 = struct_extract %0 : $StructMemberTest, #StructMemberTest.s
+  // CHECK:  %3 = struct_extract %2 : $AnotherStruct, #AnotherStruct.i
+  // CHECK-NOT:  destroy_value %0 : $StructMemberTest
+  // CHECK:  return %3 : $Int
+  
+  func testTupleMemberLoad() -> Int {
+    return t.1.i
+  }
+  // CHECK-LABEL: sil hidden @$S9let_decls16StructMemberTestV09testTupleD4LoadSiyF : $@convention(method) (@guaranteed StructMemberTest)
+  // CHECK: bb0(%0 : @guaranteed $StructMemberTest):
+  // CHECK-NEXT:   debug_value %0 : $StructMemberTest, let, name "self"
+  // CHECK-NEXT:   [[T0:%.*]] = struct_extract %0 : $StructMemberTest, #StructMemberTest.t
+  // CHECK-NEXT:   [[T1:%.*]] = tuple_extract [[T0]] : $(Int, AnotherStruct), 0
+  // CHECK-NEXT:   [[T2:%.*]] = tuple_extract [[T0]] : $(Int, AnotherStruct), 1
+  // CHECK-NEXT:   [[T3:%.*]] = struct_extract [[T2]] : $AnotherStruct, #AnotherStruct.i
+  // CHECK-NEXT:   return [[T3]] : $Int
+
+}
+
+struct GenericStruct<T> {
+  var a : T
+  var b : Int
+
+  func getA() -> T {
+    return a
+  }
+  // CHECK-LABEL: sil hidden @{{.*}}GenericStructV4getA{{.*}} : $@convention(method) <T> (@in_guaranteed GenericStruct<T>) -> @out T
+  // CHECK: bb0(%0 : @trivial $*T, %1 : @trivial $*GenericStruct<T>):
+  // CHECK-NEXT: debug_value_addr %1 : $*GenericStruct<T>, let, name "self"
+  // CHECK-NEXT: %3 = struct_element_addr %1 : $*GenericStruct<T>, #GenericStruct.a
+  // CHECK-NEXT: copy_addr %3 to [initialization] %0 : $*T
+  // CHECK-NEXT: %5 = tuple ()
+  // CHECK-NEXT: return %5 : $()
+
+  func getB() -> Int {
+    return b
+  }
+  
+  // CHECK-LABEL: sil hidden @{{.*}}GenericStructV4getB{{.*}} : $@convention(method) <T> (@in_guaranteed GenericStruct<T>) -> Int
+  // CHECK: bb0([[SELF_ADDR:%.*]] : @trivial $*GenericStruct<T>):
+  // CHECK-NEXT: debug_value_addr [[SELF_ADDR]] : $*GenericStruct<T>, let, name "self"
+  // CHECK-NEXT: [[PROJ_ADDR:%.*]] = struct_element_addr [[SELF_ADDR]] : $*GenericStruct<T>, #GenericStruct.b
+  // CHECK-NEXT: [[PROJ_VAL:%.*]] = load [trivial] [[PROJ_ADDR]] : $*Int
+  // CHECK-NOT: destroy_addr [[SELF]] : $*GenericStruct<T>
+  // CHECK-NEXT: return [[PROJ_VAL]] : $Int
+}
+
+
+// rdar://15877337
+struct LetPropertyStruct {
+  let lp : Int
+}
+
+// CHECK-LABEL: sil hidden @{{.*}}testLetPropertyAccessOnLValueBase
+// CHECK: bb0(%0 : @trivial $LetPropertyStruct):
+// CHECK:  [[ABOX:%[0-9]+]] = alloc_box ${ var LetPropertyStruct }
+// CHECK:  [[A:%[0-9]+]] = project_box [[ABOX]]
+// CHECK:   store %0 to [trivial] [[A]] : $*LetPropertyStruct
+// CHECK:   [[READ:%.*]] = begin_access [read] [unknown] [[A]]
+// CHECK:   [[STRUCT:%[0-9]+]] = load [trivial] [[READ]] : $*LetPropertyStruct
+// CHECK:   [[PROP:%[0-9]+]] = struct_extract [[STRUCT]] : $LetPropertyStruct, #LetPropertyStruct.lp
+// CHECK:   destroy_value [[ABOX]] : ${ var LetPropertyStruct }
+// CHECK:   return [[PROP]] : $Int
+func testLetPropertyAccessOnLValueBase(_ a : LetPropertyStruct) -> Int {
+  var a = a
+  return a.lp
+}
+
+
+var addressOnlyGetOnlyGlobalProperty : SimpleProtocol { get {} }
+
+// CHECK-LABEL: sil hidden @$S9let_decls018testAddressOnlyGetE14GlobalPropertyAA14SimpleProtocol_pyF
+// CHECK: bb0(%0 : @trivial $*SimpleProtocol):
+// CHECK-NEXT:   // function_ref
+// CHECK-NEXT:  %1 = function_ref @$S9let_decls014addressOnlyGetD14GlobalPropertyAA14SimpleProtocol_pvg
+// CHECK-NEXT:  %2 = apply %1(%0) : $@convention(thin) () -> @out SimpleProtocol
+// CHECK-NEXT:  %3 = tuple ()
+// CHECK-NEXT:  return %3 : $()
+// CHECK-NEXT: }
+func testAddressOnlyGetOnlyGlobalProperty() -> SimpleProtocol {
+  return addressOnlyGetOnlyGlobalProperty
+}
+
+
+// rdar://15962740
+struct LetDeclInStruct {
+    let immutable: Int
+    init() {
+        immutable = 1
+    }
+}
+
+// rdar://19854166 - Swift 1.2 uninitialized constant causes crash
+// The destroy_addr for a let stack temporary should be generated against 
+// mark_uninitialized instruction, so DI will see it.
+func test_unassigned_let_constant() {
+  let string : String
+}
+// CHECK: [[S:%[0-9]+]] = alloc_stack $String, let, name "string"
+// CHECK-NEXT:  [[MUI:%[0-9]+]] = mark_uninitialized [var] [[S]] : $*String
+// CHECK-NEXT:  destroy_addr [[MUI]] : $*String
+// CHECK-NEXT:  dealloc_stack [[S]] : $*String
+
diff --git a/test/SILGen/plus_zero_lifetime.swift b/test/SILGen/plus_zero_lifetime.swift
new file mode 100644
index 0000000..f5917ab
--- /dev/null
+++ b/test/SILGen/plus_zero_lifetime.swift
@@ -0,0 +1,812 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -Xllvm -sil-full-demangle -parse-as-library -emit-silgen -primary-file %s | %FileCheck %s
+
+struct Buh<T> {
+  var x: Int {
+    get {}
+    set {}
+  }
+}
+
+class Ref {
+  init() { }
+}
+struct Val {
+}
+
+// CHECK-LABEL: sil hidden @$S8lifetime13local_valtypeyyF
+func local_valtype() {
+    var b: Val
+    // CHECK: [[B:%[0-9]+]] = alloc_box ${ var Val }
+    // CHECK: [[MARKED_B:%.*]] = mark_uninitialized [var] [[B]]
+    // CHECK: destroy_value [[MARKED_B]]
+    // CHECK: return
+}
+
+// CHECK-LABEL: sil hidden @$S8lifetime20local_valtype_branch{{[_0-9a-zA-Z]*}}F
+func local_valtype_branch(_ a: Bool) {
+    var a = a
+    // CHECK: [[A:%[0-9]+]] = alloc_box ${ var Bool }
+
+    if a { return }
+    // CHECK: cond_br
+    // CHECK: {{bb.*:}}
+    // CHECK: br [[EPILOG:bb[0-9]+]]
+
+    var x:Int
+    // CHECK: [[X:%[0-9]+]] = alloc_box ${ var Int }
+    // CHECK: [[MARKED_X:%.*]] = mark_uninitialized [var] [[X]]
+
+    if a { return }
+    // CHECK: cond_br
+    // CHECK: {{bb.*:}}
+    // CHECK: destroy_value [[MARKED_X]]
+    // CHECK: br [[EPILOG]]
+
+    while a {
+    // CHECK: cond_br
+        if a { break }
+        // CHECK: cond_br
+        // CHECK: {{bb.*:}}
+        // CHECK-NOT: destroy_value [[X]]
+        // CHECK: br
+
+        if a { return }
+        // CHECK: cond_br
+        // CHECK: {{bb.*:}}
+        // CHECK: destroy_value [[MARKED_X]]
+        // CHECK: br [[EPILOG]]
+
+        var y:Int
+        // CHECK: [[Y:%[0-9]+]] = alloc_box ${ var Int }
+        // CHECK: [[MARKED_Y:%.*]] = mark_uninitialized [var] [[Y]]
+
+        if a { break }
+        // CHECK: cond_br
+        // CHECK: {{bb.*:}}
+        // CHECK: destroy_value [[MARKED_Y]]
+        // CHECK-NOT: destroy_value [[MARKED_X]]
+        // CHECK-NOT: destroy_value [[A]]
+        // CHECK: br
+
+        if a { return }
+        // CHECK: cond_br
+        // CHECK: {{bb.*:}}
+        // CHECK: destroy_value [[MARKED_Y]]
+        // CHECK: destroy_value [[MARKED_X]]
+        // CHECK: br [[EPILOG]]
+
+        if true {
+            var z:Int
+            // CHECK: [[Z:%[0-9]+]] = alloc_box ${ var Int }
+            // CHECK: [[MARKED_Z:%.*]] = mark_uninitialized [var] [[Z]]
+
+            if a { break }
+            // CHECK: cond_br
+            // CHECK: {{bb.*:}}
+            // CHECK: destroy_value [[MARKED_Z]]
+            // CHECK: destroy_value [[MARKED_Y]]
+            // CHECK-NOT: destroy_value [[MARKED_X]]
+            // CHECK-NOT: destroy_value [[A]]
+            // CHECK: br
+
+            if a { return }
+            // CHECK: cond_br
+            // CHECK: {{bb.*:}}
+            // CHECK: destroy_value [[MARKED_Z]]
+            // CHECK: destroy_value [[MARKED_Y]]
+            // CHECK: destroy_value [[MARKED_X]]
+            // CHECK: br [[EPILOG]]
+
+            // CHECK: destroy_value [[MARKED_Z]]
+        }
+        if a { break }
+        // CHECK: cond_br
+        // CHECK: {{bb.*:}}
+        // CHECK: destroy_value [[MARKED_Y]]
+        // CHECK-NOT: destroy_value [[MARKED_X]]
+        // CHECK-NOT: destroy_value [[A]]
+        // CHECK: br
+
+        // CHECK: {{bb.*:}}
+        // CHECK: destroy_value [[MARKED_Y]]
+        // CHECK: br
+    }
+    // CHECK: destroy_value [[MARKED_X]]
+    // CHECK: [[EPILOG]]:
+    // CHECK: return
+}
+
+func reftype_func() -> Ref {}
+func reftype_func_with_arg(_ x: Ref) -> Ref {}
+
+// CHECK-LABEL: sil hidden @$S8lifetime14reftype_returnAA3RefCyF
+func reftype_return() -> Ref {
+    return reftype_func()
+    // CHECK: [[RF:%[0-9]+]] = function_ref @$S8lifetime12reftype_funcAA3RefCyF : $@convention(thin) () -> @owned Ref
+    // CHECK-NOT: destroy_value
+    // CHECK: [[RET:%[0-9]+]] = apply [[RF]]()
+    // CHECK-NOT: destroy_value
+    // CHECK: return [[RET]]
+}
+
+// CHECK-LABEL: sil hidden @$S8lifetime11reftype_argyyAA3RefCF : $@convention(thin) (@guaranteed Ref) -> () {
+// CHECK: bb0([[A:%[0-9]+]] : $Ref):
+// CHECK:   [[AADDR:%[0-9]+]] = alloc_box ${ var Ref }
+// CHECK:   [[PA:%[0-9]+]] = project_box [[AADDR]]
+// CHECK:   [[A_COPY:%.*]] = copy_value [[A]]
+// CHECK:   store [[A_COPY]] to [init] [[PA]]
+// CHECK:   destroy_value [[AADDR]]
+// CHECK-NOT:   destroy_value [[A]]
+// CHECK:   return
+// CHECK: } // end sil function '$S8lifetime11reftype_argyyAA3RefCF'
+func reftype_arg(_ a: Ref) {
+    var a = a
+}
+
+// CHECK-LABEL: sil hidden @$S8lifetime26reftype_call_ignore_returnyyF
+func reftype_call_ignore_return() {
+    reftype_func()
+    // CHECK: = function_ref @$S8lifetime12reftype_funcAA3RefCyF : $@convention(thin) () -> @owned Ref
+    // CHECK-NEXT: [[R:%[0-9]+]] = apply
+    // CHECK: destroy_value [[R]]
+    // CHECK: return
+}
+
+// CHECK-LABEL: sil hidden @$S8lifetime27reftype_call_store_to_localyyF
+func reftype_call_store_to_local() {
+    var a = reftype_func()
+    // CHECK: [[A:%[0-9]+]] = alloc_box ${ var Ref }
+    // CHECK-NEXT: [[PB:%.*]] = project_box [[A]]
+    // CHECK: = function_ref @$S8lifetime12reftype_funcAA3RefCyF : $@convention(thin) () -> @owned Ref
+    // CHECK-NEXT: [[R:%[0-9]+]] = apply
+    // CHECK-NOT: copy_value [[R]]
+    // CHECK: store [[R]] to [init] [[PB]]
+    // CHECK-NOT: destroy_value [[R]]
+    // CHECK: destroy_value [[A]]
+    // CHECK-NOT: destroy_value [[R]]
+    // CHECK: return
+}
+
+// CHECK-LABEL: sil hidden @$S8lifetime16reftype_call_argyyF
+func reftype_call_arg() {
+    reftype_func_with_arg(reftype_func())
+    // CHECK: [[RF:%[0-9]+]] = function_ref @$S8lifetime12reftype_func{{[_0-9a-zA-Z]*}}F
+    // CHECK: [[R1:%[0-9]+]] = apply [[RF]]
+    // CHECK: [[RFWA:%[0-9]+]] = function_ref @$S8lifetime21reftype_func_with_arg{{[_0-9a-zA-Z]*}}F
+    // CHECK: [[R2:%[0-9]+]] = apply [[RFWA]]([[R1]])
+    // CHECK: destroy_value [[R2]]
+    // CHECK: return
+}
+
+// CHECK-LABEL: sil hidden @$S8lifetime21reftype_call_with_arg{{[_0-9a-zA-Z]*}}F
+// CHECK: bb0([[A1:%[0-9]+]] : $Ref):
+// CHECK:   [[AADDR:%[0-9]+]] = alloc_box ${ var Ref }
+// CHECK:   [[PB:%.*]] = project_box [[AADDR]]
+// CHECK:   [[A1_COPY:%.*]] = copy_value [[A1]]
+// CHECK:   store [[A1_COPY]] to [init] [[PB]]
+// CHECK:   [[READ:%.*]] = begin_access [read] [unknown] [[PB]]
+// CHECK:   [[A2:%[0-9]+]] = load [copy] [[READ]]
+// CHECK:   [[RFWA:%[0-9]+]] = function_ref @$S8lifetime21reftype_func_with_arg{{[_0-9a-zA-Z]*}}F
+// CHECK:   [[RESULT:%.*]] = apply [[RFWA]]([[A2]])
+// CHECK:   destroy_value [[RESULT]]
+// CHECK:   destroy_value [[AADDR]]
+// CHECK-NOT:   destroy_value [[A1]]
+// CHECK:   return
+func reftype_call_with_arg(_ a: Ref) {
+    var a = a
+
+    reftype_func_with_arg(a)
+}
+
+// CHECK-LABEL: sil hidden @$S8lifetime16reftype_reassign{{[_0-9a-zA-Z]*}}F
+func reftype_reassign(_ a: inout Ref, b: Ref) {
+    var b = b
+    // CHECK: bb0([[AADDR:%[0-9]+]] : $*Ref, [[B1:%[0-9]+]] : $Ref):
+    // CHECK: [[BADDR:%[0-9]+]] = alloc_box ${ var Ref }
+    // CHECK: [[PBB:%.*]] = project_box [[BADDR]]
+    a = b
+    // CHECK: destroy_value
+
+    // CHECK: return
+}
+
+func tuple_with_ref_elements() -> (Val, (Ref, Val), Ref) {}
+
+// CHECK-LABEL: sil hidden @$S8lifetime28tuple_with_ref_ignore_returnyyF
+func tuple_with_ref_ignore_return() {
+  tuple_with_ref_elements()
+  // CHECK: [[FUNC:%[0-9]+]] = function_ref @$S8lifetime23tuple_with_ref_elementsAA3ValV_AA3RefC_ADtAFtyF
+  // CHECK: [[TUPLE:%[0-9]+]] = apply [[FUNC]]
+  // CHECK: [[BORROWED_TUPLE:%.*]] = begin_borrow [[TUPLE]]
+  // CHECK: [[T0:%[0-9]+]] = tuple_extract [[BORROWED_TUPLE]] : {{.*}}, 0
+  // CHECK: [[T1_0:%[0-9]+]] = tuple_extract [[BORROWED_TUPLE]] : {{.*}}, 1
+  // CHECK: [[T1_0_COPY:%.*]] = copy_value [[T1_0]]
+  // CHECK: [[T1_1:%[0-9]+]] = tuple_extract [[BORROWED_TUPLE]] : {{.*}}, 2
+  // CHECK: [[T2:%[0-9]+]] = tuple_extract [[BORROWED_TUPLE]] : {{.*}}, 3
+  // CHECK: [[T2_COPY:%.*]] = copy_value [[T2]]
+  // CHECK: end_borrow [[BORROWED_TUPLE]] from [[TUPLE]]
+  // CHECK: destroy_value [[TUPLE]]
+  // CHECK: destroy_value [[T2_COPY]]
+  // CHECK: destroy_value [[T1_0_COPY]]
+  // CHECK: return
+}
+
+struct Aleph {
+  var a:Ref
+  var b:Val
+
+  // -- loadable value constructor:
+  // CHECK-LABEL: sil hidden @$S8lifetime5AlephV{{[_0-9a-zA-Z]*}}fC : $@convention(method) (@owned Ref, Val, @thin Aleph.Type) -> @owned Aleph
+  // CHECK: bb0([[A:%.*]] : $Ref, [[B:%.*]] : $Val, {{%.*}} : $@thin Aleph.Type):
+  // CHECK-NEXT:   [[RET:%.*]] = struct $Aleph ([[A]] : {{.*}}, [[B]] : {{.*}})
+  // CHECK-NEXT:   return [[RET]]
+}
+
+struct Beth {
+  var a:Val
+  var b:Aleph
+  var c:Ref
+
+  func gimel() {}
+}
+
+protocol Unloadable {}
+
+struct Daleth {
+  var a:Aleph
+  var b:Beth
+  var c:Unloadable
+
+  // -- address-only value constructor:
+  // CHECK-LABEL: sil hidden @$S8lifetime6DalethV{{[_0-9a-zA-Z]*}}fC : $@convention(method) (@owned Aleph, @owned Beth, @in Unloadable, @thin Daleth.Type) -> @out Daleth {
+  // CHECK: bb0([[THIS:%.*]] : $*Daleth, [[A:%.*]] : $Aleph, [[B:%.*]] : $Beth, [[C:%.*]] : $*Unloadable, {{%.*}} : $@thin Daleth.Type):
+  // CHECK-NEXT:   [[A_ADDR:%.*]] = struct_element_addr [[THIS]] : $*Daleth, #Daleth.a
+  // CHECK-NEXT:   store [[A]] to [init] [[A_ADDR]]
+  // CHECK-NEXT:   [[B_ADDR:%.*]] = struct_element_addr [[THIS]] : $*Daleth, #Daleth.b
+  // CHECK-NEXT:   store [[B]] to [init] [[B_ADDR]]
+  // CHECK-NEXT:   [[C_ADDR:%.*]] = struct_element_addr [[THIS]] : $*Daleth, #Daleth.c
+  // CHECK-NEXT:   copy_addr [take] [[C]] to [initialization] [[C_ADDR]]
+  // CHECK-NEXT:   tuple ()
+  // CHECK-NEXT:   return
+}
+
+class He {
+  
+  // -- default allocator:
+  // CHECK-LABEL: sil hidden @$S8lifetime2HeC{{[_0-9a-zA-Z]*}}fC : $@convention(method) (@thick He.Type) -> @owned He {
+  // CHECK: bb0({{%.*}} : $@thick He.Type):
+  // CHECK-NEXT:   [[THIS:%.*]] = alloc_ref $He
+  // CHECK-NEXT:   // function_ref lifetime.He.init
+  // CHECK-NEXT:   [[INIT:%.*]] = function_ref @$S8lifetime2HeC{{[_0-9a-zA-Z]*}}fc : $@convention(method) (@owned He) -> @owned He
+  // CHECK-NEXT:   [[THIS1:%.*]] = apply [[INIT]]([[THIS]])
+  // CHECK-NEXT:   return [[THIS1]]
+  // CHECK-NEXT: }
+
+  // -- default initializer:
+  // CHECK-LABEL: sil hidden @$S8lifetime2HeC{{[_0-9a-zA-Z]*}}fc : $@convention(method) (@owned He) -> @owned He {
+  // CHECK: bb0([[SELF:%.*]] : $He):
+  // CHECK-NEXT: debug_value
+  // CHECK-NEXT: [[UNINITIALIZED_SELF:%.*]] = mark_uninitialized [rootself] [[SELF]]
+  // CHECK-NEXT: [[UNINITIALIZED_SELF_COPY:%.*]] = copy_value [[UNINITIALIZED_SELF]]
+  // CHECK-NEXT: destroy_value [[UNINITIALIZED_SELF]]
+  // CHECK-NEXT: return [[UNINITIALIZED_SELF_COPY]]
+  // CHECK: } // end sil function '$S8lifetime2HeC{{[_0-9a-zA-Z]*}}fc'
+
+  init() { }
+}
+
+struct Waw {
+  var a:(Ref, Val)
+  var b:Val
+
+  // -- loadable value initializer with tuple destructuring:
+  // CHECK-LABEL: sil hidden @$S8lifetime3WawV{{[_0-9a-zA-Z]*}}fC : $@convention(method) (@owned Ref, Val, Val, @thin Waw.Type) -> @owned Waw 
+  // CHECK: bb0([[A0:%.*]] : $Ref, [[A1:%.*]] : $Val, [[B:%.*]] : $Val, {{%.*}} : $@thin Waw.Type):
+  // CHECK-NEXT:   [[A:%.*]] = tuple ([[A0]] : {{.*}}, [[A1]] : {{.*}})
+  // CHECK-NEXT:   [[RET:%.*]] = struct $Waw ([[A]] : {{.*}}, [[B]] : {{.*}})
+  // CHECK-NEXT:   return [[RET]]
+}
+
+struct Zayin {
+  var a:(Unloadable, Val)
+  var b:Unloadable
+
+  // -- address-only value initializer with tuple destructuring:
+  // CHECK-LABEL: sil hidden @$S8lifetime5ZayinV{{[_0-9a-zA-Z]*}}fC : $@convention(method) (@in Unloadable, Val, @in Unloadable, @thin Zayin.Type) -> @out Zayin
+  // CHECK: bb0([[THIS:%.*]] : $*Zayin, [[A0:%.*]] : $*Unloadable, [[A1:%.*]] : $Val, [[B:%.*]] : $*Unloadable, {{%.*}} : $@thin Zayin.Type):
+  // CHECK-NEXT:   [[THIS_A_ADDR:%.*]] = struct_element_addr [[THIS]] : $*Zayin, #Zayin.a
+  // CHECK-NEXT:   [[THIS_A0_ADDR:%.*]] = tuple_element_addr [[THIS_A_ADDR]] : {{.*}}, 0
+  // CHECK-NEXT:   [[THIS_A1_ADDR:%.*]] = tuple_element_addr [[THIS_A_ADDR]] : {{.*}}, 1
+  // CHECK-NEXT:   copy_addr [take] [[A0]] to [initialization] [[THIS_A0_ADDR]]
+  // CHECK-NEXT:   store [[A1]] to [trivial] [[THIS_A1_ADDR]]
+  // CHECK-NEXT:   [[THIS_B_ADDR:%.*]] = struct_element_addr [[THIS]] : $*Zayin, #Zayin.b
+  // CHECK-NEXT:   copy_addr [take] [[B]] to [initialization] [[THIS_B_ADDR]]
+  // CHECK-NEXT:   tuple ()
+  // CHECK-NEXT:   return
+}
+
+func fragile_struct_with_ref_elements() -> Beth {}
+
+// CHECK-LABEL: sil hidden @$S8lifetime29struct_with_ref_ignore_returnyyF
+func struct_with_ref_ignore_return() {
+  fragile_struct_with_ref_elements()
+  // CHECK: [[FUNC:%[0-9]+]] = function_ref @$S8lifetime32fragile_struct_with_ref_elementsAA4BethVyF
+  // CHECK: [[STRUCT:%[0-9]+]] = apply [[FUNC]]
+  // CHECK: destroy_value [[STRUCT]] : $Beth
+  // CHECK: return
+}
+
+// CHECK-LABEL: sil hidden @$S8lifetime28struct_with_ref_materializedyyF
+func struct_with_ref_materialized() {
+  fragile_struct_with_ref_elements().gimel()
+  // CHECK: [[FUNC:%[0-9]+]] = function_ref @$S8lifetime32fragile_struct_with_ref_elementsAA4BethVyF
+  // CHECK: [[STRUCT:%[0-9]+]] = apply [[FUNC]]
+  // CHECK: [[METHOD:%[0-9]+]] = function_ref @$S8lifetime4BethV5gimel{{[_0-9a-zA-Z]*}}F
+  // CHECK: apply [[METHOD]]([[STRUCT]])
+}
+
+class RefWithProp {
+  var int_prop: Int { get {} set {} }
+  var aleph_prop: Aleph { get {} set {} }
+}
+
+// CHECK-LABEL: sil hidden @$S8lifetime015logical_lvalue_A0yyAA11RefWithPropC_SiAA3ValVtF : $@convention(thin) (@guaranteed RefWithProp, Int, Val) -> () {
+func logical_lvalue_lifetime(_ r: RefWithProp, _ i: Int, _ v: Val) {
+  var r = r
+  var i = i
+  var v = v
+  // CHECK: [[RADDR:%[0-9]+]] = alloc_box ${ var RefWithProp }
+  // CHECK: [[PR:%[0-9]+]] = project_box [[RADDR]]
+  // CHECK: [[IADDR:%[0-9]+]] = alloc_box ${ var Int }
+  // CHECK: [[PI:%[0-9]+]] = project_box [[IADDR]]
+  // CHECK: store %1 to [trivial] [[PI]]
+  // CHECK: [[VADDR:%[0-9]+]] = alloc_box ${ var Val }
+  // CHECK: [[PV:%[0-9]+]] = project_box [[VADDR]]
+
+  // -- Reference types need to be copy_valued as property method args.
+  r.int_prop = i
+  // CHECK:   [[READ:%.*]] = begin_access [read] [unknown] [[PR]]
+  // CHECK: [[R1:%[0-9]+]] = load [copy] [[READ]]
+  // CHECK: [[SETTER_METHOD:%[0-9]+]] = class_method {{.*}} : $RefWithProp, #RefWithProp.int_prop!setter.1 : (RefWithProp) -> (Int) -> (), $@convention(method) (Int, @guaranteed RefWithProp) -> ()
+  // CHECK: apply [[SETTER_METHOD]]({{.*}}, [[R1]])
+  // CHECK: destroy_value [[R1]]
+
+  r.aleph_prop.b = v
+  // CHECK: [[READ:%.*]] = begin_access [read] [unknown] [[PR]]
+  // CHECK: [[R2:%[0-9]+]] = load [copy] [[READ]]
+  // CHECK: [[STORAGE:%.*]] = alloc_stack $Builtin.UnsafeValueBuffer
+  // CHECK: [[ALEPH_PROP_TEMP:%[0-9]+]] = alloc_stack $Aleph
+  // CHECK: [[BORROWED_R2:%.*]] = begin_borrow [[R2]]
+  // CHECK: [[T0:%.*]] = address_to_pointer [[ALEPH_PROP_TEMP]]
+  // CHECK: [[MATERIALIZE_METHOD:%[0-9]+]] = class_method [[BORROWED_R2]] : $RefWithProp, #RefWithProp.aleph_prop!materializeForSet.1 :
+  // CHECK: [[MATERIALIZE:%.*]] = apply [[MATERIALIZE_METHOD]]([[T0]], [[STORAGE]], [[BORROWED_R2]])
+  // CHECK: [[PTR:%.*]] = tuple_extract [[MATERIALIZE]] : {{.*}}, 0
+  // CHECK: [[OPTCALLBACK:%.*]] = tuple_extract [[MATERIALIZE]] : {{.*}}, 1
+  // CHECK: [[ADDR:%.*]] = pointer_to_address [[PTR]]
+  // CHECK: [[MARKED_ADDR:%.*]] = mark_dependence [[ADDR]] : $*Aleph on [[R2]]
+  // CHECK: {{.*}}([[CALLBACK_ADDR:%.*]] : 
+  // CHECK: [[CALLBACK:%.*]] = pointer_to_thin_function [[CALLBACK_ADDR]] : $Builtin.RawPointer to $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout RefWithProp, @thick RefWithProp.Type) -> ()
+  // CHECK: [[TEMP:%.*]] = alloc_stack $RefWithProp
+  // CHECK: store [[R2]] to [init] [[TEMP]]
+  // CHECK: apply [[CALLBACK]]({{.*}}, [[STORAGE]], [[TEMP]], {{%.*}})
+}
+
+func bar() -> Int {}
+
+class Foo<T> {
+  var x : Int
+  var y = (Int(), Ref())
+  var z : T
+  var w = Ref()
+
+  class func makeT() -> T {}
+
+  // Class initializer
+  init() {
+  // -- allocating entry point
+  // CHECK-LABEL: sil hidden @$S8lifetime3FooC{{[_0-9a-zA-Z]*}}fC :
+    // CHECK: bb0([[METATYPE:%[0-9]+]] : $@thick Foo<T>.Type):
+    // CHECK: [[THIS:%[0-9]+]] = alloc_ref $Foo<T>
+    // CHECK: [[INIT_METHOD:%[0-9]+]] = function_ref @$S8lifetime3FooC{{[_0-9a-zA-Z]*}}fc
+    // CHECK: [[INIT_THIS:%[0-9]+]] = apply [[INIT_METHOD]]<{{.*}}>([[THIS]])
+    // CHECK: return [[INIT_THIS]]
+
+  // -- initializing entry point
+  // CHECK-LABEL: sil hidden @$S8lifetime3FooC{{[_0-9a-zA-Z]*}}fc :
+    // CHECK: bb0([[THISIN:%[0-9]+]] : $Foo<T>):
+    // CHECK: [[THIS:%[0-9]+]] = mark_uninitialized
+
+    // -- initialization for y
+    // CHECK: [[Y_INIT:%[0-9]+]] = function_ref @$S8lifetime3FooC1ySi_AA3RefCtvpfi : $@convention(thin) <τ_0_0> () -> (Int, @owned Ref)
+    // CHECK: [[Y_VALUE:%[0-9]+]] = apply [[Y_INIT]]<T>()
+    // CHECK: [[BORROWED_Y_VALUE:%.*]] = begin_borrow [[Y_VALUE]]
+    // CHECK: [[Y_EXTRACTED_0:%.*]] = tuple_extract [[BORROWED_Y_VALUE]] : $(Int, Ref), 0
+    // CHECK: [[Y_EXTRACTED_1:%.*]] = tuple_extract [[BORROWED_Y_VALUE]] : $(Int, Ref), 1
+    // CHECK: [[COPIED_Y_EXTRACTED_1:%.*]] = copy_value [[Y_EXTRACTED_1]]
+    // CHECK: end_borrow [[BORROWED_Y_VALUE]] from [[Y_VALUE]]
+    // CHECK: destroy_value [[Y_VALUE]]
+    // CHECK: [[BORROWED_THIS:%.*]] = begin_borrow [[THIS]]
+    // CHECK: [[THIS_Y:%.*]] = ref_element_addr [[BORROWED_THIS]] : {{.*}}, #Foo.y
+    // CHECK: [[WRITE:%.*]] = begin_access [modify] [dynamic] [[THIS_Y]] : $*(Int, Ref)
+    // CHECK: [[THIS_Y_0:%.*]] = tuple_element_addr [[WRITE]] : $*(Int, Ref), 0
+    // CHECK: assign [[Y_EXTRACTED_0]] to [[THIS_Y_0]]
+    // CHECK: [[THIS_Y_1:%.*]] = tuple_element_addr [[WRITE]] : $*(Int, Ref), 1
+    // CHECK: assign [[COPIED_Y_EXTRACTED_1]] to [[THIS_Y_1]]
+    // CHECK: end_access [[WRITE]] : $*(Int, Ref)
+    // CHECK: end_borrow [[BORROWED_THIS]] from [[THIS]]
+
+    // -- Initialization for w
+    // CHECK: [[Z_FUNC:%.*]] = function_ref @$S{{.*}}8lifetime3FooC1wAA3RefCvpfi : $@convention(thin) <τ_0_0> () -> @owned Ref
+    // CHECK: [[Z_RESULT:%.*]] = apply [[Z_FUNC]]<T>()
+    // CHECK: [[BORROWED_THIS:%.*]] = begin_borrow [[THIS]]
+    // CHECK: [[THIS_Z:%.*]] = ref_element_addr [[BORROWED_THIS]]
+    // CHECK: [[WRITE:%.*]] = begin_access [modify] [dynamic] [[THIS_Z]] : $*Ref
+    // CHECK: assign [[Z_RESULT]] to [[WRITE]]
+    // CHECK: end_borrow [[BORROWED_THIS]] from [[THIS]]
+
+    // -- Initialization for x
+    // CHECK: [[BORROWED_THIS:%.*]] = begin_borrow [[THIS]]
+    // CHECK: [[THIS_X:%[0-9]+]] = ref_element_addr [[BORROWED_THIS]] : {{.*}}, #Foo.x
+    // CHECK: [[WRITE:%.*]] = begin_access [modify] [dynamic] [[THIS_X]] : $*Int
+    // CHECK: assign {{.*}} to [[WRITE]]
+    // CHECK: end_borrow [[BORROWED_THIS]] from [[THIS]]
+
+    x = bar()
+
+    z = Foo<T>.makeT()
+    // CHECK: [[FOOMETA:%[0-9]+]] = metatype $@thick Foo<T>.Type
+    // CHECK: [[MAKET:%[0-9]+]] = class_method [[FOOMETA]] : {{.*}}, #Foo.makeT!1
+    // CHECK: ref_element_addr
+
+    // -- cleanup this lvalue and return this
+    // CHECK: [[THIS_RESULT:%.*]] = copy_value [[THIS]]
+    // -- TODO: This copy should be unnecessary.
+    // CHECK: destroy_value [[THIS]]
+    // CHECK: return [[THIS_RESULT]]
+
+  }
+
+  init(chi:Int) {
+    var chi = chi
+    z = Foo<T>.makeT()
+
+  // -- allocating entry point
+  // CHECK-LABEL: sil hidden @$S8lifetime3FooC{{[_0-9a-zA-Z]*}}fC :
+    // CHECK: bb0([[CHI:%[0-9]+]] : $Int, [[METATYPE:%[0-9]+]] : $@thick Foo<T>.Type):
+    // CHECK: [[THIS:%[0-9]+]] = alloc_ref $Foo<T>
+    // CHECK: [[INIT_METHOD:%[0-9]+]] = function_ref @$S8lifetime3FooC{{[_0-9a-zA-Z]*}}fc
+    // CHECK: [[INIT_THIS:%[0-9]+]] = apply [[INIT_METHOD]]<{{.*}}>([[CHI]], [[THIS]])
+    // CHECK: return [[INIT_THIS]]
+
+  // -- initializing entry point
+  // CHECK-LABEL: sil hidden @$S8lifetime3FooC3chiACyxGSi_tcfc : $@convention(method) <T> (Int, @owned Foo<T>) -> @owned Foo<T> {
+    // CHECK: bb0([[CHI:%[0-9]+]] : $Int, [[THISIN:%[0-9]+]] : $Foo<T>):
+    // CHECK:   [[THIS:%[0-9]+]] = mark_uninitialized [rootself] [[THISIN]]
+
+    // -- First we initialize #Foo.y.
+    // CHECK:   [[BORROWED_THIS:%.*]] = begin_borrow [[THIS]]
+    // CHECK:   [[THIS_Y:%.*]] = ref_element_addr [[BORROWED_THIS]] : $Foo<T>, #Foo.y
+    // CHECK:   [[WRITE:%.*]] = begin_access [modify] [dynamic] [[THIS_Y]] : $*(Int, Ref)
+    // CHECK:   [[THIS_Y_1:%.*]] = tuple_element_addr [[WRITE]] : $*(Int, Ref), 0
+    // CHECK:   assign {{.*}} to [[THIS_Y_1]] : $*Int
+    // CHECK:   [[THIS_Y_2:%.*]] = tuple_element_addr [[WRITE]] : $*(Int, Ref), 1
+    // CHECK:   assign {{.*}} to [[THIS_Y_2]] : $*Ref
+    // CHECK:   end_borrow [[BORROWED_THIS]] from [[THIS]]
+
+    // -- Then we create a box that we will use to perform a copy_addr into #Foo.x a bit later.
+    // CHECK:   [[CHIADDR:%[0-9]+]] = alloc_box ${ var Int }, var, name "chi"
+    // CHECK:   [[PCHI:%[0-9]+]] = project_box [[CHIADDR]]
+    // CHECK:   store [[CHI]] to [trivial] [[PCHI]]
+
+    // -- Then we initialize #Foo.z
+    // CHECK:   [[BORROWED_THIS:%.*]] = begin_borrow [[THIS]]
+    // CHECK:   [[THIS_Z:%.*]] = ref_element_addr [[BORROWED_THIS]] : {{.*}}, #Foo.z
+    // CHECK:   [[WRITE:%.*]] = begin_access [modify] [dynamic] [[THIS_Z]] : $*T
+    // CHECK:   copy_addr [take] {{.*}} to [[WRITE]]
+    // CHECK:   end_borrow [[BORROWED_THIS]] from [[THIS]]
+
+    // -- Then initialize #Foo.x using the earlier stored value of CHI to THIS_Z.
+    x = chi
+    // CHECK:   [[BORROWED_THIS:%.*]] = begin_borrow [[THIS]]
+    // CHECK:   [[READ:%.*]] = begin_access [read] [unknown] [[PCHI]]
+    // CHECK:   [[X:%.*]] = load [trivial] [[READ]]
+    // CHECK:   [[THIS_X:%[0-9]+]] = ref_element_addr [[BORROWED_THIS]] : {{.*}}, #Foo.x
+    // CHECK:   [[WRITE:%.*]] = begin_access [modify] [dynamic] [[THIS_X]] : $*Int
+    // CHECK:   assign [[X]] to [[WRITE]]
+    // CHECK:   end_borrow [[BORROWED_THIS]] from [[THIS]]
+
+    // -- cleanup chi
+    // CHECK: destroy_value [[CHIADDR]]
+
+    // -- Then begin the epilogue sequence
+    // CHECK: [[THIS_RETURN:%.*]] = copy_value [[THIS]]
+    // CHECK: destroy_value [[THIS]]
+    // CHECK: return [[THIS_RETURN]]
+  // CHECK: } // end sil function '$S8lifetime3FooC3chiACyxGSi_tcfc'
+  }
+
+  // -- allocating entry point
+  // CHECK-LABEL: sil hidden @$S8lifetime3FooC{{[_0-9a-zA-Z]*}}fC :
+    // CHECK: [[INIT_METHOD:%[0-9]+]] = function_ref @$S8lifetime3FooC{{[_0-9a-zA-Z]*}}fc
+
+  // -- initializing entry point
+  // CHECK-LABEL: sil hidden @$S8lifetime3FooC{{[_0-9a-zA-Z]*}}fc :
+
+  init<U:Intifiable>(chi:U) {
+    z = Foo<T>.makeT()
+
+    x = chi.intify()
+  }
+  
+  // CHECK-LABEL: sil hidden @$S8lifetime3FooCfd : $@convention(method) <T> (@guaranteed Foo<T>) -> @owned Builtin.NativeObject
+
+  deinit {
+    // CHECK: bb0([[THIS:%[0-9]+]] : $Foo<T>):
+    bar()
+    // CHECK: function_ref @$S8lifetime3barSiyF
+    // CHECK: apply
+
+    // -- don't need to destroy_value x because it's trivial
+    // CHECK-NOT: ref_element_addr [[THIS]] : {{.*}}, #Foo.x
+    // -- destroy_value y
+    // CHECK: [[YADDR:%[0-9]+]] = ref_element_addr [[THIS]] : {{.*}}, #Foo.y
+    // CHECK: destroy_addr [[YADDR]]
+    // -- destroy_value z
+    // CHECK: [[ZADDR:%[0-9]+]] = ref_element_addr [[THIS]] : {{.*}}, #Foo.z
+    // CHECK: destroy_addr [[ZADDR]]
+    // -- destroy_value w
+    // CHECK: [[WADDR:%[0-9]+]] = ref_element_addr [[THIS]] : {{.*}}, #Foo.w
+    // CHECK: destroy_addr [[WADDR]]
+    // -- return back this
+    // CHECK: [[PTR:%.*]] = unchecked_ref_cast [[THIS]] : $Foo<T> to $Builtin.NativeObject
+    // CHECK: [[PTR_OWNED:%.*]] = unchecked_ownership_conversion [[PTR]] : $Builtin.NativeObject, @guaranteed to @owned
+    // CHECK: return [[PTR_OWNED]]
+    // CHECK: } // end sil function '$S8lifetime3FooCfd'
+  }
+
+  // Deallocating destructor for Foo.
+  // CHECK-LABEL: sil hidden @$S8lifetime3FooCfD : $@convention(method) <T> (@owned Foo<T>) -> ()
+  // CHECK: bb0([[SELF:%[0-9]+]] : $Foo<T>):
+  // CHECK:   [[DESTROYING_REF:%[0-9]+]] = function_ref @$S8lifetime3FooCfd : $@convention(method) <τ_0_0> (@guaranteed Foo<τ_0_0>) -> @owned Builtin.NativeObject
+  // CHECK-NEXT:   [[BORROWED_SELF:%.*]] = begin_borrow [[SELF]]
+  // CHECK-NEXT:   [[RESULT_SELF:%[0-9]+]] = apply [[DESTROYING_REF]]<T>([[BORROWED_SELF]]) : $@convention(method) <τ_0_0> (@guaranteed Foo<τ_0_0>) -> @owned Builtin.NativeObject
+  // CHECK-NEXT:   end_borrow [[BORROWED_SELF]] from [[SELF]]
+  // CHECK-NEXT:   end_lifetime [[SELF]]
+  // CHECK-NEXT:   [[SELF:%[0-9]+]] = unchecked_ref_cast [[RESULT_SELF]] : $Builtin.NativeObject to $Foo<T>
+  // CHECK-NEXT:   dealloc_ref [[SELF]] : $Foo<T>
+  // CHECK-NEXT:   [[RESULT:%[0-9]+]] = tuple ()
+  // CHECK-NEXT:   return [[RESULT]] : $()
+  // CHECK-NEXT: } // end sil function '$S8lifetime3FooCfD'
+
+}
+
+class FooSubclass<T> : Foo<T> {
+
+  // CHECK-LABEL: sil hidden @$S8lifetime11FooSubclassCfd : $@convention(method) <T> (@guaranteed FooSubclass<T>) -> @owned Builtin.NativeObject
+  // CHECK: bb0([[THIS:%[0-9]+]] : $FooSubclass<T>):
+  // -- base dtor
+  // CHECK: [[BASE:%[0-9]+]] = upcast [[THIS]] : ${{.*}} to $Foo<T>
+  // CHECK: [[BASE_DTOR:%[0-9]+]] = function_ref @$S8lifetime3FooCfd : $@convention(method) <τ_0_0> (@guaranteed Foo<τ_0_0>) -> @owned Builtin.NativeObject
+  // CHECK: [[PTR:%.*]] = apply [[BASE_DTOR]]<T>([[BASE]])
+  // CHECK: [[BORROWED_PTR:%.*]] = begin_borrow [[PTR]]
+  // CHECK: end_borrow [[BORROWED_PTR]] from [[PTR]]
+  // CHECK: return [[PTR]]
+  
+
+  deinit {
+    bar()
+  }
+}
+
+class ImplicitDtor {
+  var x:Int
+  var y:(Int, Ref)
+  var w:Ref
+  init() { }
+
+  // CHECK-LABEL: sil hidden @$S8lifetime12ImplicitDtorCfd
+  // CHECK: bb0([[THIS:%[0-9]+]] : $ImplicitDtor):
+  // -- don't need to destroy_value x because it's trivial
+  // CHECK-NOT: ref_element_addr [[THIS]] : {{.*}}, #ImplicitDtor.x
+  // -- destroy_value y
+  // CHECK: [[YADDR:%[0-9]+]] = ref_element_addr [[THIS]] : {{.*}}, #ImplicitDtor.y
+  // CHECK: destroy_addr [[YADDR]]
+  // -- destroy_value w
+  // CHECK: [[WADDR:%[0-9]+]] = ref_element_addr [[THIS]] : {{.*}}, #ImplicitDtor.w
+  // CHECK: destroy_addr [[WADDR]]
+  // CHECK: return
+}
+
+class ImplicitDtorDerived<T> : ImplicitDtor {
+  var z:T
+
+  init(z : T) { 
+    super.init() 
+    self.z = z
+  }
+
+  // CHECK: sil hidden @$S8lifetime19ImplicitDtorDerivedCfd : $@convention(method) <T> (@guaranteed ImplicitDtorDerived<T>) -> @owned Builtin.NativeObject {
+  // CHECK: bb0([[THIS:%[0-9]+]] : $ImplicitDtorDerived<T>):
+  // -- base dtor
+  // CHECK: [[BASE:%[0-9]+]] = upcast [[THIS]] : ${{.*}} to $ImplicitDtor
+  // CHECK: [[BASE_DTOR:%[0-9]+]] = function_ref @$S8lifetime12ImplicitDtorCfd
+  // CHECK: [[PTR:%.*]] = apply [[BASE_DTOR]]([[BASE]])
+  // -- destroy_value z
+  // CHECK: [[BORROWED_PTR:%.*]] = begin_borrow [[PTR]]
+  // CHECK: [[CAST_BORROWED_PTR:%.*]] = unchecked_ref_cast [[BORROWED_PTR]] : $Builtin.NativeObject to $ImplicitDtorDerived<T>
+  // CHECK: [[ZADDR:%[0-9]+]] = ref_element_addr [[CAST_BORROWED_PTR]] : {{.*}}, #ImplicitDtorDerived.z
+  // CHECK: destroy_addr [[ZADDR]]
+  // CHECK: end_borrow [[BORROWED_PTR]] from [[PTR]]
+  // -- epilog
+  // CHECK-NOT: unchecked_ref_cast
+  // CHECK-NOT: unchecked_ownership_conversion
+  // CHECK: return [[PTR]]
+}
+
+class ImplicitDtorDerivedFromGeneric<T> : ImplicitDtorDerived<Int> {
+  init() { super.init(z: 5) }
+
+  // CHECK-LABEL: sil hidden @$S8lifetime30ImplicitDtorDerivedFromGenericC{{[_0-9a-zA-Z]*}}fc
+  // CHECK: bb0([[THIS:%[0-9]+]] : $ImplicitDtorDerivedFromGeneric<T>):
+  // -- base dtor
+  // CHECK: [[BASE:%[0-9]+]] = upcast [[THIS]] : ${{.*}} to $ImplicitDtorDerived<Int>
+  // CHECK: [[BASE_DTOR:%[0-9]+]] = function_ref @$S8lifetime19ImplicitDtorDerivedCfd
+  // CHECK: [[PTR:%.*]] = apply [[BASE_DTOR]]<Int>([[BASE]])
+  // CHECK: return [[PTR]]
+}
+
+protocol Intifiable {
+  func intify() -> Int
+}
+
+struct Bar {
+  var x:Int
+
+  // Loadable struct initializer
+  // CHECK-LABEL: sil hidden @$S8lifetime3BarV{{[_0-9a-zA-Z]*}}fC
+  init() {
+    // CHECK: bb0([[METATYPE:%[0-9]+]] : $@thin Bar.Type):
+    // CHECK: [[SELF_BOX:%[0-9]+]] = alloc_box ${ var Bar }
+    // CHECK: [[MARKED_SELF_BOX:%[0-9]+]] = mark_uninitialized [rootself] [[SELF_BOX]]
+    // CHECK: [[PB_BOX:%.*]] = project_box [[MARKED_SELF_BOX]]
+
+    x = bar()
+    // CHECK:   [[WRITE:%.*]] = begin_access [modify] [unknown] [[PB_BOX]]
+    // CHECK: [[SELF_X:%[0-9]+]] = struct_element_addr [[WRITE]] : $*Bar, #Bar.x
+    // CHECK: assign {{.*}} to [[SELF_X]]
+
+    // -- load and return this
+    // CHECK: [[SELF_VAL:%[0-9]+]] = load [trivial] [[PB_BOX]]
+    // CHECK: destroy_value [[MARKED_SELF_BOX]]
+    // CHECK: return [[SELF_VAL]]
+  }
+
+  init<T:Intifiable>(xx:T) {
+    x = xx.intify()
+  }
+}
+
+struct Bas<T> {
+  var x:Int
+  var y:T
+
+  // Address-only struct initializer
+  // CHECK-LABEL: sil hidden @$S8lifetime3BasV{{[_0-9a-zA-Z]*}}fC
+  init(yy:T) {
+    // CHECK: bb0([[THISADDRPTR:%[0-9]+]] : $*Bas<T>, [[YYADDR:%[0-9]+]] : $*T, [[META:%[0-9]+]] : $@thin Bas<T>.Type):
+    // CHECK: [[SELF_BOX:%[0-9]+]] = alloc_box $<τ_0_0> { var Bas<τ_0_0> } <T>
+    // CHECK: [[MARKED_SELF_BOX:%[0-9]+]] = mark_uninitialized [rootself] [[SELF_BOX]]
+    // CHECK: [[PB_BOX:%.*]] = project_box [[MARKED_SELF_BOX]]
+
+    x = bar()
+    // CHECK: [[WRITE:%.*]] = begin_access [modify] [unknown] [[PB_BOX]]
+    // CHECK: [[SELF_X:%[0-9]+]] = struct_element_addr [[WRITE]] : $*Bas<T>, #Bas.x
+    // CHECK: assign {{.*}} to [[SELF_X]]
+
+    y = yy
+    // CHECK: [[WRITE:%.*]] = begin_access [modify] [unknown] [[PB_BOX]]
+    // CHECK: [[SELF_Y:%[0-9]+]] = struct_element_addr [[WRITE]] : $*Bas<T>, #Bas.y
+    // CHECK: copy_addr {{.*}} to [[SELF_Y]]
+    // CHECK: destroy_value
+
+    // -- 'self' was emplaced into indirect return slot
+    // CHECK: return
+  }
+
+  init<U:Intifiable>(xx:U, yy:T) {
+    x = xx.intify()
+    y = yy
+  }
+}
+
+class B { init(y:Int) {} }
+class D : B {
+  // CHECK-LABEL: sil hidden @$S8lifetime1DC1x1yACSi_Sitcfc
+  // CHECK: bb0([[X:%[0-9]+]] : $Int, [[Y:%[0-9]+]] : $Int, [[SELF:%[0-9]+]] : $D):
+  init(x: Int, y: Int) {
+    var x = x
+    var y = y
+    // CHECK: [[SELF_BOX:%[0-9]+]] = alloc_box ${ var D }
+    // CHECK: [[MARKED_SELF_BOX:%[0-9]+]] = mark_uninitialized [derivedself] [[SELF_BOX]]
+    // CHECK: [[PB_BOX:%[0-9]+]] = project_box [[MARKED_SELF_BOX]]
+    // CHECK: store [[SELF]] to [init] [[PB_BOX]]
+    // CHECK: [[XADDR:%[0-9]+]] = alloc_box ${ var Int }
+    // CHECK: [[PX:%[0-9]+]] = project_box [[XADDR]]
+    // CHECK: store [[X]] to [trivial] [[PX]]
+    // CHECK: [[YADDR:%[0-9]+]] = alloc_box ${ var Int }
+    // CHECK: [[PY:%[0-9]+]] = project_box [[YADDR]]
+    // CHECK: store [[Y]] to [trivial] [[PY]]
+
+    super.init(y: y)
+    // CHECK: [[THIS1:%[0-9]+]] = load [take] [[PB_BOX]]
+    // CHECK: [[THIS1_SUP:%[0-9]+]] = upcast [[THIS1]] : ${{.*}} to $B
+    // CHECK: [[READ:%.*]] = begin_access [read] [unknown] [[PY]]
+    // CHECK: [[Y:%[0-9]+]] = load [trivial] [[READ]]
+    // CHECK: [[SUPER_CTOR:%[0-9]+]] = function_ref @$S8lifetime1BC1yACSi_tcfc : $@convention(method) (Int, @owned B) -> @owned B
+    // CHECK: [[THIS2_SUP:%[0-9]+]] = apply [[SUPER_CTOR]]([[Y]], [[THIS1_SUP]])
+    // CHECK: [[THIS2:%[0-9]+]] = unchecked_ref_cast [[THIS2_SUP]] : $B to $D
+    // CHECK: [[THIS1:%[0-9]+]] = load [copy] [[PB_BOX]]
+    // CHECK: destroy_value [[MARKED_SELF_BOX]]
+  }
+
+  func foo() {}
+}
+
+// CHECK-LABEL: sil hidden @$S8lifetime8downcast{{[_0-9a-zA-Z]*}}F
+func downcast(_ b: B) {
+  var b = b
+  // CHECK: [[BADDR:%[0-9]+]] = alloc_box ${ var B }
+  // CHECK: [[PB:%[0-9]+]] = project_box [[BADDR]]
+  (b as! D).foo()
+  // CHECK: [[READ:%.*]] = begin_access [read] [unknown] [[PB]]
+  // CHECK: [[B:%[0-9]+]] = load [copy] [[READ]]
+  // CHECK: [[D:%[0-9]+]] = unconditional_checked_cast [[B]] : {{.*}} to $D
+  // CHECK: apply {{.*}}([[D]])
+  // CHECK-NOT: destroy_value [[B]]
+  // CHECK: destroy_value [[D]]
+  // CHECK: destroy_value [[BADDR]]
+  // CHECK: return
+}
+
+func int(_ x: Int) {}
+func ref(_ x: Ref) {}
+
+func tuple() -> (Int, Ref) { return (1, Ref()) }
+
+func tuple_explosion() {
+  int(tuple().0)
+  // CHECK: [[F:%[0-9]+]] = function_ref @$S8lifetime5tupleSi_AA3RefCtyF
+  // CHECK: [[TUPLE:%[0-9]+]] = apply [[F]]()
+  // CHECK: [[BORROWED_TUPLE:%.*]] = begin_borrow [[TUPLE]]
+  // CHECK: [[T1:%[0-9]+]] = tuple_extract [[BORROWED_TUPLE]] : {{.*}}, 1
+  // CHECK: [[T1_COPY:%.*]] = copy_value [[T1]]
+  // CHECK: end_borrow [[BORROWED_TUPLE]] from [[TUPLE]]
+  // CHECK: destroy_value [[T1_COPY]]
+  // CHECK-NOT: tuple_extract [[TUPLE]] : {{.*}}, 1
+  // CHECK-NOT: destroy_value
+
+  ref(tuple().1)
+  // CHECK: [[F:%[0-9]+]] = function_ref @$S8lifetime5tupleSi_AA3RefCtyF
+  // CHECK: [[TUPLE:%[0-9]+]] = apply [[F]]()
+  // CHECK: [[BORROWED_TUPLE:%.*]] = begin_borrow [[TUPLE]]
+  // CHECK: [[T1:%[0-9]+]] = tuple_extract [[BORROWED_TUPLE]] : {{.*}}, 1
+  // CHECK: [[T1_COPY:%.*]] = copy_value [[T1]]
+  // CHECK: end_borrow [[BORROWED_TUPLE]] from [[TUPLE]]
+  // CHECK: destroy_value [[TUPLE]]
+  // CHECK-NOT: destroy_value [[T1]]
+  // CHECK-NOT: tuple_extract [[TUPLE]] : {{.*}}, 1
+  // CHECK-NOT: destroy_value [[TUPLE]]
+}
+
+class C {
+  var v = ""
+  // CHECK-LABEL: sil hidden @$S8lifetime1CC18ignored_assignment{{[_0-9a-zA-Z]*}}F
+  func ignored_assignment() {
+    // CHECK: [[STRING:%.*]] = alloc_stack $String
+    // CHECK: [[UNINIT:%.*]] = mark_uninitialized [var] [[STRING]]
+    // CHECK: assign {{%.*}} to [[UNINIT]]
+    // CHECK: destroy_addr [[UNINIT]]
+    _ = self.v
+  }
+}
diff --git a/test/SILGen/plus_zero_mangling.swift b/test/SILGen/plus_zero_mangling.swift
new file mode 100644
index 0000000..a0357ce
--- /dev/null
+++ b/test/SILGen/plus_zero_mangling.swift
@@ -0,0 +1,191 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -Xllvm -sil-full-demangle -sdk %S/Inputs -I %S/Inputs -enable-source-import %s -emit-silgen -enable-sil-ownership | %FileCheck %s
+
+// REQUIRES: objc_interop
+
+import gizmo
+
+// Test mangling of Unicode identifiers.
+// These examples are from RFC 3492, which defines the Punycode encoding used
+// by name mangling.
+
+// CHECK-LABEL: sil hidden @$S8mangling0022egbpdajGbuEbxfgehfvwxnyyF
+func ليهمابتكلموشعربي؟() { }
+// CHECK-LABEL: sil hidden @$S8mangling0024ihqwcrbEcvIaIdqgAFGpqjyeyyF
+func 他们为什么不说中文() { }
+// CHECK-LABEL: sil hidden @$S8mangling0027ihqwctvzcJBfGFJdrssDxIboAybyyF
+func 他們爲什麽不說中文() { }
+// CHECK-LABEL: sil hidden @$S8mangling0030Proprostnemluvesky_uybCEdmaEBayyF
+func Pročprostěnemluvíčesky() { }
+
+// <rdar://problem/13757744> Variadic tuples need a different mangling from
+// non-variadic tuples.
+
+// CHECK-LABEL: sil hidden @$S8mangling9r137577441xySaySiG_tF
+func r13757744(x: [Int]) {}
+// CHECK-LABEL: sil hidden @$S8mangling9r137577441xySid_tF
+func r13757744(x: Int...) {}
+
+// <rdar://problem/13757750> Prefix, postfix, and infix operators need
+// distinct manglings.
+
+prefix operator +-
+postfix operator +-
+infix operator +-
+
+// CHECK-LABEL: sil hidden @$S8mangling2psopyyxlF
+prefix func +- <T>(a: T) {}
+// CHECK-LABEL: sil hidden @$S8mangling2psoPyyxlF
+postfix func +- <T>(a: T) {}
+
+// CHECK-LABEL: sil hidden @$S8mangling2psoiyyx_xtlF
+func +- <T>(a: T, b: T) {}
+
+// CHECK-LABEL: sil hidden @$S8mangling2psopyyx1a_x1bt_tlF
+prefix func +- <T>(_: (a: T, b: T)) {}
+// CHECK-LABEL: sil hidden @$S8mangling2psoPyyx1a_x1bt_tlF
+postfix func +- <T>(_: (a: T, b: T)) {}
+
+infix operator «+» {}
+
+// CHECK-LABEL: sil hidden @$S8mangling007p_qcaDcoiyS2i_SitF
+func «+»(a: Int, b: Int) -> Int { return a + b }
+
+protocol Foo {}
+protocol Bar {}
+
+// Ensure protocol list manglings are '_' terminated regardless of length
+// CHECK-LABEL: sil hidden @$S8mangling12any_protocolyyypF
+func any_protocol(_: Any) {}
+// CHECK-LABEL: sil hidden @$S8mangling12one_protocolyyAA3Foo_pF
+func one_protocol(_: Foo) {}
+// CHECK-LABEL: sil hidden @$S8mangling18one_protocol_twiceyyAA3Foo_p_AaC_ptF
+func one_protocol_twice(_: Foo, _: Foo) {}
+// CHECK-LABEL: sil hidden @$S8mangling12two_protocolyyAA3Bar_AA3FoopF
+func two_protocol(_: Foo & Bar) {}
+
+// Ensure archetype depths are mangled correctly.
+class Zim<T> {
+  // CHECK-LABEL: sil hidden @$S8mangling3ZimC4zangyyx_qd__tlF
+  func zang<U>(_: T, _: U) {}
+  // CHECK-LABEL: sil hidden @$S8mangling3ZimC4zungyyqd___xtlF
+  func zung<U>(_: U, _: T) {}
+}
+
+// Don't crash mangling single-protocol "composition" types.
+// CHECK-LABEL: sil hidden @$S8mangling27single_protocol_composition1xyAA3Foo_p_tF
+func single_protocol_composition(x: protocol<Foo>) {} // expected-warning {{'protocol<...>' composition syntax is deprecated; join the protocols using '&'}}
+
+// Clang-imported classes and protocols get mangled into a magic 'So' context
+// to make collisions into link errors. <rdar://problem/14221244>
+// CHECK-LABEL: sil hidden @$S8mangling28uses_objc_class_and_protocol1o1p2p2ySo8NSObjectC_So8NSAnsing_pSo14NSBetterAnsing_ptF
+func uses_objc_class_and_protocol(o: NSObject, p: NSAnsing, p2: BetterAnsing) {}
+
+// Clang-imported structs get mangled using their Clang module name.
+// FIXME: Temporarily mangles everything into the virtual module __C__
+// <rdar://problem/14221244>
+// CHECK-LABEL: sil hidden @$S8mangling17uses_clang_struct1rySo6NSRectV_tF
+func uses_clang_struct(r: NSRect) {}
+
+// CHECK-LABEL: sil hidden @$S8mangling14uses_optionals1xs7UnicodeO6ScalarVSgSiSg_tF
+func uses_optionals(x: Int?) -> UnicodeScalar? { return nil }
+
+enum GenericUnion<T> {
+  // CHECK-LABEL: sil shared [transparent] @$S8mangling12GenericUnionO3FooyACyxGSicAEmlF
+  case Foo(Int)
+}
+
+func instantiateGenericUnionConstructor<T>(_ t: T) {
+  _ = GenericUnion<T>.Foo
+}
+
+struct HasVarInit {
+  static var state = true && false
+}
+// CHECK-LABEL: // function_ref implicit closure #1 : @autoclosure () throws -> Swift.Bool in variable initialization expression of static mangling.HasVarInit.state : Swift.Bool
+// CHECK-NEXT:  function_ref @$S8mangling10HasVarInitV5stateSbvpZfiSbyKXKfu_
+
+// auto_closures should not collide with the equivalent non-auto_closure
+// function type.
+
+// CHECK-LABEL: sil hidden @$S8mangling19autoClosureOverload1fySiyXK_tF : $@convention(thin) (@noescape @callee_guaranteed () -> Int) -> () {
+func autoClosureOverload(f: @autoclosure () -> Int) {}
+// CHECK-LABEL: sil hidden @$S8mangling19autoClosureOverload1fySiyXE_tF : $@convention(thin) (@noescape @callee_guaranteed () -> Int) -> () {
+func autoClosureOverload(f: () -> Int) {}
+
+// CHECK-LABEL: sil hidden @$S8mangling24autoClosureOverloadCallsyyF : $@convention(thin) () -> () {
+func autoClosureOverloadCalls() {
+  // CHECK: function_ref @$S8mangling19autoClosureOverload1fySiyXK_tF
+  autoClosureOverload(f: 1)
+  // CHECK: function_ref @$S8mangling19autoClosureOverload1fySiyXE_tF
+  autoClosureOverload {1}
+}
+
+// <rdar://problem/16079822> Associated type requirements need to appear in the
+// mangling.
+
+protocol AssocReqt {}
+
+protocol HasAssocType {
+  associatedtype Assoc
+}
+
+// CHECK-LABEL: sil hidden @$S8mangling4fooAyyxAA12HasAssocTypeRzlF : $@convention(thin) <T where T : HasAssocType> (@in_guaranteed T) -> ()
+func fooA<T: HasAssocType>(_: T) {}
+// CHECK-LABEL: sil hidden @$S8mangling4fooByyxAA12HasAssocTypeRzAA0D4Reqt0D0RpzlF : $@convention(thin) <T where T : HasAssocType, T.Assoc : AssocReqt> (@in_guaranteed T) -> ()
+func fooB<T: HasAssocType>(_: T) where T.Assoc: AssocReqt {}
+
+// CHECK-LABEL: sil hidden @$S8mangling2qqoiyySi_SitF
+func ??(x: Int, y: Int) {}
+
+struct InstanceAndClassProperty {
+  var property: Int {
+    // CHECK-LABEL: sil hidden @$S8mangling24InstanceAndClassPropertyV8propertySivg
+    get { return 0 }
+    // CHECK-LABEL: sil hidden @$S8mangling24InstanceAndClassPropertyV8propertySivs
+    set {}
+  }
+  static var property: Int {
+    // CHECK-LABEL: sil hidden @$S8mangling24InstanceAndClassPropertyV8propertySivgZ
+    get { return 0 }
+    // CHECK-LABEL: sil hidden @$S8mangling24InstanceAndClassPropertyV8propertySivsZ
+    set {}
+  }
+}
+
+// CHECK-LABEL: sil hidden @$S8mangling6curry1yyF : $@convention(thin) () -> ()
+func curry1() {
+
+}
+
+// CHECK-LABEL: sil hidden @$S8mangling3barSiyKF : $@convention(thin) () -> (Int, @error Error)
+func bar() throws -> Int { return 0 }
+
+// CHECK-LABEL: sil hidden @$S8mangling12curry1ThrowsyyKF : $@convention(thin) () -> @error Error
+func curry1Throws() throws {
+
+}
+
+// CHECK-LABEL: sil hidden @$S8mangling12curry2ThrowsyycyKF : $@convention(thin) () -> (@owned @callee_guaranteed () -> (), @error Error)
+func curry2Throws() throws -> () -> () {
+  return curry1
+}
+
+// CHECK-LABEL: sil hidden @$S8mangling6curry3yyKcyF : $@convention(thin) () -> @owned @callee_guaranteed () -> @error Error
+func curry3() -> () throws -> () {
+  return curry1Throws
+}
+
+// CHECK-LABEL: sil hidden @$S8mangling12curry3ThrowsyyKcyKF : $@convention(thin) () -> (@owned @callee_guaranteed () -> @error Error, @error Error)
+func curry3Throws() throws -> () throws -> () {
+  return curry1Throws
+}
+
+// CHECK-LABEL: sil hidden @$S8mangling14varargsVsArray3arr1nySid_SStF : $@convention(thin) (@guaranteed Array<Int>, @guaranteed String) -> ()
+func varargsVsArray(arr: Int..., n: String) { }
+
+// CHECK-LABEL: sil hidden @$S8mangling14varargsVsArray3arr1nySaySiG_SStF : $@convention(thin) (@guaranteed Array<Int>, @guaranteed String) -> ()
+func varargsVsArray(arr: [Int], n: String) { }
+
+// CHECK-LABEL: sil hidden @$S8mangling14varargsVsArray3arr1nySaySiGd_SStF : $@convention(thin) (@guaranteed Array<Array<Int>>, @guaranteed String) -> ()
+func varargsVsArray(arr: [Int]..., n: String) { }
diff --git a/test/SILGen/plus_zero_materializeForSet.swift b/test/SILGen/plus_zero_materializeForSet.swift
new file mode 100644
index 0000000..f742400a
--- /dev/null
+++ b/test/SILGen/plus_zero_materializeForSet.swift
@@ -0,0 +1,677 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -emit-silgen %s | %FileCheck %s
+// RUN: %target-swift-frontend -emit-silgen -enforce-exclusivity=unchecked %s | %FileCheck --check-prefix=UNCHECKED %s
+
+class Base {
+  var stored: Int = 0
+
+// CHECK-LABEL: sil hidden [transparent] @$S17materializeForSet4BaseC6storedSivm : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @guaranteed Base) -> (Builtin.RawPointer, Optional<Builtin.RawPointer>) {
+// CHECK: bb0([[BUFFER:%.*]] : $Builtin.RawPointer, [[STORAGE:%.*]] : $*Builtin.UnsafeValueBuffer, [[SELF:%.*]] : $Base):
+// CHECK:   [[T0:%.*]] = ref_element_addr [[SELF]] : $Base, #Base.stored
+// CHECK:   [[T1:%.*]] = address_to_pointer [[T0]] : $*Int to $Builtin.RawPointer
+// CHECK:   [[T2:%.*]] = enum $Optional<Builtin.RawPointer>, #Optional.some
+// CHECK:   [[T3:%.*]] = tuple ([[T1]] : $Builtin.RawPointer, [[T2]] : $Optional<Builtin.RawPointer>)
+// CHECK:   return [[T3]] : $(Builtin.RawPointer, Optional<Builtin.RawPointer>)
+// CHECK: }
+
+// UNCHECKED-LABEL: sil hidden [transparent] @$S17materializeForSet4BaseC6storedSivm : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @guaranteed Base) -> (Builtin.RawPointer, Optional<Builtin.RawPointer>) {
+// UNCHECKED: bb0([[BUFFER:%.*]] : $Builtin.RawPointer, [[STORAGE:%.*]] : $*Builtin.UnsafeValueBuffer, [[SELF:%.*]] : $Base):
+// UNCHECKED:   [[T0:%.*]] = ref_element_addr [[SELF]] : $Base, #Base.stored
+// UNCHECKED:   [[T1:%.*]] = address_to_pointer [[T0]] : $*Int to $Builtin.RawPointer
+// UNCHECKED:   [[T2:%.*]] = enum $Optional<Builtin.RawPointer>, #Optional.none
+// UNCHECKED:   [[T3:%.*]] = tuple ([[T1]] : $Builtin.RawPointer, [[T2]] : $Optional<Builtin.RawPointer>)
+// UNCHECKED:   return [[T3]] : $(Builtin.RawPointer, Optional<Builtin.RawPointer>)
+// UNCHECKED: }
+
+// CHECK-LABEL: sil private [transparent] @$S17materializeForSet4BaseC8computedSivmytfU_ : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout Base, @thick Base.Type) -> () {
+// CHECK: bb0([[BUFFER:%.*]] : $Builtin.RawPointer, [[STORAGE:%.*]] : $*Builtin.UnsafeValueBuffer, [[SELF:%.*]] : $*Base, [[SELFTYPE:%.*]] : $@thick Base.Type):
+// CHECK:   [[T0:%.*]] = load_borrow [[SELF]]
+// CHECK:   [[T1:%.*]] = pointer_to_address [[BUFFER]] : $Builtin.RawPointer to [strict] $*Int
+// CHECK:   [[T2:%.*]] = load [trivial] [[T1]] : $*Int
+// CHECK:   [[SETTER:%.*]] = function_ref @$S17materializeForSet4BaseC8computedSivs
+// CHECK:   apply [[SETTER]]([[T2]], [[T0]])
+
+// CHECK-LABEL: sil hidden [transparent] @$S17materializeForSet4BaseC8computedSivm : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @guaranteed Base) -> (Builtin.RawPointer, Optional<Builtin.RawPointer>) {
+// CHECK: bb0([[BUFFER:%.*]] : $Builtin.RawPointer, [[STORAGE:%.*]] : $*Builtin.UnsafeValueBuffer, [[SELF:%.*]] : $Base):
+// CHECK:   [[ADDR:%.*]] = pointer_to_address [[BUFFER]] : $Builtin.RawPointer to [strict] $*Int
+// CHECK:   [[T0:%.*]] = function_ref @$S17materializeForSet4BaseC8computedSivg
+// CHECK:   [[T1:%.*]] = apply [[T0]]([[SELF]])
+// CHECK:   store [[T1]] to [trivial] [[ADDR]] : $*Int
+// CHECK:   [[BUFFER:%.*]] = address_to_pointer [[ADDR]]
+// CHECK:   [[T0:%.*]] = function_ref @$S17materializeForSet4BaseC8computedSivmytfU_ : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout Base, @thick Base.Type) -> ()
+// CHECK:   [[T2:%.*]] = thin_function_to_pointer [[T0]]
+// CHECK:   [[T3:%.*]] = enum $Optional<Builtin.RawPointer>, #Optional.some!enumelt.1, [[T2]] : $Builtin.RawPointer
+// CHECK:   [[T4:%.*]] = tuple ([[BUFFER]] : $Builtin.RawPointer, [[T3]] : $Optional<Builtin.RawPointer>)
+// CHECK:   return [[T4]] : $(Builtin.RawPointer, Optional<Builtin.RawPointer>)
+// CHECK: }
+
+  var computed: Int {
+    get { return 0 }
+    set(value) {}
+  }
+
+  var storedFunction: () -> Int = { 0 }
+  final var finalStoredFunction: () -> Int = { 0 }
+  var computedFunction: () -> Int {
+    get { return {0} }
+    set {}
+  }
+  static var staticFunction: () -> Int {
+    get { return {0} }
+    set {}
+  }
+}
+
+class Derived : Base {}
+
+protocol Abstractable {
+  associatedtype Result
+  var storedFunction: () -> Result { get set }
+  var finalStoredFunction: () -> Result { get set }
+  var computedFunction: () -> Result { get set }
+  static var staticFunction: () -> Result { get set }
+}
+
+// Validate that we thunk materializeForSet correctly when there's
+// an abstraction pattern present.
+
+extension Derived : Abstractable {}
+
+// CHECK-LABEL: sil private [transparent] @$S17materializeForSet7DerivedCAA12AbstractableA2aDP14storedFunction6ResultQzycvmytfU_TW : $@convention(witness_method: Abstractable) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout Derived, @thick Derived.Type) -> ()
+// CHECK: bb0(%0 : $Builtin.RawPointer, %1 : $*Builtin.UnsafeValueBuffer, %2 : $*Derived, %3 : $@thick Derived.Type):
+// CHECK-NEXT: [[T0:%.*]] = load_borrow %2 : $*Derived
+// CHECK-NEXT: [[SELF:%.*]] = upcast [[T0]] : $Derived to $Base
+// CHECK-NEXT: [[RESULT_ADDR:%.*]] = pointer_to_address %0 : $Builtin.RawPointer to [strict] $*@callee_guaranteed () -> @out Int
+// CHECK-NEXT: [[VALUE:%.*]] = load [take] [[RESULT_ADDR]] : $*@callee_guaranteed () -> @out Int
+// CHECK-NEXT: function_ref
+// CHECK-NEXT: [[REABSTRACTOR:%.*]] = function_ref @$SSiIegr_SiIegd_TR : $@convention(thin) (@guaranteed @callee_guaranteed () -> @out Int) -> Int
+// CHECK-NEXT: [[NEWVALUE:%.*]] = partial_apply [callee_guaranteed] [[REABSTRACTOR]]([[VALUE]])
+// CHECK-NEXT: [[FN:%.*]] = class_method [[SELF]] : $Base, #Base.storedFunction!setter.1 : (Base) -> (@escaping () -> Int) -> ()
+// CHECK-NEXT: apply [[FN]]([[NEWVALUE]], [[SELF]])
+// CHECK-NEXT: end_borrow [[T0]] from %2
+// CHECK-NEXT: tuple ()
+// CHECK-NEXT: return
+
+// CHECK-LABEL: sil private [transparent] [thunk] @$S17materializeForSet7DerivedCAA12AbstractableA2aDP14storedFunction{{[_0-9a-zA-Z]*}}vmTW
+// CHECK: bb0(%0 : $Builtin.RawPointer, %1 : $*Builtin.UnsafeValueBuffer, %2 : $*Derived):
+// CHECK-NEXT: [[RESULT_ADDR:%.*]] = pointer_to_address %0 : $Builtin.RawPointer to [strict] $*@callee_guaranteed () -> @out Int
+// CHECK-NEXT: [[T0:%.*]] = load_borrow %2 : $*Derived
+// CHECK-NEXT: [[SELF:%.*]] = upcast [[T0]] : $Derived to $Base
+// CHECK-NEXT: [[TEMP:%.*]] = alloc_stack $@callee_guaranteed () -> Int
+// CHECK-NEXT: [[FN:%.*]] = class_method [[SELF]] : $Base, #Base.storedFunction!getter.1
+// CHECK-NEXT: [[RESULT:%.*]] = apply [[FN]]([[SELF]])
+// CHECK-NEXT: store [[RESULT]] to [init] [[TEMP]]
+// CHECK-NEXT: [[RESULT:%.*]] = load [copy] [[TEMP]]
+// CHECK-NEXT: function_ref
+// CHECK-NEXT: [[REABSTRACTOR:%.*]] = function_ref @$SSiIegd_SiIegr_TR : $@convention(thin) (@guaranteed @callee_guaranteed () -> Int) -> @out Int
+// CHECK-NEXT: [[T1:%.*]] = partial_apply [callee_guaranteed] [[REABSTRACTOR]]([[RESULT]])
+// CHECK-NEXT: destroy_addr [[TEMP]]
+// CHECK-NEXT: store [[T1]] to [init] [[RESULT_ADDR]]
+// CHECK-NEXT: [[RESULT_PTR:%.*]] = address_to_pointer [[RESULT_ADDR]] : $*@callee_guaranteed () -> @out Int to $Builtin.RawPointer
+// CHECK-NEXT: function_ref
+// CHECK-NEXT: [[T2:%.*]] = function_ref @$S17materializeForSet7DerivedCAA12AbstractableA2aDP14storedFunction6ResultQzycvmytfU_TW
+// CHECK-NEXT: [[T3:%.*]] = thin_function_to_pointer [[T2]]
+// CHECK-NEXT: [[CALLBACK:%.*]] = enum $Optional<Builtin.RawPointer>, #Optional.some!enumelt.1, [[T3]]
+// CHECK-NEXT: [[T4:%.*]] = tuple ([[RESULT_PTR]] : $Builtin.RawPointer, [[CALLBACK]] : $Optional<Builtin.RawPointer>)
+// CHECK-NEXT: dealloc_stack [[TEMP]]
+// CHECK-NEXT: end_borrow [[T0]] from %2
+// CHECK-NEXT: return [[T4]]
+
+// CHECK-LABEL: sil private [transparent] @$S17materializeForSet7DerivedCAA12AbstractableA2aDP19finalStoredFunction6ResultQzycvmytfU_TW :
+// CHECK: bb0(%0 : $Builtin.RawPointer, %1 : $*Builtin.UnsafeValueBuffer, %2 : $*Derived, %3 : $@thick Derived.Type):
+// CHECK-NEXT: [[T0:%.*]] = load_borrow %2 : $*Derived
+// CHECK-NEXT: [[SELF:%.*]] = upcast [[T0]] : $Derived to $Base
+// CHECK-NEXT: [[RESULT_ADDR:%.*]] = pointer_to_address %0 : $Builtin.RawPointer to [strict] $*@callee_guaranteed () -> @out Int
+// CHECK-NEXT: [[VALUE:%.*]] = load [take] [[RESULT_ADDR]] : $*@callee_guaranteed () -> @out Int
+// CHECK-NEXT: // function_ref
+// CHECK-NEXT: [[REABSTRACTOR:%.*]] = function_ref @$SSiIegr_SiIegd_TR : $@convention(thin) (@guaranteed @callee_guaranteed () -> @out Int) -> Int
+// CHECK-NEXT: [[NEWVALUE:%.*]] = partial_apply [callee_guaranteed] [[REABSTRACTOR]]([[VALUE]])
+// CHECK-NEXT: [[ADDR:%.*]] = ref_element_addr [[SELF]] : $Base, #Base.finalStoredFunction
+// CHECK-NEXT: [[WRITE:%.*]] = begin_access [modify] [dynamic] [[ADDR]] : $*@callee_guaranteed () -> Int
+// CHECK-NEXT: assign [[NEWVALUE]] to [[WRITE]]
+// CHECK-NEXT: end_access [[WRITE]] : $*@callee_guaranteed () -> Int
+// CHECK-NEXT: end_borrow [[T0]] from %2
+// CHECK-NEXT: tuple ()
+// CHECK-NEXT: return
+
+// UNCHECKED-LABEL: sil private [transparent] @$S17materializeForSet7DerivedCAA12AbstractableA2aDP19finalStoredFunction6ResultQzycvmytfU_TW :
+// UNCHECKED: bb0(%0 : $Builtin.RawPointer, %1 : $*Builtin.UnsafeValueBuffer, %2 : $*Derived, %3 : $@thick Derived.Type):
+// UNCHECKED-NEXT: [[T0:%.*]] = load_borrow %2 : $*Derived
+// UNCHECKED-NEXT: [[SELF:%.*]] = upcast [[T0]] : $Derived to $Base
+// UNCHECKED-NEXT: [[RESULT_ADDR:%.*]] = pointer_to_address %0 : $Builtin.RawPointer to [strict] $*@callee_guaranteed () -> @out Int
+// UNCHECKED-NEXT: [[VALUE:%.*]] = load [take] [[RESULT_ADDR]] : $*@callee_guaranteed () -> @out Int
+// UNCHECKED-NEXT: // function_ref
+// UNCHECKED-NEXT: [[REABSTRACTOR:%.*]] = function_ref @$SSiIegr_SiIegd_TR : $@convention(thin) (@guaranteed @callee_guaranteed () -> @out Int) -> Int
+// UNCHECKED-NEXT: [[NEWVALUE:%.*]] = partial_apply [callee_guaranteed] [[REABSTRACTOR]]([[VALUE]])
+// UNCHECKED-NEXT: [[ADDR:%.*]] = ref_element_addr [[SELF]] : $Base, #Base.finalStoredFunction
+// UNCHECKED-NEXT: assign [[NEWVALUE]] to [[ADDR]]
+// UNCHECKED-NEXT: end_borrow [[T0]] from %2
+// UNCHECKED-NEXT: tuple ()
+// UNCHECKED-NEXT: return
+
+// CHECK-LABEL: sil private [transparent] [thunk] @$S17materializeForSet7DerivedCAA12AbstractableA2aDP19finalStoredFunction{{[_0-9a-zA-Z]*}}vmTW
+// CHECK: bb0(%0 : $Builtin.RawPointer, %1 : $*Builtin.UnsafeValueBuffer, %2 : $*Derived):
+// CHECK-NEXT: [[RESULT_ADDR:%.*]] = pointer_to_address %0 : $Builtin.RawPointer to [strict] $*@callee_guaranteed () -> @out Int
+// CHECK-NEXT: [[T0:%.*]] = load_borrow %2 : $*Derived
+// CHECK-NEXT: [[SELF:%.*]] = upcast [[T0]] : $Derived to $Base
+// CHECK-NEXT: [[ADDR:%.*]] = ref_element_addr [[SELF]] : $Base, #Base.finalStoredFunction
+// CHECK-NEXT: [[READ:%.*]] = begin_access [read] [dynamic] [[ADDR]] : $*@callee_guaranteed () -> Int
+// CHECK-NEXT: [[RESULT:%.*]] = load [copy] [[READ]]
+// CHECK-NEXT: function_ref
+// CHECK-NEXT: [[REABSTRACTOR:%.*]] = function_ref @$SSiIegd_SiIegr_TR : $@convention(thin) (@guaranteed @callee_guaranteed () -> Int) -> @out Int
+// CHECK-NEXT: [[T1:%.*]] = partial_apply [callee_guaranteed] [[REABSTRACTOR]]([[RESULT]])
+// CHECK-NEXT: end_access [[READ]] : $*@callee_guaranteed () -> Int
+// CHECK-NEXT: store [[T1]] to [init] [[RESULT_ADDR]]
+// CHECK-NEXT: [[RESULT_PTR:%.*]] = address_to_pointer [[RESULT_ADDR]] : $*@callee_guaranteed () -> @out Int to $Builtin.RawPointer
+// CHECK-NEXT: function_ref
+// CHECK-NEXT: [[T2:%.*]] = function_ref @$S17materializeForSet7DerivedCAA12AbstractableA2aDP19finalStoredFunction6ResultQzycvmytfU_TW
+// CHECK-NEXT: [[T3:%.*]] = thin_function_to_pointer [[T2]]
+// CHECK-NEXT: [[CALLBACK:%.*]] = enum $Optional<Builtin.RawPointer>, #Optional.some!enumelt.1, [[T3]]
+// CHECK-NEXT: [[T4:%.*]] = tuple ([[RESULT_PTR]] : $Builtin.RawPointer, [[CALLBACK]] : $Optional<Builtin.RawPointer>)
+// CHECK-NEXT: end_borrow [[T0]] from %2
+// CHECK-NEXT: return [[T4]]
+
+// UNCHECKED-LABEL: sil private [transparent] [thunk] @$S17materializeForSet7DerivedCAA12AbstractableA2aDP19finalStoredFunction{{[_0-9a-zA-Z]*}}vmTW
+// UNCHECKED: bb0(%0 : $Builtin.RawPointer, %1 : $*Builtin.UnsafeValueBuffer, %2 : $*Derived):
+// UNCHECKED-NEXT: [[RESULT_ADDR:%.*]] = pointer_to_address %0 : $Builtin.RawPointer to [strict] $*@callee_guaranteed () -> @out Int
+// UNCHECKED-NEXT: [[T0:%.*]] = load_borrow %2 : $*Derived
+// UNCHECKED-NEXT: [[SELF:%.*]] = upcast [[T0]] : $Derived to $Base
+// UNCHECKED-NEXT: [[ADDR:%.*]] = ref_element_addr [[SELF]] : $Base, #Base.finalStoredFunction
+// UNCHECKED-NEXT: [[RESULT:%.*]] = load [copy] [[ADDR]]
+// UNCHECKED-NEXT: function_ref
+// UNCHECKED-NEXT: [[REABSTRACTOR:%.*]] = function_ref @$SSiIegd_SiIegr_TR : $@convention(thin) (@guaranteed @callee_guaranteed () -> Int) -> @out Int
+// UNCHECKED-NEXT: [[T1:%.*]] = partial_apply [callee_guaranteed] [[REABSTRACTOR]]([[RESULT]])
+// UNCHECKED-NEXT: store [[T1]] to [init] [[RESULT_ADDR]]
+// UNCHECKED-NEXT: [[RESULT_PTR:%.*]] = address_to_pointer [[RESULT_ADDR]] : $*@callee_guaranteed () -> @out Int to $Builtin.RawPointer
+// UNCHECKED-NEXT: function_ref
+// UNCHECKED-NEXT: [[T2:%.*]] = function_ref @$S17materializeForSet7DerivedCAA12AbstractableA2aDP19finalStoredFunction6ResultQzycvmytfU_TW
+// UNCHECKED-NEXT: [[T3:%.*]] = thin_function_to_pointer [[T2]]
+// UNCHECKED-NEXT: [[CALLBACK:%.*]] = enum $Optional<Builtin.RawPointer>, #Optional.some!enumelt.1, [[T3]]
+// UNCHECKED-NEXT: [[T4:%.*]] = tuple ([[RESULT_PTR]] : $Builtin.RawPointer, [[CALLBACK]] : $Optional<Builtin.RawPointer>)
+// UNCHECKED-NEXT: end_borrow [[T0]] from %2
+// UNCHECKED-NEXT: return [[T4]]
+
+// CHECK-LABEL: sil private [transparent] @$S17materializeForSet7DerivedCAA12AbstractableA2aDP14staticFunction6ResultQzycvmZytfU_TW
+// CHECK: bb0([[ARG1:%.*]] : $Builtin.RawPointer, [[ARG2:%.*]] : $*Builtin.UnsafeValueBuffer, [[ARG3:%.*]] : $*@thick Derived.Type, [[ARG4:%.*]] : $@thick Derived.Type.Type):
+// CHECK-NEXT: [[SELF:%.*]] = load [trivial] [[ARG3]] : $*@thick Derived.Type
+// CHECK-NEXT: [[BASE_SELF:%.*]] = upcast [[SELF]] : $@thick Derived.Type to $@thick Base.Type
+// CHECK-NEXT: [[BUFFER:%.*]] = pointer_to_address [[ARG1]] : $Builtin.RawPointer to [strict] $*@callee_guaranteed () -> @out Int
+// CHECK-NEXT: [[VALUE:%.*]] = load [take] [[BUFFER]] : $*@callee_guaranteed () -> @out Int
+// CHECK:      [[REABSTRACTOR:%.*]] = function_ref @$SSiIegr_SiIegd_TR : $@convention(thin) (@guaranteed @callee_guaranteed () -> @out Int) -> Int
+// CHECK-NEXT: [[NEWVALUE:%.*]] = partial_apply [callee_guaranteed] [[REABSTRACTOR]]([[VALUE]]) : $@convention(thin) (@guaranteed @callee_guaranteed () -> @out Int) -> Int
+// CHECK:      [[SETTER_FN:%.*]] = function_ref @$S17materializeForSet4BaseC14staticFunctionSiycvsZ : $@convention(method) (@owned @callee_guaranteed () -> Int, @thick Base.Type) -> ()
+// CHECK-NEXT: apply [[SETTER_FN]]([[NEWVALUE]], [[BASE_SELF]]) : $@convention(method) (@owned @callee_guaranteed () -> Int, @thick Base.Type) -> ()
+// CHECK-NEXT: [[RESULT:%.*]] = tuple ()
+// CHECK-NEXT: return [[RESULT]] : $()
+
+// CHECK-LABEL: sil private [transparent] [thunk] @$S17materializeForSet7DerivedCAA12AbstractableA2aDP14staticFunction6ResultQzycvmZTW
+// CHECK: bb0(%0 : $Builtin.RawPointer, %1 : $*Builtin.UnsafeValueBuffer, %2 : $@thick Derived.Type):
+// CHECK-NEXT: [[RESULT_ADDR:%.*]] = pointer_to_address %0 : $Builtin.RawPointer to [strict] $*@callee_guaranteed () -> @out Int
+// CHECK-NEXT: [[SELF:%.*]] = upcast %2 : $@thick Derived.Type to $@thick Base.Type
+// CHECK-NEXT: [[OUT:%.*]] = alloc_stack $@callee_guaranteed () -> Int
+// CHECK:      [[GETTER:%.*]] = function_ref @$S17materializeForSet4BaseC14staticFunctionSiycvgZ : $@convention(method) (@thick Base.Type) -> @owned @callee_guaranteed () -> Int
+// CHECK-NEXT: [[VALUE:%.*]] = apply [[GETTER]]([[SELF]]) : $@convention(method) (@thick Base.Type) -> @owned @callee_guaranteed () -> Int
+// CHECK-NEXT: store [[VALUE]] to [init] [[OUT]] : $*@callee_guaranteed () -> Int
+// CHECK-NEXT: [[VALUE:%.*]] = load [copy] [[OUT]] : $*@callee_guaranteed () -> Int
+// CHECK:      [[REABSTRACTOR:%.*]] = function_ref @$SSiIegd_SiIegr_TR : $@convention(thin) (@guaranteed @callee_guaranteed () -> Int) -> @out Int
+// CHECK-NEXT: [[NEWVALUE:%.*]] = partial_apply [callee_guaranteed] [[REABSTRACTOR]]([[VALUE]])
+// CHECK-NEXT: destroy_addr [[OUT]] : $*@callee_guaranteed () -> Int
+// CHECK-NEXT: store [[NEWVALUE]] to [init] [[RESULT_ADDR]] : $*@callee_guaranteed () -> @out Int
+// CHECK-NEXT: [[ADDR:%.*]] = address_to_pointer [[RESULT_ADDR]] : $*@callee_guaranteed () -> @out Int to $Builtin.RawPointer
+// CHECK:      [[CALLBACK_FN:%.*]] = function_ref @$S17materializeForSet7DerivedCAA12AbstractableA2aDP14staticFunction6ResultQzycvmZytfU_TW : $@convention(witness_method: Abstractable) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout @thick Derived.Type, @thick Derived.Type.Type) -> ()
+// CHECK-NEXT: [[CALLBACK_ADDR:%.*]] = thin_function_to_pointer [[CALLBACK_FN]] : $@convention(witness_method: Abstractable) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout @thick Derived.Type, @thick Derived.Type.Type) -> () to $Builtin.RawPointer
+// CHECK-NEXT: [[CALLBACK:%.*]] = enum $Optional<Builtin.RawPointer>, #Optional.some!enumelt.1, [[CALLBACK_ADDR]] : $Builtin.RawPointer
+// CHECK-NEXT: [[RESULT:%.*]] = tuple ([[ADDR]] : $Builtin.RawPointer, [[CALLBACK]] : $Optional<Builtin.RawPointer>)
+// CHECK-NEXT: dealloc_stack [[OUT]] : $*@callee_guaranteed () -> Int
+// CHECK-NEXT: return [[RESULT]] : $(Builtin.RawPointer, Optional<Builtin.RawPointer>)
+
+protocol ClassAbstractable : class {
+  associatedtype Result
+  var storedFunction: () -> Result { get set }
+  var finalStoredFunction: () -> Result { get set }
+  var computedFunction: () -> Result { get set }
+  static var staticFunction: () -> Result { get set }
+}
+
+extension Derived : ClassAbstractable {}
+
+protocol Signatures {
+  associatedtype Result
+  var computedFunction: () -> Result { get set }
+}
+protocol Implementations {}
+extension Implementations {
+  var computedFunction: () -> Int {
+    get { return {0} }
+    set {}
+  }
+}
+
+class ImplementingClass : Implementations, Signatures {}
+struct ImplementingStruct : Implementations, Signatures {
+  var ref: ImplementingClass?
+}
+
+class HasDidSet : Base {
+  override var stored: Int {
+    didSet {}
+  }
+
+// CHECK-LABEL: sil hidden [transparent] @$S17materializeForSet06HasDidC0C6storedSivm : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @guaranteed HasDidSet) -> (Builtin.RawPointer, Optional<Builtin.RawPointer>) {
+// CHECK: bb0([[BUFFER:%.*]] : $Builtin.RawPointer, [[STORAGE:%.*]] : $*Builtin.UnsafeValueBuffer, [[SELF:%.*]] : $HasDidSet):
+// CHECK:   [[T2:%.*]] = pointer_to_address [[BUFFER]] : $Builtin.RawPointer to [strict] $*Int
+// CHECK:   [[T0:%.*]] = function_ref @$S17materializeForSet06HasDidC0C6storedSivg
+// CHECK:   [[T1:%.*]] = apply [[T0]]([[SELF]])
+// CHECK:   store [[T1]] to [trivial] [[T2]] : $*Int
+// CHECK:   [[BUFFER:%.*]] = address_to_pointer [[T2]]
+// CHECK:   [[CALLBACK_FN:%.*]] = function_ref @$S17materializeForSet06HasDidC0C6storedSivmytfU_ : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout HasDidSet, @thick HasDidSet.Type) -> ()
+// CHECK:   [[CALLBACK_ADDR:%.*]] = thin_function_to_pointer [[CALLBACK_FN]]
+// CHECK:   [[CALLBACK:%.*]] = enum $Optional<Builtin.RawPointer>, #Optional.some!enumelt.1, [[CALLBACK_ADDR]]
+// CHECK:   [[T4:%.*]] = tuple ([[BUFFER]] : $Builtin.RawPointer, [[CALLBACK]] : $Optional<Builtin.RawPointer>)
+// CHECK:   return [[T4]] : $(Builtin.RawPointer, Optional<Builtin.RawPointer>)
+// CHECK: }
+
+  override var computed: Int {
+    get { return 0 }
+    set(value) {}
+  }
+
+// CHECK-LABEL: sil hidden [transparent] @$S17materializeForSet06HasDidC0C8computedSivm : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @guaranteed HasDidSet) -> (Builtin.RawPointer, Optional<Builtin.RawPointer>) {
+// CHECK: bb0([[BUFFER:%.*]] : $Builtin.RawPointer, [[STORAGE:%.*]] : $*Builtin.UnsafeValueBuffer, [[SELF:%.*]] : $HasDidSet):
+// CHECK:   [[T2:%.*]] = pointer_to_address [[BUFFER]] : $Builtin.RawPointer to [strict] $*Int
+// CHECK:   [[T0:%.*]] = function_ref @$S17materializeForSet06HasDidC0C8computedSivg
+// CHECK:   [[T1:%.*]] = apply [[T0]]([[SELF]])
+// CHECK:   store [[T1]] to [trivial] [[T2]] : $*Int
+// CHECK:   [[BUFFER:%.*]] = address_to_pointer [[T2]]
+// CHECK:   [[CALLBACK_FN:%.*]] = function_ref @$S17materializeForSet06HasDidC0C8computedSivmytfU_ : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout HasDidSet, @thick HasDidSet.Type) -> ()
+// CHECK:   [[CALLBACK_ADDR:%.*]] = thin_function_to_pointer [[CALLBACK_FN]]
+// CHECK:   [[CALLBACK:%.*]] = enum $Optional<Builtin.RawPointer>, #Optional.some!enumelt.1, [[CALLBACK_ADDR]]
+// CHECK:   [[T4:%.*]] = tuple ([[BUFFER]] : $Builtin.RawPointer, [[CALLBACK]] : $Optional<Builtin.RawPointer>)
+// CHECK:   return [[T4]] : $(Builtin.RawPointer, Optional<Builtin.RawPointer>)
+// CHECK: }
+}
+
+class HasStoredDidSet {
+  var stored: Int = 0 {
+    didSet {}
+  }
+
+// CHECK-LABEL: sil private [transparent] @$S17materializeForSet012HasStoredDidC0C6storedSivmytfU_ : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout HasStoredDidSet, @thick HasStoredDidSet.Type) -> () {
+// CHECK: bb0([[BUFFER:%.*]] : $Builtin.RawPointer, [[STORAGE:%.*]] : $*Builtin.UnsafeValueBuffer, [[SELF:%.*]] : $*HasStoredDidSet, [[METATYPE:%.*]] : $@thick HasStoredDidSet.Type):
+// CHECK:   [[SELF_VALUE:%.*]] = load_borrow [[SELF]] : $*HasStoredDidSet
+// CHECK:   [[BUFFER_ADDR:%.*]] = pointer_to_address [[BUFFER]] : $Builtin.RawPointer to [strict] $*Int
+// CHECK:   [[VALUE:%.*]] = load [trivial] [[BUFFER_ADDR]] : $*Int
+// CHECK:   [[SETTER_FN:%.*]] = function_ref @$S17materializeForSet012HasStoredDidC0C6storedSivs : $@convention(method) (Int, @guaranteed HasStoredDidSet) -> ()
+// CHECK:   apply [[SETTER_FN]]([[VALUE]], [[SELF_VALUE]]) : $@convention(method) (Int, @guaranteed HasStoredDidSet) -> ()
+// CHECK:   return
+// CHECK: }
+
+// CHECK-LABEL: sil hidden [transparent] @$S17materializeForSet012HasStoredDidC0C6storedSivm : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @guaranteed HasStoredDidSet) -> (Builtin.RawPointer, Optional<Builtin.RawPointer>) {
+// CHECK: bb0([[BUFFER:%.*]] : $Builtin.RawPointer, [[STORAGE:%.*]] : $*Builtin.UnsafeValueBuffer, [[SELF:%.*]] : $HasStoredDidSet):
+// CHECK:   [[T2:%.*]] = pointer_to_address [[BUFFER]] : $Builtin.RawPointer to [strict] $*Int
+// CHECK:   [[T0:%.*]] = function_ref @$S17materializeForSet012HasStoredDidC0C6storedSivg
+// CHECK:   [[T1:%.*]] = apply [[T0]]([[SELF]])
+// CHECK:   store [[T1]] to [trivial] [[T2]] : $*Int
+// CHECK:   [[BUFFER:%.*]] = address_to_pointer [[T2]]
+// CHECK:   [[CALLBACK_FN:%.*]] = function_ref @$S17materializeForSet012HasStoredDidC0C6storedSivmytfU_ : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout HasStoredDidSet, @thick HasStoredDidSet.Type) -> ()
+// CHECK:   [[CALLBACK_ADDR:%.*]] = thin_function_to_pointer [[CALLBACK_FN]]
+// CHECK:   [[CALLBACK:%.*]] = enum $Optional<Builtin.RawPointer>, #Optional.some!enumelt.1, [[CALLBACK_ADDR]]
+// CHECK:   [[T4:%.*]] = tuple ([[BUFFER]] : $Builtin.RawPointer, [[CALLBACK]] : $Optional<Builtin.RawPointer>)
+// CHECK:   return [[T4]] : $(Builtin.RawPointer, Optional<Builtin.RawPointer>)
+// CHECK: }
+}
+
+class HasWeak {
+  weak var weakvar: HasWeak?
+}
+// CHECK-LABEL: sil hidden [transparent] @$S17materializeForSet7HasWeakC7weakvarACSgXwvm : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @guaranteed HasWeak) -> (Builtin.RawPointer, Optional<Builtin.RawPointer>) {
+// CHECK: bb0([[BUFFER:%.*]] : $Builtin.RawPointer, [[STORAGE:%.*]] : $*Builtin.UnsafeValueBuffer, [[SELF:%.*]] : $HasWeak):
+// CHECK:   [[T2:%.*]] = pointer_to_address [[BUFFER]] : $Builtin.RawPointer to [strict] $*Optional<HasWeak>
+// CHECK:   [[T0:%.*]] = ref_element_addr [[SELF]] : $HasWeak, #HasWeak.weakvar
+// CHECK:   [[READ:%.*]] = begin_access [read] [dynamic] [[T0]] : $*@sil_weak Optional<HasWeak>
+// CHECK:   [[T1:%.*]] = load_weak [[READ]] : $*@sil_weak Optional<HasWeak>
+// CHECK:   end_access [[READ]] : $*@sil_weak Optional<HasWeak>
+// CHECK:   store [[T1]] to [init] [[T2]] : $*Optional<HasWeak>
+// CHECK:   [[BUFFER:%.*]] = address_to_pointer [[T2]]
+// CHECK:   [[T0:%.*]] = function_ref @$S17materializeForSet7HasWeakC7weakvarACSgXwvmytfU_ : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout HasWeak, @thick HasWeak.Type) -> () 
+// CHECK:   [[T4:%.*]] = tuple ([[BUFFER]] : $Builtin.RawPointer, {{.*}} : $Optional<Builtin.RawPointer>)
+// CHECK:   return [[T4]] : $(Builtin.RawPointer, Optional<Builtin.RawPointer>)
+// CHECK: }
+
+// UNCHECKED-LABEL: sil hidden [transparent] @$S17materializeForSet7HasWeakC7weakvarACSgXwvm : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @guaranteed HasWeak) -> (Builtin.RawPointer, Optional<Builtin.RawPointer>) {
+// UNCHECKED: bb0([[BUFFER:%.*]] : $Builtin.RawPointer, [[STORAGE:%.*]] : $*Builtin.UnsafeValueBuffer, [[SELF:%.*]] : $HasWeak):
+// UNCHECKED:   [[T2:%.*]] = pointer_to_address [[BUFFER]] : $Builtin.RawPointer to [strict] $*Optional<HasWeak>
+// UNCHECKED:   [[T0:%.*]] = ref_element_addr [[SELF]] : $HasWeak, #HasWeak.weakvar
+// UNCHECKED:   [[T1:%.*]] = load_weak [[T0]] : $*@sil_weak Optional<HasWeak>
+// UNCHECKED:   store [[T1]] to [init] [[T2]] : $*Optional<HasWeak>
+// UNCHECKED:   [[BUFFER:%.*]] = address_to_pointer [[T2]]
+// UNCHECKED:   [[T0:%.*]] = function_ref @$S17materializeForSet7HasWeakC7weakvarACSgXwvmytfU_ : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout HasWeak, @thick HasWeak.Type) -> () 
+// UNCHECKED:   [[T4:%.*]] = tuple ([[BUFFER]] : $Builtin.RawPointer, {{.*}} : $Optional<Builtin.RawPointer>)
+// UNCHECKED:   return [[T4]] : $(Builtin.RawPointer, Optional<Builtin.RawPointer>)
+// UNCHECKED: }
+
+// rdar://22109071
+// Test that we don't use materializeForSet from a protocol extension.
+protocol Magic {}
+extension Magic {
+  var hocus: Int {
+    get { return 0 }
+    set {}
+  }
+}
+struct Wizard : Magic {}
+func improve(_ x: inout Int) {}
+func improveWizard(_ wizard: inout Wizard) {
+  improve(&wizard.hocus)
+}
+// CHECK-LABEL: sil hidden @$S17materializeForSet13improveWizardyyAA0E0VzF
+// CHECK:       [[WRITE:%.*]] = begin_access [modify] [unknown] %0 : $*Wizard
+// CHECK-NEXT:  [[TEMP:%.*]] = alloc_stack $Int
+//   Call the getter and materialize the result in the temporary.
+// CHECK-NEXT:  [[T0:%.*]] = load [trivial] [[WRITE:.*]] : $*Wizard
+// CHECK:       [[WTEMP:%.*]] = alloc_stack $Wizard
+// CHECK-NEXT:  store [[T0]] to [trivial] [[WTEMP]]
+// CHECK:       [[GETTER:%.*]] = function_ref @$S17materializeForSet5MagicPAAE5hocusSivg
+// CHECK-NEXT:  [[T0:%.*]] = apply [[GETTER]]<Wizard>([[WTEMP]])
+// CHECK-NEXT:  dealloc_stack [[WTEMP]]
+// CHECK-NEXT:  store [[T0]] to [trivial] [[TEMP]]
+//   Call improve.
+// CHECK:       [[IMPROVE:%.*]] = function_ref @$S17materializeForSet7improveyySizF :
+// CHECK-NEXT:  apply [[IMPROVE]]([[TEMP]])
+// CHECK-NEXT:  [[T0:%.*]] = load [trivial] [[TEMP]]
+// CHECK:       [[SETTER:%.*]] = function_ref @$S17materializeForSet5MagicPAAE5hocusSivs
+// CHECK-NEXT:  apply [[SETTER]]<Wizard>([[T0]], [[WRITE]])
+// CHECK-NEXT:  end_access [[WRITE]] : $*Wizard
+// CHECK-NEXT:  dealloc_stack [[TEMP]]
+
+protocol Totalled {
+  var total: Int { get set }
+}
+
+struct Bill : Totalled {
+  var total: Int
+}
+
+// CHECK-LABEL: sil hidden [transparent] @$S17materializeForSet4BillV5totalSivm : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout Bill) -> (Builtin.RawPointer, Optional<Builtin.RawPointer>) {
+// CHECK: bb0([[BUFFER:%.*]] : $Builtin.RawPointer, [[STORAGE:%.*]] : $*Builtin.UnsafeValueBuffer, [[SELF:%.*]] : $*Bill):
+// CHECK:   [[T0:%.*]] = struct_element_addr [[SELF]] : $*Bill, #Bill.total
+// CHECK:   [[T1:%.*]] = address_to_pointer [[T0]] : $*Int to $Builtin.RawPointer
+// CHECK:   [[T3:%.*]] = enum $Optional<Builtin.RawPointer>, #Optional.none!enumelt
+// CHECK:   [[T4:%.*]] = tuple ([[T1]] : $Builtin.RawPointer, [[T3]] : $Optional<Builtin.RawPointer>)
+// CHECK:   return [[T4]] : $(Builtin.RawPointer, Optional<Builtin.RawPointer>)
+// CHECK: }
+
+// CHECK-LABEL:  sil private [transparent] [thunk] @$S17materializeForSet4BillVAA8TotalledA2aDP5totalSivmTW : $@convention(witness_method: Totalled) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout Bill) -> (Builtin.RawPointer, Optional<Builtin.RawPointer>) {
+// CHECK:        bb0([[BUFFER:%.*]] : $Builtin.RawPointer, [[STORAGE:%.*]] : $*Builtin.UnsafeValueBuffer, [[SELF:%.*]] : $*Bill):
+// CHECK:          [[T0:%.*]] = function_ref @$S17materializeForSet4BillV5totalSivm
+// CHECK-NEXT:     [[T1:%.*]] = apply [[T0]]([[BUFFER]], [[STORAGE]], [[SELF]])
+// CHECK-NEXT:     [[LEFT:%.*]] = tuple_extract [[T1]]
+// CHECK-NEXT:     [[RIGHT:%.*]] = tuple_extract [[T1]]
+// CHECK-NEXT:     [[T1:%.*]] = tuple ([[LEFT]] : $Builtin.RawPointer, [[RIGHT]] : $Optional<Builtin.RawPointer>)
+// CHECK-NEXT:     return [[T1]] :
+
+protocol AddressOnlySubscript {
+  associatedtype Index
+  subscript(i: Index) -> Index { get set }
+}
+
+struct Foo<T>: AddressOnlySubscript {
+  subscript(i: T) -> T {
+    get { return i }
+    set { print("\(i) = \(newValue)") }
+  }
+}
+
+func increment(_ x: inout Int) { x += 1 }
+
+// Generic subscripts.
+
+protocol GenericSubscriptProtocol {
+  subscript<T>(_: T) -> T { get set }
+}
+
+struct GenericSubscriptWitness : GenericSubscriptProtocol {
+  subscript<T>(_: T) -> T { get { } set { } }
+}
+
+// CHECK-LABEL: sil private [transparent] @$S17materializeForSet23GenericSubscriptWitnessVyxxcluimytfU_ : $@convention(method) <T> (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout GenericSubscriptWitness, @thick GenericSubscriptWitness.Type) -> () {
+// CHECK:       bb0(%0 : $Builtin.RawPointer, %1 : $*Builtin.UnsafeValueBuffer, %2 : $*GenericSubscriptWitness, %3 : $@thick GenericSubscriptWitness.Type):
+// CHECK:         [[BUFFER:%.*]] = project_value_buffer $T in %1 : $*Builtin.UnsafeValueBuffer
+// CHECK-NEXT:    [[INDICES:%.*]] = pointer_to_address %0 : $Builtin.RawPointer to [strict] $*T
+// CHECK:         [[SETTER:%.*]] = function_ref @$S17materializeForSet23GenericSubscriptWitnessVyxxcluis : $@convention(method) <τ_0_0> (@in τ_0_0, @in τ_0_0, @inout GenericSubscriptWitness) -> ()
+// CHECK-NEXT:    apply [[SETTER]]<T>([[INDICES]], [[BUFFER]], %2) : $@convention(method) <τ_0_0> (@in τ_0_0, @in τ_0_0, @inout GenericSubscriptWitness) -> ()
+// CHECK-NEXT:    dealloc_value_buffer $*T in %1 : $*Builtin.UnsafeValueBuffer
+// CHECK-NEXT:    [[RESULT:%.*]] = tuple ()
+// CHECK-NEXT:    return [[RESULT]] : $()
+
+// CHECK-LABEL: sil hidden [transparent] @$S17materializeForSet23GenericSubscriptWitnessVyxxcluim : $@convention(method) <T> (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @in_guaranteed T, @inout GenericSubscriptWitness) -> (Builtin.RawPointer, Optional<Builtin.RawPointer>) {
+// CHECK:      bb0(%0 : $Builtin.RawPointer, %1 : $*Builtin.UnsafeValueBuffer, %2 : $*T, %3 : $*GenericSubscriptWitness):
+// CHECK-NEXT:   [[BUFFER:%.*]] = alloc_value_buffer $T in %1 : $*Builtin.UnsafeValueBuffer
+// CHECK-NEXT:   copy_addr %2 to [initialization] [[BUFFER]] : $*T
+// CHECK-NEXT:   [[VALUE:%.*]] = pointer_to_address %0 : $Builtin.RawPointer to [strict] $*T
+// CHECK-NEXT:   [[SELF:%.*]] = load [trivial] %3 : $*GenericSubscriptWitness
+// CHECK:        [[GETTER:%.*]] = function_ref @$S17materializeForSet23GenericSubscriptWitnessVyxxcluig : $@convention(method) <τ_0_0> (@in_guaranteed τ_0_0, GenericSubscriptWitness) -> @out τ_0_0
+// CHECK-NEXT:   apply [[GETTER]]<T>([[VALUE]], %2, [[SELF]]) : $@convention(method) <τ_0_0> (@in_guaranteed τ_0_0, GenericSubscriptWitness) -> @out τ_0_0
+// CHECK-NEXT:   [[VALUE_PTR:%.*]] = address_to_pointer [[VALUE]] : $*T to $Builtin.RawPointer
+// CHECK:        [[CALLBACK:%.*]] = function_ref @$S17materializeForSet23GenericSubscriptWitnessVyxxcluimytfU_
+// CHECK-NEXT:   [[CALLBACK_PTR:%.*]] = thin_function_to_pointer [[CALLBACK]] : $@convention(method) <τ_0_0> (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout GenericSubscriptWitness, @thick GenericSubscriptWitness.Type) -> () to $Builtin.RawPointer
+// CHECK-NEXT:   [[CALLBACK_OPTIONAL:%.*]] = enum $Optional<Builtin.RawPointer>, #Optional.some!enumelt.1, [[CALLBACK_PTR]] : $Builtin.RawPointer
+// CHECK-NEXT:   [[RESULT:%.*]] = tuple ([[VALUE_PTR]] : $Builtin.RawPointer, [[CALLBACK_OPTIONAL]] : $Optional<Builtin.RawPointer>)
+// CHECK-NEXT:   return [[RESULT]] : $(Builtin.RawPointer, Optional<Builtin.RawPointer>)
+
+extension GenericSubscriptProtocol {
+  subscript<T>(t: T) -> T { get { } set { } }
+}
+
+struct GenericSubscriptDefaultWitness : GenericSubscriptProtocol { }
+
+// Make sure we correctly infer the 'T : Magic' requirement on all the accessors
+// of the subscript.
+
+struct GenericTypeWithRequirement<T : Magic> {}
+
+protocol InferredRequirementOnSubscriptProtocol {
+  subscript<T>(i: Int) -> GenericTypeWithRequirement<T> { get set }
+}
+
+struct InferredRequirementOnSubscript : InferredRequirementOnSubscriptProtocol {
+  subscript<T>(i: Int) -> GenericTypeWithRequirement<T> {
+    get { }
+    set { }
+  }
+}
+
+// CHECK-LABEL: sil hidden @$S17materializeForSet30InferredRequirementOnSubscriptVyAA015GenericTypeWithE0VyxGSicAA5MagicRzluig : $@convention(method) <T where T : Magic> (Int, InferredRequirementOnSubscript) -> GenericTypeWithRequirement<T>
+
+// CHECK-LABEL: sil hidden @$S17materializeForSet30InferredRequirementOnSubscriptVyAA015GenericTypeWithE0VyxGSicAA5MagicRzluis : $@convention(method) <T where T : Magic> (GenericTypeWithRequirement<T>, Int, @inout InferredRequirementOnSubscript) -> ()
+
+// CHECK-LABEL: sil hidden [transparent] @$S17materializeForSet30InferredRequirementOnSubscriptVyAA015GenericTypeWithE0VyxGSicAA5MagicRzluim : $@convention(method) <T where T : Magic> (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, Int, @inout InferredRequirementOnSubscript) -> (Builtin.RawPointer, Optional<Builtin.RawPointer>)
+
+// Test for materializeForSet vs static properties of structs.
+
+protocol Beverage {
+  static var abv: Int { get set }
+}
+
+struct Beer : Beverage {
+  static var abv: Int {
+    get {
+      return 7
+    }
+    set { }
+  }
+}
+
+struct Wine<Color> : Beverage {
+  static var abv: Int {
+    get {
+      return 14
+    }
+    set { }
+  }
+}
+
+// Make sure we can perform an inout access of such a property too.
+
+func inoutAccessOfStaticProperty<T : Beverage>(_ t: T.Type) {
+  increment(&t.abv)
+}
+
+// Test for materializeForSet vs overridden computed property of classes.
+class BaseForOverride {
+  var valueStored: Int
+  var valueComputed: Int { get { } set { } }
+
+  init(valueStored: Int) {
+    self.valueStored = valueStored
+  }
+}
+
+class DerivedForOverride : BaseForOverride {
+  override var valueStored: Int { get { } set { } }
+  override var valueComputed: Int { get { } set { } }
+}
+
+// Test for materializeForSet vs static properties of classes.
+
+class ReferenceBeer {
+  class var abv: Int {
+    get {
+      return 7
+    }
+    set { }
+  }
+}
+
+func inoutAccessOfClassProperty() {
+  increment(&ReferenceBeer.abv)
+}
+
+// Test for materializeForSet when Self is re-abstracted.
+//
+// We have to open-code the materializeForSelf witness, and not screw up
+// the re-abstraction.
+
+protocol Panda {
+  var x: (Self) -> Self { get set }
+}
+
+func id<T>(_ t: T) -> T { return t }
+
+extension Panda {
+  var x: (Self) -> Self {
+    get { return id }
+    set { }
+  }
+}
+
+struct TuxedoPanda : Panda { }
+
+// CHECK-LABEL: sil private [transparent] @$S17materializeForSet11TuxedoPandaVAA0E0A2aDP1xyxxcvmytfU_TW : $@convention(witness_method: Panda) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout TuxedoPanda, @thick TuxedoPanda.Type) -> ()
+
+  // FIXME: Useless re-abstractions
+
+  // CHECK: function_ref @$S17materializeForSet11TuxedoPandaVACIegnr_A2CIegyd_TR : $@convention(thin) (TuxedoPanda, @guaranteed @callee_guaranteed (@in_guaranteed TuxedoPanda) -> @out TuxedoPanda) -> TuxedoPanda
+
+  // CHECK: function_ref @$S17materializeForSet11TuxedoPandaVACIegyd_A2CIegnr_TR : $@convention(thin) (@in_guaranteed TuxedoPanda, @guaranteed @callee_guaranteed (TuxedoPanda) -> TuxedoPanda) -> @out TuxedoPanda
+
+  // CHECK: function_ref @$S17materializeForSet5PandaPAAE1xyxxcvs : $@convention(method) <τ_0_0 where τ_0_0 : Panda> (@owned @callee_guaranteed (@in_guaranteed τ_0_0) -> @out τ_0_0, @inout τ_0_0) -> ()
+
+// CHECK: }
+
+// CHECK-LABEL: sil private [transparent] [thunk] @$S17materializeForSet11TuxedoPandaVAA0E0A2aDP1xyxxcvmTW
+
+// Call the getter:
+
+  // CHECK: function_ref @$S17materializeForSet5PandaPAAE1xyxxcvg : $@convention(method) <τ_0_0 where τ_0_0 : Panda> (@in_guaranteed τ_0_0) -> @owned @callee_guaranteed (@in_guaranteed τ_0_0) -> @out τ_0_0
+
+// Result of calling the getter is re-abstracted to the maximally substituted type
+// by SILGenFunction::emitApply():
+
+  // CHECK: function_ref @$S17materializeForSet11TuxedoPandaVACIegnr_A2CIegyd_TR : $@convention(thin) (TuxedoPanda, @guaranteed @callee_guaranteed (@in_guaranteed TuxedoPanda) -> @out TuxedoPanda) -> TuxedoPanda
+
+// ... then we re-abstract to the requirement signature:
+// FIXME: Peephole this away with the previous one since there's actually no
+// abstraction change in this case.
+
+  // CHECK: function_ref @$S17materializeForSet11TuxedoPandaVACIegyd_A2CIegnr_TR : $@convention(thin) (@in_guaranteed TuxedoPanda, @guaranteed @callee_guaranteed (TuxedoPanda) -> TuxedoPanda) -> @out TuxedoPanda
+
+// The callback:
+
+  // CHECK: function_ref @$S17materializeForSet11TuxedoPandaVAA0E0A2aDP1xyxxcvmytfU_TW : $@convention(witness_method: Panda) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout TuxedoPanda, @thick TuxedoPanda.Type) -> ()
+
+// CHECK: }
+
+
+// Test for materializeForSet vs lazy properties of structs.
+
+struct LazyStructProperty {
+  lazy var cat: Int = 5
+}
+
+// CHECK-LABEL: sil hidden @$S17materializeForSet31inoutAccessOfLazyStructProperty1lyAA0ghI0Vz_tF
+// CHECK:   function_ref @$S17materializeForSet18LazyStructPropertyV3catSivg
+// CHECK:   function_ref @$S17materializeForSet18LazyStructPropertyV3catSivs
+func inoutAccessOfLazyStructProperty(l: inout LazyStructProperty) {
+  increment(&l.cat)
+}
+
+// Test for materializeForSet vs lazy properties of classes.
+
+// CHECK-LABEL: sil hidden [transparent] @$S17materializeForSet17LazyClassPropertyC3catSivm
+
+class LazyClassProperty {
+  lazy var cat: Int = 5
+}
+
+// CHECK-LABEL: sil hidden @$S17materializeForSet30inoutAccessOfLazyClassProperty1lyAA0ghI0Cz_tF
+// CHECK:    class_method {{.*}} : $LazyClassProperty, #LazyClassProperty.cat!materializeForSet.1
+func inoutAccessOfLazyClassProperty(l: inout LazyClassProperty) {
+  increment(&l.cat)
+}
+
+// Test for materializeForSet vs lazy properties of final classes.
+
+final class LazyFinalClassProperty {
+  lazy var cat: Int = 5
+}
+
+// CHECK-LABEL: sil hidden @$S17materializeForSet35inoutAccessOfLazyFinalClassProperty1lyAA0ghiJ0Cz_tF
+// CHECK:    function_ref @$S17materializeForSet22LazyFinalClassPropertyC3catSivg
+// CHECK:    function_ref @$S17materializeForSet22LazyFinalClassPropertyC3catSivs
+func inoutAccessOfLazyFinalClassProperty(l: inout LazyFinalClassProperty) {
+  increment(&l.cat)
+}
+
+// Make sure the below doesn't crash SILGen
+struct FooClosure {
+ var computed: (((Int) -> Int) -> Int)? {
+   get { return stored }
+   set {}
+ }
+ var stored: (((Int) -> Int) -> Int)? = nil
+}
+
+// CHECK-LABEL: $S17materializeForSet22testMaterializedSetteryyF
+func testMaterializedSetter() {
+  // CHECK: function_ref @$S17materializeForSet10FooClosureVACycfC
+  var f = FooClosure()
+  // CHECK: function_ref @$S17materializeForSet10FooClosureV8computedS3iXEcSgvg
+  // CHECK: function_ref @$S17materializeForSet10FooClosureV8computedS3iXEcSgvs
+  f.computed = f.computed
+}
+
+// CHECK-LABEL: sil_vtable DerivedForOverride {
+// CHECK:   #BaseForOverride.valueStored!getter.1: (BaseForOverride) -> () -> Int : @$S17materializeForSet07DerivedB8OverrideC11valueStoredSivg
+// CHECK:   #BaseForOverride.valueStored!setter.1: (BaseForOverride) -> (Int) -> () : @$S17materializeForSet07DerivedB8OverrideC11valueStoredSivs
+// CHECK:   #BaseForOverride.valueStored!materializeForSet.1: (BaseForOverride) -> (Builtin.RawPointer, inout Builtin.UnsafeValueBuffer) -> (Builtin.RawPointer, Builtin.RawPointer?) : @$S17materializeForSet07DerivedB8OverrideC11valueStoredSivm
+// CHECK:   #BaseForOverride.valueComputed!getter.1: (BaseForOverride) -> () -> Int : @$S17materializeForSet07DerivedB8OverrideC13valueComputedSivg
+// CHECK:   #BaseForOverride.valueComputed!setter.1: (BaseForOverride) -> (Int) -> () : @$S17materializeForSet07DerivedB8OverrideC13valueComputedSivs
+// CHECK:   #BaseForOverride.valueComputed!materializeForSet.1: (BaseForOverride) -> (Builtin.RawPointer, inout Builtin.UnsafeValueBuffer) -> (Builtin.RawPointer, Builtin.RawPointer?) : @$S17materializeForSet07DerivedB8OverrideC13valueComputedSivm
+// CHECK: }
+
+// CHECK-LABEL: sil_witness_table hidden Bill: Totalled module materializeForSet {
+// CHECK:   method #Totalled.total!getter.1: {{.*}} : @$S17materializeForSet4BillVAA8TotalledA2aDP5totalSivgTW
+// CHECK:   method #Totalled.total!setter.1: {{.*}} : @$S17materializeForSet4BillVAA8TotalledA2aDP5totalSivsTW
+// CHECK:   method #Totalled.total!materializeForSet.1: {{.*}} : @$S17materializeForSet4BillVAA8TotalledA2aDP5totalSivmTW
+// CHECK: }
diff --git a/test/SILGen/plus_zero_metatype_abstraction.swift b/test/SILGen/plus_zero_metatype_abstraction.swift
new file mode 100644
index 0000000..8dfa81f
--- /dev/null
+++ b/test/SILGen/plus_zero_metatype_abstraction.swift
@@ -0,0 +1,142 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership -module-name Swift -parse-stdlib %s | %FileCheck %s
+
+enum Optional<Wrapped> {
+  case none
+  case some(Wrapped)
+}
+
+struct S {}
+class C {}
+
+struct Generic<T> {
+  var value: T
+}
+
+struct GenericMetatype<T> {
+  var value: T.Type
+}
+
+// CHECK-LABEL: sil hidden @$Ss26genericMetatypeFromGeneric{{[_0-9a-zA-Z]*}}F
+// CHECK:         [[ADDR:%.*]] = struct_element_addr {{%.*}} : $*Generic<T.Type>, #Generic.value
+// CHECK:         [[META:%.*]] = load [trivial] [[ADDR]] : $*@thick T.Type
+// CHECK:         return [[META]] : $@thick T.Type
+// CHECK:       }
+func genericMetatypeFromGeneric<T>(_ x: Generic<T.Type>) -> T.Type {
+  var x = x
+  return x.value
+}
+// CHECK-LABEL: sil hidden @$Ss26dynamicMetatypeFromGeneric{{[_0-9a-zA-Z]*}}F
+// CHECK:         [[ADDR:%.*]] = struct_element_addr {{%.*}} : $*Generic<C.Type>, #Generic.value
+// CHECK:         [[META:%.*]] = load [trivial] [[ADDR]] : $*@thick C.Type
+// CHECK:         return [[META]] : $@thick C.Type
+// CHECK:       }
+func dynamicMetatypeFromGeneric(_ x: Generic<C.Type>) -> C.Type {
+  var x = x
+  return x.value
+}
+// CHECK-LABEL: sil hidden @$Ss25staticMetatypeFromGeneric{{[_0-9a-zA-Z]*}}F
+// CHECK:         [[META:%.*]] = metatype $@thin S.Type
+// CHECK:         return [[META]] : $@thin S.Type
+// CHECK:       }
+func staticMetatypeFromGeneric(_ x: Generic<S.Type>) -> S.Type {
+  return x.value
+}
+
+// CHECK-LABEL: sil hidden @$Ss026genericMetatypeFromGenericB0{{[_0-9a-zA-Z]*}}F
+// CHECK:         [[ADDR:%.*]] = struct_element_addr {{%.*}} : $*GenericMetatype<T>, #GenericMetatype.value
+// CHECK:         [[META:%.*]] = load [trivial] [[ADDR]] : $*@thick T.Type
+// CHECK:         return [[META]] : $@thick T.Type
+// CHECK:       }
+func genericMetatypeFromGenericMetatype<T>(_ x: GenericMetatype<T>)-> T.Type {
+  var x = x
+  return x.value
+}
+// CHECK-LABEL: sil hidden @$Ss026dynamicMetatypeFromGenericB0ys1CCms0dB0VyACGF
+// CHECK:         [[XBOX:%[0-9]+]] = alloc_box ${ var GenericMetatype<C> }
+// CHECK:         [[PX:%[0-9]+]] = project_box [[XBOX]]
+// CHECK:         [[READ:%.*]] = begin_access [read] [unknown] [[PX]] : $*GenericMetatype<C>
+// CHECK:         [[ADDR:%.*]] = struct_element_addr [[READ]] : $*GenericMetatype<C>, #GenericMetatype.value
+// CHECK:         [[META:%.*]] = load [trivial] [[ADDR]] : $*@thick C.Type
+// CHECK:         return [[META]] : $@thick C.Type
+// CHECK:       }
+func dynamicMetatypeFromGenericMetatype(_ x: GenericMetatype<C>) -> C.Type {
+  var x = x
+  return x.value
+}
+
+func takeGeneric<T>(_ x: T) {}
+func takeGenericMetatype<T>(_ x: T.Type) {}
+
+// CHECK-LABEL: sil hidden @$Ss23staticMetatypeToGeneric{{[_0-9a-zA-Z]*}}F
+// CHECK:         [[MAT:%.*]] = alloc_stack $@thick S.Type
+// CHECK:         [[META:%.*]] = metatype $@thick S.Type
+// CHECK:         store [[META]] to [trivial] [[MAT]] : $*@thick S.Type
+// CHECK:         apply {{%.*}}<S.Type>([[MAT]])
+func staticMetatypeToGeneric(_ x: S.Type) {
+  takeGeneric(x)
+}
+// CHECK-LABEL: sil hidden @$Ss023staticMetatypeToGenericB0{{[_0-9a-zA-Z]*}}F
+// CHECK:         [[META:%.*]] = metatype $@thick S.Type
+// CHECK:         apply {{%.*}}<S>([[META]])
+func staticMetatypeToGenericMetatype(_ x: S.Type) {
+  takeGenericMetatype(x)
+}
+// CHECK-LABEL: sil hidden @$Ss24dynamicMetatypeToGeneric{{[_0-9a-zA-Z]*}}F
+// CHECK:         [[MAT:%.*]] = alloc_stack $@thick C.Type
+// CHECK:         apply {{%.*}}<C.Type>([[MAT]]) : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> ()
+func dynamicMetatypeToGeneric(_ x: C.Type) {
+  var x = x
+  takeGeneric(x)
+}
+// CHECK-LABEL: sil hidden @$Ss024dynamicMetatypeToGenericB0yys1CCmF
+// CHECK:         [[XBOX:%[0-9]+]] = alloc_box ${ var @thick C.Type }
+// CHECK:         [[PX:%[0-9]+]] = project_box [[XBOX]]
+// CHECK:         [[READ:%.*]] = begin_access [read] [unknown] [[PX]] : $*@thick C.Type
+// CHECK:         [[META:%.*]] = load [trivial] [[READ]] : $*@thick C.Type
+// CHECK:         apply {{%.*}}<C>([[META]]) : $@convention(thin) <τ_0_0> (@thick τ_0_0.Type) -> ()
+func dynamicMetatypeToGenericMetatype(_ x: C.Type) {
+  var x = x
+  takeGenericMetatype(x)
+}
+// CHECK-LABEL: sil hidden @$Ss24genericMetatypeToGeneric{{[_0-9a-zA-Z]*}}F
+// CHECK:         [[MAT:%.*]] = alloc_stack $@thick U.Type
+// CHECK:         apply {{%.*}}<U.Type>([[MAT]]) : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> ()
+func genericMetatypeToGeneric<U>(_ x: U.Type) {
+  var x = x
+  takeGeneric(x)
+}
+func genericMetatypeToGenericMetatype<U>(_ x: U.Type) {
+  takeGenericMetatype(x)
+}
+
+// CHECK-LABEL: sil hidden @$Ss019static_metatype_of_B0ys1SVmmACF
+// CHECK:         metatype $@thin S.Type.Type
+func static_metatype_of_metatype(_ x: S) -> S.Type.Type {
+  return type(of: type(of: x))
+}
+
+// CHECK-LABEL: sil hidden @$Ss018class_metatype_of_B0ys1CCmmACF
+// CHECK:         [[METATYPE:%.*]] = value_metatype $@thick C.Type
+// CHECK:         [[META_METATYPE:%.*]] = value_metatype $@thick C.Type.Type, [[METATYPE]]
+func class_metatype_of_metatype(_ x: C) -> C.Type.Type {
+  return type(of: type(of: x))
+}
+
+// CHECK-LABEL: sil hidden @$Ss020generic_metatype_of_B0{{[_0-9a-zA-Z]*}}F
+// CHECK:         [[METATYPE:%.*]] = value_metatype $@thick T.Type
+// CHECK:         [[META_METATYPE:%.*]] = value_metatype $@thick T.Type.Type, [[METATYPE]]
+func generic_metatype_of_metatype<T>(_ x: T) -> T.Type.Type {
+  return type(of: type(of: x))
+}
+
+// FIXME rdar://problem/18419772
+/*
+func existential_metatype_of_metatype(_ x: Any) -> Any.Type.Type {
+ return type(of: type(of: x))
+}
+ */
+
+func function_metatype_of_metatype(_ x: @escaping () -> ()) -> (() -> ()).Type.Type {
+  return type(of: type(of: x))
+}
diff --git a/test/SILGen/plus_zero_multi_file.swift b/test/SILGen/plus_zero_multi_file.swift
new file mode 100644
index 0000000..aaccbcc
--- /dev/null
+++ b/test/SILGen/plus_zero_multi_file.swift
@@ -0,0 +1,53 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership -primary-file %s %S/Inputs/multi_file_helper.swift | %FileCheck %s
+
+func markUsed<T>(_ t: T) {}
+
+// CHECK-LABEL: sil hidden @$S10multi_file12rdar16016713{{[_0-9a-zA-Z]*}}F
+func rdar16016713(_ r: Range) {
+  // CHECK: [[LIMIT:%[0-9]+]] = function_ref @$S10multi_file5RangeV5limitSivg : $@convention(method) (Range) -> Int
+  // CHECK: {{%[0-9]+}} = apply [[LIMIT]]({{%[0-9]+}}) : $@convention(method) (Range) -> Int
+  markUsed(r.limit)
+}
+
+// CHECK-LABEL: sil hidden @$S10multi_file26lazyPropertiesAreNotStored{{[_0-9a-zA-Z]*}}F
+func lazyPropertiesAreNotStored(_ container: LazyContainer) {
+  var container = container
+  // CHECK: {{%[0-9]+}} = function_ref @$S10multi_file13LazyContainerV7lazyVarSivg : $@convention(method) (@inout LazyContainer) -> Int
+  markUsed(container.lazyVar)
+}
+
+// CHECK-LABEL: sil hidden @$S10multi_file29lazyRefPropertiesAreNotStored{{[_0-9a-zA-Z]*}}F
+func lazyRefPropertiesAreNotStored(_ container: LazyContainerClass) {
+  // CHECK: bb0([[ARG:%.*]] : @guaranteed $LazyContainerClass):
+  // CHECK:   {{%[0-9]+}} = class_method [[ARG]] : $LazyContainerClass, #LazyContainerClass.lazyVar!getter.1 : (LazyContainerClass) -> () -> Int, $@convention(method) (@guaranteed LazyContainerClass) -> Int
+  markUsed(container.lazyVar)
+}
+
+// CHECK-LABEL: sil hidden @$S10multi_file25finalVarsAreDevirtualizedyyAA18FinalPropertyClassCF
+func finalVarsAreDevirtualized(_ obj: FinalPropertyClass) {
+  // CHECK: bb0([[ARG:%.*]] : @guaranteed $FinalPropertyClass):
+  // CHECK:   ref_element_addr [[ARG]] : $FinalPropertyClass, #FinalPropertyClass.foo
+  markUsed(obj.foo)
+  // CHECK: class_method [[ARG]] : $FinalPropertyClass, #FinalPropertyClass.bar!getter.1
+  markUsed(obj.bar)
+}
+
+// rdar://18448869
+// CHECK-LABEL: sil hidden @$S10multi_file34finalVarsDontNeedMaterializeForSetyyAA27ObservingPropertyFinalClassCF
+func finalVarsDontNeedMaterializeForSet(_ obj: ObservingPropertyFinalClass) {
+  obj.foo += 1
+  // CHECK: function_ref @$S10multi_file27ObservingPropertyFinalClassC3fooSivg
+  // CHECK: function_ref @$S10multi_file27ObservingPropertyFinalClassC3fooSivs
+}
+
+// rdar://18503960
+// Ensure that we type-check the materializeForSet accessor from the protocol.
+class HasComputedProperty: ProtocolWithProperty {
+  var foo: Int {
+    get { return 1 }
+    set {}
+  }
+}
+// CHECK-LABEL: sil hidden [transparent] @$S10multi_file19HasComputedPropertyC3fooSivm : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @guaranteed HasComputedProperty) -> (Builtin.RawPointer, Optional<Builtin.RawPointer>) {
+// CHECK-LABEL: sil private [transparent] [thunk] @$S10multi_file19HasComputedPropertyCAA012ProtocolWithE0A2aDP3fooSivmTW : $@convention(witness_method: ProtocolWithProperty) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout HasComputedProperty) -> (Builtin.RawPointer, Optional<Builtin.RawPointer>) {
diff --git a/test/SILGen/plus_zero_nested_generics.swift b/test/SILGen/plus_zero_nested_generics.swift
new file mode 100644
index 0000000..32abb9f
--- /dev/null
+++ b/test/SILGen/plus_zero_nested_generics.swift
@@ -0,0 +1,261 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -enable-sil-ownership -Xllvm -sil-full-demangle -emit-silgen  -parse-as-library %s | %FileCheck %s
+// RUN: %target-swift-frontend -enable-sil-ownership -Xllvm -sil-full-demangle -emit-sil -parse-as-library %s > /dev/null
+// RUN: %target-swift-frontend -enable-sil-ownership -Xllvm -sil-full-demangle -emit-sil -O -parse-as-library %s > /dev/null
+// RUN: %target-swift-frontend -enable-sil-ownership -Xllvm -sil-full-demangle -emit-ir -parse-as-library %s > /dev/null
+
+// TODO:
+// - test generated SIL -- mostly we're just testing mangling here
+// - class_method calls
+// - witness_method calls
+// - inner generic parameters on protocol requirements
+// - generic parameter list on method in nested type
+// - types nested inside unconstrained extensions of generic types
+
+protocol Pizza : class {
+  associatedtype Topping
+}
+
+protocol HotDog {
+  associatedtype Condiment
+}
+
+protocol CuredMeat {}
+
+// Generic nested inside generic
+
+struct Lunch<T : Pizza> where T.Topping : CuredMeat {
+  struct Dinner<U : HotDog> where U.Condiment == Deli<Pepper>.Mustard {
+    let firstCourse: T
+    let secondCourse: U?
+
+    var leftovers: T
+    var transformation: (T) -> U
+
+    func coolCombination(t: T.Topping, u: U.Condiment) {
+      func nestedGeneric<X, Y>(x: X, y: Y) -> (X, Y) {
+        return (x, y)
+      }
+      _ = nestedGeneric(x: t, y: u)
+    }
+  }
+}
+
+// CHECK-LABEL: // nested_generics.Lunch.Dinner.coolCombination(t: A.Topping, u: nested_generics.Deli<nested_generics.Pepper>.Mustard) -> ()
+// CHECK-LABEL: sil hidden @$S15nested_generics5LunchV6DinnerV15coolCombination1t1uy7ToppingQz_AA4DeliC7MustardOyAA6PepperV_GtF : $@convention(method) <T where T : Pizza, T.Topping : CuredMeat><U where U : HotDog, U.Condiment == Deli<Pepper>.Mustard> (@in_guaranteed T.Topping, Deli<Pepper>.Mustard, @in_guaranteed Lunch<T>.Dinner<U>) -> ()
+
+// CHECK-LABEL: // nestedGeneric #1 <A><A1><A2, B2 where A: nested_generics.Pizza, A1: nested_generics.HotDog, A.Topping: nested_generics.CuredMeat, A1.Condiment == nested_generics.Deli<nested_generics.Pepper>.Mustard>(x: A2, y: B2) -> (A2, B2) in nested_generics.Lunch.Dinner.coolCombination(t: A.Topping, u: nested_generics.Deli<nested_generics.Pepper>.Mustard) -> ()
+// CHECK-LABEL: sil private @$S15nested_generics5LunchV6DinnerV15coolCombination1t1uy7ToppingQz_AA4DeliC7MustardOyAA6PepperV_GtF0A7GenericL_1x1yqd0___qd0_0_tqd0___qd0_0_tAA5PizzaRzAA6HotDogRd__AA9CuredMeatAJRQAQ9CondimentRtd__r__0_lF : $@convention(thin) <T where T : Pizza, T.Topping : CuredMeat><U where U : HotDog, U.Condiment == Deli<Pepper>.Mustard><X, Y> (@in_guaranteed X, @in_guaranteed Y) -> (@out X, @out Y)
+
+// CHECK-LABEL: // nested_generics.Lunch.Dinner.init(firstCourse: A, secondCourse: Swift.Optional<A1>, leftovers: A, transformation: (A) -> A1) -> nested_generics.Lunch<A>.Dinner<A1>
+// CHECK-LABEL: sil hidden @$S15nested_generics5LunchV6DinnerV11firstCourse06secondF09leftovers14transformationAEyx_qd__Gx_qd__Sgxqd__xctcfC : $@convention(method) <T where T : Pizza, T.Topping : CuredMeat><U where U : HotDog, U.Condiment == Deli<Pepper>.Mustard> (@owned T, @in Optional<U>, @owned T, @owned @callee_guaranteed (@guaranteed T) -> @out U, @thin Lunch<T>.Dinner<U>.Type) -> @out Lunch<T>.Dinner<U>
+
+// Non-generic nested inside generic
+
+class Deli<Spices> : CuredMeat {
+
+  class Pepperoni : CuredMeat {}
+  struct Sausage : CuredMeat {}
+
+  enum Mustard {
+    case Yellow
+    case Dijon
+    case DeliStyle(Spices)
+  }
+}
+
+// CHECK-LABEL: // nested_generics.Deli.Pepperoni.init() -> nested_generics.Deli<A>.Pepperoni
+// CHECK-LABEL: sil hidden @$S15nested_generics4DeliC9PepperoniCAEyx_Gycfc : $@convention(method) <Spices> (@owned Deli<Spices>.Pepperoni) -> @owned Deli<Spices>.Pepperoni
+
+// Typealiases referencing outer generic parameters
+
+struct Pizzas<Spices> {
+  class NewYork : Pizza {
+    typealias Topping = Deli<Spices>.Pepperoni
+  }
+
+  class DeepDish : Pizza {
+    typealias Topping = Deli<Spices>.Sausage
+  }
+}
+
+class HotDogs {
+  struct Bratwurst : HotDog {
+    typealias Condiment = Deli<Pepper>.Mustard
+  }
+  struct American : HotDog {
+    typealias Condiment = Deli<Pepper>.Mustard
+  }
+}
+
+// Local type in extension of type in another module
+extension String {
+  func foo() {
+    // CHECK-LABEL: // init(material: A) -> Cheese #1 in (extension in nested_generics):Swift.String.foo() -> ()<A> in Cheese #1 in (extension in nested_generics):Swift.String.foo() -> ()
+    // CHECK-LABEL: sil private @$SSS15nested_genericsE3fooyyF6CheeseL_V8materialADyxGx_tcfC
+    struct Cheese<Milk> {
+      let material: Milk
+    }
+    let _ = Cheese(material: "cow")
+  }
+}
+
+// Local type in extension of type in same module
+extension HotDogs {
+  func applyRelish() {
+    // CHECK-LABEL: // init(material: A) -> Relish #1 in nested_generics.HotDogs.applyRelish() -> ()<A> in Relish #1 in nested_generics.HotDogs.applyRelish() -> ()
+    // CHECK-LABEL: sil private @$S15nested_generics7HotDogsC11applyRelishyyF0F0L_V8materialAFyxGx_tcfC
+
+    struct Relish<Material> {
+      let material: Material
+    }
+    let _ = Relish(material: "pickles")
+  }
+}
+
+struct Pepper {}
+struct ChiliFlakes {}
+
+// CHECK-LABEL: // nested_generics.eatDinnerGeneric<A, B where A: nested_generics.Pizza, B: nested_generics.HotDog, A.Topping: nested_generics.CuredMeat, B.Condiment == nested_generics.Deli<nested_generics.Pepper>.Mustard>(d: inout nested_generics.Lunch<A>.Dinner<B>, t: A.Topping, u: nested_generics.Deli<nested_generics.Pepper>.Mustard) -> ()
+// CHECK-LABEL: sil hidden @$S15nested_generics16eatDinnerGeneric1d1t1uyAA5LunchV0D0Vyx_q_Gz_7ToppingQzAA4DeliC7MustardOyAA6PepperV_GtAA5PizzaRzAA6HotDogR_AA9CuredMeatALRQAS9CondimentRt_r0_lF : $@convention(thin) <T, U where T : Pizza, U : HotDog, T.Topping : CuredMeat, U.Condiment == Deli<Pepper>.Mustard> (@inout Lunch<T>.Dinner<U>, @in_guaranteed T.Topping, Deli<Pepper>.Mustard) -> ()
+
+func eatDinnerGeneric<T, U>(d: inout Lunch<T>.Dinner<U>, t: T.Topping, u: U.Condiment) {
+  // Method call
+  _ = d.coolCombination(t: t, u: u)
+
+  // Read a let, store into var
+  d.leftovers = d.firstCourse
+
+  // Read a var
+  let _ = d.secondCourse
+
+  // Call property of function type
+  _ = d.transformation(d.leftovers)
+}
+
+// Overloading concrete function with different bound generic arguments in parent type
+
+// CHECK-LABEL: // nested_generics.eatDinnerConcrete(d: inout nested_generics.Lunch<nested_generics.Pizzas<nested_generics.ChiliFlakes>.NewYork>.Dinner<nested_generics.HotDogs.American>, t: nested_generics.Deli<nested_generics.ChiliFlakes>.Pepperoni, u: nested_generics.Deli<nested_generics.Pepper>.Mustard) -> ()
+// CHECK-LABEL: sil hidden @$S15nested_generics17eatDinnerConcrete1d1t1uyAA5LunchV0D0VyAA6PizzasV7NewYorkCyAA11ChiliFlakesV_G_AA7HotDogsC8AmericanVGz_AA4DeliC9PepperoniCyAO_GAW7MustardOyAA6PepperV_GtF : $@convention(thin) (@inout Lunch<Pizzas<ChiliFlakes>.NewYork>.Dinner<HotDogs.American>, @guaranteed Deli<ChiliFlakes>.Pepperoni, Deli<Pepper>.Mustard) -> ()
+
+func eatDinnerConcrete(d: inout Lunch<Pizzas<ChiliFlakes>.NewYork>.Dinner<HotDogs.American>,
+                       t: Deli<ChiliFlakes>.Pepperoni,
+                       u: Deli<Pepper>.Mustard) {
+  // Method call
+  _ = d.coolCombination(t: t, u: u)
+
+  // Read a let, store into var
+  d.leftovers = d.firstCourse
+
+  // Read a var
+  let _ = d.secondCourse
+
+  // Call property of function type
+  _ = d.transformation(d.leftovers)
+}
+
+// CHECK-LABEL: // reabstraction thunk helper from @escaping @callee_guaranteed (@guaranteed nested_generics.Pizzas<nested_generics.ChiliFlakes>.NewYork) -> (@out nested_generics.HotDogs.American) to @escaping @callee_guaranteed (@guaranteed nested_generics.Pizzas<nested_generics.ChiliFlakes>.NewYork) -> (@unowned nested_generics.HotDogs.American)
+// CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] @$S15nested_generics6PizzasV7NewYorkCyAA11ChiliFlakesV_GAA7HotDogsC8AmericanVIeggr_AhLIeggd_TR : $@convention(thin) (@guaranteed Pizzas<ChiliFlakes>.NewYork, @guaranteed @callee_guaranteed (@guaranteed Pizzas<ChiliFlakes>.NewYork) -> @out HotDogs.American) -> HotDogs.American
+
+// CHECK-LABEL: // nested_generics.eatDinnerConcrete(d: inout nested_generics.Lunch<nested_generics.Pizzas<nested_generics.Pepper>.NewYork>.Dinner<nested_generics.HotDogs.American>, t: nested_generics.Deli<nested_generics.Pepper>.Pepperoni, u: nested_generics.Deli<nested_generics.Pepper>.Mustard) -> ()
+// CHECK-LABEL: sil hidden @$S15nested_generics17eatDinnerConcrete1d1t1uyAA5LunchV0D0VyAA6PizzasV7NewYorkCyAA6PepperV_G_AA7HotDogsC8AmericanVGz_AA4DeliC9PepperoniCyAO_GAW7MustardOyAO_GtF : $@convention(thin) (@inout Lunch<Pizzas<Pepper>.NewYork>.Dinner<HotDogs.American>, @guaranteed Deli<Pepper>.Pepperoni, Deli<Pepper>.Mustard) -> ()
+
+func eatDinnerConcrete(d: inout Lunch<Pizzas<Pepper>.NewYork>.Dinner<HotDogs.American>,
+                       t: Deli<Pepper>.Pepperoni,
+                       u: Deli<Pepper>.Mustard) {
+  // Method call
+  _ = d.coolCombination(t: t, u: u)
+
+  // Read a let, store into var
+  d.leftovers = d.firstCourse
+
+  // Read a var
+  let _ = d.secondCourse
+
+  // Call property of function type
+  _ = d.transformation(d.leftovers)
+}
+
+// CHECK-LABEL: // reabstraction thunk helper from @escaping @callee_guaranteed (@guaranteed nested_generics.Pizzas<nested_generics.Pepper>.NewYork) -> (@out nested_generics.HotDogs.American) to @escaping @callee_guaranteed (@guaranteed nested_generics.Pizzas<nested_generics.Pepper>.NewYork) -> (@unowned nested_generics.HotDogs.American)
+// CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] @$S15nested_generics6PizzasV7NewYorkCyAA6PepperV_GAA7HotDogsC8AmericanVIeggr_AhLIeggd_TR : $@convention(thin) (@guaranteed Pizzas<Pepper>.NewYork, @guaranteed @callee_guaranteed (@guaranteed Pizzas<Pepper>.NewYork) -> @out HotDogs.American) -> HotDogs.American
+
+// CHECK-LABEL: // closure #1 (nested_generics.Pizzas<nested_generics.Pepper>.NewYork) -> nested_generics.HotDogs.American in nested_generics.calls() -> ()
+// CHECK-LABEL: sil private @$S15nested_generics5callsyyFAA7HotDogsC8AmericanVAA6PizzasV7NewYorkCyAA6PepperV_GcfU_ : $@convention(thin) (@guaranteed Pizzas<Pepper>.NewYork) -> HotDogs.American
+
+func calls() {
+
+  let firstCourse = Pizzas<Pepper>.NewYork()
+  let secondCourse = HotDogs.American()
+
+  var dinner = Lunch<Pizzas<Pepper>.NewYork>.Dinner<HotDogs.American>(
+      firstCourse: firstCourse,
+      secondCourse: secondCourse,
+      leftovers: firstCourse,
+      transformation: { _ in HotDogs.American() })
+
+  let topping = Deli<Pepper>.Pepperoni()
+
+  let condiment1 = Deli<Pepper>.Mustard.Dijon
+  let condiment2 = Deli<Pepper>.Mustard.DeliStyle(Pepper())
+
+  eatDinnerGeneric(d: &dinner, t: topping, u: condiment1)
+  eatDinnerConcrete(d: &dinner, t: topping, u: condiment2)
+
+}
+
+protocol ProtocolWithGenericRequirement {
+  associatedtype T
+  associatedtype U
+  func method<V>(t: T, u: U, v: V) -> (T, U, V)
+}
+
+class OuterRing<T> {
+  class InnerRing<U> : ProtocolWithGenericRequirement {
+    func method<V>(t: T, u: U, v: V) -> (T, U, V) {
+      return (t, u, v)
+    }
+  }
+}
+
+class SubclassOfInner<T, U> : OuterRing<T>.InnerRing<U> {
+  override func method<V>(t: T, u: U, v: V) -> (T, U, V) {
+    return super.method(t: t, u: u, v: v)
+  }
+}
+
+// CHECK-LABEL: // reabstraction thunk helper from @escaping @callee_guaranteed (@guaranteed nested_generics.Pizzas<nested_generics.Pepper>.NewYork) -> (@unowned nested_generics.HotDogs.American) to @escaping @callee_guaranteed (@guaranteed nested_generics.Pizzas<nested_generics.Pepper>.NewYork) -> (@out nested_generics.HotDogs.American)
+// CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] @$S15nested_generics6PizzasV7NewYorkCyAA6PepperV_GAA7HotDogsC8AmericanVIeggd_AhLIeggr_TR : $@convention(thin) (@guaranteed Pizzas<Pepper>.NewYork, @guaranteed @callee_guaranteed (@guaranteed Pizzas<Pepper>.NewYork) -> HotDogs.American) -> @out HotDogs.American
+
+// CHECK-LABEL: sil private [transparent] [thunk] @$S15nested_generics9OuterRingC05InnerD0Cyx_qd__GAA30ProtocolWithGenericRequirementA2aGP6method1t1u1v1TQz_1UQzqd__tAN_APqd__tlFTW : $@convention(witness_method: ProtocolWithGenericRequirement) <τ_0_0><τ_1_0><τ_2_0> (@in_guaranteed τ_0_0, @in_guaranteed τ_1_0, @in_guaranteed τ_2_0, @in_guaranteed OuterRing<τ_0_0>.InnerRing<τ_1_0>) -> (@out τ_0_0, @out τ_1_0, @out τ_2_0) {
+// CHECK: bb0([[T:%[0-9]+]] : @trivial $*τ_0_0, [[U:%[0-9]+]] : @trivial $*τ_1_0, [[V:%[0-9]+]] : @trivial $*τ_2_0, [[TOut:%[0-9]+]] : @trivial $*τ_0_0, [[UOut:%[0-9]+]] : @trivial $*τ_1_0, [[VOut:%[0-9]+]] : @trivial $*τ_2_0, [[SELF:%[0-9]+]] : @trivial $*OuterRing<τ_0_0>.InnerRing<τ_1_0>):
+// CHECK:   [[SELF_COPY_VAL:%[0-9]+]] = load_borrow [[SELF]] : $*OuterRing<τ_0_0>.InnerRing<τ_1_0>
+// CHECK:   [[METHOD:%[0-9]+]] = class_method [[SELF_COPY_VAL]] : $OuterRing<τ_0_0>.InnerRing<τ_1_0>, #OuterRing.InnerRing.method!1 : <T><U><V> (OuterRing<T>.InnerRing<U>) -> (T, U, V) -> (T, U, V), $@convention(method) <τ_0_0><τ_1_0><τ_2_0> (@in_guaranteed τ_0_0, @in_guaranteed τ_1_0, @in_guaranteed τ_2_0, @guaranteed OuterRing<τ_0_0>.InnerRing<τ_1_0>) -> (@out τ_0_0, @out τ_1_0, @out τ_2_0)
+// CHECK:   apply [[METHOD]]<τ_0_0, τ_1_0, τ_2_0>([[T]], [[U]], [[V]], [[TOut]], [[UOut]], [[VOut]], [[SELF_COPY_VAL]]) : $@convention(method) <τ_0_0><τ_1_0><τ_2_0> (@in_guaranteed τ_0_0, @in_guaranteed τ_1_0, @in_guaranteed τ_2_0, @guaranteed OuterRing<τ_0_0>.InnerRing<τ_1_0>) -> (@out τ_0_0, @out τ_1_0, @out τ_2_0)
+// CHECK:   [[RESULT:%[0-9]+]] = tuple ()
+// CHECK:   end_borrow [[SELF_COPY_VAL]] from [[SELF]]
+// CHECK:   return [[RESULT]] : $()
+
+// CHECK: sil_witness_table hidden <Spices> Deli<Spices>.Pepperoni: CuredMeat module nested_generics {
+// CHECK: }
+
+// CHECK: sil_witness_table hidden <Spices> Deli<Spices>.Sausage: CuredMeat module nested_generics {
+// CHECK: }
+
+// CHECK: sil_witness_table hidden <Spices> Deli<Spices>: CuredMeat module nested_generics {
+// CHECK: }
+
+// CHECK: sil_witness_table hidden <Spices> Pizzas<Spices>.NewYork: Pizza module nested_generics {
+// CHECK:   associated_type Topping: Deli<Spices>.Pepperoni
+// CHECK: }
+
+// CHECK: sil_witness_table hidden <Spices> Pizzas<Spices>.DeepDish: Pizza module nested_generics {
+// CHECK:   associated_type Topping: Deli<Spices>.Sausage
+// CHECK: }
+
+// CHECK: sil_witness_table hidden HotDogs.Bratwurst: HotDog module nested_generics {
+// CHECK:   associated_type Condiment: Deli<Pepper>.Mustard
+// CHECK: }
+
+// CHECK: sil_witness_table hidden HotDogs.American: HotDog module nested_generics {
+// CHECK:   associated_type Condiment: Deli<Pepper>.Mustard
+// CHECK: }
diff --git a/test/SILGen/plus_zero_nested_types_referencing_nested_functions.swift b/test/SILGen/plus_zero_nested_types_referencing_nested_functions.swift
new file mode 100644
index 0000000..a0aa92e
--- /dev/null
+++ b/test/SILGen/plus_zero_nested_types_referencing_nested_functions.swift
@@ -0,0 +1,34 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership %s | %FileCheck %s
+
+do {
+  func foo() { bar(2) }
+  func bar<T>(_: T) { foo() }
+
+  class Foo {
+    // CHECK-LABEL: sil private @$S025nested_types_referencing_A10_functions3FooL_CACycfc : $@convention(method) (@owned Foo) -> @owned Foo {
+    init() {
+      foo()
+    }
+    // CHECK-LABEL: sil private @$S025nested_types_referencing_A10_functions3FooL_C3zimyyF : $@convention(method) (@guaranteed Foo) -> ()
+    func zim() {
+      foo()
+    }
+    // CHECK-LABEL: sil private @$S025nested_types_referencing_A10_functions3FooL_C4zangyyxlF : $@convention(method) <T> (@in_guaranteed T, @guaranteed Foo) -> ()
+    func zang<T>(_ x: T) {
+      bar(x)
+    }
+    // CHECK-LABEL: sil private @$S025nested_types_referencing_A10_functions3FooL_CfD : $@convention(method) (@owned Foo) -> ()
+    deinit {
+      foo()
+    }
+  }
+
+  let x = Foo()
+  x.zim()
+  x.zang(1)
+  _ = Foo.zim
+  _ = Foo.zang as (Foo) -> (Int) -> ()
+  _ = x.zim
+  _ = x.zang as (Int) -> ()
+}
diff --git a/test/SILGen/plus_zero_newtype.swift b/test/SILGen/plus_zero_newtype.swift
new file mode 100644
index 0000000..778e1bb
--- /dev/null
+++ b/test/SILGen/plus_zero_newtype.swift
@@ -0,0 +1,86 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -emit-silgen -sdk %S/Inputs -I %S/Inputs -enable-source-import  %s | %FileCheck %s -check-prefix=CHECK-RAW
+
+// RUN: %target-swift-frontend -emit-sil -sdk %S/Inputs -I %S/Inputs -enable-source-import  %s | %FileCheck %s -check-prefix=CHECK-CANONICAL
+
+// REQUIRES: objc_interop
+
+import Newtype
+
+// CHECK-CANONICAL-LABEL: sil hidden @$S7newtype17createErrorDomain{{[_0-9a-zA-Z]*}}F
+// CHECK-CANONICAL: bb0([[STR:%[0-9]+]] : $String)
+func createErrorDomain(str: String) -> ErrorDomain {
+  // CHECK-CANONICAL: [[BRIDGE_FN:%[0-9]+]] = function_ref @{{.*}}_bridgeToObjectiveC
+  // CHECK-CANONICAL-NEXT: [[BRIDGED:%[0-9]+]] = apply [[BRIDGE_FN]]([[STR]])
+  // CHECK-CANONICAL: struct $ErrorDomain ([[BRIDGED]] : $NSString)
+  return ErrorDomain(rawValue: str)
+}
+
+// CHECK-RAW-LABEL: sil shared [transparent] [serializable] @$SSo14SNTErrorDomaina8rawValueABSS_tcfC
+// CHECK-RAW: bb0([[STR:%[0-9]+]] : $String,
+// CHECK-RAW: [[SELF_BOX:%[0-9]+]] = alloc_box ${ var ErrorDomain }, var, name "self"
+// CHECK-RAW: [[MARKED_SELF_BOX:%[0-9]+]] = mark_uninitialized [rootself] [[SELF_BOX]]
+// CHECK-RAW: [[PB_BOX:%[0-9]+]] = project_box [[MARKED_SELF_BOX]]
+// CHECK-RAW: [[BORROWED_STR:%.*]] = begin_borrow [[STR]]
+// CHECK-RAW: [[COPIED_STR:%.*]] = copy_value [[BORROWED_STR]]
+// CHECK-RAW: [[BRIDGE_FN:%[0-9]+]] = function_ref @{{.*}}_bridgeToObjectiveC
+// CHECK-RAW: [[BORROWED_COPIED_STR:%.*]] = begin_borrow [[COPIED_STR]]
+// CHECK-RAW: [[BRIDGED:%[0-9]+]] = apply [[BRIDGE_FN]]([[BORROWED_COPIED_STR]])
+// CHECK-RAW: [[WRITE:%.*]] = begin_access [modify] [unknown] [[PB_BOX]]
+// CHECK-RAW: [[RAWVALUE_ADDR:%[0-9]+]] = struct_element_addr [[WRITE]]
+// CHECK-RAW: assign [[BRIDGED]] to [[RAWVALUE_ADDR]]
+// CHECK-RAW: end_borrow [[BORROWED_COPIED_STR]] from [[COPIED_STR]]
+// CHECK-RAW: end_borrow [[BORROWED_STR]] from [[STR]]
+
+func getRawValue(ed: ErrorDomain) -> String {
+  return ed.rawValue
+}
+
+// CHECK-RAW-LABEL: sil shared [serializable] @$SSo14SNTErrorDomaina8rawValueSSvg
+// CHECK-RAW: bb0([[SELF:%[0-9]+]] : $ErrorDomain):
+// CHECK-RAW: [[STORED_VALUE:%[0-9]+]] = struct_extract [[SELF]] : $ErrorDomain, #ErrorDomain._rawValue
+// CHECK-RAW: [[STORED_VALUE_COPY:%.*]] = copy_value [[STORED_VALUE]]
+// CHECK-RAW: [[BRIDGE_FN:%[0-9]+]] = function_ref @$SSS10FoundationE36_unconditionallyBridgeFromObjectiveCySSSo8NSStringCSgFZ
+// CHECK-RAW: [[OPT_STORED_VALUE_COPY:%.*]] = enum $Optional<NSString>, #Optional.some!enumelt.1, [[STORED_VALUE_COPY]]
+// CHECK-RAW: [[STRING_META:%[0-9]+]] = metatype $@thin String.Type
+// CHECK-RAW: [[STRING_RESULT:%[0-9]+]] = apply [[BRIDGE_FN]]([[OPT_STORED_VALUE_COPY]], [[STRING_META]])
+// CHECK-RAW: return [[STRING_RESULT]]
+
+class ObjCTest {
+  // CHECK-RAW-LABEL: sil hidden @$S7newtype8ObjCTestC19optionalPassThroughySo14SNTErrorDomainaSgAGF : $@convention(method) (@guaranteed Optional<ErrorDomain>, @guaranteed ObjCTest) -> @owned Optional<ErrorDomain> {
+  // CHECK-RAW: sil hidden [thunk] @$S7newtype8ObjCTestC19optionalPassThroughySo14SNTErrorDomainaSgAGFTo : $@convention(objc_method) (Optional<ErrorDomain>, ObjCTest) -> Optional<ErrorDomain> {
+  @objc func optionalPassThrough(_ ed: ErrorDomain?) -> ErrorDomain? {
+    return ed
+  }  
+
+  // CHECK-RAW-LABEL: sil hidden @$S7newtype8ObjCTestC18integerPassThroughySo5MyIntaAFF : $@convention(method) (MyInt, @guaranteed ObjCTest) -> MyInt {
+  // CHECK-RAW: sil hidden [thunk] @$S7newtype8ObjCTestC18integerPassThroughySo5MyIntaAFFTo : $@convention(objc_method) (MyInt, ObjCTest) -> MyInt {
+  @objc func integerPassThrough(_ ed: MyInt) -> MyInt {
+    return ed
+  }  
+}
+
+// These use a bridging conversion with a specialization of a generic witness.
+// CHECK-RAW-LABEL: sil hidden @$S7newtype15bridgeToNewtypeSo8MyStringayF
+func bridgeToNewtype() -> MyString {
+// CHECK-RAW: [[STRING:%.*]] = apply
+// CHECK-RAW: [[TO_NS:%.*]] = function_ref @$SSS10FoundationE19_bridgeToObjectiveCSo8NSStringCyF
+// CHECK-RAW: [[BORROW:%.*]] = begin_borrow [[STRING]]
+// CHECK-RAW: [[NS:%.*]] = apply [[TO_NS]]([[BORROW]])
+// CHECK-RAW: [[TO_MY:%.*]] = function_ref @$Ss20_SwiftNewtypeWrapperPss21_ObjectiveCBridgeable8RawValueRpzrlE026_unconditionallyBridgeFromD1CyxAD_01_D5CTypeQZSgFZ : $@convention(method) <τ_0_0 where τ_0_0 : _SwiftNewtypeWrapper, τ_0_0.RawValue : _ObjectiveCBridgeable> (@guaranteed Optional<τ_0_0.RawValue._ObjectiveCType>, @thick τ_0_0.Type)
+// CHECK-RAW: [[OPTNS:%.*]] = enum $Optional<NSString>, #Optional.some!enumelt.1, [[NS]]
+// CHECK-RAW: [[META:%.*]] = metatype $@thick MyString.Type
+// CHECK-RAW: apply [[TO_MY]]<MyString, String>({{.*}}, [[OPTNS]], [[META]])
+  return "foo" as NSString as MyString
+}
+
+// CHECK-RAW-LABEL: sil hidden @$S7newtype17bridgeFromNewtype6stringSSSo8MyStringa_tF
+func bridgeFromNewtype(string: MyString) -> String {
+// CHECK-RAW: [[FROM_MY:%.*]] = function_ref @$Ss20_SwiftNewtypeWrapperPss21_ObjectiveCBridgeable8RawValueRpzrlE09_bridgeToD1CAD_01_D5CTypeQZyF : $@convention(method) <τ_0_0 where τ_0_0 : _SwiftNewtypeWrapper, τ_0_0.RawValue : _ObjectiveCBridgeable> (@in_guaranteed τ_0_0) -> @owned τ_0_0.RawValue._ObjectiveCType
+// CHECK-RAW: [[NS:%.*]] = apply [[FROM_MY]]<MyString, String>(
+// CHECK-RAW: [[FROM_NS:%.*]] = function_ref @$SSS10FoundationE36_unconditionallyBridgeFromObjectiveCySSSo8NSStringCSgFZ
+// CHECK-RAW: [[OPTNS:%.*]] = enum $Optional<NSString>, #Optional.some!enumelt.1, [[NS]]
+// CHECK-RAW: [[META:%.*]] = metatype $@thin String.Type
+// CHECK-RAW: apply [[FROM_NS]]([[OPTNS]], [[META]])
+  return string as NSString as String
+}
diff --git a/test/SILGen/plus_zero_noescape_reabstraction.swift b/test/SILGen/plus_zero_noescape_reabstraction.swift
new file mode 100644
index 0000000..36d8a93
--- /dev/null
+++ b/test/SILGen/plus_zero_noescape_reabstraction.swift
@@ -0,0 +1,24 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership %s | %FileCheck %s
+
+struct S {}
+
+func noescape_concrete(_ x: (S) -> S) {
+  noescape_generic(x)
+}
+
+func noescape_generic<T>(_ x: (T) -> T) {
+}
+
+// CHECK-LABEL: sil hidden @$S22noescape_reabstraction0A9_concreteyyAA1SVADXEF
+// CHECK:         function_ref [[REABSTRACTION_THUNK:@\$S22noescape_reabstraction1SVACIgyd_A2CIegnr_TR]]
+
+func concrete(_ x: (S) -> S) {
+  noescape_generic(x)
+}
+
+func generic<T>(_ x: (T) -> T) {
+}
+
+// CHECK-LABEL: sil hidden @$S22noescape_reabstraction8concreteyyAA1SVADXEF
+// CHECK:         function_ref [[REABSTRACTION_THUNK]]
diff --git a/test/SILGen/plus_zero_objc_attr_NSManaged.swift b/test/SILGen/plus_zero_objc_attr_NSManaged.swift
new file mode 100644
index 0000000..64754aa
--- /dev/null
+++ b/test/SILGen/plus_zero_objc_attr_NSManaged.swift
@@ -0,0 +1,137 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -sdk %S/Inputs %s -I %S/Inputs -enable-source-import -emit-silgen -enable-sil-ownership | %FileCheck %s
+
+// REQUIRES: objc_interop
+
+// This file is also used by objc_attr_NSManaged_multi.swift.
+
+import Foundation
+import gizmo
+
+@objc class X : NSObject {
+  func foo() -> X { return self }
+}
+
+class SwiftGizmo : Gizmo {
+  @NSManaged var x: X
+
+  @NSManaged func kvc()
+
+  // CHECK-NOT: sil hidden @$S19objc_attr_NSManaged10SwiftGizmoC1x{{[_0-9a-zA-Z]*}}fgTo
+  // CHECK-NOT: sil hidden @$S19objc_attr_NSManaged10SwiftGizmoC1x{{[_0-9a-zA-Z]*}}fsTo
+  // CHECK-NOT: sil hidden @$S19objc_attr_NSManaged10SwiftGizmoC3kvc{{[_0-9a-zA-Z]*}}FTo
+
+  // Make sure that we're calling through the @objc entry points.
+  // CHECK-LABEL: sil hidden @$S19objc_attr_NSManaged10SwiftGizmoC7modifyX{{[_0-9a-zA-Z]*}}F : $@convention(method) (@guaranteed SwiftGizmo) -> () {
+  func modifyX() {
+    // CHECK:   [[GETTER:%[0-9]+]] = objc_method [[SELF:%.*]] : $SwiftGizmo, #SwiftGizmo.x!getter.1.foreign : (SwiftGizmo) -> () -> X, $@convention(objc_method) (SwiftGizmo) -> @autoreleased X
+    // CHECK-NEXT: apply [[GETTER]]([[SELF]]) : $@convention(objc_method) (SwiftGizmo) -> @autoreleased X
+    // CHECK-NOT: return
+    // CHECK:   [[SETTER:%[0-9]+]] = objc_method [[SELF]] : $SwiftGizmo, #SwiftGizmo.x!setter.1.foreign : (SwiftGizmo) -> (X) -> (), $@convention(objc_method) (X, SwiftGizmo) -> ()
+    // CHECK:  apply [[SETTER]]([[XMOD:%.*]], [[SELF]]) : $@convention(objc_method) (X, SwiftGizmo) -> ()
+    x = x.foo()
+    // CHECK: return
+  }
+
+  // CHECK-LABEL: sil hidden @$S19objc_attr_NSManaged10SwiftGizmoC8testFunc{{[_0-9a-zA-Z]*}}F
+  func testFunc() {
+    // CHECK: = objc_method %0 : $SwiftGizmo, #SwiftGizmo.kvc!1.foreign : (SwiftGizmo) -> () -> (), $@convention(objc_method) (SwiftGizmo) -> ()
+    // CHECK: return
+    kvc()
+  }
+}
+
+extension SwiftGizmo {
+  @NSManaged func extKVC()
+
+  // CHECK-LABEL: $S19objc_attr_NSManaged10SwiftGizmoC7testExt{{[_0-9a-zA-Z]*}}F
+  func testExt() {
+    // CHECK: = objc_method %0 : $SwiftGizmo, #SwiftGizmo.extKVC!1.foreign : (SwiftGizmo) -> () -> (), $@convention(objc_method) (SwiftGizmo) -> ()
+    // CHECK: return
+    extKVC()
+  }
+}
+
+final class FinalGizmo : SwiftGizmo {
+  @NSManaged var y: String
+
+  @NSManaged func kvc2()
+}
+
+extension FinalGizmo {
+  @NSManaged func extKVC2()
+
+  // CHECK-LABEL: $S19objc_attr_NSManaged10FinalGizmoC8testExt2{{[_0-9a-zA-Z]*}}F
+  func testExt2() {
+    // CHECK: = objc_method %0 : $FinalGizmo, #FinalGizmo.extKVC2!1.foreign : (FinalGizmo) -> () -> (), $@convention(objc_method) (FinalGizmo) -> ()
+    // CHECK: return
+    extKVC2()
+  }
+}
+
+// CHECK-LABEL: sil hidden @$S19objc_attr_NSManaged9testFinalySSAA0E5GizmoCF : $@convention(thin) (@guaranteed FinalGizmo) -> @owned String {
+// CHECK: bb0([[ARG:%.*]] : @guaranteed $FinalGizmo):
+// CHECK: objc_method [[ARG]] : $FinalGizmo, #FinalGizmo.kvc2!1.foreign : (FinalGizmo) -> () -> (), $@convention(objc_method) (FinalGizmo) -> ()
+// CHECK-NOT: return
+// CHECK: objc_method [[ARG]] : $FinalGizmo, #FinalGizmo.y!getter.1.foreign : (FinalGizmo) -> () -> String, $@convention(objc_method) (FinalGizmo) -> @autoreleased NSString
+// CHECK: return
+func testFinal(_ obj: FinalGizmo) -> String {
+  obj.kvc2()
+  return obj.y
+}
+
+// SR-2673: @NSManaged property can't satisfy protocol requirement
+@objc protocol ObjCProto {
+  var managedProp: String { get set }
+  var managedExtProp: AnyObject { get }
+}
+
+class ProtoAdopter: Gizmo, ObjCProto {
+  @NSManaged var managedProp: String
+}
+extension ProtoAdopter {
+  @NSManaged var managedExtProp: AnyObject
+}
+
+
+// SR-6534: @NSManaged properties can be 'final'
+protocol EntityIDProto {
+  var entityID: String { get set }
+}
+
+class FinalEntity: NSObject, EntityIDProto {
+	@NSManaged final var entityID: String
+}
+
+// CHECK-LABEL: sil private @$S19objc_attr_NSManaged11FinalEntityC8entityIDSSvmytfU_ : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout FinalEntity, @thick FinalEntity.Type) -> ()
+// CHECK: objc_method {{.*}} : $FinalEntity, #FinalEntity.entityID!setter.1.foreign
+// CHECK: return
+
+// CHECK-LABEL: sil hidden @$S19objc_attr_NSManaged11FinalEntityC8entityIDSSvm : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @guaranteed FinalEntity) -> (Builtin.RawPointer, Optional<Builtin.RawPointer>)
+// CHECK: objc_method {{.*}} : $FinalEntity, #FinalEntity.entityID!getter.1.foreign
+// CHECK: return
+
+// CHECK-NOT: sil hidden @$S19objc_attr_NSManaged10SwiftGizmoC1xAA1XCfgTo : $@convention(objc_method) (SwiftGizmo) -> @autoreleased X
+// CHECK-NOT: sil hidden @$S19objc_attr_NSManaged10SwiftGizmoC1xAA1XCfsTo
+// CHECK-NOT: sil hidden @$S19objc_attr_NSManaged10{{[_0-9a-zA-Z]*}}FinalGizmoC1yytfgTo
+
+// The vtable should not contain any entry points for getters and setters.
+// CHECK-LABEL: sil_vtable SwiftGizmo {
+// CHECK-NEXT:   #SwiftGizmo.modifyX!1: {{.*}} : @$S19objc_attr_NSManaged10SwiftGizmoC7modifyXyyF
+// CHECK-NEXT:   #SwiftGizmo.testFunc!1: {{.*}} : @$S19objc_attr_NSManaged10SwiftGizmoC8testFuncyyF
+// CHECK-NEXT:   #SwiftGizmo.init!initializer.1: {{.*}} : @$S19objc_attr_NSManaged10SwiftGizmoCACSgycfc
+// CHECK-NEXT:   #SwiftGizmo.init!initializer.1: {{.*}} : @$S19objc_attr_NSManaged10SwiftGizmoC7bellsOnACSgSi_tcfc
+// CHECK-NEXT:   #SwiftGizmo.deinit!deallocator: @$S19objc_attr_NSManaged10SwiftGizmoCfD
+// CHECK-NEXT: }
+
+// CHECK-LABEL: sil_vtable FinalGizmo {
+// CHECK-NEXT:   #SwiftGizmo.modifyX!1: {{.*}} : @$S19objc_attr_NSManaged10SwiftGizmoC7modifyX{{[_0-9a-zA-Z]*}}F
+// CHECK-NEXT:   #SwiftGizmo.testFunc!1: {{.*}} : @$S19objc_attr_NSManaged10SwiftGizmoC8testFunc{{[_0-9a-zA-Z]*}}F
+// CHECK-NEXT:   #SwiftGizmo.init!initializer.1: {{.*}} : @$S19objc_attr_NSManaged10FinalGizmoC{{[_0-9a-zA-Z]*}}fc
+// CHECK-NEXT:   #SwiftGizmo.init!initializer.1: {{.*}} : @$S19objc_attr_NSManaged10FinalGizmoC{{[_0-9a-zA-Z]*}}fc
+// CHECK-NEXT:   #FinalGizmo.deinit!deallocator: @$S19objc_attr_NSManaged10FinalGizmoCfD
+// CHECK-NEXT: }
+
+// CHECK-LABEL: sil_vtable ProtoAdopter {
+// CHECK-NOT: managed{{.*}}Prop
+// CHECK: {{^}$}}
diff --git a/test/SILGen/plus_zero_objc_attr_NSManaged_multi.swift b/test/SILGen/plus_zero_objc_attr_NSManaged_multi.swift
new file mode 100644
index 0000000..c1c9a5f
--- /dev/null
+++ b/test/SILGen/plus_zero_objc_attr_NSManaged_multi.swift
@@ -0,0 +1,34 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -sdk %S/Inputs -primary-file %s %S/objc_attr_NSManaged.swift -I %S/Inputs -enable-source-import -emit-silgen -enable-sil-ownership | %FileCheck %s
+
+// REQUIRES: objc_interop
+
+import Foundation
+
+// CHECK-LABEL: sil hidden @$S25objc_attr_NSManaged_multi9testMultiyyXlAA10SwiftGizmoCF : $@convention(thin) (@guaranteed SwiftGizmo) -> @owned AnyObject {
+// CHECK: bb0([[ARG:%.*]] : @guaranteed $SwiftGizmo):
+// CHECK: = objc_method [[ARG]] : $SwiftGizmo, #SwiftGizmo.kvc!1.foreign : (SwiftGizmo) -> () -> (), $@convention(objc_method) (SwiftGizmo) -> ()
+// CHECK-NOT: return
+// CHECK: = objc_method [[ARG]] : $SwiftGizmo, #SwiftGizmo.extKVC!1.foreign : (SwiftGizmo) -> () -> (), $@convention(objc_method) (SwiftGizmo) -> ()
+// CHECK-NOT: return
+// CHECK: objc_method [[ARG]] : $SwiftGizmo, #SwiftGizmo.x!getter.1.foreign : (SwiftGizmo) -> () -> X, $@convention(objc_method) (SwiftGizmo) -> @autoreleased X
+// CHECK: return
+func testMulti(_ obj: SwiftGizmo) -> AnyObject {
+  obj.kvc()
+  obj.extKVC()
+  return obj.x
+}
+
+// CHECK-LABEL: sil hidden @$S25objc_attr_NSManaged_multi14testFinalMultiySSAA0F5GizmoCF : $@convention(thin) (@guaranteed FinalGizmo) -> @owned String {
+// CHECK: bb0([[ARG:%.*]] : @guaranteed $FinalGizmo):
+// CHECK: objc_method [[ARG]] : $FinalGizmo, #FinalGizmo.kvc2!1.foreign : (FinalGizmo) -> () -> (), $@convention(objc_method) (FinalGizmo) -> ()
+// CHECK-NOT: return
+// CHECK: objc_method [[ARG]] : $FinalGizmo, #FinalGizmo.extKVC2!1.foreign : (FinalGizmo) -> () -> (), $@convention(objc_method) (FinalGizmo) -> ()
+// CHECK-NOT: return
+// CHECK: objc_method [[ARG]] : $FinalGizmo, #FinalGizmo.y!getter.1.foreign : (FinalGizmo) -> () -> String, $@convention(objc_method) (FinalGizmo) -> @autoreleased NSString
+// CHECK: return
+func testFinalMulti(_ obj: FinalGizmo) -> String {
+  obj.kvc2()
+  obj.extKVC2()
+  return obj.y
+}
diff --git a/test/SILGen/plus_zero_objc_blocks_bridging.swift b/test/SILGen/plus_zero_objc_blocks_bridging.swift
new file mode 100644
index 0000000..06b79c0
--- /dev/null
+++ b/test/SILGen/plus_zero_objc_blocks_bridging.swift
@@ -0,0 +1,202 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %empty-directory(%t)
+// RUN: %build-silgen-test-overlays
+// RUN: %target-swift-frontend(mock-sdk: -sdk %S/Inputs -I %t) -verify -emit-silgen -I %S/Inputs -disable-objc-attr-requires-foundation-module -enable-sil-ownership %s | %FileCheck %s
+// RUN: %target-swift-frontend(mock-sdk: -sdk %S/Inputs -I %t) -verify -emit-silgen -I %S/Inputs -disable-objc-attr-requires-foundation-module -enable-sil-ownership  %s | %FileCheck %s --check-prefix=GUARANTEED
+
+// REQUIRES: objc_interop
+
+import Foundation
+
+@objc class Foo {
+// CHECK-LABEL: sil hidden [thunk] @$S20objc_blocks_bridging3FooC3foo_1xS3iXE_SitFTo :
+  // CHECK: bb0([[ARG1:%.*]] : @unowned $@convention(block) @noescape (Int) -> Int, {{.*}}, [[SELF:%.*]] : @unowned $Foo):
+  // CHECK:         [[ARG1_COPY:%.*]] = copy_block [[ARG1]]
+  // CHECK:         [[SELF_COPY:%.*]] = copy_value [[SELF]]
+  // CHECK:         [[THUNK:%.*]] = function_ref @$SS2iIyByd_S2iIegyd_TR
+  // CHECK:         [[BRIDGED:%.*]] = partial_apply [callee_guaranteed] [[THUNK]]([[ARG1_COPY]])
+  // CHECK:         [[CONVERT:%.*]] = convert_escape_to_noescape [[BRIDGED]]
+  // CHECK:         [[BORROWED_SELF_COPY:%.*]] = begin_borrow [[SELF_COPY]]
+  // CHECK:         [[NATIVE:%.*]] = function_ref @$S20objc_blocks_bridging3FooC3foo{{[_0-9a-zA-Z]*}}F : $@convention(method) (@noescape @callee_guaranteed (Int) -> Int, Int, @guaranteed Foo) -> Int
+  // CHECK:         apply [[NATIVE]]([[CONVERT]], {{.*}}, [[BORROWED_SELF_COPY]])
+  // CHECK:         end_borrow [[BORROWED_SELF_COPY]] from [[SELF_COPY]]
+  // CHECK: } // end sil function '$S20objc_blocks_bridging3FooC3foo_1xS3iXE_SitFTo'
+  dynamic func foo(_ f: (Int) -> Int, x: Int) -> Int {
+    return f(x)
+  }
+
+  // CHECK-LABEL: sil hidden [thunk] @$S20objc_blocks_bridging3FooC3bar_1xS3SXE_SStFTo : $@convention(objc_method) (@convention(block) @noescape (NSString) -> @autoreleased NSString, NSString, Foo) -> @autoreleased NSString {
+  // CHECK:       bb0([[BLOCK:%.*]] : @unowned $@convention(block) @noescape (NSString) -> @autoreleased NSString, [[NSSTRING:%.*]] : @unowned $NSString, [[SELF:%.*]] : @unowned $Foo):
+  // CHECK:         [[BLOCK_COPY:%.*]] = copy_block [[BLOCK]]
+  // CHECK:         [[NSSTRING_COPY:%.*]] = copy_value [[NSSTRING]]
+  // CHECK:         [[SELF_COPY:%.*]] = copy_value [[SELF]]
+  // CHECK:         [[THUNK:%.*]] = function_ref @$SSo8NSStringCABIyBya_S2SIeggo_TR
+  // CHECK:         [[BRIDGED:%.*]] = partial_apply [callee_guaranteed] [[THUNK]]([[BLOCK_COPY]])
+  // CHECK:         [[CONVERT:%.*]] = convert_escape_to_noescape [[BRIDGED]]
+  // CHECK:         [[BORROWED_SELF_COPY:%.*]] = begin_borrow [[SELF_COPY]]
+  // CHECK:         [[NATIVE:%.*]] = function_ref @$S20objc_blocks_bridging3FooC3bar{{[_0-9a-zA-Z]*}}F : $@convention(method) (@noescape @callee_guaranteed (@guaranteed String) -> @owned String, @guaranteed String, @guaranteed Foo) -> @owned String
+  // CHECK:         apply [[NATIVE]]([[CONVERT]], {{%.*}}, [[BORROWED_SELF_COPY]])
+  // CHECK:         end_borrow [[BORROWED_SELF_COPY]] from [[SELF_COPY]]
+  // CHECK: } // end sil function '$S20objc_blocks_bridging3FooC3bar_1xS3SXE_SStFTo'
+  dynamic func bar(_ f: (String) -> String, x: String) -> String {
+    return f(x)
+  }
+
+  // GUARANTEED-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] @$SSo8NSStringCABIyBya_S2SIeggo_TR : $@convention(thin) (@guaranteed String, @guaranteed @convention(block) @noescape (NSString) -> @autoreleased NSString) -> @owned String {
+  // GUARANTEED: bb0(%0 : @guaranteed $String, [[BLOCK:%.*]] : @guaranteed $@convention(block) @noescape (NSString) -> @autoreleased NSString):
+  // GUARANTEED:   [[BRIDGE:%.*]] = function_ref @$SSS10FoundationE19_bridgeToObjectiveCSo8NSStringCyF
+  // GUARANTEED:   [[NSSTR:%.*]] = apply [[BRIDGE]](%0)
+  // GUARANTEED:   apply [[BLOCK]]([[NSSTR]]) : $@convention(block) @noescape (NSString) -> @autoreleased NSString
+  // GUARANTEED: } // end sil function '$SSo8NSStringCABIyBya_S2SIeggo_TR'
+
+  // CHECK-LABEL: sil hidden [thunk] @$S20objc_blocks_bridging3FooC3bas_1xSSSgA2FXE_AFtFTo : $@convention(objc_method) (@convention(block) @noescape (Optional<NSString>) -> @autoreleased Optional<NSString>, Optional<NSString>, Foo) -> @autoreleased Optional<NSString> {
+  // CHECK:       bb0([[BLOCK:%.*]] : @unowned $@convention(block) @noescape (Optional<NSString>) -> @autoreleased Optional<NSString>, [[OPT_STRING:%.*]] : @unowned $Optional<NSString>, [[SELF:%.*]] : @unowned $Foo):
+  // CHECK:         [[BLOCK_COPY:%.*]] = copy_block [[BLOCK]]
+  // CHECK:         [[OPT_STRING_COPY:%.*]] = copy_value [[OPT_STRING]]
+  // CHECK:         [[SELF_COPY:%.*]] = copy_value [[SELF]]
+  // CHECK:         [[THUNK:%.*]] = function_ref @$SSo8NSStringCSgACIyBya_SSSgADIeggo_TR
+  // CHECK:         [[BRIDGED:%.*]] = partial_apply [callee_guaranteed] [[THUNK]]([[BLOCK_COPY]])
+  // CHECK:         [[CONVERT:%.*]] = convert_escape_to_noescape [[BRIDGED]]
+  // CHECK:         [[BORROWED_SELF_COPY:%.*]] = begin_borrow [[SELF_COPY]]
+  // CHECK:         [[NATIVE:%.*]] = function_ref @$S20objc_blocks_bridging3FooC3bas{{[_0-9a-zA-Z]*}}F : $@convention(method) (@noescape @callee_guaranteed (@guaranteed Optional<String>) -> @owned Optional<String>, @guaranteed Optional<String>, @guaranteed Foo) -> @owned Optional<String>
+  // CHECK:         apply [[NATIVE]]([[CONVERT]], {{%.*}}, [[BORROWED_SELF_COPY]])
+  // CHECK:         end_borrow [[BORROWED_SELF_COPY]] from [[SELF_COPY]]
+  dynamic func bas(_ f: (String?) -> String?, x: String?) -> String? {
+    return f(x)
+  }
+
+  // CHECK-LABEL: sil hidden [thunk] @$S20objc_blocks_bridging3FooC16cFunctionPointer{{[_0-9a-zA-Z]*}}FTo
+  // CHECK:       bb0([[F:%.*]] : @trivial $@convention(c) @noescape (Int) -> Int, [[X:%.*]] : @trivial $Int, [[SELF:%.*]] : @unowned $Foo):
+  // CHECK:         [[SELF_COPY:%.*]] = copy_value [[SELF]]
+  // CHECK:         [[BORROWED_SELF_COPY:%.*]] = begin_borrow [[SELF_COPY]]
+  // CHECK:         [[NATIVE:%.*]] = function_ref @$S20objc_blocks_bridging3FooC16cFunctionPointer{{[_0-9a-zA-Z]*}}F
+  // CHECK:         apply [[NATIVE]]([[F]], [[X]], [[BORROWED_SELF_COPY]])
+  // CHECK:         end_borrow [[BORROWED_SELF_COPY]] from [[SELF_COPY]]
+  // CHECK:         destroy_value [[SELF_COPY]]
+  dynamic func cFunctionPointer(_ fp: @convention(c) (Int) -> Int, x: Int) -> Int {
+    _ = fp(x)
+  }
+
+  // Blocks and C function pointers must not be reabstracted when placed in optionals.
+  // CHECK-LABEL: sil hidden [thunk] @$S20objc_blocks_bridging3FooC7optFunc{{[_0-9a-zA-Z]*}}FTo
+  // CHECK: bb0([[ARG0:%.*]] : @unowned $Optional<@convention(block) (NSString) -> @autoreleased NSString>,
+  // CHECK:         [[COPY:%.*]] = copy_block [[ARG0]]
+  // CHECK:         switch_enum [[COPY]] : $Optional<@convention(block) (NSString) -> @autoreleased NSString>, case #Optional.some!enumelt.1: [[SOME_BB:bb[0-9]+]], case #Optional.none!enumelt: [[NONE_BB:bb[0-9]+]]
+  // CHECK: [[SOME_BB]]([[BLOCK:%.*]] : @owned $@convention(block) (NSString) -> @autoreleased NSString):
+  // TODO: redundant reabstractions here
+  // CHECK:         [[BLOCK_THUNK:%.*]] = function_ref @$SSo8NSStringCABIeyBya_S2SIeggo_TR
+  // CHECK:         [[BRIDGED:%.*]] = partial_apply [callee_guaranteed] [[BLOCK_THUNK]]([[BLOCK]])
+  // CHECK:         enum $Optional<@callee_guaranteed (@guaranteed String) -> @owned String>, #Optional.some!enumelt.1, [[BRIDGED]]
+  // CHECK:         [[NATIVE:%.*]] = function_ref @$S20objc_blocks_bridging3FooC7optFunc{{[_0-9a-zA-Z]*}}F : $@convention(method) (@guaranteed Optional<@callee_guaranteed (@guaranteed String) -> @owned String>, @guaranteed String, @guaranteed Foo) -> @owned Optional<String>
+  // CHECK:         apply [[NATIVE]]
+  dynamic func optFunc(_ f: ((String) -> String)?, x: String) -> String? {
+    return f?(x)
+  }
+
+  // CHECK-LABEL: sil hidden @$S20objc_blocks_bridging3FooC19optCFunctionPointer{{[_0-9a-zA-Z]*}}F
+  // CHECK:         [[FP_BUF:%.*]] = unchecked_enum_data %0
+  dynamic func optCFunctionPointer(_ fp: (@convention(c) (String) -> String)?, x: String) -> String? {
+    return fp?(x)
+  }
+}
+
+// => SEMANTIC SIL TODO: This test needs to be filled out more for ownership
+//
+// CHECK-LABEL: sil hidden @$S20objc_blocks_bridging10callBlocks{{[_0-9a-zA-Z]*}}F
+func callBlocks(_ x: Foo,
+  f: @escaping (Int) -> Int,
+  g: @escaping (String) -> String,
+  h: @escaping (String?) -> String?
+) -> (Int, String, String?, String?) {
+  // CHECK: bb0([[ARG0:%.*]] : @guaranteed $Foo, [[ARG1:%.*]] : @guaranteed $@callee_guaranteed (Int) -> Int, [[ARG2:%.*]] : @guaranteed $@callee_guaranteed (@guaranteed String) -> @owned String, [[ARG3:%.*]] : @guaranteed $@callee_guaranteed (@guaranteed Optional<String>) -> @owned Optional<String>):
+  // CHECK: [[CLOSURE_COPY:%.*]] = copy_value [[ARG1]]
+  // CHECK: [[CONVERT:%.*]] = convert_escape_to_noescape [[CLOSURE_COPY]]
+  // CHECK: [[F_BLOCK_STORAGE:%.*]] = alloc_stack $@block_storage
+  // CHECK: [[F_BLOCK_CAPTURE:%.*]] = project_block_storage [[F_BLOCK_STORAGE]]
+  // CHECK: store [[CONVERT]] to [trivial] [[F_BLOCK_CAPTURE]]
+  // CHECK: [[F_BLOCK_INVOKE:%.*]] = function_ref @$SS2iIgyd_S2iIyByd_TR
+  // CHECK: [[F_STACK_BLOCK:%.*]] = init_block_storage_header [[F_BLOCK_STORAGE]] : {{.*}}, invoke [[F_BLOCK_INVOKE]]
+  // CHECK: [[F_BLOCK:%.*]] = copy_block [[F_STACK_BLOCK]]
+  // CHECK: [[FOO:%.*]] =  objc_method [[ARG0]] : $Foo, #Foo.foo!1.foreign
+  // CHECK: apply [[FOO]]([[F_BLOCK]]
+
+  // CHECK: [[G_BLOCK_INVOKE:%.*]] = function_ref @$SS2SIggo_So8NSStringCABIyBya_TR
+  // CHECK: [[G_STACK_BLOCK:%.*]] = init_block_storage_header {{.*}}, invoke [[G_BLOCK_INVOKE]]
+  // CHECK: [[G_BLOCK:%.*]] = copy_block [[G_STACK_BLOCK]]
+  // CHECK: [[BAR:%.*]] = objc_method [[ARG0]] : $Foo, #Foo.bar!1.foreign
+  // CHECK: apply [[BAR]]([[G_BLOCK]]
+
+  // CHECK: [[H_BLOCK_INVOKE:%.*]] = function_ref @$SSSSgAAIggo_So8NSStringCSgADIyBya_TR
+  // CHECK: [[H_STACK_BLOCK:%.*]] = init_block_storage_header {{.*}}, invoke [[H_BLOCK_INVOKE]]
+  // CHECK: [[H_BLOCK:%.*]] = copy_block [[H_STACK_BLOCK]]
+  // CHECK: [[BAS:%.*]] = objc_method [[ARG0]] : $Foo, #Foo.bas!1.foreign
+  // CHECK: apply [[BAS]]([[H_BLOCK]]
+
+  // CHECK: [[G_BLOCK:%.*]] = copy_block {{%.*}} : $@convention(block) (NSString) -> @autoreleased NSString
+  // CHECK: enum $Optional<@convention(block) (NSString) -> @autoreleased NSString>, #Optional.some!enumelt.1, [[G_BLOCK]]
+
+  return (x.foo(f, x: 0), x.bar(g, x: "one"), x.bas(h, x: "two"), x.optFunc(g, x: "three"))
+}
+
+class Test: NSObject {
+  func blockTakesBlock() -> ((Int) -> Int) -> Int {}
+}
+
+// CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] @$SS2iIgyd_SiIegyd_S2iIyByd_SiIeyByd_TR
+// CHECK:         [[BLOCK_COPY:%.*]] = copy_block [[ORIG_BLOCK:%.*]] :
+// CHECK:         [[CLOSURE:%.*]] = partial_apply [callee_guaranteed] {{%.*}}([[BLOCK_COPY]])
+// CHECK: [[CONVERT:%.*]] = convert_escape_to_noescape [[CLOSURE]]
+// CHECK:         [[RESULT:%.*]] = apply {{%.*}}([[CONVERT]])
+// CHECK:         return [[RESULT]]
+
+func clearDraggingItemImageComponentsProvider(_ x: NSDraggingItem) {
+  x.imageComponentsProvider = {}
+}
+// CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] @$SSayypGIego_So7NSArrayCSgIeyBa_TR
+// CHECK:         [[CONVERT:%.*]] = function_ref @$SSa10FoundationE19_bridgeToObjectiveCSo7NSArrayCyF
+// CHECK:         [[CONVERTED:%.*]] = apply [[CONVERT]]
+// CHECK:         [[OPTIONAL:%.*]] = enum $Optional<NSArray>, #Optional.some!enumelt.1, [[CONVERTED]]
+// CHECK:         return [[OPTIONAL]]
+
+// CHECK-LABEL: sil hidden @{{.*}}bridgeNonnullBlockResult{{.*}}
+// CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] @$SSSIego_So8NSStringCSgIeyBa_TR
+// CHECK:         [[CONVERT:%.*]] = function_ref @$SSS10FoundationE19_bridgeToObjectiveCSo8NSStringCyF
+// CHECK:         [[BRIDGED:%.*]] = apply [[CONVERT]]
+// CHECK:         [[OPTIONAL_BRIDGED:%.*]] = enum $Optional<NSString>, #Optional.some!enumelt.1, [[BRIDGED]]
+// CHECK:         return [[OPTIONAL_BRIDGED]]
+func bridgeNonnullBlockResult() {
+  nonnullStringBlockResult { return "test" }
+}
+
+// CHECK-LABEL: sil hidden @{{.*}}bridgeNoescapeBlock{{.*}}
+func bridgeNoescapeBlock() {
+  // CHECK: function_ref @$SIg_IyB_TR
+  noescapeBlockAlias { }
+  // CHECK: function_ref @$SIg_IyB_TR
+  noescapeNonnullBlockAlias { }
+}
+
+class ObjCClass : NSObject {}
+
+extension ObjCClass {
+  func someDynamicMethod(closure: (() -> ()) -> ()) {}
+}
+
+struct GenericStruct<T> {
+  let closure: (() -> ()) -> ()
+
+  func doStuff(o: ObjCClass) {
+    o.someDynamicMethod(closure: closure)
+  }
+}
+// CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] @$SIg_Igy_IyB_IyBy_TR : $@convention(c) (@inout_aliasable @block_storage @noescape @callee_guaranteed (@noescape @callee_guaranteed () -> ()) -> (), @convention(block) @noescape () -> ()) -> () {
+// CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] @$SIyB_Ieg_TR : $@convention(thin) (@guaranteed @convention(block) @noescape () -> ()) -> ()
+
+// rdar://35402696
+func takeOptStringFunction(fn: (String) -> String?) {}
+func testGlobalBlock() {
+  takeOptStringFunction(fn: GlobalBlock)
+}
+// CHECK-LABEL: sil hidden @$S20objc_blocks_bridging15testGlobalBlockyyF
+// CHECK: global_addr @GlobalBlock : $*@convention(block) (NSString) -> @autoreleased Optional<NSString>
+// CHECK: function_ref @$SSo8NSStringCABSgIeyBya_S2SIeggo_TR : $@convention(thin) (@guaranteed String, @guaranteed @convention(block) (NSString) -> @autoreleased Optional<NSString>) -> @owned String
diff --git a/test/SILGen/plus_zero_objc_bridged_results.swift b/test/SILGen/plus_zero_objc_bridged_results.swift
new file mode 100644
index 0000000..862c5b1
--- /dev/null
+++ b/test/SILGen/plus_zero_objc_bridged_results.swift
@@ -0,0 +1,154 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %empty-directory(%t)
+// RUN: %build-silgen-test-overlays
+
+// RUN: %target-swift-frontend(mock-sdk: -sdk %S/Inputs -I %t) -emit-silgen %s -Xllvm -sil-print-debuginfo -import-objc-header %S/Inputs/objc_bridged_results.h -enable-sil-ownership | %FileCheck %s
+
+// REQUIRES: objc_interop
+
+import Foundation
+
+// CHECK-LABEL: sil hidden @$S20objc_bridged_results11testNonnullySayypGSo4TestCF
+// CHECK: bb0([[ARG:%.*]] : @guaranteed $Test):
+// CHECK: [[METHOD:%[0-9]+]] = objc_method [[ARG]] : $Test, #Test.nonnullArray!getter.1.foreign : (Test) -> () -> [Any], $@convention(objc_method) (Test) -> @autoreleased Optional<NSArray>
+// CHECK: [[COCOA_VAL:%[0-9]+]] = apply [[METHOD]]([[ARG]]) : $@convention(objc_method) (Test) -> @autoreleased Optional<NSArray>
+// CHECK: [[CONVERT:%[0-9]+]] = function_ref @$SSa10FoundationE36_unconditionallyBridgeFromObjectiveCySayxGSo7NSArrayCSgFZ
+// CHECK: [[ARRAY_META:%[0-9]+]] = metatype $@thin Array<Any>.Type
+// CHECK: [[RESULT:%[0-9]+]] = apply [[CONVERT]]<Any>([[COCOA_VAL]], [[ARRAY_META]])
+// CHECK-NOT: destroy_value %0 : $Test
+// CHECK: return [[RESULT]] : $Array<Any>
+func testNonnull(_ obj: Test) -> [Any] {
+  return obj.nonnullArray
+} // CHECK: } // end sil function '$S20objc_bridged_results11testNonnullySayypGSo4TestCF'
+
+// CHECK-LABEL: sil hidden @$S20objc_bridged_results12testNullableySayypGSgSo4TestCF
+func testNullable(_ obj: Test) -> [Any]? {
+  // CHECK: bb0([[ARG:%.*]] : @guaranteed $Test):
+  // CHECK: [[METHOD:%[0-9]+]] = objc_method [[ARG]] : $Test, #Test.nullableArray!getter.1.foreign : (Test) -> () -> [Any]?, $@convention(objc_method) (Test) -> @autoreleased Optional<NSArray>
+  // CHECK: [[COCOA_VAL:%[0-9]+]] = apply [[METHOD]]([[ARG]]) : $@convention(objc_method) (Test) -> @autoreleased Optional<NSArray>
+  // CHECK: switch_enum [[COCOA_VAL]] : $Optional<NSArray>, case #Optional.some!enumelt.1: [[CASE_NON_NIL:bb[0-9]+]], case #Optional.none!enumelt: [[CASE_NIL:bb[0-9]+]]
+  //
+  // CHECK: [[CASE_NON_NIL]]([[COCOA_VAL_NON_NIL:%.*]] : @owned $NSArray):
+  // CHECK-NOT: unchecked_enum_data
+  // CHECK: [[CONVERT:%[0-9]+]] = function_ref @$SSa10FoundationE36_unconditionallyBridgeFromObjectiveCySayxGSo7NSArrayCSgFZ
+  // CHECK: [[COCOA_SOME_VAL:%[0-9]+]] = enum $Optional<NSArray>, #Optional.some!enumelt.1, [[COCOA_VAL_NON_NIL]]
+  // CHECK: [[ARRAY_META:%[0-9]+]] = metatype $@thin Array<Any>.Type
+  // CHECK: [[RESULT_VAL:%[0-9]+]] = apply [[CONVERT]]<Any>([[COCOA_SOME_VAL]], [[ARRAY_META]])
+  // CHECK: [[RESULT_SOME:%[0-9]+]] = enum $Optional<Array<Any>>, #Optional.some!enumelt.1, [[RESULT_VAL]] : $Array<Any>
+  // CHECK: br [[FINISH:bb[0-9]+]]([[RESULT_SOME]] : $Optional<Array<Any>>)
+  
+  // CHECK: [[CASE_NIL]]:
+  // CHECK:   [[RESULT_NONE:%[0-9]+]] = enum $Optional<Array<Any>>, #Optional.none!enumelt
+  // CHECK: br [[FINISH]]([[RESULT_NONE]] : $Optional<Array<Any>>)
+  
+  // CHECK: [[FINISH]]([[RESULT:%[0-9]+]] : @owned $Optional<Array<Any>>):
+  // CHECK-NOT: destroy_value [[ARG]] : $Test
+  // CHECK: return [[RESULT]] : $Optional<Array<Any>>
+  return obj.nullableArray
+} // CHECK: } // end sil function '$S20objc_bridged_results12testNullableySayypGSgSo4TestCF'
+
+// CHECK-LABEL: sil hidden @$S20objc_bridged_results19testNullUnspecifiedySayypGSgSo4TestCF
+func testNullUnspecified(_ obj: Test) -> [Any]! {
+  // CHECK: bb0([[ARG:%.*]] : @guaranteed $Test):
+  // CHECK: [[METHOD:%[0-9]+]] = objc_method [[ARG]] : $Test, #Test.nullUnspecifiedArray!getter.1.foreign : (Test) -> () -> [Any]?, $@convention(objc_method) (Test) -> @autoreleased Optional<NSArray>
+  // CHECK: [[COCOA_VAL:%[0-9]+]] = apply [[METHOD]]([[ARG]]) : $@convention(objc_method) (Test) -> @autoreleased Optional<NSArray>
+  // CHECK: switch_enum [[COCOA_VAL]] : $Optional<NSArray>, case #Optional.some!enumelt.1: [[CASE_NON_NIL:bb[0-9]+]], case #Optional.none!enumelt: [[CASE_NIL:bb[0-9]+]]
+
+  // CHECK: [[CASE_NON_NIL]]([[COCOA_VAL_NON_NIL:%.*]] : @owned $NSArray):
+  // CHECK-NOT: unchecked_enum_data
+  // CHECK: [[CONVERT:%[0-9]+]] = function_ref @$SSa10FoundationE36_unconditionallyBridgeFromObjectiveCySayxGSo7NSArrayCSgFZ
+  // CHECK: [[COCOA_SOME_VAL:%[0-9]+]] = enum $Optional<NSArray>, #Optional.some!enumelt.1, [[COCOA_VAL_NON_NIL]]
+  // CHECK: [[ARRAY_META:%[0-9]+]] = metatype $@thin Array<Any>.Type
+  // CHECK: [[RESULT_VAL:%[0-9]+]] = apply [[CONVERT]]<Any>([[COCOA_SOME_VAL]], [[ARRAY_META]])
+  // CHECK: [[RESULT_SOME:%[0-9]+]] = enum $Optional<Array<Any>>, #Optional.some!enumelt.1, [[RESULT_VAL]] : $Array<Any>
+  // CHECK: br [[FINISH:bb[0-9]+]]([[RESULT_SOME]] : $Optional<Array<Any>>)
+  
+  // CHECK: [[CASE_NIL]]:
+  // CHECK:   [[RESULT_NONE:%[0-9]+]] = enum $Optional<Array<Any>>, #Optional.none!enumelt
+  // CHECK: br [[FINISH]]([[RESULT_NONE]] : $Optional<Array<Any>>)
+
+  // CHECK: [[FINISH]]([[RESULT:%[0-9]+]] : @owned $Optional<Array<Any>>):
+  // CHECK-NOT: destroy_value [[ARG]] : $Test
+  // CHECK: return [[RESULT]] : $Optional<Array<Any>>
+  return obj.nullUnspecifiedArray
+} // CHECK: } // end sil function '$S20objc_bridged_results19testNullUnspecifiedySayypGSgSo4TestCF'
+
+
+// CHECK-LABEL: sil hidden @$S20objc_bridged_results21testNonnullDictionaryys0F0Vys11AnyHashableVypGSo4TestCF
+func testNonnullDictionary(_ obj: Test) -> [AnyHashable: Any] {
+  // CHECK: bb0([[ARG:%.*]] : @guaranteed $Test):
+  // CHECK: [[METHOD:%[0-9]+]] = objc_method [[ARG]] : $Test, #Test.nonnullDictionary!getter.1.foreign : (Test) -> () -> [AnyHashable : Any], $@convention(objc_method) (Test) -> @autoreleased Optional<NSDictionary>
+  // CHECK: [[COCOA_VAL:%[0-9]+]] = apply [[METHOD]]([[ARG]]) : $@convention(objc_method) (Test) -> @autoreleased Optional<NSDictionary>
+  // CHECK: [[CONVERT:%[0-9]+]] = function_ref @$Ss10DictionaryV10FoundationE36_unconditionallyBridgeFromObjectiveCyAByxq_GSo12NSDictionaryCSgFZ
+  // CHECK: [[DICT_META:%[0-9]+]] = metatype $@thin Dictionary<AnyHashable, Any>.Type
+  // CHECK: [[RESULT:%[0-9]+]] = apply [[CONVERT]]<AnyHashable, Any>([[COCOA_VAL]], [[DICT_META]])
+  // CHECK-NOT: destroy_value [[ARG]] : $Test
+  // CHECK: return [[RESULT]] : $Dictionary<AnyHashable, Any>
+  return obj.nonnullDictionary
+} // CHECK: } // end sil function '$S20objc_bridged_results21testNonnullDictionaryys0F0Vys11AnyHashableVypGSo4TestCF'
+
+// CHECK-LABEL: sil hidden @$S20objc_bridged_results14testNonnullSetys0F0Vys11AnyHashableVGSo4TestCF
+func testNonnullSet(_ obj: Test) -> Set<AnyHashable> {
+  // CHECK: bb0([[ARG:%.*]] : @guaranteed $Test):
+  // CHECK: [[METHOD:%[0-9]+]] = objc_method [[ARG]] : $Test, #Test.nonnullSet!getter.1.foreign : (Test) -> () -> Set<AnyHashable>, $@convention(objc_method) (Test) -> @autoreleased Optional<NSSet>
+  // CHECK: [[COCOA_VAL:%[0-9]+]] = apply [[METHOD]]([[ARG]]) : $@convention(objc_method) (Test) -> @autoreleased Optional<NSSet>
+  // CHECK: [[CONVERT:%[0-9]+]] = function_ref @$Ss3SetV10FoundationE36_unconditionallyBridgeFromObjectiveCyAByxGSo5NSSetCSgFZ
+  // CHECK: [[SET_META:%[0-9]+]] = metatype $@thin Set<AnyHashable>.Type
+  // CHECK: [[RESULT:%[0-9]+]] = apply [[CONVERT]]<AnyHashable>([[COCOA_VAL]], [[SET_META]])
+  // CHECK-NOT: destroy_value [[ARG]] : $Test
+  // CHECK: return [[RESULT]] : $Set<AnyHashable>
+  return obj.nonnullSet
+} // CHECK: } // end sil function '$S20objc_bridged_results14testNonnullSetys0F0Vys11AnyHashableVGSo4TestCF'
+
+// CHECK-LABEL: sil hidden @$S20objc_bridged_results17testNonnullStringySSSo4TestCF
+func testNonnullString(_ obj: Test) -> String {
+  // CHECK: bb0([[ARG:%.*]] : @guaranteed $Test):
+  // CHECK: [[METHOD:%[0-9]+]] = objc_method [[ARG]] : $Test, #Test.nonnullString!getter.1.foreign : (Test) -> () -> String, $@convention(objc_method) (Test) -> @autoreleased Optional<NSString>
+  // CHECK: [[COCOA_VAL:%[0-9]+]] = apply [[METHOD]]([[ARG]]) : $@convention(objc_method) (Test) -> @autoreleased Optional<NSString>
+  // CHECK: [[CONVERT:%[0-9]+]] = function_ref @$SSS10FoundationE36_unconditionallyBridgeFromObjectiveCySSSo8NSStringCSgFZ
+  // CHECK: [[STRING_META:%[0-9]+]] = metatype $@thin String.Type
+  // CHECK: [[RESULT:%[0-9]+]] = apply [[CONVERT]]([[COCOA_VAL]], [[STRING_META]]) : $@convention(method) (@guaranteed Optional<NSString>, @thin String.Type) -> @owned String
+  // CHECK-NOT: destroy_value [[ARG]] : $Test
+  // CHECK: return [[RESULT]] : $String
+  return obj.nonnullString
+} // CHECK: } // end sil function '$S20objc_bridged_results17testNonnullStringySSSo4TestCF'
+
+// CHECK-LABEL: sil hidden @$S20objc_bridged_results13testClassPropSSyF
+func testClassProp() -> String {
+  // CHECK: [[CLASS:%.+]] = metatype $@objc_metatype Test.Type
+  // CHECK: [[METHOD:%.+]] = objc_method [[CLASS]] : $@objc_metatype Test.Type, #Test.nonnullSharedString!getter.1.foreign : (Test.Type) -> () -> String, $@convention(objc_method) (@objc_metatype Test.Type) -> @autoreleased Optional<NSString>
+  // CHECK: [[COCOA_VAL:%[0-9]+]] = apply [[METHOD]]([[CLASS]]) : $@convention(objc_method) (@objc_metatype Test.Type) -> @autoreleased Optional<NSString>
+  // CHECK: [[CONVERT:%[0-9]+]] = function_ref @$SSS10FoundationE36_unconditionallyBridgeFromObjectiveCySSSo8NSStringCSgFZ
+  // CHECK: [[STRING_META:%[0-9]+]] = metatype $@thin String.Type
+  // CHECK: [[RESULT:%[0-9]+]] = apply [[CONVERT]]([[COCOA_VAL]], [[STRING_META]]) : $@convention(method) (@guaranteed Optional<NSString>, @thin String.Type) -> @owned String
+  // CHECK: return [[RESULT]] : $String
+  return Test.nonnullSharedString
+} // CHECK: } // end sil function '$S20objc_bridged_results13testClassPropSSyF'
+
+
+// Note: This doesn't really "work" in that it doesn't accept a nil value the
+// way the others do, because subscripts are thunked. But the main thing is
+// not to crash trying to generate the thunk.
+// CHECK-LABEL: sil hidden @$S20objc_bridged_results20testNonnullSubscriptySayypGSo4TestCF
+func testNonnullSubscript(_ obj: Test) -> [Any] {
+  // CHECK: bb0([[ARG:%.*]] : @guaranteed $Test):
+  // CHECK: [[METHOD:%[0-9]+]] = objc_method [[ARG]] : $Test, #Test.subscript!getter.1.foreign : (Test) -> (Int) -> [Any], $@convention(objc_method) (Int, Test) -> @autoreleased Optional<NSArray>
+  // CHECK: [[COCOA_VAL:%[0-9]+]] = apply [[METHOD]]({{%[0-9]+}}, [[ARG]]) : $@convention(objc_method) (Int, Test) -> @autoreleased Optional<NSArray>
+  // CHECK: [[CONVERT:%[0-9]+]] = function_ref @$SSa10FoundationE36_unconditionallyBridgeFromObjectiveCySayxGSo7NSArrayCSgFZ
+  // CHECK: [[ARRAY_META:%[0-9]+]] = metatype $@thin Array<Any>.Type,
+  // CHECK: [[RESULT:%[0-9]+]] = apply [[CONVERT]]<Any>([[COCOA_VAL]], [[ARRAY_META]])
+  // CHECK-NOT: destroy_value [[ARG]] : $Test
+  // CHECK: return [[RESULT]] : $Array<Any>
+  return obj[0]
+} // CHECK: } // end sil function '$S20objc_bridged_results20testNonnullSubscriptySayypGSo4TestCF'
+
+
+// CHECK-LABEL: sil hidden @$S20objc_bridged_results19testPerformSelectoryySo8NSObjectCF
+func testPerformSelector(_ obj: NSObject) {
+  // CHECK: bb0([[ARG:%.*]] : @guaranteed $NSObject):
+  // CHECK: [[METHOD:%[0-9]+]] = objc_method [[ARG]] : $NSObject, #NSObject.perform!1.foreign
+  // CHECK: [[RESULT:%[0-9]+]] = apply [[METHOD]]({{%[0-9]+}}, {{%[0-9]+}}, [[ARG]])
+  _ = obj.perform("foo", with: nil)
+  // CHECK-NOT: {{(retain|release).+}}[[RESULT]]
+  // CHECK-NOT: {{(retain|release).+}}[[RESULT]]
+} // CHECK: } // end sil function '$S20objc_bridged_results19testPerformSelectoryySo8NSObjectCF'
diff --git a/test/SILGen/plus_zero_objc_bridging.swift b/test/SILGen/plus_zero_objc_bridging.swift
new file mode 100644
index 0000000..c4c6e1a
--- /dev/null
+++ b/test/SILGen/plus_zero_objc_bridging.swift
@@ -0,0 +1,648 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %empty-directory(%t)
+// RUN: %build-silgen-test-overlays
+// RUN: %target-swift-frontend(mock-sdk: -sdk %S/Inputs -I %t) -emit-module -o %t -I %S/../Inputs/ObjCBridging %S/../Inputs/ObjCBridging/Appliances.swift
+// RUN: %target-swift-frontend(mock-sdk: -sdk %S/Inputs -I %t) -I %S/../Inputs/ObjCBridging -Xllvm -sil-full-demangle -emit-silgen %s -enable-sil-ownership | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%target-cpu --check-prefix=CHECK-%target-os-%target-cpu
+
+// REQUIRES: objc_interop
+
+import Foundation
+import Appliances
+
+
+func getDescription(_ o: NSObject) -> String {
+  return o.description
+}
+// CHECK-LABEL: sil hidden @$S13objc_bridging14getDescription{{.*}}F
+// CHECK: bb0([[ARG:%.*]] : @guaranteed $NSObject):
+// CHECK:   [[DESCRIPTION:%.*]] = objc_method [[ARG]] : $NSObject, #NSObject.description!getter.1.foreign
+// CHECK:   [[OPT_BRIDGED:%.*]] = apply [[DESCRIPTION]]([[ARG]])
+// CHECK:   switch_enum [[OPT_BRIDGED]] : $Optional<NSString>, case #Optional.some!enumelt.1: [[SOME_BB:bb[0-9]+]], case #Optional.none!enumelt: [[NONE_BB:bb[0-9]+]]
+//
+// CHECK: [[SOME_BB]]([[BRIDGED:%.*]] : @owned $NSString):
+// CHECK-NOT:   unchecked_enum_data
+// CHECK:   [[NSSTRING_TO_STRING:%.*]] = function_ref @$SSS10FoundationE36_unconditionallyBridgeFromObjectiveCySSSo8NSStringCSgFZ
+// CHECK:   [[BRIDGED_BOX:%.*]] = enum $Optional<NSString>, #Optional.some!enumelt.1, [[BRIDGED]]
+// CHECK:   [[NATIVE:%.*]] = apply [[NSSTRING_TO_STRING]]([[BRIDGED_BOX]],
+// CHECK:   [[OPT_NATIVE:%.*]] = enum $Optional<String>, #Optional.some!enumelt.1, [[NATIVE]]
+// CHECK:   br [[CONT_BB:bb[0-9]+]]([[OPT_NATIVE]] : $Optional<String>)
+//
+// CHECK: [[NONE_BB]]:
+// CHECK:   [[OPT_NATIVE:%.*]] = enum $Optional<String>, #Optional.none!enumelt
+// CHECK:   br [[CONT_BB]]([[OPT_NATIVE]] : $Optional<String>)
+//
+// CHECK: [[CONT_BB]]([[OPT_NATIVE:%.*]] : @owned $Optional<String>):
+// CHECK:   switch_enum [[OPT_NATIVE]] : $Optional<String>, case #Optional.some!enumelt.1: [[SOME_BB:bb[0-9]+]], case #Optional.none!enumelt: [[NONE_BB:bb[0-9]+]]
+//
+// CHECK: [[NONE_BB]]:
+// CHECK:   unreachable
+//
+// CHECK: [[SOME_BB]]([[NATIVE:%.*]] : @owned $String):
+// CHECK-NOT:    destroy_value [[ARG]]
+// CHECK:    return [[NATIVE]] 
+// CHECK:}
+
+func getUppercaseString(_ s: NSString) -> String {
+  return s.uppercase()
+}
+// CHECK-LABEL: sil hidden @$S13objc_bridging18getUppercaseString{{.*}}F
+// CHECK: bb0([[ARG:%.*]] : @guaranteed $NSString):
+// -- The 'self' argument of NSString methods doesn't bridge.
+// CHECK-NOT: function_ref @$SSS10FoundationE36_unconditionallyBridgeFromObjectiveCySSSo8NSStringCSgFZ
+// CHECK-NOT: function_ref @swift_StringToNSString
+// CHECK:   [[UPPERCASE_STRING:%.*]] = objc_method [[ARG]] : $NSString, #NSString.uppercase!1.foreign
+// CHECK:   [[OPT_BRIDGED:%.*]] = apply [[UPPERCASE_STRING]]([[ARG]]) : $@convention(objc_method) (NSString) -> @autoreleased Optional<NSString>
+// CHECK:   switch_enum [[OPT_BRIDGED]] : $Optional<NSString>, case #Optional.some!enumelt.1: [[SOME_BB:bb[0-9]+]], case #Optional.none!enumelt: [[NONE_BB:bb[0-9]+]]
+//
+//
+// CHECK: [[SOME_BB]]([[BRIDGED:%.*]] :
+// CHECK-NOT:  unchecked_enum_data
+// CHECK:   [[NSSTRING_TO_STRING:%.*]] = function_ref @$SSS10FoundationE36_unconditionallyBridgeFromObjectiveCySSSo8NSStringCSgFZ
+// CHECK:   [[BRIDGED_BOX:%.*]] = enum $Optional<NSString>, #Optional.some!enumelt.1, [[BRIDGED]]
+// CHECK:   [[NATIVE:%.*]] = apply [[NSSTRING_TO_STRING]]([[BRIDGED_BOX]]
+// CHECK:   [[OPT_NATIVE:%.*]] = enum $Optional<String>, #Optional.some!enumelt.1, [[NATIVE]]
+// CHECK:   br [[CONT_BB:bb[0-9]+]]([[OPT_NATIVE]] : $Optional<String>)
+//
+// CHECK: [[NONE_BB]]:
+// CHECK:   [[OPT_NATIVE:%.*]] = enum $Optional<String>, #Optional.none!enumelt
+// CHECK:   br [[CONT_BB]]([[OPT_NATIVE]] : $Optional<String>)
+//
+// CHECK: [[CONT_BB]]([[OPT_NATIVE:%.*]] : @owned $Optional<String>):
+// CHECK:   switch_enum [[OPT_NATIVE]] : $Optional<String>, case #Optional.some!enumelt.1: [[SOME_BB:bb[0-9]+]], case #Optional.none!enumelt: [[NONE_BB:bb[0-9]+]]
+//
+// CHECK: [[NONE_BB]]:
+// CHECK:   unreachable
+//
+// CHECK: [[SOME_BB]]([[NATIVE:%.*]] : @owned $String):
+// CHECK:   return [[NATIVE]]
+// CHECK: }
+
+// @interface Foo -(void) setFoo: (NSString*)s; @end
+func setFoo(_ f: Foo, s: String) {
+  var s = s
+  f.setFoo(s)
+}
+// CHECK-LABEL: sil hidden @$S13objc_bridging6setFoo{{.*}}F
+// CHECK: bb0([[ARG0:%.*]] : @guaranteed $Foo, {{%.*}} : @guaranteed $String):
+// CHECK:   [[NATIVE:%.*]] = load
+// CHECK:   [[STRING_TO_NSSTRING:%.*]] = function_ref @$SSS10FoundationE19_bridgeToObjectiveCSo8NSStringCyF
+// CHECK:   [[BORROWED_NATIVE:%.*]] = begin_borrow [[NATIVE]]
+// CHECK:   [[BRIDGED:%.*]] = apply [[STRING_TO_NSSTRING]]([[BORROWED_NATIVE]])
+// CHECK:   [[OPT_BRIDGED:%.*]] = enum $Optional<NSString>, #Optional.some!enumelt.1, [[BRIDGED]]
+// CHECK:   [[SET_FOO:%.*]] = objc_method [[ARG0]] : $Foo, #Foo.setFoo!1.foreign
+// CHECK:   apply [[SET_FOO]]([[OPT_BRIDGED]], [[ARG0]]) : $@convention(objc_method) (Optional<NSString>, Foo) -> ()
+// CHECK:   destroy_value [[OPT_BRIDGED]]
+// CHECK-NOT:   destroy_value [[ARG0]]
+// CHECK: }
+
+// @interface Foo -(BOOL) zim; @end
+func getZim(_ f: Foo) -> Bool {
+  return f.zim()
+}
+
+// CHECK-ios-i386-LABEL: sil hidden @$S13objc_bridging6getZim{{.*}}F
+// CHECK-ios-i386: bb0([[SELF:%.*]] : @guaranteed $Foo):
+// CHECK-ios-i386:   [[BORROWED_SELF:%.*]] = begin_borrow [[SELF]]
+// CHECK-ios-i386:   [[METHOD:%.*]] = objc_method [[BORROWED_SELF]] : $Foo, #Foo.zim!1.foreign : (Foo) -> () -> Bool
+// CHECK-ios-i386:   [[OBJC_BOOL:%.*]] = apply [[METHOD]]([[BORROWED_SELF]])  : $@convention(objc_method) (Foo) -> ObjCBool
+// CHECK-ios-i386:   end_borrow [[BORROWED_SELF]] from [[SELF]]
+// CHECK-ios-i386:   [[CONVERT:%.*]] = function_ref @swift_ObjCBoolToBool : $@convention(thin) (ObjCBool) -> Bool
+// CHECK-ios-i386:   [[SWIFT_BOOL:%.*]] = apply [[CONVERT]]([[OBJC_BOOL]]) : $@convention(thin) (ObjCBool) -> Bool
+// CHECK-ios-i386:   return [[SWIFT_BOOL]] : $Bool
+// CHECK-ios-i386: }
+
+// CHECK-watchos-i386-LABEL: sil hidden @$S13objc_bridging6getZim{{.*}}F
+// CHECK-watchos-i386: bb0([[SELF:%.*]] : @guaranteed $Foo):
+// CHECK-watchos-i386:   [[BORROWED_SELF:%.*]] = begin_borrow [[SELF]]
+// CHECK-watchos-i386:   [[METHOD:%.*]] = objc_method [[BORROWED_SELF]] : $Foo, #Foo.zim!1.foreign : (Foo) -> () -> Boo
+// CHECK-watchos-i386:   [[BOOL:%.*]] = apply [[METHOD]]([[BORROWED_SELF]]) : $@convention(objc_method) (Foo) -> Bool
+// CHECK-watchos-i386:   end_borrow [[BORROWED_SELF]] from [[SELF]]
+// CHECK-watchos-i386:   return [[BOOL]] : $Bool
+// CHECK-watchos-i386: }
+
+// CHECK-macosx-x86_64-LABEL: sil hidden @$S13objc_bridging6getZim{{.*}}F
+// CHECK-macosx-x86_64: bb0([[SELF:%.*]] : @guaranteed $Foo):
+// CHECK-macosx-x86_64:   [[METHOD:%.*]] = objc_method [[SELF]] : $Foo, #Foo.zim!1.foreign : (Foo) -> () -> Bool
+// CHECK-macosx-x86_64:   [[OBJC_BOOL:%.*]] = apply [[METHOD]]([[SELF]])  : $@convention(objc_method) (Foo) -> ObjCBool
+// CHECK-macosx-x86_64:   [[CONVERT:%.*]] = function_ref @swift_ObjCBoolToBool : $@convention(thin) (ObjCBool) -> Bool
+// CHECK-macosx-x86_64:   [[SWIFT_BOOL:%.*]] = apply [[CONVERT]]([[OBJC_BOOL]]) : $@convention(thin) (ObjCBool) -> Bool
+// CHECK-macosx-x86_64:   return [[SWIFT_BOOL]] : $Bool
+// CHECK-macosx-x86_64: }
+
+// CHECK-ios-x86_64-LABEL: sil hidden @$S13objc_bridging6getZim{{.*}}F
+// CHECK-ios-x86_64: bb0([[SELF:%.*]] : @guaranteed $Foo):
+// CHECK-ios-x86_64:   [[METHOD:%.*]] = objc_method [[SELF]] : $Foo, #Foo.zim!1.foreign : (Foo) -> () -> Boo
+// CHECK-ios-x86_64:   [[BOOL:%.*]] = apply [[METHOD]]([[SELF]]) : $@convention(objc_method) (Foo) -> Bool
+// CHECK-ios-x86_64:   return [[BOOL]] : $Bool
+// CHECK-ios-x86_64: }
+
+// CHECK-arm64-LABEL: sil hidden @$S13objc_bridging6getZim{{.*}}F
+// CHECK-arm64: bb0([[SELF:%.*]] : @guaranteed $Foo):
+// CHECK-arm64:   [[METHOD:%.*]] = objc_method [[SELF]] : $Foo, #Foo.zim!1.foreign : (Foo) -> () -> Boo
+// CHECK-arm64:   [[BOOL:%.*]] = apply [[METHOD]]([[SELF]]) : $@convention(objc_method) (Foo) -> Bool
+// CHECK-arm64:   return [[BOOL]] : $Bool
+// CHECK-arm64: }
+
+// @interface Foo -(void) setZim: (BOOL)b; @end
+func setZim(_ f: Foo, b: Bool) {
+  f.setZim(b)
+}
+// CHECK-ios-i386-LABEL: sil hidden @$S13objc_bridging6setZim{{.*}}F
+// CHECK-ios-i386: bb0([[ARG0:%.*]] : @guaranteed $Foo, [[ARG1:%.*]] : @trivial $Bool):
+// CHECK-ios-i386:   [[CONVERT:%.*]] = function_ref @swift_BoolToObjCBool : $@convention(thin) (Bool) -> ObjCBool
+// CHECK-ios-i386:   [[OBJC_BOOL:%.*]] = apply [[CONVERT]]([[ARG1]]) : $@convention(thin) (Bool) -> ObjCBool
+// CHECK-ios-i386:   [[METHOD:%.*]] = objc_method [[ARG0]] : $Foo, #Foo.setZim!1.foreign
+// CHECK-ios-i386:   apply [[METHOD]]([[OBJC_BOOL]], [[ARG0]]) : $@convention(objc_method) (ObjCBool, Foo) -> ()
+// CHECK-ios-i386-NOT:   destroy_value [[ARG0]]
+// CHECK-ios-i386: }
+
+// CHECK-macosx-x86_64-LABEL: sil hidden @$S13objc_bridging6setZim{{.*}}F
+// CHECK-macosx-x86_64: bb0([[ARG0:%.*]] : @guaranteed $Foo, [[ARG1:%.*]] : @trivial $Bool):
+// CHECK-macosx-x86_64:   [[CONVERT:%.*]] = function_ref @swift_BoolToObjCBool : $@convention(thin) (Bool) -> ObjCBool
+// CHECK-macosx-x86_64:   [[OBJC_BOOL:%.*]] = apply [[CONVERT]]([[ARG1]]) : $@convention(thin) (Bool) -> ObjCBool
+// CHECK-macosx-x86_64:   [[METHOD:%.*]] = objc_method [[ARG0]] : $Foo, #Foo.setZim!1.foreign
+// CHECK-macosx-x86_64:   apply [[METHOD]]([[OBJC_BOOL]], [[ARG0]]) : $@convention(objc_method) (ObjCBool, Foo) -> ()
+// CHECK-macosx-x86_64-NOT:   destroy_value [[ARG0]]
+// CHECK-macosx-x86_64: }
+
+// CHECK-ios-x86_64-LABEL: sil hidden @$S13objc_bridging6setZim{{.*}}F
+// CHECK-ios-x86_64: bb0([[ARG0:%.*]] : @guaranteed $Foo, [[ARG1:%.*]] : @trivial $Bool):
+// CHECK-ios-x86_64:   [[METHOD:%.*]] = objc_method [[ARG0]] : $Foo, #Foo.setZim!1.foreign
+// CHECK-ios-x86_64:   apply [[METHOD]]([[ARG1]], [[ARG0]]) : $@convention(objc_method) (Bool, Foo) -> ()
+// CHECK-ios-x86_64-NOT:   destroy_value [[ARG0]]
+// CHECK-ios-x86_64: }
+
+// CHECK-arm64-LABEL: sil hidden @$S13objc_bridging6setZim{{.*}}F
+// CHECK-arm64: bb0([[ARG0:%.*]] : @guaranteed $Foo, [[ARG1:%.*]] : @trivial $Bool):
+// CHECK-arm64:   [[BORROWED_ARG0:%.*]] = begin_borrow [[ARG0]]
+// CHECK-arm64:   [[METHOD:%.*]] = objc_method [[BORROWED_ARG0]] : $Foo, #Foo.setZim!1.foreign
+// CHECK-arm64:   apply [[METHOD]]([[ARG1]], [[BORROWED_ARG0]]) : $@convention(objc_method) (Bool, Foo) -> ()
+// CHECK-arm64:   end_borrow [[BORROWED_ARG0]] from [[ARG0]]
+// CHECK-arm64:   destroy_value [[ARG0]]
+// CHECK-arm64: }
+
+// CHECK-watchos-i386-LABEL: sil hidden @$S13objc_bridging6setZim{{.*}}F
+// CHECK-watchos-i386: bb0([[ARG0:%.*]] : @guaranteed $Foo, [[ARG1:%.*]] : @trivial $Bool):
+// CHECK-watchos-i386:   [[BORROWED_ARG0:%.*]] = begin_borrow [[ARG0]]
+// CHECK-watchos-i386:   [[METHOD:%.*]] = objc_method [[BORROWED_ARG0]] : $Foo, #Foo.setZim!1.foreign
+// CHECK-watchos-i386:   apply [[METHOD]]([[ARG1]], [[BORROWED_ARG0]]) : $@convention(objc_method) (Bool, Foo) -> ()
+// CHECK-watchos-i386:   end_borrow [[BORROWED_ARG0]] from [[ARG0]]
+// CHECK-watchos-i386:   destroy_value [[ARG0]]
+// CHECK-watchos-i386: }
+
+// @interface Foo -(_Bool) zang; @end
+func getZang(_ f: Foo) -> Bool {
+  return f.zang()
+}
+// CHECK-LABEL: sil hidden @$S13objc_bridging7getZangySbSo3FooCF
+// CHECK: bb0([[ARG:%.*]] : @guaranteed $Foo)
+// CHECK:   [[METHOD:%.*]] = objc_method [[ARG]] : $Foo, #Foo.zang!1.foreign
+// CHECK:   [[BOOL:%.*]] = apply [[METHOD]]([[ARG]]) : $@convention(objc_method) (Foo) -> Bool
+// CHECK-NOT:   destroy_value [[ARG]]
+// CHECK:   return [[BOOL]]
+
+// @interface Foo -(void) setZang: (_Bool)b; @end
+func setZang(_ f: Foo, _ b: Bool) {
+  f.setZang(b)
+}
+// CHECK-LABEL: sil hidden @$S13objc_bridging7setZangyySo3FooC_SbtF
+// CHECK: bb0([[ARG0:%.*]] : @guaranteed $Foo, [[ARG1:%.*]] : @trivial $Bool):
+// CHECK:   [[METHOD:%.*]] = objc_method [[ARG0]] : $Foo, #Foo.setZang!1.foreign
+// CHECK:   apply [[METHOD]]([[ARG1]], [[ARG0]]) : $@convention(objc_method) (Bool, Foo) -> ()
+// CHECK-NOT:   destroy_value [[ARG0]]
+// CHECK: } // end sil function '$S13objc_bridging7setZangyySo3FooC_SbtF'
+
+// NSString *bar(void);
+func callBar() -> String {
+  return bar()
+}
+// CHECK-LABEL: sil hidden @$S13objc_bridging7callBar{{.*}}F
+// CHECK: bb0:
+// CHECK:   [[BAR:%.*]] = function_ref @bar
+// CHECK:   [[OPT_BRIDGED:%.*]] = apply [[BAR]]() : $@convention(c) () -> @autoreleased Optional<NSString>
+// CHECK:   switch_enum [[OPT_BRIDGED]] : $Optional<NSString>, case #Optional.some!enumelt.1: [[SOME_BB:bb[0-9]+]], case #Optional.none!enumelt: [[NONE_BB:bb[0-9]+]]
+
+// CHECK: [[SOME_BB]]([[BRIDGED:%.*]] : @owned $NSString):
+// CHECK:   [[NSSTRING_TO_STRING:%.*]] = function_ref @$SSS10FoundationE36_unconditionallyBridgeFromObjectiveCySSSo8NSStringCSgFZ
+// CHECK:   [[BRIDGED_BOX:%.*]] = enum $Optional<NSString>, #Optional.some!enumelt.1, [[BRIDGED]]
+// CHECK:   [[NATIVE:%.*]] = apply [[NSSTRING_TO_STRING]]([[BRIDGED_BOX]]
+// CHECK:   [[OPT_NATIVE:%.*]] = enum $Optional<String>, #Optional.some!enumelt.1, [[NATIVE]]
+// CHECK:   bb5([[NATIVE:%.*]] : @owned $String):
+// CHECK:   return [[NATIVE]]
+// CHECK: }
+
+// void setBar(NSString *s);
+func callSetBar(_ s: String) {
+  var s = s
+  setBar(s)
+}
+// CHECK-LABEL: sil hidden @$S13objc_bridging10callSetBar{{.*}}F
+// CHECK: bb0({{%.*}} : @guaranteed $String):
+// CHECK:   [[NATIVE:%.*]] = load
+// CHECK:   [[STRING_TO_NSSTRING:%.*]] = function_ref @$SSS10FoundationE19_bridgeToObjectiveCSo8NSStringCyF
+// CHECK:   [[BORROWED_NATIVE:%.*]] = begin_borrow [[NATIVE]]
+// CHECK:   [[BRIDGED:%.*]] = apply [[STRING_TO_NSSTRING]]([[BORROWED_NATIVE]])
+// CHECK:   [[OPT_BRIDGED:%.*]] = enum $Optional<NSString>, #Optional.some!enumelt.1, [[BRIDGED]]
+// CHECK:   end_borrow [[BORROWED_NATIVE]] from [[NATIVE]]
+// CHECK:   [[SET_BAR:%.*]] = function_ref @setBar
+// CHECK:   apply [[SET_BAR]]([[OPT_BRIDGED]])
+// CHECK:   destroy_value [[OPT_BRIDGED]]
+// CHECK: }
+
+var NSS: NSString
+
+// -- NSString methods don't convert 'self'
+extension NSString {
+  var nsstrFakeProp: NSString {
+    get { return NSS }
+    set {}
+  }
+  // CHECK-LABEL: sil hidden [thunk] @$SSo8NSStringC13objc_bridgingE13nsstrFakePropABvgTo
+  // CHECK-NOT: swift_StringToNSString
+  // CHECK-NOT: $SSS10FoundationE36_unconditionallyBridgeFromObjectiveCySSSo8NSStringCSgFZ
+  // CHECK: }
+  // CHECK-LABEL: sil hidden [thunk] @$SSo8NSStringC13objc_bridgingE13nsstrFakePropABvsTo
+  // CHECK-NOT: swift_StringToNSString
+  // CHECK-NOT: $SSS10FoundationE36_unconditionallyBridgeFromObjectiveCySSSo8NSStringCSgFZ
+  // CHECK: }
+
+  func nsstrResult() -> NSString { return NSS }
+  // CHECK-LABEL: sil hidden [thunk] @$SSo8NSStringC13objc_bridgingE11nsstrResultAByFTo
+  // CHECK-NOT: swift_StringToNSString
+  // CHECK-NOT: $SSS10FoundationE36_unconditionallyBridgeFromObjectiveCySSSo8NSStringCSgFZ
+  // CHECK: }
+
+  func nsstrArg(_ s: NSString) { }
+  // CHECK-LABEL: sil hidden [thunk] @$SSo8NSStringC13objc_bridgingE8nsstrArgyyABFTo
+  // CHECK-NOT: swift_StringToNSString
+  // CHECK-NOT: $SSS10FoundationE36_unconditionallyBridgeFromObjectiveCySSSo8NSStringCSgFZ
+  // CHECK: }
+
+}
+
+class Bas : NSObject {
+  // -- Bridging thunks for String properties convert between NSString
+  var strRealProp: String = "Hello"
+  // CHECK-LABEL: sil hidden [thunk] @$S13objc_bridging3BasC11strRealPropSSvgTo : $@convention(objc_method) (Bas) -> @autoreleased NSString {
+  // CHECK: bb0([[THIS:%.*]] : @unowned $Bas):
+  // CHECK:   [[THIS_COPY:%.*]] = copy_value [[THIS]] : $Bas
+  // CHECK:   [[BORROWED_THIS_COPY:%.*]] = begin_borrow [[THIS_COPY]]
+  // CHECK:   // function_ref objc_bridging.Bas.strRealProp.getter
+  // CHECK:   [[PROPIMPL:%.*]] = function_ref @$S13objc_bridging3BasC11strRealPropSSvg
+  // CHECK:   [[PROP_COPY:%.*]] = apply [[PROPIMPL]]([[BORROWED_THIS_COPY]]) : $@convention(method) (@guaranteed Bas) -> @owned String
+  // CHECK:   end_borrow [[BORROWED_THIS_COPY]] from [[THIS_COPY]]
+  // CHECK:   destroy_value [[THIS_COPY]]
+  // CHECK:   [[STRING_TO_NSSTRING:%.*]] = function_ref @$SSS10FoundationE19_bridgeToObjectiveCSo8NSStringCyF
+  // CHECK:   [[BORROWED_PROP_COPY:%.*]] = begin_borrow [[PROP_COPY]]
+  // CHECK:   [[NSSTR:%.*]] = apply [[STRING_TO_NSSTRING]]([[BORROWED_PROP_COPY]])
+  // CHECK:   end_borrow [[BORROWED_PROP_COPY]] from [[PROP_COPY]]
+  // CHECK:   destroy_value [[PROP_COPY]]
+  // CHECK:   return [[NSSTR]]
+  // CHECK: }
+
+
+  // CHECK-LABEL: sil hidden @$S13objc_bridging3BasC11strRealPropSSvg
+  // CHECK:   [[PROP_ADDR:%.*]] = ref_element_addr %0 : {{.*}}, #Bas.strRealProp
+  // CHECK:   [[READ:%.*]] = begin_access [read] [dynamic] [[PROP_ADDR]] : $*String
+  // CHECK:   [[PROP:%.*]] = load [copy] [[READ]]
+
+
+  // CHECK-LABEL: sil hidden [thunk] @$S13objc_bridging3BasC11strRealPropSSvsTo : $@convention(objc_method) (NSString, Bas) -> () {
+  // CHECK: bb0([[VALUE:%.*]] : @unowned $NSString, [[THIS:%.*]] : @unowned $Bas):
+  // CHECK:   [[VALUE_COPY:%.*]] = copy_value [[VALUE]]
+  // CHECK:   [[THIS_COPY:%.*]] = copy_value [[THIS]]
+  // CHECK:   [[NSSTRING_TO_STRING:%.*]] = function_ref @$SSS10FoundationE36_unconditionallyBridgeFromObjectiveCySSSo8NSStringCSgFZ
+  // CHECK:   [[VALUE_BOX:%.*]] = enum $Optional<NSString>, #Optional.some!enumelt.1, [[VALUE_COPY]]
+  // CHECK:   [[STR:%.*]] = apply [[NSSTRING_TO_STRING]]([[VALUE_BOX]]
+
+  // CHECK:   [[BORROWED_THIS_COPY:%.*]] = begin_borrow [[THIS_COPY]]
+  // CHECK:   [[SETIMPL:%.*]] = function_ref @$S13objc_bridging3BasC11strRealPropSSvs
+  // CHECK:   apply [[SETIMPL]]([[STR]], [[BORROWED_THIS_COPY]])
+  // CHECK:   end_borrow [[BORROWED_THIS_COPY]] from [[THIS_COPY]]
+  // CHECK:   destroy_value [[THIS_COPY]]
+  // CHECK: } // end sil function '$S13objc_bridging3BasC11strRealPropSSvsTo'
+
+  // CHECK-LABEL: sil hidden @$S13objc_bridging3BasC11strRealPropSSvs
+  // CHECK: bb0(%0 : @owned $String, %1 : @guaranteed $Bas):
+
+  // CHECK:   [[STR_ADDR:%.*]] = ref_element_addr %1 : {{.*}}, #Bas.strRealProp
+  // CHECK:   [[WRITE:%.*]] = begin_access [modify] [dynamic] [[STR_ADDR]] : $*String
+  // CHECK:   assign {{.*}} to [[WRITE]]
+  // CHECK: }
+
+  var strFakeProp: String {
+    get { return "" }
+    set {}
+  }
+  // CHECK-LABEL: sil hidden [thunk] @$S13objc_bridging3BasC11strFakePropSSvgTo : $@convention(objc_method) (Bas) -> @autoreleased NSString {
+  // CHECK: bb0([[THIS:%.*]] : @unowned $Bas):
+  // CHECK:   [[THIS_COPY:%.*]] = copy_value [[THIS]]
+  // CHECK:   [[BORROWED_THIS_COPY:%.*]] = begin_borrow [[THIS_COPY]]
+  // CHECK:   [[GETTER:%.*]] = function_ref @$S13objc_bridging3BasC11strFakePropSSvg
+  // CHECK:   [[STR:%.*]] = apply [[GETTER]]([[BORROWED_THIS_COPY]])
+  // CHECK:   end_borrow [[BORROWED_THIS_COPY]] from [[THIS_COPY]]
+  // CHECK:   destroy_value [[THIS_COPY]]
+  // CHECK:   [[STRING_TO_NSSTRING:%.*]] = function_ref @$SSS10FoundationE19_bridgeToObjectiveCSo8NSStringCyF
+  // CHECK:   [[BORROWED_STR:%.*]] = begin_borrow [[STR]]
+  // CHECK:   [[NSSTR:%.*]] = apply [[STRING_TO_NSSTRING]]([[BORROWED_STR]])
+  // CHECK:   end_borrow [[BORROWED_STR]] from [[STR]]
+  // CHECK:   destroy_value [[STR]]
+  // CHECK:   return [[NSSTR]]
+  // CHECK: }
+
+  // CHECK-LABEL: sil hidden [thunk] @$S13objc_bridging3BasC11strFakePropSSvsTo : $@convention(objc_method) (NSString, Bas) -> () {
+  // CHECK: bb0([[NSSTR:%.*]] : @unowned $NSString, [[THIS:%.*]] : @unowned $Bas):
+  // CHECK:   [[NSSTR_COPY:%.*]] = copy_value [[NSSTR]]
+  // CHECK:   [[THIS_COPY:%.*]] = copy_value [[THIS]]
+  // CHECK:   [[NSSTRING_TO_STRING:%.*]] = function_ref @$SSS10FoundationE36_unconditionallyBridgeFromObjectiveCySSSo8NSStringCSgFZ
+  // CHECK:   [[NSSTR_BOX:%.*]] = enum $Optional<NSString>, #Optional.some!enumelt.1, [[NSSTR_COPY]]
+  // CHECK:   [[STR:%.*]] = apply [[NSSTRING_TO_STRING]]([[NSSTR_BOX]]
+  // CHECK:   [[BORROWED_THIS_COPY:%.*]] = begin_borrow [[THIS_COPY]]
+  // CHECK:   [[SETTER:%.*]] = function_ref @$S13objc_bridging3BasC11strFakePropSSvs
+  // CHECK:   apply [[SETTER]]([[STR]], [[BORROWED_THIS_COPY]])
+  // CHECK:   end_borrow [[BORROWED_THIS_COPY]] from [[THIS_COPY]]
+  // CHECK:   destroy_value [[THIS_COPY]]
+  // CHECK: } // end sil function '$S13objc_bridging3BasC11strFakePropSSvsTo'
+
+  // -- Bridging thunks for explicitly NSString properties don't convert
+  var nsstrRealProp: NSString
+  var nsstrFakeProp: NSString {
+    get { return NSS }
+    set {}
+  }
+  // CHECK-LABEL: sil hidden [thunk] @$S13objc_bridging3BasC13nsstrRealPropSo8NSStringCvgTo : $@convention(objc_method) (Bas) -> @autoreleased NSString {
+  // CHECK-NOT: swift_StringToNSString
+  // CHECK-NOT: $SSS10FoundationE36_unconditionallyBridgeFromObjectiveCySSSo8NSStringCSgFZ
+  // CHECK: }
+
+  // CHECK-LABEL: sil hidden [thunk] @$S13objc_bridging3BasC13nsstrRealPropSo8NSStringCvsTo : $@convention(objc_method) (NSString, Bas) ->
+  // CHECK-NOT: swift_StringToNSString
+  // CHECK-NOT: $SSS10FoundationE36_unconditionallyBridgeFromObjectiveCySSSo8NSStringCSgFZ
+  // CHECK: }
+
+  // -- Bridging thunks for String methods convert between NSString
+  func strResult() -> String { return "" }
+  // CHECK-LABEL: sil hidden [thunk] @$S13objc_bridging3BasC9strResultSSyFTo
+  // CHECK: bb0([[THIS:%.*]] : @unowned $Bas):
+  // CHECK:   [[THIS_COPY:%.*]] = copy_value [[THIS]]
+  // CHECK:   [[BORROWED_THIS_COPY:%.*]] = begin_borrow [[THIS_COPY]]
+  // CHECK:   [[METHOD:%.*]] = function_ref @$S13objc_bridging3BasC9strResultSSyF
+  // CHECK:   [[STR:%.*]] = apply [[METHOD]]([[BORROWED_THIS_COPY]])
+  // CHECK:   end_borrow [[BORROWED_THIS_COPY]] from [[THIS_COPY]]
+  // CHECK:   destroy_value [[THIS_COPY]]
+  // CHECK:   [[STRING_TO_NSSTRING:%.*]] = function_ref @$SSS10FoundationE19_bridgeToObjectiveCSo8NSStringCyF
+  // CHECK:   [[BORROWED_STR:%.*]] = begin_borrow [[STR]]
+  // CHECK:   [[NSSTR:%.*]] = apply [[STRING_TO_NSSTRING]]([[BORROWED_STR]])
+  // CHECK:   end_borrow [[BORROWED_STR]] from [[STR]]
+  // CHECK:   destroy_value [[STR]]
+  // CHECK:   return [[NSSTR]]
+  // CHECK: }
+  func strArg(_ s: String) { }
+  // CHECK-LABEL: sil hidden [thunk] @$S13objc_bridging3BasC6strArgyySSFTo
+  // CHECK: bb0([[NSSTR:%.*]] : @unowned $NSString, [[THIS:%.*]] : @unowned $Bas):
+  // CHECK:   [[NSSTR_COPY:%.*]] = copy_value [[NSSTR]]
+  // CHECK:   [[THIS_COPY:%.*]] = copy_value [[THIS]]
+  // CHECK:   [[NSSTRING_TO_STRING:%.*]] = function_ref @$SSS10FoundationE36_unconditionallyBridgeFromObjectiveCySSSo8NSStringCSgFZ
+  // CHECK:   [[NSSTR_BOX:%.*]] = enum $Optional<NSString>, #Optional.some!enumelt.1, [[NSSTR_COPY]]
+  // CHECK:   [[STR:%.*]] = apply [[NSSTRING_TO_STRING]]([[NSSTR_BOX]]
+  // CHECK:   [[BORROWED_STR:%.*]] = begin_borrow [[STR]]
+  // CHECK:   [[BORROWED_THIS_COPY:%.*]] = begin_borrow [[THIS_COPY]]
+  // CHECK:   [[METHOD:%.*]] = function_ref @$S13objc_bridging3BasC6strArgyySSF
+  // CHECK:   apply [[METHOD]]([[BORROWED_STR]], [[BORROWED_THIS_COPY]])
+  // CHECK:   end_borrow [[BORROWED_THIS_COPY]] from [[THIS_COPY]]
+  // CHECK:   destroy_value [[THIS_COPY]]
+  // CHECK: } // end sil function '$S13objc_bridging3BasC6strArgyySSFTo'
+
+  // -- Bridging thunks for explicitly NSString properties don't convert
+  func nsstrResult() -> NSString { return NSS }
+  // CHECK-LABEL: sil hidden [thunk] @$S13objc_bridging3BasC11nsstrResultSo8NSStringCyFTo
+  // CHECK-NOT: swift_StringToNSString
+  // CHECK-NOT: $SSS10FoundationE36_unconditionallyBridgeFromObjectiveCySSSo8NSStringCSgFZ
+  // CHECK: }
+  func nsstrArg(_ s: NSString) { }
+  // CHECK-LABEL: sil hidden @$S13objc_bridging3BasC8nsstrArgyySo8NSStringCF
+  // CHECK-NOT: swift_StringToNSString
+  // CHECK-NOT: $SSS10FoundationE36_unconditionallyBridgeFromObjectiveCySSSo8NSStringCSgFZ
+  // CHECK: }
+
+  init(str: NSString) {
+    nsstrRealProp = str
+    super.init()
+  }
+
+  // CHECK-LABEL: sil hidden [thunk] @$S13objc_bridging3BasC8arrayArgyySayyXlGFTo : $@convention(objc_method) (NSArray, Bas) -> ()
+  // CHECK: bb0([[NSARRAY:%[0-9]+]] : @unowned $NSArray, [[SELF:%[0-9]+]] : @unowned $Bas):
+  // CHECK:   [[NSARRAY_COPY:%.*]] = copy_value [[NSARRAY]] : $NSArray
+  // CHECK:   [[SELF_COPY:%.*]] = copy_value [[SELF]] : $Bas
+  // CHECK:   [[CONV_FN:%[0-9]+]] = function_ref @$SSa10FoundationE36_unconditionallyBridgeFromObjectiveCySayxGSo7NSArrayCSgFZ
+  // CHECK:   [[OPT_NSARRAY:%[0-9]+]] = enum $Optional<NSArray>, #Optional.some!enumelt.1, [[NSARRAY_COPY]] : $NSArray
+  // CHECK:   [[ARRAY_META:%[0-9]+]] = metatype $@thin Array<AnyObject>.Type
+  // CHECK:   [[ARRAY:%[0-9]+]] = apply [[CONV_FN]]<AnyObject>([[OPT_NSARRAY]], [[ARRAY_META]])
+  // CHECK:   [[BORROWED_ARRAY:%.*]] = begin_borrow [[ARRAY]]
+  // CHECK:   [[BORROWED_SELF_COPY:%.*]] = begin_borrow [[SELF_COPY]]
+  // CHECK:   [[SWIFT_FN:%[0-9]+]] = function_ref @$S13objc_bridging3BasC8arrayArgyySayyXlGF : $@convention(method) (@guaranteed Array<AnyObject>, @guaranteed Bas) -> ()
+  // CHECK:   [[RESULT:%[0-9]+]] = apply [[SWIFT_FN]]([[BORROWED_ARRAY]], [[BORROWED_SELF_COPY]]) : $@convention(method) (@guaranteed Array<AnyObject>, @guaranteed Bas) -> ()
+  // CHECK:   end_borrow [[BORROWED_SELF_COPY]] from [[SELF_COPY]]
+  // CHECK:   destroy_value [[SELF_COPY]] : $Bas
+  // CHECK:   return [[RESULT]] : $()
+  func arrayArg(_ array: [AnyObject]) { }
+  
+  // CHECK-LABEL: sil hidden [thunk] @$S13objc_bridging3BasC11arrayResultSayyXlGyFTo : $@convention(objc_method) (Bas) -> @autoreleased NSArray
+  // CHECK: bb0([[SELF:%[0-9]+]] : @unowned $Bas):
+  // CHECK:   [[SELF_COPY:%.*]] = copy_value [[SELF]] : $Bas
+  // CHECK:   [[BORROWED_SELF_COPY:%.*]] = begin_borrow [[SELF_COPY]]
+  // CHECK:   [[SWIFT_FN:%[0-9]+]] = function_ref @$S13objc_bridging3BasC11arrayResultSayyXlGyF : $@convention(method) (@guaranteed Bas) -> @owned Array<AnyObject>
+  // CHECK:   [[ARRAY:%[0-9]+]] = apply [[SWIFT_FN]]([[BORROWED_SELF_COPY]]) : $@convention(method) (@guaranteed Bas) -> @owned Array<AnyObject>
+  // CHECK:   end_borrow [[BORROWED_SELF_COPY]] from [[SELF_COPY]]
+  // CHECK:   destroy_value [[SELF_COPY]]
+  // CHECK:   [[CONV_FN:%[0-9]+]] = function_ref @$SSa10FoundationE19_bridgeToObjectiveCSo7NSArrayCyF
+  // CHECK:   [[BORROWED_ARRAY:%.*]] = begin_borrow [[ARRAY]]
+  // CHECK:   [[NSARRAY:%[0-9]+]] = apply [[CONV_FN]]<AnyObject>([[BORROWED_ARRAY]]) : $@convention(method) <τ_0_0> (@guaranteed Array<τ_0_0>) -> @owned NSArray
+  // CHECK:   end_borrow [[BORROWED_ARRAY]] from [[ARRAY]]
+  // CHECK:   destroy_value [[ARRAY]]
+  // CHECK:   return [[NSARRAY]]
+  func arrayResult() -> [AnyObject] { return [] }
+
+  // CHECK-LABEL: sil hidden [thunk] @$S13objc_bridging3BasC9arrayPropSaySSGvgTo : $@convention(objc_method) (Bas) -> @autoreleased NSArray
+  // CHECK-LABEL: sil hidden [thunk] @$S13objc_bridging3BasC9arrayPropSaySSGvsTo : $@convention(objc_method) (NSArray, Bas) -> ()
+  var arrayProp: [String] = []
+}
+
+// CHECK-LABEL: sil hidden @$S13objc_bridging16applyStringBlock_1xS3SXB_SStF
+func applyStringBlock(_ f: @convention(block) (String) -> String, x: String) -> String {
+  // CHECK: bb0([[BLOCK:%.*]] : @guaranteed $@convention(block) @noescape (NSString) -> @autoreleased NSString, [[STRING:%.*]] : @guaranteed $String):
+  // CHECK:   [[BLOCK_COPY:%.*]] = copy_block [[BLOCK]]
+  // CHECK:   [[BORROWED_BLOCK_COPY:%.*]] = begin_borrow [[BLOCK_COPY]]
+  // CHECK:   [[BLOCK_COPY_COPY:%.*]] = copy_value [[BORROWED_BLOCK_COPY]]
+  // CHECK:   [[STRING_COPY:%.*]] = copy_value [[STRING]]
+  // CHECK:   [[STRING_TO_NSSTRING:%.*]] = function_ref @$SSS10FoundationE19_bridgeToObjectiveCSo8NSStringCyF
+  // CHECK:   [[BORROWED_STRING_COPY:%.*]] = begin_borrow [[STRING_COPY]]
+  // CHECK:   [[NSSTR:%.*]] = apply [[STRING_TO_NSSTRING]]([[BORROWED_STRING_COPY]]) : $@convention(method) (@guaranteed String)
+  // CHECK:   end_borrow [[BORROWED_STRING_COPY]] from [[STRING_COPY]]
+  // CHECK:   destroy_value [[STRING_COPY]]
+  // CHECK:   [[RESULT_NSSTR:%.*]] = apply [[BLOCK_COPY_COPY]]([[NSSTR]]) : $@convention(block) @noescape (NSString) -> @autoreleased NSString
+  // CHECK:   destroy_value [[NSSTR]]
+  // CHECK:   [[FINAL_BRIDGE:%.*]] = function_ref @$SSS10FoundationE36_unconditionallyBridgeFromObjectiveCySSSo8NSStringCSgFZ
+  // CHECK:   [[OPTIONAL_NSSTR:%.*]] = enum $Optional<NSString>, #Optional.some!enumelt.1, [[RESULT_NSSTR]]
+  // CHECK:   [[RESULT:%.*]] = apply [[FINAL_BRIDGE]]([[OPTIONAL_NSSTR]], {{.*}}) : $@convention(method) (@guaranteed Optional<NSString>, @thin String.Type) -> @owned String
+  // CHECK:   destroy_value [[BLOCK_COPY_COPY]]
+  // CHECK-NOT:   destroy_value [[STRING]]
+  // CHECK:   destroy_value [[BLOCK_COPY]]
+  // CHECK-NOT:   destroy_value [[BLOCK]]
+  // CHECK:   return [[RESULT]] : $String
+  return f(x)
+}
+// CHECK: } // end sil function '$S13objc_bridging16applyStringBlock_1xS3SXB_SStF'
+
+// CHECK-LABEL: sil hidden @$S13objc_bridging15bridgeCFunction{{.*}}F
+func bridgeCFunction() -> (String?) -> (String?) {
+  // CHECK: [[THUNK:%.*]] = function_ref @$SSo18NSStringFromStringySSSgABFTO : $@convention(thin) (@guaranteed Optional<String>) -> @owned Optional<String>
+  // CHECK: [[THICK:%.*]] = thin_to_thick_function [[THUNK]]
+  // CHECK: return [[THICK]]
+  return NSStringFromString
+}
+
+func forceNSArrayMembers() -> (NSArray, NSArray) {
+  let x = NSArray(objects: nil, count: 0)
+  return (x, x)
+}
+
+// Check that the allocating initializer shim for initializers that take pointer
+// arguments lifetime-extends the bridged pointer for the right duration.
+// <rdar://problem/16738050>
+
+// CHECK-LABEL: sil shared [serializable] @$SSo7NSArrayC7objects5countABSPyyXlSgGSg_s5Int32VtcfC
+// CHECK:         [[SELF:%.*]] = alloc_ref_dynamic
+// CHECK:         [[METHOD:%.*]] = function_ref @$SSo7NSArrayC7objects5countABSPyyXlSgGSg_s5Int32VtcfcTO
+// CHECK:         [[RESULT:%.*]] = apply [[METHOD]]
+// CHECK:         return [[RESULT]]
+
+// Check that type lowering preserves the bool/BOOL distinction when bridging
+// imported C functions.
+
+// CHECK-ios-i386-LABEL: sil hidden @$S13objc_bridging5boolsySb_SbtSbF
+// CHECK-ios-i386:         function_ref @useBOOL : $@convention(c) (ObjCBool) -> ()
+// CHECK-ios-i386:         function_ref @useBool : $@convention(c) (Bool) -> ()
+// CHECK-ios-i386:         function_ref @getBOOL : $@convention(c) () -> ObjCBool
+// CHECK-ios-i386:         function_ref @getBool : $@convention(c) () -> Bool
+
+// CHECK-macosx-x86_64-LABEL: sil hidden @$S13objc_bridging5boolsySb_SbtSbF
+// CHECK-macosx-x86_64:         function_ref @useBOOL : $@convention(c) (ObjCBool) -> ()
+// CHECK-macosx-x86_64:         function_ref @useBool : $@convention(c) (Bool) -> ()
+// CHECK-macosx-x86_64:         function_ref @getBOOL : $@convention(c) () -> ObjCBool
+// CHECK-macosx-x86_64:         function_ref @getBool : $@convention(c) () -> Bool
+
+// FIXME: no distinction on x86_64, arm64 or watchos-i386, since SILGen looks
+// at the underlying Clang decl of the bridged decl to decide whether it needs
+// bridging.
+//
+// CHECK-watchos-i386-LABEL: sil hidden @$S13objc_bridging5boolsySb_SbtSbF
+// CHECK-watchos-i386:         function_ref @useBOOL : $@convention(c) (Bool) -> ()
+// CHECK-watchos-i386:         function_ref @useBool : $@convention(c) (Bool) -> ()
+// CHECK-watchos-i386:         function_ref @getBOOL : $@convention(c) () -> Bool
+// CHECK-watchos-i386:         function_ref @getBool : $@convention(c) () -> Bool
+
+// CHECK-ios-x86_64-LABEL: sil hidden @$S13objc_bridging5boolsySb_SbtSbF
+// CHECK-ios-x86_64:         function_ref @useBOOL : $@convention(c) (Bool) -> ()
+// CHECK-ios-x86_64:         function_ref @useBool : $@convention(c) (Bool) -> ()
+// CHECK-ios-x86_64:         function_ref @getBOOL : $@convention(c) () -> Bool
+// CHECK-ios-x86_64:         function_ref @getBool : $@convention(c) () -> Bool
+
+// CHECK-arm64-LABEL: sil hidden @$S13objc_bridging5boolsySb_SbtSbF
+// CHECK-arm64:         function_ref @useBOOL : $@convention(c) (Bool) -> ()
+// CHECK-arm64:         function_ref @useBool : $@convention(c) (Bool) -> ()
+// CHECK-arm64:         function_ref @getBOOL : $@convention(c) () -> Bool
+// CHECK-arm64:         function_ref @getBool : $@convention(c) () -> Bool
+
+func bools(_ x: Bool) -> (Bool, Bool) {
+  useBOOL(x)
+  useBool(x)
+
+  return (getBOOL(), getBool())
+}
+
+// CHECK-LABEL: sil hidden @$S13objc_bridging9getFridge{{.*}}F
+// CHECK: bb0([[HOME:%[0-9]+]] : @guaranteed $APPHouse):
+func getFridge(_ home: APPHouse) -> Refrigerator {
+  // CHECK: [[GETTER:%[0-9]+]] = objc_method [[HOME]] : $APPHouse, #APPHouse.fridge!getter.1.foreign
+  // CHECK: [[OBJC_RESULT:%[0-9]+]] = apply [[GETTER]]([[HOME]])
+  // CHECK: [[BRIDGE_FN:%[0-9]+]] = function_ref @$S10Appliances12RefrigeratorV36_unconditionallyBridgeFromObjectiveCyACSo15APPRefrigeratorCSgFZ
+  // CHECK: [[REFRIGERATOR_META:%[0-9]+]] = metatype $@thin Refrigerator.Type
+  // CHECK: [[RESULT:%[0-9]+]] = apply [[BRIDGE_FN]]([[OBJC_RESULT]], [[REFRIGERATOR_META]])
+  // CHECK-NOT: destroy_value [[HOME]] : $APPHouse
+  // CHECK: return [[RESULT]] : $Refrigerator
+  return home.fridge
+}
+
+// FIXME(integers): the following checks should be updated for the new integer
+// protocols. <rdar://problem/29939484>
+// XCHECK-LABEL: sil hidden @$S13objc_bridging16updateFridgeTemp{{.*}}F
+// XCHECK: bb0([[HOME:%[0-9]+]] : $APPHouse, [[DELTA:%[0-9]+]] : $Double):
+func updateFridgeTemp(_ home: APPHouse, delta: Double) {
+  // +=
+  // XCHECK: [[PLUS_EQ:%[0-9]+]] = function_ref @$Ss2peoiyySdz_SdtF
+
+  // Temporary fridge
+  // XCHECK: [[TEMP_FRIDGE:%[0-9]+]]  = alloc_stack $Refrigerator
+
+  // Get operation
+  // CHECK: [[GETTER:%[0-9]+]] = objc_method [[HOME]] : $APPHouse, #APPHouse.fridge!getter.1.foreign
+  // CHECK: [[OBJC_FRIDGE:%[0-9]+]] = apply [[GETTER]]([[HOME]])
+  // CHECK: [[BRIDGE_FROM_FN:%[0-9]+]] = function_ref @$S10Appliances12RefrigeratorV36_unconditionallyBridgeFromObjectiveCyACSo15APPRefrigeratorCSgFZ
+  // CHECK: [[REFRIGERATOR_META:%[0-9]+]] = metatype $@thin Refrigerator.Type
+  // CHECK: [[FRIDGE:%[0-9]+]] = apply [[BRIDGE_FROM_FN]]([[OBJC_FRIDGE]], [[REFRIGERATOR_META]])
+
+  // Addition
+  // XCHECK: [[TEMP:%[0-9]+]] = struct_element_addr [[TEMP_FRIDGE]] : $*Refrigerator, #Refrigerator.temperature
+  // XCHECK: apply [[PLUS_EQ]]([[TEMP]], [[DELTA]])
+
+  // Setter
+  // XCHECK: [[FRIDGE:%[0-9]+]] = load [trivial] [[TEMP_FRIDGE]] : $*Refrigerator
+  // XCHECK: [[SETTER:%[0-9]+]] = objc_method [[BORROWED_HOME]] : $APPHouse, #APPHouse.fridge!setter.1.foreign
+  // XCHECK: [[BRIDGE_TO_FN:%[0-9]+]] = function_ref @$S10Appliances12RefrigeratorV19_bridgeToObjectiveCSo15APPRefrigeratorCyF
+  // XCHECK: [[OBJC_ARG:%[0-9]+]] = apply [[BRIDGE_TO_FN]]([[FRIDGE]])
+  // XCHECK: apply [[SETTER]]([[OBJC_ARG]], [[BORROWED_HOME]]) : $@convention(objc_method) (APPRefrigerator, APPHouse) -> ()
+  // XCHECK: destroy_value [[OBJC_ARG]]
+  // XCHECK: end_borrow [[BORROWED_HOME]] from [[HOME]]
+  // XCHECK: destroy_value [[HOME]]
+  home.fridge.temperature += delta
+}
+
+// CHECK-LABEL: sil hidden @$S13objc_bridging20callNonStandardBlock5valueySi_tF
+func callNonStandardBlock(value: Int) {
+  // CHECK: enum $Optional<@convention(block) () -> @owned Optional<AnyObject>>
+  takesNonStandardBlock { return value }
+}
+
+func takeTwoAnys(_ lhs: Any, _ rhs: Any) -> Any { return lhs }
+
+// CHECK-LABEL: sil hidden @$S13objc_bridging22defineNonStandardBlock1xyyp_tF
+func defineNonStandardBlock(x: Any) {
+  // CHECK: function_ref @$S13objc_bridging22defineNonStandardBlock1xyyp_tFypypcfU_
+  // CHECK: function_ref @$SypypIegnr_yXlyXlIeyBya_TR : $@convention(c) (@inout_aliasable @block_storage @callee_guaranteed (@in_guaranteed Any) -> @out Any, AnyObject) -> @autoreleased AnyObject
+
+  let fn : @convention(block) (Any) -> Any = { y in takeTwoAnys(x, y) }
+}
+
+// CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] @$SypypIegnr_yXlyXlIeyBya_TR : $@convention(c) (@inout_aliasable @block_storage @callee_guaranteed (@in_guaranteed Any) -> @out Any, AnyObject) -> @autoreleased AnyObject
+// CHECK: bb0(%0 : @trivial $*@block_storage @callee_guaranteed (@in_guaranteed Any) -> @out Any, %1 : @unowned $AnyObject):
+// CHECK:   [[T0:%.*]] = copy_value %1 : $AnyObject
+// CHECK:   [[T1:%.*]] = open_existential_ref [[T0]] : $AnyObject
+// CHECK:   [[ARG:%.*]] = alloc_stack $Any
+// CHECK:   [[T2:%.*]] = init_existential_addr [[ARG]]
+// CHECK:   store [[T1]] to [init] [[T2]]
+// CHECK:   [[RESULT:%.*]] = alloc_stack $Any
+// CHECK:   apply {{.*}}([[RESULT]], [[ARG]])
+
+// CHECK-LABEL: sil hidden @$S13objc_bridging15castToCFunction3ptrySV_tF : $@convention(thin) (UnsafeRawPointer) -> () {
+func castToCFunction(ptr: UnsafeRawPointer) {
+  // CHECK: [[OUT:%.*]] = alloc_stack $@convention(c) (Optional<AnyObject>) -> ()
+  // CHECK: [[IN:%.]] = alloc_stack $UnsafeRawPointer
+  // CHECK: store %0 to [trivial] [[IN]] : $*UnsafeRawPointer
+  // CHECK: [[META:%.*]] = metatype $@thick (@convention(c) (Optional<AnyObject>) -> ()).Type
+  // CHECK: [[CASTFN:%.*]] = function_ref @$Ss13unsafeBitCast_2toq_x_q_mtr0_lF
+  // CHECK: apply [[CASTFN]]<UnsafeRawPointer, @convention(c) (AnyObject?) -> ()>([[OUT]], [[IN]], [[META]]) : $@convention(thin) <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0, @thick τ_0_1.Type) -> @out τ_0_1
+  // CHECK: [[RESULT:%.*]] = load [trivial] [[OUT]] : $*@convention(c) (Optional<AnyObject>) -> ()
+  typealias Fn = @convention(c) (AnyObject?) -> Void
+  unsafeBitCast(ptr, to: Fn.self)(nil)
+}
diff --git a/test/SILGen/plus_zero_objc_bridging_any.swift b/test/SILGen/plus_zero_objc_bridging_any.swift
new file mode 100644
index 0000000..6e994ee
--- /dev/null
+++ b/test/SILGen/plus_zero_objc_bridging_any.swift
@@ -0,0 +1,692 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -Xllvm -sil-print-debuginfo -emit-silgen -enable-sil-ownership %s | %FileCheck %s
+// REQUIRES: objc_interop
+
+import Foundation
+import objc_generics
+
+protocol P {}
+protocol CP: class {}
+
+struct KnownUnbridged {}
+
+// CHECK-LABEL: sil hidden @$S17objc_bridging_any11passingToId{{.*}}F
+func passingToId<T: CP, U>(receiver: NSIdLover,
+                           string: String,
+                           nsString: NSString,
+                           object: AnyObject,
+                           classGeneric: T,
+                           classExistential: CP,
+                           generic: U,
+                           existential: P,
+                           error: Error,
+                           any: Any,
+                           knownUnbridged: KnownUnbridged,
+                           optionalA: String?,
+                           optionalB: NSString?,
+                           optionalC: Any?) {
+  // CHECK: bb0([[SELF:%.*]] : @guaranteed $NSIdLover,
+  // CHECK:   debug_value [[STRING:%.*]] : $String
+  // CHECK:   debug_value [[NSSTRING:%.*]] : $NSString
+  // CHECK:   debug_value [[OBJECT:%.*]] : $AnyObject
+  // CHECK:   debug_value [[CLASS_GENERIC:%.*]] : $T
+  // CHECK:   debug_value [[CLASS_EXISTENTIAL:%.*]] : $CP
+  // CHECK:   debug_value_addr [[GENERIC:%.*]] : $*U
+  // CHECK:   debug_value_addr [[EXISTENTIAL:%.*]] : $*P
+  // CHECK:   debug_value [[ERROR:%.*]] : $Error
+  // CHECK:   debug_value_addr [[ANY:%.*]] : $*Any
+  // CHECK:   debug_value [[KNOWN_UNBRIDGED:%.*]] : $KnownUnbridged
+  // CHECK:   debug_value [[OPT_STRING:%.*]] : $Optional<String>
+  // CHECK:   debug_value [[OPT_NSSTRING:%.*]] : $Optional<NSString>
+  // CHECK:   debug_value_addr [[OPT_ANY:%.*]] : $*Optional<Any>
+
+  // CHECK:   [[STRING_COPY:%.*]] = copy_value [[STRING]]
+  // CHECK:   [[BRIDGE_STRING:%.*]] = function_ref @$SSS10FoundationE19_bridgeToObjectiveCSo8NSStringCyF
+  // CHECK:   [[BORROWED_STRING_COPY:%.*]] = begin_borrow [[STRING_COPY]]
+  // CHECK:   [[BRIDGED:%.*]] = apply [[BRIDGE_STRING]]([[BORROWED_STRING_COPY]])
+  // CHECK:   [[ANYOBJECT:%.*]] = init_existential_ref [[BRIDGED]] : $NSString : $NSString, $AnyObject
+  // CHECK:   end_borrow [[BORROWED_STRING_COPY]] from [[STRING_COPY]]
+  // CHECK:   destroy_value [[STRING_COPY]]
+  // CHECK:   [[METHOD:%.*]] = objc_method [[SELF]]
+  // CHECK:   apply [[METHOD]]([[ANYOBJECT]], [[SELF]])
+  // CHECK:   destroy_value [[ANYOBJECT]]
+  receiver.takesId(string)
+
+  // CHECK:   [[NSSTRING_COPY:%.*]] = copy_value [[NSSTRING]]
+  // CHECK:   [[ANYOBJECT:%.*]] = init_existential_ref [[NSSTRING_COPY]] : $NSString : $NSString, $AnyObject
+  // CHECK:   [[METHOD:%.*]] = objc_method [[SELF]] : $NSIdLover,
+  // CHECK:   apply [[METHOD]]([[ANYOBJECT]], [[SELF]])
+  // CHECK:   destroy_value [[ANYOBJECT]]
+  receiver.takesId(nsString)
+
+  // CHECK:   [[CLASS_GENERIC_COPY:%.*]] = copy_value [[CLASS_GENERIC]]
+  // CHECK:   [[ANYOBJECT:%.*]] = init_existential_ref [[CLASS_GENERIC_COPY]] : $T : $T, $AnyObject
+  // CHECK:   [[METHOD:%.*]] = objc_method [[SELF]] : $NSIdLover,
+  // CHECK:   apply [[METHOD]]([[ANYOBJECT]], [[SELF]])
+  // CHECK:   destroy_value [[ANYOBJECT]]
+  receiver.takesId(classGeneric)
+
+  // CHECK:   [[OBJECT_COPY:%.*]] = copy_value [[OBJECT]]
+  // CHECK:   [[METHOD:%.*]] = objc_method [[SELF]] : $NSIdLover,
+  // CHECK:   apply [[METHOD]]([[OBJECT_COPY]], [[SELF]])
+  // CHECK:   destroy_value [[OBJECT_COPY]]
+  receiver.takesId(object)
+
+  // CHECK:   [[CLASS_EXISTENTIAL_COPY:%.*]] = copy_value [[CLASS_EXISTENTIAL]]
+  // CHECK:   [[OPENED:%.*]] = open_existential_ref [[CLASS_EXISTENTIAL_COPY]] : $CP
+  // CHECK:   [[ANYOBJECT:%.*]] = init_existential_ref [[OPENED]]
+  // CHECK:   [[METHOD:%.*]] = objc_method [[SELF]] : $NSIdLover,
+  // CHECK:   apply [[METHOD]]([[ANYOBJECT]], [[SELF]])
+  // CHECK:   destroy_value [[ANYOBJECT]]
+  receiver.takesId(classExistential)
+
+  // These cases perform a universal bridging conversion.
+
+  // CHECK:   [[COPY:%.*]] = alloc_stack $U
+  // CHECK:   copy_addr [[GENERIC]] to [initialization] [[COPY]]
+  // CHECK:   // function_ref _bridgeAnythingToObjectiveC
+  // CHECK:   [[BRIDGE_ANYTHING:%.*]] = function_ref
+  // CHECK:   [[ANYOBJECT:%.*]] = apply [[BRIDGE_ANYTHING]]<U>([[COPY]])
+  // CHECK:   dealloc_stack [[COPY]]
+  // CHECK:   [[METHOD:%.*]] = objc_method [[SELF]] : $NSIdLover,
+  // CHECK:   apply [[METHOD]]([[ANYOBJECT]], [[SELF]])
+  // CHECK:   destroy_value [[ANYOBJECT]]
+  receiver.takesId(generic)
+
+  // CHECK:   [[COPY:%.*]] = alloc_stack $P
+  // CHECK:   copy_addr [[EXISTENTIAL]] to [initialization] [[COPY]]
+  // CHECK:   [[OPENED_COPY:%.*]] = open_existential_addr immutable_access [[COPY]] : $*P to $*[[OPENED_TYPE:@opened.*P]],
+  // CHECK:   [[TMP:%.*]] = alloc_stack $[[OPENED_TYPE]]
+  // CHECK:   copy_addr [[OPENED_COPY]] to [initialization] [[TMP]]
+  // CHECK:   // function_ref _bridgeAnythingToObjectiveC
+  // CHECK:   [[BRIDGE_ANYTHING:%.*]] = function_ref
+  // CHECK:   [[ANYOBJECT:%.*]] = apply [[BRIDGE_ANYTHING]]<[[OPENED_TYPE]]>([[TMP]])
+  // CHECK:   dealloc_stack [[TMP]]
+  // CHECK:   destroy_addr [[COPY]]
+  // CHECK:   dealloc_stack [[COPY]]
+  // CHECK:   [[METHOD:%.*]] = objc_method [[SELF]] : $NSIdLover,
+  // CHECK:   apply [[METHOD]]([[ANYOBJECT]], [[SELF]])
+  // CHECK:   destroy_value [[ANYOBJECT]]
+  receiver.takesId(existential)
+
+  // CHECK:   [[ERROR_COPY:%.*]] = copy_value [[ERROR]] : $Error
+  // CHECK:   [[ERROR_BOX:%[0-9]+]] = open_existential_box [[ERROR_COPY]] : $Error to $*@opened([[ERROR_ARCHETYPE:"[^"]*"]]) Error
+  // CHECK:   [[ERROR_STACK:%[0-9]+]] = alloc_stack $@opened([[ERROR_ARCHETYPE]]) Error
+  // CHECK:   copy_addr [[ERROR_BOX]] to [initialization] [[ERROR_STACK]] : $*@opened([[ERROR_ARCHETYPE]]) Error
+  // CHECK:   [[BRIDGE_FUNCTION:%[0-9]+]] = function_ref @$Ss27_bridgeAnythingToObjectiveCyyXlxlF
+  // CHECK:   [[BRIDGED_ERROR:%[0-9]+]] = apply [[BRIDGE_FUNCTION]]<@opened([[ERROR_ARCHETYPE]]) Error>([[ERROR_STACK]])
+  // CHECK:   dealloc_stack [[ERROR_STACK]] : $*@opened([[ERROR_ARCHETYPE]]) Error
+  // CHECK:   destroy_value [[ERROR_COPY]] : $Error
+  // CHECK:   [[METHOD:%.*]] = objc_method [[SELF]] : $NSIdLover,
+  // CHECK:   apply [[METHOD]]([[BRIDGED_ERROR]], [[SELF]])
+  // CHECK:   destroy_value [[BRIDGED_ERROR]] : $AnyObject
+  receiver.takesId(error)
+
+  // CHECK:   [[COPY:%.*]] = alloc_stack $Any
+  // CHECK:   copy_addr [[ANY]] to [initialization] [[COPY]]
+  // CHECK:   [[OPENED_COPY:%.*]] = open_existential_addr immutable_access [[COPY]] : $*Any to $*[[OPENED_TYPE:@opened.*Any]],
+  // CHECK:   [[TMP:%.*]] = alloc_stack $[[OPENED_TYPE]]
+  // CHECK:   copy_addr [[OPENED_COPY]] to [initialization] [[TMP]]
+  // CHECK:   // function_ref _bridgeAnythingToObjectiveC
+  // CHECK:   [[BRIDGE_ANYTHING:%.*]] = function_ref
+  // CHECK:   [[ANYOBJECT:%.*]] = apply [[BRIDGE_ANYTHING]]<[[OPENED_TYPE]]>([[TMP]])
+  // CHECK:   destroy_addr [[COPY]]
+  // CHECK:   dealloc_stack [[COPY]]
+  // CHECK:   [[METHOD:%.*]] = objc_method [[SELF]] : $NSIdLover,
+  // CHECK:   apply [[METHOD]]([[ANYOBJECT]], [[SELF]])
+  // CHECK:   destroy_value [[ANYOBJECT]]
+  receiver.takesId(any)
+
+  // CHECK:   [[TMP:%.*]] = alloc_stack $KnownUnbridged
+  // CHECK:   store [[KNOWN_UNBRIDGED]] to [trivial] [[TMP]]
+  // CHECK:   [[BRIDGE_ANYTHING:%.*]] = function_ref @$Ss27_bridgeAnythingToObjectiveC{{.*}}F
+  // CHECK:   [[ANYOBJECT:%.*]] = apply [[BRIDGE_ANYTHING]]<KnownUnbridged>([[TMP]])
+  // CHECK:   [[METHOD:%.*]] = objc_method [[SELF]] : $NSIdLover,
+  // CHECK:   apply [[METHOD]]([[ANYOBJECT]], [[SELF]])
+  receiver.takesId(knownUnbridged)
+
+  // These cases bridge using Optional's _ObjectiveCBridgeable conformance.
+
+  // CHECK:   [[OPT_STRING_COPY:%.*]] = copy_value [[OPT_STRING]]
+  // CHECK:   [[BRIDGE_OPTIONAL:%.*]] = function_ref @$SSq19_bridgeToObjectiveCyXlyF
+  // CHECK:   [[TMP:%.*]] = alloc_stack $Optional<String>
+  // CHECK:   [[BORROWED_OPT_STRING_COPY:%.*]] = begin_borrow [[OPT_STRING_COPY]]
+  // CHECK:   store_borrow [[BORROWED_OPT_STRING_COPY]] to [[TMP]]
+  // CHECK:   [[ANYOBJECT:%.*]] = apply [[BRIDGE_OPTIONAL]]<String>([[TMP]])
+  // CHECK:   end_borrow [[BORROWED_OPT_STRING_COPY]] from [[OPT_STRING_COPY]]
+  // CHECK:   [[METHOD:%.*]] = objc_method [[SELF]] : $NSIdLover,
+  // CHECK:   apply [[METHOD]]([[ANYOBJECT]], [[SELF]])
+  receiver.takesId(optionalA)
+
+  // CHECK:   [[OPT_NSSTRING_COPY:%.*]] = copy_value [[OPT_NSSTRING]]
+  // CHECK:   [[BRIDGE_OPTIONAL:%.*]] = function_ref @$SSq19_bridgeToObjectiveCyXlyF
+  // CHECK:   [[TMP:%.*]] = alloc_stack $Optional<NSString>
+  // CHECK:   [[BORROWED_OPT_NSSTRING_COPY:%.*]] = begin_borrow [[OPT_NSSTRING_COPY]]
+  // CHECK:   store_borrow [[BORROWED_OPT_NSSTRING_COPY]] to [[TMP]]
+  // CHECK:   [[ANYOBJECT:%.*]] = apply [[BRIDGE_OPTIONAL]]<NSString>([[TMP]])
+  // CHECK:   end_borrow [[BORROWED_OPT_NSSTRING_COPY]] from [[OPT_NSSTRING]]
+  // CHECK:   [[METHOD:%.*]] = objc_method [[SELF]] : $NSIdLover,
+  // CHECK:   apply [[METHOD]]([[ANYOBJECT]], [[SELF]])
+  receiver.takesId(optionalB)
+
+  // CHECK:   [[TMP:%.*]] = alloc_stack $Optional<Any>
+  // CHECK:   copy_addr [[OPT_ANY]] to [initialization] [[TMP]]
+  // CHECK:   [[BRIDGE_OPTIONAL:%.*]] = function_ref @$SSq19_bridgeToObjectiveCyXlyF
+  // CHECK:   [[ANYOBJECT:%.*]] = apply [[BRIDGE_OPTIONAL]]<Any>([[TMP]])
+  // CHECK:   [[METHOD:%.*]] = objc_method [[SELF]] : $NSIdLover,
+  // CHECK:   apply [[METHOD]]([[ANYOBJECT]], [[SELF]])
+  receiver.takesId(optionalC)
+
+  // TODO: Property and subscript setters
+}
+
+// Once upon a time, as a workaround for rdar://problem/28318984, we had
+// to skip the peephole for types with nontrivial SIL lowerings because we
+// didn't correctly form the substitutions for a generic
+// _bridgeAnythingToObjectiveC call.  That's not true anymore.
+func zim() {}
+struct Zang {}
+// CHECK-LABEL: sil hidden @$S17objc_bridging_any27typesWithNontrivialLowering8receiverySo9NSIdLoverC_tF
+func typesWithNontrivialLowering(receiver: NSIdLover) {
+  // CHECK: apply {{.*}}<() -> ()>
+  receiver.takesId(zim)
+  // CHECK: apply {{.*}}<Zang.Type>
+  receiver.takesId(Zang.self)
+  // CHECK: apply {{.*}}<(() -> (), Zang.Type)>
+  receiver.takesId((zim, Zang.self))
+  // CHECK: apply {{%.*}}<(Int, String)>
+  receiver.takesId((0, "one"))
+}
+
+// CHECK-LABEL: sil hidden @$S17objc_bridging_any19passingToNullableId{{.*}}F
+func passingToNullableId<T: CP, U>(receiver: NSIdLover,
+                                   string: String,
+                                   nsString: NSString,
+                                   object: AnyObject,
+                                   classGeneric: T,
+                                   classExistential: CP,
+                                   generic: U,
+                                   existential: P,
+                                   error: Error,
+                                   any: Any,
+                                   knownUnbridged: KnownUnbridged,
+                                   optString: String?,
+                                   optNSString: NSString?,
+                                   optObject: AnyObject?,
+                                   optClassGeneric: T?,
+                                   optClassExistential: CP?,
+                                   optGeneric: U?,
+                                   optExistential: P?,
+                                   optAny: Any?,
+                                   optKnownUnbridged: KnownUnbridged?,
+                                   optOptA: String??,
+                                   optOptB: NSString??,
+                                   optOptC: Any??)
+{
+  // CHECK: bb0([[SELF:%.*]] : @guaranteed $NSIdLover,
+  // CHECK: [[STRING:%.*]] : $String,
+  // CHECK: [[NSSTRING:%.*]] : $NSString
+  // CHECK: [[OBJECT:%.*]] : $AnyObject
+  // CHECK: [[CLASS_GENERIC:%.*]] : $T
+  // CHECK: [[CLASS_EXISTENTIAL:%.*]] : $CP
+  // CHECK: [[GENERIC:%.*]] : $*U
+  // CHECK: [[EXISTENTIAL:%.*]] : $*P
+  // CHECK: [[ERROR:%.*]] : $Error
+  // CHECK: [[ANY:%.*]] : $*Any,
+  // CHECK: [[KNOWN_UNBRIDGED:%.*]] : $KnownUnbridged,
+  // CHECK: [[OPT_STRING:%.*]] : $Optional<String>,
+  // CHECK: [[OPT_NSSTRING:%.*]] : $Optional<NSString>
+  // CHECK: [[OPT_OBJECT:%.*]] : $Optional<AnyObject>
+  // CHECK: [[OPT_CLASS_GENERIC:%.*]] : $Optional<T>
+  // CHECK: [[OPT_CLASS_EXISTENTIAL:%.*]] : $Optional<CP>
+  // CHECK: [[OPT_GENERIC:%.*]] : $*Optional<U>
+  // CHECK: [[OPT_EXISTENTIAL:%.*]] : $*Optional<P>
+  // CHECK: [[OPT_ANY:%.*]] : $*Optional<Any>
+  // CHECK: [[OPT_KNOWN_UNBRIDGED:%.*]] : $Optional<KnownUnbridged>
+  // CHECK: [[OPT_OPT_A:%.*]] : $Optional<Optional<String>>
+  // CHECK: [[OPT_OPT_B:%.*]] : $Optional<Optional<NSString>>
+  // CHECK: [[OPT_OPT_C:%.*]] : $*Optional<Optional<Any>>
+
+  // CHECK: [[STRING_COPY:%.*]] = copy_value [[STRING]]
+  // CHECK: [[BRIDGE_STRING:%.*]] = function_ref @$SSS10FoundationE19_bridgeToObjectiveCSo8NSStringCyF
+  // CHECK: [[BORROWED_STRING_COPY:%.*]] = begin_borrow [[STRING_COPY]]
+  // CHECK: [[BRIDGED:%.*]] = apply [[BRIDGE_STRING]]([[BORROWED_STRING_COPY]])
+  // CHECK: [[ANYOBJECT:%.*]] = init_existential_ref [[BRIDGED]] : $NSString : $NSString, $AnyObject
+  // CHECK: [[OPT_ANYOBJECT:%.*]] = enum {{.*}} [[ANYOBJECT]]
+  // CHECK: end_borrow [[BORROWED_STRING_COPY]] from [[STRING_COPY]]
+  // CHECK: destroy_value [[STRING_COPY]]
+  // CHECK: [[METHOD:%.*]] = objc_method [[SELF]]
+  // CHECK: apply [[METHOD]]([[OPT_ANYOBJECT]], [[SELF]])
+  // CHECK: destroy_value [[OPT_ANYOBJECT]]
+  receiver.takesNullableId(string)
+
+  // CHECK: [[NSSTRING_COPY:%.*]] = copy_value [[NSSTRING]]
+  // CHECK: [[ANYOBJECT:%.*]] = init_existential_ref [[NSSTRING_COPY]] : $NSString : $NSString, $AnyObject
+  // CHECK: [[OPT_ANYOBJECT:%.*]] = enum {{.*}} [[ANYOBJECT]]
+  // CHECK: [[METHOD:%.*]] = objc_method [[SELF]] : $NSIdLover,
+  // CHECK: apply [[METHOD]]([[OPT_ANYOBJECT]], [[SELF]])
+  receiver.takesNullableId(nsString)
+
+  // CHECK: [[OBJECT_COPY:%.*]] = copy_value [[OBJECT]]
+  // CHECK: [[OPT_ANYOBJECT:%.*]] = enum {{.*}} [[OBJECT_COPY]]
+  // CHECK: [[METHOD:%.*]] = objc_method [[SELF]] : $NSIdLover,
+  // CHECK: apply [[METHOD]]([[OPT_ANYOBJECT]], [[SELF]])
+  receiver.takesNullableId(object)
+
+  // CHECK: [[CLASS_GENERIC_COPY:%.*]] = copy_value [[CLASS_GENERIC]]
+  // CHECK: [[ANYOBJECT:%.*]] = init_existential_ref [[CLASS_GENERIC_COPY]] : $T : $T, $AnyObject
+  // CHECK: [[OPT_ANYOBJECT:%.*]] = enum {{.*}} [[ANYOBJECT]]
+  // CHECK: [[METHOD:%.*]] = objc_method [[SELF]] : $NSIdLover,
+  // CHECK: apply [[METHOD]]([[OPT_ANYOBJECT]], [[SELF]])
+  receiver.takesNullableId(classGeneric)
+
+  // CHECK: [[CLASS_EXISTENTIAL_COPY:%.*]] = copy_value [[CLASS_EXISTENTIAL]]
+  // CHECK: [[OPENED:%.*]] = open_existential_ref [[CLASS_EXISTENTIAL_COPY]] : $CP
+  // CHECK: [[ANYOBJECT:%.*]] = init_existential_ref [[OPENED]]
+  // CHECK: [[OPT_ANYOBJECT:%.*]] = enum {{.*}} [[ANYOBJECT]]
+  // CHECK: [[METHOD:%.*]] = objc_method [[SELF]] : $NSIdLover,
+  // CHECK: apply [[METHOD]]([[OPT_ANYOBJECT]], [[SELF]])
+  // CHECK: destroy_value [[OPT_ANYOBJECT]]
+  receiver.takesNullableId(classExistential)
+
+  // CHECK-NEXT: [[COPY:%.*]] = alloc_stack $U
+  // CHECK-NEXT: copy_addr [[GENERIC]] to [initialization] [[COPY]]
+  // CHECK-NEXT: // function_ref _bridgeAnythingToObjectiveC
+  // CHECK-NEXT: [[BRIDGE_ANYTHING:%.*]] = function_ref
+  // CHECK-NEXT: [[ANYOBJECT:%.*]] = apply [[BRIDGE_ANYTHING]]<U>([[COPY]])
+  // CHECK-NEXT: [[OPT_ANYOBJECT:%.*]] = enum {{.*}} [[ANYOBJECT]]
+  // CHECK-NEXT: destroy_addr [[COPY]]
+  // CHECK-NEXT: dealloc_stack [[COPY]]
+  // CHECK: [[METHOD:%.*]] = objc_method [[SELF]] : $NSIdLover,
+  // CHECK-NEXT: apply [[METHOD]]([[OPT_ANYOBJECT]], [[SELF]])
+  // CHECK-NEXT: destroy_value [[OPT_ANYOBJECT]]
+  receiver.takesNullableId(generic)
+
+  // CHECK-NEXT: [[COPY:%.*]] = alloc_stack $P
+  // CHECK-NEXT: copy_addr [[EXISTENTIAL]] to [initialization] [[COPY]]
+  // CHECK-NEXT: [[OPENED_COPY:%.*]] = open_existential_addr immutable_access [[COPY]] : $*P to $*[[OPENED_TYPE:@opened.*P]],
+  // CHECK: [[TMP:%.*]] = alloc_stack $[[OPENED_TYPE]]
+  // CHECK: copy_addr [[OPENED_COPY]] to [initialization] [[TMP]]
+  // CHECK-NEXT: // function_ref _bridgeAnythingToObjectiveC
+  // CHECK-NEXT: [[BRIDGE_ANYTHING:%.*]] = function_ref
+  // CHECK-NEXT: [[ANYOBJECT:%.*]] = apply [[BRIDGE_ANYTHING]]<[[OPENED_TYPE]]>([[TMP]])
+  // CHECK-NEXT: [[OPT_ANYOBJECT:%.*]] = enum {{.*}} [[ANYOBJECT]]
+  // CHECK-NEXT: destroy_addr [[TMP]]
+  // CHECK-NEXT: dealloc_stack [[TMP]]
+  // CHECK-NEXT: destroy_addr [[COPY]]
+  // CHECK-NEXT: dealloc_stack [[COPY]]
+  // CHECK: [[METHOD:%.*]] = objc_method [[SELF]] : $NSIdLover,
+  // CHECK-NEXT: apply [[METHOD]]([[OPT_ANYOBJECT]], [[SELF]])
+  // CHECK-NEXT: destroy_value [[OPT_ANYOBJECT]]
+  receiver.takesNullableId(existential)
+
+  // CHECK-NEXT: [[ERROR_COPY:%.*]] = copy_value [[ERROR]] : $Error
+  // CHECK-NEXT: [[ERROR_BOX:%[0-9]+]] = open_existential_box [[ERROR_COPY]] : $Error to $*@opened([[ERROR_ARCHETYPE:"[^"]*"]]) Error
+  // CHECK-NEXT: [[ERROR_STACK:%[0-9]+]] = alloc_stack $@opened([[ERROR_ARCHETYPE]]) Error
+  // CHECK-NEXT: copy_addr [[ERROR_BOX]] to [initialization] [[ERROR_STACK]] : $*@opened([[ERROR_ARCHETYPE]]) Error
+  // CHECK: [[BRIDGE_FUNCTION:%[0-9]+]] = function_ref @$Ss27_bridgeAnythingToObjectiveCyyXlxlF
+  // CHECK-NEXT: [[BRIDGED_ERROR:%[0-9]+]] = apply [[BRIDGE_FUNCTION]]<@opened([[ERROR_ARCHETYPE]]) Error>([[ERROR_STACK]])
+  // CHECK-NEXT: [[BRIDGED_ERROR_OPT:%[0-9]+]] = enum $Optional<AnyObject>, #Optional.some!enumelt.1, [[BRIDGED_ERROR]] : $AnyObject
+  // CHECK-NEXT: destroy_addr [[ERROR_STACK]]
+  // CHECK-NEXT: dealloc_stack [[ERROR_STACK]] : $*@opened([[ERROR_ARCHETYPE]]) Error
+  // CHECK-NEXT: destroy_value [[ERROR_COPY]] : $Error
+  // CHECK: [[METHOD:%.*]] = objc_method [[SELF]] : $NSIdLover,
+  // CHECK-NEXT: apply [[METHOD]]([[BRIDGED_ERROR_OPT]], [[SELF]])
+  // CHECK-NEXT: destroy_value [[BRIDGED_ERROR_OPT]]
+  receiver.takesNullableId(error)
+
+  // CHECK-NEXT: [[COPY:%.*]] = alloc_stack $Any
+  // CHECK-NEXT: copy_addr [[ANY]] to [initialization] [[COPY]]
+  // CHECK-NEXT: [[OPENED_COPY:%.*]] = open_existential_addr immutable_access [[COPY]] : $*Any to $*[[OPENED_TYPE:@opened.*Any]],
+  // CHECK: [[TMP:%.*]] = alloc_stack $[[OPENED_TYPE]]
+  // CHECK: copy_addr [[OPENED_COPY]] to [initialization] [[TMP]]
+  // CHECK-NEXT: // function_ref _bridgeAnythingToObjectiveC
+  // CHECK-NEXT: [[BRIDGE_ANYTHING:%.*]] = function_ref
+  // CHECK-NEXT: [[ANYOBJECT:%.*]] = apply [[BRIDGE_ANYTHING]]<[[OPENED_TYPE]]>([[TMP]])
+  // CHECK-NEXT: [[OPT_ANYOBJECT:%.*]] = enum {{.*}} [[ANYOBJECT]]
+  // CHECK-NEXT: destroy_addr [[TMP]]
+  // CHECK-NEXT: dealloc_stack [[TMP]]
+  // CHECK-NEXT: destroy_addr [[COPY]]
+  // CHECK-NEXT: dealloc_stack [[COPY]]
+  // CHECK: [[METHOD:%.*]] = objc_method [[SELF]] : $NSIdLover,
+  // CHECK-NEXT: apply [[METHOD]]([[OPT_ANYOBJECT]], [[SELF]])
+  // CHECK-NEXT: destroy_value [[OPT_ANYOBJECT]]
+  receiver.takesNullableId(any)
+
+  // CHECK: [[TMP:%.*]] = alloc_stack $KnownUnbridged
+  // CHECK: store [[KNOWN_UNBRIDGED]] to [trivial] [[TMP]]
+  // CHECK: [[BRIDGE_ANYTHING:%.*]] = function_ref @$Ss27_bridgeAnythingToObjectiveC{{.*}}F
+  // CHECK: [[ANYOBJECT:%.*]] = apply [[BRIDGE_ANYTHING]]<KnownUnbridged>([[TMP]])
+  // CHECK: [[OPT_ANYOBJECT:%.*]] = enum {{.*}} [[ANYOBJECT]]
+  // CHECK: [[METHOD:%.*]] = objc_method [[SELF]] : $NSIdLover,
+  // CHECK: apply [[METHOD]]([[OPT_ANYOBJECT]], [[SELF]])
+  receiver.takesNullableId(knownUnbridged)
+
+  // CHECK: [[OPT_STRING_COPY:%.*]] = copy_value [[OPT_STRING]]
+  // CHECK: switch_enum [[OPT_STRING_COPY]] : $Optional<String>, case #Optional.some!enumelt.1: [[SOME_BB:bb[0-9]+]], case #Optional.none!enumelt: [[NONE_BB:bb[0-9]+]]
+  //
+  // CHECK: [[SOME_BB]]([[STRING_DATA:%.*]] : @owned $String):
+  // CHECK:   [[BRIDGE_STRING:%.*]] = function_ref @$SSS10FoundationE19_bridgeToObjectiveCSo8NSStringCyF
+  // CHECK:   [[BORROWED_STRING_DATA:%.*]] = begin_borrow [[STRING_DATA]]
+  // CHECK:   [[BRIDGED:%.*]] = apply [[BRIDGE_STRING]]([[BORROWED_STRING_DATA]])
+  // CHECK:   [[ANYOBJECT:%.*]] = init_existential_ref [[BRIDGED]] : $NSString : $NSString, $AnyObject
+  // CHECK:   [[OPT_ANYOBJECT:%.*]] = enum {{.*}} [[ANYOBJECT]]
+  // CHECK:   end_borrow [[BORROWED_STRING_DATA]] from [[STRING_DATA]]
+  // CHECK:   destroy_value [[STRING_DATA]]
+  // CHECK:   br [[JOIN:bb.*]]([[OPT_ANYOBJECT]]
+  //
+  // CHECK: [[NONE_BB]]:
+  // CHECK:   [[OPT_NONE:%.*]] = enum $Optional<AnyObject>, #Optional.none!enumelt
+  // CHECK:   br [[JOIN]]([[OPT_NONE]]
+  //
+  // CHECK: [[JOIN]]([[PHI:%.*]] : @owned $Optional<AnyObject>):
+  // CHECK: [[METHOD:%.*]] = objc_method [[SELF]]
+  // CHECK:   apply [[METHOD]]([[PHI]], [[SELF]])
+  // CHECK:   destroy_value [[PHI]]
+  receiver.takesNullableId(optString)
+
+  // CHECK: [[METHOD:%.*]] = objc_method [[SELF]]
+  receiver.takesNullableId(optNSString)
+
+  // CHECK: [[OPT_OBJECT_COPY:%.*]] = copy_value [[OPT_OBJECT]]
+  // CHECK: [[METHOD:%.*]] = objc_method [[SELF]]
+  // CHECK: apply [[METHOD]]([[OPT_OBJECT_COPY]], [[SELF]])
+  receiver.takesNullableId(optObject)
+  receiver.takesNullableId(optClassGeneric)
+  receiver.takesNullableId(optClassExistential)
+  receiver.takesNullableId(optGeneric)
+  receiver.takesNullableId(optExistential)
+  receiver.takesNullableId(optAny)
+  receiver.takesNullableId(optKnownUnbridged)
+
+  receiver.takesNullableId(optOptA)
+  receiver.takesNullableId(optOptB)
+  receiver.takesNullableId(optOptC)
+}
+
+protocol Anyable {
+  init(any: Any)
+  init(anyMaybe: Any?)
+  var anyProperty: Any { get }
+  var maybeAnyProperty: Any? { get }
+}
+
+// Make sure we generate correct bridging thunks
+class SwiftIdLover : NSObject, Anyable {
+
+  func methodReturningAny() -> Any {}
+  // SEMANTIC ARC TODO: This is another case of pattern matching the body of one
+  // function in a different function... Just pattern match the unreachable case
+  // to preserve behavior. We should check if it is correct.
+
+  // CHECK-LABEL: sil hidden @$S17objc_bridging_any12SwiftIdLoverC18methodReturningAnyypyF : $@convention(method) (@guaranteed SwiftIdLover) -> @out Any
+  // CHECK: unreachable
+  // CHECK: } // end sil function '$S17objc_bridging_any12SwiftIdLoverC18methodReturningAnyypyF'
+
+  // CHECK-LABEL: sil hidden [thunk] @$S17objc_bridging_any12SwiftIdLoverC18methodReturningAnyypyFTo : $@convention(objc_method) (SwiftIdLover) -> @autoreleased AnyObject {
+  // CHECK: bb0([[SELF:%[0-9]+]] : @unowned $SwiftIdLover):
+  // CHECK:   [[NATIVE_RESULT:%.*]] = alloc_stack $Any
+  // CHECK:   [[SELF_COPY:%.*]] = copy_value [[SELF]] : $SwiftIdLover
+  // CHECK:   [[BORROWED_SELF_COPY:%.*]] = begin_borrow [[SELF_COPY]]
+  // CHECK:   [[NATIVE_IMP:%.*]] = function_ref @$S17objc_bridging_any12SwiftIdLoverC18methodReturningAnyypyF
+  // CHECK:   apply [[NATIVE_IMP]]([[NATIVE_RESULT]], [[BORROWED_SELF_COPY]])
+  // CHECK:   end_borrow [[BORROWED_SELF_COPY]] from [[SELF_COPY]]
+  // CHECK:   destroy_value [[SELF_COPY]]
+  // CHECK:   [[OPEN_RESULT:%.*]] = open_existential_addr immutable_access [[NATIVE_RESULT]]
+	// CHECK:   [[TMP:%.*]] = alloc_stack
+  // CHECK:   copy_addr [[OPEN_RESULT]] to [initialization] [[TMP]]
+  // CHECK:   [[BRIDGE_ANYTHING:%.*]] = function_ref @$Ss27_bridgeAnythingToObjectiveC{{.*}}F
+  // CHECK:   [[OBJC_RESULT:%.*]] = apply [[BRIDGE_ANYTHING]]<{{.*}}>([[TMP]])
+  // CHECK:   return [[OBJC_RESULT]]
+  // CHECK: } // end sil function '$S17objc_bridging_any12SwiftIdLoverC18methodReturningAnyypyFTo'
+
+  func methodReturningOptionalAny() -> Any? {}
+  // CHECK-LABEL: sil hidden @$S17objc_bridging_any12SwiftIdLoverC26methodReturningOptionalAnyypSgyF
+  // CHECK-LABEL: sil hidden [thunk] @$S17objc_bridging_any12SwiftIdLoverC26methodReturningOptionalAnyypSgyFTo
+  // CHECK:       function_ref @$Ss27_bridgeAnythingToObjectiveC{{.*}}F
+
+  @objc func methodTakingAny(a: Any) {}
+  // CHECK-LABEL: sil hidden [thunk] @$S17objc_bridging_any12SwiftIdLoverC15methodTakingAny1ayyp_tFTo : $@convention(objc_method) (AnyObject, SwiftIdLover) -> ()
+  // CHECK:     bb0([[ARG:%.*]] : @unowned $AnyObject, [[SELF:%.*]] : @unowned $SwiftIdLover):
+  // CHECK-NEXT:  [[ARG_COPY:%.*]] = copy_value [[ARG]]
+  // CHECK-NEXT:  [[SELF_COPY:%.*]] = copy_value [[SELF]]
+  // CHECK-NEXT:  [[OPENED_SELF:%.*]] = open_existential_ref [[ARG_COPY]]
+  // CHECK-NEXT:  [[RESULT:%.*]] = alloc_stack $Any
+  // CHECK-NEXT:  [[INIT:%.*]] = init_existential_addr [[RESULT]] : $*Any
+  // CHECK-NEXT:  store [[OPENED_SELF]] to [init] [[INIT]]
+  // CHECK-NEXT:  [[BORROWED_SELF_COPY:%.*]] = begin_borrow [[SELF_COPY]]
+  // CHECK-NEXT:  // function_ref
+  // CHECK-NEXT:  [[METHOD:%.*]] = function_ref @$S17objc_bridging_any12SwiftIdLoverC15methodTakingAny1ayyp_tF
+  // CHECK-NEXT:  apply [[METHOD]]([[RESULT]], [[BORROWED_SELF_COPY]])
+  // CHECK-NEXT:  end_borrow [[BORROWED_SELF_COPY]] from [[SELF_COPY]]
+  // CHECK-NEXT:  destroy_addr [[RESULT]]
+  // CHECK-NEXT:  dealloc_stack [[RESULT]]
+  // CHECK-NEXT:  destroy_value [[SELF_COPY]]
+  // CHECK-NEXT:  return
+
+  func methodTakingOptionalAny(a: Any?) {}
+  // CHECK-LABEL: sil hidden @$S17objc_bridging_any12SwiftIdLoverC23methodTakingOptionalAny1ayypSg_tF
+
+  // CHECK-LABEL: sil hidden [thunk] @$S17objc_bridging_any12SwiftIdLoverC23methodTakingOptionalAny1ayypSg_tFTo
+
+  // CHECK-LABEL: sil hidden @$S17objc_bridging_any12SwiftIdLoverC017methodTakingBlockH3AnyyyyypXEF : $@convention(method) (@noescape @callee_guaranteed (@in_guaranteed Any) -> (), @guaranteed SwiftIdLover) -> ()
+
+  // CHECK-LABEL: sil hidden [thunk] @$S17objc_bridging_any12SwiftIdLoverC017methodTakingBlockH3AnyyyyypXEFTo : $@convention(objc_method) (@convention(block) @noescape (AnyObject) -> (), SwiftIdLover) -> ()
+  // CHECK:    bb0([[BLOCK:%.*]] : @unowned $@convention(block) @noescape (AnyObject) -> (), [[SELF:%.*]] : @unowned $SwiftIdLover):
+  // CHECK-NEXT:  [[BLOCK_COPY:%.*]] = copy_block [[BLOCK]]
+  // CHECK-NEXT:  [[SELF_COPY:%.*]] = copy_value [[SELF]]
+  // CHECK:       [[THUNK_FN:%.*]] = function_ref @$SyXlIyBy_ypIegn_TR
+  // CHECK-NEXT:  [[THUNK:%.*]] = partial_apply [callee_guaranteed] [[THUNK_FN]]([[BLOCK_COPY]])
+  // CHECK-NEXT:  [[THUNK_CVT:%.*]] = convert_escape_to_noescape [[THUNK]]
+  // CHECK:       [[BORROWED_SELF_COPY:%.*]] = begin_borrow [[SELF_COPY]]
+  // CHECK-NEXT:  // function_ref
+  // CHECK-NEXT:  [[METHOD:%.*]] = function_ref @$S17objc_bridging_any12SwiftIdLoverC017methodTakingBlockH3AnyyyyypXEF
+  // CHECK-NEXT:  [[RESULT:%.*]] = apply [[METHOD]]([[THUNK_CVT]], [[BORROWED_SELF_COPY]])
+  // CHECK-NEXT:  end_borrow [[BORROWED_SELF_COPY]] from [[SELF_COPY]]
+  // CHECK-NEXT:  destroy_value [[THUNK]]
+  // CHECK-NEXT:  destroy_value [[SELF_COPY]]
+  // CHECK-NEXT:  return [[RESULT]]
+
+  // CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] @$SyXlIyBy_ypIegn_TR
+  // CHECK:     bb0([[ANY:%.*]] : @trivial $*Any, [[BLOCK:%.*]] : @guaranteed $@convention(block) @noescape (AnyObject) -> ()):
+  // CHECK-NEXT:  [[OPENED_ANY:%.*]] = open_existential_addr immutable_access [[ANY]] : $*Any to $*[[OPENED_TYPE:@opened.*Any]],
+	// CHECK:   [[TMP:%.*]] = alloc_stack
+  // CHECK:   copy_addr [[OPENED_ANY]] to [initialization] [[TMP]]
+  // CHECK-NEXT:  // function_ref _bridgeAnythingToObjectiveC
+  // CHECK-NEXT:  [[BRIDGE_ANYTHING:%.*]] = function_ref
+  // CHECK-NEXT:  [[BRIDGED:%.*]] = apply [[BRIDGE_ANYTHING]]<[[OPENED_TYPE]]>([[TMP]])
+  // CHECK-NEXT:  apply [[BLOCK]]([[BRIDGED]])
+  // CHECK-NEXT:  [[VOID:%.*]] = tuple ()
+  // CHECK-NEXT:  destroy_value [[BRIDGED]]
+  // CHECK-NEXT:  destroy_addr [[TMP]]
+  // CHECK-NEXT:  dealloc_stack [[TMP]]
+  // CHECK-NEXT:  return [[VOID]]
+
+  @objc func methodTakingBlockTakingAny(_: (Any) -> ()) {}
+
+  // CHECK-LABEL: sil hidden @$S17objc_bridging_any12SwiftIdLoverC29methodReturningBlockTakingAnyyypcyF : $@convention(method) (@guaranteed SwiftIdLover) -> @owned @callee_guaranteed (@in_guaranteed Any) -> ()
+
+  // CHECK-LABEL: sil hidden [thunk] @$S17objc_bridging_any12SwiftIdLoverC29methodReturningBlockTakingAnyyypcyFTo : $@convention(objc_method) (SwiftIdLover) -> @autoreleased @convention(block) (AnyObject) -> ()
+  // CHECK:     bb0([[SELF:%.*]] : @unowned $SwiftIdLover):
+  // CHECK-NEXT:  [[SELF_COPY:%.*]] = copy_value [[SELF]]
+  // CHECK-NEXT:  [[BORROWED_SELF_COPY:%.*]] = begin_borrow [[SELF_COPY]]
+  // CHECK-NEXT:  // function_ref
+  // CHECK-NEXT:  [[METHOD:%.*]] = function_ref @$S17objc_bridging_any12SwiftIdLoverC29methodReturningBlockTakingAnyyypcyF
+  // CHECK-NEXT:  [[RESULT:%.*]] = apply [[METHOD:%.*]]([[BORROWED_SELF_COPY]])
+  // CHECK-NEXT:  end_borrow [[BORROWED_SELF_COPY]] from [[SELF_COPY]]
+  // CHECK-NEXT:  destroy_value [[SELF_COPY]]
+  // CHECK-NEXT:  [[BLOCK_STORAGE:%.*]] = alloc_stack $@block_storage @callee_guaranteed (@in_guaranteed Any) -> ()
+  // CHECK-NEXT:  [[BLOCK_STORAGE_ADDR:%.*]] = project_block_storage [[BLOCK_STORAGE]]
+  // CHECK-NEXT:  store [[RESULT:%.*]] to [init] [[BLOCK_STORAGE_ADDR]]
+  // CHECK:       [[THUNK_FN:%.*]] = function_ref @$SypIegn_yXlIeyBy_TR
+  // CHECK-NEXT:  [[BLOCK_HEADER:%.*]] = init_block_storage_header [[BLOCK_STORAGE]] : $*@block_storage @callee_guaranteed (@in_guaranteed Any) -> (), invoke [[THUNK_FN]]
+  // CHECK-NEXT:  [[BLOCK:%.*]] = copy_block [[BLOCK_HEADER]]
+  // CHECK-NEXT:  destroy_addr [[BLOCK_STORAGE_ADDR]]
+  // CHECK-NEXT:  dealloc_stack [[BLOCK_STORAGE]]
+  // CHECK-NEXT:  return [[BLOCK]]
+
+  // CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] @$SypIegn_yXlIeyBy_TR : $@convention(c) (@inout_aliasable @block_storage @callee_guaranteed (@in_guaranteed Any) -> (), AnyObject) -> ()
+  // CHECK:     bb0([[BLOCK_STORAGE:%.*]] : @trivial $*@block_storage @callee_guaranteed (@in_guaranteed Any) -> (), [[ANY:%.*]] : @unowned $AnyObject):
+  // CHECK-NEXT:  [[BLOCK_STORAGE_ADDR:%.*]] = project_block_storage [[BLOCK_STORAGE]]
+  // CHECK-NEXT:  [[FUNCTION:%.*]] = load [copy] [[BLOCK_STORAGE_ADDR]]
+  // CHECK-NEXT:  [[ANY_COPY:%.*]] = copy_value [[ANY]]
+  // CHECK-NEXT:  [[OPENED_ANY:%.*]] = open_existential_ref [[ANY_COPY]]
+  // CHECK-NEXT:  [[RESULT:%.*]] = alloc_stack $Any
+  // CHECK-NEXT:  [[INIT:%.*]] = init_existential_addr [[RESULT]] : $*Any
+  // CHECK-NEXT:  store [[OPENED_ANY]] to [init] [[INIT]]
+  // CHECK-NEXT:  [[BORROW_FUN:%.*]] =  begin_borrow [[FUNCTION]]
+  // CHECK-NEXT:  apply [[BORROW_FUN]]([[RESULT]])
+  // CHECK-NEXT:  end_borrow [[BORROW_FUN]] from [[FUNCTION]]
+  // CHECK-NEXT:  [[VOID:%.*]] = tuple ()
+  // CHECK-NEXT:  destroy_addr [[RESULT]]
+  // CHECK-NEXT:  dealloc_stack [[RESULT]]
+  // CHECK-NEXT:  destroy_value [[FUNCTION]]
+  // CHECK-NEXT:  return [[VOID]] : $()
+
+  @objc func methodTakingBlockTakingOptionalAny(_: (Any?) -> ()) {}
+
+  @objc func methodReturningBlockTakingAny() -> ((Any) -> ()) {}
+
+  // CHECK-LABEL: sil hidden @$S17objc_bridging_any12SwiftIdLoverC29methodTakingBlockReturningAnyyyypyXEF : $@convention(method) (@noescape @callee_guaranteed () -> @out Any, @guaranteed SwiftIdLover) -> () {
+
+  // CHECK-LABEL: sil hidden [thunk] @$S17objc_bridging_any12SwiftIdLoverC29methodTakingBlockReturningAnyyyypyXEFTo : $@convention(objc_method) (@convention(block) @noescape () -> @autoreleased AnyObject, SwiftIdLover) -> ()
+  // CHECK:     bb0([[BLOCK:%.*]] : @unowned $@convention(block) @noescape () -> @autoreleased AnyObject, [[ANY:%.*]] : @unowned $SwiftIdLover):
+  // CHECK-NEXT:  [[BLOCK_COPY:%.*]] = copy_block [[BLOCK]]
+  // CHECK-NEXT:  [[ANY_COPY:%.*]] = copy_value [[ANY]]
+  // CHECK-NEXT:  // function_ref
+  // CHECK-NEXT:  [[THUNK_FN:%.*]] = function_ref @$SyXlIyBa_ypIegr_TR
+  // CHECK-NEXT:  [[THUNK:%.*]] = partial_apply [callee_guaranteed] [[THUNK_FN]]([[BLOCK_COPY]])
+  // CHECK-NEXT:  [[THUNK_CVT:%.*]] = convert_escape_to_noescape [[THUNK]]
+  // CHECK-NEXT:  [[BORROWED_ANY_COPY:%.*]] = begin_borrow [[ANY_COPY]]
+  // CHECK-NEXT:  // function_ref
+  // CHECK-NEXT:  [[METHOD:%.*]] = function_ref @$S17objc_bridging_any12SwiftIdLoverC29methodTakingBlockReturningAnyyyypyXEF
+  // CHECK-NEXT:  [[RESULT:%.*]] = apply [[METHOD]]([[THUNK_CVT]], [[BORROWED_ANY_COPY]])
+  // CHECK-NEXT:  end_borrow [[BORROWED_ANY_COPY]] from [[ANY_COPY]]
+  // CHECK-NEXT:  destroy_value [[THUNK]]
+  // CHECK-NEXT:  destroy_value [[ANY_COPY]]
+  // CHECK-NEXT:  return [[RESULT]]
+
+  // CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] @$SyXlIyBa_ypIegr_TR : $@convention(thin) (@guaranteed @convention(block) @noescape () -> @autoreleased AnyObject) -> @out Any
+  // CHECK:     bb0([[ANY_ADDR:%.*]] : @trivial $*Any, [[BLOCK:%.*]] : @guaranteed $@convention(block) @noescape () -> @autoreleased AnyObject):
+  // CHECK-NEXT:  [[BRIDGED:%.*]] = apply [[BLOCK]]()
+  // CHECK-NEXT:  [[OPTIONAL:%.*]] = unchecked_ref_cast [[BRIDGED]]
+  // CHECK-NEXT:  // function_ref
+  // CHECK-NEXT:  [[BRIDGE_TO_ANY:%.*]] = function_ref [[BRIDGE_TO_ANY_FUNC:@.*]] :
+  // CHECK-NEXT:  [[BORROWED_OPTIONAL:%.*]] = begin_borrow [[OPTIONAL]]
+  // CHECK-NEXT:  [[RESULT_VAL:%.*]] = apply [[BRIDGE_TO_ANY]]([[ANY_ADDR]], [[BORROWED_OPTIONAL]])
+  // CHECK-NEXT:  [[EMPTY:%.*]] = tuple ()
+  // CHECK-NEXT:  end_borrow [[BORROWED_OPTIONAL]]
+  // CHECK-NEXT:  destroy_value [[OPTIONAL]]
+  // CHECK-NEXT:  return [[EMPTY]]
+
+  @objc func methodReturningBlockTakingOptionalAny() -> ((Any?) -> ()) {}
+
+  @objc func methodTakingBlockReturningAny(_: () -> Any) {}
+
+  // CHECK-LABEL: sil hidden @$S17objc_bridging_any12SwiftIdLoverC020methodReturningBlockH3AnyypycyF : $@convention(method) (@guaranteed SwiftIdLover) -> @owned @callee_guaranteed () -> @out Any
+
+  // CHECK-LABEL: sil hidden [thunk] @$S17objc_bridging_any12SwiftIdLoverC020methodReturningBlockH3AnyypycyFTo : $@convention(objc_method) (SwiftIdLover) -> @autoreleased @convention(block) () -> @autoreleased AnyObject
+  // CHECK:     bb0([[SELF:%.*]] : @unowned $SwiftIdLover):
+  // CHECK-NEXT:  [[SELF_COPY:%.*]] = copy_value [[SELF]]
+  // CHECK-NEXT:  [[BORROWED_SELF_COPY:%.*]] = begin_borrow [[SELF_COPY]]
+  // CHECK-NEXT:  // function_ref
+  // CHECK-NEXT:  [[METHOD:%.*]] = function_ref @$S17objc_bridging_any12SwiftIdLoverC020methodReturningBlockH3AnyypycyF
+  // CHECK-NEXT:  [[FUNCTION:%.*]] = apply [[METHOD]]([[BORROWED_SELF_COPY]])
+  // CHECK-NEXT:  end_borrow [[BORROWED_SELF_COPY]] from [[SELF_COPY]]
+  // CHECK-NEXT:  destroy_value [[SELF_COPY]]
+  // CHECK-NEXT:  [[BLOCK_STORAGE:%.*]] = alloc_stack $@block_storage @callee_guaranteed () -> @out Any
+  // CHECK-NEXT:  [[BLOCK_STORAGE_ADDR:%.*]] = project_block_storage [[BLOCK_STORAGE]]
+  // CHECK-NEXT:  store [[FUNCTION]] to [init] [[BLOCK_STORAGE_ADDR]]
+  // CHECK-NEXT:  // function_ref
+  // CHECK-NEXT:  [[THUNK_FN:%.*]] = function_ref @$SypIegr_yXlIeyBa_TR
+  // CHECK-NEXT:  [[BLOCK_HEADER:%.*]] = init_block_storage_header [[BLOCK_STORAGE]] : $*@block_storage @callee_guaranteed () -> @out Any, invoke [[THUNK_FN]]
+  // CHECK-NEXT:  [[BLOCK:%.*]] = copy_block [[BLOCK_HEADER]]
+  // CHECK-NEXT:  destroy_addr [[BLOCK_STORAGE_ADDR]]
+  // CHECK-NEXT:  dealloc_stack [[BLOCK_STORAGE]]
+  // CHECK-NEXT:  return [[BLOCK]]
+
+  // CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] @$SypIegr_yXlIeyBa_TR : $@convention(c) (@inout_aliasable @block_storage @callee_guaranteed () -> @out Any) -> @autoreleased AnyObject
+  // CHECK:     bb0(%0 : @trivial $*@block_storage @callee_guaranteed () -> @out Any):
+  // CHECK-NEXT:  [[BLOCK_STORAGE_ADDR:%.*]] = project_block_storage %0
+  // CHECK-NEXT:  [[FUNCTION:%.*]] = load [copy] [[BLOCK_STORAGE_ADDR]]
+  // CHECK-NEXT:  [[RESULT:%.*]] = alloc_stack $Any
+  // CHECK-NEXT:  [[BORROW_FUN:%.*]] = begin_borrow [[FUNCTION]]
+  // CHECK-NEXT:  apply [[BORROW_FUN]]([[RESULT]])
+  // CHECK-NEXT:  end_borrow [[BORROW_FUN]] from [[FUNCTION]]
+  // CHECK-NEXT:  [[OPENED:%.*]] = open_existential_addr immutable_access [[RESULT]] : $*Any to $*[[OPENED_TYPE:@opened.*Any]],
+  // CHECK:       [[TMP:%.*]] = alloc_stack $[[OPENED_TYPE]]
+  // CHECK:       copy_addr [[OPENED]] to [initialization] [[TMP]]
+  // CHECK-NEXT:  // function_ref _bridgeAnythingToObjectiveC
+  // CHECK-NEXT:  [[BRIDGE_ANYTHING:%.*]] = function_ref
+  // CHECK-NEXT:  [[BRIDGED:%.*]] = apply [[BRIDGE_ANYTHING]]<[[OPENED_TYPE]]>([[TMP]])
+  // CHECK-NEXT:  destroy_addr [[TMP]]
+  // CHECK-NEXT:  dealloc_stack [[TMP]]
+  // CHECK-NEXT:  destroy_addr [[RESULT]]
+  // CHECK-NEXT:  dealloc_stack [[RESULT]]
+  // CHECK-NEXT:  destroy_value [[FUNCTION]]
+  // CHECK-NEXT:  return [[BRIDGED]]
+
+  @objc func methodTakingBlockReturningOptionalAny(_: () -> Any?) {}
+
+  @objc func methodReturningBlockReturningAny() -> (() -> Any) {}
+
+  @objc func methodReturningBlockReturningOptionalAny() -> (() -> Any?) {}
+  // CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] @$SypSgIegr_yXlSgIeyBa_TR
+  // CHECK: function_ref @$Ss27_bridgeAnythingToObjectiveC{{.*}}F
+
+  override init() { super.init() }
+  @objc dynamic required convenience init(any: Any) { self.init() }
+  @objc dynamic required convenience init(anyMaybe: Any?) { self.init() }
+  @objc dynamic var anyProperty: Any
+  @objc dynamic var maybeAnyProperty: Any?
+
+  subscript(_: IndexForAnySubscript) -> Any { get {} set {} }
+
+  @objc func methodReturningAnyOrError() throws -> Any {}
+}
+
+class IndexForAnySubscript {}
+
+func dynamicLookup(x: AnyObject) {
+  _ = x.anyProperty
+  _ = x[IndexForAnySubscript()]
+}
+
+extension GenericClass {
+  // CHECK-LABEL: sil hidden @$SSo12GenericClassC17objc_bridging_anyE23pseudogenericAnyErasure1xypx_tF :
+  func pseudogenericAnyErasure(x: T) -> Any {
+    // CHECK: bb0([[ANY_OUT:%.*]] : @trivial $*Any, [[ARG:%.*]] : @guaranteed $T, [[SELF:%.*]] : @guaranteed $GenericClass<T>
+    // CHECK:   [[ANY_BUF:%.*]] = init_existential_addr [[ANY_OUT]] : $*Any, $AnyObject
+    // CHECK:   [[ARG_COPY:%.*]] = copy_value [[ARG]]
+    // CHECK:   [[ANYOBJECT:%.*]] = init_existential_ref [[ARG_COPY]] : $T : $T, $AnyObject
+    // CHECK:   store [[ANYOBJECT]] to [init] [[ANY_BUF]]
+    return x
+  }
+  // CHECK: } // end sil function '$SSo12GenericClassC17objc_bridging_anyE23pseudogenericAnyErasure1xypx_tF'
+}
+
+// Make sure AnyHashable erasure marks Hashable conformance as used
+class AnyHashableClass : NSObject {
+  // CHECK-LABEL: sil hidden @$S17objc_bridging_any16AnyHashableClassC07returnsdE0s0dE0VyF
+  // CHECK: [[FN:%.*]] = function_ref @$Ss21_convertToAnyHashableys0cD0Vxs0D0RzlF
+  // CHECK: apply [[FN]]<GenericOption>({{.*}})
+  func returnsAnyHashable() -> AnyHashable {
+    return GenericOption.multithreaded
+  }
+}
+
+// CHECK-LABEL: sil hidden @$S17objc_bridging_any33bridgeOptionalFunctionToAnyObject2fnyXlyycSg_tF : $@convention(thin) (@guaranteed Optional<@callee_guaranteed () -> ()>) -> @owned AnyObject
+// CHECK: [[BRIDGE:%.*]] = function_ref @$SSq19_bridgeToObjectiveCyXlyF
+// CHECK: [[FN:%.*]] = function_ref @$SIeg_ytytIegnr_TR
+// CHECK: partial_apply [callee_guaranteed] [[FN]]
+// CHECK: [[SELF:%.*]] = alloc_stack $Optional<@callee_guaranteed (@in_guaranteed ()) -> @out ()>
+// CHECK: apply [[BRIDGE]]<() -> ()>([[SELF]])
+func bridgeOptionalFunctionToAnyObject(fn: (() -> ())?) -> AnyObject {
+  return fn as AnyObject
+}
+
+// CHECK-LABEL: sil_witness_table shared [serialized] GenericOption: Hashable module objc_generics {
+// CHECK-NEXT: base_protocol Equatable: GenericOption: Equatable module objc_generics
+// CHECK-NEXT: method #Hashable.hashValue!getter.1: {{.*}} : @$SSo13GenericOptionas8HashableSCsACP9hashValueSivgTW
+// CHECK-NEXT: method #Hashable._hash!1: {{.*}} : @$SSo13GenericOptionas8HashableSCsACP5_hash4intoys7_HasherVz_tFTW
+// CHECK-NEXT: }
diff --git a/test/SILGen/plus_zero_objc_bridging_peephole.swift b/test/SILGen/plus_zero_objc_bridging_peephole.swift
new file mode 100644
index 0000000..8797bc5
--- /dev/null
+++ b/test/SILGen/plus_zero_objc_bridging_peephole.swift
@@ -0,0 +1,617 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -emit-silgen -enable-sil-ownership %s | %FileCheck %s
+// REQUIRES: objc_interop
+
+import Foundation
+import OtherSubscripts
+import objc_generics
+
+func useNS(_ : NSString) {}
+func useOptNS(_ : NSString?) {}
+func makeNS() -> NSString { return "help" as NSString }
+func makeOptNS() -> NSString? { return nil }
+
+func useAnyObject(_: AnyObject) {}
+func useOptAnyObject(_: AnyObject?) {}
+
+/*** Return values ***********************************************************/
+
+// CHECK-LABEL: sil hidden @$S22objc_bridging_peephole16testMethodResult5dummyySo10DummyClassC_tF
+func testMethodResult(dummy: DummyClass) {
+  // CHECK: bb0([[SELF:%.*]] : @guaranteed $DummyClass):
+  // CHECK: [[METHOD:%.*]] = objc_method [[SELF]] : $DummyClass, #DummyClass.fetchNullableString!1.foreign
+  // CHECK-NEXT: [[RESULT:%.*]] = apply [[METHOD]]([[SELF]])
+  // CHECK-NEXT: [[BORROWED_RESULT:%.*]] = begin_borrow [[RESULT]]
+  // CHECK:      [[USE:%.*]] = function_ref @$S22objc_bridging_peephole8useOptNSyySo8NSStringCSgF
+  // CHECK-NEXT: apply [[USE]]([[BORROWED_RESULT]])
+  useOptNS(dummy.fetchNullableString() as NSString?)
+
+  // CHECK: [[METHOD:%.*]] = objc_method [[SELF]] : $DummyClass, #DummyClass.fetchNullproneString!1.foreign
+  // CHECK-NEXT: [[RESULT:%.*]] = apply [[METHOD]]([[SELF]])
+  // CHECK:      [[BORROWED_RESULT:%.*]] = begin_borrow [[RESULT]]
+  // CHECK:      [[USE:%.*]] = function_ref @$S22objc_bridging_peephole8useOptNSyySo8NSStringCSgF
+  // CHECK-NEXT: apply [[USE]]([[BORROWED_RESULT]])
+  useOptNS(dummy.fetchNullproneString() as NSString?)
+
+  // CHECK: [[METHOD:%.*]] = objc_method [[SELF]] : $DummyClass, #DummyClass.fetchNonnullString!1.foreign
+  // CHECK-NEXT: [[RESULT:%.*]] = apply [[METHOD]]([[SELF]])
+  // CHECK:      [[BORROWED_RESULT:%.*]] = begin_borrow [[RESULT]]
+  // CHECK:      [[USE:%.*]] = function_ref @$S22objc_bridging_peephole8useOptNSyySo8NSStringCSgF
+  // CHECK-NEXT: apply [[USE]]([[BORROWED_RESULT]])
+  useOptNS(dummy.fetchNonnullString() as NSString?)
+
+  // CHECK: [[METHOD:%.*]] = objc_method
+  // CHECK-NEXT: [[RESULT:%.*]] = apply [[METHOD]]([[SELF]])
+  // CHECK-NEXT: [[ANYOBJECT:%.*]] = unchecked_ref_cast [[RESULT]] : $Optional<NSString> to $Optional<AnyObject>
+  // CHECK-NEXT: [[BORROWED_ANYOBJECT:%.*]] = begin_borrow [[ANYOBJECT]]
+  // CHECK:      [[USE:%.*]] = function_ref @$S22objc_bridging_peephole15useOptAnyObjectyyyXlSgF
+  // CHECK-NEXT: apply [[USE]]([[BORROWED_ANYOBJECT]])
+  useOptAnyObject(dummy.fetchNullableString() as AnyObject?)
+
+  // CHECK: [[METHOD:%.*]] = objc_method 
+  // CHECK-NEXT: [[RESULT:%.*]] = apply [[METHOD]]([[SELF]])
+  // CHECK-NEXT: [[ANYOBJECT:%.*]] = unchecked_ref_cast [[RESULT]] : $Optional<NSString> to $Optional<AnyObject>
+  // CHECK:      [[BORROWED_ANYOBJECT:%.*]] = begin_borrow [[ANYOBJECT]]
+  // CHECK:      [[USE:%.*]] = function_ref @$S22objc_bridging_peephole15useOptAnyObjectyyyXlSgF
+  // CHECK-NEXT: apply [[USE]]([[BORROWED_ANYOBJECT]])
+  useOptAnyObject(dummy.fetchNullproneString() as AnyObject?)
+
+  // CHECK: [[METHOD:%.*]] = objc_method
+  // CHECK-NEXT: [[RESULT:%.*]] = apply [[METHOD]]([[SELF]])
+  // CHECK-NEXT: [[ANYOBJECT:%.*]] = unchecked_ref_cast [[RESULT]] : $Optional<NSString> to $Optional<AnyObject>
+  // CHECK:      [[BORROWED_ANYOBJECT:%.*]] = begin_borrow [[ANYOBJECT]]
+  // CHECK:      [[USE:%.*]] = function_ref @$S22objc_bridging_peephole15useOptAnyObjectyyyXlSgF
+  // CHECK-NEXT: apply [[USE]]([[BORROWED_ANYOBJECT]])
+  useOptAnyObject(dummy.fetchNonnullString() as AnyObject?)
+
+  // CHECK:      return
+}
+
+// CHECK-LABEL: sil hidden @$S22objc_bridging_peephole23testNonNullMethodResult5dummyySo10DummyClassC_tF
+func testNonNullMethodResult(dummy: DummyClass) {
+  // CHECK: bb0([[ARG:%.*]] @guaranteed $DummyClass):
+  // CHECK:      [[METHOD:%.*]] = objc_method
+  // CHECK-NEXT: [[RESULT:%.*]] = apply [[METHOD]]([[SELF]])
+  // CHECK-NEXT: switch_enum [[RESULT]]
+  //
+  // CHECK:    bb1:
+  // CHECK:      function_ref @$Ss30_diagnoseUnexpectedNilOptional14_filenameStart01_E6Length01_E7IsASCII5_lineyBp_BwBi1_BwtF
+  // CHECK:    bb2([[RESULT:%.*]] : @owned $NSString):
+  // CHECK:      [[BORROWED_RESULT:%.*]] = begin_borrow [[RESULT]]
+  // CHECK:      [[USE:%.*]] = function_ref @$S22objc_bridging_peephole5useNSyySo8NSStringCF
+  // CHECK-NEXT: apply [[USE]]([[BORROWED_RESULT]])
+  useNS(dummy.fetchNonnullString() as NSString)
+
+  // CHECK: [[METHOD:%.*]] = objc_method
+  // CHECK-NEXT: [[RESULT:%.*]] = apply [[METHOD]]([[SELF]])
+  // CHECK-NEXT: switch_enum [[RESULT]]
+  // CHECK:    bb3:
+  // CHECK:      function_ref @$Ss30_diagnoseUnexpectedNilOptional14_filenameStart01_E6Length01_E7IsASCII5_lineyBp_BwBi1_BwtF
+  // CHECK:    bb4([[RESULT:%.*]] : @owned $NSString):
+  // CHECK-NEXT: [[ANYOBJECT:%.*]] = init_existential_ref [[RESULT]] : $NSString : $NSString, $AnyObject
+  // CHECK-NEXT: [[BORROWED_ANYOBJECT:%.*]] = begin_borrow [[ANYOBJECT]]
+  // CHECK:      [[USE:%.*]] = function_ref @$S22objc_bridging_peephole12useAnyObjectyyyXlF
+  // CHECK-NEXT: apply [[USE]]([[BORROWED_ANYOBJECT]])
+  useAnyObject(dummy.fetchNonnullString() as AnyObject)
+
+  // CHECK:      return
+}
+
+// CHECK-LABEL: sil hidden @$S22objc_bridging_peephole22testForcedMethodResult5dummyySo10DummyClassC_tF
+// CHECK: bb0([[SELF:%.*]] : @guaranteed $DummyClass):
+func testForcedMethodResult(dummy: DummyClass) {
+  // CHECK:      [[METHOD:%.*]] = objc_method
+  // CHECK-NEXT: [[RESULT:%.*]] = apply [[METHOD]]([[SELF]])
+  // CHECK-NEXT: switch_enum [[RESULT]]
+  // CHECK:    bb1:
+  // CHECK:      function_ref @$Ss30_diagnoseUnexpectedNilOptional14_filenameStart01_E6Length01_E7IsASCII5_lineyBp_BwBi1_BwtF
+  // CHECK:    bb2([[RESULT:%.*]] : @owned $NSString):
+  // CHECK:      [[BORROWED_RESULT:%.*]] = begin_borrow [[RESULT]]
+  // CHECK:      [[USE:%.*]] = function_ref @$S22objc_bridging_peephole5useNSyySo8NSStringCF
+  // CHECK-NEXT: apply [[USE]]([[BORROWED_RESULT]])
+  useNS(dummy.fetchNullproneString() as NSString)
+
+  //   This is not a force.
+  //   TODO: we could do it more efficiently than this, though
+  // CHECK:      [[METHOD:%.*]] = objc_method
+  // CHECK-NEXT: [[RESULT:%.*]] = apply [[METHOD]]([[SELF]])
+  // CHECK-NEXT: switch_enum [[RESULT]]
+  //
+  // CHECK:    bb3([[RESULT:%.*]] : @owned $NSString):
+  // CHECK:      function_ref @$SSS10FoundationE36_unconditionallyBridgeFromObjectiveCySSSo8NSStringCSgFZ
+  //
+  // CHECK:    bb4:
+  // CHECK:      enum $Optional<String>, #Optional.none
+  //
+  // CHECK:    bb5([[OPTSTRING:%.*]] : @owned $Optional<String>):
+  // CHECK:      [[BRIDGE:%.*]] = function_ref @$SSq19_bridgeToObjectiveCyXlyF
+  // CHECK-NEXT: [[TEMP:%.*]] = alloc_stack $Optional<String>
+  // CHECK-NEXT: [[BORROW:%.*]] = begin_borrow [[OPTSTRING]]
+  // CHECK-NEXT: store_borrow [[BORROW]] to [[TEMP]] : $*Optional<String>
+  // CHECK-NEXT: [[ANYOBJECT:%.*]] = apply [[BRIDGE]]<String>([[TEMP]])
+  // CHECK:      [[BORROWED_ANYOBJECT:%.*]] = begin_borrow [[ANYOBJECT]]
+  // CHECK:      [[USE:%.*]] = function_ref @$S22objc_bridging_peephole12useAnyObjectyyyXlF
+  // CHECK:      apply [[USE]]([[BORROWED_ANYOBJECT]])
+  useAnyObject(dummy.fetchNullproneString() as AnyObject)
+
+  // CHECK:      return
+}
+
+/*** Property loads **********************************************************/
+
+// CHECK-LABEL: sil hidden @$S22objc_bridging_peephole17testPropertyValue5dummyySo10DummyClassC_tF
+// CHECK: bb0([[SELF:%.*]] : @guaranteed $DummyClass):
+func testPropertyValue(dummy: DummyClass) {
+  // CHECK: [[METHOD:%.*]] = objc_method
+  // CHECK:      [[RESULT:%.*]] = apply [[METHOD]]([[SELF]])
+  // CHECK:      [[BORROWED_RESULT:%.*]] = begin_borrow [[RESULT]]
+  // CHECK:      [[USE:%.*]] = function_ref @$S22objc_bridging_peephole8useOptNSyySo8NSStringCSgF
+  // CHECK:      apply [[USE]]([[BORROWED_RESULT]])
+  useOptNS(dummy.nullableStringProperty as NSString?)
+
+  // CHECK:      [[METHOD:%.*]] = objc_method
+  // CHECK:      [[RESULT:%.*]] = apply [[METHOD]]([[SELF]])
+  // CHECK:      [[BORROWED_RESULT:%.*]] = begin_borrow [[RESULT]]
+  // CHECK:      [[USE:%.*]] = function_ref @$S22objc_bridging_peephole8useOptNSyySo8NSStringCSgF
+  // CHECK:      apply [[USE]]([[BORROWED_RESULT]])
+  useOptNS(dummy.nullproneStringProperty as NSString?)
+
+  // CHECK:      [[METHOD:%.*]] = objc_method
+  // CHECK:      [[RESULT:%.*]] = apply [[METHOD]]([[SELF]])
+  // CHECK:      [[BORROWED_RESULT:%.*]] = begin_borrow [[RESULT]]
+  // CHECK:      [[USE:%.*]] = function_ref @$S22objc_bridging_peephole8useOptNSyySo8NSStringCSgF
+  // CHECK:      apply [[USE]]([[BORROWED_RESULT]])
+  useOptNS(dummy.nonnullStringProperty as NSString?)
+
+  // CHECK:      [[METHOD:%.*]] = objc_method
+  // CHECK:      [[RESULT:%.*]] = apply [[METHOD]]([[SELF]])
+  // CHECK:      [[ANYOBJECT:%.*]] = unchecked_ref_cast [[RESULT]] : $Optional<NSString> to $Optional<AnyObject>
+  // CHECK:      [[BORROWED_ANYOBJECT:%.*]] = begin_borrow [[ANYOBJECT]]
+  // CHECK:      [[USE:%.*]] = function_ref @$S22objc_bridging_peephole15useOptAnyObjectyyyXlSgF
+  // CHECK:      apply [[USE]]([[BORROWED_ANYOBJECT]])
+  useOptAnyObject(dummy.nullableStringProperty as AnyObject?)
+
+  // CHECK:      [[METHOD:%.*]] = objc_method
+  // CHECK:      [[RESULT:%.*]] = apply [[METHOD]]([[SELF]])
+  // CHECK:      [[ANYOBJECT:%.*]] = unchecked_ref_cast [[RESULT]] : $Optional<NSString> to $Optional<AnyObject>
+  // CHECK:      [[BORROWED_ANYOBJECT:%.*]] = begin_borrow [[ANYOBJECT]]
+  // CHECK:      [[USE:%.*]] = function_ref @$S22objc_bridging_peephole15useOptAnyObjectyyyXlSgF
+  // CHECK:      apply [[USE]]([[BORROWED_ANYOBJECT]])
+  useOptAnyObject(dummy.nullproneStringProperty as AnyObject?)
+
+  // CHECK:      [[METHOD:%.*]] = objc_method
+  // CHECK:      [[RESULT:%.*]] = apply [[METHOD]]([[SELF]])
+  // CHECK:      [[ANYOBJECT:%.*]] = unchecked_ref_cast [[RESULT]] : $Optional<NSString> to $Optional<AnyObject>
+  // CHECK:      [[BORROWED_ANYOBJECT:%.*]] = begin_borrow [[ANYOBJECT]]
+  // CHECK:      [[USE:%.*]] = function_ref @$S22objc_bridging_peephole15useOptAnyObjectyyyXlSgF
+  // CHECK:      apply [[USE]]([[BORROWED_ANYOBJECT]])
+  useOptAnyObject(dummy.nonnullStringProperty as AnyObject?)
+
+  // CHECK:      return
+}
+
+// CHECK-LABEL: sil hidden @$S22objc_bridging_peephole24testNonNullPropertyValue5dummyySo10DummyClassC_tF
+func testNonNullPropertyValue(dummy: DummyClass) {
+  // CHECK:    bb0([[SELF:%.*]] : @guaranteed $DummyClass):
+  // CHECK:       [[METHOD:%.*]] = objc_method
+  // CHECK:       [[RESULT:%.*]] = apply [[METHOD]]([[SELF]])
+  // CHECK:       switch_enum [[RESULT]]
+  // CHECK:    bb1:
+  // CHECK:      function_ref @$Ss30_diagnoseUnexpectedNilOptional14_filenameStart01_E6Length01_E7IsASCII5_lineyBp_BwBi1_BwtF
+  // CHECK:    bb2([[RESULT:%.*]] : @owned $NSString):
+  // CHECK:      [[BORROWED_RESULT:%.*]] = begin_borrow [[RESULT]]
+  // CHECK:      [[USE:%.*]] = function_ref @$S22objc_bridging_peephole5useNSyySo8NSStringCF
+  // CHECK:      apply [[USE]]([[BORROWED_RESULT]])
+  useNS(dummy.nonnullStringProperty as NSString)
+
+  // CHECK:      [[METHOD:%.*]] = objc_method
+  // CHECK:      [[RESULT:%.*]] = apply [[METHOD]]([[SELF]])
+  // CHECK:      switch_enum [[RESULT]]
+  // CHECK:    bb3:
+  // CHECK:      function_ref @$Ss30_diagnoseUnexpectedNilOptional14_filenameStart01_E6Length01_E7IsASCII5_lineyBp_BwBi1_BwtF
+  // CHECK:    bb4([[RESULT:%.*]] : @owned $NSString):
+  // CHECK:      [[ANYOBJECT:%.*]] = init_existential_ref [[RESULT]] : $NSString : $NSString, $AnyObject
+  // CHECK:      [[BORROWED_ANYOBJECT:%.*]] = begin_borrow [[ANYOBJECT]]
+  // CHECK:      [[USE:%.*]] = function_ref @$S22objc_bridging_peephole12useAnyObjectyyyXlF
+  // CHECK:      apply [[USE]]([[BORROWED_ANYOBJECT]])
+  useAnyObject(dummy.nonnullStringProperty as AnyObject)
+
+  // CHECK:      return
+}
+
+// CHECK-LABEL: sil hidden @$S22objc_bridging_peephole23testForcedPropertyValue5dummyySo10DummyClassC_tF
+func testForcedPropertyValue(dummy: DummyClass) {
+  // CHECK:    bb0([[ARG:%.*]] : @guaranteed $DummyClass):
+  // CHECK:      [[METHOD:%.*]] = objc_method
+  // CHECK:      [[RESULT:%.*]] = apply [[METHOD]]([[SELF]])
+  // CHECK:      switch_enum [[RESULT]]
+  // CHECK:    bb1:
+  // CHECK:      function_ref @$Ss30_diagnoseUnexpectedNilOptional14_filenameStart01_E6Length01_E7IsASCII5_lineyBp_BwBi1_BwtF
+  // CHECK:    bb2([[RESULT:%.*]] : @owned $NSString):
+  // CHECK:      [[BORROWED_RESULT:%.*]] = begin_borrow [[RESULT]]
+  // CHECK:      [[USE:%.*]] = function_ref @$S22objc_bridging_peephole5useNSyySo8NSStringCF
+  // CHECK:      apply [[USE]]([[BORROWED_RESULT]])
+  useNS(dummy.nullproneStringProperty as NSString)
+
+  //   This is not a force.
+  //   TODO: we could do it more efficiently than this, though
+  // CHECK:      [[METHOD:%.*]] = objc_method
+  // CHECK:      [[RESULT:%.*]] = apply [[METHOD]]([[SELF]])
+  // CHECK:      switch_enum [[RESULT]]
+  // CHECK:    bb3([[RESULT:%.*]] : @owned $NSString):
+  // CHECK:      function_ref @$SSS10FoundationE36_unconditionallyBridgeFromObjectiveCySSSo8NSStringCSgFZ
+  // CHECK:    bb4:
+  // CHECK:      enum $Optional<String>, #Optional.none
+  // CHECK:    bb5([[OPTSTRING:%.*]] : @owned $Optional<String>):
+  // CHECK:      [[BRIDGE:%.*]] = function_ref @$SSq19_bridgeToObjectiveCyXlyF
+  // CHECK-NEXT: [[TEMP:%.*]] = alloc_stack $Optional<String>
+  // CHECK-NEXT: [[BORROW:%.*]] = begin_borrow [[OPTSTRING]]
+  // CHECK-NEXT: store_borrow [[BORROW]] to [[TEMP]] : $*Optional<String>
+  // CHECK-NEXT: [[ANYOBJECT:%.*]] = apply [[BRIDGE]]<String>([[TEMP]])
+  // CHECK:      [[BORROWED_ANYOBJECT:%.*]] = begin_borrow [[ANYOBJECT]]
+  // CHECK:      [[USE:%.*]] = function_ref @$S22objc_bridging_peephole12useAnyObjectyyyXlF
+  // CHECK-NEXT: apply [[USE]]([[BORROWED_ANYOBJECT]])
+  // CHECK:      dealloc_stack [[TEMP]]
+  // CHECK:      destroy_value [[OPTSTRING]]
+  useAnyObject(dummy.nullproneStringProperty as AnyObject)
+
+  // CHECK:      return
+}
+
+/*** Subscript loads *********************************************************/
+
+// FIXME: apply peepholes to indices, too!
+
+// CHECK-LABEL: sil hidden @$S22objc_bridging_peephole23testNonnullSubscriptGet6object5indexySo0eF0C_yXltF
+func testNonnullSubscriptGet(object: NonnullSubscript, index: AnyObject) {
+  // CHECK:   bb0([[SELF:%.*]] : @guaranteed $NonnullSubscript,
+  // CHECK:      [[BRIDGE_TO_ID:%.*]] = function_ref @$Ss27_bridgeAnythingToObjectiveCyyXlxlF
+  // CHECK-NEXT: [[INDEX:%.*]] = apply [[BRIDGE_TO_ID]]
+  // CHECK:      [[METHOD:%.*]] = objc_method
+  // CHECK:      [[RESULT:%.*]] = apply [[METHOD]]([[INDEX]], [[SELF]])
+  // CHECK-NEXT: destroy_value [[INDEX]] : $AnyObject
+  // CHECK:      [[BORROWED_RESULT:%.*]] = begin_borrow [[RESULT]]
+  // CHECK:      [[USE:%.*]] = function_ref @$S22objc_bridging_peephole8useOptNSyySo8NSStringCSgF
+  // CHECK-NEXT: apply [[USE]]([[BORROWED_RESULT]])
+  useOptNS(object[index] as NSString?)
+
+  // CHECK:      [[BRIDGE_TO_ID:%.*]] = function_ref @$Ss27_bridgeAnythingToObjectiveCyyXlxlF
+  // CHECK-NEXT: [[INDEX:%.*]] = apply [[BRIDGE_TO_ID]]
+  // CHECK:      [[METHOD:%.*]] = objc_method
+  // CHECK:      [[RESULT:%.*]] = apply [[METHOD]]([[INDEX]], [[SELF]])
+  // CHECK-NEXT: destroy_value [[INDEX]] : $AnyObject
+  // CHECK-NEXT: switch_enum [[RESULT]]
+  // CHECK:      function_ref @$Ss30_diagnoseUnexpectedNilOptional14_filenameStart01_E6Length01_E7IsASCII5_lineyBp_BwBi1_BwtF
+  // CHECK:    bb{{[0-9]+}}([[RESULT:%.*]] : @owned $NSString):
+  // CHECK:      [[BORROWED_RESULT:%.*]] = begin_borrow [[RESULT]]
+  // CHECK:      [[USE:%.*]] = function_ref @$S22objc_bridging_peephole5useNSyySo8NSStringCF
+  // CHECK-NEXT: apply [[USE]]([[BORROWED_RESULT]])
+  useNS(object[index] as NSString)
+
+  // CHECK:      return
+}
+
+// CHECK-LABEL: sil hidden @$S22objc_bridging_peephole24testNullableSubscriptGet6object5indexySo0eF0C_yXltF
+func testNullableSubscriptGet(object: NullableSubscript, index: AnyObject) {
+  // CHECK: bb0([[ARG:%.*]] : @guaranteed $NullableSubscript,
+  // CHECK:      [[BRIDGE_TO_ID:%.*]] = function_ref @$Ss27_bridgeAnythingToObjectiveCyyXlxlF
+  // CHECK-NEXT: [[INDEX:%.*]] = apply [[BRIDGE_TO_ID]]
+  // CHECK:      [[METHOD:%.*]] = objc_method
+  // CHECK:      [[RESULT:%.*]] = apply [[METHOD]]([[INDEX]], [[SELF]])
+  // CHECK-NEXT: destroy_value [[INDEX]] : $AnyObject
+  // CHECK:      [[BORROWED_RESULT:%.*]] = begin_borrow [[RESULT]]
+  // CHECK:      [[USE:%.*]] = function_ref @$S22objc_bridging_peephole8useOptNSyySo8NSStringCSgF
+  // CHECK-NEXT: apply [[USE]]([[BORROWED_RESULT]])
+  useOptNS(object[index] as NSString?)
+
+  // CHECK:      return
+}
+
+// CHECK-LABEL: sil hidden @$S22objc_bridging_peephole25testNullproneSubscriptGet6object5indexySo0eF0C_yXltF
+func testNullproneSubscriptGet(object: NullproneSubscript, index: AnyObject) {
+  // CHECK:   bb0([[ARG:%.*]] : @guaranteed $NullproneSubscript,
+  // CHECK:      [[BRIDGE_TO_ID:%.*]] = function_ref @$Ss27_bridgeAnythingToObjectiveCyyXlxlF
+  // CHECK-NEXT: [[INDEX:%.*]] = apply [[BRIDGE_TO_ID]]
+  // CHECK:      [[METHOD:%.*]] = objc_method
+  // CHECK:      [[RESULT:%.*]] = apply [[METHOD]]([[INDEX]], [[SELF]])
+  // CHECK-NEXT: destroy_value [[INDEX]] : $AnyObject
+  // CHECK:      [[BORROWED_RESULT:%.*]] = begin_borrow [[RESULT]]
+  // CHECK:      [[USE:%.*]] = function_ref @$S22objc_bridging_peephole8useOptNSyySo8NSStringCSgF
+  // CHECK-NEXT: apply [[USE]]([[BORROWED_RESULT]])
+  useOptNS(object[index] as NSString?)
+
+  // CHECK:      [[BRIDGE_TO_ID:%.*]] = function_ref @$Ss27_bridgeAnythingToObjectiveCyyXlxlF
+  // CHECK-NEXT: [[INDEX:%.*]] = apply [[BRIDGE_TO_ID]]
+  // CHECK:      [[METHOD:%.*]] = objc_method
+  // CHECK:      [[RESULT:%.*]] = apply [[METHOD]]([[INDEX]], [[SELF]])
+  // CHECK-NEXT: destroy_value [[INDEX]] : $AnyObject
+  // CHECK-NEXT: switch_enum [[RESULT]]
+  // CHECK:      function_ref @$Ss30_diagnoseUnexpectedNilOptional14_filenameStart01_E6Length01_E7IsASCII5_lineyBp_BwBi1_BwtF
+  // CHECK:    bb{{[0-9]+}}([[RESULT:%.*]] : @owned $NSString):
+  // CHECK:      [[BORROWED_RESULT:%.*]] = begin_borrow [[RESULT]]
+  // CHECK:      [[USE:%.*]] = function_ref @$S22objc_bridging_peephole5useNSyySo8NSStringCF
+  // CHECK-NEXT: apply [[USE]]([[BORROWED_RESULT]])
+  useNS(object[index] as NSString)
+
+  // CHECK:      return
+}
+
+/*** Call arguments **********************************************************/
+
+// CHECK-LABEL: sil hidden @$S22objc_bridging_peephole18testMethodArgument5dummyySo10DummyClassC_tF
+func testMethodArgument(dummy: DummyClass) {
+  // CHECK: bb0([[SELF:%.*]] : @guaranteed $DummyClass):
+  // CHECK:      // function_ref
+  // CHECK-NEXT: [[MAKE:%.*]] = function_ref @$S22objc_bridging_peephole6makeNSSo8NSStringCyF
+  // CHECK-NEXT: [[ARG:%.*]] = apply [[MAKE]]()
+  // CHECK-NEXT: [[METHOD:%.*]] = objc_method
+  // CHECK-NEXT: apply [[METHOD]]([[ARG]], [[SELF]])
+  // CHECK-NEXT: destroy_value [[ARG]]
+  dummy.takeNonnullString(makeNS() as String)
+
+  // CHECK:      // function_ref
+  // CHECK-NEXT: [[MAKE:%.*]] = function_ref @$S22objc_bridging_peephole6makeNSSo8NSStringCyF
+  // CHECK-NEXT: [[ARG:%.*]] = apply [[MAKE]]()
+  // CHECK-NEXT: [[OPTARG:%.*]] = enum $Optional<NSString>, #Optional.some!enumelt.1, [[ARG]] : $NSString
+  // CHECK-NEXT: [[METHOD:%.*]] = objc_method
+  // CHECK-NEXT: apply [[METHOD]]([[OPTARG]], [[SELF]])
+  // CHECK-NEXT: destroy_value [[OPTARG]]
+  dummy.takeNullableString(makeNS() as String)
+
+  // CHECK-NEXT: // function_ref
+  // CHECK-NEXT: [[MAKE:%.*]] = function_ref @$S22objc_bridging_peephole6makeNSSo8NSStringCyF
+  // CHECK-NEXT: [[ARG:%.*]] = apply [[MAKE]]()
+  // CHECK-NEXT: [[OPTARG:%.*]] = enum $Optional<NSString>, #Optional.some!enumelt.1, [[ARG]] : $NSString
+  // CHECK-NEXT: [[METHOD:%.*]] = objc_method
+  // CHECK-NEXT: apply [[METHOD]]([[OPTARG]], [[SELF]])
+  // CHECK-NEXT: destroy_value [[OPTARG]]
+  dummy.takeNullproneString(makeNS() as String)
+
+  // CHECK:      return
+}
+
+// CHECK-LABEL: sil hidden @$S22objc_bridging_peephole28testValueToOptMethodArgument5dummyySo10DummyClassC_tF
+func testValueToOptMethodArgument(dummy: DummyClass) {
+  // CHECK: bb0([[ARG:%.*]] : @guaranteed $DummyClass):
+  // CHECK: [[MAKE:%.*]] = function_ref @$S22objc_bridging_peephole6makeNSSo8NSStringCyF
+  // CHECK-NEXT: [[ARG:%.*]] = apply [[MAKE]]()
+  // CHECK-NEXT: [[OPTARG:%.*]] = enum $Optional<NSString>, #Optional.some!enumelt.1, [[ARG]] : $NSString
+  // CHECK-NEXT: [[METHOD:%.*]] = objc_method
+  // CHECK-NEXT: apply [[METHOD]]([[OPTARG]], [[SELF]])
+  // CHECK-NEXT: destroy_value [[OPTARG]]
+  dummy.takeNullableString(makeNS() as String?)
+
+  // CHECK: [[MAKE:%.*]] = function_ref @$S22objc_bridging_peephole6makeNSSo8NSStringCyF
+  // CHECK-NEXT: [[ARG:%.*]] = apply [[MAKE]]()
+  // CHECK-NEXT: [[OPTARG:%.*]] = enum $Optional<NSString>, #Optional.some!enumelt.1, [[ARG]] : $NSString
+  // CHECK-NEXT: [[METHOD:%.*]] = objc_method
+  // CHECK-NEXT: apply [[METHOD]]([[OPTARG]], [[SELF]])
+  // CHECK-NEXT: destroy_value [[OPTARG]]
+  dummy.takeNullproneString(makeNS() as String?)
+
+  // CHECK:      return
+}
+
+// CHECK-LABEL: sil hidden @$S22objc_bridging_peephole09testOptToE14MethodArgument5dummyySo10DummyClassC_tF
+func testOptToOptMethodArgument(dummy: DummyClass) {
+  // CHECK: bb0([[ARG:%.*]] : @guaranteed $DummyClass):
+  // CHECK: [[MAKE:%.*]] = function_ref @$S22objc_bridging_peephole9makeOptNSSo8NSStringCSgyF
+  // CHECK-NEXT: [[ARG:%.*]] = apply [[MAKE]]()
+  // CHECK-NEXT: [[METHOD:%.*]] = objc_method
+  // CHECK-NEXT: apply [[METHOD]]([[ARG]], [[SELF]])
+  // CHECK-NEXT: destroy_value [[ARG]]
+  dummy.takeNullableString(makeOptNS() as String?)
+
+  // CHECK: [[MAKE:%.*]] = function_ref @$S22objc_bridging_peephole9makeOptNSSo8NSStringCSgyF
+  // CHECK-NEXT: [[ARG:%.*]] = apply [[MAKE]]()
+  // CHECK-NEXT: [[METHOD:%.*]] = objc_method
+  // CHECK-NEXT: apply [[METHOD]]([[ARG]], [[SELF]])
+  // CHECK-NEXT: destroy_value [[ARG]]
+  dummy.takeNullproneString(makeOptNS() as String?)
+
+  // CHECK:      return
+}
+
+/*** Property assignments ****************************************************/
+
+// CHECK-LABEL: sil hidden @$S22objc_bridging_peephole18testPropertySetter5dummyySo10DummyClassC_tF
+func testPropertySetter(dummy: DummyClass) {
+  // CHECK: bb0([[ARG:%.*]] : @guaranteed $DummyClass):
+  // CHECK: [[MAKE:%.*]] = function_ref @$S22objc_bridging_peephole6makeNSSo8NSStringCyF
+  // CHECK-NEXT: [[ARG:%.*]] = apply [[MAKE]]()
+  // CHECK-NEXT: [[METHOD:%.*]] = objc_method
+  // CHECK-NEXT: apply [[METHOD]]([[ARG]], [[SELF]])
+  // CHECK-NEXT: destroy_value [[ARG]]
+  dummy.nonnullStringProperty = makeNS() as String
+
+  // CHECK: [[MAKE:%.*]] = function_ref @$S22objc_bridging_peephole6makeNSSo8NSStringCyF
+  // CHECK-NEXT: [[ARG:%.*]] = apply [[MAKE]]()
+  // CHECK-NEXT: [[OPTARG:%.*]] = enum $Optional<NSString>, #Optional.some!enumelt.1, [[ARG]] : $NSString
+  // CHECK-NEXT: [[METHOD:%.*]] = objc_method
+  // CHECK-NEXT: apply [[METHOD]]([[OPTARG]], [[SELF]])
+  // CHECK-NEXT: destroy_value [[OPTARG]]
+  dummy.nullableStringProperty = makeNS() as String
+
+  // CHECK: [[MAKE:%.*]] = function_ref @$S22objc_bridging_peephole6makeNSSo8NSStringCyF
+  // CHECK-NEXT: [[ARG:%.*]] = apply [[MAKE]]()
+  // CHECK-NEXT: [[OPTARG:%.*]] = enum $Optional<NSString>, #Optional.some!enumelt.1, [[ARG]] : $NSString
+  // CHECK-NEXT: [[METHOD:%.*]] = objc_method
+  // CHECK-NEXT: apply [[METHOD]]([[OPTARG]], [[SELF]])
+  // CHECK-NEXT: destroy_value [[OPTARG]]
+  dummy.nullproneStringProperty = makeNS() as String
+
+  // CHECK:      return
+}
+
+// CHECK-LABEL: sil hidden @$S22objc_bridging_peephole28testValueToOptPropertySetter5dummyySo10DummyClassC_tF
+func testValueToOptPropertySetter(dummy: DummyClass) {
+  // CHECK: bb0([[ARG:%.*]] : @guaranteed $DummyClass):
+  // CHECK: [[MAKE:%.*]] = function_ref @$S22objc_bridging_peephole6makeNSSo8NSStringCyF
+  // CHECK-NEXT: [[ARG:%.*]] = apply [[MAKE]]()
+  // CHECK-NEXT: [[OPTARG:%.*]] = enum $Optional<NSString>, #Optional.some!enumelt.1, [[ARG]] : $NSString
+  // CHECK-NEXT: [[METHOD:%.*]] = objc_method
+  // CHECK-NEXT: apply [[METHOD]]([[OPTARG]], [[SELF]])
+  // CHECK-NEXT: destroy_value [[OPTARG]]
+  dummy.nullableStringProperty = makeNS() as String?
+
+  // CHECK: [[MAKE:%.*]] = function_ref @$S22objc_bridging_peephole6makeNSSo8NSStringCyF
+  // CHECK-NEXT: [[ARG:%.*]] = apply [[MAKE]]()
+  // CHECK-NEXT: [[OPTARG:%.*]] = enum $Optional<NSString>, #Optional.some!enumelt.1, [[ARG]] : $NSString
+  // CHECK-NEXT: [[METHOD:%.*]] = objc_method
+  // CHECK-NEXT: apply [[METHOD]]([[OPTARG]], [[SELF]])
+  // CHECK-NEXT: destroy_value [[OPTARG]]
+  dummy.nullproneStringProperty = makeNS() as String?
+
+  // CHECK:      return
+}
+
+// CHECK-LABEL: sil hidden @$S22objc_bridging_peephole09testOptToE14PropertySetter5dummyySo10DummyClassC_tF
+func testOptToOptPropertySetter(dummy: DummyClass) {
+  // CHECK: bb0([[SELF:%.*]] : @guaranteed $DummyClass):
+  // CHECK: [[MAKE:%.*]] = function_ref @$S22objc_bridging_peephole9makeOptNSSo8NSStringCSgyF
+  // CHECK-NEXT: [[ARG:%.*]] = apply [[MAKE]]()
+  // CHECK-NEXT: [[METHOD:%.*]] = objc_method
+  // CHECK-NEXT: apply [[METHOD]]([[ARG]], [[SELF]])
+  // CHECK-NEXT: destroy_value [[ARG]]
+  dummy.nullableStringProperty = makeOptNS() as String?
+
+  // CHECK: [[MAKE:%.*]] = function_ref @$S22objc_bridging_peephole9makeOptNSSo8NSStringCSgyF
+  // CHECK-NEXT: [[ARG:%.*]] = apply [[MAKE]]()
+  // CHECK-NEXT: [[METHOD:%.*]] = objc_method
+  // CHECK-NEXT: apply [[METHOD]]([[ARG]], [[SELF]])
+  // CHECK-NEXT: destroy_value [[ARG]]
+  dummy.nullproneStringProperty = makeOptNS() as String?
+
+  // CHECK:      return
+}
+
+/*** Subscript assignments ***************************************************/
+
+// FIXME: apply peepholes to indices, too!
+
+// CHECK-LABEL: sil hidden @$S22objc_bridging_peephole23testNonnullSubscriptSet6object5indexySo0eF0C_yXltF
+func testNonnullSubscriptSet(object: NonnullSubscript, index: AnyObject) {
+  // CHECK: bb0([[SELF:%.*]] : @guaranteed $NonnullSubscript,
+  // CHECK:      [[MAKE:%.*]] = function_ref @$S22objc_bridging_peephole6makeNSSo8NSStringCyF
+  // CHECK-NEXT: [[ARG:%.*]] = apply [[MAKE]]()
+  // CHECK:      [[BRIDGE_TO_ID:%.*]] = function_ref @$Ss27_bridgeAnythingToObjectiveCyyXlxlF
+  // CHECK-NEXT: [[INDEX:%.*]] = apply [[BRIDGE_TO_ID]]
+  // CHECK:      [[METHOD:%.*]] = objc_method
+  // CHECK:      apply [[METHOD]]([[ARG]], [[INDEX]], [[SELF]])
+  // CHECK:      destroy_value [[INDEX]]
+  // CHECK:      destroy_value [[ARG]]
+  object[index] = makeNS() as String
+
+  // CHECK:      return
+}
+
+// CHECK-LABEL: sil hidden @$S22objc_bridging_peephole24testNullableSubscriptSet6object5indexySo0eF0C_yXltF
+func testNullableSubscriptSet(object: NullableSubscript, index: AnyObject) {
+  // CHECK: bb0([[SELF:%.*]] : @guaranteed $NullableSubscript,
+  // CHECK:      [[MAKE:%.*]] = function_ref @$S22objc_bridging_peephole6makeNSSo8NSStringCyF
+  // CHECK-NEXT: [[ARG:%.*]] = apply [[MAKE]]()
+  // CHECK-NEXT: [[OPTARG:%.*]] = enum $Optional<NSString>, #Optional.some!enumelt.1, [[ARG]]
+  // CHECK:      [[BRIDGE_TO_ID:%.*]] = function_ref @$Ss27_bridgeAnythingToObjectiveCyyXlxlF
+  // CHECK-NEXT: [[INDEX:%.*]] = apply [[BRIDGE_TO_ID]]
+  // CHECK:      [[METHOD:%.*]] = objc_method
+  // CHECK:      apply [[METHOD]]([[OPTARG]], [[INDEX]], [[SELF]])
+  // CHECK:      destroy_value [[INDEX]]
+  // CHECK:      destroy_value [[OPTARG]]
+  object[index] = makeNS() as String
+
+  // CHECK:      [[MAKE:%.*]] = function_ref @$S22objc_bridging_peephole6makeNSSo8NSStringCyF
+  // CHECK-NEXT: [[ARG:%.*]] = apply [[MAKE]]()
+  // CHECK-NEXT: [[OPTARG:%.*]] = enum $Optional<NSString>, #Optional.some!enumelt.1, [[ARG]]
+  // CHECK:      [[BRIDGE_TO_ID:%.*]] = function_ref @$Ss27_bridgeAnythingToObjectiveCyyXlxlF
+  // CHECK-NEXT: [[INDEX:%.*]] = apply [[BRIDGE_TO_ID]]
+  // CHECK:      [[METHOD:%.*]] = objc_method
+  // CHECK:      apply [[METHOD]]([[OPTARG]], [[INDEX]], [[SELF]])
+  // CHECK:      destroy_value [[INDEX]]
+  // CHECK:      destroy_value [[OPTARG]]
+  object[index] = makeNS() as String?
+
+  // CHECK:      [[MAKE:%.*]] = function_ref @$S22objc_bridging_peephole9makeOptNSSo8NSStringCSgyF
+  // CHECK-NEXT: [[ARG:%.*]] = apply [[MAKE]]()
+  // CHECK:      [[BRIDGE_TO_ID:%.*]] = function_ref @$Ss27_bridgeAnythingToObjectiveCyyXlxlF
+  // CHECK-NEXT: [[INDEX:%.*]] = apply [[BRIDGE_TO_ID]]
+  // CHECK:      [[METHOD:%.*]] = objc_method
+  // CHECK:      apply [[METHOD]]([[ARG]], [[INDEX]], [[SELF]])
+  // CHECK:      destroy_value [[INDEX]]
+  // CHECK:      destroy_value [[ARG]]
+  object[index] = makeOptNS() as String?
+
+  // CHECK:      return
+}
+
+// CHECK-LABEL: sil hidden @$S22objc_bridging_peephole25testNullproneSubscriptSet6object5indexySo0eF0C_yXltF
+func testNullproneSubscriptSet(object: NullproneSubscript, index: AnyObject) {
+  // CHECK: bb0([[ARG:%.*]] : @guaranteed $NullproneSubscript,
+  // CHECK:      [[MAKE:%.*]] = function_ref @$S22objc_bridging_peephole6makeNSSo8NSStringCyF
+  // CHECK-NEXT: [[ARG:%.*]] = apply [[MAKE]]()
+  // CHECK-NEXT: [[OPTARG:%.*]] = enum $Optional<NSString>, #Optional.some!enumelt.1, [[ARG]]
+  // CHECK:      [[BRIDGE_TO_ID:%.*]] = function_ref @$Ss27_bridgeAnythingToObjectiveCyyXlxlF
+  // CHECK-NEXT: [[INDEX:%.*]] = apply [[BRIDGE_TO_ID]]
+  // CHECK:      [[METHOD:%.*]] = objc_method
+  // CHECK:      apply [[METHOD]]([[OPTARG]], [[INDEX]], [[SELF]])
+  // CHECK:      destroy_value [[INDEX]]
+  // CHECK:      destroy_value [[OPTARG]]
+  object[index] = makeNS() as String
+
+  // CHECK:      [[MAKE:%.*]] = function_ref @$S22objc_bridging_peephole6makeNSSo8NSStringCyF
+  // CHECK-NEXT: [[ARG:%.*]] = apply [[MAKE]]()
+  // CHECK-NEXT: [[OPTARG:%.*]] = enum $Optional<NSString>, #Optional.some!enumelt.1, [[ARG]]
+  // CHECK:      [[BRIDGE_TO_ID:%.*]] = function_ref @$Ss27_bridgeAnythingToObjectiveCyyXlxlF
+  // CHECK-NEXT: [[INDEX:%.*]] = apply [[BRIDGE_TO_ID]]
+  // CHECK:      [[METHOD:%.*]] = objc_method
+  // CHECK:      apply [[METHOD]]([[OPTARG]], [[INDEX]], [[SELF]])
+  // CHECK:      destroy_value [[INDEX]]
+  // CHECK:      destroy_value [[OPTARG]]
+  object[index] = makeNS() as String?
+
+  // CHECK:      [[MAKE:%.*]] = function_ref @$S22objc_bridging_peephole9makeOptNSSo8NSStringCSgyF
+  // CHECK-NEXT: [[ARG:%.*]] = apply [[MAKE]]()
+  // CHECK:      [[BRIDGE_TO_ID:%.*]] = function_ref @$Ss27_bridgeAnythingToObjectiveCyyXlxlF
+  // CHECK-NEXT: [[INDEX:%.*]] = apply [[BRIDGE_TO_ID]]
+  // CHECK:      [[METHOD:%.*]] = objc_method
+  // CHECK:      apply [[METHOD]]([[ARG]], [[INDEX]], [[SELF]])
+  // CHECK:      destroy_value [[INDEX]]
+  // CHECK:      destroy_value [[ARG]]
+  object[index] = makeOptNS() as String?
+
+  // CHECK:      return
+}
+
+/*** Bugfixes ***************************************************************/
+
+protocol P {
+  var title : String { get }
+}
+
+func foo(p: P) {
+  DummyClass().takeNullableString(p.title)
+}
+
+// rdar://35402853
+//   Make sure that we don't peephole AnyObject? -> Any? -> AnyObject naively.
+// CHECK-LABEL: sil hidden @$S22objc_bridging_peephole017testOptionalToNonE6BridgeyyF
+func testOptionalToNonOptionalBridge() {
+  // CHECK: apply {{.*}}() : $@convention(c) () -> @autoreleased Optional<AnyObject>
+  // CHECK: function_ref @$Ss018_bridgeAnyObjectToB0yypyXlSgF :
+  // CHECK: [[T0:%.*]] = function_ref @$SSq19_bridgeToObjectiveCyXlyF
+  // CHECK: apply [[T0]]<Any>
+  useAnyObject(returnNullableId() as AnyObject)
+} // CHECK: end sil function '$S22objc_bridging_peephole017testOptionalToNonE6BridgeyyF'
+
+// CHECK-LABEL: sil hidden @$S22objc_bridging_peephole34testBlockToOptionalAnyObjectBridge5blockyyyXB_tF
+func testBlockToOptionalAnyObjectBridge(block: @escaping @convention(block) () -> ()) {
+  // CHECK:      [[T0:%.*]] = begin_borrow {{%.*}} : $@convention(block) () -> ()
+  // CHECK-NEXT: [[T1:%.*]] = copy_value [[T0]]
+  // CHECK-NEXT: [[REF:%.*]] = unchecked_ref_cast [[T1]] : $@convention(block) () -> () to $AnyObject
+  // CHECK-NEXT: [[OPTREF:%.*]] = enum $Optional<AnyObject>, #Optional.some!enumelt.1, [[REF]] : $AnyObject
+  // CHECK-NEXT: end_borrow [[T0]]
+  // CHECK-NEXT: // function_ref
+  // CHECK-NEXT: [[FN:%.*]] = function_ref @takeNullableId : $@convention(c) (Optional<AnyObject>) -> ()
+  // CHECK-NEXT: apply [[FN]]([[OPTREF]])
+  // CHECK-NEXT: destroy_value [[OPTREF]]
+  takeNullableId(block as Any)
+}
diff --git a/test/SILGen/plus_zero_objc_currying.swift b/test/SILGen/plus_zero_objc_currying.swift
new file mode 100644
index 0000000..8094585
--- /dev/null
+++ b/test/SILGen/plus_zero_objc_currying.swift
@@ -0,0 +1,212 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %empty-directory(%t)
+// RUN: %build-silgen-test-overlays
+// RUN: %target-swift-frontend(mock-sdk: -sdk %S/Inputs -I %t) -enable-sil-ownership -emit-silgen %s | %FileCheck %s
+
+// REQUIRES: objc_interop
+
+import Foundation
+import gizmo
+
+func curry_pod(_ x: CurryTest) -> (Int) -> Int {
+  return x.pod
+}
+// CHECK-LABEL: sil hidden @$S13objc_currying9curry_podyS2icSo9CurryTestCF : $@convention(thin) (@guaranteed CurryTest) -> @owned @callee_guaranteed (Int) -> Int
+// CHECK:      bb0([[ARG1:%.*]] : @guaranteed $CurryTest):
+// CHECK:         [[THUNK:%.*]] = function_ref @[[THUNK_FOO_1:\$SSo9CurryTestC3podyS2iFTcTO]] : $@convention(thin) (@guaranteed CurryTest) -> @owned @callee_guaranteed (Int) -> Int
+// CHECK:         [[FN:%.*]] = apply [[THUNK]]([[ARG1]])
+// CHECK-NOT:     destroy_value
+// CHECK:         return [[FN]]
+// CHECK: } // end sil function '$S13objc_currying9curry_podyS2icSo9CurryTestCF'
+
+// CHECK: sil shared [serializable] [thunk] @[[THUNK_FOO_1]] : $@convention(thin) (@guaranteed CurryTest) -> @owned @callee_guaranteed (Int) -> Int
+// CHECK: bb0([[ARG1:%.*]] : @guaranteed $CurryTest):
+// CHECK:   [[THUNK:%.*]] = function_ref @[[THUNK_FOO_2:\$SSo9CurryTestC3podyS2iFTO]]
+// CHECK:   [[ARG1_COPY:%.*]] = copy_value [[ARG1]]
+// CHECK:   [[FN:%.*]] = partial_apply [callee_guaranteed] [[THUNK]]([[ARG1_COPY]])
+// CHECK-NOT: destroy_value
+// CHECK:   return [[FN]]
+// CHECK: } // end sil function '[[THUNK_FOO_1]]'
+
+// CHECK: sil shared [serializable] [thunk] @[[THUNK_FOO_2]] : $@convention(method) (Int, @guaranteed CurryTest) -> Int
+// CHECK: bb0([[ARG1:%.*]] : @trivial $Int, [[ARG2:%.*]] : @guaranteed $CurryTest):
+// CHECK:   [[COPIED_ARG2:%.*]] = copy_value [[ARG2]]
+// CHECK:   [[METHOD:%.*]] = objc_method [[COPIED_ARG2]] : $CurryTest, #CurryTest.pod!1.foreign
+// CHECK:   [[RESULT:%.*]] = apply [[METHOD]]([[ARG1]], [[COPIED_ARG2]])
+// CHECK:   destroy_value [[COPIED_ARG2]]
+// CHECK:   return [[RESULT]]
+// CHECK: } // end sil function '[[THUNK_FOO_2]]'
+
+func curry_bridged(_ x: CurryTest) -> (String?) -> String? {
+  return x.bridged
+}
+// CHECK-LABEL: sil hidden @$S13objc_currying13curry_bridgedySSSgACcSo9CurryTestCF : $@convention(thin) (@guaranteed CurryTest) -> @owned @callee_guaranteed (@guaranteed Optional<String>) -> @owned Optional<String>
+// CHECK: bb0([[ARG1:%.*]] : @guaranteed $CurryTest):
+// CHECK:   [[THUNK:%.*]] = function_ref @[[THUNK_BAR_1:\$SSo9CurryTestC7bridgedySSSgADFTcTO]]
+// CHECK:   [[FN:%.*]] = apply [[THUNK]]([[ARG1]])
+// CHECK-NOT:   destroy_value [[ARG1]]
+// CHECK:   return [[FN]]
+// CHECK: } // end sil function '$S13objc_currying13curry_bridgedySSSgACcSo9CurryTestCF'
+
+// CHECK: sil shared [serializable] [thunk] @[[THUNK_BAR_1]] : $@convention(thin) (@guaranteed CurryTest) -> @owned @callee_guaranteed (@guaranteed Optional<String>) -> @owned Optional<String>
+// CHECK: bb0([[ARG1:%.*]] : @guaranteed $CurryTest):
+// CHECK:   [[THUNK:%.*]] = function_ref @[[THUNK_BAR_2:\$SSo9CurryTestC7bridgedySSSgADFTO]]
+// CHECK:   [[COPY_ARG1:%.*]] = copy_value [[ARG1]]
+// CHECK:   [[FN:%.*]] = partial_apply [callee_guaranteed] [[THUNK]]([[COPY_ARG1]])
+// CHECK:   return [[FN]]
+// CHECK: } // end sil function '[[THUNK_BAR_1]]'
+
+// CHECK: sil shared [serializable] [thunk] @[[THUNK_BAR_2]] : $@convention(method) (@guaranteed Optional<String>, @guaranteed CurryTest) -> @owned Optional<String>
+// CHECK: bb0([[OPT_STRING:%.*]] : @guaranteed $Optional<String>, [[SELF:%.*]] : @guaranteed $CurryTest):
+// CHECK:   [[COPY_OPT_STRING:%.*]] = copy_value [[OPT_STRING]]
+// CHECK:   switch_enum [[COPY_OPT_STRING]] : $Optional<String>, case #Optional.some!enumelt.1: [[SOME_BB:bb[0-9]+]],
+//
+// CHECK: [[SOME_BB]]([[STRING:%.*]] : @owned $String):
+// CHECK:   [[BRIDGING_FUNC:%.*]] = function_ref @$SSS10FoundationE19_bridgeToObjectiveCSo8NSStringCyF
+// CHECK:   [[BORROWED_STRING:%.*]] = begin_borrow [[STRING]]
+// CHECK:   [[NSSTRING:%.*]] = apply [[BRIDGING_FUNC]]([[BORROWED_STRING]])
+// CHECK:   [[OPT_NSSTRING:%.*]] = enum $Optional<NSString>, #Optional.some!enumelt.1, [[NSSTRING]] : $NSString
+// CHECK:   end_borrow [[BORROWED_STRING]] from [[STRING]]
+// CHECK:   destroy_value [[STRING]]
+// CHECK:   br bb3([[OPT_NSSTRING]] : $Optional<NSString>)
+
+// CHECK: bb2:
+// CHECK:   [[OPT_NONE:%.*]] = enum $Optional<NSString>, #Optional.none!enumelt
+// CHECK:   br bb3([[OPT_NONE]] : $Optional<NSString>)
+
+// CHECK: bb3([[OPT_NSSTRING:%.*]] : @owned $Optional<NSString>):
+// CHECK:   [[SELF_COPY:%.*]] = copy_value [[SELF]]
+// CHECK:   [[METHOD:%.*]] = objc_method [[SELF_COPY]] : $CurryTest, #CurryTest.bridged!1.foreign
+// CHECK:   [[RESULT_OPT_NSSTRING:%.*]] = apply [[METHOD]]([[OPT_NSSTRING]], [[SELF_COPY]]) : $@convention(objc_method) (Optional<NSString>, CurryTest) -> @autoreleased Optional<NSString>
+// CHECK:   switch_enum [[RESULT_OPT_NSSTRING]] : $Optional<NSString>, case #Optional.some!enumelt.1: [[SOME_BB:bb[0-9]+]],
+
+// CHECK: [[SOME_BB]]([[RESULT_NSSTRING:%.*]] : @owned $NSString):
+// CHECK:   [[BRIDGE_FUNC:%.*]] = function_ref @$SSS10FoundationE36_unconditionallyBridgeFromObjectiveCySSSo8NSStringCSgFZ
+// CHECK:   [[REWRAP_RESULT_NSSTRING:%.*]] = enum $Optional<NSString>, #Optional.some!enumelt.1, [[RESULT_NSSTRING]]
+// CHECK:   [[RESULT_STRING:%.*]] = apply [[BRIDGE_FUNC]]([[REWRAP_RESULT_NSSTRING]]
+// CHECK:   [[WRAPPED_RESULT_STRING:%.*]] = enum $Optional<String>, #Optional.some!enumelt.1, [[RESULT_STRING]]
+// CHECK:   br bb6([[WRAPPED_RESULT_STRING]] : $Optional<String>)
+
+// CHECK: bb5:
+// CHECK:   [[OPT_NONE:%.*]] = enum $Optional<String>, #Optional.none!enumelt
+// CHECK:   br bb6([[OPT_NONE]] : $Optional<String>)
+
+// CHECK: bb6([[FINAL_RESULT:%.*]] : @owned $Optional<String>):
+// CHECK:   destroy_value [[SELF_COPY]]
+// CHECK:   destroy_value [[OPT_NSSTRING]]
+// CHECK:   return [[FINAL_RESULT]] : $Optional<String>
+// CHECK: } // end sil function '[[THUNK_BAR_2]]'
+
+func curry_returnsInnerPointer(_ x: CurryTest) -> () -> UnsafeMutableRawPointer? {
+  return x.returnsInnerPointer
+}
+// CHECK-LABEL: sil hidden @$S13objc_currying25curry_returnsInnerPointerySvSgycSo9CurryTestCF : $@convention(thin) (@guaranteed CurryTest) -> @owned @callee_guaranteed () -> Optional<UnsafeMutableRawPointer> {
+// CHECK: bb0([[SELF:%.*]] : @guaranteed $CurryTest):
+// CHECK:   [[THUNK:%.*]] = function_ref @[[THUNK_RETURNSINNERPOINTER:\$SSo9CurryTestC19returnsInnerPointerSvSgyFTcTO]]
+// CHECK:   [[FN:%.*]] = apply [[THUNK]]([[SELF]])
+// CHECK-NOT:   destroy_value [[SELF]]
+// CHECK:   return [[FN]]
+// CHECK: } // end sil function '$S13objc_currying25curry_returnsInnerPointerySvSgycSo9CurryTestCF'
+
+// CHECK: sil shared [serializable] [thunk] @[[THUNK_RETURNSINNERPOINTER]] : $@convention(thin) (@guaranteed CurryTest) -> @owned @callee_guaranteed () -> Optional<UnsafeMutableRawPointer>
+// CHECK: bb0([[ARG1:%.*]] : @guaranteed
+// CHECK:   [[THUNK:%.*]] = function_ref @[[THUNK_RETURNSINNERPOINTER_2:\$SSo9CurryTestC19returnsInnerPointerSvSgyFTO]]
+// CHECK:   [[COPY_ARG1:%.*]] = copy_value [[ARG1]]
+// CHECK:   [[FN:%.*]] = partial_apply [callee_guaranteed] [[THUNK]]([[COPY_ARG1]])
+// CHECK:   return [[FN]]
+// CHECK: } // end sil function '[[THUNK_RETURNSINNERPOINTER]]'
+
+// CHECK: sil shared [serializable] [thunk] @[[THUNK_RETURNSINNERPOINTER_2]] : $@convention(method) (@guaranteed CurryTest) -> Optional<UnsafeMutableRawPointer>
+// CHECK:  bb0([[ARG1:%.*]] : @guaranteed $CurryTest):
+// CHECK:   [[ARG1_COPY:%.*]] = copy_value [[ARG1]]
+// CHECK:   [[METHOD:%.*]] = objc_method [[ARG1_COPY]] : $CurryTest, #CurryTest.returnsInnerPointer!1.foreign
+// CHECK:   [[RES:%.*]] = apply [[METHOD]]([[ARG1_COPY]]) : $@convention(objc_method) (CurryTest) -> @unowned_inner_pointer Optional<UnsafeMutableRawPointer>
+// CHECK:   autorelease_value 
+// CHECK:   return [[RES]]
+// CHECK: } // end sil function '[[THUNK_RETURNSINNERPOINTER_2]]'
+
+// CHECK-LABEL: sil hidden @$S13objc_currying19curry_pod_AnyObjectyS2icyXlF : $@convention(thin) (@guaranteed AnyObject) -> @owned @callee_guaranteed (Int) -> Int
+// CHECK: bb0([[ANY:%.*]] : @guaranteed $AnyObject):
+// CHECK:   [[OPENED_ANY:%.*]] = open_existential_ref [[ANY]]
+// CHECK:   [[OPENED_ANY_COPY:%.*]] = copy_value [[OPENED_ANY]]
+// CHECK:   dynamic_method_br [[OPENED_ANY_COPY]] : $@opened({{.*}}) AnyObject, #CurryTest.pod!1.foreign, [[HAS_METHOD:bb[0-9]+]]
+// CHECK:   [[HAS_METHOD]]([[METHOD:%.*]] : @trivial $@convention(objc_method) (Int, @opened({{.*}}) AnyObject) -> Int):
+// CHECK:   [[OPENED_ANY_COPY_2:%.*]] = copy_value [[OPENED_ANY_COPY]]
+// CHECK:   partial_apply [callee_guaranteed] [[METHOD]]([[OPENED_ANY_COPY_2]])
+// CHECK: } // end sil function '$S13objc_currying19curry_pod_AnyObjectyS2icyXlF'
+func curry_pod_AnyObject(_ x: AnyObject) -> (Int) -> Int {
+  return x.pod!
+}
+
+// normalOwnership requires a thunk to bring the method to Swift conventions
+// CHECK-LABEL: sil hidden @$S13objc_currying31curry_normalOwnership_AnyObjectySo9CurryTestCSgAEcyXlF : $@convention(thin) (@guaranteed AnyObject) -> @owned @callee_guaranteed (@guaranteed Optional<CurryTest>) -> @owned Optional<CurryTest> {
+// CHECK: bb0([[ANY:%.*]] : @guaranteed $AnyObject):
+// CHECK:   [[OPENED_ANY:%.*]] = open_existential_ref [[ANY]]
+// CHECK:   [[OPENED_ANY_COPY:%.*]] = copy_value [[OPENED_ANY]]
+// CHECK:   dynamic_method_br [[OPENED_ANY_COPY]] : $@opened({{.*}}) AnyObject, #CurryTest.normalOwnership!1.foreign, [[HAS_METHOD:bb[0-9]+]]
+// CHECK: [[HAS_METHOD]]([[METHOD:%.*]] : @trivial $@convention(objc_method) (Optional<CurryTest>, @opened({{.*}}) AnyObject) -> @autoreleased Optional<CurryTest>):
+// CHECK:   [[OPENED_ANY_COPY_2:%.*]] = copy_value [[OPENED_ANY_COPY]]
+// CHECK:   [[PA:%.*]] = partial_apply [callee_guaranteed] [[METHOD]]([[OPENED_ANY_COPY_2]])
+// CHECK:   [[THUNK:%.*]] = function_ref @$SSo9CurryTestCSgACIegyo_A2CIeggo_TR
+// CHECK:   partial_apply [callee_guaranteed] [[THUNK]]([[PA]])
+// CHECK: } // end sil function '$S13objc_currying31curry_normalOwnership_AnyObjectySo9CurryTestCSgAEcyXlF'
+func curry_normalOwnership_AnyObject(_ x: AnyObject) -> (CurryTest?) -> CurryTest? {
+  return x.normalOwnership!
+}
+
+// weirdOwnership is NS_RETURNS_RETAINED and NS_CONSUMES_SELF so already
+// follows Swift conventions
+// CHECK-LABEL: sil hidden @$S13objc_currying30curry_weirdOwnership_AnyObjectySo9CurryTestCSgAEcyXlF : $@convention(thin) (@guaranteed AnyObject) -> @owned @callee_guaranteed (@guaranteed Optional<CurryTest>) -> @owned Optional<CurryTest>
+// CHECK: bb0([[ANY:%.*]] : @guaranteed $AnyObject):
+// CHECK:   [[OPENED_ANY:%.*]] = open_existential_ref [[ANY]]
+// CHECK:   [[OPENED_ANY_COPY:%.*]] = copy_value [[OPENED_ANY]]
+// CHECK:   dynamic_method_br [[SELF:%.*]] : $@opened({{.*}}) AnyObject, #CurryTest.weirdOwnership!1.foreign, [[HAS_METHOD:bb[0-9]+]]
+//
+// CHECK: bb1([[METHOD:%.*]] : @trivial $@convention(objc_method) (@owned Optional<CurryTest>, @owned @opened({{.*}}) AnyObject) -> @owned Optional<CurryTest>):
+// CHECK:   [[OPENED_ANY_COPY_2:%.*]] = copy_value [[OPENED_ANY_COPY]]
+// CHECK:   partial_apply [callee_guaranteed] [[METHOD]]([[OPENED_ANY_COPY_2]])
+// CHECK: } // end sil function '$S13objc_currying30curry_weirdOwnership_AnyObjectySo9CurryTestCSgAEcyXlF'
+func curry_weirdOwnership_AnyObject(_ x: AnyObject) -> (CurryTest?) -> CurryTest? {
+  return x.weirdOwnership!
+}
+
+// bridged requires a thunk to handle bridging conversions
+// CHECK-LABEL: sil hidden @$S13objc_currying23curry_bridged_AnyObjectySSSgACcyXlF : $@convention(thin) (@guaranteed AnyObject) -> @owned @callee_guaranteed (@guaranteed Optional<String>) -> @owned Optional<String>
+// CHECK: bb0([[ANY:%.*]] : @guaranteed $AnyObject):
+// CHECK:   [[OPENED_ANY:%.*]] = open_existential_ref [[ANY]]
+// CHECK:   [[OPENED_ANY_COPY:%.*]] = copy_value [[OPENED_ANY]]
+// CHECK:   dynamic_method_br [[OPENED_ANY_COPY]] : $@opened({{.*}}) AnyObject, #CurryTest.bridged!1.foreign, [[HAS_METHOD:bb[0-9]+]]
+// CHECK: } // end sil function '$S13objc_currying23curry_bridged_AnyObjectySSSgACcyXlF'
+func curry_bridged_AnyObject(_ x: AnyObject) -> (String?) -> String? {
+  return x.bridged!
+}
+
+// check that we substitute Self = AnyObject correctly for Self-returning
+// methods
+// CHECK-LABEL: sil hidden @$S13objc_currying27curry_returnsSelf_AnyObjectyyXlSgycyXlF : $@convention(thin) (@guaranteed AnyObject) -> @owned @callee_guaranteed () -> @owned Optional<AnyObject> {
+// CHECK: bb0([[ANY:%.*]] : @guaranteed $AnyObject):
+// CHECK:   [[OPENED_ANY:%.*]] = open_existential_ref [[ANY]]
+// CHECK:   [[OPENED_ANY_COPY:%.*]] = copy_value [[OPENED_ANY]]
+// CHECK:   dynamic_method_br [[OPENED_ANY_COPY]] : $@opened({{.*}}) AnyObject, #CurryTest.returnsSelf!1.foreign, [[HAS_METHOD:bb[0-9]+]]
+// CHECK: [[HAS_METHOD]]([[METHOD:%.*]] : @trivial $@convention(objc_method) (@opened({{.*}}) AnyObject) -> @autoreleased Optional<AnyObject>):
+// CHECK:   [[OPENED_ANY_COPY_2:%.*]] = copy_value [[OPENED_ANY_COPY]]
+// CHECK:   [[PA:%.*]] = partial_apply [callee_guaranteed] [[METHOD]]([[OPENED_ANY_COPY_2]])
+// CHECK: } // end sil function '$S13objc_currying27curry_returnsSelf_AnyObjectyyXlSgycyXlF'
+func curry_returnsSelf_AnyObject(_ x: AnyObject) -> () -> AnyObject? {
+  return x.returnsSelf!
+}
+
+// CHECK-LABEL: sil hidden @$S13objc_currying35curry_returnsInnerPointer_AnyObjectySvSgycyXlF : $@convention(thin) (@guaranteed AnyObject) -> @owned @callee_guaranteed () -> Optional<UnsafeMutableRawPointer> {
+// CHECK: bb0([[ANY:%.*]] : @guaranteed $AnyObject):
+// CHECK:   [[OPENED_ANY:%.*]] = open_existential_ref [[ANY]]
+// CHECK:   [[OPENED_ANY_COPY:%.*]] = copy_value [[OPENED_ANY]]
+// CHECK:   dynamic_method_br [[OPENED_ANY_COPY]] : $@opened({{.*}}) AnyObject, #CurryTest.returnsInnerPointer!1.foreign, [[HAS_METHOD:bb[0-9]+]]
+// CHECK: [[HAS_METHOD]]([[METHOD:%.*]] : @trivial $@convention(objc_method) (@opened({{.*}}) AnyObject) -> @unowned_inner_pointer Optional<UnsafeMutableRawPointer>):
+// CHECK:   [[OPENED_ANY_COPY_2:%.*]] = copy_value [[OPENED_ANY_COPY]]
+// CHECK:   [[PA:%.*]] = partial_apply [callee_guaranteed] [[METHOD]]([[OPENED_ANY_COPY_2]])
+// CHECK: } // end sil function '$S13objc_currying35curry_returnsInnerPointer_AnyObjectySvSgycyXlF'
+
+func curry_returnsInnerPointer_AnyObject(_ x: AnyObject) -> () -> UnsafeMutableRawPointer? {
+  return x.returnsInnerPointer!
+}
+
diff --git a/test/SILGen/plus_zero_objc_dictionary_bridging.swift b/test/SILGen/plus_zero_objc_dictionary_bridging.swift
new file mode 100644
index 0000000..cee9ad3
--- /dev/null
+++ b/test/SILGen/plus_zero_objc_dictionary_bridging.swift
@@ -0,0 +1,96 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %empty-directory(%t)
+// RUN: %build-silgen-test-overlays
+
+// RUN: %target-swift-frontend(mock-sdk: -sdk %S/Inputs -I %t) -emit-silgen -enable-sil-ownership %s | %FileCheck %s
+
+// REQUIRES: objc_interop
+
+import Foundation
+import gizmo
+
+@objc class Foo : NSObject {
+  // Bridging dictionary parameters
+  // CHECK-LABEL: sil hidden [thunk] @$S24objc_dictionary_bridging3FooC23bridge_Dictionary_param{{[_0-9a-zA-Z]*}}FTo : $@convention(objc_method) (NSDictionary, Foo) -> ()
+  func bridge_Dictionary_param(_ dict: Dictionary<Foo, Foo>) {
+    // CHECK: bb0([[NSDICT:%[0-9]+]] : @unowned $NSDictionary, [[SELF:%[0-9]+]] : @unowned $Foo):
+    // CHECK:   [[NSDICT_COPY:%.*]] = copy_value [[NSDICT]]
+    // CHECK:   [[SELF_COPY:%.*]] = copy_value [[SELF]]
+    // CHECK:   [[CONVERTER:%[0-9]+]] = function_ref @$Ss10DictionaryV10FoundationE36_unconditionallyBridgeFromObjectiveCyAByxq_GSo12NSDictionaryCSgFZ
+    // CHECK:   [[OPT_NSDICT:%[0-9]+]] = enum $Optional<NSDictionary>, #Optional.some!enumelt.1, [[NSDICT_COPY]] : $NSDictionary
+    // CHECK:   [[DICT_META:%[0-9]+]] = metatype $@thin Dictionary<Foo, Foo>.Type
+    // CHECK:   [[DICT:%[0-9]+]] = apply [[CONVERTER]]<Foo, Foo>([[OPT_NSDICT]], [[DICT_META]])
+    // CHECK:   [[BORROWED_DICT:%.*]] = begin_borrow [[DICT]]
+    // CHECK:   [[BORROWED_SELF_COPY:%.*]] = begin_borrow [[SELF_COPY]]
+    // CHECK:   [[SWIFT_FN:%[0-9]+]] = function_ref @$S24objc_dictionary_bridging3FooC23bridge_Dictionary_param{{[_0-9a-zA-Z]*}}F
+    // CHECK:   [[RESULT:%[0-9]+]] = apply [[SWIFT_FN]]([[BORROWED_DICT]], [[BORROWED_SELF_COPY]]) : $@convention(method) (@guaranteed Dictionary<Foo, Foo>, @guaranteed Foo) -> ()
+    // CHECK:   end_borrow [[BORROWED_SELF_COPY]] from [[SELF_COPY]]
+    // CHECK:   destroy_value [[SELF_COPY]]
+    // CHECK:   return [[RESULT]] : $()
+  }
+  // CHECK: } // end sil function '$S24objc_dictionary_bridging3FooC23bridge_Dictionary_param{{[_0-9a-zA-Z]*}}FTo'
+
+  // Bridging dictionary results
+  // CHECK-LABEL: sil hidden [thunk] @$S24objc_dictionary_bridging3FooC24bridge_Dictionary_result{{[_0-9a-zA-Z]*}}FTo : $@convention(objc_method) (Foo) -> @autoreleased NSDictionary
+  func bridge_Dictionary_result() -> Dictionary<Foo, Foo> { 
+    // CHECK: bb0([[SELF:%[0-9]+]] : @unowned $Foo):
+    // CHECK:   [[SELF_COPY:%.*]] = copy_value [[SELF]]
+    // CHECK:   [[BORROWED_SELF_COPY:%.*]] = begin_borrow [[SELF_COPY]]
+    // CHECK:   [[SWIFT_FN:%[0-9]+]] = function_ref @$S24objc_dictionary_bridging3FooC24bridge_Dictionary_result{{[_0-9a-zA-Z]*}}F : $@convention(method) (@guaranteed Foo) -> @owned Dictionary<Foo, Foo>
+    // CHECK:   [[DICT:%[0-9]+]] = apply [[SWIFT_FN]]([[BORROWED_SELF_COPY]]) : $@convention(method) (@guaranteed Foo) -> @owned Dictionary<Foo, Foo>
+    // CHECK:   end_borrow [[BORROWED_SELF_COPY]] from [[SELF_COPY]]
+    // CHECK:   destroy_value [[SELF_COPY]]
+
+    // CHECK:   [[CONVERTER:%[0-9]+]] = function_ref @$Ss10DictionaryV10FoundationE19_bridgeToObjectiveCSo12NSDictionaryCyF
+    // CHECK:   [[BORROWED_DICT:%.*]] = begin_borrow [[DICT]]
+    // CHECK:   [[NSDICT:%[0-9]+]] = apply [[CONVERTER]]<Foo, Foo>([[BORROWED_DICT]]) : $@convention(method) <τ_0_0, τ_0_1 where τ_0_0 : Hashable> (@guaranteed Dictionary<τ_0_0, τ_0_1>) -> @owned NSDictionary
+    // CHECK:   end_borrow [[BORROWED_DICT]] from [[DICT]]
+    // CHECK:   destroy_value [[DICT]]
+    // CHECK:   return [[NSDICT]] : $NSDictionary
+  }
+  // CHECK: } // end sil function '$S24objc_dictionary_bridging3FooC24bridge_Dictionary_result{{[_0-9a-zA-Z]*}}FTo'
+
+  var property: Dictionary<Foo, Foo> = [:]
+
+  // Property getter
+  // CHECK-LABEL: sil hidden [thunk] @$S24objc_dictionary_bridging3FooC8propertys10DictionaryVyA2CSo8NSObjectCs8Hashable10Foundationg_GvgTo : $@convention(objc_method) (Foo) -> @autoreleased NSDictionary
+  //                                 @$S24objc_dictionary_bridging3FooC8propertys10DictionaryVyA2CSo8NSObjectCs8Hashable10Foundationg_Gvpfi
+  // CHECK: bb0([[SELF:%[0-9]+]] : @unowned $Foo):
+  // CHECK:   [[SELF_COPY:%.*]] = copy_value [[SELF]]
+  // CHECK:   [[BORROWED_SELF_COPY:%.*]] = begin_borrow [[SELF_COPY]]
+  // CHECK:   [[GETTER:%[0-9]+]] = function_ref @$S24objc_dictionary_bridging3FooC8propertys10DictionaryVyA2CSo8NSObjectCs8Hashable10Foundationg_Gvg : $@convention(method) (@guaranteed Foo) -> @owned Dictionary<Foo, Foo>
+  // CHECK:   [[DICT:%[0-9]+]] = apply [[GETTER]]([[BORROWED_SELF_COPY]]) : $@convention(method) (@guaranteed Foo) -> @owned Dictionary<Foo, Foo>
+  // CHECK:   end_borrow [[BORROWED_SELF_COPY]] from [[SELF_COPY]]
+  // CHECK:   destroy_value [[SELF_COPY]]
+  // CHECK:   [[CONVERTER:%[0-9]+]] = function_ref @$Ss10DictionaryV10FoundationE19_bridgeToObjectiveCSo12NSDictionaryCyF
+  // CHECK:   [[BORROWED_DICT:%.*]] = begin_borrow [[DICT]]
+  // CHECK:   [[NSDICT:%[0-9]+]] = apply [[CONVERTER]]<Foo, Foo>([[BORROWED_DICT]]) : $@convention(method) <τ_0_0, τ_0_1 where τ_0_0 : Hashable> (@guaranteed Dictionary<τ_0_0, τ_0_1>) -> @owned NSDictionary
+  // CHECK:   end_borrow [[BORROWED_DICT]] from [[DICT]]
+  // CHECK:   destroy_value [[DICT]]
+  // CHECK:   return [[NSDICT]] : $NSDictionary
+  // CHECK: } // end sil function
+
+  // Property setter
+  // CHECK-LABEL: sil hidden [thunk] @$S24objc_dictionary_bridging3FooC8propertys10DictionaryVyA2CSo8NSObjectCs8Hashable10Foundationg_GvsTo : $@convention(objc_method) (NSDictionary, Foo) -> ()
+  // CHECK: bb0([[NSDICT:%[0-9]+]] : @unowned $NSDictionary, [[SELF:%[0-9]+]] : @unowned $Foo):
+  // CHECK:   [[NSDICT_COPY:%.*]] = copy_value [[NSDICT]]
+  // CHECK:   [[SELF_COPY:%.*]] = copy_value [[SELF]]
+  // CHECK:   [[CONVERTER:%[0-9]+]] = function_ref @$Ss10DictionaryV10FoundationE36_unconditionallyBridgeFromObjectiveCyAByxq_GSo12NSDictionaryCSgFZ
+  // CHECK:   [[OPT_NSDICT:%[0-9]+]] = enum $Optional<NSDictionary>, #Optional.some!enumelt.1, [[NSDICT_COPY]] : $NSDictionary
+  // CHECK:   [[DICT_META:%[0-9]+]] = metatype $@thin Dictionary<Foo, Foo>.Type
+  // CHECK:   [[DICT:%[0-9]+]] = apply [[CONVERTER]]<Foo, Foo>([[OPT_NSDICT]], [[DICT_META]])
+
+  // CHECK:   [[BORROWED_SELF_COPY:%.*]] = begin_borrow [[SELF_COPY]]
+  // CHECK:   [[SETTER:%[0-9]+]] = function_ref @$S24objc_dictionary_bridging3FooC8propertys10DictionaryVyA2CSo8NSObjectCs8Hashable10Foundationg_Gvs : $@convention(method) (@owned Dictionary<Foo, Foo>, @guaranteed Foo) -> ()
+  // CHECK:   [[RESULT:%[0-9]+]] = apply [[SETTER]]([[DICT]], [[BORROWED_SELF_COPY]]) : $@convention(method) (@owned Dictionary<Foo, Foo>, @guaranteed Foo) -> ()
+  // CHECK:   end_borrow [[BORROWED_SELF_COPY]] from [[SELF_COPY]]
+  // CHECK:   destroy_value [[SELF_COPY]]
+  // CHECK:   return [[RESULT]] : $()
+
+  // CHECK-LABEL: sil hidden [thunk] @$S24objc_dictionary_bridging3FooC19nonVerbatimProperty{{[_0-9a-zA-Z]*}}vgTo : $@convention(objc_method) (Foo) -> @autoreleased NSDictionary
+
+  // CHECK-LABEL: sil hidden [thunk] @$S24objc_dictionary_bridging3FooC19nonVerbatimProperty{{[_0-9a-zA-Z]*}}vsTo : $@convention(objc_method) (NSDictionary, Foo) -> ()
+  @objc var nonVerbatimProperty: Dictionary<String, Int> = [:]
+}
+
+func ==(x: Foo, y: Foo) -> Bool { }
diff --git a/test/SILGen/plus_zero_objc_error.swift b/test/SILGen/plus_zero_objc_error.swift
new file mode 100644
index 0000000..e48d19c
--- /dev/null
+++ b/test/SILGen/plus_zero_objc_error.swift
@@ -0,0 +1,173 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %empty-directory(%t)
+// RUN: %build-clang-importer-objc-overlays
+
+// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk-nosource -I %t) -emit-silgen -enable-sil-ownership %s | %FileCheck %s
+
+// REQUIRES: objc_interop
+
+import Foundation
+
+// CHECK-LABEL: sil hidden @$S10objc_error20NSErrorError_erasureys0D0_pSo0C0CF : $@convention(thin) (@guaranteed NSError) -> @owned Error {
+// CHECK:         bb0([[ERROR:%.*]] : @guaranteed $NSError):
+// CHECK:           [[ERROR_COPY:%.*]] = copy_value [[ERROR]]
+// CHECK:           [[ERROR_TYPE:%.*]] = init_existential_ref [[ERROR_COPY]] : $NSError : $NSError, $Error
+// CHECK-NOT:           destroy_value [[ERROR]]
+// CHECK:           return [[ERROR_TYPE]]
+// CHECK:       } // end sil function '$S10objc_error20NSErrorError_erasureys0D0_pSo0C0CF'
+func NSErrorError_erasure(_ x: NSError) -> Error {
+  return x
+}
+
+// CHECK-LABEL: sil hidden @$S10objc_error30NSErrorError_archetype_erasureys0D0_pxSo0C0CRbzlF : $@convention(thin) <T where T : NSError> (@guaranteed T) -> @owned Error {
+// CHECK:         bb0([[ERROR:%.*]] : @guaranteed $T):
+// CHECK:           [[ERROR_COPY:%.*]] = copy_value [[ERROR]]
+// CHECK:           [[T0:%.*]] = upcast [[ERROR_COPY]] : $T to $NSError
+// CHECK:           [[ERROR_TYPE:%.*]] = init_existential_ref [[T0]] : $NSError : $NSError, $Error
+// CHECK-NOT:           destroy_value [[ERROR]]
+// CHECK:           return [[ERROR_TYPE]]
+// CHECK: } // end sil function '$S10objc_error30NSErrorError_archetype_erasureys0D0_pxSo0C0CRbzlF'
+func NSErrorError_archetype_erasure<T : NSError>(_ t: T) -> Error {
+  return t
+}
+
+// Test patterns that are non-trivial, but irrefutable.  SILGen shouldn't crash
+// on these.
+func test_doesnt_throw() {
+  do {
+    throw NSError(domain: "", code: 1, userInfo: [:])
+  } catch is Error {  // expected-warning {{'is' test is always true}}
+  }
+
+  do {
+    throw NSError(domain: "", code: 1, userInfo: [:])
+  } catch let e as NSError {  // ok.
+    _ = e
+  }
+}
+
+class ErrorClass: Error {
+  let _domain = ""
+  let _code = 0
+}
+
+// Class-to-NSError casts must be done as indirect casts since they require
+// a representation change, and checked_cast_br currently doesn't allow that.
+
+// CHECK-LABEL: sil hidden @$S10objc_error20test_cast_to_nserroryyF
+func test_cast_to_nserror() {
+  let e = ErrorClass()
+
+  // CHECK: function_ref @$S10Foundation22_convertErrorToNSErrorySo0E0Cs0C0_pF
+  let nsCoerced = e as Error as NSError
+
+  // CHECK: unconditional_checked_cast_addr AnyObject in {{%.*}} : $*AnyObject to NSError in {{%.*}} : $*NSError
+  let nsForcedCast = (e as AnyObject) as! NSError
+
+  // CHECK: checked_cast_addr_br {{.*}} Error in {{%.*}} : $*Error to NSError in {{%.*}} : $*NSError, bb3, bb4
+  do {
+    throw e
+  } catch _ as NSError {
+    
+  }
+}
+
+// A class-constrained archetype may be NSError, so we can't use scalar casts
+// in that case either.
+// CHECK-LABEL: sil hidden @$S10objc_error28test_cast_to_class_archetype{{[_0-9a-zA-Z]*}}F
+func test_cast_to_class_archetype<T: AnyObject>(_: T) {
+  // CHECK: unconditional_checked_cast_addr ErrorClass in {{%.*}} : $*ErrorClass to T in {{.*}} : $*T
+  let e = ErrorClass()
+  let forcedCast = e as! T
+}
+
+// CHECK-LABEL: sil hidden @$S10objc_error15testAcceptError{{[_0-9a-zA-Z]*}}F
+func testAcceptError(error: Error) {
+  // CHECK-NOT: return
+  // CHECK: function_ref @$S10Foundation22_convertErrorToNSErrorySo0E0Cs0C0_pF
+  acceptError(error)
+}
+
+// CHECK-LABEL: sil hidden @$S10objc_error16testProduceError{{[_0-9a-zA-Z]*}}F
+func testProduceError() -> Error {
+  // CHECK: function_ref @produceError : $@convention(c) () -> @autoreleased NSError
+  // CHECK: init_existential_ref {{.*}} : $NSError : $NSError, $Error
+  return produceError()
+}
+
+// CHECK-LABEL: sil hidden @$S10objc_error24testProduceOptionalError{{[_0-9a-zA-Z]*}}F
+func testProduceOptionalError() -> Error? {
+  // CHECK: function_ref @produceOptionalError
+  // CHECK: init_existential_ref {{.*}} : $NSError : $NSError, $Error
+  return produceOptionalError();
+}
+
+class MyNSError : NSError {
+  override init() {
+    super.init(domain: "MyNSError", code: 0, userInfo: [:])
+  }
+}
+
+// CHECK-LABEL: sil hidden @$S10objc_error14eraseMyNSError{{[_0-9a-zA-Z]*}}F : $@convention(thin) () -> @owned Error {
+// CHECK: bb0:
+// CHECK:   [[NSERROR_SUBCLASS:%.*]] = apply {{.*}}({{.*}}) : $@convention(method) (@thick MyNSError.Type) -> @owned MyNSError
+// CHECK:   [[UPCAST:%.*]] = upcast [[NSERROR_SUBCLASS]] : $MyNSError to $NSError
+// CHECK:   [[EXISTENTIAL_REF:%.*]] = init_existential_ref [[UPCAST]]
+// CHECK:   [[BORROWED_EXISTENTIAL_REF:%.*]] = begin_borrow [[EXISTENTIAL_REF]]
+// CHECK:   [[COPY_BORROWED_EXISTENTIAL_REF:%.*]] = copy_value [[BORROWED_EXISTENTIAL_REF]]
+// CHECK:   end_borrow [[BORROWED_EXISTENTIAL_REF]] from [[EXISTENTIAL_REF]]
+// CHECK:   destroy_value [[EXISTENTIAL_REF]]
+// CHECK:   return [[COPY_BORROWED_EXISTENTIAL_REF]]
+// CHECK: } // end sil function '$S10objc_error14eraseMyNSError{{[_0-9a-zA-Z]*}}F'
+func eraseMyNSError() -> Error {
+  let x: Error = MyNSError()
+  return x
+}
+
+// CHECK-LABEL: sil hidden @$S10objc_error25eraseFictionalServerErrors0F0_pyF
+func eraseFictionalServerError() -> Error {
+  // CHECK-NOT: return
+  // CHECK: [[NSERROR:%[0-9]+]] = struct_extract {{.*}} : $FictionalServerError, #FictionalServerError._nsError
+  // CHECK: [[NSERROR_COPY:%.*]] = copy_value [[NSERROR]]
+  // CHECK: [[ERROR:%[0-9]+]] = init_existential_ref [[NSERROR_COPY]]
+  // CHECK: return [[ERROR]]
+  return FictionalServerError(.meltedDown)
+}
+// CHECK: } // end sil function '$S10objc_error25eraseFictionalServerErrors0F0_pyF'
+
+// SR-1562
+extension Error {
+  // CHECK-LABEL: sil hidden @$Ss5ErrorP10objc_errorE16convertToNSErrorSo0F0CyF
+  // CHECK: bb0([[SELF:%[0-9]+]] : @trivial $*Self)
+	func convertToNSError() -> NSError {
+    // CHECK: [[COPY:%.*]] = alloc_stack $Self
+    // CHECK: copy_addr [[SELF]] to [initialization] [[COPY]]
+    // CHECK: [[COPY2:%.*]] = alloc_stack $Self
+    // CHECK: copy_addr [[COPY]] to [initialization] [[COPY2]]
+    // CHECK: [[GET_EMBEDDED_FN:%[0-9]+]] = function_ref @$Ss24_getErrorEmbeddedNSErroryyXlSgxs0B0RzlF
+    // CHECK: [[EMBEDDED_RESULT_OPT:%[0-9]+]] = apply [[GET_EMBEDDED_FN]]<Self>([[COPY2]])
+    // CHECK: switch_enum [[EMBEDDED_RESULT_OPT]] : $Optional<AnyObject>,
+    // CHECK-SAME: case #Optional.some!enumelt.1: [[SUCCESS:bb[0-9]+]],
+    // CHECK-SAME: case #Optional.none!enumelt: [[FAILURE:bb[0-9]+]]
+
+    // CHECK: [[SUCCESS]]([[EMBEDDED_RESULT:%.*]] : @owned $AnyObject):
+    // CHECK: [[EMBEDDED_NSERROR:%[0-9]+]] = unchecked_ref_cast [[EMBEDDED_RESULT]] : $AnyObject to $NSError
+    // CHECK: [[ERROR:%[0-9]+]] = init_existential_ref [[EMBEDDED_NSERROR]] : $NSError : $NSError, $Error
+    // CHECK: destroy_addr [[COPY]] : $*Self
+    // CHECK: br [[CONTINUATION:bb[0-9]+]]([[ERROR]] : $Error)
+
+    // CHECK: [[FAILURE]]:
+    // CHECK: [[ERROR_BOX:%[0-9]+]] = alloc_existential_box $Error, $Self
+    // CHECK: [[ERROR_PROJECTED:%[0-9]+]] = project_existential_box $Self in [[ERROR_BOX]] : $Error
+    // CHECK: copy_addr [take] [[COPY]] to [initialization] [[ERROR_PROJECTED]] : $*Self
+    // CHECK: br [[CONTINUATION]]([[ERROR_BOX]] : $Error)
+
+    // CHECK: [[CONTINUATION]]([[ERROR_ARG:%[0-9]+]] : @owned $Error):
+		return self as NSError
+	}
+}
+
+class Gizmoid : NSObject {
+  // CHECK-LABEL: sil hidden [thunk] @$S10objc_error7GizmoidC3fooACyt_tKcfcTo : $@convention(objc_method) (Optional<AutoreleasingUnsafeMutablePointer<Optional<NSError>>>, @owned Gizmoid) -> @owned Optional<Gizmoid>
+  @objc init(foo: ()) throws {}
+}
diff --git a/test/SILGen/plus_zero_objc_extensions.swift b/test/SILGen/plus_zero_objc_extensions.swift
new file mode 100644
index 0000000..96a4c49
--- /dev/null
+++ b/test/SILGen/plus_zero_objc_extensions.swift
@@ -0,0 +1,187 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -enable-sil-ownership -emit-silgen -sdk %S/Inputs/ -I %S/Inputs -enable-source-import %s | %FileCheck %s
+
+// REQUIRES: objc_interop
+
+import Foundation
+import objc_extensions_helper
+
+class Sub : Base {}
+
+extension Sub {
+  override var prop: String! {
+    didSet {
+      // Ignore it.
+    }
+
+    // Make sure that we are generating the @objc thunk and are calling the actual method.
+    //
+    // CHECK-LABEL: sil hidden [thunk] @$S15objc_extensions3SubC4propSSSgvgTo : $@convention(objc_method) (Sub) -> @autoreleased Optional<NSString> {
+    // CHECK: bb0([[SELF:%.*]] : @unowned $Sub):
+    // CHECK: [[SELF_COPY:%.*]] = copy_value [[SELF]]
+    // CHECK: [[BORROWED_SELF_COPY:%.*]] = begin_borrow [[SELF_COPY]]
+    // CHECK: [[GETTER_FUNC:%.*]] = function_ref @$S15objc_extensions3SubC4propSSSgvg : $@convention(method) (@guaranteed Sub) -> @owned Optional<String>
+    // CHECK: apply [[GETTER_FUNC]]([[BORROWED_SELF_COPY]])
+    // CHECK: end_borrow [[BORROWED_SELF_COPY]] from [[SELF_COPY]]
+    // CHECK: destroy_value [[SELF_COPY]]
+    // CHECK: } // end sil function '$S15objc_extensions3SubC4propSSSgvgTo'
+
+    // Then check the body of the getter calls the super_method.
+    // CHECK-LABEL: sil hidden @$S15objc_extensions3SubC4propSSSgvg : $@convention(method) (@guaranteed Sub) -> @owned Optional<String> {
+    // CHECK: bb0([[SELF:%.*]] : @guaranteed $Sub):
+    // CHECK: [[SELF_COPY:%.*]] = copy_value [[SELF]]
+    // CHECK: [[SELF_COPY_CAST:%.*]] = upcast [[SELF_COPY]] : $Sub to $Base
+    // CHECK: [[BORROWED_SELF_COPY_CAST:%.*]] = begin_borrow [[SELF_COPY_CAST]]
+    // CHECK: [[CAST_BACK:%.*]] = unchecked_ref_cast [[BORROWED_SELF_COPY_CAST]] : $Base to $Sub
+    // CHECK: [[SUPER_METHOD:%.*]] = objc_super_method [[CAST_BACK]] : $Sub, #Base.prop!getter.1.foreign
+    // CHECK: end_borrow [[BORROWED_SELF_COPY_CAST]]
+    // CHECK: [[RESULT:%.*]] = apply [[SUPER_METHOD]]([[SELF_COPY_CAST]])
+    // CHECK: bb3(
+    // CHECK: destroy_value [[SELF_COPY_CAST]]
+    // CHECK: } // end sil function '$S15objc_extensions3SubC4propSSSgvg'
+
+    // Then check the setter @objc thunk.
+    //
+    // CHECK-LABEL: sil hidden [thunk] @$S15objc_extensions3SubC4propSSSgvsTo : $@convention(objc_method) (Optional<NSString>, Sub) -> () {
+    // CHECK: bb0([[NEW_VALUE:%.*]] : @unowned $Optional<NSString>, [[SELF:%.*]] : @unowned $Sub):
+    // CHECK:   [[NEW_VALUE_COPY:%.*]] = copy_value [[NEW_VALUE]]
+    // CHECK:   [[SELF_COPY:%.*]] = copy_value [[SELF]] : $Sub
+    // CHECK:   switch_enum [[NEW_VALUE_COPY]] : $Optional<NSString>, case #Optional.some!enumelt.1: [[SUCC_BB:bb[0-9]+]], case #Optional.none!enumelt: [[FAIL_BB:bb[0-9]+]]
+    // CHECK: [[SUCC_BB]]([[STR:%.*]] : @owned $NSString):
+    // CHECK: [[FAIL_BB]]:
+    // CHECK: bb3([[BRIDGED_NEW_VALUE:%.*]] : @owned $Optional<String>):
+    // CHECK:   [[BORROWED_SELF_COPY:%.*]] = begin_borrow [[SELF_COPY]]
+    // CHECK:   [[NORMAL_FUNC:%.*]] = function_ref @$S15objc_extensions3SubC4propSSSgvs : $@convention(method) (@owned Optional<String>, @guaranteed Sub) -> ()
+    // CHECK:   apply [[NORMAL_FUNC]]([[BRIDGED_NEW_VALUE]], [[BORROWED_SELF_COPY]])
+    // CHECK:   end_borrow [[BORROWED_SELF_COPY]] from [[SELF_COPY]]
+    // CHECK:   destroy_value [[SELF_COPY]]
+    // CHECK: } // end sil function '$S15objc_extensions3SubC4propSSSgvsTo'
+
+    // Then check the body of the actually setter value and make sure that we
+    // call the didSet function.
+    // CHECK-LABEL: sil hidden @$S15objc_extensions3SubC4propSSSgvs : $@convention(method) (@owned Optional<String>, @guaranteed Sub) -> () {
+
+    // First we get the old value.
+    // CHECK: bb0([[NEW_VALUE:%.*]] : @owned $Optional<String>, [[SELF:%.*]] : @guaranteed $Sub):
+    // CHECK:   [[SELF_COPY:%.*]] = copy_value [[SELF]]
+    // CHECK:   [[UPCAST_SELF_COPY:%.*]] = upcast [[SELF_COPY]] : $Sub to $Base
+    // CHECK:   [[BORROWED_UPCAST_SELF_COPY:%.*]] = begin_borrow [[UPCAST_SELF_COPY]]
+    // CHECK:   [[CAST_BACK:%.*]] = unchecked_ref_cast [[BORROWED_UPCAST_SELF_COPY]] : $Base to $Sub
+    // CHECK:   [[GET_SUPER_METHOD:%.*]] = objc_super_method [[CAST_BACK]] : $Sub, #Base.prop!getter.1.foreign : (Base) -> () -> String?, $@convention(objc_method) (Base) -> @autoreleased Optional<NSString>
+    // CHECK:   end_borrow [[BORROWED_UPCAST_SELF_COPY]] from [[UPCAST_SELF_COPY]]
+    // CHECK:   [[OLD_NSSTRING:%.*]] = apply [[GET_SUPER_METHOD]]([[UPCAST_SELF_COPY]])
+
+    // CHECK: bb3([[OLD_NSSTRING_BRIDGED:%.*]] : @owned $Optional<String>):
+    // This next line is completely not needed. But we are emitting it now.
+    // CHECK:   destroy_value [[UPCAST_SELF_COPY]]
+    // CHECK:   [[SELF_COPY:%.*]] = copy_value [[SELF]]
+    // CHECK:   [[UPCAST_SELF_COPY:%.*]] = upcast [[SELF_COPY]] : $Sub to $Base
+    // CHECK:   [[BORROWED_NEW_VALUE:%.*]] = begin_borrow [[NEW_VALUE]]
+    // CHECK:   [[NEW_VALUE_COPY:%.*]] = copy_value [[BORROWED_NEW_VALUE]]
+    // CHECK:   switch_enum [[NEW_VALUE_COPY]] : $Optional<String>, case #Optional.some!enumelt.1: [[SOME_BB:bb[0-9]+]], case #Optional.none!enumelt: [[NONE_BB:bb[0-9]+]]
+    //
+    // CHECK: bb4([[OLD_STRING:%.*]] : @owned $String):
+    // CHECK: bb6([[BRIDGED_NEW_STRING:%.*]] : @owned $Optional<NSString>):
+    // CHECK:    end_borrow [[BORROWED_NEW_VALUE]]
+    // CHECK:   [[BORROWED_UPCAST_SELF:%.*]] = begin_borrow [[UPCAST_SELF_COPY]] : $Base
+    // CHECK:   [[SUPERREF_DOWNCAST:%.*]] = unchecked_ref_cast [[BORROWED_UPCAST_SELF]] : $Base to $Sub
+    // CHECK:   [[SET_SUPER_METHOD:%.*]] = objc_super_method [[SUPERREF_DOWNCAST]] : $Sub, #Base.prop!setter.1.foreign : (Base) -> (String?) -> (), $@convention(objc_method) (Optional<NSString>, Base) -> ()
+    // CHECK:    apply [[SET_SUPER_METHOD]]([[BRIDGED_NEW_STRING]], [[UPCAST_SELF_COPY]])
+    // CHECK:    destroy_value [[BRIDGED_NEW_STRING]]
+    // CHECK:    destroy_value [[UPCAST_SELF_COPY]]
+    // CHECK:    [[BORROWED_OLD_NSSTRING_BRIDGED:%.*]] = begin_borrow [[OLD_NSSTRING_BRIDGED]]
+    // This is an identity cast that should be eliminated by SILGen peepholes.
+    // CHECK:    [[DIDSET_NOTIFIER:%.*]] = function_ref @$S15objc_extensions3SubC4propSSSgvW : $@convention(method) (@guaranteed Optional<String>, @guaranteed Sub) -> ()
+    // CHECK:    apply [[DIDSET_NOTIFIER]]([[BORROWED_OLD_NSSTRING_BRIDGED]], [[SELF]])
+    // CHECK:    end_borrow [[BORROWED_OLD_NSSTRING_BRIDGED]] from [[OLD_NSSTRING_BRIDGED]]
+    // CHECK:    destroy_value [[OLD_NSSTRING_BRIDGED]]
+    // CHECK:    destroy_value [[NEW_VALUE]]
+    // CHECK: } // end sil function '$S15objc_extensions3SubC4propSSSgvs'
+
+  }
+
+  func foo() {
+  }
+
+  override func objCBaseMethod() {}
+}
+
+// CHECK-LABEL: sil hidden @$S15objc_extensions20testOverridePropertyyyAA3SubCF
+func testOverrideProperty(_ obj: Sub) {
+  // CHECK: bb0([[ARG:%.*]] : @guaranteed $Sub):
+  // CHECK: = objc_method [[ARG]] : $Sub, #Sub.prop!setter.1.foreign : (Sub) -> (String?) -> ()
+  obj.prop = "abc"
+} // CHECK: } // end sil function '$S15objc_extensions20testOverridePropertyyyAA3SubCF'
+
+testOverrideProperty(Sub())
+
+// CHECK-LABEL: sil shared [thunk] @$S15objc_extensions3SubC3fooyyFTc
+// CHECK:         function_ref @$S15objc_extensions3SubC3fooyyFTD
+// CHECK: } // end sil function '$S15objc_extensions3SubC3fooyyFTc'
+// CHECK:       sil shared [transparent] [serializable] [thunk] @$S15objc_extensions3SubC3fooyyFTD
+// CHECK:       bb0([[SELF:%.*]] : @guaranteed $Sub):
+// CHECK:         [[SELF_COPY:%.*]] = copy_value [[SELF]]
+// CHECK:         objc_method [[SELF_COPY]] : $Sub, #Sub.foo!1.foreign
+// CHECK: } // end sil function '$S15objc_extensions3SubC3fooyyFTD'
+func testCurry(_ x: Sub) {
+  _ = x.foo
+}
+
+extension Sub {
+  var otherProp: String {
+    get { return "hello" }
+    set { }
+  }
+}
+
+class SubSub : Sub {
+  // CHECK-LABEL: sil hidden @$S15objc_extensions03SubC0C14objCBaseMethodyyF :
+  // CHECK: bb0([[SELF:%.*]] : @guaranteed $SubSub):
+  // CHECK:   [[SELF_COPY:%.*]] = copy_value [[SELF]]
+  // CHECK:   [[UPCAST_SELF_COPY:%.*]] = upcast [[SELF_COPY]] : $SubSub to $Sub
+  // CHECK:   [[BORROWED_UPCAST_SELF_COPY:%.*]] = begin_borrow [[UPCAST_SELF_COPY]]
+  // CHECK:   [[DOWNCAST:%.*]] = unchecked_ref_cast [[BORROWED_UPCAST_SELF_COPY]] : $Sub to $SubSub
+  // CHECK:   objc_super_method [[DOWNCAST]] : $SubSub, #Sub.objCBaseMethod!1.foreign : (Sub) -> () -> (), $@convention(objc_method) (Sub) -> ()
+  // CHECK:   end_borrow [[BORROWED_UPCAST_SELF_COPY]] from [[UPCAST_SELF_COPY]]
+  // CHECK: } // end sil function '$S15objc_extensions03SubC0C14objCBaseMethodyyF'
+  override func objCBaseMethod() {
+    super.objCBaseMethod()
+  }
+}
+
+extension SubSub {
+  // CHECK-LABEL: sil hidden @$S15objc_extensions03SubC0C9otherPropSSvs
+  // CHECK: bb0([[NEW_VALUE:%.*]] : @owned $String, [[SELF:%.*]] : @guaranteed $SubSub):
+  // CHECK:   [[SELF_COPY_1:%.*]] = copy_value [[SELF]]
+  // CHECK:   [[UPCAST_SELF_COPY_1:%.*]] = upcast [[SELF_COPY_1]] : $SubSub to $Sub
+  // CHECK:   [[BORROWED_UPCAST_SELF_COPY_1:%.*]] = begin_borrow [[UPCAST_SELF_COPY_1]]
+  // CHECK:   [[DOWNCAST_BORROWED_UPCAST_SELF_COPY_1:%.*]] = unchecked_ref_cast [[BORROWED_UPCAST_SELF_COPY_1]] : $Sub to $SubSub
+  // CHECK:   = objc_super_method [[DOWNCAST_BORROWED_UPCAST_SELF_COPY_1]] : $SubSub, #Sub.otherProp!getter.1.foreign
+  // CHECK:   end_borrow [[BORROWED_UPCAST_SELF_COPY_1]] from [[UPCAST_SELF_COPY_1]]
+
+  // CHECK:   [[SELF_COPY_2:%.*]] = copy_value [[SELF]]
+  // CHECK:   [[UPCAST_SELF_COPY_2:%.*]] = upcast [[SELF_COPY_2]] : $SubSub to $Sub
+  // CHECK:   [[BORROWED_UPCAST_SELF_COPY_2:%.*]] = begin_borrow [[UPCAST_SELF_COPY_2]]
+  // CHECK:   [[DOWNCAST_BORROWED_UPCAST_SELF_COPY_2:%.*]] = unchecked_ref_cast [[BORROWED_UPCAST_SELF_COPY_2]] : $Sub to $SubSub
+  // CHECK:   = objc_super_method [[DOWNCAST_BORROWED_UPCAST_SELF_COPY_2]] : $SubSub, #Sub.otherProp!setter.1.foreign
+  // CHECK:   end_borrow [[BORROWED_UPCAST_SELF_COPY_2]] from [[UPCAST_SELF_COPY_2]]
+  // CHECK: } // end sil function '$S15objc_extensions03SubC0C9otherPropSSvs'
+  override var otherProp: String {
+    didSet {
+      // Ignore it.
+    }
+  }
+}
+
+// SR-1025
+extension Base {
+  fileprivate static var x = 1
+}
+
+// CHECK-LABEL: sil hidden @$S15objc_extensions19testStaticVarAccessyyF
+func testStaticVarAccess() {
+  // CHECK: [[F:%.*]] = function_ref @$SSo4BaseC15objc_extensionsE1x33_1F05E59585E0BB585FCA206FBFF1A92DLLSivau
+  // CHECK: [[PTR:%.*]] = apply [[F]]()
+  // CHECK: [[ADDR:%.*]] = pointer_to_address [[PTR]]
+  _ = Base.x
+}
diff --git a/test/SILGen/plus_zero_objc_imported_generic.swift b/test/SILGen/plus_zero_objc_imported_generic.swift
new file mode 100644
index 0000000..f874ba7
--- /dev/null
+++ b/test/SILGen/plus_zero_objc_imported_generic.swift
@@ -0,0 +1,144 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -emit-silgen %s -enable-sil-ownership | %FileCheck %s
+// For integration testing, ensure we get through IRGen too.
+// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -emit-ir -verify -DIRGEN_INTEGRATION_TEST %s
+
+// REQUIRES: objc_interop
+
+import objc_generics
+
+func callInitializer() {
+  _ = GenericClass(thing: NSObject())
+}
+
+// CHECK-LABEL: sil shared [serializable] @$SSo12GenericClassC5thingAByxGSgxSg_tcfC
+// CHECK:         thick_to_objc_metatype {{%.*}} : $@thick GenericClass<T>.Type to $@objc_metatype GenericClass<T>.Type
+
+public func genericMethodOnAnyObject(o: AnyObject, b: Bool) -> AnyObject {
+  return o.thing!()!
+}
+
+// CHECK-LABEL: sil @$S21objc_imported_generic0C17MethodOnAnyObject{{[_0-9a-zA-Z]*}}F
+// CHECK:         objc_method {{%.*}} : $@opened([[TAG:.*]]) AnyObject, #GenericClass.thing!1.foreign : <T where T : AnyObject> (GenericClass<T>) -> () -> T?, $@convention(objc_method) @pseudogeneric (@opened([[TAG]]) AnyObject) -> @autoreleased Optional<AnyObject>
+
+public func genericMethodOnAnyObjectChained(o: AnyObject, b: Bool) -> AnyObject? {
+  return o.thing?()
+}
+
+// CHECK-LABEL: sil @$S21objc_imported_generic0C24MethodOnAnyObjectChained1o1byXlSgyXl_SbtF
+// CHECK: bb0([[ANY:%.*]] : @guaranteed $AnyObject, [[BOOL:%.*]] : @trivial $Bool):
+// CHECK:   [[OPENED_ANY:%.*]] = open_existential_ref [[ANY]]
+// CHECK:   [[OPENED_ANY_COPY:%.*]] = copy_value [[OPENED_ANY]]
+// CHECK:   dynamic_method_br [[OPENED_ANY_COPY]] : $@opened([[TAG:.*]]) AnyObject, #GenericClass.thing!1.foreign, bb1
+// CHECK:   bb1({{%.*}} : @trivial $@convention(objc_method) @pseudogeneric (@opened([[TAG]]) AnyObject) -> @autoreleased Optional<AnyObject>):
+// CHECK: } // end sil function '$S21objc_imported_generic0C24MethodOnAnyObjectChained1o1byXlSgyXl_SbtF'
+
+public func genericSubscriptOnAnyObject(o: AnyObject, b: Bool) -> AnyObject? {
+  return o[0 as UInt16]
+}
+
+// CHECK-LABEL: sil @$S21objc_imported_generic0C20SubscriptOnAnyObject1o1byXlSgyXl_SbtF
+// CHECK: bb0([[ANY:%.*]]
+// CHCEK:   [[OPENED_ANY:%.*]] = open_existential_ref [[ANY]]
+// CHECK:   [[OPENED_ANY_COPY:%.*]] = copy_value [[OPENED_ANY]]
+// CHECK:   dynamic_method_br [[OPENED_ANY_COPY]] : $@opened([[TAG:.*]]) AnyObject, #GenericClass.subscript!getter.1.foreign, bb1
+// CHECK:   bb1({{%.*}} : @trivial $@convention(objc_method) @pseudogeneric (UInt16, @opened([[TAG]]) AnyObject) -> @autoreleased AnyObject):
+// CHECK: } // end sil function '$S21objc_imported_generic0C20SubscriptOnAnyObject1o1byXlSgyXl_SbtF'
+
+public func genericPropertyOnAnyObject(o: AnyObject, b: Bool) -> AnyObject?? {
+  return o.propertyThing
+}
+
+// CHECK-LABEL: sil @$S21objc_imported_generic0C19PropertyOnAnyObject1o1byXlSgSgyXl_SbtF
+// CHECK: bb0([[ANY:%.*]] : @guaranteed $AnyObject, [[BOOL:%.*]] : @trivial $Bool):
+// CHECK:   [[OPENED_ANY:%.*]] = open_existential_ref [[ANY]]
+// CHECK:   [[OPENED_ANY_COPY:%.*]] = copy_value [[OPENED_ANY]]
+// CHECK:   dynamic_method_br [[OPENED_ANY_COPY]] : $@opened([[TAG:.*]]) AnyObject, #GenericClass.propertyThing!getter.1.foreign, bb1
+// CHECK:   bb1({{%.*}} : @trivial $@convention(objc_method) @pseudogeneric (@opened([[TAG]]) AnyObject) -> @autoreleased Optional<AnyObject>):
+// CHECK: } // end sil function '$S21objc_imported_generic0C19PropertyOnAnyObject1o1byXlSgSgyXl_SbtF'
+
+public protocol ThingHolder {
+  associatedtype Thing
+
+  init!(thing: Thing!)
+  func thing() -> Thing?
+  func arrayOfThings() -> [Thing]
+  func setArrayOfThings(_: [Thing])
+  static func classThing() -> Thing?
+
+  var propertyThing: Thing? { get set }
+  var propertyArrayOfThings: [Thing]? { get set }
+}
+
+// TODO: Crashes in IRGen because the type metadata for `T` is not found in
+// the witness thunk to satisfy the associated type requirement. This could be
+// addressed by teaching IRGen to fulfill erased type parameters from protocol
+// witness tables (rdar://problem/26602097).
+#if !IRGEN_INTEGRATION_TEST
+extension GenericClass: ThingHolder {}
+#endif
+
+public protocol Ansible: class {
+  associatedtype Anser: ThingHolder
+}
+
+public func genericBlockBridging<T: Ansible>(x: GenericClass<T>) {
+  let block = x.blockForPerformingOnThings()
+  x.performBlock(onThings: block)
+}
+
+// CHECK-LABEL: sil @$S21objc_imported_generic0C13BlockBridging{{[_0-9a-zA-Z]*}}F
+// CHECK:         [[BLOCK_TO_FUNC:%.*]] = function_ref @$SxxIeyBya_xxIeggo_21objc_imported_generic7AnsibleRzlTR
+// CHECK:         partial_apply [callee_guaranteed] [[BLOCK_TO_FUNC]]<T>
+// CHECK:         [[FUNC_TO_BLOCK:%.*]] = function_ref @$SxxIeggo_xxIeyBya_21objc_imported_generic7AnsibleRzlTR
+// CHECK:         init_block_storage_header {{.*}} invoke [[FUNC_TO_BLOCK]]<T>
+
+// CHECK-LABEL: sil @$S21objc_imported_generic20arraysOfGenericParam{{[_0-9a-zA-Z]*}}F
+public func arraysOfGenericParam<T: AnyObject>(y: Array<T>) {
+  // CHECK:         function_ref @$SSo12GenericClassC13arrayOfThingsAByxGSgSayxG_tcfC : $@convention(method) <τ_0_0 where τ_0_0 : AnyObject> (@owned Array<τ_0_0>, @thick GenericClass<τ_0_0>.Type) -> @owned Optional<GenericClass<τ_0_0>>
+  let x = GenericClass<T>(arrayOfThings: y)!
+  // CHECK:         objc_method {{%.*}} : $GenericClass<T>, #GenericClass.setArrayOfThings!1.foreign {{.*}}, $@convention(objc_method) @pseudogeneric <τ_0_0 where τ_0_0 : AnyObject> (NSArray, GenericClass<τ_0_0>) -> ()
+  x.setArrayOfThings(y)
+  // CHECK:         objc_method {{%.*}} : $GenericClass<T>, #GenericClass.propertyArrayOfThings!getter.1.foreign {{.*}}, $@convention(objc_method) @pseudogeneric <τ_0_0 where τ_0_0 : AnyObject> (GenericClass<τ_0_0>) -> @autoreleased Optional<NSArray>
+  _ = x.propertyArrayOfThings
+  // CHECK:         objc_method {{%.*}} : $GenericClass<T>, #GenericClass.propertyArrayOfThings!setter.1.foreign {{.*}}, $@convention(objc_method) @pseudogeneric <τ_0_0 where τ_0_0 : AnyObject> (Optional<NSArray>, GenericClass<τ_0_0>) -> ()
+  x.propertyArrayOfThings = y
+}
+
+// CHECK-LABEL: sil private @$S21objc_imported_generic0C4FuncyyxmRlzClFyycfU_ : $@convention(thin) <V where V : AnyObject> () -> () {
+// CHECK:  [[META:%.*]] = metatype $@thick GenericClass<V>.Type
+// CHECK:  [[INIT:%.*]] = function_ref @$SSo12GenericClassCAByxGycfC : $@convention(method) <τ_0_0 where τ_0_0 : AnyObject> (@thick GenericClass<τ_0_0>.Type) -> @owned GenericClass<τ_0_0>
+// CHECK:  apply [[INIT]]<V>([[META]])
+// CHECK:  return
+func genericFunc<V: AnyObject>(_ v: V.Type) {
+  let _ = {
+    var _ = GenericClass<V>()
+  }
+}
+
+// CHECK-LABEL: sil hidden @$S21objc_imported_generic23configureWithoutOptionsyyF : $@convention(thin) () -> ()
+// CHECK: [[NIL_FN:%.*]] = function_ref @$SSq10nilLiteralxSgyt_tcfC : $@convention(method) <τ_0_0> (@thin Optional<τ_0_0>.Type) -> @out Optional<τ_0_0>
+// CHECK: apply [[NIL_FN]]<[GenericOption : Any]>({{.*}})
+// CHECK: return
+func configureWithoutOptions() {
+  _ = GenericClass<NSObject>(options: nil)
+}
+
+// This gets emitted down here for some reason
+
+// CHECK-LABEL: sil shared [serializable] [thunk] @$SSo12GenericClassC13arrayOfThingsAByxGSgSayxG_tcfcTO
+// CHECK:         objc_method {{%.*}} : $GenericClass<T>, #GenericClass.init!initializer.1.foreign {{.*}}, $@convention(objc_method) @pseudogeneric <τ_0_0 where τ_0_0 : AnyObject> (NSArray, @owned GenericClass<τ_0_0>) -> @owned Optional<GenericClass<τ_0_0>>
+
+// foreign to native thunk for init(options:), uses GenericOption : Hashable
+// conformance
+
+// CHECK-LABEL: sil shared [serializable] [thunk] @$SSo12GenericClassC7optionsAByxGSgs10DictionaryVySo0A6OptionaypGSg_tcfcTO : $@convention(method) <T where T : AnyObject> (@owned Optional<Dictionary<GenericOption, Any>>, @owned GenericClass<T>) -> @owned Optional<GenericClass<T>>
+// CHECK: [[FN:%.*]] = function_ref @$Ss10DictionaryV10FoundationE19_bridgeToObjectiveCSo12NSDictionaryCyF : $@convention(method) <τ_0_0, τ_0_1 where τ_0_0 : Hashable> (@guaranteed Dictionary<τ_0_0, τ_0_1>) -> @owned NSDictionary
+// CHECK: apply [[FN]]<GenericOption, Any>({{.*}}) : $@convention(method) <τ_0_0, τ_0_1 where τ_0_0 : Hashable> (@guaranteed Dictionary<τ_0_0, τ_0_1>) -> @owned NSDictionary
+// CHECK: return
+
+// Make sure we emitted the witness table for the above conformance
+
+// CHECK-LABEL: sil_witness_table shared [serialized] GenericOption: Hashable module objc_generics {
+// CHECK: method #Hashable.hashValue!getter.1: {{.*}}: @$SSo13GenericOptionas8HashableSCsACP9hashValueSivgTW
+// CHECK: }
diff --git a/test/SILGen/plus_zero_objc_ownership_conventions.swift b/test/SILGen/plus_zero_objc_ownership_conventions.swift
new file mode 100644
index 0000000..3ef9bb6
--- /dev/null
+++ b/test/SILGen/plus_zero_objc_ownership_conventions.swift
@@ -0,0 +1,226 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -sdk %S/Inputs -I %S/Inputs -enable-source-import %s -emit-silgen -enable-sil-ownership | %FileCheck %s
+
+// REQUIRES: objc_interop
+
+import gizmo
+
+// CHECK-LABEL: sil hidden @$S26objc_ownership_conventions5test3So8NSObjectCyF
+func test3() -> NSObject {
+  // initializer returns at +1
+  return Gizmo()
+  // CHECK: [[GIZMO_META:%[0-9]+]] = metatype $@thick Gizmo.Type
+  // CHECK: [[CTOR:%[0-9]+]] = function_ref @$SSo5GizmoC{{[_0-9a-zA-Z]*}}fC : $@convention(method) (@thick Gizmo.Type) -> @owned Optional<Gizmo>
+  // CHECK-NEXT: [[GIZMO:%[0-9]+]] = apply [[CTOR]]([[GIZMO_META]]) : $@convention(method) (@thick Gizmo.Type) -> @owned Optional<Gizmo>
+  // CHECK: [[GIZMO_NS:%[0-9]+]] = upcast [[GIZMO:%[0-9]+]] : $Gizmo to $NSObject
+  // CHECK: return [[GIZMO_NS]] : $NSObject
+
+  // CHECK-LABEL: sil shared [serializable] @$SSo5GizmoC{{[_0-9a-zA-Z]*}}fC : $@convention(method) (@thick Gizmo.Type) -> @owned Optional<Gizmo>
+  // alloc is implicitly ns_returns_retained
+  // init is implicitly ns_consumes_self and ns_returns_retained
+  // CHECK: bb0([[GIZMO_META:%[0-9]+]] : @trivial $@thick Gizmo.Type):
+  // CHECK-NEXT: [[GIZMO_META_OBJC:%[0-9]+]] = thick_to_objc_metatype [[GIZMO_META]] : $@thick Gizmo.Type to $@objc_metatype Gizmo.Type
+  // CHECK-NEXT: [[GIZMO:%[0-9]+]] = alloc_ref_dynamic [objc] [[GIZMO_META_OBJC]] : $@objc_metatype Gizmo.Type, $Gizmo
+  // CHECK-NEXT: // function_ref
+  // CHECK-NEXT: [[INIT_CTOR:%[0-9]+]] = function_ref @$SSo5GizmoC{{[_0-9a-zA-Z]*}}fcTO
+  // CHECK-NEXT: [[RESULT:%[0-9]+]] = apply [[INIT_CTOR]]([[GIZMO]]) : $@convention(method) (@owned Gizmo) -> @owned Optional<Gizmo>
+  // CHECK-NEXT: return [[RESULT]] : $Optional<Gizmo>
+}
+
+
+
+// Normal message send with argument, no transfers.
+// CHECK-LABEL: sil hidden @$S26objc_ownership_conventions5test5{{[_0-9a-zA-Z]*}}F
+func test5(_ g: Gizmo) {
+  var g = g
+  Gizmo.inspect(g)
+  // CHECK: bb0([[ARG:%.*]] : @guaranteed $Gizmo):
+  // CHECK:   [[GIZMO_BOX:%.*]] = alloc_box ${ var Gizmo }
+  // CHECK:   [[GIZMO_BOX_PB:%.*]] = project_box [[GIZMO_BOX]]
+  // CHECK:   [[ARG_COPY:%.*]] = copy_value [[ARG]]
+  // CHECK:   store [[ARG_COPY]] to [init] [[GIZMO_BOX_PB]]
+  // CHECK:   [[CLASS:%.*]] = metatype $@objc_metatype Gizmo.Type
+  // CHECK:   [[READ:%.*]] = begin_access [read] [unknown] [[GIZMO_BOX_PB]] : $*Gizmo
+  // CHECK:   [[V:%.*]] = load [copy] [[READ]]
+  // CHECK:   [[G:%.*]] = enum $Optional<Gizmo>, #Optional.some!enumelt.1, [[V]]
+  // CHECK:   [[METHOD:%.*]] = objc_method [[CLASS]] : {{.*}}, #Gizmo.inspect!1.foreign
+  // CHECK:   apply [[METHOD]]([[G]], [[CLASS]])
+  // CHECK:   destroy_value [[G]]
+  // CHECK:   destroy_value [[GIZMO_BOX]]
+  // CHECK-NOT:   destroy_value [[ARG]]
+}
+// CHECK: } // end sil function '$S26objc_ownership_conventions5test5{{[_0-9a-zA-Z]*}}F'
+
+// The argument to consume is __attribute__((ns_consumed)).
+// CHECK-LABEL: sil hidden @$S26objc_ownership_conventions5test6{{[_0-9a-zA-Z]*}}F
+func test6(_ g: Gizmo) {
+  var g = g
+  Gizmo.consume(g)
+  // CHECK: bb0([[ARG:%.*]] : @guaranteed $Gizmo):
+  // CHECK:   [[GIZMO_BOX:%.*]] = alloc_box ${ var Gizmo }
+  // CHECK:   [[GIZMO_BOX_PB:%.*]] = project_box [[GIZMO_BOX]]
+  // CHECK:   [[ARG_COPY:%.*]] = copy_value [[ARG]]
+  // CHECK:   store [[ARG_COPY]] to [init] [[GIZMO_BOX_PB]]
+  // CHECK:   [[CLASS:%.*]] = metatype $@objc_metatype Gizmo.Type
+  // CHECK:   [[READ:%.*]] = begin_access [read] [unknown] [[GIZMO_BOX_PB]] : $*Gizmo
+  // CHECK:   [[V:%.*]] = load [copy] [[READ]]
+  // CHECK:   [[G:%.*]] = enum $Optional<Gizmo>, #Optional.some!enumelt.1, [[V]]
+  // CHECK:   [[METHOD:%.*]] = objc_method [[CLASS]] : {{.*}}, #Gizmo.consume!1.foreign
+  // CHECK:   apply [[METHOD]]([[G]], [[CLASS]])
+  // CHECK-NOT:  destroy_value [[G]]
+  // CHECK:   destroy_value [[GIZMO_BOX]]
+  // CHECK-NOT:  destroy_value [[G]]
+  // CHECK-NOT:   destroy_value [[ARG]]
+  // CHECK-NOT:  destroy_value [[G]]
+}
+// CHECK: } // end sil function '$S26objc_ownership_conventions5test6{{[_0-9a-zA-Z]*}}F'
+
+// fork is __attribute__((ns_consumes_self)).
+// CHECK-LABEL: sil hidden @$S26objc_ownership_conventions5test7{{[_0-9a-zA-Z]*}}F
+func test7(_ g: Gizmo) {
+  var g = g
+  g.fork()
+  // CHECK: bb0([[ARG:%.*]] : @guaranteed $Gizmo):
+  // CHECK:   [[GIZMO_BOX:%.*]] = alloc_box ${ var Gizmo }
+  // CHECK:   [[GIZMO_BOX_PB:%.*]] = project_box [[GIZMO_BOX]]
+  // CHECK:   [[ARG_COPY:%.*]] = copy_value [[ARG]]
+  // CHECK:   store [[ARG_COPY]] to [init] [[GIZMO_BOX_PB]]
+  // CHECK:   [[READ:%.*]] = begin_access [read] [unknown] [[GIZMO_BOX_PB]] : $*Gizmo
+  // CHECK:   [[G:%.*]] = load [copy] [[READ]]
+  // CHECK:   [[METHOD:%.*]] = objc_method [[G]] : {{.*}}, #Gizmo.fork!1.foreign
+  // CHECK:   apply [[METHOD]]([[G]])
+  // CHECK-NOT:  destroy_value [[G]]
+  // CHECK:   destroy_value [[GIZMO_BOX]]
+  // CHECK-NOT:  destroy_value [[G]]
+  // CHECK-NOT:   destroy_value [[ARG]]
+  // CHECK-NOT:  destroy_value [[G]]
+}
+// CHECK: } // end sil function '$S26objc_ownership_conventions5test7{{[_0-9a-zA-Z]*}}F'
+
+// clone is __attribute__((ns_returns_retained)).
+// CHECK-LABEL: sil hidden @$S26objc_ownership_conventions5test8{{[_0-9a-zA-Z]*}}F
+func test8(_ g: Gizmo) -> Gizmo {
+  return g.clone()
+  // CHECK: bb0([[G:%.*]] : @guaranteed $Gizmo):
+  // CHECK-NOT:  copy_value
+  // CHECK:      [[METHOD:%.*]] = objc_method [[G]] : {{.*}}, #Gizmo.clone!1.foreign
+  // CHECK-NOT:  copy_value [[RESULT]]
+  // CHECK:      bb2([[RESULT:%.*]] : @owned $Gizmo):
+  // CHECK-NOT:  copy_value [[RESULT]]
+  // CHECK-NOT: destroy_value [[G]]
+  // CHECK-NEXT: return [[RESULT]]
+}
+// duplicate returns an autoreleased object at +0.
+// CHECK-LABEL: sil hidden @$S26objc_ownership_conventions5test9{{[_0-9a-zA-Z]*}}F
+func test9(_ g: Gizmo) -> Gizmo {
+  return g.duplicate()
+  // CHECK: bb0([[G:%.*]] : @guaranteed $Gizmo):
+  // CHECK-NOT:      copy_value [[G:%0]]
+  // CHECK: [[METHOD:%.*]] = objc_method [[G]] : {{.*}}, #Gizmo.duplicate!1.foreign
+  // CHECK-NEXT: [[RESULT:%.*]] = apply [[METHOD]]([[G]])
+  // CHECK-NOT:  copy_value [[RESULT]]
+  // CHECK: bb2([[RESULT:%.*]] : @owned $Gizmo):
+  // CHECK-NOT:  copy_value [[RESULT]]
+  // CHECK-NOT: destroy_value [[G]]
+  // CHECK-NEXT: return [[RESULT]]
+}
+
+// CHECK-LABEL: sil hidden @$S26objc_ownership_conventions6test10{{[_0-9a-zA-Z]*}}F
+func test10(_ g: Gizmo) -> AnyClass {
+  // CHECK: bb0([[G:%[0-9]+]] : @guaranteed $Gizmo):
+  // CHECK:      [[G_COPY:%.*]] = copy_value [[G]]
+  // CHECK-NEXT: [[NS_G_COPY:%[0-9]+]] = upcast [[G_COPY]] : $Gizmo to $NSObject
+  // CHECK-NEXT: [[GETTER:%[0-9]+]] = objc_method [[NS_G_COPY]] : $NSObject, #NSObject.classProp!getter.1.foreign : (NSObject) -> () -> AnyObject.Type?, $@convention(objc_method) (NSObject) -> Optional<@objc_metatype AnyObject.Type>
+  // CHECK-NEXT: [[OPT_OBJC:%.*]] = apply [[GETTER]]([[NS_G_COPY]]) : $@convention(objc_method) (NSObject) -> Optional<@objc_metatype AnyObject.Type>
+  // CHECK-NEXT: switch_enum [[OPT_OBJC]] : $Optional<{{.*}}>, case #Optional.some!enumelt.1: [[SOME_BB:bb[0-9]+]], case #Optional.none!enumelt: [[NONE_BB:bb[0-9]+]]
+  //
+  // CHECK: [[SOME_BB]]([[OBJC:%.*]] : @trivial $@objc_metatype AnyObject.Type):
+  // CHECK-NEXT: [[THICK:%.*]] = objc_to_thick_metatype [[OBJC]]
+  // CHECK:      [[T0:%.*]] = enum $Optional<@thick AnyObject.Type>, #Optional.some!enumelt.1, [[THICK]]
+  // CHECK:   bb{{.*}}(%{{.*}} : @trivial $Optional<@thick AnyObject.Type>):
+  // CHECK:      destroy_value [[NS_G_COPY]] : $NSObject
+  // CHECK:   bb{{.*}}([[RES:%.*]] : @trivial $@thick AnyObject.Type):
+  // CHECK-NOT:      destroy_value [[G]] : $Gizmo
+  // CHECK-NEXT: return [[RES]] : $@thick AnyObject.Type
+  return g.classProp
+}
+
+// CHECK-LABEL: sil hidden @$S26objc_ownership_conventions6test11{{[_0-9a-zA-Z]*}}F
+func test11(_ g: Gizmo) -> AnyClass {
+  // CHECK: bb0([[G:%[0-9]+]] : @guaranteed $Gizmo):
+  // CHECK: [[G_COPY:%.*]] = copy_value [[G]]
+  // CHECK: [[NS_G_COPY:%[0-9]+]] = upcast [[G_COPY:%[0-9]+]] : $Gizmo to $NSObject
+  // CHECK-NEXT: [[GETTER:%[0-9]+]] = objc_method [[NS_G_COPY]] : $NSObject, #NSObject.qualifiedClassProp!getter.1.foreign : (NSObject) -> () -> NSAnsing.Type?, $@convention(objc_method) (NSObject) -> Optional<@objc_metatype NSAnsing.Type>
+  // CHECK-NEXT: [[OPT_OBJC:%.*]] = apply [[GETTER]]([[NS_G_COPY]]) : $@convention(objc_method) (NSObject) -> Optional<@objc_metatype NSAnsing.Type>
+  // CHECK-NEXT: switch_enum [[OPT_OBJC]] : $Optional<{{.*}}>, case #Optional.some!enumelt.1: [[SOME_BB:bb[0-9]+]], case #Optional.none!enumelt: [[NONE_BB:bb[0-9]+]]
+  //
+  // CHECK: [[SOME_BB]]([[OBJC:%.*]] : @trivial $@objc_metatype NSAnsing.Type):
+  // CHECK-NEXT: [[THICK:%.*]] = objc_to_thick_metatype [[OBJC]]
+  // CHECK:      [[T0:%.*]] = enum $Optional<@thick NSAnsing.Type>, #Optional.some!enumelt.1, [[THICK]]
+  // CHECK:   bb{{.*}}(%{{.*}} : @trivial $Optional<@thick NSAnsing.Type>):
+  // CHECK:      destroy_value [[NS_G_COPY]] : $NSObject
+  // CHECK:   bb{{.*}}([[RES:%.*]] : @trivial $@thick NSAnsing.Type):
+  // CHECK:      [[OPENED:%.*]] = open_existential_metatype [[RES]]
+  // CHECK:      [[RES_ANY:%.*]] = init_existential_metatype [[OPENED]]
+  // CHECK-NOT:      destroy_value [[G]] : $Gizmo
+  // CHECK-NEXT: return [[RES_ANY]] : $@thick AnyObject.Type
+  return g.qualifiedClassProp
+}
+
+// ObjC blocks should have cdecl calling convention and follow C/ObjC
+// ownership conventions, where the callee, arguments, and return are all +0.
+// CHECK-LABEL: sil hidden @$S26objc_ownership_conventions10applyBlock{{[_0-9a-zA-Z]*}}F
+func applyBlock(_ f: @convention(block) (Gizmo) -> Gizmo, x: Gizmo) -> Gizmo {
+  // CHECK:     bb0([[BLOCK:%.*]] : @guaranteed $@convention(block) @noescape (Gizmo) -> @autoreleased Gizmo, [[ARG:%.*]] : @guaranteed $Gizmo):
+  // CHECK:       [[BLOCK_COPY:%.*]] = copy_block [[BLOCK]]
+  // CHECK:       [[BORROWED_BLOCK_COPY:%.*]] = begin_borrow [[BLOCK_COPY]]
+  // CHECK:       [[BLOCK_COPY_COPY:%.*]] = copy_value [[BORROWED_BLOCK_COPY]]
+  // CHECK:       [[RESULT:%.*]] = apply [[BLOCK_COPY_COPY]]([[ARG]])
+  // CHECK:       destroy_value [[BLOCK_COPY_COPY]]
+  // CHECK:       end_borrow [[BORROWED_BLOCK_COPY]] from [[BLOCK_COPY]]
+  // CHECK-NOT:       destroy_value [[ARG]]
+  // CHECK:       destroy_value [[BLOCK_COPY]]
+  // CHECK-NOT:       destroy_value [[BLOCK]]
+  // CHECK:       return [[RESULT]]
+  return f(x)
+}
+
+// CHECK-LABEL: sil hidden @$S26objc_ownership_conventions15maybeApplyBlock{{[_0-9a-zA-Z]*}}F
+func maybeApplyBlock(_ f: (@convention(block) (Gizmo) -> Gizmo)?, x: Gizmo) -> Gizmo? {
+  // CHECK:     bb0([[BLOCK:%.*]] : @guaranteed $Optional<@convention(block) (Gizmo) -> @autoreleased Gizmo>, [[ARG:%.*]] : @guaranteed $Gizmo):
+  // CHECK:       [[BLOCK_COPY:%.*]] = copy_block [[BLOCK]]
+  return f?(x)
+}
+
+func useInnerPointer(_ p: UnsafeMutableRawPointer) {}
+
+// Handle inner-pointer methods by autoreleasing self after the call.
+// CHECK-LABEL: sil hidden @$S26objc_ownership_conventions18innerPointerMethodyySo5GizmoCF : $@convention(thin) (@guaranteed Gizmo) -> () {
+// CHECK: bb0([[ARG:%.*]] : @guaranteed $Gizmo):
+// CHECK:         [[METHOD:%.*]] = objc_method [[ARG]] : $Gizmo, #Gizmo.getBytes!1.foreign : (Gizmo) -> () -> UnsafeMutableRawPointer, $@convention(objc_method) (Gizmo) -> @unowned_inner_pointer UnsafeMutableRawPointer
+// CHECK:         [[ARG_COPY:%.*]] = copy_value [[ARG]]
+// => SEMANTIC ARC TODO: The apply below /should/ be on ARG_COPY. It is safe how
+// it is today though since we are using a reference type.
+// CHECK:         [[PTR:%.*]] = apply [[METHOD]]([[ARG]])
+// CHECK:         autorelease_value [[ARG_COPY]]
+// CHECK:         [[USE:%.*]] = function_ref @$S26objc_ownership_conventions15useInnerPointer{{[_0-9a-zA-Z]*}}F
+// CHECK:         apply [[USE]]([[PTR]])
+// CHECK-NOT:         destroy_value [[ARG]]
+func innerPointerMethod(_ g: Gizmo) {
+  useInnerPointer(g.getBytes())
+}
+
+// CHECK-LABEL: sil hidden @$S26objc_ownership_conventions20innerPointerPropertyyySo5GizmoCF : $@convention(thin) (@guaranteed Gizmo) -> () {
+// CHECK:       bb0([[ARG:%.*]] : @guaranteed $Gizmo):
+// CHECK:         [[METHOD:%.*]] = objc_method [[ARG]] : $Gizmo, #Gizmo.innerProperty!getter.1.foreign : (Gizmo) -> () -> UnsafeMutableRawPointer, $@convention(objc_method) (Gizmo) -> @unowned_inner_pointer UnsafeMutableRawPointer
+// CHECK:         [[ARG_COPY:%.*]] = copy_value [[ARG]]
+// => SEMANTIC ARC TODO: The apply below should be on ARG_COPY. It is benign since objc objects are reference types.
+// CHECK:         [[PTR:%.*]] = apply [[METHOD]]([[ARG]])
+// CHECK:         autorelease_value [[ARG_COPY]]
+// CHECK:         [[USE:%.*]] = function_ref @$S26objc_ownership_conventions15useInnerPointer{{[_0-9a-zA-Z]*}}F
+// CHECK:         apply [[USE]]([[PTR]])
+// CHECK-NOT:         destroy_value [[ARG]]
+// CHECK: } // end sil function '$S26objc_ownership_conventions20innerPointerPropertyyySo5GizmoCF'
+func innerPointerProperty(_ g: Gizmo) {
+  useInnerPointer(g.innerProperty)
+}
diff --git a/test/SILGen/plus_zero_objc_protocol_native_thunk.swift b/test/SILGen/plus_zero_objc_protocol_native_thunk.swift
new file mode 100644
index 0000000..3d75ecf
--- /dev/null
+++ b/test/SILGen/plus_zero_objc_protocol_native_thunk.swift
@@ -0,0 +1,17 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -emit-silgen -enable-sil-ownership %s | %FileCheck %s
+// REQUIRES: objc_interop
+
+import Foundation
+
+@objc protocol P {
+  func p(_: String)
+}
+@objc class C: NSObject {
+  func c(_: String) {}
+}
+
+// CHECK-LABEL: sil shared [serializable] [thunk] @$S{{.*}}1P{{.*}}1p{{.*}} : $@convention(method) <Self where Self : P> (@guaranteed String, @guaranteed Self) -> ()
+func foo(x: Bool, y: C & P) -> (String) -> () {
+  return x ? y.c : y.p
+}
diff --git a/test/SILGen/plus_zero_objc_protocols.swift b/test/SILGen/plus_zero_objc_protocols.swift
new file mode 100644
index 0000000..5052509
--- /dev/null
+++ b/test/SILGen/plus_zero_objc_protocols.swift
@@ -0,0 +1,293 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -sdk %S/Inputs -I %S/Inputs -enable-source-import %s -emit-silgen -disable-objc-attr-requires-foundation-module -enable-sil-ownership | %FileCheck %s
+
+// REQUIRES: objc_interop
+
+import gizmo
+import objc_protocols_Bas
+
+@objc protocol NSRuncing {
+  func runce() -> NSObject
+  func copyRuncing() -> NSObject
+
+  func foo()
+
+  static func mince() -> NSObject
+}
+
+@objc protocol NSFunging {
+  func funge()
+
+  func foo()
+}
+
+protocol Ansible {
+  func anse()
+}
+
+// CHECK-LABEL: sil hidden @$S14objc_protocols0A8_generic{{[_0-9a-zA-Z]*}}F
+// CHECK: bb0([[THIS:%.*]] : @guaranteed $T):
+// -- Result of runce is autoreleased according to default objc conv
+// CHECK: [[METHOD:%.*]] = objc_method [[THIS]] : {{\$.*}},  #NSRuncing.runce!1.foreign
+// CHECK: [[RESULT1:%.*]] = apply [[METHOD]]<T>([[THIS:%.*]]) : $@convention(objc_method) <τ_0_0 where τ_0_0 : NSRuncing> (τ_0_0) -> @autoreleased NSObject
+
+// -- Result of copyRuncing is received copy_valued according to -copy family
+// CHECK: [[METHOD:%.*]] = objc_method [[THIS]] : {{\$.*}},  #NSRuncing.copyRuncing!1.foreign
+// CHECK: [[RESULT2:%.*]] = apply [[METHOD]]<T>([[THIS:%.*]]) : $@convention(objc_method) <τ_0_0 where τ_0_0 : NSRuncing> (τ_0_0) -> @owned NSObject
+
+// -- Arguments are not consumed by objc calls
+// CHECK-NOT: destroy_value [[THIS]]
+func objc_generic<T : NSRuncing>(_ x: T) -> (NSObject, NSObject) {
+  return (x.runce(), x.copyRuncing())
+}
+
+// CHECK-LABEL: sil hidden @$S14objc_protocols0A22_generic_partial_applyyyxAA9NSRuncingRzlF : $@convention(thin) <T where T : NSRuncing> (@guaranteed T) -> () {
+func objc_generic_partial_apply<T : NSRuncing>(_ x: T) {
+  // CHECK: bb0([[ARG:%.*]] : @guaranteed $T):
+  // CHECK:   [[FN:%.*]] = function_ref @[[THUNK1:\$S14objc_protocols9NSRuncingP5runceSo8NSObjectCyFTcTO]] :
+  // CHECK:   [[METHOD:%.*]] = apply [[FN]]<T>([[ARG]])
+  // CHECK:   destroy_value [[METHOD]]
+  _ = x.runce
+
+  // CHECK:   [[FN:%.*]] = function_ref @[[THUNK1]] :
+  // CHECK:   [[METHOD:%.*]] = partial_apply [callee_guaranteed] [[FN]]<T>()
+  // CHECK:   destroy_value [[METHOD]]
+  _ = T.runce
+
+  // CHECK:   [[METATYPE:%.*]] = metatype $@thick T.Type
+  // CHECK:   [[FN:%.*]] = function_ref @[[THUNK2:\$S14objc_protocols9NSRuncingP5minceSo8NSObjectCyFZTcTO]]
+  // CHECK:   [[METHOD:%.*]] = apply [[FN]]<T>([[METATYPE]])
+  // CHECK:   destroy_value [[METHOD:%.*]]
+  _ = T.mince
+  // CHECK-NOT:   destroy_value [[ARG]]
+}
+// CHECK: } // end sil function '$S14objc_protocols0A22_generic_partial_applyyyxAA9NSRuncingRzlF'
+
+// CHECK: sil shared [serializable] [thunk] @[[THUNK1]] :
+// CHECK: bb0([[SELF:%.*]] : @guaranteed $Self):
+// CHECK:   [[FN:%.*]] = function_ref @[[THUNK1_THUNK:\$S14objc_protocols9NSRuncingP5runceSo8NSObjectCyFTO]] :
+// CHECK:   [[SELF_COPY:%.*]] = copy_value [[SELF]]
+// CHECK:   [[METHOD:%.*]] = partial_apply [callee_guaranteed] [[FN]]<Self>([[SELF_COPY]])
+// CHECK:   return [[METHOD]]
+// CHECK: } // end sil function '[[THUNK1]]'
+
+// CHECK: sil shared [serializable] [thunk] @[[THUNK1_THUNK]]
+// CHECK: bb0([[SELF:%.*]] : @guaranteed $Self):
+// CHECK:   [[SELF_COPY:%.*]] = copy_value [[SELF]]
+// CHECK:   [[FN:%.*]] = objc_method [[SELF_COPY]] : $Self, #NSRuncing.runce!1.foreign
+// CHECK:   [[RESULT:%.*]] = apply [[FN]]<Self>([[SELF_COPY]])
+// CHECK:   destroy_value [[SELF_COPY]]
+// CHECK:   return [[RESULT]]
+// CHECK: } // end sil function '[[THUNK1_THUNK]]'
+
+// CHECK: sil shared [serializable] [thunk] @[[THUNK2]] :
+// CHECK:   [[FN:%.*]] = function_ref @[[THUNK2_THUNK:\$S14objc_protocols9NSRuncingP5minceSo8NSObjectCyFZTO]]
+// CHECK:   [[METHOD:%.*]] = partial_apply [callee_guaranteed] [[FN]]<Self>(%0)
+// CHECK:   return [[METHOD]]
+// CHECK: } // end sil function '[[THUNK2]]'
+
+// CHECK: sil shared [serializable] [thunk] @[[THUNK2_THUNK]] :
+// CHECK:      [[FN:%.*]] = objc_method %0 : $@thick Self.Type, #NSRuncing.mince!1.foreign
+// CHECK-NEXT: [[RESULT:%.*]] = apply [[FN]]<Self>(%0)
+// CHECK-NEXT: return [[RESULT]]
+// CHECK: } // end sil function '[[THUNK2_THUNK]]'
+
+// CHECK-LABEL: sil hidden @$S14objc_protocols0A9_protocol{{[_0-9a-zA-Z]*}}F
+// CHECK: bb0([[THIS:%.*]] : @guaranteed $NSRuncing):
+// -- Result of runce is autoreleased according to default objc conv
+// CHECK: [[THIS1:%.*]] = open_existential_ref [[THIS]] : $NSRuncing to $[[OPENED:@opened(.*) NSRuncing]]
+// CHECK: [[METHOD:%.*]] = objc_method [[THIS1]] : $[[OPENED]], #NSRuncing.runce!1.foreign
+// CHECK: [[RESULT1:%.*]] = apply [[METHOD]]<[[OPENED]]>([[THIS1]])
+
+// -- Result of copyRuncing is received copy_valued according to -copy family
+// CHECK: [[THIS2:%.*]] = open_existential_ref [[THIS]] : $NSRuncing to $[[OPENED2:@opened(.*) NSRuncing]]
+// CHECK: [[METHOD:%.*]] = objc_method [[THIS2]] : $[[OPENED2]], #NSRuncing.copyRuncing!1.foreign
+// CHECK: [[RESULT2:%.*]] = apply [[METHOD]]<[[OPENED2]]>([[THIS2:%.*]])
+
+// -- Arguments are not consumed by objc calls
+// CHECK-NOT: destroy_value [[THIS]]
+func objc_protocol(_ x: NSRuncing) -> (NSObject, NSObject) {
+  return (x.runce(), x.copyRuncing())
+}
+
+// CHECK-LABEL: sil hidden @$S14objc_protocols0A23_protocol_partial_applyyyAA9NSRuncing_pF : $@convention(thin) (@guaranteed NSRuncing) -> () {
+func objc_protocol_partial_apply(_ x: NSRuncing) {
+  // CHECK: bb0([[ARG:%.*]] : @guaranteed $NSRuncing):
+  // CHECK:   [[OPENED_ARG:%.*]] = open_existential_ref [[ARG]] : $NSRuncing to $[[OPENED:@opened(.*) NSRuncing]]
+  // CHECK:   [[FN:%.*]] = function_ref @$S14objc_protocols9NSRuncingP5runceSo8NSObjectCyFTcTO
+  // CHECK:   [[RESULT:%.*]] = apply [[FN]]<[[OPENED]]>([[OPENED_ARG]])
+  // CHECK:   destroy_value [[RESULT]]
+  // CHECK-NOT:   destroy_value [[ARG]]
+  _ = x.runce
+
+  // FIXME: rdar://21289579
+  // _ = NSRuncing.runce
+}
+// CHECK : } // end sil function '$S14objc_protocols0A23_protocol_partial_applyyyAA9NSRuncing_pF'
+
+// CHECK-LABEL: sil hidden @$S14objc_protocols0A21_protocol_composition{{[_0-9a-zA-Z]*}}F
+func objc_protocol_composition(_ x: NSRuncing & NSFunging) {
+  // CHECK: [[THIS:%.*]] = open_existential_ref [[THIS_ORIG:%.*]] : $NSFunging & NSRuncing to $[[OPENED:@opened(.*) NSFunging & NSRuncing]]
+  // CHECK: [[METHOD:%.*]] = objc_method [[THIS]] : $[[OPENED]], #NSRuncing.runce!1.foreign
+  // CHECK: apply [[METHOD]]<[[OPENED]]>([[THIS]])
+  x.runce()
+
+  // CHECK: [[THIS:%.*]] = open_existential_ref [[THIS_ORIG:%.*]] : $NSFunging & NSRuncing to $[[OPENED:@opened(.*) NSFunging & NSRuncing]]
+  // CHECK: [[METHOD:%.*]] = objc_method [[THIS]] : $[[OPENED]], #NSFunging.funge!1.foreign
+  // CHECK: apply [[METHOD]]<[[OPENED]]>([[THIS]])
+  x.funge()
+}
+// -- ObjC thunks get emitted for ObjC protocol conformances
+
+class Foo : NSRuncing, NSFunging, Ansible {
+  // -- NSRuncing
+  @objc func runce() -> NSObject { return NSObject() }
+  @objc func copyRuncing() -> NSObject { return NSObject() }
+
+  @objc static func mince() -> NSObject { return NSObject() }
+
+  // -- NSFunging
+  @objc func funge() {}
+
+  // -- Both NSRuncing and NSFunging
+  @objc func foo() {}
+
+  // -- Ansible
+  func anse() {}
+}
+
+// CHECK-LABEL: sil hidden [thunk] @$S14objc_protocols3FooC5runce{{[_0-9a-zA-Z]*}}FTo
+// CHECK-LABEL: sil hidden [thunk] @$S14objc_protocols3FooC11copyRuncing{{[_0-9a-zA-Z]*}}FTo
+// CHECK-LABEL: sil hidden [thunk] @$S14objc_protocols3FooC5funge{{[_0-9a-zA-Z]*}}FTo
+// CHECK-LABEL: sil hidden [thunk] @$S14objc_protocols3FooC3foo{{[_0-9a-zA-Z]*}}FTo
+// CHECK-NOT: sil hidden @_TToF{{.*}}anse{{.*}}
+
+class Bar { }
+
+extension Bar : NSRuncing {
+  @objc func runce() -> NSObject { return NSObject() }
+  @objc func copyRuncing() -> NSObject { return NSObject() }
+  @objc func foo() {}
+  @objc static func mince() -> NSObject { return NSObject() }
+}
+
+// CHECK-LABEL: sil hidden [thunk] @$S14objc_protocols3BarC5runce{{[_0-9a-zA-Z]*}}FTo
+// CHECK-LABEL: sil hidden [thunk] @$S14objc_protocols3BarC11copyRuncing{{[_0-9a-zA-Z]*}}FTo
+// CHECK-LABEL: sil hidden [thunk] @$S14objc_protocols3BarC3foo{{[_0-9a-zA-Z]*}}FTo
+
+// class Bas from objc_protocols_Bas module
+extension Bas : NSRuncing {
+  // runce() implementation from the original definition of Bas
+  @objc func copyRuncing() -> NSObject { return NSObject() }
+  @objc func foo() {}
+  @objc static func mince() -> NSObject { return NSObject() }
+}
+
+// CHECK-LABEL: sil hidden [thunk] @$S18objc_protocols_Bas0C0C0a1_B0E11copyRuncing{{[_0-9a-zA-Z]*}}FTo
+// CHECK-LABEL: sil hidden [thunk] @$S18objc_protocols_Bas0C0C0a1_B0E3foo{{[_0-9a-zA-Z]*}}FTo
+
+// -- Inherited objc protocols
+
+protocol Fungible : NSFunging { }
+
+class Zim : Fungible {
+  @objc func funge() {}
+  @objc func foo() {}
+}
+
+// CHECK-LABEL: sil hidden [thunk] @$S14objc_protocols3ZimC5funge{{[_0-9a-zA-Z]*}}FTo
+// CHECK-LABEL: sil hidden [thunk] @$S14objc_protocols3ZimC3foo{{[_0-9a-zA-Z]*}}FTo
+
+// class Zang from objc_protocols_Bas module
+extension Zang : Fungible {
+  // funge() implementation from the original definition of Zim
+  @objc func foo() {}
+}
+
+// CHECK-LABEL: sil hidden [thunk] @$S18objc_protocols_Bas4ZangC0a1_B0E3foo{{[_0-9a-zA-Z]*}}FTo
+
+// -- objc protocols with property requirements in extensions
+//    <rdar://problem/16284574>
+
+@objc protocol NSCounting {
+  var count: Int {get}
+}
+
+class StoredPropertyCount {
+  @objc let count = 0
+}
+
+extension StoredPropertyCount: NSCounting {}
+// CHECK-LABEL: sil hidden [transparent] [thunk] @$S14objc_protocols19StoredPropertyCountC5countSivgTo
+
+class ComputedPropertyCount {
+  @objc var count: Int { return 0 }
+}
+
+extension ComputedPropertyCount: NSCounting {}
+// CHECK-LABEL: sil hidden [thunk] @$S14objc_protocols21ComputedPropertyCountC5countSivgTo
+
+// -- adding @objc protocol conformances to native ObjC classes should not
+//    emit thunks since the methods are already available to ObjC.
+
+// Gizmo declared in Inputs/usr/include/Gizmo.h
+extension Gizmo : NSFunging { }
+
+// CHECK-NOT: _TTo{{.*}}5Gizmo{{.*}}
+
+@objc class InformallyFunging {
+  @objc func funge() {}
+  @objc func foo() {}
+}
+
+extension InformallyFunging: NSFunging { }
+
+@objc protocol Initializable {
+  init(int: Int)
+}
+
+// CHECK-LABEL: sil hidden @$S14objc_protocols28testInitializableExistential_1iAA0D0_pAaD_pXp_SitF : $@convention(thin) (@thick Initializable.Type, Int) -> @owned Initializable {
+func testInitializableExistential(_ im: Initializable.Type, i: Int) -> Initializable {
+  // CHECK: bb0([[META:%[0-9]+]] : @trivial $@thick Initializable.Type, [[I:%[0-9]+]] : @trivial $Int):
+  // CHECK:   [[I2_BOX:%[0-9]+]] = alloc_box ${ var Initializable }
+  // CHECK:   [[PB:%.*]] = project_box [[I2_BOX]]
+  // CHECK:   [[ARCHETYPE_META:%[0-9]+]] = open_existential_metatype [[META]] : $@thick Initializable.Type to $@thick (@opened([[N:".*"]]) Initializable).Type
+  // CHECK:   [[ARCHETYPE_META_OBJC:%[0-9]+]] = thick_to_objc_metatype [[ARCHETYPE_META]] : $@thick (@opened([[N]]) Initializable).Type to $@objc_metatype (@opened([[N]]) Initializable).Type
+  // CHECK:   [[I2_ALLOC:%[0-9]+]] = alloc_ref_dynamic [objc] [[ARCHETYPE_META_OBJC]] : $@objc_metatype (@opened([[N]]) Initializable).Type, $@opened([[N]]) Initializable
+  // CHECK:   [[INIT_WITNESS:%[0-9]+]] = objc_method [[I2_ALLOC]] : $@opened([[N]]) Initializable, #Initializable.init!initializer.1.foreign : {{.*}}
+  // CHECK:   [[I2:%[0-9]+]] = apply [[INIT_WITNESS]]<@opened([[N]]) Initializable>([[I]], [[I2_ALLOC]]) : $@convention(objc_method) <τ_0_0 where τ_0_0 : Initializable> (Int, @owned τ_0_0) -> @owned τ_0_0
+  // CHECK:   [[I2_EXIST_CONTAINER:%[0-9]+]] = init_existential_ref [[I2]] : $@opened([[N]]) Initializable : $@opened([[N]]) Initializable, $Initializable
+  // CHECK:   store [[I2_EXIST_CONTAINER]] to [init] [[PB]] : $*Initializable
+  // CHECK:   [[READ:%.*]] = begin_access [read] [unknown] [[PB]] : $*Initializable
+  // CHECK:   [[I2:%[0-9]+]] = load [copy] [[READ]] : $*Initializable
+  // CHECK:   destroy_value [[I2_BOX]] : ${ var Initializable }
+  // CHECK:   return [[I2]] : $Initializable
+  var i2 = im.init(int: i)
+  return i2
+}
+// CHECK: } // end sil function '$S14objc_protocols28testInitializableExistential_1iAA0D0_pAaD_pXp_SitF'
+
+class InitializableConformer: Initializable {
+  @objc required init(int: Int) {}
+}
+// CHECK-LABEL: sil hidden [thunk] @$S14objc_protocols22InitializableConformerC{{[_0-9a-zA-Z]*}}fcTo
+
+final class InitializableConformerByExtension {
+  init() {}
+}
+
+extension InitializableConformerByExtension: Initializable {
+  @objc convenience init(int: Int) {
+    self.init()
+  }
+}
+// CHECK-LABEL: sil hidden [thunk] @$S14objc_protocols33InitializableConformerByExtensionC{{[_0-9a-zA-Z]*}}fcTo
+
+// Make sure we're crashing from trying to use materializeForSet here.
+@objc protocol SelectionItem {
+  var time: Double { get set }
+}
+
+func incrementTime(contents: SelectionItem) {
+  contents.time += 1.0
+}
diff --git a/test/SILGen/plus_zero_objc_set_bridging.swift b/test/SILGen/plus_zero_objc_set_bridging.swift
new file mode 100644
index 0000000..3c790c1
--- /dev/null
+++ b/test/SILGen/plus_zero_objc_set_bridging.swift
@@ -0,0 +1,92 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %empty-directory(%t)
+// RUN: %build-silgen-test-overlays
+
+// RUN: %target-swift-frontend(mock-sdk: -sdk %S/Inputs -I %t) -emit-silgen %s -enable-sil-ownership | %FileCheck %s
+
+// REQUIRES: objc_interop
+
+import Foundation
+import gizmo
+
+@objc class Foo : NSObject {
+  // Bridging set parameters
+  // CHECK-LABEL: sil hidden [thunk] @$S17objc_set_bridging3FooC16bridge_Set_param{{[_0-9a-zA-Z]*}}FTo : $@convention(objc_method) (NSSet, Foo) -> ()
+  func bridge_Set_param(_ s: Set<Foo>) {
+    // CHECK: bb0([[NSSET:%[0-9]+]] : @unowned $NSSet, [[SELF:%[0-9]+]] : @unowned $Foo):
+    // CHECK:   [[NSSET_COPY:%.*]] = copy_value [[NSSET]] : $NSSet
+    // CHECK:   [[SELF_COPY:%.*]] = copy_value [[SELF]] : $Foo
+    // CHECK:   [[CONVERTER:%[0-9]+]] = function_ref @$Ss3SetV10FoundationE36_unconditionallyBridgeFromObjectiveCyAByxGSo5NSSetCSgFZ
+    // CHECK:   [[OPT_NSSET:%[0-9]+]] = enum $Optional<NSSet>, #Optional.some!enumelt.1, [[NSSET_COPY]] : $NSSet
+    // CHECK:   [[SET_META:%[0-9]+]] = metatype $@thin Set<Foo>.Type
+    // CHECK:   [[SET:%[0-9]+]] = apply [[CONVERTER]]<Foo>([[OPT_NSSET]], [[SET_META]])
+    // CHECK:   [[BORROWED_SET:%.*]] = begin_borrow [[SET]]
+    // CHECK:   [[BORROWED_SELF_COPY:%.*]] = begin_borrow [[SELF_COPY]]
+    // CHECK:   [[SWIFT_FN:%[0-9]+]] = function_ref @$S17objc_set_bridging3FooC16bridge_Set_param{{[_0-9a-zA-Z]*}}F : $@convention(method) (@guaranteed Set<Foo>, @guaranteed Foo) -> ()
+    // CHECK:   [[RESULT:%[0-9]+]] = apply [[SWIFT_FN]]([[BORROWED_SET]], [[BORROWED_SELF_COPY]]) : $@convention(method) (@guaranteed Set<Foo>, @guaranteed Foo) -> ()
+    // CHECK:   end_borrow [[BORROWED_SELF_COPY]] from [[SELF_COPY]]
+    // CHECK:   destroy_value [[SELF_COPY]]
+    // CHECK:   return [[RESULT]] : $()
+  }
+  // CHECK: // end sil function '$S17objc_set_bridging3FooC16bridge_Set_param{{[_0-9a-zA-Z]*}}FTo'
+
+  // Bridging set results
+  // CHECK-LABEL: sil hidden [thunk] @$S17objc_set_bridging3FooC17bridge_Set_result{{[_0-9a-zA-Z]*}}FTo : $@convention(objc_method) (Foo) -> @autoreleased NSSet {
+  func bridge_Set_result() -> Set<Foo> { 
+    // CHECK: bb0([[SELF:%[0-9]+]] : @unowned $Foo):
+    // CHECK:   [[SELF_COPY:%.*]] = copy_value [[SELF]] : $Foo
+    // CHECK:   [[BORROWED_SELF_COPY:%.*]] = begin_borrow [[SELF_COPY]]
+    // CHECK:   [[SWIFT_FN:%[0-9]+]] = function_ref @$S17objc_set_bridging3FooC17bridge_Set_result{{[_0-9a-zA-Z]*}}F : $@convention(method) (@guaranteed Foo) -> @owned Set<Foo>
+    // CHECK:   [[SET:%[0-9]+]] = apply [[SWIFT_FN]]([[BORROWED_SELF_COPY]]) : $@convention(method) (@guaranteed Foo) -> @owned Set<Foo>
+    // CHECK:   end_borrow [[BORROWED_SELF_COPY]] from [[SELF_COPY]]
+    // CHECK:   destroy_value [[SELF_COPY]]
+    // CHECK:   [[CONVERTER:%[0-9]+]] = function_ref @$Ss3SetV10FoundationE19_bridgeToObjectiveCSo5NSSetCyF
+    // CHECK:   [[BORROWED_SET:%.*]] = begin_borrow [[SET]]
+    // CHECK:   [[NSSET:%[0-9]+]] = apply [[CONVERTER]]<Foo>([[BORROWED_SET]]) : $@convention(method) <τ_0_0 where τ_0_0 : Hashable> (@guaranteed Set<τ_0_0>) -> @owned NSSet
+    // CHECK:   end_borrow [[BORROWED_SET]] from [[SET]]
+    // CHECK:   destroy_value [[SET]]
+    // CHECK:   return [[NSSET]] : $NSSet
+  }
+  // CHECK: } // end sil function '$S17objc_set_bridging3FooC17bridge_Set_result{{[_0-9a-zA-Z]*}}FTo'
+
+  var property: Set<Foo> = Set()
+
+  // Property getter
+  // CHECK-LABEL: sil hidden [thunk] @$S17objc_set_bridging3FooC8property{{[_0-9a-zA-Z]*}}vgTo : $@convention(objc_method) (Foo) -> @autoreleased NSSet
+  // CHECK: bb0([[SELF:%[0-9]+]] : @unowned $Foo):
+  // CHECK:   [[SELF_COPY]] = copy_value [[SELF]] : $Foo
+  // CHECK:   [[BORROWED_SELF_COPY:%.*]] = begin_borrow [[SELF_COPY]]
+  // CHECK:   [[GETTER:%[0-9]+]] = function_ref @$S17objc_set_bridging3FooC8property{{[_0-9a-zA-Z]*}}vg : $@convention(method) (@guaranteed Foo) -> @owned Set<Foo>
+  // CHECK:   [[SET:%[0-9]+]] = apply [[GETTER]]([[BORROWED_SELF_COPY]]) : $@convention(method) (@guaranteed Foo) -> @owned Set<Foo>
+  // CHECK:   end_borrow [[BORROWED_SELF_COPY]] from [[SELF_COPY]]
+  // CHECK:   destroy_value [[SELF_COPY]]
+  // CHECK:   [[CONVERTER:%[0-9]+]] = function_ref @$Ss3SetV10FoundationE19_bridgeToObjectiveCSo5NSSetCyF
+  // CHECK:   [[BORROWED_SET:%.*]] = begin_borrow [[SET]]
+  // CHECK:   [[NSSET:%[0-9]+]] = apply [[CONVERTER]]<Foo>([[BORROWED_SET]]) : $@convention(method) <τ_0_0 where τ_0_0 : Hashable> (@guaranteed Set<τ_0_0>) -> @owned NSSet
+  // CHECK:   end_borrow [[BORROWED_SET]] from [[SET]]
+  // CHECK:   destroy_value [[SET]]
+  // CHECK:   return [[NSSET]] : $NSSet
+  // CHECK: } // end sil function '$S17objc_set_bridging3FooC8property{{[_0-9a-zA-Z]*}}vgTo'
+  
+  // Property setter
+  // CHECK-LABEL: sil hidden [thunk] @$S17objc_set_bridging3FooC8property{{[_0-9a-zA-Z]*}}vsTo : $@convention(objc_method) (NSSet, Foo) -> () {
+  // CHECK: bb0([[NSSET:%[0-9]+]] : @unowned $NSSet, [[SELF:%[0-9]+]] : @unowned $Foo):
+  // CHECK:   [[NSSET_COPY:%.*]] = copy_value [[NSSET]] : $NSSet
+  // CHECK:   [[SELF_COPY:%.*]] = copy_value [[SELF]] : $Foo
+  // CHECK:   [[CONVERTER:%[0-9]+]] = function_ref @$Ss3SetV10FoundationE36_unconditionallyBridgeFromObjectiveCyAByxGSo5NSSetCSgFZ
+  // CHECK:   [[OPT_NSSET:%[0-9]+]] = enum $Optional<NSSet>, #Optional.some!enumelt.1, [[NSSET_COPY]] : $NSSet
+  // CHECK:   [[SET_META:%[0-9]+]] = metatype $@thin Set<Foo>.Type
+  // CHECK:   [[SET:%[0-9]+]] = apply [[CONVERTER]]<Foo>([[OPT_NSSET]], [[SET_META]])
+  // CHECK:   [[BORROWED_SELF_COPY:%.*]] = begin_borrow [[SELF_COPY]]
+  // CHECK:   [[SETTER:%[0-9]+]] = function_ref @$S17objc_set_bridging3FooC8property{{[_0-9a-zA-Z]*}}vs : $@convention(method) (@owned Set<Foo>, @guaranteed Foo) -> ()
+  // CHECK:   [[RESULT:%[0-9]+]] = apply [[SETTER]]([[SET]], [[BORROWED_SELF_COPY]]) : $@convention(method) (@owned Set<Foo>, @guaranteed Foo) -> ()
+  // CHECK:   end_borrow [[BORROWED_SELF_COPY]] from [[SELF_COPY]]
+  // CHECK:   destroy_value [[SELF_COPY]] : $Foo
+  // CHECK:   return [[RESULT]] : $()
+  
+  // CHECK-LABEL: sil hidden [thunk] @$S17objc_set_bridging3FooC19nonVerbatimProperty{{[_0-9a-zA-Z]*}}vgTo : $@convention(objc_method) (Foo) -> @autoreleased NSSet
+  // CHECK-LABEL: sil hidden [thunk] @$S17objc_set_bridging3FooC19nonVerbatimProperty{{[_0-9a-zA-Z]*}}vsTo : $@convention(objc_method) (NSSet, Foo) -> () {
+  @objc var nonVerbatimProperty: Set<String> = Set()
+}
+
+func ==(x: Foo, y: Foo) -> Bool { }
diff --git a/test/SILGen/plus_zero_objc_thunks.swift b/test/SILGen/plus_zero_objc_thunks.swift
new file mode 100644
index 0000000..0a40a32
--- /dev/null
+++ b/test/SILGen/plus_zero_objc_thunks.swift
@@ -0,0 +1,542 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -Xllvm -sil-full-demangle -Xllvm -sil-print-debuginfo -sdk %S/Inputs -I %S/Inputs -enable-source-import %s -emit-silgen -emit-verbose-sil -enable-sil-ownership | %FileCheck %s
+
+// REQUIRES: objc_interop
+
+import gizmo
+import ansible
+
+class Hoozit : Gizmo {
+  @objc func typical(_ x: Int, y: Gizmo) -> Gizmo { return y }
+  // CHECK-LABEL: sil hidden [thunk] @$S11objc_thunks6HoozitC7typical_1ySo5GizmoCSi_AGtFTo : $@convention(objc_method) (Int, Gizmo, Hoozit) -> @autoreleased Gizmo {
+  // CHECK: bb0([[X:%.*]] : @trivial $Int, [[Y:%.*]] : @unowned $Gizmo, [[THIS:%.*]] : @unowned $Hoozit):
+  // CHECK-NEXT:   [[Y_COPY:%.*]] = copy_value [[Y]]
+  // CHECK-NEXT:   [[THIS_COPY:%.*]] = copy_value [[THIS]]
+  // CHECK-NEXT:   [[BORROWED_Y_COPY:%.*]] = begin_borrow [[Y_COPY]]
+  // CHECK-NEXT:   [[BORROWED_THIS_COPY:%.*]] = begin_borrow [[THIS_COPY]]
+  // CHECK-NEXT:   // function_ref objc_thunks.Hoozit.typical
+  // CHECK-NEXT:   [[NATIVE:%.*]] = function_ref @$S11objc_thunks6HoozitC7typical_1ySo5GizmoCSi_AGtF : $@convention(method) (Int, @guaranteed Gizmo, @guaranteed Hoozit) -> @owned Gizmo
+  // CHECK-NEXT:   [[RES:%.*]] = apply [[NATIVE]]([[X]], [[BORROWED_Y_COPY]], [[BORROWED_THIS_COPY]]) {{.*}} line:[[@LINE-9]]:14:auto_gen
+  // CHECK-NEXT:   end_borrow [[BORROWED_THIS_COPY]] from [[THIS_COPY]]
+  // CHECK-NEXT:   end_borrow [[BORROWED_Y_COPY]] from [[Y_COPY]]
+  // CHECK-NEXT:   destroy_value [[THIS_COPY]] : $Hoozit
+  // CHECK-NEXT:   destroy_value [[Y_COPY]]
+  // CHECK-NEXT:   return [[RES]] : $Gizmo{{.*}} line:[[@LINE-14]]:14:auto_gen
+  // CHECK-NEXT: } // end sil function '$S11objc_thunks6HoozitC7typical_1ySo5GizmoCSi_AGtFTo'
+
+  // NS_CONSUMES_SELF by inheritance
+  override func fork() { }
+  // CHECK-LABEL: sil hidden [thunk] @$S11objc_thunks6HoozitC4forkyyFTo : $@convention(objc_method) (@owned Hoozit) -> () {
+  // CHECK: bb0([[THIS:%.*]] : @owned $Hoozit):
+  // CHECK-NEXT:   [[BORROWED_THIS:%.*]] = begin_borrow [[THIS]]
+  // CHECK-NEXT:   // function_ref
+  // CHECK-NEXT:   [[NATIVE:%.*]] = function_ref @$S11objc_thunks6HoozitC4forkyyF : $@convention(method) (@guaranteed Hoozit) -> ()
+  // CHECK-NEXT:   apply [[NATIVE]]([[BORROWED_THIS]])
+  // CHECK-NEXT:   end_borrow [[BORROWED_THIS]] from [[THIS]]
+  // CHECK-NEXT:   destroy_value [[THIS]]
+  // CHECK-NEXT:   return
+  // CHECK-NEXT: }
+
+  // NS_CONSUMED 'gizmo' argument by inheritance
+  override class func consume(_ gizmo: Gizmo?) { }
+   // CHECK-LABEL: sil hidden [thunk] @$S11objc_thunks6HoozitC7consumeyySo5GizmoCSgFZTo : $@convention(objc_method) (@owned Optional<Gizmo>, @objc_metatype Hoozit.Type) -> () {
+  // CHECK: bb0([[GIZMO:%.*]] : @owned $Optional<Gizmo>, [[THIS:%.*]] : @trivial $@objc_metatype Hoozit.Type):
+  // CHECK-NEXT: [[BORROWED_GIZMO:%.*]] = begin_borrow [[GIZMO]]
+  // CHECK-NEXT: [[THICK_THIS:%[0-9]+]] = objc_to_thick_metatype [[THIS]] : $@objc_metatype Hoozit.Type to $@thick Hoozit.Type
+  // CHECK:   [[NATIVE:%.*]] = function_ref @$S11objc_thunks6HoozitC7consumeyySo5GizmoCSgFZ : $@convention(method) (@guaranteed Optional<Gizmo>, @thick Hoozit.Type) -> ()
+  // CHECK-NEXT:   apply [[NATIVE]]([[BORROWED_GIZMO]], [[THICK_THIS]])
+  // CHECK-NEXT:   end_borrow [[BORROWED_GIZMO]]
+  // CHECK-NEXT:   destroy_value [[GIZMO]]
+  // CHECK-NEXT:   return
+  // CHECK-NEXT: }
+
+  // NS_RETURNS_RETAINED by family (-copy)
+  @objc func copyFoo() -> Gizmo { return self }
+  // CHECK-LABEL: sil hidden [thunk] @$S11objc_thunks6HoozitC7copyFooSo5GizmoCyFTo : $@convention(objc_method) (Hoozit) -> @owned Gizmo
+  // CHECK: bb0([[THIS:%.*]] : @unowned $Hoozit):
+  // CHECK-NEXT:   [[THIS_COPY:%.*]] = copy_value [[THIS]]
+  // CHECK-NEXT:   [[BORROWED_THIS_COPY:%.*]] = begin_borrow [[THIS_COPY]]
+  // CHECK-NEXT:   // function_ref
+  // CHECK-NEXT:   [[NATIVE:%.*]] = function_ref @$S11objc_thunks6HoozitC7copyFooSo5GizmoCyF : $@convention(method) (@guaranteed Hoozit) -> @owned Gizmo
+  // CHECK-NEXT:   [[RES:%.*]] = apply [[NATIVE]]([[BORROWED_THIS_COPY]])
+  // CHECK-NEXT:   end_borrow [[BORROWED_THIS_COPY]] from [[THIS_COPY]]
+  // CHECK-NEXT:   destroy_value [[THIS_COPY]]
+  // CHECK-NEXT:   return [[RES]]
+  // CHECK-NEXT: }
+
+  // NS_RETURNS_RETAINED by family (-copy)
+  @objc(copyDuplicate) func makeDuplicate() -> Gizmo { return self }
+  // CHECK-LABEL: sil hidden [thunk] @$S11objc_thunks6HoozitC13makeDuplicateSo5GizmoCyFTo : $@convention(objc_method) (Hoozit) -> @owned Gizmo
+  // CHECK: bb0([[THIS:%.*]] : @unowned $Hoozit):
+  // CHECK-NEXT:   [[THIS_COPY:%.*]] = copy_value [[THIS]]
+  // CHECK-NEXT:   [[BORROWED_THIS_COPY:%.*]] = begin_borrow [[THIS_COPY]]
+  // CHECK-NEXT:   // function_ref
+  // CHECK-NEXT:   [[NATIVE:%.*]] = function_ref @$S11objc_thunks6HoozitC13makeDuplicateSo5GizmoCyF : $@convention(method) (@guaranteed Hoozit) -> @owned Gizmo
+  // CHECK-NEXT:   [[RES:%.*]] = apply [[NATIVE]]([[BORROWED_THIS_COPY]])
+  // CHECK-NEXT:   end_borrow [[BORROWED_THIS_COPY]] from [[THIS_COPY]]
+  // CHECK-NEXT:   destroy_value [[THIS_COPY]]
+  // CHECK-NEXT:   return [[RES]]
+  // CHECK-NEXT: }
+
+  // Override the normal family conventions to make this non-consuming and
+  // returning at +0.
+  @objc func initFoo() -> Gizmo { return self }
+  // CHECK-LABEL: sil hidden [thunk] @$S11objc_thunks6HoozitC7initFooSo5GizmoCyFTo : $@convention(objc_method) (Hoozit) -> @autoreleased Gizmo
+  // CHECK: bb0([[THIS:%.*]] : @unowned $Hoozit):
+  // CHECK-NEXT:   [[THIS_COPY:%.*]] = copy_value [[THIS]]
+  // CHECK-NEXT:   [[BORROWED_THIS_COPY:%.*]] = begin_borrow [[THIS_COPY]]
+  // CHECK-NEXT:   // function_ref
+  // CHECK-NEXT:   [[NATIVE:%.*]] = function_ref @$S11objc_thunks6HoozitC7initFooSo5GizmoCyF : $@convention(method) (@guaranteed Hoozit) -> @owned Gizmo
+  // CHECK-NEXT:   [[RES:%.*]] = apply [[NATIVE]]([[BORROWED_THIS_COPY]])
+  // CHECK-NEXT:   end_borrow [[BORROWED_THIS_COPY]] from [[THIS_COPY]]
+  // CHECK-NEXT:   destroy_value [[THIS_COPY]]
+  // CHECK-NEXT:   return [[RES]]
+  // CHECK-NEXT: }
+
+  @objc var typicalProperty: Gizmo
+  // -- getter
+  // CHECK-LABEL: sil hidden [thunk] @$S11objc_thunks6HoozitC15typicalPropertySo5GizmoCvgTo : $@convention(objc_method) (Hoozit) -> @autoreleased Gizmo {
+  // CHECK: bb0([[SELF:%.*]] : @unowned $Hoozit):
+  // CHECK-NEXT:   [[SELF_COPY:%.*]] = copy_value [[SELF]]
+  // CHECK-NEXT:   [[BORROWED_SELF_COPY:%.*]] = begin_borrow [[SELF_COPY]]
+  // CHECK-NEXT:   // function_ref objc_thunks.Hoozit.typicalProperty.getter
+  // CHECK-NEXT:   [[GETIMPL:%.*]] = function_ref @$S11objc_thunks6HoozitC15typicalPropertySo5GizmoCvg
+  // CHECK-NEXT:   [[RES:%.*]] = apply [[GETIMPL]]([[BORROWED_SELF_COPY]])
+  // CHECK-NEXT:   end_borrow [[BORROWED_SELF_COPY]] from [[SELF_COPY]]
+  // CHECK-NEXT:   destroy_value [[SELF_COPY]]
+  // CHECK-NEXT:   return [[RES]] : $Gizmo
+  // CHECK-NEXT: }
+  
+  // CHECK-LABEL: sil hidden @$S11objc_thunks6HoozitC15typicalPropertySo5GizmoCvg : $@convention(method) (@guaranteed Hoozit) -> @owned Gizmo
+  // CHECK: bb0(%0 : @guaranteed $Hoozit):
+  // CHECK-NEXT:   debug_value %0
+  // CHECK-NEXT:   [[ADDR:%.*]] = ref_element_addr %0 : {{.*}}, #Hoozit.typicalProperty
+  // CHECK-NEXT:   [[READ:%.*]] = begin_access [read] [dynamic] [[ADDR]] : $*Gizmo
+  // CHECK-NEXT:   [[RES:%.*]] = load [copy] [[READ]] {{.*}}
+  // CHECK-NEXT:   end_access [[READ]] : $*Gizmo
+  // CHECK-NEXT:   return [[RES]]
+
+  // -- setter
+  // CHECK-LABEL: sil hidden [thunk] @$S11objc_thunks6HoozitC15typicalPropertySo5GizmoCvsTo : $@convention(objc_method) (Gizmo, Hoozit) -> () {
+  // CHECK: bb0([[VALUE:%.*]] : @unowned $Gizmo, [[THIS:%.*]] : @unowned $Hoozit):
+  // CHECK:   [[VALUE_COPY:%.*]] = copy_value [[VALUE]] : $Gizmo
+  // CHECK:   [[THIS_COPY:%.*]] = copy_value [[THIS]] : $Hoozit
+  // CHECK:   [[BORROWED_THIS_COPY:%.*]] = begin_borrow [[THIS_COPY]]
+  // CHECK:   // function_ref objc_thunks.Hoozit.typicalProperty.setter
+  // CHECK:   [[FR:%.*]] = function_ref @$S11objc_thunks6HoozitC15typicalPropertySo5GizmoCvs
+  // CHECK:   [[RES:%.*]] = apply [[FR]]([[VALUE_COPY]], [[BORROWED_THIS_COPY]])
+  // CHECK:   end_borrow [[BORROWED_THIS_COPY]] from [[THIS_COPY]]
+  // CHECK:   destroy_value [[THIS_COPY]]
+  // CHECK:   return [[RES]] : $(), loc {{.*}}, scope {{.*}} // id: {{.*}} line:[[@LINE-34]]:13:auto_gen
+  // CHECK: } // end sil function '$S11objc_thunks6HoozitC15typicalPropertySo5GizmoCvsTo'
+
+  // CHECK-LABEL: sil hidden @$S11objc_thunks6HoozitC15typicalPropertySo5GizmoCvs
+  // CHECK: bb0([[ARG0:%.*]] : @owned $Gizmo, [[ARG1:%.*]] : @guaranteed $Hoozit):
+  // CHECK:   [[BORROWED_ARG0:%.*]] = begin_borrow [[ARG0]]
+  // CHECK:   [[ARG0_COPY:%.*]] = copy_value [[BORROWED_ARG0]]
+  // CHECK:   [[ADDR:%.*]] = ref_element_addr [[ARG1]] : {{.*}}, #Hoozit.typicalProperty
+  // CHECK:   [[WRITE:%.*]] = begin_access [modify] [dynamic] [[ADDR]] : $*Gizmo
+  // CHECK:   assign [[ARG0_COPY]] to [[WRITE]] : $*Gizmo
+  // CHECK:   end_access [[WRITE]] : $*Gizmo
+  // CHECK:   end_borrow [[BORROWED_ARG0]] from [[ARG0]]
+  // CHECK:   destroy_value [[ARG0]]
+  // CHECK: } // end sil function '$S11objc_thunks6HoozitC15typicalPropertySo5GizmoCvs'
+
+  // NS_RETURNS_RETAINED getter by family (-copy)
+  @objc var copyProperty: Gizmo
+  // -- getter
+  // CHECK-LABEL: sil hidden [thunk] @$S11objc_thunks6HoozitC12copyPropertySo5GizmoCvgTo : $@convention(objc_method) (Hoozit) -> @owned Gizmo {
+  // CHECK: bb0([[SELF:%.*]] : @unowned $Hoozit):
+  // CHECK-NEXT:   [[SELF_COPY:%.*]] = copy_value [[SELF]]
+  // CHECK-NEXT:   [[BORROWED_SELF_COPY:%.*]] = begin_borrow [[SELF_COPY]]
+  // CHECK-NEXT:   // function_ref objc_thunks.Hoozit.copyProperty.getter
+  // CHECK-NEXT:   [[FR:%.*]] = function_ref @$S11objc_thunks6HoozitC12copyPropertySo5GizmoCvg
+  // CHECK-NEXT:   [[RES:%.*]] = apply [[FR]]([[BORROWED_SELF_COPY]])
+  // CHECK-NEXT:   end_borrow [[BORROWED_SELF_COPY]] from [[SELF_COPY]]
+  // CHECK-NEXT:   destroy_value [[SELF_COPY]]
+  // CHECK-NEXT:   return [[RES]]
+  // CHECK-NEXT: }
+
+  // CHECK-LABEL: sil hidden @$S11objc_thunks6HoozitC12copyPropertySo5GizmoCvg
+  // CHECK: bb0(%0 : @guaranteed $Hoozit):
+  // CHECK:        [[ADDR:%.*]] = ref_element_addr %0 : {{.*}}, #Hoozit.copyProperty
+  // CHECK-NEXT:   [[READ:%.*]] = begin_access [read] [dynamic] [[ADDR]] : $*Gizmo
+  // CHECK-NEXT:   [[RES:%.*]] = load [copy] [[READ]]
+  // CHECK-NEXT:   end_access [[READ]] : $*Gizmo
+  // CHECK-NEXT:   return [[RES]]
+
+  // -- setter is normal
+  // CHECK-LABEL: sil hidden [thunk] @$S11objc_thunks6HoozitC12copyPropertySo5GizmoCvsTo : $@convention(objc_method) (Gizmo, Hoozit) -> () {
+  // CHECK: bb0([[VALUE:%.*]] : @unowned $Gizmo, [[THIS:%.*]] : @unowned $Hoozit):
+  // CHECK-NEXT:   [[VALUE_COPY:%.*]] = copy_value [[VALUE]]
+  // CHECK-NEXT:   [[THIS_COPY:%.*]] = copy_value [[THIS]]
+  // CHECK-NEXT:   [[BORROWED_THIS_COPY:%.*]] = begin_borrow [[THIS_COPY]]
+  // CHECK-NEXT:   // function_ref objc_thunks.Hoozit.copyProperty.setter
+  // CHECK-NEXT:   [[FR:%.*]] = function_ref @$S11objc_thunks6HoozitC12copyPropertySo5GizmoCvs
+  // CHECK-NEXT:   [[RES:%.*]] = apply [[FR]]([[VALUE_COPY]], [[BORROWED_THIS_COPY]])
+  // CHECK-NEXT:   end_borrow [[BORROWED_THIS_COPY]] from [[THIS_COPY]]
+  // CHECK-NEXT:   destroy_value [[THIS_COPY]]
+  // CHECK-NEXT:   return [[RES]]
+
+  // CHECK-LABEL: sil hidden @$S11objc_thunks6HoozitC12copyPropertySo5GizmoCvs
+  // CHECK: bb0([[ARG1:%.*]] : @owned $Gizmo, [[SELF:%.*]] : @guaranteed $Hoozit):
+  // CHECK:   [[BORROWED_ARG1:%.*]] = begin_borrow [[ARG1]]
+  // CHECK:   [[ARG1_COPY:%.*]] = copy_value [[BORROWED_ARG1]]
+  // CHECK:   [[ADDR:%.*]] = ref_element_addr [[SELF]] : {{.*}}, #Hoozit.copyProperty
+  // CHECK:   [[WRITE:%.*]] = begin_access [modify] [dynamic] [[ADDR]] : $*Gizmo
+  // CHECK:   assign [[ARG1_COPY]] to [[WRITE]]
+  // CHECK:   end_access [[WRITE]] : $*Gizmo
+  // CHECK:   end_borrow [[BORROWED_ARG1]] from [[ARG1]]
+  // CHECK:   destroy_value [[ARG1]]
+  // CHECK: } // end sil function '$S11objc_thunks6HoozitC12copyPropertySo5GizmoCvs'
+
+  @objc var roProperty: Gizmo { return self }
+  // -- getter
+  // CHECK-LABEL: sil hidden [thunk] @$S11objc_thunks6HoozitC10roPropertySo5GizmoCvgTo : $@convention(objc_method) (Hoozit) -> @autoreleased Gizmo {
+  // CHECK: bb0([[THIS:%.*]] : @unowned $Hoozit):
+  // CHECK-NEXT:   [[THIS_COPY:%.*]] = copy_value [[THIS]]
+  // CHECK-NEXT:   [[BORROWED_THIS_COPY:%.*]] = begin_borrow [[THIS_COPY]]
+  // CHECK-NEXT:   // function_ref
+  // CHECK-NEXT:   [[NATIVE:%.*]] = function_ref @$S11objc_thunks6HoozitC10roPropertySo5GizmoCvg : $@convention(method) (@guaranteed Hoozit) -> @owned Gizmo
+  // CHECK-NEXT:   [[RES:%.*]] = apply [[NATIVE]]([[BORROWED_THIS_COPY]])
+  // CHECK-NEXT:   end_borrow [[BORROWED_THIS_COPY]] from [[THIS_COPY]]
+  // CHECK-NEXT:   destroy_value [[THIS_COPY]] : $Hoozit
+  // CHECK-NEXT:   return [[RES]] : $Gizmo
+  // CHECK-NEXT: } // end sil function '$S11objc_thunks6HoozitC10roPropertySo5GizmoCvgTo'
+
+  // -- no setter
+  // CHECK-NOT: sil hidden [thunk] @$S11objc_thunks6HoozitC10roPropertySo5GizmoCvsTo
+
+  @objc var rwProperty: Gizmo {
+    get {
+      return self
+    }
+    set {}
+  }
+  // -- getter
+  // CHECK-LABEL: sil hidden [thunk] @$S11objc_thunks6HoozitC10rwPropertySo5GizmoCvgTo : $@convention(objc_method) (Hoozit) -> @autoreleased Gizmo 
+
+  // -- setter
+  // CHECK-LABEL: sil hidden [thunk] @$S11objc_thunks6HoozitC10rwPropertySo5GizmoCvsTo : $@convention(objc_method) (Gizmo, Hoozit) -> () {
+  // CHECK: bb0([[VALUE:%.*]] : @unowned $Gizmo, [[THIS:%.*]] : @unowned $Hoozit):
+  // CHECK-NEXT:   [[VALUE_COPY:%.*]] = copy_value [[VALUE]]
+  // CHECK-NEXT:   [[THIS_COPY:%.*]] = copy_value [[THIS]]
+  // CHECK-NEXT:   [[BORROWED_THIS_COPY:%.*]] = begin_borrow [[THIS_COPY]]
+  // CHECK-NEXT:   // function_ref
+  // CHECK-NEXT:   [[NATIVE:%.*]] = function_ref @$S11objc_thunks6HoozitC10rwPropertySo5GizmoCvs : $@convention(method) (@owned Gizmo, @guaranteed Hoozit) -> ()
+  // CHECK-NEXT:   apply [[NATIVE]]([[VALUE_COPY]], [[BORROWED_THIS_COPY]])
+  // CHECK-NEXT:   end_borrow [[BORROWED_THIS_COPY]] from [[THIS_COPY]]
+  // CHECK-NEXT:   destroy_value [[THIS_COPY]]
+  // CHECK-NEXT:   return
+  // CHECK-NEXT: }
+
+  @objc var copyRWProperty: Gizmo {
+    get {
+      return self
+    }
+    set {}
+  }
+  // -- getter
+  // CHECK-LABEL: sil hidden [thunk] @$S11objc_thunks6HoozitC14copyRWPropertySo5GizmoCvgTo : $@convention(objc_method) (Hoozit) -> @owned Gizmo {
+  // CHECK: bb0([[THIS:%.*]] : @unowned $Hoozit):
+  // CHECK-NEXT:   [[THIS_COPY:%.*]] = copy_value [[THIS]]
+  // CHECK-NEXT:   [[BORROWED_THIS_COPY:%.*]] = begin_borrow [[THIS_COPY]]
+  // CHECK-NEXT:   // function_ref
+  // CHECK-NEXT:   [[NATIVE:%.*]] = function_ref @$S11objc_thunks6HoozitC14copyRWPropertySo5GizmoCvg : $@convention(method) (@guaranteed Hoozit) -> @owned Gizmo
+  // CHECK-NEXT:   [[RES:%.*]] = apply [[NATIVE]]([[BORROWED_THIS_COPY]])
+  // CHECK-NEXT:   end_borrow [[BORROWED_THIS_COPY]] from [[THIS_COPY]]
+  // CHECK-NEXT:   destroy_value [[THIS_COPY]]
+  // CHECK-NOT:    return
+  // CHECK-NEXT:   return [[RES]]
+  // CHECK-NEXT: }
+
+  // -- setter is normal
+  // CHECK-LABEL: sil hidden [thunk] @$S11objc_thunks6HoozitC14copyRWPropertySo5GizmoCvsTo : $@convention(objc_method) (Gizmo, Hoozit) -> () {
+  // CHECK: bb0([[VALUE:%.*]] : @unowned $Gizmo, [[THIS:%.*]] : @unowned $Hoozit):
+  // CHECK-NEXT:   [[VALUE_COPY:%.*]] = copy_value [[VALUE]]
+  // CHECK-NEXT:   [[THIS_COPY:%.*]] = copy_value [[THIS]]
+  // CHECK-NEXT:   [[BORROWED_THIS_COPY:%.*]] = begin_borrow [[THIS_COPY]]
+  // CHECK-NEXT:   // function_ref
+  // CHECK-NEXT:   [[NATIVE:%.*]] = function_ref @$S11objc_thunks6HoozitC14copyRWPropertySo5GizmoCvs : $@convention(method) (@owned Gizmo, @guaranteed Hoozit) -> ()
+  // CHECK-NEXT:   apply [[NATIVE]]([[VALUE_COPY]], [[BORROWED_THIS_COPY]])
+  // CHECK-NEXT:   end_borrow [[BORROWED_THIS_COPY]] from [[THIS_COPY]]
+  // CHECK-NEXT:   destroy_value [[THIS_COPY]]
+  // CHECK-NEXT:   return
+  // CHECK-NEXT: }
+
+  @objc var initProperty: Gizmo
+  // -- getter
+  // CHECK-LABEL: sil hidden [thunk] @$S11objc_thunks6HoozitC12initPropertySo5GizmoCvgTo : $@convention(objc_method) (Hoozit) -> @autoreleased Gizmo {
+  // CHECK: bb0([[THIS:%.*]] : @unowned $Hoozit):
+  // CHECK-NEXT:   [[THIS_COPY:%.*]] = copy_value [[THIS]]
+  // CHECK-NEXT:   [[BORROWED_THIS_COPY:%.*]] = begin_borrow [[THIS_COPY]]
+  // CHECK-NEXT:   // function_ref
+  // CHECK-NEXT:   [[NATIVE:%.*]] = function_ref @$S11objc_thunks6HoozitC12initPropertySo5GizmoCvg : $@convention(method) (@guaranteed Hoozit) -> @owned Gizmo
+  // CHECK-NEXT:   [[RES:%.*]] = apply [[NATIVE]]([[BORROWED_THIS_COPY]])
+  // CHECK-NEXT:   end_borrow [[BORROWED_THIS_COPY]] from [[THIS_COPY]]
+  // CHECK-NEXT:   destroy_value [[THIS_COPY]]
+  // CHECK-NEXT:   return [[RES]]
+  // CHECK-NEXT: }
+
+  // -- setter
+  // CHECK-LABEL: sil hidden [thunk] @$S11objc_thunks6HoozitC12initPropertySo5GizmoCvsTo : $@convention(objc_method) (Gizmo, Hoozit) -> () {
+  // CHECK: bb0([[VALUE:%.*]] : @unowned $Gizmo, [[THIS:%.*]] : @unowned $Hoozit):
+  // CHECK-NEXT:   [[VALUE_COPY:%.*]] = copy_value [[VALUE]]
+  // CHECK-NEXT:   [[THIS_COPY:%.*]] = copy_value [[THIS]]
+  // CHECK-NEXT:   [[BORROWED_THIS_COPY:%.*]] = begin_borrow [[THIS_COPY]]
+  // CHECK-NEXT:   // function_ref
+  // CHECK-NEXT:   [[NATIVE:%.*]] = function_ref @$S11objc_thunks6HoozitC12initPropertySo5GizmoCvs : $@convention(method) (@owned Gizmo, @guaranteed Hoozit) -> ()
+  // CHECK-NEXT:   apply [[NATIVE]]([[VALUE_COPY]], [[BORROWED_THIS_COPY]])
+  // CHECK-NEXT:   end_borrow [[BORROWED_THIS_COPY]] from [[THIS_COPY]]
+  // CHECK-NEXT:   destroy_value [[THIS_COPY]]
+  // CHECK-NEXT:   return
+  // CHECK-NEXT: }
+
+  @objc var propComputed: Gizmo {
+    @objc(initPropComputedGetter) get { return self }
+    @objc(initPropComputedSetter:) set {}
+  }
+  // -- getter
+  // CHECK-LABEL: sil hidden [thunk] @$S11objc_thunks6HoozitC12propComputedSo5GizmoCvgTo : $@convention(objc_method) (Hoozit) -> @autoreleased Gizmo {
+  // CHECK: bb0([[THIS:%.*]] : @unowned $Hoozit):
+  // CHECK-NEXT:   [[THIS_COPY:%.*]] = copy_value [[THIS]]
+  // CHECK-NEXT:   [[BORROWED_THIS_COPY:%.*]] = begin_borrow [[THIS_COPY]]
+  // CHECK-NEXT:   // function_ref
+  // CHECK-NEXT:   [[NATIVE:%.*]] = function_ref @$S11objc_thunks6HoozitC12propComputedSo5GizmoCvg : $@convention(method) (@guaranteed Hoozit) -> @owned Gizmo
+  // CHECK-NEXT:   [[RES:%.*]] = apply [[NATIVE]]([[BORROWED_THIS_COPY]])
+  // CHECK-NEXT:   end_borrow [[BORROWED_THIS_COPY]] from [[THIS_COPY]]
+  // CHECK-NEXT:   destroy_value [[THIS_COPY]]
+  // CHECK-NEXT:   return [[RES]]
+  // CHECK-NEXT: }
+
+  // -- setter
+  // CHECK-LABEL: sil hidden [thunk] @$S11objc_thunks6HoozitC12propComputedSo5GizmoCvsTo : $@convention(objc_method) (Gizmo, Hoozit) -> () {
+  // CHECK: bb0([[VALUE:%.*]] : @unowned $Gizmo, [[THIS:%.*]] : @unowned $Hoozit):
+  // CHECK-NEXT:   [[VALUE_COPY:%.*]] = copy_value [[VALUE]]
+  // CHECK-NEXT:   [[THIS_COPY:%.*]] = copy_value [[THIS]]
+  // CHECK-NEXT:   [[BORROWED_THIS_COPY:%.*]] = begin_borrow [[THIS_COPY]]
+  // CHECK-NEXT:   // function_ref
+  // CHECK-NEXT:   [[NATIVE:%.*]] = function_ref @$S11objc_thunks6HoozitC12propComputedSo5GizmoCvs : $@convention(method) (@owned Gizmo, @guaranteed Hoozit) -> ()
+  // CHECK-NEXT:   apply [[NATIVE]]([[VALUE_COPY]], [[BORROWED_THIS_COPY]])
+  // CHECK-NEXT:   end_borrow [[BORROWED_THIS_COPY]] from [[THIS_COPY]]
+  // CHECK-NEXT:   destroy_value [[THIS_COPY]]
+  // CHECK-NEXT:   return
+  // CHECK-NEXT: }
+
+  // Don't export generics to ObjC yet
+  func generic<T>(_ x: T) {}
+  // CHECK-NOT: sil hidden [thunk] @_TToFC11objc_thunks6Hoozit7generic{{.*}}
+
+  // Constructor.
+  // CHECK-LABEL: sil hidden @$S11objc_thunks6HoozitC7bellsOnACSi_tcfc : $@convention(method) (Int, @owned Hoozit) -> @owned Hoozit {
+  // CHECK: [[SELF_BOX:%[0-9]+]] = alloc_box ${ var Hoozit }
+  // CHECK: [[MARKED_SELF_BOX:%[0-9]+]] = mark_uninitialized [derivedself] [[SELF_BOX]]
+  // CHECK: [[PB_BOX:%.*]] = project_box [[MARKED_SELF_BOX]]
+  // CHECK: [[GIZMO:%[0-9]+]] = upcast [[SELF:%[0-9]+]] : $Hoozit to $Gizmo
+  // CHECK: [[BORROWED_GIZMO:%.*]] = begin_borrow [[GIZMO]]
+  // CHECK: [[CAST_BORROWED_GIZMO:%.*]] = unchecked_ref_cast [[BORROWED_GIZMO]] : $Gizmo to $Hoozit
+  // CHECK: [[SUPERMETHOD:%[0-9]+]] = objc_super_method [[CAST_BORROWED_GIZMO]] : $Hoozit, #Gizmo.init!initializer.1.foreign : (Gizmo.Type) -> (Int) -> Gizmo?, $@convention(objc_method) (Int, @owned Gizmo) -> @owned Optional<Gizmo>
+  // CHECK-NEXT: end_borrow [[BORROWED_GIZMO]] from [[GIZMO]]
+  // CHECK-NEXT: [[SELF_REPLACED:%[0-9]+]] = apply [[SUPERMETHOD]](%0, [[X:%[0-9]+]]) : $@convention(objc_method) (Int, @owned Gizmo) -> @owned Optional<Gizmo>
+  // CHECK-NOT: unconditional_checked_cast downcast [[SELF_REPLACED]] : $Gizmo to $Hoozit
+  // CHECK: unchecked_ref_cast
+  // CHECK: return
+  override init(bellsOn x : Int) {
+    super.init(bellsOn: x)
+    other()
+  }
+
+  // Subscript
+  @objc subscript (i: Int) -> Hoozit {
+  // Getter
+  // CHECK-LABEL: sil hidden [thunk] @$S11objc_thunks6HoozitCyACSicigTo : $@convention(objc_method) (Int, Hoozit) -> @autoreleased Hoozit
+  // CHECK: bb0([[I:%[0-9]+]] : @trivial $Int, [[SELF:%[0-9]+]] : @unowned $Hoozit):
+  // CHECK-NEXT: [[SELF_COPY:%.*]] = copy_value [[SELF]] : $Hoozit
+  // CHECK-NEXT: [[BORROWED_SELF_COPY:%.*]] = begin_borrow [[SELF_COPY]]
+  // CHECK-NEXT: // function_ref
+  // CHECK-NEXT: [[NATIVE:%[0-9]+]] = function_ref @$S11objc_thunks6HoozitCyACSicig : $@convention(method) (Int, @guaranteed Hoozit) -> @owned Hoozit
+  // CHECK-NEXT: [[RESULT:%[0-9]+]] = apply [[NATIVE]]([[I]], [[BORROWED_SELF_COPY]]) : $@convention(method) (Int, @guaranteed Hoozit) -> @owned Hoozit
+  // CHECK-NEXT: end_borrow [[BORROWED_SELF_COPY]] from [[SELF_COPY]]
+  // CHECK-NEXT: destroy_value [[SELF_COPY]]
+  // CHECK-NEXT: return [[RESULT]] : $Hoozit
+  get {
+    return self
+  }
+
+  // Setter
+  // CHECK-LABEL: sil hidden [thunk] @$S11objc_thunks6HoozitCyACSicisTo : $@convention(objc_method) (Hoozit, Int, Hoozit) -> ()
+  // CHECK: bb0([[VALUE:%[0-9]+]] : @unowned $Hoozit, [[I:%[0-9]+]] : @trivial $Int, [[SELF:%[0-9]+]] : @unowned $Hoozit):
+  // CHECK:   [[VALUE_COPY:%.*]] = copy_value [[VALUE]] : $Hoozit
+  // CHECK:   [[SELF_COPY:%.*]] = copy_value [[SELF]] : $Hoozit
+  // CHECK:   [[BORROWED_SELF_COPY:%.*]] = begin_borrow [[SELF_COPY]]
+  // CHECK:   [[NATIVE:%[0-9]+]] = function_ref @$S11objc_thunks6HoozitCyACSicis : $@convention(method) (@owned Hoozit, Int, @guaranteed Hoozit) -> ()
+  // CHECK:   [[RESULT:%[0-9]+]] = apply [[NATIVE]]([[VALUE_COPY]], [[I]], [[BORROWED_SELF_COPY]]) : $@convention(method) (@owned Hoozit, Int, @guaranteed Hoozit) -> ()
+  // CHECK:   end_borrow [[BORROWED_SELF_COPY]] from [[SELF_COPY]]
+  // CHECK:   destroy_value [[SELF_COPY]]
+  // CHECK:   return [[RESULT]] : $()
+  // CHECK: } // end sil function '$S11objc_thunks6HoozitCyACSicisTo'
+  set {}
+  }
+}
+
+class Wotsit<T> : Gizmo {
+  // CHECK-LABEL: sil hidden [thunk] @$S11objc_thunks6WotsitC5plainyyFTo : $@convention(objc_method) <T> (Wotsit<T>) -> () {
+  // CHECK: bb0([[SELF:%.*]] : @unowned $Wotsit<T>):
+  // CHECK-NEXT: [[SELF_COPY:%.*]] = copy_value [[SELF]] : $Wotsit<T>
+  // CHECK-NEXT: [[BORROWED_SELF_COPY:%.*]] = begin_borrow [[SELF_COPY]]
+  // CHECK-NEXT: // function_ref
+  // CHECK-NEXT: [[NATIVE:%.*]] = function_ref @$S11objc_thunks6WotsitC5plainyyF : $@convention(method) <τ_0_0> (@guaranteed Wotsit<τ_0_0>) -> ()
+  // CHECK-NEXT: [[RESULT:%.*]] = apply [[NATIVE]]<T>([[BORROWED_SELF_COPY]]) : $@convention(method) <τ_0_0> (@guaranteed Wotsit<τ_0_0>) -> ()
+  // CHECK-NEXT: end_borrow [[BORROWED_SELF_COPY]] from [[SELF_COPY]]
+  // CHECK-NEXT: destroy_value [[SELF_COPY]] : $Wotsit<T>
+  // CHECK-NEXT: return [[RESULT]] : $()
+  // CHECK-NEXT: }
+  @objc func plain() { }
+
+  func generic<U>(_ x: U) {}
+
+  var property : T
+
+  init(t: T) {
+    self.property = t
+    super.init()
+  }
+
+  // CHECK-LABEL: sil hidden [thunk] @$S11objc_thunks6WotsitC11descriptionSSvgTo : $@convention(objc_method) <T> (Wotsit<T>) -> @autoreleased NSString {
+  // CHECK: bb0([[SELF:%.*]] : @unowned $Wotsit<T>):
+  // CHECK-NEXT:   [[SELF_COPY:%.*]] = copy_value [[SELF]] : $Wotsit<T>
+  // CHECK-NEXT:   [[BORROWED_SELF_COPY:%.*]] = begin_borrow [[SELF_COPY]]
+  // CHECK-NEXT:   // function_ref
+  // CHECK-NEXT:   [[NATIVE:%.*]] = function_ref @$S11objc_thunks6WotsitC11descriptionSSvg : $@convention(method) <τ_0_0> (@guaranteed Wotsit<τ_0_0>) -> @owned String
+  // CHECK-NEXT:   [[RESULT:%.*]] = apply [[NATIVE:%.*]]<T>([[BORROWED_SELF_COPY]]) : $@convention(method) <τ_0_0> (@guaranteed Wotsit<τ_0_0>) -> @owned String
+  // CHECK-NEXT:   end_borrow [[BORROWED_SELF_COPY]] from [[SELF_COPY]]
+  // CHECK-NEXT:   destroy_value [[SELF_COPY]] : $Wotsit<T>
+  // CHECK-NEXT:   // function_ref
+  // CHECK-NEXT:   [[BRIDGE:%.*]] = function_ref @$SSS10FoundationE19_bridgeToObjectiveCSo8NSStringCyF
+  // CHECK-NEXT:   [[BORROWED_RESULT:%.*]] = begin_borrow [[RESULT]]
+  // CHECK-NEXT:   [[NSRESULT:%.*]] = apply [[BRIDGE]]([[BORROWED_RESULT]]) : $@convention(method) (@guaranteed String) -> @owned NSString
+  // CHECK-NEXT:   end_borrow [[BORROWED_RESULT]] from [[RESULT]]
+  // CHECK-NEXT:   destroy_value [[RESULT]]
+  // CHECK-NEXT:   return [[NSRESULT]] : $NSString
+  // CHECK-NEXT: }
+  override var description : String {
+    return "Hello, world."
+  }
+
+  // Ivar destroyer
+  // CHECK: sil hidden @$S11objc_thunks6WotsitCfETo
+
+  // CHECK-LABEL: sil hidden [thunk] @$S11objc_thunks6WotsitCACyxGSgycfcTo : $@convention(objc_method) <T> (@owned Wotsit<T>) -> @owned Optional<Wotsit<T>>
+
+  // CHECK-LABEL: sil hidden [thunk] @$S11objc_thunks6WotsitC7bellsOnACyxGSgSi_tcfcTo : $@convention(objc_method) <T> (Int, @owned Wotsit<T>) -> @owned Optional<Wotsit<T>>
+}
+
+// CHECK-NOT: sil hidden [thunk] @_TToF{{.*}}Wotsit{{.*}}
+
+// Extension initializers, properties and methods need thunks too.
+extension Hoozit {
+  // CHECK-LABEL: sil hidden [thunk] @$S11objc_thunks6HoozitC3intACSi_tcfcTo : $@convention(objc_method) (Int, @owned Hoozit) -> @owned Hoozit
+  @objc dynamic convenience init(int i: Int) { self.init(bellsOn: i) }
+
+  // CHECK-LABEL: sil hidden @$S11objc_thunks6HoozitC6doubleACSd_tcfc : $@convention(method) (Double, @owned Hoozit) -> @owned Hoozit
+  convenience init(double d: Double) { 
+    // CHECK: [[SELF_BOX:%[0-9]+]] = alloc_box ${ var Hoozit }
+    // CHECK: [[MARKED_SELF_BOX:%[0-9]+]] = mark_uninitialized [delegatingself] [[SELF_BOX]]
+    // CHECK: [[PB_BOX:%.*]] = project_box [[MARKED_SELF_BOX]]
+    // CHECK: [[X_BOX:%[0-9]+]] = alloc_box ${ var X }
+    var x = X()
+    // CHECK: [[CTOR:%[0-9]+]] = objc_method [[SELF:%[0-9]+]] : $Hoozit, #Hoozit.init!initializer.1.foreign : (Hoozit.Type) -> (Int) -> Hoozit, $@convention(objc_method) (Int, @owned Hoozit) -> @owned Hoozit
+    // CHECK: [[NEW_SELF:%[0-9]+]] = apply [[CTOR]]
+    // CHECK: store [[NEW_SELF]] to [init] [[PB_BOX]] : $*Hoozit
+    // CHECK: return
+    self.init(int:Int(d))
+    other()
+  }
+
+  func foof() {}
+  // CHECK-LABEL: sil hidden [thunk] @$S11objc_thunks6HoozitC4foofyyFTo : $@convention(objc_method) (Hoozit) -> () {
+
+  var extensionProperty: Int { return 0 }
+  // CHECK-LABEL: sil hidden @$S11objc_thunks6HoozitC17extensionPropertySivg : $@convention(method) (@guaranteed Hoozit) -> Int
+}
+
+// Calling objc methods of subclass should go through native entry points
+func useHoozit(_ h: Hoozit) {
+// sil @$S11objc_thunks9useHoozit1hyAA0D0C_tF
+  // In the class decl, overrides importd method, 'dynamic' was inferred
+  h.fork()
+  // CHECK: objc_method {{%.*}} : {{.*}}, #Hoozit.fork!1.foreign
+
+  // In an extension, 'dynamic' was inferred.
+  h.foof()
+  // CHECK: objc_method {{%.*}} : {{.*}}, #Hoozit.foof!1.foreign
+}
+
+func useWotsit(_ w: Wotsit<String>) {
+// sil @$S11objc_thunks9useWotsit1wySo0D0CySSG_tF
+  w.plain()
+  // CHECK: class_method {{%.*}} : {{.*}}, #Wotsit.plain!1 :
+  w.generic(2)
+  // CHECK: class_method {{%.*}} : {{.*}}, #Wotsit.generic!1 :
+
+  // Inherited methods only have objc entry points
+  w.clone()
+  // CHECK: objc_method {{%.*}} : {{.*}}, #Gizmo.clone!1.foreign
+}
+
+func other() { }
+
+class X { }
+
+// CHECK-LABEL: sil hidden @$S11objc_thunks8propertyySiSo5GizmoCF
+func property(_ g: Gizmo) -> Int {
+  // CHECK: bb0([[ARG:%.*]] : @guaranteed $Gizmo):
+  // CHECK:   objc_method [[ARG]] : $Gizmo, #Gizmo.count!getter.1.foreign
+  return g.count
+}
+
+// CHECK-LABEL: sil hidden @$S11objc_thunks13blockPropertyyySo5GizmoCF
+func blockProperty(_ g: Gizmo) {
+  // CHECK: bb0([[ARG:%.*]] : @guaranteed $Gizmo):
+  // CHECK:   objc_method [[ARG]] : $Gizmo, #Gizmo.block!setter.1.foreign
+  g.block = { }
+  // CHECK:   objc_method [[ARG]] : $Gizmo, #Gizmo.block!getter.1.foreign
+  g.block()
+}
+
+class DesignatedStubs : Gizmo {
+  var i: Int
+
+  override init() { i = 5 }
+
+  // CHECK-LABEL: sil hidden @$S11objc_thunks15DesignatedStubsC7bellsOnACSgSi_tcfc
+  // CHECK: string_literal utf8 "objc_thunks.DesignatedStubs"
+  // CHECK: string_literal utf8 "init(bellsOn:)"
+  // CHECK: string_literal utf8 "{{.*}}objc_thunks.swift"
+  // CHECK: function_ref @$Ss25_unimplementedInitializer9className04initD04file4line6columns5NeverOs12StaticStringV_A2JS2utF
+  // CHECK: return
+
+  // CHECK-NOT: sil hidden @_TFCSo15DesignatedStubsc{{.*}}
+}
+
+class DesignatedOverrides : Gizmo {
+  var i: Int = 5
+
+  // CHECK-LABEL: sil hidden @$S11objc_thunks19DesignatedOverridesCACSgycfc
+  // CHECK-NOT: return
+  // CHECK: function_ref @$S11objc_thunks19DesignatedOverridesC1iSivpfi : $@convention(thin) () -> Int
+  // CHECK: objc_super_method [[SELF:%[0-9]+]] : $DesignatedOverrides, #Gizmo.init!initializer.1.foreign : (Gizmo.Type) -> () -> Gizmo?, $@convention(objc_method) (@owned Gizmo) -> @owned Optional<Gizmo>
+  // CHECK: return
+
+  // CHECK-LABEL: sil hidden @$S11objc_thunks19DesignatedOverridesC7bellsOnACSgSi_tcfc
+  // CHECK: function_ref @$S11objc_thunks19DesignatedOverridesC1iSivpfi : $@convention(thin) () -> Int
+  // CHECK: objc_super_method [[SELF:%[0-9]+]] : $DesignatedOverrides, #Gizmo.init!initializer.1.foreign : (Gizmo.Type) -> (Int) -> Gizmo?, $@convention(objc_method) (Int, @owned Gizmo) -> @owned Optional<Gizmo>
+  // CHECK: return
+}
+
+// Make sure we copy blocks passed in as IUOs - <rdar://problem/22471309>
+
+func registerAnsible() {
+  // CHECK: function_ref @$S11objc_thunks15registerAnsibleyyFyyycSgcfU_
+  Ansible.anseAsync({ completion in completion!() })
+}
diff --git a/test/SILGen/plus_zero_opaque_ownership.swift b/test/SILGen/plus_zero_opaque_ownership.swift
new file mode 100644
index 0000000..622ffaf
--- /dev/null
+++ b/test/SILGen/plus_zero_opaque_ownership.swift
@@ -0,0 +1,257 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -enable-sil-opaque-values -enable-sil-ownership -emit-sorted-sil -Xllvm -sil-full-demangle -emit-silgen -parse-stdlib -parse-as-library -module-name Swift %s | %FileCheck %s
+// RUN: %target-swift-frontend -target x86_64-apple-macosx10.9 -enable-sil-opaque-values -enable-sil-ownership -emit-sorted-sil -Xllvm -sil-full-demangle -emit-silgen -parse-stdlib -parse-as-library -module-name Swift %s | %FileCheck --check-prefix=CHECK-OSX %s
+
+public typealias AnyObject = Builtin.AnyObject
+
+precedencegroup AssignmentPrecedence {}
+precedencegroup CastingPrecedence {}
+precedencegroup ComparisonPrecedence {}
+
+public protocol _ObjectiveCBridgeable {}
+
+public protocol UnkeyedDecodingContainer {
+  var isAtEnd: Builtin.Int1 { get }
+}
+
+public protocol Decoder {
+  func unkeyedContainer() throws -> UnkeyedDecodingContainer
+}
+
+// Test open_existential_value ownership
+// ---
+// CHECK-LABEL: sil @$Ss11takeDecoder4fromBi1_s0B0_p_tKF : $@convention(thin) (@in_guaranteed Decoder) -> (Builtin.Int1, @error Error) {
+// CHECK: bb0(%0 : @guaranteed $Decoder):
+// CHECK:  [[OPENED:%.*]] = open_existential_value %0 : $Decoder to $@opened("{{.*}}") Decoder
+// CHECK:  [[WT:%.*]] = witness_method $@opened("{{.*}}") Decoder, #Decoder.unkeyedContainer!1 : <Self where Self : Decoder> (Self) -> () throws -> UnkeyedDecodingContainer, %3 : $@opened("{{.*}}") Decoder : $@convention(witness_method: Decoder) <τ_0_0 where τ_0_0 : Decoder> (@in_guaranteed τ_0_0) -> (@out UnkeyedDecodingContainer, @error Error)
+// CHECK:  try_apply [[WT]]<@opened("{{.*}}") Decoder>([[OPENED]]) : $@convention(witness_method: Decoder) <τ_0_0 where τ_0_0 : Decoder> (@in_guaranteed τ_0_0) -> (@out UnkeyedDecodingContainer, @error Error), normal bb2, error bb1
+//
+// CHECK:bb{{.*}}([[RET1:%.*]] : @owned $UnkeyedDecodingContainer):
+// CHECK:  [[BORROW2:%.*]] = begin_borrow [[RET1]] : $UnkeyedDecodingContainer
+// CHECK:  [[OPENED2:%.*]] = open_existential_value [[BORROW2]] : $UnkeyedDecodingContainer to $@opened("{{.*}}") UnkeyedDecodingContainer
+// CHECK:  [[WT2:%.*]] = witness_method $@opened("{{.*}}") UnkeyedDecodingContainer, #UnkeyedDecodingContainer.isAtEnd!getter.1 : <Self where Self : UnkeyedDecodingContainer> (Self) -> () -> Builtin.Int1, [[OPENED2]] : $@opened("{{.*}}") UnkeyedDecodingContainer : $@convention(witness_method: UnkeyedDecodingContainer) <τ_0_0 where τ_0_0 : UnkeyedDecodingContainer> (@in_guaranteed τ_0_0) -> Builtin.Int1
+// CHECK:  [[RET2:%.*]] = apply [[WT2]]<@opened("{{.*}}") UnkeyedDecodingContainer>([[OPENED2]]) : $@convention(witness_method: UnkeyedDecodingContainer) <τ_0_0 where τ_0_0 : UnkeyedDecodingContainer> (@in_guaranteed τ_0_0) -> Builtin.Int1
+// CHECK:  end_borrow [[BORROW2]] from [[RET1]] : $UnkeyedDecodingContainer, $UnkeyedDecodingContainer
+// CHECK:  destroy_value [[RET1]] : $UnkeyedDecodingContainer
+// CHECK-NOT:  destroy_value %0 : $Decoder
+// CHECK:  return [[RET2]] : $Builtin.Int1
+// CHECK-LABEL: } // end sil function '$Ss11takeDecoder4fromBi1_s0B0_p_tKF'
+public func takeDecoder(from decoder: Decoder) throws -> Builtin.Int1 {
+  let container = try decoder.unkeyedContainer()
+  return container.isAtEnd
+}
+
+// Test unsafe_bitwise_cast nontrivial ownership.
+// ---
+// CHECK-LABEL: sil @$Ss13unsafeBitCast_2toq_x_q_mtr0_lF : $@convention(thin) <T, U> (@in_guaranteed T, @thick U.Type) -> @out U {
+// CHECK: bb0([[ARG0:%.*]] : @guaranteed $T, [[ARG1:%.*]] : @trivial $@thick U.Type):
+// CHECK:   [[RESULT:%.*]] = unchecked_bitwise_cast [[ARG0]] : $T to $U
+// CHECK:   [[RESULT_COPY:%.*]] = copy_value [[RESULT]] : $U
+// CHECK:   return [[RESULT_COPY]] : $U
+// CHECK-LABEL: } // end sil function '$Ss13unsafeBitCast_2toq_x_q_mtr0_lF'
+public func unsafeBitCast<T, U>(_ x: T, to type: U.Type) -> U {
+  return Builtin.reinterpretCast(x)
+}
+
+// A lot of standard library support is necessary to support raw enums.
+// --------------------------------------------------------------------
+
+infix operator  == : ComparisonPrecedence
+infix operator  ~= : ComparisonPrecedence
+
+public struct Bool {
+  var _value: Builtin.Int1
+
+  public init() {
+    let zero: Int64 = 0
+    self._value = Builtin.trunc_Int64_Int1(zero._value)
+  }
+
+  internal init(_ v: Builtin.Int1) { self._value = v }
+
+  public init(_ value: Bool) {
+    self = value
+  }
+}
+
+extension Bool {
+  public func _getBuiltinLogicValue() -> Builtin.Int1 {
+    return _value
+  }
+}
+
+public protocol Equatable {
+  /// Returns a Boolean value indicating whether two values are equal.
+  ///
+  /// Equality is the inverse of inequality. For any values `a` and `b`,
+  /// `a == b` implies that `a != b` is `false`.
+  ///
+  /// - Parameters:
+  ///   - lhs: A value to compare.
+  ///   - rhs: Another value to compare.
+  static func == (lhs: Self, rhs: Self) -> Bool
+}
+
+public func ~= <T : Equatable>(a: T, b: T) -> Bool {
+  return a == b
+}
+
+public protocol RawRepresentable {
+  associatedtype RawValue
+
+  init?(rawValue: RawValue)
+
+  var rawValue: RawValue { get }
+}
+
+public func == <T : RawRepresentable>(lhs: T, rhs: T) -> Bool
+  where T.RawValue : Equatable {
+  return lhs.rawValue == rhs.rawValue
+}
+
+public typealias _MaxBuiltinIntegerType = Builtin.Int2048
+
+public protocol _ExpressibleByBuiltinIntegerLiteral {
+  init(_builtinIntegerLiteral value: _MaxBuiltinIntegerType)
+}
+
+public protocol ExpressibleByIntegerLiteral {
+  associatedtype IntegerLiteralType : _ExpressibleByBuiltinIntegerLiteral
+
+  init(integerLiteral value: IntegerLiteralType)
+}
+
+extension ExpressibleByIntegerLiteral
+  where Self : _ExpressibleByBuiltinIntegerLiteral {
+  @_transparent
+  public init(integerLiteral value: Self) {
+    self = value
+  }
+}
+
+public protocol ExpressibleByStringLiteral {}
+public protocol ExpressibleByFloatLiteral {}
+public protocol ExpressibleByUnicodeScalarLiteral {}
+public protocol ExpressibleByExtendedGraphemeClusterLiteral {}
+
+public struct Int64 : ExpressibleByIntegerLiteral, _ExpressibleByBuiltinIntegerLiteral, Equatable {
+  public var _value: Builtin.Int64
+  public init(_builtinIntegerLiteral x: _MaxBuiltinIntegerType) {
+    _value = Builtin.s_to_s_checked_trunc_Int2048_Int64(x).0
+  }
+  public typealias IntegerLiteralType = Int64
+  public init(integerLiteral value: Int64) {
+    self = value
+  }
+  public static func ==(_ lhs: Int64, rhs: Int64) -> Bool {
+    return Bool(Builtin.cmp_eq_Int64(lhs._value, rhs._value))
+  }
+}
+
+// Test ownership of multi-case Enum values in the context of @trivial to @in thunks.
+// ---
+// CHECK-LABEL: sil shared [transparent] [serialized] [thunk] @$Ss17FloatingPointSignOs9EquatablessACP2eeoiySbx_xtFZTW : $@convention(witness_method: Equatable) (@in_guaranteed FloatingPointSign, @in_guaranteed FloatingPointSign, @thick FloatingPointSign.Type) -> Bool {
+// CHECK: bb0(%0 : @trivial $FloatingPointSign, %1 : @trivial $FloatingPointSign, %2 : @trivial $@thick FloatingPointSign.Type):
+// CHECK:   %3 = function_ref @$Ss2eeoiySbx_xts16RawRepresentableRzs9Equatable0B5ValueRpzlF : $@convention(thin) <τ_0_0 where τ_0_0 : RawRepresentable, τ_0_0.RawValue : Equatable> (@in_guaranteed τ_0_0, @in_guaranteed τ_0_0) -> Bool
+// CHECK:   %4 = apply %3<FloatingPointSign, Int64>(%0, %1) : $@convention(thin) <τ_0_0 where τ_0_0 : RawRepresentable, τ_0_0.RawValue : Equatable> (@in_guaranteed τ_0_0, @in_guaranteed τ_0_0) -> Bool
+// CHECK:   return %4 : $Bool
+// CHECK-LABEL: } // end sil function '$Ss17FloatingPointSignOs9EquatablessACP2eeoiySbx_xtFZTW'
+public enum FloatingPointSign: Int64 {
+  /// The sign for a positive value.
+  case plus
+
+  /// The sign for a negative value.
+  case minus
+}
+
+#if os(OSX)
+// Test open_existential_value used in a conversion context.
+// (the actual bridging call is dropped because we don't import Swift).
+// ---
+// CHECK-OSX-LABEL: sil @$Ss26_unsafeDowncastToAnyObject04fromD0yXlyp_tF : $@convention(thin) (@in_guaranteed Any) -> @owned AnyObject {
+// CHECK-OSX: bb0(%0 : @guaranteed $Any):
+// CHECK-OSX:   [[COPY:%.*]] = copy_value %0 : $Any
+// CHECK-OSX:   [[BORROW2:%.*]] = begin_borrow [[COPY]] : $Any
+// CHECK-OSX:   [[VAL:%.*]] = open_existential_value [[BORROW2]] : $Any to $@opened
+// CHECK-OSX:   [[COPY2:%.*]] = copy_value [[VAL]] : $@opened
+// CHECK-OSX:   destroy_value [[COPY2]] : $@opened
+// CHECK-OSX:   end_borrow [[BORROW2]] from [[COPY]] : $Any, $Any
+// CHECK-OSX:   destroy_value [[COPY]] : $Any
+// CHECK-OSX-NOT:   destroy_value %0 : $Any
+// CHECK-OSX:   return undef : $AnyObject
+// CHECK-OSX-LABEL: } // end sil function '$Ss26_unsafeDowncastToAnyObject04fromD0yXlyp_tF'
+public func _unsafeDowncastToAnyObject(fromAny any: Any) -> AnyObject {
+  return any as AnyObject
+}
+#endif
+
+public protocol Error {}
+
+#if os(OSX)
+// Test open_existential_box_value in a conversion context.
+// ---
+// CHECK-OSX-LABEL: sil @$Ss3foo1eys5Error_pSg_tF : $@convention(thin) (@guaranteed Optional<Error>) -> () {
+// CHECK-OSX: [[BORROW:%.*]] = begin_borrow %{{.*}} : $Error
+// CHECK-OSX: [[VAL:%.*]] = open_existential_box_value [[BORROW]] : $Error to $@opened
+// CHECK-OSX: [[COPY:%.*]] = copy_value [[VAL]] : $@opened
+// CHECK-OSX: [[ANY:%.*]] = init_existential_value [[COPY]] : $@opened
+// CHECK-OSX: end_borrow [[BORROW]] from %{{.*}} : $Error, $Error
+// CHECK-OSX-LABEL: } // end sil function '$Ss3foo1eys5Error_pSg_tF'
+public func foo(e: Error?) {
+  if let u = e {
+    let a: Any = u
+    _ = a
+  }
+}
+#endif
+
+public enum Optional<Wrapped> {
+  case none
+  case some(Wrapped)
+}
+
+public protocol IP {}
+
+public protocol Seq {
+  associatedtype Iterator : IP
+
+  func makeIterator() -> Iterator
+}
+
+extension Seq where Self.Iterator == Self {
+  public func makeIterator() -> Self {
+    return self
+  }
+}
+
+public struct EnumIter<Base : IP> : IP, Seq {
+  internal var _base: Base
+
+  public typealias Iterator = EnumIter<Base>
+}
+
+// Test passing a +1 RValue to @in_guaranteed.
+// ---
+// CHECK-LABEL: sil @$Ss7EnumSeqV12makeIterators0A4IterVy0D0QzGyF : $@convention(method) <Base where Base : Seq> (@in_guaranteed EnumSeq<Base>) -> @out EnumIter<Base.Iterator> {
+// CHECK: bb0(%0 : @guaranteed $EnumSeq<Base>):
+// CHECK:  [[MT:%.*]] = metatype $@thin EnumIter<Base.Iterator>.Type
+// CHECK:  [[FIELD:%.*]] = struct_extract %0 : $EnumSeq<Base>, #EnumSeq._base
+// CHECK:  [[COPY:%.*]] = copy_value [[FIELD]] : $Base
+// CHECK:  [[BORROW:%.*]] = begin_borrow [[COPY]] : $Base
+// CHECK:  [[WT:%.*]] = witness_method $Base, #Seq.makeIterator!1 : <Self where Self : Seq> (Self) -> () -> Self.Iterator : $@convention(witness_method: Seq) <τ_0_0 where τ_0_0 : Seq> (@in_guaranteed τ_0_0) -> @out τ_0_0.Iterator
+// CHECK:  [[ITER:%.*]] = apply [[WT]]<Base>([[BORROW]]) : $@convention(witness_method: Seq) <τ_0_0 where τ_0_0 : Seq> (@in_guaranteed τ_0_0) -> @out τ_0_0.Iterator
+// CHECK:  end_borrow [[BORROW]] from [[COPY]] : $Base, $Base
+// CHECK:  destroy_value [[COPY]] : $Base
+// CHECK: [[FN:%.*]] = function_ref @$Ss8EnumIterV5_baseAByxGx_tcfC : $@convention(method) <τ_0_0 where τ_0_0 : IP> (@in τ_0_0, @thin EnumIter<τ_0_0>.Type) -> @out EnumIter<τ_0_0>
+// CHECK:  [[RET:%.*]] = apply [[FN]]<Base.Iterator>([[ITER]], [[MT]]) : $@convention(method) <τ_0_0 where τ_0_0 : IP> (@in τ_0_0, @thin EnumIter<τ_0_0>.Type) -> @out EnumIter<τ_0_0>
+// CHECK:  return [[RET]] : $EnumIter<Base.Iterator>
+// CHECK-LABEL: } // end sil function '$Ss7EnumSeqV12makeIterators0A4IterVy0D0QzGyF'
+public struct EnumSeq<Base : Seq> : Seq {
+  public typealias Iterator = EnumIter<Base.Iterator>
+
+  internal var _base: Base
+
+  public func makeIterator() -> Iterator {
+    return EnumIter(_base: _base.makeIterator())
+  }
+}
diff --git a/test/SILGen/plus_zero_opaque_values_silgen.swift b/test/SILGen/plus_zero_opaque_values_silgen.swift
new file mode 100644
index 0000000..1c7f8f7
--- /dev/null
+++ b/test/SILGen/plus_zero_opaque_values_silgen.swift
@@ -0,0 +1,1236 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -enable-sil-opaque-values -emit-sorted-sil -Xllvm -sil-full-demangle -emit-silgen %s | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%target-runtime
+
+// UNSUPPORTED: resilient_stdlib
+
+struct TrivialStruct {
+  var x: Int
+}
+
+protocol Foo {
+  func foo()
+}
+
+protocol P {
+  var x : Int { get }
+}
+
+protocol P2 : P {}
+
+extension TrivialStruct : P2 {}
+
+struct Box<T> {
+  let t: T
+}
+
+protocol EmptyP {}
+
+struct AddressOnlyStruct : EmptyP {}
+
+struct AnyStruct {
+  let a: Any
+}
+
+protocol Clonable {
+  func maybeClone() -> Self?
+}
+
+indirect enum IndirectEnum<T> {
+  case Nil
+  case Node(T)
+}
+
+protocol SubscriptableGet {
+  subscript(a : Int) -> Int { get }
+}
+
+protocol SubscriptableGetSet {
+  subscript(a : Int) -> Int { get set }
+}
+
+var subscriptableGet : SubscriptableGet
+var subscriptableGetSet : SubscriptableGetSet
+
+class OpaqueClass<T> {
+  typealias ObnoxiousTuple = (T, (T.Type, (T) -> T))
+
+  func inAndOut(x: T) -> T { return x }
+  func variantOptionalityTuples(x: ObnoxiousTuple) -> ObnoxiousTuple? { return x }
+}
+
+class StillOpaqueClass<T>: OpaqueClass<T> {
+  override func variantOptionalityTuples(x: ObnoxiousTuple?) -> ObnoxiousTuple { return x! }
+}
+
+class OpaqueTupleClass<U>: OpaqueClass<(U, U)> {
+  override func inAndOut(x: (U, U)) -> (U, U) { return x }
+}
+
+func unreachableF<T>() -> (Int, T)? { }
+
+func s010_hasVarArg(_ args: Any...) {}
+
+// Tests Address only enums's construction
+// CHECK-LABEL: sil shared [transparent] @$S20opaque_values_silgen15AddressOnlyEnumO4mereyAcA6EmptyP_pcACmF : $@convention(method) (@in EmptyP, @thin AddressOnlyEnum.Type) -> @out AddressOnlyEnum {
+// CHECK: bb0([[ARG0:%.*]] : $EmptyP, [[ARG1:%.*]] : $@thin AddressOnlyEnum.Type):
+// CHECK:   [[RETVAL:%.*]] = enum $AddressOnlyEnum, #AddressOnlyEnum.mere!enumelt.1, [[ARG0]] : $EmptyP
+// CHECK:   return [[RETVAL]] : $AddressOnlyEnum
+// CHECK-LABEL: } // end sil function '$S20opaque_values_silgen15AddressOnlyEnumO4mereyAcA6EmptyP_pcACmF'
+
+// CHECK-LABEL: sil shared [transparent] [thunk] @$S20opaque_values_silgen15AddressOnlyEnumO4mereyAcA6EmptyP_pcACmFTc : $@convention(thin) (@thin AddressOnlyEnum.Type) -> @owned @callee_guaranteed (@in_guaranteed EmptyP) -> @out AddressOnlyEnum {
+// CHECK: bb0([[ARG:%.*]] : $@thin AddressOnlyEnum.Type):
+// CHECK:   [[RETVAL:%.*]] = partial_apply {{.*}}([[ARG]]) : $@convention(method) (@in EmptyP, @thin AddressOnlyEnum.Type) -> @out AddressOnlyEnum
+// CHECK:   [[CANONICAL_THUNK_FN:%.*]] = function_ref @$S20opaque_values_silgen6EmptyP_pAA15AddressOnlyEnumOIegir_AaB_pADIegnr_TR : $@convention(thin) (@in_guaranteed EmptyP, @guaranteed @callee_guaranteed (@in EmptyP) -> @out AddressOnlyEnum) -> @out AddressOnlyEnum
+// CHECK:   [[CANONICAL_THUNK:%.*]] = partial_apply [callee_guaranteed] [[CANONICAL_THUNK_FN]]([[RETVAL]])
+// CHECK:   return [[CANONICAL_THUNK]] : $@callee_guaranteed (@in_guaranteed EmptyP) -> @out AddressOnlyEnum
+// CHECK-LABEL: } // end sil function '$S20opaque_values_silgen15AddressOnlyEnumO4mereyAcA6EmptyP_pcACmFTc'
+enum AddressOnlyEnum {
+  case nought
+  case mere(EmptyP)
+  case phantom(AddressOnlyStruct)
+}
+
+// Test vtables - OpaqueTupleClass
+// ---
+// CHECK-LABEL: sil private @$S20opaque_values_silgen16OpaqueTupleClassC8inAndOut1xx_xtx_xt_tFAA0dF0CAdExx_tFTV : $@convention(method) <U> (@in_guaranteed (U, U), @guaranteed OpaqueTupleClass<U>) -> @out (U, U) {
+// CHECK: bb0([[ARG0:%.*]] : $(U, U), [[ARG1:%.*]] : $OpaqueTupleClass<U>):
+// CHECK:   ([[TELEM0:%.*]], [[TELEM1:%.*]]) = destructure_tuple [[ARG0]] : $(U, U)
+// CHECK:   [[APPLY:%.*]] = apply {{.*}}<U>([[TELEM0]], [[TELEM1]], [[ARG1]]) : $@convention(method) <τ_0_0> (@in_guaranteed τ_0_0, @in_guaranteed τ_0_0, @guaranteed OpaqueTupleClass<τ_0_0>) -> (@out τ_0_0, @out τ_0_0)
+// CHECK:   [[BORROWED_CALL:%.*]] = begin_borrow [[APPLY]]
+// CHECK:   [[BORROWED_CALL_EXT0:%.*]] = tuple_extract [[BORROWED_CALL]] : $(U, U), 0
+// CHECK:   [[RETVAL0:%.*]] = copy_value [[BORROWED_CALL_EXT0]] : $U
+// CHECK:   [[BORROWED_CALL_EXT1:%.*]] = tuple_extract [[BORROWED_CALL]] : $(U, U), 1
+// CHECK:   [[RETVAL1:%.*]] = copy_value [[BORROWED_CALL_EXT1]] : $U
+// CHECK:   end_borrow [[BORROWED_CALL]]
+// CHECK:   [[RETVAL:%.*]] = tuple ([[RETVAL0]] : $U, [[RETVAL1]] : $U)
+// CHECK:   return [[RETVAL]]
+// CHECK-LABEL: } // end sil function '$S20opaque_values_silgen16OpaqueTupleClassC8inAndOut1xx_xtx_xt_tFAA0dF0CAdExx_tFTV'
+
+// Test vtables - StillOpaqueClass
+// ---
+// CHECK-LABEL: sil private @$S20opaque_values_silgen16StillOpaqueClassC24variantOptionalityTuples1xx_xm_xxcttx_xm_xxcttSg_tFAA0eF0CAdeFx_xm_xxctt_tFTV : $@convention(method) <T> (@in_guaranteed T, @thick T.Type, @guaranteed @callee_guaranteed (@in_guaranteed T) -> @out T, @guaranteed StillOpaqueClass<T>) -> @out Optional<(T, (@thick T.Type, @callee_guaranteed (@in_guaranteed T) -> @out T))> {
+// CHECK: bb0([[ARG0:%.*]] : $T, [[ARG1:%.*]] : $@thick T.Type, [[ARG2:%.*]] : $@callee_guaranteed (@in_guaranteed T) -> @out T, [[ARG3:%.*]] : $StillOpaqueClass<T>):
+// CHECK:   [[TELEM0:%.*]] = tuple ([[ARG1]] : $@thick T.Type, [[ARG2]] : $@callee_guaranteed (@in_guaranteed T) -> @out T)
+// CHECK:   [[TELEM1:%.*]] = tuple ([[ARG0]] : $T, [[TELEM0]] : $(@thick T.Type, @callee_guaranteed (@in_guaranteed T) -> @out T))
+// CHECK:   [[ENUMOPT0:%.*]] = enum $Optional<(T, (@thick T.Type, @callee_guaranteed (@in_guaranteed T) -> @out T))>, #Optional.some!enumelt.1, [[TELEM1]] : $(T, (@thick T.Type, @callee_guaranteed (@in_guaranteed T) -> @out T))
+// CHECK:   [[APPLY:%.*]] = apply {{.*}}<T>([[ENUMOPT0]], [[ARG3]]) : $@convention(method) <τ_0_0> (@in_guaranteed Optional<(τ_0_0, (@thick τ_0_0.Type, @callee_guaranteed (@in_guaranteed τ_0_0) -> @out τ_0_0))>, @guaranteed StillOpaqueClass<τ_0_0>) -> (@out τ_0_0, @thick τ_0_0.Type, @owned @callee_guaranteed (@in_guaranteed τ_0_0) -> @out τ_0_0)
+// CHECK:   [[BORROWED_T:%.*]] = begin_borrow [[APPLY]]
+// CHECK:   [[BORROWED_T_EXT0:%.*]] = tuple_extract [[BORROWED_T]] : $(T, @thick T.Type, @callee_guaranteed (@in_guaranteed T) -> @out T), 0
+// CHECK:   [[RETVAL0:%.*]] = copy_value [[BORROWED_T_EXT0]]
+// CHECK:   [[BORROWED_T_EXT1:%.*]] = tuple_extract [[BORROWED_T]] : $(T, @thick T.Type, @callee_guaranteed (@in_guaranteed T) -> @out T), 1
+// CHECK:   [[BORROWED_T_EXT2:%.*]] = tuple_extract [[BORROWED_T]] : $(T, @thick T.Type, @callee_guaranteed (@in_guaranteed T) -> @out T), 2
+// CHECK:   [[RETVAL1:%.*]] = copy_value [[BORROWED_T_EXT2]]
+// CHECK:   end_borrow [[BORROWED_T]]
+// CHECK:   [[RETTUPLE0:%.*]] = tuple ([[BORROWED_T_EXT1]] : $@thick T.Type, [[RETVAL1]] : $@callee_guaranteed (@in_guaranteed T) -> @out T)
+// CHECK:   [[RETTUPLE1:%.*]] = tuple ([[RETVAL0]] : $T, [[RETTUPLE0]] : $(@thick T.Type, @callee_guaranteed (@in_guaranteed T) -> @out T))
+// CHECK:   [[RETVAL:%.*]] = enum $Optional<(T, (@thick T.Type, @callee_guaranteed (@in_guaranteed T) -> @out T))>, #Optional.some!enumelt.1, [[RETTUPLE1]] : $(T, (@thick T.Type, @callee_guaranteed (@in_guaranteed T) -> @out T))
+// CHECK:   return [[RETVAL]]
+// CHECK-LABEL: } // end sil function '$S20opaque_values_silgen16StillOpaqueClassC24variantOptionalityTuples1xx_xm_xxcttx_xm_xxcttSg_tFAA0eF0CAdeFx_xm_xxctt_tFTV'
+
+
+// part of s280_convExistTrivial: conversion between existential types - reabstraction thunk
+// ---
+// CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] @$S20opaque_values_silgen1P_pAA13TrivialStructVIegnd_AA2P2_pAaE_pIegnr_TR : $@convention(thin) (@in_guaranteed P2, @guaranteed @callee_guaranteed (@in_guaranteed P) -> TrivialStruct) -> @out P2 {
+// CHECK: bb0([[ARG0:%.*]] : $P2, [[ARG1:%.*]] : $@callee_guaranteed (@in_guaranteed P) -> TrivialStruct):
+// CHECK:   [[OPENED_ARG:%.*]] = open_existential_value [[ARG]] : $P2 to $@opened({{.*}}) P2
+// CHECK:   [[COPIED_VAL:%.*]] = copy_value [[OPENED_ARG]]
+// CHECK:   [[INIT_P:%.*]] = init_existential_value [[COPIED_VAL]] : $@opened({{.*}}) P2, $@opened({{.*}}) P2, $P
+// CHECK:   [[BORROWED_INIT_P:%.*]] = begin_borrow [[INIT_P]]
+// CHECK:   [[APPLY_P:%.*]] = apply [[ARG1]]([[BORROWED_INIT_P]]) : $@callee_guaranteed (@in_guaranteed P) -> TrivialStruct
+// CHECK:   [[RETVAL:%.*]] = init_existential_value [[APPLY_P]] : $TrivialStruct, $TrivialStruct, $P2
+// CHECK:   end_borrow [[BORROWED_INIT_P]]
+// CHECK-NOT:   destroy_value [[ARG0]]
+// CHECK:   return [[RETVAL]] : $P2
+// CHECK-LABEL: } // end sil function '$S20opaque_values_silgen1P_pAA13TrivialStructVIegnd_AA2P2_pAaE_pIegnr_TR'
+
+// part of s290_convOptExistTriv: conversion between existential types - reabstraction thunk - optionals case
+// ---
+// CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] @$S20opaque_values_silgen1P_pSgAA13TrivialStructVIegnd_AESgAA2P2_pIegyr_TR : $@convention(thin) (Optional<TrivialStruct>, @guaranteed @callee_guaranteed (@in_guaranteed Optional<P>) -> TrivialStruct) -> @out P2 {
+// CHECK: bb0([[ARG0:%.*]] : $Optional<TrivialStruct>, [[ARG1:%.*]] : $@callee_guaranteed (@in_guaranteed Optional<P>) -> TrivialStruct):
+// CHECK:   switch_enum [[ARG0]] : $Optional<TrivialStruct>, case #Optional.some!enumelt.1: bb2, case #Optional.none!enumelt: bb1
+// CHECK: bb1:
+// CHECK:   [[ONONE:%.*]] = enum $Optional<P>, #Optional.none!enumelt
+// CHECK:   br bb3([[ONONE]] : $Optional<P>)
+// CHECK: bb2([[OSOME:%.*]] : $TrivialStruct):
+// CHECK:   [[INIT_S:%.*]] = init_existential_value [[OSOME]] : $TrivialStruct, $TrivialStruct, $P
+// CHECK:   [[ENUM_S:%.*]] = enum $Optional<P>, #Optional.some!enumelt.1, [[INIT_S]] : $P
+// CHECK:   br bb3([[ENUM_S]] : $Optional<P>)
+// CHECK: bb3([[OPT_S:%.*]] : $Optional<P>):
+// CHECK:   [[BORROWED_OPT_S:%.*]] = begin_borrow [[OPT_S]]
+// CHECK:   [[APPLY_P:%.*]] = apply [[ARG1]]([[BORROWED_OPT_S]]) : $@callee_guaranteed (@in_guaranteed Optional<P>) -> TrivialStruct
+// CHECK:   [[RETVAL:%.*]] = init_existential_value [[APPLY_P]] : $TrivialStruct, $TrivialStruct, $P2
+// CHECK:   return [[RETVAL]] : $P2
+// CHECK-LABEL: } // end sil function '$S20opaque_values_silgen1P_pSgAA13TrivialStructVIegnd_AESgAA2P2_pIegyr_TR'
+
+// Test array initialization - we are still (somewhat) using addresses
+// ---
+// CHECK-LABEL: sil @$S20opaque_values_silgen21s020_______callVarArgyyF : $@convention(thin) () -> () {
+// CHECK: %[[APY:.*]] = apply %{{.*}}<Any>(%{{.*}}) : $@convention(thin) <τ_0_0> (Builtin.Word) -> (@owned Array<τ_0_0>, Builtin.RawPointer)
+// CHECK: %[[BRW:.*]] = begin_borrow %[[APY]]
+// CHECK: %[[TPL:.*]] = tuple_extract %[[BRW]] : $(Array<Any>, Builtin.RawPointer), 1
+// CHECK: end_borrow %[[BRW]] from %[[APY]] : $(Array<Any>, Builtin.RawPointer), $(Array<Any>, Builtin.RawPointer)
+// CHECK: destroy_value %[[APY]]
+// CHECK: %[[PTR:.*]] = pointer_to_address %[[TPL]] : $Builtin.RawPointer to [strict] $*Any
+// CHECK: [[IOPAQUE:%.*]] = init_existential_value %{{.*}} : $Int, $Int, $Any
+// CHECK: store [[IOPAQUE]] to [init] %[[PTR]] : $*Any
+// CHECK: return %{{.*}} : $()
+// CHECK-LABEL: } // end sil function '$S20opaque_values_silgen21s020_______callVarArgyyF'
+public func s020_______callVarArg() {
+  s010_hasVarArg(3)
+}
+
+// Test emitSemanticStore.
+// ---
+// CHECK-LABEL: sil hidden @$S20opaque_values_silgen21s030______assigninoutyyxz_xtlF : $@convention(thin) <T> (@inout T, @in_guaranteed T) -> () {
+// CHECK: bb0([[ARG0:%.*]] : $*T, [[ARG1:%.*]] : $T):
+// CHECK:   [[CPY:%.*]] = copy_value [[ARG1]] : $T
+// CHECK:   [[READ:%.*]] = begin_access [modify] [unknown] [[ARG0]] : $*T
+// CHECK:   assign [[CPY]] to [[READ]] : $*T
+// CHECK-NOT:   destroy_value [[ARG1]] : $T
+// CHECK:   return %{{.*}} : $()
+// CHECK-LABEL: } // end sil function '$S20opaque_values_silgen21s030______assigninoutyyxz_xtlF'
+func s030______assigninout<T>(_ a: inout T, _ b: T) {
+  a = b
+}
+
+// Test that we no longer use copy_addr or tuple_element_addr when copy by value is possible
+// ---
+// CHECK-LABEL: sil hidden @$S20opaque_values_silgen21s040___tupleReturnIntyS2i_xt_tlF : $@convention(thin) <T> (Int, @in_guaranteed T) -> Int {
+// CHECK: bb0([[ARG0:%.*]] : $Int, [[ARG1:%.*]] : $T):
+// CHECK:   [[ARG1_COPY:%.*]] = copy_value [[ARG1]]
+// CHECK:   [[TPL:%.*]] = tuple ([[ARG0]] : $Int, [[ARG1_COPY]] : $T)
+// CHECK:   [[BORROWED_ARG1:%.*]] = begin_borrow [[TPL]] : $(Int, T)
+// CHECK:   [[CPY:%.*]] = copy_value [[BORROWED_ARG1]] : $(Int, T)
+// CHECK:   [[BORROWED_CPY:%.*]] = begin_borrow [[CPY]]
+// CHECK:   [[INT:%.*]] = tuple_extract [[BORROWED_CPY]] : $(Int, T), 0
+// CHECK:   [[GEN:%.*]] = tuple_extract [[BORROWED_CPY]] : $(Int, T), 1
+// CHECK:   [[COPY_GEN:%.*]] = copy_value [[GEN]]
+// CHECK:   destroy_value [[COPY_GEN]]
+// CHECK:   end_borrow [[BORROWED_CPY]] from [[CPY]]
+// CHECK:   destroy_value [[CPY]]
+// CHECK:   end_borrow [[BORROWED_ARG1]] from [[TPL]] : $(Int, T), $(Int, T)
+// CHECK:   destroy_value [[TPL]] : $(Int, T)
+// CHECK:   return [[INT]]
+// CHECK-LABEL: } // end sil function '$S20opaque_values_silgen21s040___tupleReturnIntyS2i_xt_tlF'
+func s040___tupleReturnInt<T>(_ x: (Int, T)) -> Int {
+  let y = x.0
+  return y
+}
+
+// Test returning an opaque tuple of tuples.
+// ---
+// CHECK-LABEL: sil hidden [noinline] @$S20opaque_values_silgen21s050______multiResultyx_x_xttxlF : $@convention(thin) <T> (@in_guaranteed T) -> (@out T, @out T, @out T) {
+// CHECK: bb0(%0 : $T):
+// CHECK: %[[CP1:.*]] = copy_value %{{.*}} : $T
+// CHECK: %[[CP2:.*]] = copy_value %{{.*}} : $T
+// CHECK: %[[CP3:.*]] = copy_value %{{.*}} : $T
+// CHECK-NOT: destroy_value %0 : $T
+// CHECK: %[[TPL:.*]] = tuple (%[[CP1]] : $T, %[[CP2]] : $T, %[[CP3]] : $T)
+// CHECK: return %[[TPL]] : $(T, T, T)
+// CHECK-LABEL: } // end sil function '$S20opaque_values_silgen21s050______multiResultyx_x_xttxlF'
+@inline(never)
+func s050______multiResult<T>(_ t: T) -> (T, (T, T)) {
+  return (t, (t, t))
+}
+
+// Test returning an opaque tuple of tuples as a concrete tuple.
+// ---
+// CHECK-LABEL: sil @$S20opaque_values_silgen21s060__callMultiResult1iSi_Si_SittSi_tF : $@convention(thin) (Int) -> (Int, Int, Int) {
+// CHECK: bb0(%0 : $Int):
+// CHECK: %[[FN:.*]] = function_ref @$S20opaque_values_silgen21s050______multiResultyx_x_xttxlF : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> (@out τ_0_0, @out τ_0_0, @out τ_0_0)
+// CHECK: %[[TPL:.*]] = apply %[[FN]]<Int>(%0) : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> (@out τ_0_0, @out τ_0_0, @out τ_0_0)
+// CHECK: %[[I1:.*]] = tuple_extract %[[TPL]] : $(Int, Int, Int), 0
+// CHECK: %[[I2:.*]] = tuple_extract %[[TPL]] : $(Int, Int, Int), 1
+// CHECK: %[[I3:.*]] = tuple_extract %[[TPL]] : $(Int, Int, Int), 2
+// CHECK: %[[R:.*]] = tuple (%[[I1]] : $Int, %[[I2]] : $Int, %[[I3]] : $Int)
+// CHECK: return %[[R]] : $(Int, Int, Int)
+// CHECK-LABEL: } // end sil function '$S20opaque_values_silgen21s060__callMultiResult1iSi_Si_SittSi_tF'
+public func s060__callMultiResult(i: Int) -> (Int, (Int, Int)) {
+  return s050______multiResult(i)
+}
+
+// SILGen, prepareArchetypeCallee. Materialize a
+// non-class-constrainted self from a class-constrained archetype.
+// ---
+// CHECK-LABEL: sil hidden @$S20opaque_values_silgen21s070__materializeSelf1tyx_tRlzCAA3FooRzlF : $@convention(thin) <T where T : AnyObject, T : Foo> (@guaranteed T) -> () {
+// CHECK: bb0([[ARG:%.*]] : $T):
+// CHECK: [[WITNESS_METHOD:%.*]] = witness_method $T, #Foo.foo!1 : <Self where Self : Foo> (Self) -> () -> () : $@convention(witness_method: Foo) <τ_0_0 where τ_0_0 : Foo> (@in_guaranteed τ_0_0) -> ()
+// CHECK: apply [[WITNESS_METHOD]]<T>([[ARG]]) : $@convention(witness_method: Foo) <τ_0_0 where τ_0_0 : Foo> (@in_guaranteed τ_0_0) -> ()
+// CHECK-NOT: destroy_value [[ARG]] : $T
+// CHECK: return %{{[0-9]+}} : $()
+// CHECK-LABEL: } // end sil function '$S20opaque_values_silgen21s070__materializeSelf1tyx_tRlzCAA3FooRzlF'
+func s070__materializeSelf<T: Foo>(t: T) where T: AnyObject {
+  t.foo()
+}
+
+// Test open existential with opaque values
+// ---
+// CHECK-LABEL: sil hidden @$S20opaque_values_silgen21s080______________bar1pSiAA1P_p_tF : $@convention(thin) (@in_guaranteed P) -> Int {
+// CHECK: bb0([[ARG:%.*]] : $P):
+// CHECK:   [[OPENED_ARG:%.*]] = open_existential_value [[ARG]] : $P to $@opened
+// CHECK:   [[WITNESS_FUNC:%.*]] = witness_method $@opened
+// CHECK:   [[RESULT:%.*]] = apply [[WITNESS_FUNC]]<{{.*}}>([[OPENED_ARG]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> Int
+// CHECK-NOT:   destroy_value [[ARG]] : $P
+// CHECK:   return [[RESULT]] : $Int
+func s080______________bar(p: P) -> Int {
+  return p.x
+}
+
+// Test OpaqueTypeLowering copyValue and destroyValue.
+// ---
+// CHECK-LABEL: sil hidden @$S20opaque_values_silgen21s090___________calleryxxlF : $@convention(thin) <T> (@in_guaranteed T) -> @out T {
+// CHECK: bb0([[ARG:%.*]] : $T):
+// CHECK-NOT: copy_value
+// CHECK:   [[RESULT:%.*]] = apply {{%.*}}<T>([[ARG]]) : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> @out τ_0_0
+// CHECK-NOT:   destroy_value [[ARG]] : $T
+// CHECK:   return %{{.*}} : $T
+// CHECK-LABEL: } // end sil function '$S20opaque_values_silgen21s090___________calleryxxlF'
+func s090___________caller<T>(_ t: T) -> T {
+  return s090___________caller(t)
+}
+
+// Test a simple opaque parameter and return value.
+// ---
+// CHECK-LABEL: sil hidden @$S20opaque_values_silgen21s100_________identityyxxlF : $@convention(thin) <T> (@in_guaranteed T) -> @out T {
+// CHECK: bb0([[ARG:%.*]] : $T):
+// CHECK:   [[COPY_ARG:%.*]] = copy_value [[ARG]] : $T
+// CHECK-NOT:   destroy_value [[ARG]] : $T
+// CHECK:   return [[COPY_ARG]] : $T
+// CHECK-LABEL: } // end sil function '$S20opaque_values_silgen21s100_________identityyxxlF'
+func s100_________identity<T>(_ t: T) -> T {
+  return t
+}
+
+// Test a guaranteed opaque parameter.
+// ---
+// CHECK-LABEL: sil private [transparent] [thunk] @$S20opaque_values_silgen21s110___GuaranteedSelfVAA3FooA2aDP3fooyyFTW : $@convention(witness_method: Foo) (@in_guaranteed s110___GuaranteedSelf) -> () {
+// CHECK: bb0(%0 : $s110___GuaranteedSelf):
+// CHECK:   %[[F:.*]] = function_ref @$S20opaque_values_silgen21s110___GuaranteedSelfV3fooyyF : $@convention(method) (s110___GuaranteedSelf) -> ()
+// CHECK:   apply %[[F]](%0) : $@convention(method) (s110___GuaranteedSelf) -> ()
+// CHECK:   return
+// CHECK-LABEL: } // end sil function '$S20opaque_values_silgen21s110___GuaranteedSelfVAA3FooA2aDP3fooyyFTW'
+struct s110___GuaranteedSelf : Foo {
+  func foo() {}
+}
+
+// Tests a corner case wherein we used to do a temporary and return a pointer to T instead of T
+// ---
+// CHECK-LABEL: sil hidden @$S20opaque_values_silgen21s120______returnValueyxxlF : $@convention(thin) <T> (@in_guaranteed T) -> @out T {
+// CHECK: bb0([[ARG:%.*]] : $T):
+// CHECK:   [[COPY_ARG1:%.*]] = copy_value [[ARG]] : $T
+// CHECK:   [[BORROWED_ARG2:%.*]] = begin_borrow [[COPY_ARG1]]
+// CHECK:   [[COPY_ARG2:%.*]] = copy_value [[BORROWED_ARG2]] : $T
+// CHECK:   end_borrow [[BORROWED_ARG2]] from [[COPY_ARG1]]
+// CHECK:   return [[COPY_ARG2]] : $T
+// CHECK-LABEL: } // end sil function '$S20opaque_values_silgen21s120______returnValueyxxlF'
+func s120______returnValue<T>(_ x: T) -> T {
+  let y = x
+  return y
+}
+
+// Tests Optional initialization by value
+// ---
+// CHECK-LABEL: sil hidden @$S20opaque_values_silgen21s130_____________wrapyxSgxlF : $@convention(thin) <T> (@in_guaranteed T) -> @out Optional<T> {
+// CHECK: bb0([[ARG:%.*]] : $T):
+// CHECK:   [[COPY_ARG:%.*]] = copy_value [[ARG]] : $T
+// CHECK:   [[OPTIONAL_ARG:%.*]] = enum $Optional<T>, #Optional.some!enumelt.1, [[COPY_ARG]] : $T
+// CHECK-NOT:   destroy_value [[ARG]] : $T
+// CHECK:   return [[OPTIONAL_ARG]] : $Optional<T>
+// CHECK-LABEL: } // end sil function '$S20opaque_values_silgen21s130_____________wrapyxSgxlF'
+func s130_____________wrap<T>(_ x: T) -> T? {
+  return x
+}
+
+// Tests For-each statements
+// ---
+// CHECK-LABEL: sil hidden @$S20opaque_values_silgen21s140______forEachStmtyyF : $@convention(thin) () -> () {
+// CHECK: bb0:
+// CHECK:   [[PROJ_BOX_ARG:%.*]] = project_box %{{.*}} : ${ var IndexingIterator<Range<Int>> }
+// CHECK:   [[APPLY_ARG1:%.*]] = apply
+// CHECK-NOT: alloc_stack $Int
+// CHECK-NOT: store [[APPLY_ARG1]] to [trivial]
+// CHECK-NOT: alloc_stack $Range<Int>
+// CHECK-NOT: dealloc_stack
+// CHECK:   [[APPLY_ARG2:%.*]] = apply %{{.*}}<Range<Int>>
+// CHECK:   store [[APPLY_ARG2]] to [trivial] [[PROJ_BOX_ARG]]
+// CHECK:   br bb1
+// CHECK: bb1:
+// CHECK-NOT: alloc_stack $Optional<Int>
+// CHECK:   [[APPLY_ARG3:%.*]] = apply %{{.*}}<Range<Int>>
+// CHECK-NOT: dealloc_stack
+// CHECK:   switch_enum [[APPLY_ARG3]]
+// CHECK: bb2:
+// CHECK:   br bb3
+// CHECK: bb3:
+// CHECK:   return %{{.*}} : $()
+// CHECK: bb4([[ENUM_ARG:%.*]] : $Int):
+// CHECK-NOT:   unchecked_enum_data
+// CHECK:   br bb1
+// CHECK-LABEL: } // end sil function '$S20opaque_values_silgen21s140______forEachStmtyyF'
+func s140______forEachStmt() {
+  for _ in 1..<42 {
+  }
+}
+
+func s150___________anyArg(_: Any) {}
+
+// Tests init of opaque existentials
+// ---
+// CHECK-LABEL: sil hidden @$S20opaque_values_silgen21s160_______callAnyArgyyF : $@convention(thin) () -> () {
+// CHECK: bb0:
+// CHECK:   [[INT_TYPE:%.*]] = metatype $@thin Int.Type
+// CHECK:   [[INT_LIT:%.*]] = integer_literal $Builtin.Int2048, 42
+// CHECK:   [[INT_ARG:%.*]] = apply %{{.*}}([[INT_LIT]], [[INT_TYPE]]) : $@convention(method) (Builtin.Int2048, @thin Int.Type) -> Int
+// CHECK:   [[INIT_OPAQUE:%.*]] = init_existential_value [[INT_ARG]] : $Int, $Int, $Any
+// CHECK:   apply %{{.*}}([[INIT_OPAQUE]]) : $@convention(thin) (@in_guaranteed Any) -> ()
+// CHECK:   return %{{.*}} : $()
+// CHECK-LABEL: } // end sil function '$S20opaque_values_silgen21s160_______callAnyArgyyF'
+func s160_______callAnyArg() {
+  s150___________anyArg(42)
+}
+
+// Tests unconditional_checked_cast for opaque values
+// ---
+// CHECK-LABEL: sil hidden @$S20opaque_values_silgen21s170____force_convertxylF : $@convention(thin) <T> () -> @out T {
+// CHECK: bb0:
+// CHECK-NOT: alloc_stack
+// CHECK:   [[INT_TYPE:%.*]] = metatype $@thin Int.Type
+// CHECK:   [[INT_LIT:%.*]] = integer_literal $Builtin.Int2048, 42
+// CHECK:   [[INT_ARG:%.*]] = apply %{{.*}}([[INT_LIT]], [[INT_TYPE]]) : $@convention(method) (Builtin.Int2048, @thin Int.Type) -> Int
+// CHECK:   [[INT_CAST:%.*]] = unconditional_checked_cast_value [[INT_ARG]] : $Int to $T
+// CHECK:   [[CAST_BORROW:%.*]] = begin_borrow [[INT_CAST]] : $T
+// CHECK:   [[RETURN_VAL:%.*]] = copy_value [[CAST_BORROW]] : $T
+// CHECK:   end_borrow [[CAST_BORROW]] from [[INT_CAST]] : $T, $T
+// CHECK:   destroy_value [[INT_CAST]] : $T
+// CHECK:   return [[RETURN_VAL]] : $T
+// CHECK-LABEL: } // end sil function '$S20opaque_values_silgen21s170____force_convertxylF'
+func s170____force_convert<T>() -> T {
+  let x : T = 42 as! T
+  return x
+}
+
+// Tests supporting function for s190___return_foo_var - cast and return of protocol
+// ---
+// CHECK-LABEL: sil hidden @$S20opaque_values_silgen21s180_______return_fooAA3Foo_pyF : $@convention(thin) () -> @out Foo {
+// CHECK: bb0:
+// CHECK:   [[INT_LIT:%.*]] = integer_literal $Builtin.Int2048, 42
+// CHECK:   [[INT_ARG:%.*]] = apply %{{.*}}([[INT_LIT]], [[INT_TYPE]]) : $@convention(method) (Builtin.Int2048, @thin Int.Type) -> Int
+// CHECK:   [[INT_CAST:%.*]] = unconditional_checked_cast_value [[INT_ARG]] : $Int to $Foo
+// CHECK:   return [[INT_CAST]] : $Foo
+// CHECK-LABEL: } // end sil function '$S20opaque_values_silgen21s180_______return_fooAA3Foo_pyF'
+func s180_______return_foo() -> Foo {
+  return 42 as! Foo
+}
+var foo_var : Foo = s180_______return_foo()
+
+// Tests return of global variables by doing a load of copy
+// ---
+// CHECK-LABEL: sil hidden @$S20opaque_values_silgen21s190___return_foo_varAA3Foo_pyF : $@convention(thin) () -> @out Foo {
+// CHECK: bb0:
+// CHECK:   [[GLOBAL:%.*]] = global_addr {{.*}} : $*Foo
+// CHECK:   [[READ:%.*]] = begin_access [read] [dynamic] [[GLOBAL]] : $*Foo
+// CHECK:   [[LOAD_GLOBAL:%.*]] = load [copy] [[READ]] : $*Foo
+// CHECK:   return [[LOAD_GLOBAL]] : $Foo
+// CHECK-LABEL: } // end sil function '$S20opaque_values_silgen21s190___return_foo_varAA3Foo_pyF'
+func s190___return_foo_var() -> Foo {
+  return foo_var
+}
+
+// Tests deinit of opaque existentials
+// ---
+// CHECK-LABEL: sil hidden @$S20opaque_values_silgen21s200______use_foo_varyyF : $@convention(thin) () -> () {
+// CHECK: bb0:
+// CHECK:   [[GLOBAL:%.*]] = global_addr {{.*}} : $*Foo
+// CHECK:   [[READ:%.*]] = begin_access [read] [dynamic] [[GLOBAL]] : $*Foo
+// CHECK:   [[LOAD_GLOBAL:%.*]] = load [copy] [[READ]] : $*Foo
+// CHECK:   [[BORROW:%.*]] = begin_borrow [[LOAD_GLOBAL]] : $Foo
+// CHECK:   [[OPEN_VAR:%.*]] = open_existential_value [[BORROW]] : $Foo
+// CHECK:   [[WITNESS:%.*]] = witness_method $@opened
+// CHECK:   apply [[WITNESS]]
+// CHECK:   end_borrow [[BORROW]]
+// CHECK:   destroy_value [[LOAD_GLOBAL]]
+// CHECK:   return %{{.*}} : $()
+// CHECK-LABEL: } // end sil function '$S20opaque_values_silgen21s200______use_foo_varyyF'
+func s200______use_foo_var() {
+  foo_var.foo()
+}
+
+// Tests composition erasure of opaque existentials + copy into of opaques
+// ---
+// CHECK-LABEL: sil hidden @$S20opaque_values_silgen21s210______compErasureys5Error_psAC_AA3FoopF : $@convention(thin) (@in_guaranteed Error & Foo) -> @owned Error {
+// CHECK: bb0([[ARG:%.*]] : $Error & Foo):
+// CHECK:   [[OPAQUE_ARG:%.*]] = open_existential_value [[ARG]] : $Error & Foo to $@opened({{.*}}) Error & Foo
+// CHECK:   [[EXIST_BOX:%.*]] = alloc_existential_box $Error, $@opened({{.*}}) Error & Foo
+// CHECK:   [[PROJ_BOX:%.*]] = project_existential_box $@opened({{.*}}) Error & Foo in [[EXIST_BOX]]
+// CHECK:   [[COPY_OPAQUE:%.*]] = copy_value [[OPAQUE_ARG]] : $@opened({{.*}}) Error & Foo
+// CHECK:   store [[COPY_OPAQUE]] to [init] [[PROJ_BOX]] : $*@opened({{.*}}) Error & Foo
+// CHECK-NOT:   destroy_value [[ARG]] : $Error & Foo
+// CHECK:   return [[EXIST_BOX]] : $Error
+// CHECK-LABEL: } // end sil function '$S20opaque_values_silgen21s210______compErasureys5Error_psAC_AA3FoopF'
+func s210______compErasure(_ x: Foo & Error) -> Error {
+  return x
+}
+
+// Tests that existential boxes can contain opaque types
+// ---
+// CHECK-LABEL: sil hidden @$S20opaque_values_silgen21s220_____openExistBoxySSs5Error_pF : $@convention(thin) (@guaranteed Error) -> @owned String {
+// CHECK: bb0([[ARG:%.*]] : $Error):
+// CHECK:   [[OPAQUE_ARG:%.*]] = open_existential_box_value [[ARG]] : $Error to $@opened({{.*}}) Error
+// CHECK:   [[ALLOC_OPEN:%.*]] = alloc_stack $@opened({{.*}}) Error
+// CHECK:   store_borrow [[OPAQUE_ARG]] to [[ALLOC_OPEN]]
+// CHECK:   dealloc_stack [[ALLOC_OPEN]]
+// CHECK-NOT:   destroy_value [[ARG]] : $Error
+// CHECK:   return {{.*}} : $String
+// CHECK-LABEL: } // end sil function '$S20opaque_values_silgen21s220_____openExistBoxySSs5Error_pF'
+func s220_____openExistBox(_ x: Error) -> String {
+  return x._domain
+}
+
+// Tests conditional value casts and correspondingly generated reabstraction thunk
+// ---
+// CHECK-LABEL: sil hidden @$S20opaque_values_silgen21s230______condFromAnyyyypF : $@convention(thin) (@in_guaranteed Any) -> () {
+// CHECK: bb0([[ARG:%.*]] : $Any):
+// CHECK:   [[COPY__ARG:%.*]] = copy_value [[ARG]]
+// CHECK:   checked_cast_value_br [[COPY__ARG]] : $Any to $@callee_guaranteed (@in_guaranteed (Int, (Int, (Int, Int)), Int)) -> @out (Int, (Int, (Int, Int)), Int), bb2, bb1
+// CHECK: bb2([[THUNK_PARAM:%.*]] : $@callee_guaranteed (@in_guaranteed (Int, (Int, (Int, Int)), Int)) -> @out (Int, (Int, (Int, Int)), Int)):
+// CHECK:   [[THUNK_REF:%.*]] = function_ref @{{.*}} : $@convention(thin) (Int, Int, Int, Int, Int, @guaranteed @callee_guaranteed (@in_guaranteed (Int, (Int, (Int, Int)), Int)) -> @out (Int, (Int, (Int, Int)), Int)) -> (Int, Int, Int, Int, Int)
+// CHECK:   partial_apply [callee_guaranteed] [[THUNK_REF]]([[THUNK_PARAM]])
+// CHECK: bb6:
+// CHECK:   return %{{.*}} : $()
+// CHECK-LABEL: } // end sil function '$S20opaque_values_silgen21s230______condFromAnyyyypF'
+func s230______condFromAny(_ x: Any) {
+  if let f = x as? (Int, (Int, (Int, Int)), Int) -> (Int, (Int, (Int, Int)), Int) {
+    _ = f(24, (4,(2, 42)), 42)
+  }
+}
+
+// Tests LValue of error types / existential boxes
+// ---
+// CHECK-LABEL: sil hidden @$S20opaque_values_silgen21s240_____propOfLValueySSs5Error_pF : $@convention(thin) (@guaranteed Error) -> @owned String {
+// CHECK: bb0([[ARG:%.*]] : $Error):
+// CHECK:   [[ALLOC_OF_BOX:%.*]] = alloc_box ${ var Error }
+// CHECK:   [[PROJ_BOX:%.*]] = project_box [[ALLOC_OF_BOX]]
+// CHECK:   [[COPY_ARG:%.*]] = copy_value [[ARG]]
+// CHECK:   store [[COPY_ARG]] to [init] [[PROJ_BOX]]
+// CHECK:   [[READ:%.*]] = begin_access [read] [unknown] [[PROJ_BOX]] : $*Error
+// CHECK:   [[LOAD_BOX:%.*]] = load [copy] [[READ]]
+// CHECK:   [[OPAQUE_ARG:%.*]] = open_existential_box [[LOAD_BOX]] : $Error to $*@opened({{.*}}) Error
+// CHECK:   [[LOAD_OPAQUE:%.*]] = load [copy] [[OPAQUE_ARG]]
+// CHECK:   [[ALLOC_OPEN:%.*]] = alloc_stack $@opened({{.*}}) Error
+// CHECK:   store [[LOAD_OPAQUE]] to [init] [[ALLOC_OPEN]]
+// CHECK:   [[RET_VAL:%.*]] = apply {{.*}}<@opened({{.*}}) Error>([[ALLOC_OPEN]])
+// CHECK:   return [[RET_VAL]] : $String
+// CHECK-LABEL: } // end sil function '$S20opaque_values_silgen21s240_____propOfLValueySSs5Error_pF'
+func s240_____propOfLValue(_ x: Error) -> String {
+  var x = x
+  return x._domain
+}
+
+// Tests Implicit Value Construction under Opaque value mode
+// ---
+// CHECK-LABEL: sil hidden @$S20opaque_values_silgen21s250_________testBoxTyyF : $@convention(thin) () -> () {
+// CHECK: bb0:
+// CHECK:   [[BOX_MTYPE:%.*]] = metatype $@thin Box<Int>.Type
+// CHECK:   [[MTYPE:%.*]] = metatype $@thin Int.Type
+// CHECK:   [[INTLIT:%.*]] = integer_literal $Builtin.Int2048, 42
+// CHECK:   [[AINT:%.*]] = apply {{.*}}([[INTLIT]], [[MTYPE]]) : $@convention(method) (Builtin.Int2048, @thin Int.Type) -> Int
+// CHECK:   apply {{.*}}<Int>([[AINT]], [[BOX_MTYPE]]) : $@convention(method) <τ_0_0> (@in τ_0_0, @thin Box<τ_0_0>.Type) -> @out Box<τ_0_0>
+// CHECK:   return %{{.*}} : $()
+// CHECK-LABEL: } // end sil function '$S20opaque_values_silgen21s250_________testBoxTyyF'
+func s250_________testBoxT() {
+  let _ = Box(t: 42)
+}
+
+// Tests Address only enums
+// ---
+// CHECK-LABEL: sil hidden @$S20opaque_values_silgen21s260_______AOnly_enumyyAA17AddressOnlyStructVF : $@convention(thin) (AddressOnlyStruct) -> () {
+// CHECK: bb0([[ARG:%.*]] : $AddressOnlyStruct):
+// CHECK:   [[MTYPE1:%.*]] = metatype $@thin AddressOnlyEnum.Type
+// CHECK:   [[APPLY1:%.*]] =  apply {{.*}}([[MTYPE1]]) : $@convention(thin) (@thin AddressOnlyEnum.Type) -> @owned @callee_guaranteed (@in_guaranteed EmptyP) -> @out AddressOnlyEnum
+// CHECK:   destroy_value [[APPLY1]]
+// CHECK:   [[MTYPE2:%.*]] = metatype $@thin AddressOnlyEnum.Type
+// CHECK:   [[ENUM1:%.*]] = enum $AddressOnlyEnum, #AddressOnlyEnum.nought!enumelt
+// CHECK:   [[MTYPE3:%.*]] = metatype $@thin AddressOnlyEnum.Type
+// CHECK:   [[INIT_OPAQUE:%.*]] = init_existential_value [[ARG]] : $AddressOnlyStruct, $AddressOnlyStruct, $EmptyP
+// CHECK:   [[ENUM2:%.*]] = enum $AddressOnlyEnum, #AddressOnlyEnum.mere!enumelt.1, [[INIT_OPAQUE]] : $EmptyP
+// CHECK:   destroy_value [[ENUM2]]
+// CHECK:   [[MTYPE4:%.*]] = metatype $@thin AddressOnlyEnum.Type
+// CHECK:   [[ENUM3:%.*]] = enum $AddressOnlyEnum, #AddressOnlyEnum.phantom!enumelt.1, [[ARG]] : $AddressOnlyStruct
+// CHECK:   return %{{.*}} : $()
+// CHECK-LABEL: } // end sil function '$S20opaque_values_silgen21s260_______AOnly_enumyyAA17AddressOnlyStructVF'
+func s260_______AOnly_enum(_ s: AddressOnlyStruct) {
+  _ = AddressOnlyEnum.mere
+
+  _ = AddressOnlyEnum.nought
+
+  _ = AddressOnlyEnum.mere(s)
+
+  _ = AddressOnlyEnum.phantom(s)
+}
+
+// Tests InjectOptional for opaque value types + conversion of opaque structs
+// ---
+// CHECK-LABEL: sil hidden @$S20opaque_values_silgen21s270_convOptAnyStructyyAA0gH0VADSgcF : $@convention(thin) (@guaranteed @callee_guaranteed (@in_guaranteed Optional<AnyStruct>) -> @out AnyStruct) -> () {
+// CHECK: bb0([[ARG:%.*]] : $@callee_guaranteed (@in_guaranteed Optional<AnyStruct>) -> @out AnyStruct):
+// CHECK:   [[COPY_ARG:%.*]] = copy_value [[ARG]]
+// CHECK:   [[PAPPLY:%.*]] = partial_apply [callee_guaranteed] %{{.*}}([[COPY_ARG]]) : $@convention(thin) (@in_guaranteed Optional<AnyStruct>, @guaranteed @callee_guaranteed (@in_guaranteed Optional<AnyStruct>) -> @out AnyStruct) -> @out Optional<AnyStruct>
+// CHECK:   destroy_value [[PAPPLY]] : $@callee_guaranteed (@in_guaranteed Optional<AnyStruct>) -> @out Optional<AnyStruct>
+// CHECK-NOT:   destroy_value [[ARG]] : $@callee_guaranteed (@in_guaranteed Optional<AnyStruct>) -> @out AnyStruct
+// CHECK:   return %{{.*}} : $()
+// CHECK-LABEL: } // end sil function '$S20opaque_values_silgen21s270_convOptAnyStructyyAA0gH0VADSgcF'
+func s270_convOptAnyStruct(_ a1: @escaping (AnyStruct?) -> AnyStruct) {
+  let _: (AnyStruct?) -> AnyStruct? = a1
+}
+
+// Tests conversion between existential types
+// ---
+// CHECK-LABEL: sil hidden @$S20opaque_values_silgen21s280_convExistTrivialyyAA0G6StructVAA1P_pcF : $@convention(thin) (@guaranteed @callee_guaranteed (@in_guaranteed P) -> TrivialStruct) -> () {
+// CHECK: bb0([[ARG:%.*]] : $@callee_guaranteed (@in_guaranteed P) -> TrivialStruct):
+// CHECK:   [[COPY_ARG:%.*]] = copy_value [[ARG]]
+// CHECK:   [[PAPPLY:%.*]] = partial_apply [callee_guaranteed] %{{.*}}([[COPY_ARG]]) : $@convention(thin) (@in_guaranteed P2, @guaranteed @callee_guaranteed (@in_guaranteed P) -> TrivialStruct) -> @out P2
+// CHECK:   destroy_value [[PAPPLY]] : $@callee_guaranteed (@in_guaranteed P2) -> @out P2
+// CHECK-NOT:   destroy_value [[ARG]]
+// CHECK:   return %{{.*}} : $()
+// CHECK-LABEL: } // end sil function '$S20opaque_values_silgen21s280_convExistTrivialyyAA0G6StructVAA1P_pcF'
+func s280_convExistTrivial(_ s: @escaping (P) -> TrivialStruct) {
+  let _: (P2) -> P2 = s
+}
+
+// Tests conversion between existential types - optionals case
+// ---
+// CHECK-LABEL: sil hidden @$S20opaque_values_silgen21s290_convOptExistTrivyyAA13TrivialStructVAA1P_pSgcF : $@convention(thin) (@guaranteed @callee_guaranteed (@in_guaranteed Optional<P>) -> TrivialStruct) -> () {
+// CHECK: bb0([[ARG:%.*]] : $@callee_guaranteed (@in_guaranteed Optional<P>) -> TrivialStruct):
+// CHECK:   [[COPY_ARG:%.*]] = copy_value [[ARG]]
+// CHECK:   [[PAPPLY:%.*]] = partial_apply [callee_guaranteed] %{{.*}}([[COPY_ARG]]) : $@convention(thin) (Optional<TrivialStruct>, @guaranteed @callee_guaranteed (@in_guaranteed Optional<P>) -> TrivialStruct) -> @out P2
+// CHECK:   destroy_value [[PAPPLY]] : $@callee_guaranteed (Optional<TrivialStruct>) -> @out P2
+// CHECK-NOT:   destroy_value [[ARG]]
+// CHECK:   return %{{.*}} : $()
+// CHECK-LABEL: } // end sil function '$S20opaque_values_silgen21s290_convOptExistTrivyyAA13TrivialStructVAA1P_pSgcF'
+func s290_convOptExistTriv(_ s: @escaping (P?) -> TrivialStruct) {
+  let _: (TrivialStruct?) -> P2 = s
+}
+
+// Tests corner-case: reabstraction of an empty tuple to any
+// ---
+// CHECK-LABEL: sil hidden @$S20opaque_values_silgen21s300__convETupleToAnyyyyycF : $@convention(thin) (@guaranteed @callee_guaranteed () -> ()) -> () {
+// CHECK: bb0([[ARG:%.*]] : $@callee_guaranteed () -> ()):
+// CHECK:   [[COPY_ARG:%.*]] = copy_value [[ARG]]
+// CHECK:   [[PAPPLY:%.*]] = partial_apply [callee_guaranteed] %{{.*}}([[COPY_ARG]]) : $@convention(thin) (@guaranteed @callee_guaranteed () -> ()) -> @out Any
+// CHECK:   destroy_value [[PAPPLY]] : $@callee_guaranteed () -> @out Any
+// CHECK-NOT:   destroy_value [[ARG]]
+// CHECK:   return %{{.*}} : $()
+// CHECK-LABEL: } // end sil function '$S20opaque_values_silgen21s300__convETupleToAnyyyyycF'
+func s300__convETupleToAny(_ t: @escaping () -> ()) {
+  let _: () -> Any = t
+}
+
+// Tests corner-case: reabstraction of a non-empty tuple to any
+// ---
+// CHECK-LABEL: sil hidden @$S20opaque_values_silgen21s310__convIntTupleAnyyySi_SitycF : $@convention(thin) (@guaranteed @callee_guaranteed () -> (Int, Int)) -> () {
+// CHECK: bb0([[ARG:%.*]] : $@callee_guaranteed () -> (Int, Int)):
+// CHECK:   [[COPY_ARG:%.*]] = copy_value [[ARG]]
+// CHECK:   [[PAPPLY:%.*]] = partial_apply [callee_guaranteed] %{{.*}}([[COPY_ARG]]) : $@convention(thin) (@guaranteed @callee_guaranteed () -> (Int, Int)) -> @out Any
+// CHECK:   destroy_value [[PAPPLY]] : $@callee_guaranteed () -> @out Any
+// CHECK-NOT:   destroy_value [[ARG]]
+// CHECK:   return %{{.*}} : $()
+// CHECK-LABEL: } // end sil function '$S20opaque_values_silgen21s310__convIntTupleAnyyySi_SitycF'
+func s310__convIntTupleAny(_ t: @escaping () -> (Int, Int)) {
+  let _: () -> Any = t
+}
+
+// Tests translating and imploding into Any under opaque value mode
+// ---
+// CHECK-LABEL: sil hidden @$S20opaque_values_silgen21s320__transImplodeAnyyyyypcF : $@convention(thin) (@guaranteed @callee_guaranteed (@in_guaranteed Any) -> ()) -> () {
+// CHECK: bb0([[ARG:%.*]] : $@callee_guaranteed (@in_guaranteed Any) -> ()):
+// CHECK:   [[COPY_ARG:%.*]] = copy_value [[ARG]]
+// CHECK:   [[PAPPLY:%.*]] = partial_apply [callee_guaranteed] %{{.*}}([[COPY_ARG]]) : $@convention(thin) (Int, Int, @guaranteed @callee_guaranteed (@in_guaranteed Any) -> ()) -> ()
+// CHECK:   destroy_value [[PAPPLY]] : $@callee_guaranteed (Int, Int) -> ()
+// CHECK-NOT:   destroy_value [[ARG]]
+// CHECK:   return %{{.*}} : $()
+// CHECK-LABEL: } // end sil function '$S20opaque_values_silgen21s320__transImplodeAnyyyyypcF'
+func s320__transImplodeAny(_ t: @escaping (Any) -> ()) {
+  let _: ((Int, Int)) -> () = t
+}
+
+// Tests support for address only let closures under opaque value mode - they are not by-address anymore
+// ---
+// CHECK-LABEL: sil private @$S20opaque_values_silgen21s330___addrLetClosureyxxlFxyXEfU_xyXEfU_ : $@convention(thin) <T> (@in_guaranteed T) -> @out T {
+// CHECK: bb0([[ARG:%.*]] : $T):
+// CHECK:   [[COPY_ARG:%.*]] = copy_value [[ARG]] : $T
+// CHECK:   return [[COPY_ARG]] : $T
+// CHECK-LABEL: } // end sil function '$S20opaque_values_silgen21s330___addrLetClosureyxxlFxyXEfU_xyXEfU_'
+func s330___addrLetClosure<T>(_ x:T) -> T {
+  return { { x }() }()
+}
+
+// Tests support for capture of a mutable opaque value type
+// ---
+// CHECK-LABEL: sil hidden @$S20opaque_values_silgen21s340_______captureBoxyyF : $@convention(thin) () -> () {
+// CHECK: bb0:
+// CHECK:   [[ALLOC_OF_BOX:%.*]] = alloc_box ${ var EmptyP }, var, name "mutableAddressOnly"
+// CHECK:   [[PROJ_BOX:%.*]] = project_box [[ALLOC_OF_BOX]]
+// CHECK:   [[APPLY_FOR_BOX:%.*]] = apply %{{.*}}(%{{.*}}) : $@convention(method) (@thin AddressOnlyStruct.Type) -> AddressOnlyStruct
+// CHECK:   [[INIT_OPAQUE:%.*]] = init_existential_value [[APPLY_FOR_BOX]] : $AddressOnlyStruct, $AddressOnlyStruct, $EmptyP
+// CHECK:   store [[INIT_OPAQUE]] to [init] [[PROJ_BOX]] : $*EmptyP
+// CHECK:   [[BORROW_BOX:%.*]] = begin_borrow [[ALLOC_OF_BOX]] : ${ var EmptyP }
+// CHECK:   mark_function_escape [[PROJ_BOX]] : $*EmptyP
+// CHECK:   apply %{{.*}}([[BORROW_BOX]]) : $@convention(thin) (@guaranteed { var EmptyP }) -> ()
+// CHECK:   return %{{.*}} : $()
+// CHECK-LABEL: } // end sil function '$S20opaque_values_silgen21s340_______captureBoxyyF'
+func s340_______captureBox() {
+  var mutableAddressOnly: EmptyP = AddressOnlyStruct()
+
+  func captureEverything() {
+    _ = s100_________identity((mutableAddressOnly))
+  }
+
+  captureEverything()
+}
+
+// Tests support for if statements for opaque value(s) under new mode
+// ---
+// CHECK-LABEL: sil hidden @$S20opaque_values_silgen21s350_______addrOnlyIf1xAA6EmptyP_pSb_tF : $@convention(thin) (Bool) -> @out EmptyP {
+// CHECK: bb0([[ARG:%.*]] : $Bool):
+// CHECK:   [[ALLOC_OF_BOX:%.*]] = alloc_box ${ var EmptyP }, var
+// CHECK:   [[PROJ_BOX:%.*]] = project_box [[ALLOC_OF_BOX]]
+// CHECK:   [[APPLY_FOR_BOX:%.*]] = apply %{{.*}}(%{{.*}}) : $@convention(method) (@thin AddressOnlyStruct.Type) -> AddressOnlyStruct
+// CHECK:   [[INIT_OPAQUE:%.*]] = init_existential_value [[APPLY_FOR_BOX]] : $AddressOnlyStruct, $AddressOnlyStruct, $EmptyP
+// CHECK:   store [[INIT_OPAQUE]] to [init] [[PROJ_BOX]] : $*EmptyP
+// CHECK:   [[APPLY_FOR_BRANCH:%.*]] = apply %{{.*}}([[ARG]]) : $@convention(method) (Bool) -> Builtin.Int1
+// CHECK:   cond_br [[APPLY_FOR_BRANCH]], bb2, bb1
+// CHECK: bb1:
+// CHECK:   [[READ:%.*]] = begin_access [read] [unknown] [[PROJ_BOX]] : $*EmptyP
+// CHECK:   [[RETVAL1:%.*]] = load [copy] [[READ]] : $*EmptyP
+// CHECK:   br bb3([[RETVAL1]] : $EmptyP)
+// CHECK: bb2:
+// CHECK:   [[READ:%.*]] = begin_access [read] [unknown] [[PROJ_BOX]] : $*EmptyP
+// CHECK:   [[RETVAL2:%.*]] = load [copy] [[READ]] : $*EmptyP
+// CHECK:   br bb3([[RETVAL2]] : $EmptyP)
+// CHECK: bb3([[RETVAL:%.*]] : $EmptyP):
+// CHECK:   destroy_value [[ALLOC_OF_BOX]]
+// CHECK:   return [[RETVAL]] : $EmptyP
+// CHECK-LABEL: } // end sil function '$S20opaque_values_silgen21s350_______addrOnlyIf1xAA6EmptyP_pSb_tF'
+func s350_______addrOnlyIf(x: Bool) -> EmptyP {
+  var a : EmptyP = AddressOnlyStruct()
+
+  return x ? a : a
+}
+
+// Tests support for guards and indirect enums for opaque values
+// ---
+// CHECK-LABEL: sil hidden @$S20opaque_values_silgen21s360________guardEnumyyAA08IndirectF0OyxGlF : $@convention(thin) <T> (@guaranteed IndirectEnum<T>) -> () {
+// CHECK: bb0([[ARG:%.*]] : $IndirectEnum<T>):
+// CHECK:   [[COPY__ARG:%.*]] = copy_value [[ARG]]
+// CHECK:   switch_enum [[COPY__ARG]] : $IndirectEnum<T>, case #IndirectEnum.Node!enumelt.1: [[NODE_BB:bb[0-9]+]], case #IndirectEnum.Nil!enumelt: [[NIL_BB:bb[0-9]+]]
+//
+// CHECK: [[NIL_BB]]:
+// CHECK:   br [[NIL_TRAMPOLINE:bb[0-9]+]]
+//
+// CHECK: [[NIL_TRAMPOLINE]]:
+// CHECK:   br [[EPILOG_BB:bb[0-9]+]]
+//
+// CHECK: [[NODE_BB]]([[EARG:%.*]] : $<τ_0_0> { var τ_0_0 } <T>):
+// CHECK:   [[PROJ_BOX:%.*]] = project_box [[EARG]]
+// CHECK:   [[LOAD_BOX:%.*]] = load [take] [[PROJ_BOX]] : $*T
+// CHECK:   [[COPY_BOX:%.*]] = copy_value [[LOAD_BOX]] : $T
+// CHECK:   destroy_value [[EARG]]
+// CHECK:   br [[CONT_BB:bb[0-9]+]]
+//
+// CHECK: [[CONT_BB]]:
+// CHECK:   destroy_value [[COPY_BOX]]
+// CHECK:   br [[EPILOG_BB]]
+//
+// CHECK: [[EPILOG_BB]]:
+// CHECK-NOT:   destroy_value [[ARG]]
+// CHECK:   return %{{.*}} : $()
+// CHECK-LABEL: } // end sil function '$S20opaque_values_silgen21s360________guardEnumyyAA08IndirectF0OyxGlF'
+func s360________guardEnum<T>(_ e: IndirectEnum<T>) {
+  do {
+    guard case .Node(let x) = e else { return }
+    _ = x
+  }
+}
+
+// Tests contextual init() of opaque value types
+// ---
+// CHECK-LABEL: sil hidden @$S20opaque_values_silgen21s370_____optToOptCastyxSgAClF : $@convention(thin) <T> (@in_guaranteed Optional<T>) -> @out Optional<T> {
+// CHECK: bb0([[ARG:%.*]] : $Optional<T>):
+// CHECK:   [[COPY__ARG:%.*]] = copy_value [[ARG]]
+// CHECK-NOT:   destroy_value [[ARG]]
+// CHECK:   return [[COPY__ARG]] : $Optional<T>
+// CHECK-LABEL: } // end sil function '$S20opaque_values_silgen21s370_____optToOptCastyxSgAClF'
+func s370_____optToOptCast<T>(_ x : T!) -> T? {
+  return x
+}
+
+// Tests casting optional opaques to optional opaques
+// ---
+// CHECK-LABEL: sil hidden @$S20opaque_values_silgen21s380___contextualInityySiSgF : $@convention(thin) (Optional<Int>) -> () {
+// CHECK: bb0([[ARG:%.*]] : $Optional<Int>):
+// CHECK:   [[ALLOC_OF_BOX:%.*]] = alloc_box ${ var Optional<Int> }, var
+// CHECK:   [[PROJ_BOX:%.*]] = project_box [[ALLOC_OF_BOX]]
+// CHECK:   store [[ARG]] to [trivial] [[PROJ_BOX]] : $*Optional<Int>
+// CHECK:   destroy_value [[ALLOC_OF_BOX]]
+// CHECK:   return %{{.*}} : $()
+// CHECK-LABEL: } // end sil function '$S20opaque_values_silgen21s380___contextualInityySiSgF'
+func s380___contextualInit(_ a : Int?) {
+  var x: Int! = a
+  _ = x
+}
+
+// Tests opaque call result types
+// ---
+// CHECK-LABEL: sil hidden @$S20opaque_values_silgen21s390___addrCallResultyyxycSglF : $@convention(thin) <T> (@guaranteed Optional<@callee_guaranteed () -> @out T>) -> () {
+// CHECK: bb0([[ARG:%.*]] : $Optional<@callee_guaranteed () -> @out T>):
+// CHECK:   [[ALLOC_OF_BOX:%.*]] = alloc_box $<τ_0_0> { var Optional<τ_0_0> } <T>
+// CHECK:   [[PROJ_BOX:%.*]] = project_box [[ALLOC_OF_BOX]]
+// CHECK:   [[COPY__ARG:%.*]] = copy_value [[ARG]]
+// CHECK:   [[SENUM:%.*]] = select_enum [[COPY__ARG]]
+// CHECK:   cond_br [[SENUM]], bb3, bb1
+// CHECK: bb1:
+// CHECK:   br bb2
+// CHECK: bb2:
+// CHECK:   [[ONONE:%.*]] = enum $Optional<T>, #Optional.none!enumelt
+// CHECK:   br bb4([[ONONE]] : $Optional<T>)
+// CHECK: bb4(%{{.*}} : $Optional<T>):
+// CHECK:   return %{{.*}} : $()
+// CHECK-LABEL: } // end sil function '$S20opaque_values_silgen21s390___addrCallResultyyxycSglF'
+func s390___addrCallResult<T>(_ f: (() -> T)?) {
+  var x = f?()
+  _ = x
+}
+
+// Tests reabstraction / partial apply of protocols under opaque value mode
+// ---
+// CHECK-LABEL: sil hidden @$S20opaque_values_silgen21s400______maybeCloneP1cyAA8Clonable_p_tF : $@convention(thin) (@in_guaranteed Clonable) -> () {
+// CHECK: bb0([[ARG:%.*]] : $Clonable):
+// CHECK:   [[OPEN_ARG:%.*]] = open_existential_value [[ARG]] : $Clonable
+// CHECK:   [[APPLY_OPAQUE:%.*]] = apply %{{.*}}<@opened({{.*}}) Clonable>([[OPEN_ARG]]) : $@convention(thin) <τ_0_0 where τ_0_0 : Clonable> (@in_guaranteed τ_0_0) -> @owned @callee_guaranteed () -> @out Optional<τ_0_0>
+// CHECK:   [[PAPPLY:%.*]] = partial_apply [callee_guaranteed] %{{.*}}<@opened({{.*}}) Clonable>([[APPLY_OPAQUE]]) : $@convention(thin) <τ_0_0 where τ_0_0 : Clonable> (@guaranteed @callee_guaranteed () -> @out Optional<τ_0_0>) -> @out Optional<Clonable>
+// CHECK-NOT:   destroy_value [[ARG]]
+// CHECK:   return %{{.*}} : $()
+// CHECK-LABEL: } // end sil function '$S20opaque_values_silgen21s400______maybeCloneP1cyAA8Clonable_p_tF'
+func s400______maybeCloneP(c: Clonable) {
+  let _: () -> Clonable? = c.maybeClone
+}
+
+// Tests global opaque values / subscript rvalues
+// ---
+// CHECK-LABEL: sil hidden @$S20opaque_values_silgen21s410__globalRvalueGetyS2iF : $@convention(thin) (Int) -> Int {
+// CHECK: bb0([[ARG:%.*]] : $Int):
+// CHECK:   [[GLOBAL_ADDR:%.*]] = global_addr @$S20opaque_values_silgen16subscriptableGetAA013SubscriptableE0_pvp : $*SubscriptableGet
+// CHECK:   [[READ:%.*]] = begin_access [read] [dynamic] [[GLOBAL_ADDR]] : $*SubscriptableGet
+// CHECK:   [[OPEN_ARG:%.*]] = open_existential_addr immutable_access [[READ]] : $*SubscriptableGet to $*@opened
+// CHECK:   [[GET_OPAQUE:%.*]] = load [copy] [[OPEN_ARG]] : $*@opened
+// CHECK:   [[RETVAL:%.*]] = apply %{{.*}}<@opened({{.*}}) SubscriptableGet>([[ARG]], [[GET_OPAQUE]]) : $@convention(witness_method: SubscriptableGet) <τ_0_0 where τ_0_0 : SubscriptableGet> (Int, @in_guaranteed τ_0_0) -> Int
+// CHECK:   destroy_value [[GET_OPAQUE]]
+// CHECK:   return [[RETVAL]] : $Int
+// CHECK-LABEL: } // end sil function '$S20opaque_values_silgen21s410__globalRvalueGetyS2iF'
+func s410__globalRvalueGet(_ i : Int) -> Int {
+  return subscriptableGet[i]
+}
+
+// Tests global opaque values / subscript lvalues
+// ---
+// CHECK-LABEL: sil hidden @$S20opaque_values_silgen21s420__globalLvalueGetyS2iF : $@convention(thin) (Int) -> Int {
+// CHECK: bb0([[ARG:%.*]] : $Int):
+// CHECK:   [[GLOBAL_ADDR:%.*]] = global_addr @$S20opaque_values_silgen19subscriptableGetSetAA013SubscriptableeF0_pvp : $*SubscriptableGetSet
+// CHECK:   [[READ:%.*]] = begin_access [read] [dynamic] [[GLOBAL_ADDR]] : $*SubscriptableGetSet
+// CHECK:   [[OPEN_ARG:%.*]] = open_existential_addr immutable_access [[READ]] : $*SubscriptableGetSet to $*@opened
+// CHECK:   [[GET_OPAQUE:%.*]] = load [copy] [[OPEN_ARG]] : $*@opened
+// CHECK:   [[RETVAL:%.*]] = apply %{{.*}}<@opened({{.*}}) SubscriptableGetSet>([[ARG]], [[GET_OPAQUE]]) : $@convention(witness_method: SubscriptableGetSet) <τ_0_0 where τ_0_0 : SubscriptableGetSet> (Int, @in_guaranteed τ_0_0) -> Int
+// CHECK:   destroy_value [[GET_OPAQUE]]
+// CHECK:   return [[RETVAL]] : $Int
+// CHECK-LABEL: } // end sil function '$S20opaque_values_silgen21s420__globalLvalueGetyS2iF'
+func s420__globalLvalueGet(_ i : Int) -> Int {
+  return subscriptableGetSet[i]
+}
+
+// Tests tuple transformation
+// ---
+// CHECK-LABEL: sil hidden @$S20opaque_values_silgen21s430_callUnreachableF1tyx_tlF : $@convention(thin) <T> (@in_guaranteed T) -> () {
+// CHECK: bb0([[ARG:%.*]] : $T):
+// CHECK:   [[APPLY_T:%.*]] = apply %{{.*}}<((T) -> (), T)>() : $@convention(thin) <τ_0_0> () -> @out Optional<(Int, τ_0_0)>
+// CHECK:   switch_enum [[APPLY_T]] : $Optional<(Int, (@callee_guaranteed (@in_guaranteed T) -> @out (), T))>, case #Optional.some!enumelt.1: bb2, case #Optional.none!enumelt: bb1
+// CHECK: bb2([[ENUMARG:%.*]] : $(Int, (@callee_guaranteed (@in_guaranteed T) -> @out (), T))):
+// CHECK:   ([[TELEM0:%.*]], [[TELEM1:%.*]]) = destructure_tuple [[ENUMARG]] : $(Int, (@callee_guaranteed (@in_guaranteed T) -> @out (), T))
+// CHECK:   ([[TELEM10:%.*]], [[TELEM11:%.*]]) = destructure_tuple [[TELEM1]] : $(@callee_guaranteed (@in_guaranteed T) -> @out (), T)
+// CHECK:   [[PAPPLY:%.*]] = partial_apply [callee_guaranteed] %{{.*}}<T>([[TELEM10]]) : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0, @guaranteed @callee_guaranteed (@in_guaranteed τ_0_0) -> @out ()) -> ()
+// CHECK:   [[NEWT0:%.*]] = tuple ([[PAPPLY]] : $@callee_guaranteed (@in_guaranteed T) -> (), [[TELEM11]] : $T)
+// CHECK:   [[NEWT1:%.*]] = tuple ([[TELEM0]] : $Int, [[NEWT0]] : $(@callee_guaranteed (@in_guaranteed T) -> (), T))
+// CHECK:   [[NEWENUM:%.*]] = enum $Optional<(Int, (@callee_guaranteed (@in_guaranteed T) -> (), T))>, #Optional.some!enumelt.1, [[NEWT1]] : $(Int, (@callee_guaranteed (@in_guaranteed T) -> (), T))
+// CHECK:   br bb3([[NEWENUM]] : $Optional<(Int, (@callee_guaranteed (@in_guaranteed T) -> (), T))>)
+// CHECK: bb3([[ENUMIN:%.*]] : $Optional<(Int, (@callee_guaranteed (@in_guaranteed T) -> (), T))>):
+// CHECK:   destroy_value [[ENUMIN]]
+// CHECK:   return %{{.*}} : $()
+// CHECK-LABEL: } // end sil function '$S20opaque_values_silgen21s430_callUnreachableF1tyx_tlF'
+func s430_callUnreachableF<T>(t: T) {
+  let _: (Int, ((T) -> (), T))? = unreachableF()
+}
+
+// Further testing for conditional checked cast under opaque value mode - make sure we don't create a buffer for results
+// ---
+// CHECK-LABEL: sil hidden @$S20opaque_values_silgen21s440__cleanupEmissionyyxlF : $@convention(thin) <T> (@in_guaranteed T) -> () {
+// CHECK: bb0([[ARG:%.*]] : $T):
+// CHECK:   [[COPY_ARG:%.*]] = copy_value [[ARG]]
+// CHECK:   checked_cast_value_br [[COPY_ARG]] : $T to $EmptyP, bb2, bb1
+//
+// CHECK: bb2([[PTYPE:%.*]] : $EmptyP):
+// CHECK:   [[PSOME:%.*]] = enum $Optional<EmptyP>, #Optional.some!enumelt.1, [[PTYPE]] : $EmptyP
+// CHECK:   br bb3([[PSOME]] : $Optional<EmptyP>)
+//
+// CHECK: bb3([[ENUMRES:%.*]] : $Optional<EmptyP>):
+// CHECK:   switch_enum [[ENUMRES]] : $Optional<EmptyP>, case #Optional.some!enumelt.1: [[SOME_BB:bb[0-9]+]], case #Optional.none!enumelt: [[NONE_BB:bb[0-9]+]]
+//
+// CHECK: [[NONE_BB]]:
+// CHECK:   br [[NONE_TRAMPOLINE:bb[0-9]+]]
+//
+// CHECK: [[NONE_TRAMPOLINE]]:
+// CHECK:   br [[EPILOG_BB:bb[0-9]+]]
+//
+// CHECK: [[SOME_BB]]([[ENUMRES2:%.*]] : $EmptyP):
+// CHECK:   br [[CONT_BB:bb[0-9]+]]
+//
+// CHECK: [[CONT_BB]]:
+// CHECK:   destroy_value [[ENUMRES2]]
+// CHECK:   br [[EPILOG_BB]]
+//
+// CHECK: [[EPILOG_BB]]:
+// CHECK-NOT:   destroy_value [[ARG]]
+// CHECK:   return %{{.*}} : $()
+// CHECK-LABEL: } // end sil function '$S20opaque_values_silgen21s440__cleanupEmissionyyxlF'
+func s440__cleanupEmission<T>(_ x: T) {
+  guard let x2 = x as? EmptyP else { return }
+  _ = x2
+}
+
+// Test SILGenBuilder.loadCopy().
+// ---
+// CHECK-LABEL: sil hidden @$S20opaque_values_silgen21s450__________lastValyxxd_tlF : $@convention(thin) <T> (@guaranteed Array<T>) -> @out T
+// CHECK: [[LOAD:%.*]] = load [copy] %{{.*}} : $*T
+// CHECK: return [[LOAD]] : $T
+// CHECK-LABEL: } // end sil function '$S20opaque_values_silgen21s450__________lastValyxxd_tlF'
+func s450__________lastVal<T>(_ rest: T...) -> T {
+  var minValue: T
+  for value in rest {
+    minValue = value
+  }
+  return minValue
+}
+
+// Test SILGenFunction::emitPointerToPointer.
+// ---
+// CHECK-LABEL: sil hidden @$S20opaque_values_silgen21s460______________foo1pSRyxGSPyxG_tlF : $@convention(thin) <Element> (UnsafePointer<Element>) -> UnsafeBufferPointer<Element> {
+// CHECK: [[F:%.*]] = function_ref @$Ss017_convertPointerToB8Argumentyq_xs01_B0RzsABR_r0_lF : $@convention(thin) <τ_0_0, τ_0_1 where τ_0_0 : _Pointer, τ_0_1 : _Pointer> (@in_guaranteed τ_0_0) -> @out τ_0_1
+// CHECK: apply [[F]]<UnsafePointer<Element>, UnsafePointer<Element>>(%0) : $@convention(thin) <τ_0_0, τ_0_1 where τ_0_0 : _Pointer, τ_0_1 : _Pointer> (@in_guaranteed τ_0_0) -> @out τ_0_1
+// CHECK-LABEL: } // end sil function '$S20opaque_values_silgen21s460______________foo1pSRyxGSPyxG_tlF'
+func s460______________foo<Element>(p: UnsafePointer<Element>) -> UnsafeBufferPointer<Element> {
+  return UnsafeBufferPointer(start: p, count: 1)
+}
+
+// Test emitNativeToCBridgedNonoptionalValue.
+// ---
+// CHECK-objc-LABEL: sil hidden @$S20opaque_values_silgen21s470________nativeToC7fromAnyyXlyp_tF : $@convention(thin) (@in_guaranteed Any) -> @owned AnyObject {
+// CHECK-objc bb0(%0 : $Any):
+// CHECK-objc [[BORROW:%.*]] = begin_borrow %0 : $Any
+// CHECK-objc [[SRC:%.*]] = copy_value [[BORROW]] : $Any
+// CHECK-objc [[OPEN:%.*]] = open_existential_opaque [[SRC]] : $Any to $@opened
+// CHECK-objc [[COPY:%.*]] = copy_value [[OPEN]] : $@opened
+// CHECK-objc [[F:%.*]] = function_ref @$Ss27_bridgeAnythingToObjectiveCyyXlxlF : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> @owned AnyObject
+// CHECK-objc [[RET:%.*]] = apply [[F]]<@opened("{{.*}}") Any>([[COPY]]) : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> @owned AnyObject
+// CHECK-objc destroy_value [[SRC]] : $Any
+// CHECK-objc destroy_value %0 : $Any
+// CHECK-objc return [[RET]] : $AnyObject
+// CHECK-objc-LABEL: } // end sil function '$S20opaque_values_silgen21s470________nativeToC7fromAnyyXlyp_tF'
+#if _runtime(_ObjC)
+func s470________nativeToC(fromAny any: Any) -> AnyObject {
+  return any as AnyObject
+}
+#endif
+
+// Test emitOpenExistential.
+// ---
+// CHECK-LABEL: sil hidden @$S20opaque_values_silgen21s480_________getError04someF0yps0F0_p_tF : $@convention(thin) (@guaranteed Error) -> @out Any {
+// CHECK: bb0([[ARG:%.*]] : $Error):
+// CHECK: [[VAL:%.*]] = open_existential_box_value [[ARG]] : $Error to $@opened("{{.*}}") Error
+// CHECK: [[COPY:%.*]] = copy_value [[VAL]] : $@opened("{{.*}}") Error
+// CHECK: [[ANY:%.*]] = init_existential_value [[COPY]] : $@opened("{{.*}}") Error, $@opened("{{.*}}") Error, $Any
+// CHECK-NOT: destroy_value [[ARG]] : $Error
+// CHECK: return [[ANY]] : $Any
+// CHECK-LABEL: } // end sil function '$S20opaque_values_silgen21s480_________getError04someF0yps0F0_p_tF'
+func s480_________getError(someError: Error) -> Any {
+  return someError
+}
+
+// Test SILBuilder.createLoadBorrow.
+// ---
+// CHECK-LABEL: sil private @$S20opaque_values_silgen21s490_______loadBorrowyyF3FooL_V3foo3pos7ElementQzSg5IndexQz_tF : $@convention(method) <Elements where Elements : Collection> (@in_guaranteed Elements.Index, @inout Foo<Elements>) -> @out Optional<Elements.Element> {
+// CHECK: bb0([[ARG0:%.*]] : $Elements.Index, [[ARG1:%.*]] : $*Foo<Elements>):
+// CHECK: [[READ:%.*]] = begin_access [read] [unknown] [[ARG1]] : $*Foo<Elements>
+// CHECK: [[LOAD:%.*]] = load [copy] [[READ]] : $*Foo<Elements>
+// CHECK: end_access [[READ]] : $*Foo<Elements>
+// CHECK: [[BORROW_LOAD:%.*]] = begin_borrow [[LOAD]]
+// CHECK: [[EXTRACT:%.*]] = struct_extract [[BORROW_LOAD]] : $Foo<Elements>, #<abstract function>Foo._elements
+// CHECK: [[COPYELT:%.*]] = copy_value [[EXTRACT]] : $Elements
+// CHECK: [[COPYIDX:%.*]] = copy_value [[ARG0]] : $Elements.Index
+// CHECK: [[WT:%.*]] = witness_method $Elements, #Collection.subscript!getter.1 : <Self where Self : Collection> (Self) -> (Self.Index) -> Self.Element : $@convention(witness_method: Collection) <τ_0_0 where τ_0_0 : Collection> (@in_guaranteed τ_0_0.Index, @in_guaranteed τ_0_0) -> @out τ_0_0.Element
+// CHECK: [[RESULT:%.*]] = apply [[WT]]<Elements>([[COPYIDX]], [[COPYELT]]) : $@convention(witness_method: Collection) <τ_0_0 where τ_0_0 : Collection> (@in_guaranteed τ_0_0.Index, @in_guaranteed τ_0_0) -> @out τ_0_0.Element
+// CHECK: destroy_value [[COPYELT]] : $Elements
+// CHECK: [[ENUM_RESULT:%.*]] = enum $Optional<Elements.Element>, #Optional.some!enumelt.1, [[RESULT]] : $Elements.Element
+// CHECK: destroy_value [[LOAD]]
+// CHECK-NOT: destroy_value [[ARG0]] : $Elements.Index
+// CHECK: return [[ENUM_RESULT]] : $Optional<Elements.Element>
+// CHECK-LABEL: } // end sil function '$S20opaque_values_silgen21s490_______loadBorrowyyF3FooL_V3foo3pos7ElementQzSg5IndexQz_tF'
+
+func s490_______loadBorrow() {
+  struct Foo<Elements : Collection> {
+    internal let _elements: Elements
+
+    public mutating func foo(pos: Elements.Index) -> Elements.Element? {
+      return _elements[pos]
+    }
+  }
+  var foo = Foo(_elements: [])
+  _ = foo.foo(pos: 1)
+}
+
+protocol ConvertibleToP {
+  func asP() -> P
+}
+
+// Test visitBindOptionalExpr
+// ---
+// CHECK-LABEL: sil hidden @$S20opaque_values_silgen21s500_______getAnyHashyAA1P_pSgAA14ConvertibleToP_pSgF : $@convention(thin) (@in_guaranteed Optional<ConvertibleToP>) -> @out Optional<P> {
+// CHECK: bb0(%0 : $Optional<ConvertibleToP>):
+// CHECK: [[COPY:%.*]] = copy_value [[ARG]] : $Optional<ConvertibleToP>
+// CHECK: [[DATA:%.*]] = unchecked_enum_data [[COPY]] : $Optional<ConvertibleToP>, #Optional.some!enumelt.1
+// CHECK: [[BORROW_DATA:%.*]] = begin_borrow [[DATA]] : $ConvertibleToP
+// CHECK: [[VAL:%.*]] = open_existential_value [[BORROW_DATA]] : $ConvertibleToP to $@opened("{{.*}}") ConvertibleToP
+// CHECK: [[WT:%.*]] = witness_method $@opened("{{.*}}") ConvertibleToP, #ConvertibleToP.asP!1 : <Self where Self : ConvertibleToP> (Self) -> () -> P, [[VAL]] : $@opened("{{.*}}") ConvertibleToP : $@convention(witness_method: ConvertibleToP) <τ_0_0 where τ_0_0 : ConvertibleToP> (@in_guaranteed τ_0_0) -> @out P
+// CHECK: [[AS_P:%.*]] = apply [[WT]]<@opened("{{.*}}") ConvertibleToP>([[VAL]]) : $@convention(witness_method: ConvertibleToP) <τ_0_0 where τ_0_0 : ConvertibleToP> (@in_guaranteed τ_0_0) -> @out P
+// CHECK: [[ENUM:%.*]] = enum $Optional<P>, #Optional.some!enumelt.1, [[AS_P]] : $P
+// CHECK: destroy_value [[DATA]] : $ConvertibleToP
+// CHECK: br bb{{.*}}([[ENUM]] : $Optional<P>)
+// CHECK: // end sil function '$S20opaque_values_silgen21s500_______getAnyHashyAA1P_pSgAA14ConvertibleToP_pSgF'
+func s500_______getAnyHash(_ value: ConvertibleToP?) -> P? {
+  return value?.asP()
+}
+
+public protocol FooP {
+  func foo() -> Self
+}
+
+// Test emitting a protocol witness for a method (with @in_guaranteed self) on a dependent generic type.
+// ---
+// CHECK-LABEL: sil private [transparent] [thunk] @$S20opaque_values_silgen21s510_______OpaqueSelfVyxGAA4FooPA2aEP3fooxyFTW : $@convention(witness_method: FooP) <τ_0_0> (@in_guaranteed s510_______OpaqueSelf<τ_0_0>) -> @out s510_______OpaqueSelf<τ_0_0> {
+// CHECK: bb0(%0 : $s510_______OpaqueSelf<τ_0_0>):
+// CHECK:   [[FN:%.*]] = function_ref @$S20opaque_values_silgen21s510_______OpaqueSelfV3fooACyxGyF : $@convention(method) <τ_0_0> (@in_guaranteed s510_______OpaqueSelf<τ_0_0>) -> @out s510_______OpaqueSelf<τ_0_0>
+// CHECK:   [[RESULT:%.*]] = apply [[FN]]<τ_0_0>(%0) : $@convention(method) <τ_0_0> (@in_guaranteed s510_______OpaqueSelf<τ_0_0>) -> @out s510_______OpaqueSelf<τ_0_0>
+// CHECK:   return [[RESULT]] : $s510_______OpaqueSelf<τ_0_0>
+// CHECK-LABEL: } // end sil function '$S20opaque_values_silgen21s510_______OpaqueSelfVyxGAA4FooPA2aEP3fooxyFTW'
+struct s510_______OpaqueSelf<Base> : FooP {
+  var x: Base
+
+  func foo() -> s510_______OpaqueSelf<Base> {
+    return self
+  }
+}
+
+// Tests conditional value casts and correspondingly generated reabstraction thunk, with <T> types
+// ---
+// CHECK-LABEL: sil hidden @$S20opaque_values_silgen21s999_____condTFromAnyyyyp_xtlF : $@convention(thin) <T> (@in_guaranteed Any, @in_guaranteed T) -> () {
+// CHECK: bb0([[ARG0:%.*]] : $Any, [[ARG1:%.*]] : $T):
+// CHECK:   [[COPY__ARG:%.*]] = copy_value [[ARG]]
+// CHECK:   checked_cast_value_br [[COPY__ARG]] : $Any to $@callee_guaranteed (@in_guaranteed (Int, T)) -> @out (Int, T), bb2, bb1
+// CHECK: bb2([[THUNK_PARAM:%.*]] : $@callee_guaranteed (@in_guaranteed (Int, T)) -> @out (Int, T)):
+// CHECK:   [[THUNK_REF:%.*]] = function_ref @{{.*}} : $@convention(thin) <τ_0_0> (Int, @in_guaranteed τ_0_0, @guaranteed @callee_guaranteed (@in_guaranteed (Int, τ_0_0)) -> @out (Int, τ_0_0)) -> (Int, @out τ_0_0)
+// CHECK:   partial_apply [callee_guaranteed] [[THUNK_REF]]<T>([[THUNK_PARAM]])
+// CHECK: bb6:
+// CHECK:   return %{{.*}} : $()
+// CHECK-LABEL: } // end sil function '$S20opaque_values_silgen21s999_____condTFromAnyyyyp_xtlF'
+func s999_____condTFromAny<T>(_ x: Any, _ y: T) {
+  if let f = x as? (Int, T) -> (Int, T) {
+    _ = f(42, y)
+  }
+}
+
+// Make sure that we insert a destroy of the box even though we used an Int type.
+// CHECK-LABEL: sil @$S20opaque_values_silgen22s020_______assignToVaryyF : $@convention(thin) () -> () {
+// CHECK: bb0:
+// CHECK:   [[Y_BOX:%.*]] = alloc_box ${ var Int }, var, name "y"
+// CHECK:   [[PROJECT_Y_BOX:%.*]] = project_box [[Y_BOX]] : ${ var Int }, 0
+// CHECK:   [[X_BOX:%.*]] = alloc_box ${ var Any }, var, name "x"
+// CHECK:   [[PROJECT_X_BOX:%.*]] = project_box [[X_BOX]] : ${ var Any }, 0
+// CHECK:   [[ACCESS_PROJECT_Y_BOX:%.*]] = begin_access [read] [unknown] [[PROJECT_Y_BOX]] : $*Int
+// CHECK:   [[Y:%.*]] = load [trivial] [[ACCESS_PROJECT_Y_BOX]] : $*Int
+// CHECK:   [[Y_ANY_FOR_X:%.*]] = init_existential_value [[Y]] : $Int, $Int, $Any
+// CHECK:   store [[Y_ANY_FOR_X]] to [init] [[PROJECT_X_BOX]]
+// CHECK:   [[ACCESS_PROJECT_Y_BOX:%.*]] = begin_access [read] [unknown] [[PROJECT_Y_BOX]] : $*Int
+// CHECK:   [[Y:%.*]] = load [trivial] [[ACCESS_PROJECT_Y_BOX]] : $*Int
+// CHECK:   [[Y_ANY_FOR_Z:%.*]] = init_existential_value [[Y]] : $Int, $Int, $Any
+// CHECK:   destroy_value [[Y_ANY_FOR_Z]]
+// CEHCK:   destroy_value [[X_BOX]]
+// CHECK:   destroy_value [[Y_BOX]]
+// CHECK: } // end sil function '$S20opaque_values_silgen22s020_______assignToVaryyF'
+public func s020_______assignToVar() {
+  var y: Int = 3
+  var x: Any = y
+  let z: Any = y
+}
+
+// s250_________testBoxT continued Test Implicit Value Construction under Opaque value mode
+// ---
+// CHECK-LABEL: sil hidden @$S20opaque_values_silgen3BoxV1tACyxGx_tcfC : $@convention(method) <T> (@in T, @thin Box<T>.Type) -> @out Box<T> {
+// CHECK: bb0([[ARG0:%.*]] : $T, [[ARG1:%.*]] : $@thin Box<T>.Type):
+// CHECK:   [[RETVAL:%.*]] = struct $Box<T> ([[ARG0]] : $T)
+// CHECK:   return [[RETVAL]] : $Box<T>
+// CHECK-LABEL: } // end sil function '$S20opaque_values_silgen3BoxV1tACyxGx_tcfC'
+
+// s270_convOptAnyStruct continued Test: reabstraction thunk helper
+// ---
+// CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] @$S20opaque_values_silgen9AnyStructVSgACIegnr_A2DIegnr_TR : $@convention(thin) (@in_guaranteed Optional<AnyStruct>, @guaranteed @callee_guaranteed (@in_guaranteed Optional<AnyStruct>) -> @out AnyStruct) -> @out Optional<AnyStruct> {
+// CHECK: bb0([[ARG0:%.*]] : $Optional<AnyStruct>, [[ARG1:%.*]] : $@callee_guaranteed (@in_guaranteed Optional<AnyStruct>) -> @out AnyStruct):
+// CHECK:   [[APPLYARG:%.*]] = apply [[ARG1]]([[ARG0]]) : $@callee_guaranteed (@in_guaranteed Optional<AnyStruct>) -> @out AnyStruct
+// CHECK:   [[RETVAL:%.*]] = enum $Optional<AnyStruct>, #Optional.some!enumelt.1, [[APPLYARG]] : $AnyStruct
+// CHECK:   return [[RETVAL]] : $Optional<AnyStruct>
+// CHECK-LABEL: } // end sil function '$S20opaque_values_silgen9AnyStructVSgACIegnr_A2DIegnr_TR'
+
+// s300__convETupleToAny continued Test: reabstraction of () to Any
+// ---
+// CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] @$SIeg_ypIegr_TR : $@convention(thin) (@guaranteed @callee_guaranteed () -> ()) -> @out Any {
+// CHECK: bb0([[ARG:%.*]] : $@callee_guaranteed () -> ()):
+// CHECK:   [[ASTACK:%.*]] = alloc_stack $Any
+// CHECK:   [[IADDR:%.*]] = init_existential_addr [[ASTACK]] : $*Any, $()
+// CHECK:   [[APPLYARG:%.*]] = apply [[ARG]]() : $@callee_guaranteed () -> ()
+// CHECK:   [[LOAD_EXIST:%.*]] = load [trivial] [[IADDR]] : $*()
+// CHECK:   [[RETVAL:%.*]] = init_existential_value [[LOAD_EXIST]] : $(), $(), $Any
+// CHECK:   return [[RETVAL]] : $Any
+// CHECK-LABEL: } // end sil function '$SIeg_ypIegr_TR'
+
+// s310_convIntTupleAny continued Test: reabstraction of non-empty tuple to Any
+// ---
+// CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] @$SS2iIegdd_ypIegr_TR : $@convention(thin) (@guaranteed @callee_guaranteed () -> (Int, Int)) -> @out Any {
+// CHECK: bb0([[ARG:%.*]] : $@callee_guaranteed () -> (Int, Int)):
+// CHECK:   [[ASTACK:%.*]] = alloc_stack $Any
+// CHECK:   [[IADDR:%.*]] = init_existential_addr [[ASTACK]] : $*Any, $(Int, Int)
+// CHECK:   [[TADDR0:%.*]] = tuple_element_addr [[IADDR]] : $*(Int, Int), 0
+// CHECK:   [[TADDR1:%.*]] = tuple_element_addr [[IADDR]] : $*(Int, Int), 1
+// CHECK:   [[APPLYARG:%.*]] = apply [[ARG]]() : $@callee_guaranteed () -> (Int, Int)
+// CHECK:   [[TEXTRACT0:%.*]] = tuple_extract [[APPLYARG]] : $(Int, Int), 0
+// CHECK:   [[TEXTRACT1:%.*]] = tuple_extract [[APPLYARG]] : $(Int, Int), 1
+// CHECK:   store [[TEXTRACT0]] to [trivial] [[TADDR0]] : $*Int
+// CHECK:   store [[TEXTRACT1]] to [trivial] [[TADDR1]] : $*Int
+// CHECK:   [[LOAD_EXIST:%.*]] = load [trivial] [[IADDR]] : $*(Int, Int)
+// CHECK:   [[RETVAL:%.*]] = init_existential_value [[LOAD_EXIST]] : $(Int, Int), $(Int, Int), $Any
+// CHECK:   dealloc_stack [[ASTACK]] : $*Any
+// CHECK:   return [[RETVAL]] : $Any
+// CHECK-LABEL: } // end sil function '$SS2iIegdd_ypIegr_TR'
+
+
+// CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] @{{.*}} : $@convention(thin) (Int, Int, Int, Int, Int, @guaranteed @callee_guaranteed (@in_guaranteed (Int, (Int, (Int, Int)), Int)) -> @out (Int, (Int, (Int, Int)), Int)) -> (Int, Int, Int, Int, Int)
+// CHECK: bb0([[ARG0:%.*]] : $Int, [[ARG1:%.*]] : $Int, [[ARG2:%.*]] : $Int, [[ARG3:%.*]] : $Int, [[ARG4:%.*]] : $Int, [[ARG5:%.*]] : $@callee_guaranteed (@in_guaranteed (Int, (Int, (Int, Int)), Int)) -> @out (Int, (Int, (Int, Int)), Int)):
+// CHECK:   [[TUPLE_TO_APPLY0:%.*]] = tuple ([[ARG2]] : $Int, [[ARG3]] : $Int)
+// CHECK:   [[TUPLE_TO_APPLY1:%.*]] = tuple ([[ARG1]] : $Int, [[TUPLE_TO_APPLY0]] : $(Int, Int))
+// CHECK:   [[TUPLE_TO_APPLY2:%.*]] = tuple ([[ARG0]] : $Int, [[TUPLE_TO_APPLY1]] : $(Int, (Int, Int)), [[ARG4]] : $Int)
+// CHECK:   [[TUPLE_APPLY:%.*]] = apply [[ARG5]]([[TUPLE_TO_APPLY2]]) : $@callee_guaranteed (@in_guaranteed (Int, (Int, (Int, Int)), Int)) -> @out (Int, (Int, (Int, Int)), Int)
+// CHECK:   [[RET_VAL0:%.*]] = tuple_extract [[TUPLE_APPLY]] : $(Int, (Int, (Int, Int)), Int), 0
+// CHECK:   [[TUPLE_EXTRACT1:%.*]] = tuple_extract [[TUPLE_APPLY]] : $(Int, (Int, (Int, Int)), Int), 1
+// CHECK:   [[RET_VAL1:%.*]] = tuple_extract [[TUPLE_EXTRACT1]] : $(Int, (Int, Int)), 0
+// CHECK:   [[TUPLE_EXTRACT2:%.*]] = tuple_extract [[TUPLE_EXTRACT1]] : $(Int, (Int, Int)), 1
+// CHECK:   [[RET_VAL2:%.*]] = tuple_extract [[TUPLE_EXTRACT2]]  : $(Int, Int), 0
+// CHECK:   [[RET_VAL3:%.*]] = tuple_extract [[TUPLE_EXTRACT2]]  : $(Int, Int), 1
+// CHECK:   [[RET_VAL4:%.*]] = tuple_extract [[TUPLE_APPLY]] : $(Int, (Int, (Int, Int)), Int), 2
+// CHECK:   [[RET_VAL_TUPLE:%.*]] = tuple ([[RET_VAL0]] : $Int, [[RET_VAL1]] : $Int, [[RET_VAL2]] : $Int, [[RET_VAL3]] : $Int, [[RET_VAL4]] : $Int)
+// CHECK:   return [[RET_VAL_TUPLE]] : $(Int, Int, Int, Int, Int)
+// CHECK-LABEL: } // end sil function '{{.*}}'
+
+// CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] @{{.*}} : $@convention(thin) <T> (Int, @in_guaranteed T, @guaranteed @callee_guaranteed (@in_guaranteed (Int, T)) -> @out (Int, T)) -> (Int, @out T) {
+// CHECK: bb0([[ARG0:%.*]] : $Int, [[ARG1:%.*]] : $T, [[ARG2:%.*]] : $@callee_guaranteed (@in_guaranteed (Int, T)) -> @out (Int, T)):
+// CHECK:   [[TUPLE_TO_APPLY:%.*]] = tuple ([[ARG0]] : $Int, [[ARG1]] : $T)
+// CHECK:   [[TUPLE_APPLY:%.*]] = apply [[ARG2]]([[TUPLE_TO_APPLY]]) : $@callee_guaranteed (@in_guaranteed (Int, T)) -> @out (Int, T)
+// CHECK:   [[TUPLE_BORROW:%.*]] = begin_borrow [[TUPLE_APPLY]] : $(Int, T)
+// CHECK:   [[RET_VAL0:%.*]] = tuple_extract [[TUPLE_BORROW]] : $(Int, T), 0
+// CHECK:   [[TUPLE_EXTRACT:%.*]] = tuple_extract [[TUPLE_BORROW]] : $(Int, T), 1
+// CHECK:   [[RET_VAL1:%.*]] = copy_value [[TUPLE_EXTRACT]] : $T
+// CHECK:   end_borrow [[TUPLE_BORROW]] from [[TUPLE_APPLY]] : $(Int, T), $(Int, T)
+// CHECK:   destroy_value [[TUPLE_APPLY]] : $(Int, T)
+// CHECK:   [[RET_VAL_TUPLE:%.*]] = tuple ([[RET_VAL0]] : $Int, [[RET_VAL1]] : $T)
+// CHECK:   return [[RET_VAL_TUPLE]] : $(Int, T)
+// CHECK-LABEL: } // end sil function '{{.*}}'
+
+
+// Tests LogicalPathComponent's writeback for opaque value types
+// ---
+// CHECK-LABEL: sil @$Ss10DictionaryV20opaque_values_silgenE22inoutAccessOfSubscript3keyyq__tF : $@convention(method) <Key, Value where Key : Hashable> (@in_guaranteed Value, @inout Dictionary<Key, Value>) -> () {
+// CHECK: bb0([[ARG0:%.*]] : $Value, [[ARG1:%.*]] : $*Dictionary<Key, Value>):
+// CHECK:   [[WRITE:%.*]] = begin_access [modify] [unknown] [[ARG1]] : $*Dictionary<Key, Value>
+// CHECK:   [[OPTIONAL_ALLOC:%.*]] = alloc_stack $Optional<Value>
+// CHECK:   switch_enum_addr [[OPTIONAL_ALLOC]] : $*Optional<Value>, case #Optional.some!enumelt.1: bb2, case #Optional.none!enumelt: bb1
+// CHECK: bb2:
+// CHECK:   [[OPTIONAL_LOAD:%.*]] = load [take] [[OPTIONAL_ALLOC]] : $*Optional<Value>
+// CHECK:   apply {{.*}}<Key, Value>([[OPTIONAL_LOAD]], {{.*}}, [[WRITE]]) : $@convention(method) <τ_0_0, τ_0_1 where τ_0_0 : Hashable> (@in Optional<τ_0_1>, @in τ_0_1, @inout Dictionary<τ_0_0, τ_0_1>) -> ()
+// CHECK:   return %{{.*}} : $()
+// CHECK-LABEL: } // end sil function '$Ss10DictionaryV20opaque_values_silgenE22inoutAccessOfSubscript3keyyq__tF'
+
+// Tests materializeForSet's createSetterCallback for opaque values
+// ---
+// CHECK-LABEL: sil shared [transparent] [serialized] @$Ss10DictionaryV20opaque_values_silgenEyq_Sgq_cimytfU_ : $@convention(method) <Key, Value where Key : Hashable> (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout Dictionary<Key, Value>, @thick Dictionary<Key, Value>.Type) -> () {
+// CHECK: bb0([[ARG0:%.*]] : $Builtin.RawPointer, [[ARG1:%.*]] : $*Builtin.UnsafeValueBuffer, [[ARG2:%.*]] : $*Dictionary<Key, Value>, [[ARG3:%.*]] : $@thick Dictionary<Key, Value>.Type):
+// CHECK:   [[PROJ_VAL1:%.*]] = project_value_buffer $Value in [[ARG1]] : $*Builtin.UnsafeValueBuffer
+// CHECK:   [[LOAD_VAL1:%.*]] = load [take] [[PROJ_VAL1]] : $*Value
+// CHECK:   [[ADDR_VAL0:%.*]] = pointer_to_address [[ARG0]] : $Builtin.RawPointer to [strict] $*Optional<Value>
+// CHECK:   [[LOAD_VAL0:%.*]] = load [take] [[ADDR_VAL0]] : $*Optional<Value>
+// CHECK:   apply {{.*}}<Key, Value>([[LOAD_VAL0]], [[LOAD_VAL1]], [[ARG2]]) : $@convention(method) <τ_0_0, τ_0_1 where τ_0_0 : Hashable> (@in Optional<τ_0_1>, @in τ_0_1, @inout Dictionary<τ_0_0, τ_0_1>) -> ()
+// CHECK:   return %{{.*}} : $()
+// CHECK-LABEL: } // end sil function '$Ss10DictionaryV20opaque_values_silgenEyq_Sgq_cimytfU_'
+extension Dictionary {
+  public subscript(key: Value) -> Value? {
+    @inline(__always)
+    get {
+      return key
+    }
+    set(newValue) {
+    }
+  }
+  
+  public mutating func inoutAccessOfSubscript(key: Value) {
+    func increment(x: inout Value) { }
+
+    increment(x: &self[key]!)
+  }
+}
+
+// s400______maybeCloneP continued Test: reabstraction thunk
+// ---
+// CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] @$SxSgIegr_20opaque_values_silgen8Clonable_pSgIegr_AbCRzlTR : $@convention(thin) <τ_0_0 where τ_0_0 : Clonable> (@guaranteed @callee_guaranteed () -> @out Optional<τ_0_0>) -> @out Optional<Clonable> {
+// CHECK: bb0([[ARG:%.*]] : $@callee_guaranteed () -> @out Optional<τ_0_0>):
+// CHECK:   [[APPLY_ARG:%.*]] = apply [[ARG]]() : $@callee_guaranteed () -> @out Optional<τ_0_0>
+// CHECK:   switch_enum [[APPLY_ARG]] : $Optional<τ_0_0>, case #Optional.some!enumelt.1: bb2, case #Optional.none!enumelt: bb1
+// CHECK: bb1:
+// CHECK:   [[ONONE:%.*]] = enum $Optional<Clonable>, #Optional.none!enumelt
+// CHECK:   br bb3([[ONONE]] : $Optional<Clonable>)
+// CHECK: bb2([[ENUM_SOME:%.*]] : $τ_0_0):
+// CHECK:   [[INIT_OPAQUE:%.*]] = init_existential_value [[ENUM_SOME]] : $τ_0_0, $τ_0_0, $Clonable
+// CHECK:   [[OSOME:%.*]] = enum $Optional<Clonable>, #Optional.some!enumelt.1, [[INIT_OPAQUE]] : $Clonable
+// CHECK:   br bb3([[OSOME]] : $Optional<Clonable>)
+// CHECK: bb3([[RETVAL:%.*]] : $Optional<Clonable>):
+// CHECK:   return [[RETVAL]] : $Optional<Clonable>
+// CHECK-LABEL: } // end sil function '$SxSgIegr_20opaque_values_silgen8Clonable_pSgIegr_AbCRzlTR'
+
+// s320__transImplodeAny continued Test: reabstraction thunk
+// ---
+// CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] @$SypIegn_S2iIegyy_TR : $@convention(thin) (Int, Int, @guaranteed @callee_guaranteed (@in_guaranteed Any) -> ()) -> () {
+// CHECK: bb0([[ARG0:%.*]] : $Int, [[ARG1:%.*]] : $Int, [[ARG2:%.*]] : $@callee_guaranteed (@in_guaranteed Any) -> ()):
+// CHECK:   [[ASTACK:%.*]] = alloc_stack $Any
+// CHECK:   [[IADDR:%.*]] = init_existential_addr [[ASTACK]] : $*Any, $(Int, Int)
+// CHECK:   [[TADDR0:%.*]] = tuple_element_addr [[IADDR]] : $*(Int, Int), 0
+// CHECK:   store [[ARG0]] to [trivial] [[TADDR0]] : $*Int
+// CHECK:   [[TADDR1:%.*]] = tuple_element_addr [[IADDR]] : $*(Int, Int), 1
+// CHECK:   store [[ARG1]] to [trivial] [[TADDR1]] : $*Int
+// CHECK:   [[LOAD_EXIST:%.*]] = load [trivial] [[IADDR]] : $*(Int, Int)
+// CHECK:   [[INIT_OPAQUE:%.*]] = init_existential_value [[LOAD_EXIST]] : $(Int, Int), $(Int, Int), $Any
+// CHECK:   [[BORROWED_INIT_OPAQUE:%.*]] = begin_borrow [[INIT_OPAQUE]]
+// CHECK:   [[APPLYARG:%.*]] = apply [[ARG2]]([[BORROWED_INIT_OPAQUE]]) : $@callee_guaranteed (@in_guaranteed Any) -> ()
+// CHECK:   dealloc_stack [[ASTACK]] : $*Any
+// CHECK:   return %{{.*}} : $()
+// CHECK-LABEL: } // end sil function '$SypIegn_S2iIegyy_TR'
diff --git a/test/SILGen/plus_zero_opaque_values_silgen_lib.swift b/test/SILGen/plus_zero_opaque_values_silgen_lib.swift
new file mode 100644
index 0000000..fa43ee0
--- /dev/null
+++ b/test/SILGen/plus_zero_opaque_values_silgen_lib.swift
@@ -0,0 +1,77 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -enable-sil-ownership -enable-sil-opaque-values -emit-sorted-sil -Xllvm -sil-full-demangle -parse-stdlib -parse-as-library -emit-silgen -module-name Swift %s | %FileCheck %s
+// UNSUPPORTED: resilient_stdlib
+
+precedencegroup AssignmentPrecedence { assignment: true }
+
+enum Optional<Wrapped> {
+  case none
+  case some(Wrapped)
+}
+
+protocol EmptyP {}
+
+struct String { var ptr: Builtin.NativeObject }
+
+// Tests Empty protocol + Builtin.NativeObject enum (including opaque tuples as a return value)
+// ---
+// CHECK-LABEL: sil hidden @$Ss21s010______PAndS_casesyyF : $@convention(thin) () -> () {
+// CHECK: bb0:
+// CHECK:   [[MTYPE:%.*]] = metatype $@thin PAndSEnum.Type
+// CHECK:   [[EAPPLY:%.*]] = apply {{.*}}([[MTYPE]]) : $@convention(thin) (@thin PAndSEnum.Type) -> @owned @callee_guaranteed (@in_guaranteed EmptyP, @guaranteed String) -> @out PAndSEnum
+// CHECK:   destroy_value [[EAPPLY]]
+// CHECK:   return %{{.*}} : $()
+// CHECK-LABEL: } // end sil function '$Ss21s010______PAndS_casesyyF'
+func s010______PAndS_cases() {
+  _ = PAndSEnum.A
+}
+
+// Test emitBuiltinReinterpretCast.
+// ---
+// CHECK-LABEL: sil hidden @$Ss21s020__________bitCast_2toq_x_q_mtr0_lF : $@convention(thin) <T, U> (@in_guaranteed T, @thick U.Type) -> @out U {
+// CHECK: bb0([[ARG:%.*]] : @guaranteed $T,
+// CHECK: [[CAST:%.*]] = unchecked_bitwise_cast [[ARG]] : $T to $U
+// CHECK: [[RET:%.*]] = copy_value [[CAST]] : $U
+// CHECK-NOT: destroy_value [[COPY]] : $T
+// CHECK: return [[RET]] : $U
+// CHECK-LABEL: } // end sil function '$Ss21s020__________bitCast_2toq_x_q_mtr0_lF'
+func s020__________bitCast<T, U>(_ x: T, to type: U.Type) -> U {
+  return Builtin.reinterpretCast(x)
+}
+
+// Test emitBuiltinCastReference
+// ---
+// CHECK-LABEL: sil hidden @$Ss21s030__________refCast_2toq_x_q_mtr0_lF : $@convention(thin) <T, U> (@in_guaranteed T, @thick U.Type) -> @out U {
+// CHECK: bb0([[ARG:%.*]] : @guaranteed $T, %1 : @trivial $@thick U.Type):
+// CHECK: [[COPY:%.*]] = copy_value [[ARG]] : $T
+// CHECK: [[SRC:%.*]] = alloc_stack $T
+// CHECK: store [[COPY]] to [init] [[SRC]] : $*T
+// CHECK: [[DEST:%.*]] = alloc_stack $U
+// CHECK: unchecked_ref_cast_addr  T in [[SRC]] : $*T to U in [[DEST]] : $*U
+// CHECK: [[LOAD:%.*]] = load [take] [[DEST]] : $*U
+// CHECK: dealloc_stack [[DEST]] : $*U
+// CHECK: dealloc_stack [[SRC]] : $*T
+// CHECK-NOT: destroy_value [[ARG]] : $T
+// CHECK: return [[LOAD]] : $U
+// CHECK-LABEL: } // end sil function '$Ss21s030__________refCast_2toq_x_q_mtr0_lF'
+func s030__________refCast<T, U>(_ x: T, to: U.Type) -> U {
+  return Builtin.castReference(x)
+}
+
+// Init of Empty protocol + Builtin.NativeObject enum (including opaque tuples as a return value)
+// ---
+// CHECK-LABEL: sil shared [transparent] @$Ss9PAndSEnumO1AyABs6EmptyP_p_SStcABmF : $@convention(method) (@in EmptyP, @owned String, @thin PAndSEnum.Type) -> @out PAndSEnum {
+// CHECK: bb0([[ARG0:%.*]] : @owned $EmptyP, [[ARG1:%.*]]  : @owned $String, [[ARG2:%.*]] : @trivial $@thin PAndSEnum.Type):
+// CHECK:   [[RTUPLE:%.*]] = tuple ([[ARG0]] : $EmptyP, [[ARG1]] : $String)
+// CHECK:   [[RETVAL:%.*]] = enum $PAndSEnum, #PAndSEnum.A!enumelt.1, [[RTUPLE]] : $(EmptyP, String)
+// CHECK:   return [[RETVAL]] : $PAndSEnum
+// CHECK-LABEL: } // end sil function '$Ss9PAndSEnumO1AyABs6EmptyP_p_SStcABmF'
+// CHECK-LABEL: sil shared [transparent] [thunk] @$Ss9PAndSEnumO1AyABs6EmptyP_p_SStcABmFTc : $@convention(thin) (@thin PAndSEnum.Type) -> @owned @callee_guaranteed (@in_guaranteed EmptyP, @guaranteed String) -> @out PAndSEnum {
+// CHECK: bb0([[ARG:%.*]] : @trivial $@thin PAndSEnum.Type):
+// CHECK:   [[RETVAL:%.*]] = partial_apply [callee_guaranteed] {{.*}}([[ARG]]) : $@convention(method) (@in EmptyP, @owned String, @thin PAndSEnum.Type) -> @out PAndSEnum
+// CHECK:   [[CANONICAL_THUNK_FN:%.*]] = function_ref @$Ss6EmptyP_pSSs9PAndSEnumOIegixr_sAA_pSSACIegngr_TR : $@convention(thin) (@in_guaranteed EmptyP, @guaranteed String, @guaranteed @callee_guaranteed (@in EmptyP, @owned String) -> @out PAndSEnum) -> @out PAndSEnum
+// CHECK:   [[CANONICAL_THUNK:%.*]] = partial_apply [callee_guaranteed] [[CANONICAL_THUNK_FN]]([[RETVAL]])
+// CHECK:   return [[CANONICAL_THUNK]] : $@callee_guaranteed (@in_guaranteed EmptyP, @guaranteed String) -> @out PAndSEnum
+// CHECK-LABEL: } // end sil function '$Ss9PAndSEnumO1AyABs6EmptyP_p_SStcABmFTc'
+enum PAndSEnum { case A(EmptyP, String) }
+
diff --git a/test/SILGen/plus_zero_optional-cast.swift b/test/SILGen/plus_zero_optional-cast.swift
new file mode 100644
index 0000000..0c0ca83
--- /dev/null
+++ b/test/SILGen/plus_zero_optional-cast.swift
@@ -0,0 +1,226 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership %s | %FileCheck %s
+
+class A {}
+class B : A {}
+
+// CHECK-LABEL: sil hidden @$S4main3fooyyAA1ACSgF : $@convention(thin) (@guaranteed Optional<A>) -> () {
+// CHECK:    bb0([[ARG:%.*]] : @guaranteed $Optional<A>):
+// CHECK:      [[X:%.*]] = alloc_box ${ var Optional<B> }, var, name "x"
+// CHECK-NEXT: [[PB:%.*]] = project_box [[X]]
+//   Check whether the temporary holds a value.
+// CHECK:      [[ARG_COPY:%.*]] = copy_value [[ARG]]
+// CHECK:      [[T1:%.*]] = select_enum [[ARG_COPY]]
+// CHECK-NEXT: cond_br [[T1]], [[IS_PRESENT:bb.*]], [[NOT_PRESENT:bb[0-9]+]]
+//
+// CHECK:    [[NOT_PRESENT]]:
+// CHECK:      br [[NOT_PRESENT_FINISH:bb[0-9]+]]
+//
+//   If so, pull the value out and check whether it's a B.
+// CHECK:    [[IS_PRESENT]]:
+// CHECK-NEXT: [[VAL:%.*]] = unchecked_enum_data [[ARG_COPY]] : $Optional<A>, #Optional.some!enumelt.1
+// CHECK-NEXT: [[X_VALUE:%.*]] = init_enum_data_addr [[PB]] : $*Optional<B>, #Optional.some
+// CHECK-NEXT: checked_cast_br [[VAL]] : $A to $B, [[IS_B:bb.*]], [[NOT_B:bb[0-9]+]]
+//
+//   If so, materialize that and inject it into x.
+// CHECK:    [[IS_B]]([[T0:%.*]] : @owned $B):
+// CHECK-NEXT: store [[T0]] to [init] [[X_VALUE]] : $*B
+// CHECK-NEXT: inject_enum_addr [[PB]] : $*Optional<B>, #Optional.some
+// CHECK-NEXT: br [[CONT:bb[0-9]+]]
+//
+//   If not, destroy_value the A and inject nothing into x.
+// CHECK:    [[NOT_B]]([[ORIGINAL_VALUE:%.*]] : @owned $A):
+// CHECK-NEXT: destroy_value [[ORIGINAL_VALUE]]
+// CHECK-NEXT: inject_enum_addr [[PB]] : $*Optional<B>, #Optional.none
+// CHECK-NEXT: br [[CONT]]
+//
+//   Finish the present path.
+// CHECK:    [[CONT]]:
+// CHECK-NEXT: br [[RETURN_BB:bb[0-9]+]]
+//
+//   Finish.
+// CHECK:    [[RETURN_BB]]:
+// CHECK-NEXT: destroy_value [[X]]
+// CHECK-NOT: destroy_value [[ARG]]
+// CHECK-NEXT: tuple
+// CHECK-NEXT: return
+//
+//   Finish the not-present path.
+// CHECK:    [[NOT_PRESENT_FINISH]]:
+// CHECK-NEXT: inject_enum_addr [[PB]] {{.*}}none
+// CHECK-NEXT: br [[RETURN_BB]]
+func foo(_ y : A?) {
+  var x = (y as? B)
+}
+
+// CHECK-LABEL: sil hidden @$S4main3baryyAA1ACSgSgSgSgF : $@convention(thin) (@guaranteed Optional<Optional<Optional<Optional<A>>>>) -> () {
+// CHECK:    bb0([[ARG:%.*]] : @guaranteed $Optional<Optional<Optional<Optional<A>>>>):
+// CHECK:      [[X:%.*]] = alloc_box ${ var Optional<Optional<Optional<B>>> }, var, name "x"
+// CHECK-NEXT: [[PB:%.*]] = project_box [[X]]
+// -- Check for some(...)
+// CHECK-NEXT: [[ARG_COPY:%.*]] = copy_value [[ARG]]
+// CHECK:      [[T1:%.*]] = select_enum [[ARG_COPY]]
+// CHECK-NEXT: cond_br [[T1]], [[P:bb.*]], [[NIL_DEPTH_1:bb[0-9]+]]
+//
+// CHECK: [[NIL_DEPTH_1]]:
+// CHECK:   br [[FINISH_NIL_0:bb[0-9]+]]
+//
+//   If so, drill down another level and check for some(some(...)).
+// CHECK:    [[P]]:
+// CHECK-NEXT: [[VALUE_OOOA:%.*]] = unchecked_enum_data [[ARG_COPY]]
+// CHECK:      [[T1:%.*]] = select_enum [[VALUE_OOOA]]
+// CHECK-NEXT: cond_br [[T1]], [[PP:bb.*]], [[NIL_DEPTH_2:bb[0-9]+]]
+//
+// CHECK: [[NIL_DEPTH_2]]:
+// CHECK:   br [[FINISH_NIL_0]]
+//
+//   If so, drill down another level and check for some(some(some(...))).
+// CHECK:    [[PP]]:
+// CHECK-NEXT: [[VALUE_OOA:%.*]] = unchecked_enum_data [[VALUE_OOOA]]
+// CHECK:      [[T1:%.*]] = select_enum [[VALUE_OOA]]
+// CHECK-NEXT: cond_br [[T1]], [[PPP:bb.*]], [[NIL_DEPTH_3:bb[0-9]+]]
+//
+// CHECK: [[NIL_DEPTH_3]]:
+// CHECK:   br [[FINISH_NIL_1:bb[0-9]+]]
+//
+//   If so, drill down another level and check for some(some(some(some(...)))).
+// CHECK:    [[PPP]]:
+// CHECK-NEXT: [[VALUE_OA:%.*]] = unchecked_enum_data [[VALUE_OOA]]
+// CHECK:      [[T1:%.*]] = select_enum [[VALUE_OA]]
+// CHECK-NEXT: cond_br [[T1]], [[PPPP:bb.*]], [[NIL_DEPTH_4:bb[0-9]+]]
+//
+// CHECK: [[NIL_DEPTH_4]]:
+// CHECK:   br [[FINISH_NIL_2:bb[0-9]+]]
+//
+//   If so, pull out the A and check whether it's a B.
+// CHECK:    [[PPPP]]:
+// CHECK-NEXT: [[VAL:%.*]] = unchecked_enum_data [[VALUE_OA]]
+// CHECK-NEXT: checked_cast_br [[VAL]] : $A to $B, [[IS_B:bb.*]], [[NOT_B:bb[0-9]+]]
+//
+//   If so, inject it back into an optional.
+//   TODO: We're going to switch back out of this; we really should peephole it.
+// CHECK:    [[IS_B]]([[T0:%.*]] : @owned $B):
+// CHECK-NEXT: enum $Optional<B>, #Optional.some!enumelt.1, [[T0]]
+// CHECK-NEXT: br [[SWITCH_OB2:bb[0-9]+]](
+//
+//   If not, inject nothing into an optional.
+// CHECK:    [[NOT_B]]([[ORIGINAL_VALUE:%.*]] : @owned $A):
+// CHECK-NEXT: destroy_value [[ORIGINAL_VALUE]]
+// CHECK-NEXT: enum $Optional<B>, #Optional.none!enumelt
+// CHECK-NEXT: br [[SWITCH_OB2]](
+//
+//   Switch out on the value in [[OB2]].
+// CHECK:    [[SWITCH_OB2]]([[VAL:%[0-9]+]] : @owned $Optional<B>):
+// CHECK:    [[T0:%.*]] = select_enum [[VAL]]
+// CHECK:    cond_br [[T0]], [[HAVE_B:bb[0-9]+]], [[FINISH_NIL_4:bb[0-9]+]]
+//
+// CHECK:    [[FINISH_NIL_4]]:
+// CHECK:      br [[FINISH_NIL_0]]
+//
+// CHECK:    [[HAVE_B]]:
+// CHECK:      [[UNWRAPPED_VAL:%.*]] = unchecked_enum_data [[VAL]]
+// CHECK:      [[REWRAPPED_VAL:%.*]] = enum $Optional<B>, #Optional.some!enumelt.1, [[UNWRAPPED_VAL]]
+// CHECK:      br [[DONE_DEPTH0:bb[0-9]+]]
+//
+// CHECK:    [[DONE_DEPTH0]](
+// CHECK-NEXT: enum $Optional<Optional<B>>, #Optional.some!enumelt.1,
+// CHECK-NEXT: br [[DONE_DEPTH1:bb[0-9]+]]
+//
+//   Set X := some(OOB).
+// CHECK:    [[DONE_DEPTH1]]
+// CHECK-NEXT: enum $Optional<Optional<Optional<B>>>, #Optional.some!enumelt.1,
+// CHECK: br [[DONE_DEPTH2:bb[0-9]+]]
+// CHECK:    [[DONE_DEPTH2]]
+// CHECK-NEXT: destroy_value [[X]]
+// CHECK-NOT: destroy_value %0
+// CHECK:      return
+//
+//   On various failure paths, set OOB := nil.
+// CHECK:    [[FINISH_NIL_2]]:
+// CHECK-NEXT: enum $Optional<B>, #Optional.none!enumelt
+// CHECK-NEXT: br [[DONE_DEPTH0]]
+//
+// CHECK:    [[FINISH_NIL_1]]:
+// CHECK-NEXT: enum $Optional<Optional<B>>, #Optional.none!enumelt
+// CHECK-NEXT: br [[DONE_DEPTH1]]
+//
+//   On various failure paths, set X := nil.
+// CHECK:    [[FINISH_NIL_0]]:
+// CHECK-NEXT: inject_enum_addr [[PB]] {{.*}}none
+// CHECK-NEXT: br [[DONE_DEPTH2]]
+//   Done.
+func bar(_ y : A????) {
+  var x = (y as? B??)
+}
+
+
+// CHECK-LABEL: sil hidden @$S4main3bazyyyXlSgF : $@convention(thin) (@guaranteed Optional<AnyObject>) -> () {
+// CHECK:       bb0([[ARG:%.*]] : @guaranteed $Optional<AnyObject>):
+// CHECK:         [[X:%.*]] = alloc_box ${ var Optional<B> }, var, name "x"
+// CHECK-NEXT:    [[PB:%.*]] = project_box [[X]]
+// CHECK-NEXT:    [[ARG_COPY:%.*]] = copy_value [[ARG]]
+// CHECK:         [[T1:%.*]] = select_enum [[ARG_COPY]]
+// CHECK:       bb1:
+// CHECK:         [[VAL:%.*]] = unchecked_enum_data [[ARG_COPY]]
+// CHECK-NEXT:    [[X_VALUE:%.*]] = init_enum_data_addr [[PB]] : $*Optional<B>, #Optional.some
+// CHECK-NEXT:    checked_cast_br [[VAL]] : $AnyObject to $B, [[IS_B:bb.*]], [[NOT_B:bb[0-9]+]]
+// CHECK:       [[IS_B]]([[CASTED_VALUE:%.*]] : @owned $B):
+// CHECK:         store [[CASTED_VALUE]] to [init] [[X_VALUE]]
+// CHECK:       [[NOT_B]]([[ORIGINAL_VALUE:%.*]] : @owned $AnyObject):
+// CHECK:         destroy_value [[ORIGINAL_VALUE]]
+// CHECK: } // end sil function '$S4main3bazyyyXlSgF'
+func baz(_ y : AnyObject?) {
+  var x = (y as? B)
+}
+
+
+// <rdar://problem/17013042> T! <-> T? conversions should not produce a diamond
+
+// CHECK-LABEL: sil hidden @$S4main07opt_to_B8_trivialySiSgACF
+// CHECK:       bb0(%0 : @trivial $Optional<Int>):
+// CHECK-NEXT:  debug_value %0 : $Optional<Int>, let, name "x"
+// CHECK-NEXT:  return %0 : $Optional<Int>
+// CHECK-NEXT:}
+func opt_to_opt_trivial(_ x: Int?) -> Int! {
+  return x
+}
+
+// CHECK-LABEL: sil hidden @$S4main07opt_to_B10_referenceyAA1CCSgAEF
+// CHECK:  bb0([[ARG:%.*]] : @guaranteed $Optional<C>):
+// CHECK:    debug_value [[ARG]] : $Optional<C>, let, name "x"
+// CHECK:    [[RESULT:%.*]] = copy_value [[ARG]]
+// CHECK-NOT:    destroy_value [[ARG]]
+// CHECK:    return [[RESULT]] : $Optional<C>
+// CHECK: } // end sil function '$S4main07opt_to_B10_referenceyAA1CCSgAEF'
+func opt_to_opt_reference(_ x : C!) -> C? { return x }
+
+// CHECK-LABEL: sil hidden @$S4main07opt_to_B12_addressOnly{{[_0-9a-zA-Z]*}}F
+// CHECK:       bb0(%0 : @trivial $*Optional<T>, %1 : @trivial $*Optional<T>):
+// CHECK-NEXT:  debug_value_addr %1 : $*Optional<T>, let, name "x"
+// CHECK-NEXT:  copy_addr %1 to [initialization] %0
+// CHECK-NOT:  destroy_addr %1
+func opt_to_opt_addressOnly<T>(_ x : T!) -> T? { return x }
+
+class C {}
+
+public struct TestAddressOnlyStruct<T> {
+  func f(_ a : T?) {}
+  
+  // CHECK-LABEL: sil hidden @$S4main21TestAddressOnlyStructV8testCall{{[_0-9a-zA-Z]*}}F
+  // CHECK: bb0(%0 : @trivial $*Optional<T>, %1 : @trivial $TestAddressOnlyStruct<T>):
+  // CHECK: apply {{.*}}<T>(%0, %1)
+  func testCall(_ a : T!) {
+    f(a)
+  }
+}
+
+// CHECK-LABEL: sil hidden @$S4main35testContextualInitOfNonAddrOnlyTypeyySiSgF
+// CHECK: bb0(%0 : @trivial $Optional<Int>):
+// CHECK-NEXT: debug_value %0 : $Optional<Int>, let, name "a"
+// CHECK-NEXT: [[X:%.*]] = alloc_box ${ var Optional<Int> }, var, name "x"
+// CHECK-NEXT: [[PB:%.*]] = project_box [[X]]
+// CHECK-NEXT: store %0 to [trivial] [[PB]] : $*Optional<Int>
+// CHECK-NEXT: destroy_value [[X]] : ${ var Optional<Int> }
+func testContextualInitOfNonAddrOnlyType(_ a : Int?) {
+  var x: Int! = a
+}
diff --git a/test/SILGen/plus_zero_optional.swift b/test/SILGen/plus_zero_optional.swift
new file mode 100644
index 0000000..038a0ab
--- /dev/null
+++ b/test/SILGen/plus_zero_optional.swift
@@ -0,0 +1,105 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership %s | %FileCheck %s
+
+func testCall(_ f: (() -> ())?) {
+  f?()
+}
+// CHECK:    sil hidden @{{.*}}testCall{{.*}}
+// CHECK:    bb0([[T0:%.*]] : @guaranteed $Optional<@callee_guaranteed () -> ()>):
+// CHECK:      [[T0_COPY:%.*]] = copy_value [[T0]]
+// CHECK:      [[T1:%.*]] = select_enum [[T0_COPY]]
+// CHECK-NEXT: cond_br [[T1]], [[SOME:bb[0-9]+]], [[NONE:bb[0-9]+]]
+
+// CHECK: [[NONE]]:
+// CHECK:   br [[NOTHING_BLOCK_EXIT:bb[0-9]+]]
+
+//   If it does, project and load the value out of the implicitly unwrapped
+//   optional...
+
+// CHECK: [[SOME]]:
+// CHECK-NEXT: [[FN0:%.*]] = unchecked_enum_data [[T0_COPY]] : $Optional<@callee_guaranteed () -> ()>, #Optional.some!enumelt.1
+//   .... then call it
+// CHECK-NEXT: [[B:%.*]] = begin_borrow [[FN0]]
+// CHECK-NEXT: apply [[B]]()
+// CHECK:      destroy_value [[FN0]]
+// CHECK:      br [[EXIT:bb[0-9]+]](
+
+//   (first nothing block)
+// CHECK:    [[NOTHING_BLOCK_EXIT]]:
+// CHECK-NEXT: enum $Optional<()>, #Optional.none!enumelt
+// CHECK-NEXT: br [[EXIT]]
+// CHECK: } // end sil function '$S8optional8testCallyyyycSgF'
+
+func testAddrOnlyCallResult<T>(_ f: (() -> T)?) {
+  var f = f
+  var x = f?()
+}
+// CHECK-LABEL: sil hidden @{{.*}}testAddrOnlyCallResult{{.*}} : $@convention(thin) <T> (@guaranteed Optional<@callee_guaranteed () -> @out T>) -> ()
+// CHECK:    bb0([[T0:%.*]] : @guaranteed $Optional<@callee_guaranteed () -> @out T>):
+// CHECK: [[F:%.*]] = alloc_box $<τ_0_0> { var Optional<@callee_guaranteed () -> @out τ_0_0> } <T>, var, name "f"
+// CHECK-NEXT: [[PBF:%.*]] = project_box [[F]]
+// CHECK: [[T0_COPY:%.*]] = copy_value [[T0]]
+// CHECK: store [[T0_COPY]] to [init] [[PBF]]
+// CHECK-NEXT: [[X:%.*]] = alloc_box $<τ_0_0> { var Optional<τ_0_0> } <T>, var, name "x"
+// CHECK-NEXT: [[PBX:%.*]] = project_box [[X]]
+// CHECK-NEXT: [[TEMP:%.*]] = init_enum_data_addr [[PBX]]
+// CHECK-NEXT: [[READ:%.*]] = begin_access [read] [unknown] [[PBF]]
+//   Check whether 'f' holds a value.
+// CHECK:      [[T1:%.*]] = select_enum_addr [[READ]]
+// CHECK-NEXT: cond_br [[T1]], bb2, bb1
+//   If so, pull out the value...
+// CHECK:    bb2:
+// CHECK-NEXT: [[T1:%.*]] = unchecked_take_enum_data_addr [[READ]]
+// CHECK-NEXT: [[T0:%.*]] = load [copy] [[T1]]
+// CHECK-NEXT: end_access [[READ]]
+//   ...evaluate the rest of the suffix...
+// CHECK:     [[B:%.*]] = begin_borrow [[T0]]
+// CHECK-NEXT: apply [[B]]([[TEMP]])
+//   ...and coerce to T?
+// CHECK: inject_enum_addr [[PBX]] {{.*}}some
+// CHECK:     destroy_value [[T0]]
+// CHECK-NEXT: br bb3
+//   Continuation block.
+// CHECK:    bb3
+// CHECK-NEXT: destroy_value [[X]]
+// CHECK-NEXT: destroy_value [[F]]
+// CHECK-NOT: destroy_value %0
+// CHECK-NEXT: [[T0:%.*]] = tuple ()
+// CHECK-NEXT: return [[T0]] : $()
+
+//   Nothing block.
+// CHECK:    bb4:
+// CHECK-NEXT: inject_enum_addr [[PBX]] {{.*}}none
+// CHECK-NEXT: br bb3
+
+
+// <rdar://problem/15180622>
+
+func wrap<T>(_ x: T) -> T? { return x }
+
+// CHECK-LABEL: sil hidden @$S8optional16wrap_then_unwrap{{[_0-9a-zA-Z]*}}F
+func wrap_then_unwrap<T>(_ x: T) -> T {
+  // CHECK:   switch_enum_addr {{.*}}, case #Optional.some!enumelt.1: [[OK:bb[0-9]+]], case #Optional.none!enumelt: [[FAIL:bb[0-9]+]]
+  // CHECK: [[FAIL]]:
+  // CHECK:   unreachable
+  // CHECK: [[OK]]:
+  // CHECK:   unchecked_take_enum_data_addr
+  return wrap(x)!
+}
+
+// CHECK-LABEL: sil hidden @$S8optional10tuple_bind{{[_0-9a-zA-Z]*}}F
+func tuple_bind(_ x: (Int, String)?) -> String? {
+  return x?.1
+  // CHECK:   cond_br {{%.*}}, [[NONNULL:bb[0-9]+]], [[NULL:bb[0-9]+]]
+  // CHECK: [[NONNULL]]:
+  // CHECK:   [[STRING:%.*]] = tuple_extract {{%.*}} : $(Int, String), 1
+  // CHECK-NOT: destroy_value [[STRING]]
+}
+
+// rdar://21883752 - We were crashing on this function because the deallocation happened
+// out of scope.
+// CHECK-LABEL: sil hidden @$S8optional16crash_on_deallocyys10DictionaryVySiSaySiGGFfA_
+func crash_on_dealloc(_ dict : [Int : [Int]] = [:]) {
+  var dict = dict
+  dict[1]?.append(2)
+}
diff --git a/test/SILGen/plus_zero_optional_lvalue.swift b/test/SILGen/plus_zero_optional_lvalue.swift
new file mode 100644
index 0000000..d2a4f17
--- /dev/null
+++ b/test/SILGen/plus_zero_optional_lvalue.swift
@@ -0,0 +1,74 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership %s | %FileCheck %s
+
+// CHECK-LABEL: sil hidden @$S15optional_lvalue07assign_a1_B0yySiSgz_SitF
+// CHECK:         [[WRITE:%.*]] = begin_access [modify] [unknown] %0 : $*Optional<Int>
+// CHECK:         [[PRECOND:%.*]] = function_ref @$Ss30_diagnoseUnexpectedNilOptional{{[_0-9a-zA-Z]*}}F
+// CHECK:         apply [[PRECOND]](
+// CHECK:         [[PAYLOAD:%.*]] = unchecked_take_enum_data_addr [[WRITE]] : $*Optional<Int>, #Optional.some!enumelt.1
+// CHECK:         assign {{%.*}} to [[PAYLOAD]]
+func assign_optional_lvalue(_ x: inout Int?, _ y: Int) {
+  x! = y
+}
+
+// CHECK-LABEL: sil hidden @$S15optional_lvalue011assign_iuo_B0yySiSgz_SitF
+// CHECK:         [[WRITE:%.*]] = begin_access [modify] [unknown] %0 : $*Optional<Int>
+// CHECK:         [[PRECOND:%.*]] = function_ref @$Ss30_diagnoseUnexpectedNilOptional{{[_0-9a-zA-Z]*}}F
+// CHECK:         apply [[PRECOND]](
+// CHECK:         [[PAYLOAD:%.*]] = unchecked_take_enum_data_addr [[WRITE]] : $*Optional<Int>, #Optional.some!enumelt.1
+// CHECK:         assign {{%.*}} to [[PAYLOAD]]
+func assign_iuo_lvalue(_ x: inout Int!, _ y: Int) {
+  x! = y
+}
+
+struct S {
+  var x: Int
+
+  var computed: Int {
+    get {}
+    set {}
+  }
+}
+
+// CHECK-LABEL: sil hidden @$S15optional_lvalue011assign_iuo_B9_implicityyAA1SVSgz_SitF
+// CHECK:         [[WRITE:%.*]] = begin_access [modify] [unknown] %0 : $*Optional<S>
+// CHECK:         [[SOME:%.*]] = unchecked_take_enum_data_addr [[WRITE]]
+// CHECK:         [[X:%.*]] = struct_element_addr [[SOME]]
+func assign_iuo_lvalue_implicit(_ s: inout S!, _ y: Int) {
+  s.x = y
+}
+
+struct Struct<T> {
+  var value: T?
+}
+
+// CHECK-LABEL: sil hidden @$S15optional_lvalue07assign_a1_B13_reabstractedyyAA6StructVyS2icGz_S2ictF
+// CHECK:         [[REABSTRACT:%.*]] = function_ref @$SS2iIegyd_S2iIegnr_TR
+// CHECK:         [[REABSTRACTED:%.*]] = partial_apply [callee_guaranteed] [[REABSTRACT]]
+// CHECK:         assign [[REABSTRACTED]] to {{%.*}} : $*@callee_guaranteed (@in_guaranteed Int) -> @out Int
+func assign_optional_lvalue_reabstracted(_ x: inout Struct<(Int) -> Int>,
+                                         _ y: @escaping (Int) -> Int) {
+  x.value! = y
+}
+
+// CHECK-LABEL: sil hidden @$S15optional_lvalue07assign_a1_B9_computedySiAA1SVSgz_SitF
+// CHECK:         function_ref @$S15optional_lvalue1SV8computedSivs
+// CHECK:         function_ref @$S15optional_lvalue1SV8computedSivg
+func assign_optional_lvalue_computed(_ x: inout S?, _ y: Int) -> Int {
+  x!.computed = y
+  return x!.computed
+}
+
+func generate_int() -> Int { return 0 }
+
+// CHECK-LABEL: sil hidden @$S15optional_lvalue013assign_bound_a1_B0yySiSgzF
+// CHECK:         select_enum_addr
+// CHECK:         cond_br {{%.*}}, [[SOME:bb[0-9]+]], [[NONE:bb[0-9]+]]
+// CHECK:       [[SOME]]:
+// CHECK:         [[PAYLOAD:%.*]] = unchecked_take_enum_data_addr
+// CHECK:         [[FN:%.*]] = function_ref
+// CHECK:         [[T0:%.*]] = apply [[FN]]()
+// CHECK:         assign [[T0]] to [[PAYLOAD]]
+func assign_bound_optional_lvalue(_ x: inout Int?) {
+  x? = generate_int()
+}
diff --git a/test/SILGen/plus_zero_partial_apply_generic.swift b/test/SILGen/plus_zero_partial_apply_generic.swift
new file mode 100644
index 0000000..dc1f4c5
--- /dev/null
+++ b/test/SILGen/plus_zero_partial_apply_generic.swift
@@ -0,0 +1,91 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership %s | %FileCheck %s
+
+protocol Panda {
+  associatedtype Cuddles : Foo
+}
+
+protocol Foo {
+  static func staticFunc()
+  func instanceFunc()
+
+  func makesSelfNonCanonical<T : Panda>(_: T) where T.Cuddles == Self
+}
+
+// CHECK-LABEL: sil hidden @$S21partial_apply_generic14getStaticFunc1{{[_0-9a-zA-Z]*}}F
+func getStaticFunc1<T: Foo>(t: T.Type) -> () -> () {
+// CHECK: [[REF:%.*]] = function_ref @$S21partial_apply_generic3FooP10staticFunc{{[_0-9a-zA-Z]*}}FZ
+// CHECK-NEXT: apply [[REF]]<T>(%0)
+  return t.staticFunc
+// CHECK-NEXT: return
+}
+
+// CHECK-LABEL: sil shared [thunk] @$S21partial_apply_generic3FooP10staticFunc{{[_0-9a-zA-Z]*}}FZ
+// CHECK: [[REF:%.*]] = witness_method $Self, #Foo.staticFunc!1
+// CHECK-NEXT: partial_apply [callee_guaranteed] [[REF]]<Self>(%0)
+// CHECK-NEXT: return
+
+// CHECK-LABEL: sil hidden @$S21partial_apply_generic14getStaticFunc2{{[_0-9a-zA-Z]*}}F
+func getStaticFunc2<T: Foo>(t: T) -> () -> () {
+// CHECK: [[REF:%.*]] = function_ref @$S21partial_apply_generic3FooP10staticFunc{{[_0-9a-zA-Z]*}}FZ
+// CHECK: apply [[REF]]<T>
+  return T.staticFunc
+// CHECK-NOT: destroy_addr %0 : $*T
+// CHECK-NEXT: return
+}
+
+// CHECK-LABEL: sil hidden @$S21partial_apply_generic16getInstanceFunc1{{[_0-9a-zA-Z]*}}F
+func getInstanceFunc1<T: Foo>(t: T) -> () -> () {
+// CHECK-NOT: alloc_stack $T
+// CHECK-NOT: copy_addr %0 to [initialization]
+// CHECK: [[REF:%.*]] = function_ref @$S21partial_apply_generic3FooP12instanceFunc{{[_0-9a-zA-Z]*}}F
+// CHECK-NEXT: apply [[REF]]<T>
+  return t.instanceFunc
+// CHECK-NOT: dealloc_stack
+// CHECK-NOT: destroy_addr %0 : $*T
+// CHECK-NEXT: return
+}
+
+// CHECK-LABEL: sil shared [thunk] @$S21partial_apply_generic3FooP12instanceFunc{{[_0-9a-zA-Z]*}}F
+// CHECK: bb0([[ARG:%.*]] : @trivial $*Self):
+// CHECK: [[REF:%.*]] = witness_method $Self, #Foo.instanceFunc!1
+// CHECK-NEXT: [[STACK:%.*]] = alloc_stack $Self
+// CHECK-NEXT: copy_addr [[ARG]] to [initialization] [[STACK]]
+// CHECK-NEXT: partial_apply [callee_guaranteed] [[REF]]<Self>([[STACK]])
+// CHECK-NEXT: dealloc_stack
+// CHECK-NEXT: return
+
+// CHECK-LABEL: sil hidden @$S21partial_apply_generic16getInstanceFunc2{{[_0-9a-zA-Z]*}}F
+func getInstanceFunc2<T: Foo>(t: T) -> (T) -> () -> () {
+// CHECK: [[REF:%.*]] = function_ref @$S21partial_apply_generic3FooP12instanceFunc{{[_0-9a-zA-Z]*}}F
+// CHECK-NEXT: partial_apply [callee_guaranteed] [[REF]]<T>(
+  return T.instanceFunc
+// CHECK-NOT: destroy_addr %0 : $*
+// CHECK-NEXT: return
+}
+
+// CHECK-LABEL: sil hidden @$S21partial_apply_generic16getInstanceFunc3{{[_0-9a-zA-Z]*}}F
+func getInstanceFunc3<T: Foo>(t: T.Type) -> (T) -> () -> () {
+// CHECK: [[REF:%.*]] = function_ref @$S21partial_apply_generic3FooP12instanceFunc{{[_0-9a-zA-Z]*}}F
+// CHECK-NEXT: partial_apply [callee_guaranteed] [[REF]]<T>(
+  return t.instanceFunc
+// CHECK-NEXT: return
+}
+
+// CHECK-LABEL: sil hidden @$S21partial_apply_generic23getNonCanonicalSelfFunc1tyq_cxcxm_t7CuddlesQy_RszAA5PandaR_r0_lF : $@convention(thin) <T, U where T == U.Cuddles, U : Panda> (@thick T.Type) -> @owned @callee_guaranteed (@in_guaranteed T) -> @owned @callee_guaranteed (@in_guaranteed U) -> () {
+func getNonCanonicalSelfFunc<T : Foo, U : Panda>(t: T.Type) -> (T) -> (U) -> () where U.Cuddles == T {
+// CHECK: [[REF:%.*]] = function_ref @$S21partial_apply_generic3FooP21makesSelfNonCanonicalyyqd__7CuddlesQyd__RszAA5PandaRd__lFTc : $@convention(thin) <τ_0_0><τ_1_0 where τ_0_0 == τ_1_0.Cuddles, τ_1_0 : Panda> (@in_guaranteed τ_0_0) -> @owned @callee_guaranteed (@in_guaranteed τ_1_0) -> ()
+// CHECK-NEXT: [[CLOSURE:%.*]] = partial_apply [callee_guaranteed] [[REF]]<T, U>()
+  return t.makesSelfNonCanonical
+// CHECK-NEXT: return [[CLOSURE]]
+}
+
+// curry thunk of Foo.makesSelfNonCanonical<A where ...> (A1) -> ()
+// CHECK-LABEL: sil shared [thunk] @$S21partial_apply_generic3FooP21makesSelfNonCanonicalyyqd__7CuddlesQyd__RszAA5PandaRd__lFTc : $@convention(thin) <Self><T where Self == T.Cuddles, T : Panda> (@in_guaranteed Self) -> @owned @callee_guaranteed (@in_guaranteed T) -> () {
+// CHECK: bb0([[ARG:%.*]] : @trivial $*Self):
+// CHECK: [[REF:%.*]] = witness_method $Self, #Foo.makesSelfNonCanonical!1 : <Self><T where Self == T.Cuddles, T : Panda> (Self) -> (T) -> () : $@convention(witness_method: Foo) <τ_0_0><τ_1_0 where τ_0_0 == τ_1_0.Cuddles, τ_1_0 : Panda> (@in_guaranteed τ_1_0, @in_guaranteed τ_0_0) -> ()
+// CHECK-NEXT: [[STACK:%.*]] = alloc_stack $Self
+// CHECK-NEXT: copy_addr [[ARG]] to [initialization] [[STACK]] : $*Self
+// CHECK-NEXT: [[CLOSURE:%.*]] = partial_apply [callee_guaranteed] [[REF]]<Self, T>([[STACK]])
+// CHECK-NEXT: dealloc_stack
+// CHECK-NEXT: return [[CLOSURE]]
diff --git a/test/SILGen/plus_zero_partial_apply_protocol.swift b/test/SILGen/plus_zero_partial_apply_protocol.swift
new file mode 100644
index 0000000..ba46add
--- /dev/null
+++ b/test/SILGen/plus_zero_partial_apply_protocol.swift
@@ -0,0 +1,159 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -enable-sil-ownership -emit-silgen -primary-file %s | %FileCheck %s
+// RUN: %target-swift-frontend -enable-sil-ownership -emit-ir -primary-file %s
+
+protocol Clonable {
+  func clone() -> Self
+  func maybeClone() -> Self?
+  func cloneMetatype() -> Self.Type
+  func getCloneFn() -> () -> Self
+
+  func genericClone<T>(t: T) -> Self
+  func genericGetCloneFn<T>(t: T) -> () -> Self
+}
+
+//===----------------------------------------------------------------------===//
+// Partial apply of methods returning Self-derived types
+//===----------------------------------------------------------------------===//
+
+// CHECK-LABEL: sil hidden @$S22partial_apply_protocol12testClonable1cyAA0E0_p_tF : $@convention(thin) (@in_guaranteed Clonable) -> ()
+func testClonable(c: Clonable) {
+  // CHECK: [[THUNK_FN:%.*]] = function_ref @$SxIegr_22partial_apply_protocol8Clonable_pIegr_AaBRzlTR : $@convention(thin) <τ_0_0 where τ_0_0 : Clonable> (@guaranteed @callee_guaranteed () -> @out τ_0_0) -> @out Clonable
+  // CHECK: [[THUNK:%.*]] = partial_apply [callee_guaranteed] [[THUNK_FN]]<@opened("{{.*}}") Clonable>({{.*}})
+  let _: () -> Clonable = c.clone
+
+  // CHECK: [[THUNK_FN:%.*]] = function_ref @$SxSgIegr_22partial_apply_protocol8Clonable_pSgIegr_AbCRzlTR : $@convention(thin) <τ_0_0 where τ_0_0 : Clonable> (@guaranteed @callee_guaranteed () -> @out Optional<τ_0_0>) -> @out Optional<Clonable>
+  // CHECK: [[THUNK:%.*]] = partial_apply [callee_guaranteed] [[THUNK_FN]]<@opened("{{.*}}") Clonable>({{.*}})
+  let _: () -> Clonable? = c.maybeClone
+
+  // CHECK: [[THUNK_FN:%.*]] = function_ref @$SxXMTIegd_22partial_apply_protocol8Clonable_pXmTIegd_AaBRzlTR : $@convention(thin) <τ_0_0 where τ_0_0 : Clonable> (@guaranteed @callee_guaranteed () -> @thick τ_0_0.Type) -> @thick Clonable.Type
+  // CHECK: [[THUNK:%.*]] = partial_apply [callee_guaranteed] [[THUNK_FN]]<@opened("{{.*}}") Clonable>({{.*}}) : $@convention(thin) <τ_0_0 where τ_0_0 : Clonable> (@guaranteed @callee_guaranteed () -> @thick τ_0_0.Type) -> @thick Clonable.Type
+  let _: () -> Clonable.Type = c.cloneMetatype
+
+  // CHECK: [[METHOD_FN:%.*]] = witness_method $@opened("{{.*}}") Clonable, #Clonable.getCloneFn!1 : {{.*}}, {{.*}} : $*@opened("{{.*}}") Clonable : $@convention(witness_method: Clonable) <τ_0_0 where τ_0_0 : Clonable> (@in_guaranteed τ_0_0) -> @owned @callee_guaranteed () -> @out τ_0_0
+  // CHECK: [[RESULT:%.*]] = apply [[METHOD_FN]]<@opened("{{.*}}") Clonable>({{.*}}) : $@convention(witness_method: Clonable) <τ_0_0 where τ_0_0 : Clonable> (@in_guaranteed τ_0_0) -> @owned @callee_guaranteed () -> @out τ_0_0
+  // CHECK: [[THUNK_FN:%.*]] = function_ref @$SxIegr_22partial_apply_protocol8Clonable_pIegr_AaBRzlTR : $@convention(thin) <τ_0_0 where τ_0_0 : Clonable> (@guaranteed @callee_guaranteed () -> @out τ_0_0) -> @out Clonable
+  // CHECK: [[THUNK:%.*]] = partial_apply [callee_guaranteed] [[THUNK_FN]]<@opened("{{.*}}") Clonable>([[RESULT]])
+  let _: () -> Clonable = c.getCloneFn()
+
+  // CHECK: [[THUNK_FN:%.*]] = function_ref @$SxIegr_Iego_22partial_apply_protocol8Clonable_pIegr_Iego_AaBRzlTR
+  // CHECK: [[THUNK:%.*]] = partial_apply [callee_guaranteed] [[THUNK_FN]]<@opened("{{.*}}") Clonable>({{.*}})
+  let _: () -> () -> Clonable = c.getCloneFn
+}
+
+// CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] @$SxIegr_22partial_apply_protocol8Clonable_pIegr_AaBRzlTR : $@convention(thin) <τ_0_0 where τ_0_0 : Clonable> (@guaranteed @callee_guaranteed () -> @out τ_0_0) -> @out Clonable
+// CHECK:       bb0(%0 : @trivial $*Clonable, %1 : @guaranteed $@callee_guaranteed () -> @out τ_0_0):
+// CHECK-NEXT:    [[INNER_RESULT:%.*]] = alloc_stack $τ_0_0
+// CHECK-NEXT:    apply %1([[INNER_RESULT]])
+// CHECK-NEXT:    [[OUTER_RESULT:%.*]] = init_existential_addr %0
+// CHECK-NEXT:    copy_addr [take] [[INNER_RESULT]] to [initialization] [[OUTER_RESULT]]
+// CHECK-NEXT:    [[EMPTY:%.*]] = tuple ()
+// CHECK-NEXT:    dealloc_stack [[INNER_RESULT]]
+// CHECK-NEXT:    return [[EMPTY]]
+
+// FIXME: This is horribly inefficient, too much alloc_stack / copy_addr!
+
+// CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] @$SxSgIegr_22partial_apply_protocol8Clonable_pSgIegr_AbCRzlTR : $@convention(thin) <τ_0_0 where τ_0_0 : Clonable> (@guaranteed @callee_guaranteed () -> @out Optional<τ_0_0>) -> @out Optional<Clonable>
+// CHECK:       bb0(%0 : @trivial $*Optional<Clonable>, %1 : @guaranteed $@callee_guaranteed () -> @out Optional<τ_0_0>):
+// CHECK-NEXT:    [[INNER_RESULT:%.*]] = alloc_stack $Optional<τ_0_0>
+// CHECK-NEXT:    apply %1([[INNER_RESULT]])
+// CHECK-NEXT:    [[OUTER_RESULT:%.*]] = alloc_stack $Optional<Clonable>
+// CHECK-NEXT:    switch_enum_addr [[INNER_RESULT]] : $*Optional<{{.*}}>, case #Optional.some!enumelt.1: [[SOME_BB:bb[0-9]+]],
+// CHECK:       [[SOME_BB]]:
+// CHECK-NEXT:    [[INNER_RESULT_ADDR:%.*]] = unchecked_take_enum_data_addr [[INNER_RESULT]]
+// CHECK-NEXT:    [[SOME_PAYLOAD:%.*]] = alloc_stack $Clonable
+// CHECK-NEXT:    [[SOME_PAYLOAD_ADDR:%.*]] = init_existential_addr [[SOME_PAYLOAD]]
+// CHECK-NEXT:    copy_addr [take] [[INNER_RESULT_ADDR]] to [initialization] [[SOME_PAYLOAD_ADDR]]
+// CHECK-NEXT:    [[OUTER_RESULT_ADDR:%.*]] = init_enum_data_addr [[OUTER_RESULT]]
+// CHECK-NEXT:    copy_addr [take] [[SOME_PAYLOAD]] to [initialization] [[OUTER_RESULT_ADDR]]
+// CHECK-NEXT:    inject_enum_addr [[OUTER_RESULT]]
+// CHECK-NEXT:    dealloc_stack [[SOME_PAYLOAD]]
+// CHECK-NEXT:    br bb3
+// CHECK:       bb2:
+// CHECK-NEXT:    inject_enum_addr [[OUTER_RESULT]]
+// CHECK-NEXT:    br bb3
+// CHECK:       bb3:
+// CHECK-NEXT:    copy_addr [take] [[OUTER_RESULT]] to [initialization] %0
+// CHECK-NEXT:    [[EMPTY:%.*]] = tuple ()
+// CHECK-NEXT:    dealloc_stack [[OUTER_RESULT]]
+// CHECK-NEXT:    dealloc_stack [[INNER_RESULT]]
+// CHECK-NEXT:    return [[EMPTY]]
+
+// CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] @$SxXMTIegd_22partial_apply_protocol8Clonable_pXmTIegd_AaBRzlTR : $@convention(thin) <τ_0_0 where τ_0_0 : Clonable> (@guaranteed @callee_guaranteed () -> @thick τ_0_0.Type) -> @thick Clonable.Type
+// CHECK:       bb0(%0 : @guaranteed $@callee_guaranteed () -> @thick τ_0_0.Type):
+// CHECK-NEXT:    [[INNER_RESULT:%.*]] = apply %0()
+// CHECK-NEXT:    [[OUTER_RESULT:%.*]] = init_existential_metatype [[INNER_RESULT]]
+// CHECK-NEXT:    return [[OUTER_RESULT]]
+
+// CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] @$SxIegr_Iego_22partial_apply_protocol8Clonable_pIegr_Iego_AaBRzlTR : $@convention(thin) <τ_0_0 where τ_0_0 : Clonable> (@guaranteed @callee_guaranteed () -> @owned @callee_guaranteed () -> @out τ_0_0) -> @owned @callee_guaranteed () -> @out Clonable
+// CHECK:       bb0(%0 : @guaranteed $@callee_guaranteed () -> @owned @callee_guaranteed () -> @out τ_0_0):
+// CHECK-NEXT:    [[INNER_RESULT:%.*]] = apply %0()
+// CHECK:         [[THUNK_FN:%.*]] = function_ref @$SxIegr_22partial_apply_protocol8Clonable_pIegr_AaBRzlTR
+// CHECK-NEXT:    [[OUTER_RESULT:%.*]] = partial_apply [callee_guaranteed] [[THUNK_FN]]<τ_0_0>([[INNER_RESULT]])
+// CHECK-NEXT:    return [[OUTER_RESULT]]
+
+//===----------------------------------------------------------------------===//
+// Partial apply of methods returning Self-derived types from generic context
+//
+// Make sure the thunk only has the context generic parameters if needed!
+//===----------------------------------------------------------------------===//
+
+// CHECK-LABEL: sil hidden @$S22partial_apply_protocol28testClonableInGenericContext1c1tyAA0E0_p_xtlF : $@convention(thin) <T> (@in_guaranteed Clonable, @in_guaranteed T) -> ()
+func testClonableInGenericContext<T>(c: Clonable, t: T) {
+  // CHECK: [[THUNK_FN:%.*]] = function_ref @$SxIegr_22partial_apply_protocol8Clonable_pIegr_AaBRzlTR : $@convention(thin) <τ_0_0 where τ_0_0 : Clonable> (@guaranteed @callee_guaranteed () -> @out τ_0_0) -> @out Clonable
+  // CHECK: [[THUNK:%.*]] = partial_apply [callee_guaranteed] [[THUNK_FN]]<@opened("{{.*}}") Clonable>({{.*}})
+  let _: () -> Clonable = c.clone
+
+  // CHECK: [[THUNK_FN:%.*]] = function_ref @$SxSgIegr_22partial_apply_protocol8Clonable_pSgIegr_AbCRzlTR : $@convention(thin) <τ_0_0 where τ_0_0 : Clonable> (@guaranteed @callee_guaranteed () -> @out Optional<τ_0_0>) -> @out Optional<Clonable>
+  // CHECK: [[THUNK:%.*]] = partial_apply [callee_guaranteed] [[THUNK_FN]]<@opened("{{.*}}") Clonable>({{.*}}) : $@convention(thin) <τ_0_0 where τ_0_0 : Clonable> (@guaranteed @callee_guaranteed () -> @out Optional<τ_0_0>) -> @out Optional<Clonable>
+  let _: () -> Clonable? = c.maybeClone
+
+  // CHECK: [[THUNK_FN:%.*]] = function_ref @$SxXMTIegd_22partial_apply_protocol8Clonable_pXmTIegd_AaBRzlTR : $@convention(thin) <τ_0_0 where τ_0_0 : Clonable> (@guaranteed @callee_guaranteed () -> @thick τ_0_0.Type) -> @thick Clonable.Type
+  // CHECK: [[THUNK:%.*]] = partial_apply [callee_guaranteed] [[THUNK_FN]]<@opened("{{.*}}") Clonable>({{.*}}) : $@convention(thin) <τ_0_0 where τ_0_0 : Clonable> (@guaranteed @callee_guaranteed () -> @thick τ_0_0.Type) -> @thick Clonable.Type
+  let _: () -> Clonable.Type = c.cloneMetatype
+
+  // CHECK: [[METHOD_FN:%.*]] = witness_method $@opened("{{.*}}") Clonable, #Clonable.getCloneFn!1 : {{.*}}, {{.*}} : $*@opened("{{.*}}") Clonable : $@convention(witness_method: Clonable) <τ_0_0 where τ_0_0 : Clonable> (@in_guaranteed τ_0_0) -> @owned @callee_guaranteed () -> @out τ_0_0
+  // CHECK: [[RESULT:%.*]] = apply [[METHOD_FN]]<@opened("{{.*}}") Clonable>({{.*}}) : $@convention(witness_method: Clonable) <τ_0_0 where τ_0_0 : Clonable> (@in_guaranteed τ_0_0) -> @owned @callee_guaranteed () -> @out τ_0_0
+  // CHECK: [[THUNK_FN:%.*]] = function_ref @$SxIegr_22partial_apply_protocol8Clonable_pIegr_AaBRzlTR : $@convention(thin) <τ_0_0 where τ_0_0 : Clonable> (@guaranteed @callee_guaranteed () -> @out τ_0_0) -> @out Clonable
+  // CHECK: [[THUNK:%.*]] = partial_apply [callee_guaranteed] [[THUNK_FN]]<@opened("{{.*}}") Clonable>([[RESULT]]) : $@convention(thin) <τ_0_0 where τ_0_0 : Clonable> (@guaranteed @callee_guaranteed () -> @out τ_0_0) -> @out Clonable
+  let _: () -> Clonable = c.getCloneFn()
+
+  // CHECK: [[THUNK_FN:%.*]] = function_ref @$SxIegr_Iego_22partial_apply_protocol8Clonable_pIegr_Iego_AaBRzlTR
+  // CHECK: [[THUNK:%.*]] = partial_apply [callee_guaranteed] [[THUNK_FN]]<@opened("{{.*}}") Clonable>({{.*}}) : $@convention(thin) <τ_0_0 where τ_0_0 : Clonable> (@guaranteed @callee_guaranteed () -> @owned @callee_guaranteed () -> @out τ_0_0) -> @owned @callee_guaranteed () -> @out Clonable
+  let _: () -> () -> Clonable = c.getCloneFn
+
+  // CHECK: [[THUNK_FN:%.*]] = function_ref @$Sxqd__Iegnr_x22partial_apply_protocol8Clonable_pIegnr_AaBRd__r__lTR : $@convention(thin) <τ_0_0><τ_1_0 where τ_1_0 : Clonable> (@in_guaranteed τ_0_0, @guaranteed @callee_guaranteed (@in_guaranteed τ_0_0) -> @out τ_1_0) -> @out Clonable
+  // CHECK: [[THUNK:%.*]] = partial_apply [callee_guaranteed] [[THUNK_FN]]<T, @opened("{{.*}}") Clonable>({{.*}}) : $@convention(thin) <τ_0_0><τ_1_0 where τ_1_0 : Clonable> (@in_guaranteed τ_0_0, @guaranteed @callee_guaranteed (@in_guaranteed τ_0_0) -> @out τ_1_0) -> @out Clonable
+  let _: (T) -> Clonable = c.genericClone
+
+  // CHECK: [[THUNK_FN:%.*]] = function_ref @$Sxqd__Iegr_Iegno_x22partial_apply_protocol8Clonable_pIegr_Iegno_AaBRd__r__lTR : $@convention(thin) <τ_0_0><τ_1_0 where τ_1_0 : Clonable> (@in_guaranteed τ_0_0, @guaranteed @callee_guaranteed (@in_guaranteed τ_0_0) -> @owned @callee_guaranteed () -> @out τ_1_0) -> @owned @callee_guaranteed () -> @out Clonable
+  // CHECK: [[THUNK:%.*]] = partial_apply [callee_guaranteed] [[THUNK_FN]]<T, @opened("{{.*}}") Clonable>({{.*}}) : $@convention(thin) <τ_0_0><τ_1_0 where τ_1_0 : Clonable> (@in_guaranteed τ_0_0, @guaranteed @callee_guaranteed (@in_guaranteed τ_0_0) -> @owned @callee_guaranteed () -> @out τ_1_0) -> @owned @callee_guaranteed () -> @out Clonable
+  let _: (T) -> () -> Clonable = c.genericGetCloneFn
+}
+
+// CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] @$Sxqd__Iegnr_x22partial_apply_protocol8Clonable_pIegnr_AaBRd__r__lTR : $@convention(thin) <τ_0_0><τ_1_0 where τ_1_0 : Clonable> (@in_guaranteed τ_0_0, @guaranteed @callee_guaranteed (@in_guaranteed τ_0_0) -> @out τ_1_0) -> @out Clonable
+// CHECK:         bb0(%0 : @trivial $*Clonable, %1 : @trivial $*τ_0_0, %2 : @guaranteed $@callee_guaranteed (@in_guaranteed τ_0_0) -> @out τ_1_0):
+// CHECK-NEXT:      [[INNER_RESULT:%.*]] = alloc_stack $τ_1_0
+// CHECK-NEXT:      apply %2([[INNER_RESULT]], %1)
+// CHECK-NEXT:      [[OUTER_RESULT:%.*]] = init_existential_addr %0
+// CHECK-NEXT:      copy_addr [take] [[INNER_RESULT]] to [initialization] [[OUTER_RESULT]]
+// CHECK-NEXT:      [[EMPTY:%.*]] = tuple ()
+// CHECK-NEXT:      dealloc_stack [[INNER_RESULT]]
+// CHECK-NEXT:      return [[EMPTY]]
+
+// CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] @$Sxqd__Iegr_Iegno_x22partial_apply_protocol8Clonable_pIegr_Iegno_AaBRd__r__lTR : $@convention(thin) <τ_0_0><τ_1_0 where τ_1_0 : Clonable> (@in_guaranteed τ_0_0, @guaranteed @callee_guaranteed (@in_guaranteed τ_0_0) -> @owned @callee_guaranteed () -> @out τ_1_0) -> @owned @callee_guaranteed () -> @out Clonable
+// CHECK:         bb0(%0 : @trivial $*τ_0_0, %1 : @guaranteed $@callee_guaranteed (@in_guaranteed τ_0_0) -> @owned @callee_guaranteed () -> @out τ_1_0):
+// CHECK-NEXT:      [[RES:%.*]] = apply %1(%0)
+// CHECK:           [[THUNK_FN:%.*]] = function_ref @$Sqd__Iegr_22partial_apply_protocol8Clonable_pIegr_AaBRd__r__lTR
+// CHECK-NEXT:      [[RESULT:%.*]] = partial_apply [callee_guaranteed] [[THUNK_FN]]<τ_0_0, τ_1_0>([[RES]])
+// CHECK-NEXT:      return [[RESULT]]
+
+// CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] @$Sqd__Iegr_22partial_apply_protocol8Clonable_pIegr_AaBRd__r__lTR : $@convention(thin) <τ_0_0><τ_1_0 where τ_1_0 : Clonable> (@guaranteed @callee_guaranteed () -> @out τ_1_0) -> @out Clonable {
+// CHECK:         bb0(%0 : @trivial $*Clonable, %1 : @guaranteed $@callee_guaranteed () -> @out τ_1_0):
+// CHECK-NEXT:      [[INNER_RESULT:%.*]] = alloc_stack $τ_1_0
+// CHECK-NEXT:      apply %1([[INNER_RESULT]])
+// CHECK-NEXT:      [[OUTER_RESULT:%.*]] = init_existential_addr %0
+// CHECK-NEXT:      copy_addr [take] [[INNER_RESULT]] to [initialization] [[OUTER_RESULT]]
+// CHECK-NEXT:      [[EMPTY:%.*]] = tuple ()
+// CHECK-NEXT:      dealloc_stack [[INNER_RESULT:%.*]]
+// CHECK-NEXT:      return [[EMPTY]]
diff --git a/test/SILGen/plus_zero_partial_apply_protocol_class_refinement_method.swift b/test/SILGen/plus_zero_partial_apply_protocol_class_refinement_method.swift
new file mode 100644
index 0000000..ec4c8be
--- /dev/null
+++ b/test/SILGen/plus_zero_partial_apply_protocol_class_refinement_method.swift
@@ -0,0 +1,16 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership %s | %FileCheck %s
+
+protocol P { func foo() }
+protocol Q: class, P {}
+
+// CHECK-LABEL: sil hidden @$S46partial_apply_protocol_class_refinement_method0A5ApplyyyycAA1Q_pF : $@convention
+// CHECK: bb0([[ARG:%.*]] : @guaranteed $Q):
+func partialApply(_ q: Q) -> () -> () {
+  // CHECK: [[OPENED:%.*]] = open_existential_ref [[ARG]]
+  // CHECK: [[TMP:%.*]] = alloc_stack 
+  // CHECK: store_borrow [[OPENED]] to [[TMP:%.*]] :
+  // CHECK: apply {{%.*}}<{{.*}}>([[TMP]])
+  // CHECK-NEXT: dealloc_stack [[TMP]]
+  return q.foo
+}
diff --git a/test/SILGen/plus_zero_partial_apply_super.swift b/test/SILGen/plus_zero_partial_apply_super.swift
new file mode 100644
index 0000000..0a823f1
--- /dev/null
+++ b/test/SILGen/plus_zero_partial_apply_super.swift
@@ -0,0 +1,320 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %empty-directory(%t)
+// RUN: %target-swift-frontend -enable-sil-ownership -I %t -emit-module -emit-module-path=%t/resilient_struct.swiftmodule -module-name resilient_struct %S/../Inputs/resilient_struct.swift
+// RUN: %target-swift-frontend -enable-sil-ownership -I %t -emit-module -emit-module-path=%t/resilient_class.swiftmodule -module-name resilient_class %S/../Inputs/resilient_class.swift
+// RUN: %target-swift-frontend -enable-sil-ownership -enable-resilience -emit-silgen -parse-as-library -I %t %s | %FileCheck %s
+
+import resilient_class
+
+func doFoo(_ f: () -> ()) {
+  f()
+}
+
+public class Parent {
+  public init() {}
+  public func method() {}
+  public final func finalMethod() {}
+  public class func classMethod() {}
+  public final class func finalClassMethod() {}
+}
+
+public class GenericParent<A> {
+  let a: A
+  public init(a: A) {
+    self.a = a
+  }
+  public func method() {}
+  public final func finalMethod() {}
+  public class func classMethod() {}
+  public final class func finalClassMethod() {}
+}
+
+class Child : Parent {
+  // CHECK-LABEL: sil hidden @$S19partial_apply_super5ChildC6methodyyF : $@convention(method) (@guaranteed Child) -> ()
+  // CHECK: bb0([[SELF:%.*]] : @guaranteed $Child):
+  // CHECK:   [[SELF_COPY:%.*]] = copy_value [[SELF]]
+  // CHECK:   [[CASTED_SELF_COPY:%.*]] = upcast [[SELF_COPY]] : $Child to $Parent
+  // CHECK:   [[BORROWED_CASTED_SELF_COPY:%.*]] = begin_borrow [[CASTED_SELF_COPY]]
+  // CHECK:   [[SUPER_METHOD:%.*]] = function_ref @$S19partial_apply_super6ParentC6methodyyFTcTd : $@convention(thin) (@guaranteed Parent) -> @owned @callee_guaranteed () -> ()
+  // CHECK:   [[PARTIAL_APPLY:%.*]] = apply [[SUPER_METHOD]]([[BORROWED_CASTED_SELF_COPY]]) : $@convention(thin) (@guaranteed Parent) -> @owned @callee_guaranteed () -> ()
+  // CHECK:   [[CONVERT:%.*]] = convert_escape_to_noescape [[PARTIAL_APPLY]]
+  // CHECK:   [[DOFOO:%.*]] = function_ref @$S19partial_apply_super5doFooyyyyXEF : $@convention(thin) (@noescape @callee_guaranteed () -> ()) -> ()
+  // CHECK:   apply [[DOFOO]]([[CONVERT]]) : $@convention(thin) (@noescape @callee_guaranteed () -> ()) -> ()
+  // CHECK: } // end sil function '$S19partial_apply_super5ChildC6methodyyF'
+  override func method() {
+    doFoo(super.method)
+  }
+
+  // CHECK-LABEL: sil hidden @$S19partial_apply_super5ChildC11classMethodyyFZ : $@convention(method) (@thick Child.Type) -> () {
+  // CHECK: [[CASTED_SELF:%.*]] = upcast %0 : $@thick Child.Type to $@thick Parent.Type
+  // CHECK: [[SUPER_METHOD:%.*]] = function_ref @$S19partial_apply_super6ParentC11classMethodyyFZTcTd : $@convention(thin) (@thick Parent.Type) -> @owned @callee_guaranteed () -> ()
+  // CHECK: [[PARTIAL_APPLY:%.*]] = apply [[SUPER_METHOD]]([[CASTED_SELF]]) : $@convention(thin) (@thick Parent.Type) -> @owned @callee_guaranteed () -> ()
+  // CHECK:   [[CONVERT:%.*]] = convert_escape_to_noescape [[PARTIAL_APPLY]]
+  // CHECK: [[DOFOO:%.*]] = function_ref @$S19partial_apply_super5doFooyyyyXEF : $@convention(thin) (@noescape @callee_guaranteed () -> ()) -> ()
+  // CHECK: apply [[DOFOO]]([[CONVERT]]) : $@convention(thin) (@noescape @callee_guaranteed () -> ()) -> ()
+  // CHECK: } // end sil function '$S19partial_apply_super5ChildC11classMethodyyFZ'
+  override class func classMethod() {
+    doFoo(super.classMethod)
+  }
+
+  // CHECK-LABEL: sil hidden @$S19partial_apply_super5ChildC20callFinalSuperMethodyyF : $@convention(method) (@guaranteed Child) -> ()
+  // CHECK: bb0([[SELF:%.*]] : @guaranteed $Child):
+  // CHECK:     [[SELF_COPY:%.*]] = copy_value [[SELF]]
+  // CHECK:     [[CASTED_SELF_COPY:%.*]] = upcast [[SELF_COPY]] : $Child to $Parent
+  // CHECK:     [[BORROWED_CASTED_SELF_COPY:%.*]] = begin_borrow [[CASTED_SELF_COPY]]
+  // CHECK:     [[SUPER_METHOD:%.*]] = function_ref @$S19partial_apply_super6ParentC11finalMethodyyFTc : $@convention(thin) (@guaranteed Parent) -> @owned @callee_guaranteed () -> ()
+  // CHECK:     [[APPLIED_SELF:%.*]] = apply [[SUPER_METHOD]]([[BORROWED_CASTED_SELF_COPY]]) : $@convention(thin) (@guaranteed Parent) -> @owned @callee_guaranteed () -> ()
+  // CHECK:     [[CONVERT:%.*]] = convert_escape_to_noescape [[APPLIED_SELF]]
+  // CHECK:     [[DOFOO:%.*]] = function_ref @$S19partial_apply_super5doFooyyyyXEF : $@convention(thin) (@noescape @callee_guaranteed () -> ()) -> ()
+  // CHECK:     apply [[DOFOO]]([[CONVERT]]) : $@convention(thin) (@noescape @callee_guaranteed () -> ()) -> ()
+  // CHECK: } // end sil function '$S19partial_apply_super5ChildC20callFinalSuperMethodyyF'
+  func callFinalSuperMethod() {
+    doFoo(super.finalMethod)
+  }
+
+  // CHECK-LABEL: sil hidden @$S19partial_apply_super5ChildC25callFinalSuperClassMethodyyFZ : $@convention(method) (@thick Child.Type) -> ()
+  // CHECK: bb0([[ARG:%.*]] : @trivial $@thick Child.Type):
+  // CHECK:   [[CASTED_SELF:%.*]] = upcast [[ARG]] : $@thick Child.Type to $@thick Parent.Type
+  // CHECK:   [[SUPER_METHOD:%.*]] = function_ref @$S19partial_apply_super6ParentC16finalClassMethodyyFZTc : $@convention(thin) (@thick Parent.Type) -> @owned @callee_guaranteed () -> ()
+  // CHECK:   [[APPLIED_SELF:%.*]] = apply [[SUPER_METHOD]]([[CASTED_SELF]]) : $@convention(thin) (@thick Parent.Type) -> @owned @callee_guaranteed () -> ()
+  // CHECK:   [[CONVERT:%.*]] = convert_escape_to_noescape [[APPLIED_SELF]]
+  // CHECK:   [[DOFOO:%.*]] = function_ref @$S19partial_apply_super5doFooyyyyXEF : $@convention(thin) (@noescape @callee_guaranteed () -> ()) -> ()
+  // CHECK:   apply [[DOFOO]]([[CONVERT]]) : $@convention(thin) (@noescape @callee_guaranteed () -> ()) -> ()
+  // CHECK: } // end sil function '$S19partial_apply_super5ChildC25callFinalSuperClassMethodyyFZ'
+  class func callFinalSuperClassMethod() {
+    doFoo(super.finalClassMethod)
+  }
+}
+
+class GenericChild<A> : GenericParent<A> {
+  override init(a: A) {
+    super.init(a: a)
+  }
+  // CHECK-LABEL: sil hidden @$S19partial_apply_super12GenericChildC6methodyyF : $@convention(method) <A> (@guaranteed GenericChild<A>) -> ()
+  // CHECK: bb0([[SELF:%.*]] : @guaranteed $GenericChild<A>):
+  // CHECK:     [[SELF_COPY:%.*]] = copy_value [[SELF]]
+  // CHECK:     [[CASTED_SELF_COPY:%.*]] = upcast [[SELF_COPY]] : $GenericChild<A> to $GenericParent<A>
+  // CHECK:     [[BORROWED_CASTED_SELF_COPY:%.*]] = begin_borrow [[CASTED_SELF_COPY]]
+  // CHECK:     [[SUPER_METHOD:%.*]] = function_ref @$S19partial_apply_super13GenericParentC6methodyyFTcTd : $@convention(thin) <τ_0_0> (@guaranteed GenericParent<τ_0_0>) -> @owned @callee_guaranteed () -> ()
+  // CHECK:     [[PARTIAL_APPLY:%.*]] = apply [[SUPER_METHOD]]<A>([[BORROWED_CASTED_SELF_COPY]]) : $@convention(thin) <τ_0_0> (@guaranteed GenericParent<τ_0_0>) -> @owned @callee_guaranteed () -> ()
+  // CHECK:     [[CONVERT:%.*]] = convert_escape_to_noescape [[PARTIAL_APPLY]]
+  // CHECK:     [[DOFOO:%.*]] = function_ref @$S19partial_apply_super5doFooyyyyXEF : $@convention(thin) (@noescape @callee_guaranteed () -> ()) -> ()
+  // CHECK:     apply [[DOFOO]]([[CONVERT]]) : $@convention(thin) (@noescape @callee_guaranteed () -> ()) -> ()
+  // CHECK: } // end sil function '$S19partial_apply_super12GenericChildC6methodyyF'
+  override func method() {
+    doFoo(super.method)
+  }
+
+  // CHECK-LABEL: sil hidden @$S19partial_apply_super12GenericChildC11classMethodyyFZ : $@convention(method) <A> (@thick GenericChild<A>.Type) -> ()
+  // CHECK: [[CASTED_SELF:%.*]] = upcast %0 : $@thick GenericChild<A>.Type to $@thick GenericParent<A>.Type
+  // CHECK: [[SUPER_METHOD:%.*]] = function_ref @$S19partial_apply_super13GenericParentC11classMethodyyFZTcTd : $@convention(thin) <τ_0_0> (@thick GenericParent<τ_0_0>.Type) -> @owned @callee_guaranteed () -> ()
+  // CHECK: [[PARTIAL_APPLY:%.*]] = apply [[SUPER_METHOD]]<A>([[CASTED_SELF]]) : $@convention(thin) <τ_0_0> (@thick GenericParent<τ_0_0>.Type) -> @owned @callee_guaranteed () -> ()
+  // CHECK: [[CONVERT:%.*]] = convert_escape_to_noescape [[PARTIAL_APPLY]]
+  // CHECK: [[DOFOO:%.*]] = function_ref @$S19partial_apply_super5doFooyyyyXEF : $@convention(thin) (@noescape @callee_guaranteed () -> ()) -> ()
+  // CHECK: apply [[DOFOO]]([[CONVERT]]) : $@convention(thin) (@noescape @callee_guaranteed () -> ()) -> ()
+  // CHECK: } // end sil function '$S19partial_apply_super12GenericChildC11classMethodyyFZ'
+  override class func classMethod() {
+    doFoo(super.classMethod)
+  }
+}
+
+class ChildToFixedOutsideParent : OutsideParent {
+  // CHECK-LABEL: sil hidden @$S19partial_apply_super25ChildToFixedOutsideParentC6methodyyF
+  // CHECK: bb0([[SELF:%.*]] : @guaranteed $ChildToFixedOutsideParent):
+  // CHECK:   [[SELF_COPY:%.*]] = copy_value [[SELF]]
+  // CHECK:   [[CASTED_SELF_COPY:%.*]] = upcast [[SELF_COPY]] : $ChildToFixedOutsideParent to $OutsideParent
+  // CHECK:   [[BORROWED_CASTED_SELF_COPY:%.*]] = begin_borrow [[CASTED_SELF_COPY]]
+  // CHECK:   [[CASTED_SELF_COPY:%.*]] = copy_value [[BORROWED_CASTED_SELF_COPY]]
+  // CHECK:   [[BORROWED_CASTED_SELF_COPY:%.*]] = begin_borrow [[CASTED_SELF_COPY]]
+  // CHECK:   [[DOWNCAST_BORROWED_CASTED_SELF_COPY:%.*]] = unchecked_ref_cast [[BORROWED_CASTED_SELF_COPY]]
+  // Semantic SIL TODO: This super_method used to take
+  // ChildToFixedOutsideParent. Since super_method IIRC goes through
+  // objc_runtime, this shouldn't matter, but we should look into it before we
+  // turn on +0.
+  // CHECK:   [[SUPER_METHOD:%.*]] = super_method [[DOWNCAST_BORROWED_CASTED_SELF_COPY]] : $OutsideParent, #OutsideParent.method!1 : (OutsideParent) -> () -> (), $@convention(method) (@guaranteed OutsideParent) -> ()
+  // CHECK:   [[PARTIAL_APPLY:%.*]] = partial_apply [callee_guaranteed] [[SUPER_METHOD]]([[CASTED_SELF_COPY]]) : $@convention(method) (@guaranteed OutsideParent) -> ()
+  // CHECK:   [[CONVERT:%.*]] = convert_escape_to_noescape [[PARTIAL_APPLY]]
+  // CHECK:   [[DOFOO:%.*]] = function_ref @$S19partial_apply_super5doFooyyyyXEF : $@convention(thin) (@noescape @callee_guaranteed () -> ()) -> ()
+  // CHECK:   apply [[DOFOO]]([[CONVERT]]) : $@convention(thin) (@noescape @callee_guaranteed () -> ()) -> ()
+  // CHECK: } // end sil function '$S19partial_apply_super25ChildToFixedOutsideParentC6methodyyF'
+  override func method() {
+    doFoo(super.method)
+  }
+
+  // CHECK-LABEL: sil hidden @$S19partial_apply_super25ChildToFixedOutsideParentC11classMethodyyFZ
+  // CHECK: [[CASTED_SELF:%.*]] = upcast %0 : $@thick ChildToFixedOutsideParent.Type to $@thick OutsideParent.Type
+  // CHECK: [[SUPER_METHOD:%.*]] = super_method %0 : $@thick ChildToFixedOutsideParent.Type, #OutsideParent.classMethod!1 : (OutsideParent.Type) -> () -> (), $@convention(method) (@thick OutsideParent.Type) -> (){{.*}}
+  // CHECK: [[PARTIAL_APPLY:%.*]] = partial_apply [callee_guaranteed] [[SUPER_METHOD]]([[CASTED_SELF]]) : $@convention(method) (@thick OutsideParent.Type) -> ()
+  // CHECK: [[CONVERT:%.*]] = convert_escape_to_noescape [[PARTIAL_APPLY]]
+  // CHECK: [[DOFOO:%.*]] = function_ref @$S19partial_apply_super5doFooyyyyXEF : $@convention(thin) (@noescape @callee_guaranteed () -> ()) -> ()
+  // CHECK: apply [[DOFOO]]([[CONVERT]]) : $@convention(thin) (@noescape @callee_guaranteed () -> ()) -> ()
+  // CHECK: } // end sil function '$S19partial_apply_super25ChildToFixedOutsideParentC11classMethodyyFZ'
+  override class func classMethod() {
+    doFoo(super.classMethod)
+  }
+}
+
+class ChildToResilientOutsideParent : ResilientOutsideParent {
+  // CHECK-LABEL: sil hidden @$S19partial_apply_super29ChildToResilientOutsideParentC6methodyyF : $@convention
+  // CHECK: bb0([[SELF:%.*]] : @guaranteed $ChildToResilientOutsideParent):
+  // CHECK:   [[SELF_COPY:%.*]] = copy_value [[SELF]]
+  // CHECK:   [[CASTED_SELF_COPY:%.*]] = upcast [[SELF_COPY]] : $ChildToResilientOutsideParent to $ResilientOutsideParent
+  // CHECK:   [[BORROWED_CASTED_SELF_COPY:%.*]] = begin_borrow [[CASTED_SELF_COPY]]
+  // CHECK:   [[CASTED_SELF_COPY:%.*]] = copy_value [[BORROWED_CASTED_SELF_COPY]]
+  // CHECK:   [[BORROWED_CASTED_SELF_COPY:%.*]] = begin_borrow [[CASTED_SELF_COPY]]
+  // CHECK:   [[DOWNCAST_BORROWED_CASTED_SELF_COPY:%.*]] = unchecked_ref_cast [[BORROWED_CASTED_SELF_COPY]]
+  // CHECK:   [[SUPER_METHOD:%.*]] = super_method [[DOWNCAST_BORROWED_CASTED_SELF_COPY]] : $ResilientOutsideParent, #ResilientOutsideParent.method!1 : (ResilientOutsideParent) -> () -> (), $@convention(method) (@guaranteed ResilientOutsideParent) -> ()
+  // CHECK:   end_borrow [[BORROWED_CASTED_SELF_COPY]] from [[CASTED_SELF_COPY]]
+  // CHECK:   [[PARTIAL_APPLY:%.*]] = partial_apply [callee_guaranteed] [[SUPER_METHOD]]([[CASTED_SELF_COPY]]) : $@convention(method) (@guaranteed ResilientOutsideParent) -> ()
+  // CHECK:   [[CONVERT:%.*]] = convert_escape_to_noescape [[PARTIAL_APPLY]]
+  // CHECK:   [[DOFOO:%.*]] = function_ref @$S19partial_apply_super5doFooyyyyXEF : $@convention(thin) (@noescape @callee_guaranteed () -> ()) -> ()
+  // CHECK:   apply [[DOFOO]]([[CONVERT]]) : $@convention(thin) (@noescape @callee_guaranteed () -> ()) -> ()
+  // CHECK: } // end sil function '$S19partial_apply_super29ChildToResilientOutsideParentC6methodyyF'
+  override func method() {
+    doFoo(super.method)
+  }
+
+  // CHECK-LABEL: sil hidden @$S19partial_apply_super29ChildToResilientOutsideParentC11classMethodyyFZ
+  // CHECK: [[CASTED_SELF:%.*]] = upcast %0 : $@thick ChildToResilientOutsideParent.Type to $@thick ResilientOutsideParent.Type
+  // CHECK: [[SUPER_METHOD:%.*]] = super_method %0 : $@thick ChildToResilientOutsideParent.Type, #ResilientOutsideParent.classMethod!1 : (ResilientOutsideParent.Type) -> () -> (), $@convention(method) (@thick ResilientOutsideParent.Type) -> ()
+  // CHECK: [[PARTIAL_APPLY:%.*]] = partial_apply [callee_guaranteed] [[SUPER_METHOD]]([[CASTED_SELF]]) : $@convention(method) (@thick ResilientOutsideParent.Type) -> ()
+  // CHECK: [[CONVERT:%.*]] = convert_escape_to_noescape [[PARTIAL_APPLY]]
+  // CHECK: [[DOFOO:%.*]] = function_ref @$S19partial_apply_super5doFooyyyyXEF : $@convention(thin) (@noescape @callee_guaranteed () -> ()) -> ()
+  // CHECK: apply [[DOFOO]]([[CONVERT]]) : $@convention(thin) (@noescape @callee_guaranteed () -> ()) -> ()
+  // CHECK: } // end sil function '$S19partial_apply_super29ChildToResilientOutsideParentC11classMethodyyFZ'
+  override class func classMethod() {
+    doFoo(super.classMethod)
+  }
+}
+
+class GrandchildToFixedOutsideChild : OutsideChild {
+  // CHECK-LABEL: sil hidden @$S19partial_apply_super29GrandchildToFixedOutsideChildC6methodyyF
+  // CHECK: bb0([[SELF:%.*]] : @guaranteed $GrandchildToFixedOutsideChild):
+  // CHECK:     [[SELF_COPY:%.*]] = copy_value [[SELF]]
+  // CHECK:     [[CASTED_SELF_COPY:%.*]] = upcast [[SELF_COPY]] : $GrandchildToFixedOutsideChild to $OutsideChild
+  // CHECK:     [[BORROWED_CASTED_SELF_COPY:%.*]] = begin_borrow [[CASTED_SELF_COPY]]
+  // CHECK:     [[CASTED_SELF_COPY:%.*]] = copy_value [[BORROWED_CASTED_SELF_COPY]]
+  // CHECK:     [[BORROWED_CASTED_SELF_COPY:%.*]] = begin_borrow [[CASTED_SELF_COPY]]
+  // CHECK:     [[DOWNCAST_BORROWED_CASTED_SELF_COPY:%.*]] = unchecked_ref_cast [[BORROWED_CASTED_SELF_COPY]]
+  // CHECK:     [[SUPER_METHOD:%.*]] = super_method [[DOWNCAST_BORROWED_CASTED_SELF_COPY]] : $OutsideChild, #OutsideChild.method!1 : (OutsideChild) -> () -> (), $@convention(method) (@guaranteed OutsideChild) -> ()
+  // CHECK:     end_borrow [[BORROWED_CASTED_SELF_COPY]] from [[CASTED_SELF_COPY]]
+  // CHECK:     [[PARTIAL_APPLY:%.*]] = partial_apply [callee_guaranteed] [[SUPER_METHOD]]([[CASTED_SELF_COPY]]) : $@convention(method) (@guaranteed OutsideChild) -> ()
+  // CHECK:     [[CONVERT:%.*]] = convert_escape_to_noescape [[PARTIAL_APPLY]]
+  // CHECK:     [[DOFOO:%.*]] = function_ref @$S19partial_apply_super5doFooyyyyXEF : $@convention(thin) (@noescape @callee_guaranteed () -> ()) -> ()
+  // CHECK:     apply [[DOFOO]]([[CONVERT]]) : $@convention(thin) (@noescape @callee_guaranteed () -> ()) -> ()
+  // CHECK: } // end sil function '$S19partial_apply_super29GrandchildToFixedOutsideChildC6methodyyF'
+  override func method() {
+    doFoo(super.method)
+  }
+
+  // CHECK-LABEL: sil hidden @$S19partial_apply_super29GrandchildToFixedOutsideChildC11classMethodyyFZ
+  // CHECK: [[CASTED_SELF:%.*]] = upcast %0 : $@thick GrandchildToFixedOutsideChild.Type to $@thick OutsideChild.Type
+  // CHECK: [[SUPER_METHOD:%.*]] = super_method %0 : $@thick GrandchildToFixedOutsideChild.Type, #OutsideChild.classMethod!1 : (OutsideChild.Type) -> () -> (), $@convention(method) (@thick OutsideChild.Type) -> ()
+  // CHECK: [[PARTIAL_APPLY:%.*]] = partial_apply [callee_guaranteed] [[SUPER_METHOD]]([[CASTED_SELF]]) : $@convention(method) (@thick OutsideChild.Type) -> ()
+  // CHECK: [[CONVERT:%.*]] = convert_escape_to_noescape [[PARTIAL_APPLY]]
+  // CHECK: [[DOFOO:%.*]] = function_ref @$S19partial_apply_super5doFooyyyyXEF : $@convention(thin) (@noescape @callee_guaranteed () -> ()) -> ()
+  // CHECK: apply [[DOFOO]]([[CONVERT]]) : $@convention(thin) (@noescape @callee_guaranteed () -> ()) -> ()
+  // CHECK: } // end sil function '$S19partial_apply_super29GrandchildToFixedOutsideChildC11classMethodyyFZ'
+  override class func classMethod() {
+    doFoo(super.classMethod)
+  }
+}
+
+class GrandchildToResilientOutsideChild : ResilientOutsideChild {
+  // CHECK-LABEL: sil hidden @$S19partial_apply_super33GrandchildToResilientOutsideChildC6methodyyF
+  // CHECK: bb0([[SELF:%.*]] : @guaranteed $GrandchildToResilientOutsideChild):
+  // CHECK:     [[SELF_COPY:%.*]] = copy_value [[SELF]]
+  // CHECK:     [[CASTED_SELF_COPY:%.*]] = upcast [[SELF_COPY]] : $GrandchildToResilientOutsideChild to $ResilientOutsideChild
+  // CHECK:     [[BORROWED_CASTED_SELF_COPY:%.*]] = begin_borrow [[CASTED_SELF_COPY]]
+  // CHECK:     [[CASTED_SELF_COPY:%.*]] = copy_value [[BORROWED_CASTED_SELF_COPY]]
+  // CHECK:     [[BORROWED_CASTED_SELF_COPY:%.*]] = begin_borrow [[CASTED_SELF_COPY]]
+  // CHECK:     [[DOWNCAST_BORROWED_CASTED_SELF_COPY:%.*]] = unchecked_ref_cast [[BORROWED_CASTED_SELF_COPY]]
+  // CHECK:     [[SUPER_METHOD:%.*]] = super_method [[DOWNCAST_BORROWED_CASTED_SELF_COPY]] : $ResilientOutsideChild, #ResilientOutsideChild.method!1 : (ResilientOutsideChild) -> () -> (), $@convention(method) (@guaranteed ResilientOutsideChild) -> ()
+  // CHEC:      end_borrow [[BORROWED_CASTED_SELF_COPY]] from [[CASTED_SELF_COPY]]
+  // CHECK:     [[PARTIAL_APPLY:%.*]] = partial_apply [callee_guaranteed] [[SUPER_METHOD]]([[CASTED_SELF_COPY]]) : $@convention(method) (@guaranteed ResilientOutsideChild) -> ()
+  // CHECK:     [[CONVERT:%.*]] = convert_escape_to_noescape [[PARTIAL_APPLY]]
+  // CHECK:     [[DOFOO:%.*]] = function_ref @$S19partial_apply_super5doFooyyyyXEF : $@convention(thin) (@noescape @callee_guaranteed () -> ()) -> ()
+  // CHECK:     apply [[DOFOO]]([[CONVERT]]) : $@convention(thin) (@noescape @callee_guaranteed () -> ()) -> ()
+  // CHECK: } // end sil function '$S19partial_apply_super33GrandchildToResilientOutsideChildC6methodyyF'
+  override func method() {
+    doFoo(super.method)
+  }
+
+  // CHECK-LABEL: sil hidden @$S19partial_apply_super33GrandchildToResilientOutsideChildC11classMethodyyFZ
+  // CHECK: [[CASTED_SELF:%.*]] = upcast %0 : $@thick GrandchildToResilientOutsideChild.Type to $@thick ResilientOutsideChild.Type
+  // CHECK: [[SUPER_METHOD:%.*]] = super_method %0 : $@thick GrandchildToResilientOutsideChild.Type, #ResilientOutsideChild.classMethod!1 : (ResilientOutsideChild.Type) -> () -> (), $@convention(method) (@thick ResilientOutsideChild.Type) -> ()
+  // CHECK: [[PARTIAL_APPLY:%.*]] = partial_apply [callee_guaranteed] [[SUPER_METHOD]]([[CASTED_SELF]]) : $@convention(method) (@thick ResilientOutsideChild.Type) -> ()
+  // CHECK: [[CONVERT:%.*]] = convert_escape_to_noescape [[PARTIAL_APPLY]]
+  // CHECK: [[DOFOO:%.*]] = function_ref @$S19partial_apply_super5doFooyyyyXEF : $@convention(thin) (@noescape @callee_guaranteed () -> ()) -> ()
+  // CHECK: apply [[DOFOO]]([[CONVERT]]) : $@convention(thin) (@noescape @callee_guaranteed () -> ()) -> ()
+  // CHECK: } // end sil function '$S19partial_apply_super33GrandchildToResilientOutsideChildC11classMethodyyFZ'
+  override class func classMethod() {
+    doFoo(super.classMethod)
+  }
+}
+
+class GenericChildToFixedGenericOutsideParent<A> : GenericOutsideParent<A> {
+  // CHECK-LABEL: sil hidden @$S19partial_apply_super019GenericChildToFixedD13OutsideParentC6methodyyF
+  // CHECK: bb0([[SELF:%.*]] : @guaranteed $GenericChildToFixedGenericOutsideParent<A>):
+  // CHECK:     [[SELF_COPY:%.*]] = copy_value [[SELF]]
+  // CHECK:     [[CASTED_SELF_COPY:%.*]] = upcast [[SELF_COPY]] : $GenericChildToFixedGenericOutsideParent<A> to $GenericOutsideParent<A>
+  // CHECK:     [[BORROWED_CASTED_SELF_COPY:%.*]] = begin_borrow [[CASTED_SELF_COPY]]
+  // CHECK:     [[CASTED_SELF_COPY:%.*]] = copy_value [[BORROWED_CASTED_SELF_COPY]]
+  // CHECK:     [[BORROWED_CASTED_SELF_COPY:%.*]] = begin_borrow [[CASTED_SELF_COPY]]
+  // CHECK:     [[DOWNCAST_BORROWED_CASTED_SELF_COPY:%.*]] = unchecked_ref_cast [[BORROWED_CASTED_SELF_COPY]]
+  // CHECK:     [[SUPER_METHOD:%.*]] = super_method [[DOWNCAST_BORROWED_CASTED_SELF_COPY]] : $GenericOutsideParent<A>, #GenericOutsideParent.method!1 : <A> (GenericOutsideParent<A>) -> () -> (), $@convention(method) <τ_0_0> (@guaranteed GenericOutsideParent<τ_0_0>) -> ()
+  // CHECK:     end_borrow [[BORROWED_CASTED_SELF_COPY]] from [[CASTED_SELF_COPY]]
+  // CHECK:     [[PARTIAL_APPLY:%.*]] = partial_apply [callee_guaranteed] [[SUPER_METHOD]]<A>([[CASTED_SELF_COPY]]) : $@convention(method) <τ_0_0> (@guaranteed GenericOutsideParent<τ_0_0>) -> ()
+  // CHECK:     [[CONVERT:%.*]] = convert_escape_to_noescape [[PARTIAL_APPLY]]
+  // CHECK:     [[DOFOO:%.*]] = function_ref @$S19partial_apply_super5doFooyyyyXEF : $@convention(thin) (@noescape @callee_guaranteed () -> ()) -> ()
+  // CHECK:     apply [[DOFOO]]([[CONVERT]]) : $@convention(thin) (@noescape @callee_guaranteed () -> ()) -> ()
+  // CHECK: } // end sil function '$S19partial_apply_super019GenericChildToFixedD13OutsideParentC6methodyyF'
+  override func method() {
+    doFoo(super.method)
+  }
+
+  // CHECK-LABEL: sil hidden @$S19partial_apply_super019GenericChildToFixedD13OutsideParentC11classMethodyyFZ
+  // CHECK: [[CASTED_SELF:%.*]] = upcast %0 : $@thick GenericChildToFixedGenericOutsideParent<A>.Type to $@thick GenericOutsideParent<A>.Type
+  // CHECK: [[SUPER_METHOD:%.*]] = super_method %0 : $@thick GenericChildToFixedGenericOutsideParent<A>.Type, #GenericOutsideParent.classMethod!1 : <A> (GenericOutsideParent<A>.Type) -> () -> (), $@convention(method) <τ_0_0> (@thick GenericOutsideParent<τ_0_0>.Type) -> ()
+  // CHECK: [[PARTIAL_APPLY:%.*]] = partial_apply [callee_guaranteed] [[SUPER_METHOD]]<A>([[CASTED_SELF]]) : $@convention(method) <τ_0_0> (@thick GenericOutsideParent<τ_0_0>.Type) -> ()
+  // CHECK: [[CONVERT:%.*]] = convert_escape_to_noescape [[PARTIAL_APPLY]]
+  // CHECK: [[DOFOO:%.*]] = function_ref @$S19partial_apply_super5doFooyyyyXEF : $@convention(thin) (@noescape @callee_guaranteed () -> ()) -> ()
+  // CHECK: apply [[DOFOO]]([[CONVERT]]) : $@convention(thin) (@noescape @callee_guaranteed () -> ()) -> ()
+  // CHECK: } // end sil function '$S19partial_apply_super019GenericChildToFixedD13OutsideParentC11classMethodyyFZ'
+  override class func classMethod() {
+    doFoo(super.classMethod)
+  }
+}
+
+class GenericChildToResilientGenericOutsideParent<A> : ResilientGenericOutsideParent<A> {
+  // CHECK-LABEL: sil hidden @$S19partial_apply_super023GenericChildToResilientD13OutsideParentC6methodyyF
+  // CHECK: bb0([[SELF:%.*]] : @guaranteed $GenericChildToResilientGenericOutsideParent<A>):
+  // CHECK:     [[SELF_COPY:%.*]] = copy_value [[SELF]]
+  // CHECK:     [[CASTED_SELF_COPY:%.*]] = upcast [[SELF_COPY]] : $GenericChildToResilientGenericOutsideParent<A> to $ResilientGenericOutsideParent<A>
+  // CHECK:     [[BORROWED_CASTED_SELF_COPY:%.*]] = begin_borrow [[CASTED_SELF_COPY]]
+  // CHECK:     [[CASTED_SELF_COPY:%.*]] = copy_value [[BORROWED_CASTED_SELF_COPY]]
+  // CHECK:     [[BORROWED_CASTED_SELF_COPY:%.*]] = begin_borrow [[CASTED_SELF_COPY]]
+  // CHECK:     [[DOWNCAST_BORROWED_CASTED_SELF_COPY:%.*]] = unchecked_ref_cast [[BORROWED_CASTED_SELF_COPY]]
+  // CHECK:     [[SUPER_METHOD:%.*]] = super_method [[DOWNCAST_BORROWED_CASTED_SELF_COPY]] : $ResilientGenericOutsideParent<A>, #ResilientGenericOutsideParent.method!1 : <A> (ResilientGenericOutsideParent<A>) -> () -> (), $@convention(method) <τ_0_0> (@guaranteed ResilientGenericOutsideParent<τ_0_0>) -> ()
+  // CHECK:     end_borrow [[BORROWED_CASTED_SELF_COPY]] from [[CASTED_SELF_COPY]]
+  // CHECK:     [[PARTIAL_APPLY:%.*]] = partial_apply [callee_guaranteed] [[SUPER_METHOD]]<A>([[CASTED_SELF_COPY]]) : $@convention(method) <τ_0_0> (@guaranteed ResilientGenericOutsideParent<τ_0_0>) -> ()
+  // CHECK:     [[CONVERT:%.*]] = convert_escape_to_noescape [[PARTIAL_APPLY]]
+  // CHECK:     [[DOFOO:%.*]] = function_ref @$S19partial_apply_super5doFooyyyyXEF : $@convention(thin) (@noescape @callee_guaranteed () -> ()) -> ()
+  // CHECK:     apply [[DOFOO]]([[CONVERT]]) : $@convention(thin) (@noescape @callee_guaranteed () -> ()) -> ()
+  // CHECK: } // end sil function '$S19partial_apply_super023GenericChildToResilientD13OutsideParentC6methodyyF'
+  override func method() {
+    doFoo(super.method)
+  }
+
+  // CHECK-LABEL: sil hidden @$S19partial_apply_super023GenericChildToResilientD13OutsideParentC11classMethodyyFZ
+  // CHECK: [[CASTED_SELF:%.*]] = upcast %0 : $@thick GenericChildToResilientGenericOutsideParent<A>.Type to $@thick ResilientGenericOutsideParent<A>.Type
+  // CHECK: [[SUPER_METHOD:%.*]] = super_method %0 : $@thick GenericChildToResilientGenericOutsideParent<A>.Type, #ResilientGenericOutsideParent.classMethod!1 : <A> (ResilientGenericOutsideParent<A>.Type) -> () -> (), $@convention(method) <τ_0_0> (@thick ResilientGenericOutsideParent<τ_0_0>.Type) -> ()
+  // CHECK: [[PARTIAL_APPLY:%.*]] = partial_apply [callee_guaranteed] [[SUPER_METHOD]]<A>([[CASTED_SELF]]) : $@convention(method) <τ_0_0> (@thick ResilientGenericOutsideParent<τ_0_0>.Type) -> ()
+  // CHECK: [[CONVERT:%.*]] = convert_escape_to_noescape [[PARTIAL_APPLY]]
+  // CHECK: [[DOFOO:%.*]] = function_ref @$S19partial_apply_super5doFooyyyyXEF : $@convention(thin) (@noescape @callee_guaranteed () -> ()) -> ()
+  // CHECK: apply [[DOFOO]]([[CONVERT]]) : $@convention(thin) (@noescape @callee_guaranteed () -> ()) -> ()
+  // CHECK: } // end sil function '$S19partial_apply_super023GenericChildToResilientD13OutsideParentC11classMethodyyFZ'
+  override class func classMethod() {
+    doFoo(super.classMethod)
+  }
+}
diff --git a/test/SILGen/plus_zero_pgo_checked_cast.swift b/test/SILGen/plus_zero_pgo_checked_cast.swift
new file mode 100644
index 0000000..a479e87
--- /dev/null
+++ b/test/SILGen/plus_zero_pgo_checked_cast.swift
@@ -0,0 +1,72 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %empty-directory(%t)
+// RUN: %target-build-swift %s -profile-generate -Xfrontend -disable-incremental-llvm-codegen -module-name pgo_checked_cast -o %t/main
+// RUN: env LLVM_PROFILE_FILE=%t/default.profraw %target-run %t/main
+// RUN: %llvm-profdata merge %t/default.profraw -o %t/default.profdata
+// RUN: %target-swift-frontend %s -Xllvm -sil-full-demangle -profile-use=%t/default.profdata -emit-sorted-sil -emit-sil -module-name pgo_checked_cast -o - | %FileCheck %s --check-prefix=SIL
+// need to lower checked_cast_addr_br(addr) into IR for this
+// %target-swift-frontend %s -Xllvm -sil-full-demangle -profile-use=%t/default.profdata -emit-ir -module-name pgo_checked_cast -o - | %FileCheck %s --check-prefix=IR
+// RUN: %target-swift-frontend %s -Xllvm -sil-full-demangle -profile-use=%t/default.profdata -O -emit-sorted-sil -emit-sil -module-name pgo_checked_cast -o - | %FileCheck %s --check-prefix=SIL-OPT
+// need to lower checked_cast_addr_br(addr) into IR for this
+// %target-swift-frontend %s -Xllvm -sil-full-demangle -profile-use=%t/default.profdata -O -emit-ir -module-name pgo_checked_cast -o - | %FileCheck %s --check-prefix=IR-OPT
+
+// REQUIRES: profile_runtime
+// REQUIRES: OS=macosx
+
+// SIL-LABEL: // pgo_checked_cast.check1<A>(Any, A) -> A
+// SIL-LABEL: sil @$S16pgo_checked_cast6check1yxyp_xtlF : $@convention(thin) <T> (@in_guaranteed Any, @in_guaranteed T) -> @out T !function_entry_count(5001) {
+// IR-LABEL: define swiftcc i32 @$S6pgo_checked_cast6guess1s5Int32VAD1x_tF
+// IR-OPT-LABEL: define swiftcc i32 @$S6pgo_checked_cast6guess1s5Int32VAD1x_tF
+public func check1<T>(_ a : Any, _ t : T) -> T {
+  // SIL: checked_cast_addr_br take_always Any in {{.*}} : $*Any to T in {{.*}} : $*T, {{.*}}, {{.*}} !true_count(5000) !false_count(1)
+  // SIL-OPT: checked_cast_addr_br take_always Any in {{.*}} : $*Any to T in {{.*}} : $*T, {{.*}}, {{.*}} !true_count(5000) !false_count(1)
+  if let x = a as? T {
+    return x
+  } else {
+    return t
+  }
+}
+
+public class B {}
+public class C : B {}
+public class D : C {}
+
+// SIL-LABEL: // pgo_checked_cast.check2(pgo_checked_cast.B) -> Swift.Int32
+// SIL-LABEL: sil @$S16pgo_checked_cast6check2ys5Int32VAA1BCF : $@convention(thin) (@guaranteed B) -> Int32 !function_entry_count(5003) {
+// IR-LABEL: define swiftcc i32 @$S6pgo_checked_cast6guess1s5Int32VAD1x_tF
+// IR-OPT-LABEL: define swiftcc i32 @$S6pgo_checked_cast6guess1s5Int32VAD1x_tF
+public func check2(_ a : B) -> Int32 {
+  // SIL: checked_cast_br %0 : $B to $D, {{.*}}, {{.*}} !true_count(5000)
+  // SIL: checked_cast_br %0 : $B to $C, {{.*}}, {{.*}} !true_count(2)
+  // SIL-OPT: checked_cast_br %0 : $B to $D, {{.*}}, {{.*}} !true_count(5000)
+  // SIL-OPT: checked_cast_br %0 : $B to $C, {{.*}}, {{.*}} !true_count(2)
+  switch a {
+    case is D:
+      return 42
+    case is C:
+      return 23
+    default:
+      return 13
+  }
+}
+
+func main() {
+  let answer : Int32 = 42
+  var sum : Int32 = 0
+
+  sum += check1("The answer to the life, the universe, and everything", answer)
+  
+  sum += check2(B())
+  sum += check2(C())
+  sum += check2(C())
+
+  for i : Int32 in 1...5000 {
+    sum += check1(i, answer)
+    sum += check2(D())
+  }
+}
+
+main()
+
+// IR: !{!"branch_weights", i32 5001, i32 2}
+// IR-OPT: !{!"branch_weights", i32 5001, i32 2}
diff --git a/test/SILGen/plus_zero_pgo_switchenum.swift b/test/SILGen/plus_zero_pgo_switchenum.swift
new file mode 100644
index 0000000..405912d
--- /dev/null
+++ b/test/SILGen/plus_zero_pgo_switchenum.swift
@@ -0,0 +1,100 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %empty-directory(%t)
+// RUN: %target-build-swift %s -Xfrontend -enable-sil-ownership -profile-generate -Xfrontend -disable-incremental-llvm-codegen -module-name pgo_switchenum -o %t/main
+// RUN: env LLVM_PROFILE_FILE=%t/default.profraw %target-run %t/main
+// RUN: %llvm-profdata merge %t/default.profraw -o %t/default.profdata
+// need to move counts attached to expr for this
+// RUN: %target-swift-frontend %s -Xllvm -sil-full-demangle -profile-use=%t/default.profdata -enable-sil-ownership -emit-sorted-sil -emit-sil -module-name pgo_switchenum -o - | %FileCheck %s --check-prefix=SIL
+// need to lower switch_enum(addr) into IR for this
+// %target-swift-frontend %s -enable-sil-ownership -Xllvm -sil-full-demangle -profile-use=%t/default.profdata -emit-ir -module-name pgo_switchenum -o - | %FileCheck %s --check-prefix=IR
+// need to check Opt support
+// %target-swift-frontend %s -enable-sil-ownership -Xllvm -sil-full-demangle -profile-use=%t/default.profdata -O -emit-sorted-sil -emit-sil -module-name pgo_switchenum -o - | %FileCheck %s --check-prefix=SIL-OPT
+// need to lower switch_enum(addr) into IR for this
+// %target-swift-frontend -enable-sil-ownership %s -Xllvm -sil-full-demangle -profile-use=%t/default.profdata -O -emit-ir -module-name pgo_switchenum -o - | %FileCheck %s --check-prefix=IR-OPT
+
+// REQUIRES: profile_runtime
+// REQUIRES: OS=macosx
+
+public enum MaybePair {
+  case Neither
+  case Left(Int32)
+  case Right(String)
+  case Both(Int32, String)
+}
+
+// SIL-LABEL: // pgo_switchenum.guess1
+// SIL-LABEL: sil @$S14pgo_switchenum6guess11xs5Int32VAA9MaybePairO_tF : $@convention(thin) (@guaranteed MaybePair) -> Int32 !function_entry_count(5011) {
+// IR-LABEL: define swiftcc i32 @$S9pgo_switchenum6guess1s5Int32VAD1x_tF
+// IR-OPT-LABEL: define swiftcc i32 @$S9pgo_switchenum6guess1s5Int32VAD1x_tF
+
+public func guess1(x: MaybePair) -> Int32 {
+  // SIL: switch_enum {{.*}} : $MaybePair, case #MaybePair.Neither!enumelt: {{.*}} !case_count(2), case #MaybePair.Left!enumelt.1: {{.*}} !case_count(5001), case #MaybePair.Right!enumelt.1: {{.*}} !case_count(3), case #MaybePair.Both!enumelt.1: {{.*}} !case_count(5)
+  // SIL-OPT: switch_enum {{.*}} : $MaybePair, case #MaybePair.Neither!enumelt: {{.*}} !case_count(2), case #MaybePair.Left!enumelt.1: {{.*}} !case_count(5001), case #MaybePair.Right!enumelt.1: {{.*}} !case_count(3), case #MaybePair.Both!enumelt.1: {{.*}} !case_count(5)
+  switch x {
+  case .Neither:
+    return 1
+  case let .Left(val):
+    return val*2
+  case let .Right(val):
+    return Int32(val.count)
+  case let .Both(valNum, valStr):
+    return valNum + Int32(valStr.count)
+  }
+}
+
+// SIL-LABEL: // pgo_switchenum.guess2
+// SIL-LABEL: sil @$S14pgo_switchenum6guess21xs5Int32VAA9MaybePairO_tF : $@convention(thin) (@guaranteed MaybePair) -> Int32 !function_entry_count(5011) {
+public func guess2(x: MaybePair) -> Int32 {
+  // SIL: switch_enum {{.*}} : $MaybePair, case #MaybePair.Neither!enumelt: {{.*}} !case_count(2), case #MaybePair.Left!enumelt.1: {{.*}} !case_count(5001), default {{.*}} !default_count(8)
+  // SIL-OPT: switch_enum {{.*}} : $MaybePair, case #MaybePair.Neither!enumelt: {{.*}} !case_count(2), case #MaybePair.Left!enumelt.1: {{.*}} !case_count(5001), default {{.*}} !default_count(8)
+  switch x {
+  case .Neither:
+    return 1
+  case let .Left(val):
+    return val*2
+  default:
+    return 42;
+  }
+}
+
+
+func main() {
+  var guesses : Int32 = 0;
+
+  guesses += guess1(x: MaybePair.Neither)
+  guesses += guess1(x: MaybePair.Neither)
+  guesses += guess1(x: MaybePair.Left(42))
+  guesses += guess1(x: MaybePair.Right("The Answer"))
+  guesses += guess1(x: MaybePair.Right("The Answer"))
+  guesses += guess1(x: MaybePair.Right("The Answer"))
+  guesses += guess1(x: MaybePair.Both(42, "The Answer"))
+  guesses += guess1(x: MaybePair.Both(42, "The Answer"))
+  guesses += guess1(x: MaybePair.Both(42, "The Answer"))
+  guesses += guess1(x: MaybePair.Both(42, "The Answer"))
+  guesses += guess1(x: MaybePair.Both(42, "The Answer"))
+
+  for _ in 1...5000 {
+    guesses += guess1(x: MaybePair.Left(10))
+  }
+  
+  guesses += guess2(x: MaybePair.Neither)
+  guesses += guess2(x: MaybePair.Neither)
+  guesses += guess2(x: MaybePair.Left(42))
+  guesses += guess2(x: MaybePair.Right("The Answer"))
+  guesses += guess2(x: MaybePair.Right("The Answer"))
+  guesses += guess2(x: MaybePair.Right("The Answer"))
+  guesses += guess2(x: MaybePair.Both(42, "The Answer"))
+  guesses += guess2(x: MaybePair.Both(42, "The Answer"))
+  guesses += guess2(x: MaybePair.Both(42, "The Answer"))
+  guesses += guess2(x: MaybePair.Both(42, "The Answer"))
+  guesses += guess2(x: MaybePair.Both(42, "The Answer"))
+
+  for _ in 1...5000 {
+    guesses += guess2(x: MaybePair.Left(10))
+  }
+}
+
+main()
+
+// IR: !{!"branch_weights", i32 5001, i32 3}
+// IR-OPT: !{!"branch_weights", i32 5001, i32 3}
diff --git a/test/SILGen/plus_zero_pointer_conversion.swift b/test/SILGen/plus_zero_pointer_conversion.swift
new file mode 100644
index 0000000..a07a9cf
--- /dev/null
+++ b/test/SILGen/plus_zero_pointer_conversion.swift
@@ -0,0 +1,457 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -enable-sil-ownership -emit-silgen -sdk %S/Inputs -I %S/Inputs -enable-source-import %s | %FileCheck %s
+
+// FIXME: rdar://problem/19648117 Needs splitting objc parts out
+// XFAIL: linux
+
+import Foundation
+
+func sideEffect1() -> Int { return 1 }
+func sideEffect2() -> Int { return 2 }
+func takesMutablePointer(_ x: UnsafeMutablePointer<Int>) {}
+func takesConstPointer(_ x: UnsafePointer<Int>) {}
+func takesOptConstPointer(_ x: UnsafePointer<Int>?, and: Int) {}
+func takesOptOptConstPointer(_ x: UnsafePointer<Int>??, and: Int) {}
+func takesMutablePointer(_ x: UnsafeMutablePointer<Int>, and: Int) {}
+func takesConstPointer(_ x: UnsafePointer<Int>, and: Int) {}
+func takesMutableVoidPointer(_ x: UnsafeMutableRawPointer) {}
+func takesConstVoidPointer(_ x: UnsafeRawPointer) {}
+func takesMutableRawPointer(_ x: UnsafeMutableRawPointer) {}
+func takesConstRawPointer(_ x: UnsafeRawPointer) {}
+func takesOptConstRawPointer(_ x: UnsafeRawPointer?, and: Int) {}
+func takesOptOptConstRawPointer(_ x: UnsafeRawPointer??, and: Int) {}
+
+// CHECK-LABEL: sil hidden @$S18pointer_conversion0A9ToPointeryySpySiG_SPySiGSvtF
+// CHECK: bb0([[MP:%.*]] : $UnsafeMutablePointer<Int>, [[CP:%.*]] : $UnsafePointer<Int>, [[MRP:%.*]] : $UnsafeMutableRawPointer):
+func pointerToPointer(_ mp: UnsafeMutablePointer<Int>,
+  _ cp: UnsafePointer<Int>, _ mrp: UnsafeMutableRawPointer) {
+
+  // There should be no conversion here
+  takesMutablePointer(mp)
+  // CHECK: [[TAKES_MUTABLE_POINTER:%.*]] = function_ref @$S18pointer_conversion19takesMutablePointer{{[_0-9a-zA-Z]*}}F
+  // CHECK: apply [[TAKES_MUTABLE_POINTER]]([[MP]])
+
+  takesMutableVoidPointer(mp)
+  // CHECK: [[CONVERT:%.*]] = function_ref @$Ss017_convertPointerToB8Argument{{[_0-9a-zA-Z]*}}F
+  // CHECK: apply [[CONVERT]]<UnsafeMutablePointer<Int>, UnsafeMutableRawPointer>
+  // CHECK: [[TAKES_MUTABLE_VOID_POINTER:%.*]] = function_ref @$S18pointer_conversion23takesMutableVoidPointer{{[_0-9a-zA-Z]*}}F
+  // CHECK: apply [[TAKES_MUTABLE_VOID_POINTER]]
+
+  takesMutableRawPointer(mp)
+  // CHECK: [[CONVERT:%.*]] = function_ref @$Ss017_convertPointerToB8Argument{{[_0-9a-zA-Z]*}}F
+  // CHECK: apply [[CONVERT]]<UnsafeMutablePointer<Int>, UnsafeMutableRawPointer>
+  // CHECK: [[TAKES_MUTABLE_RAW_POINTER:%.*]] = function_ref @$S18pointer_conversion22takesMutableRawPointeryySvF :
+  // CHECK: apply [[TAKES_MUTABLE_RAW_POINTER]]
+
+  takesConstPointer(mp)
+  // CHECK: [[CONVERT:%.*]] = function_ref @$Ss017_convertPointerToB8Argument{{[_0-9a-zA-Z]*}}F
+  // CHECK: apply [[CONVERT]]<UnsafeMutablePointer<Int>, UnsafePointer<Int>>
+  // CHECK: [[TAKES_CONST_POINTER:%.*]] = function_ref @$S18pointer_conversion17takesConstPointeryySPySiGF
+  // CHECK: apply [[TAKES_CONST_POINTER]]
+
+  takesConstVoidPointer(mp)
+  // CHECK: [[CONVERT:%.*]] = function_ref @$Ss017_convertPointerToB8Argument{{[_0-9a-zA-Z]*}}F
+  // CHECK: apply [[CONVERT]]<UnsafeMutablePointer<Int>, UnsafeRawPointer>
+  // CHECK: [[TAKES_CONST_VOID_POINTER:%.*]] = function_ref @$S18pointer_conversion21takesConstVoidPointeryySVF
+  // CHECK: apply [[TAKES_CONST_VOID_POINTER]]
+
+  takesConstRawPointer(mp)
+  // CHECK: [[CONVERT:%.*]] = function_ref @$Ss017_convertPointerToB8Argument{{[_0-9a-zA-Z]*}}F
+  // CHECK: apply [[CONVERT]]<UnsafeMutablePointer<Int>, UnsafeRawPointer>
+  // CHECK: [[TAKES_CONST_RAW_POINTER:%.*]] = function_ref @$S18pointer_conversion20takesConstRawPointeryySVF :
+  // CHECK: apply [[TAKES_CONST_RAW_POINTER]]
+
+  takesConstPointer(cp)
+  // CHECK: [[TAKES_CONST_POINTER:%.*]] = function_ref @$S18pointer_conversion17takesConstPointeryySPySiGF
+  // CHECK: apply [[TAKES_CONST_POINTER]]([[CP]])
+
+  takesConstVoidPointer(cp)
+  // CHECK: [[CONVERT:%.*]] = function_ref @$Ss017_convertPointerToB8Argument{{[_0-9a-zA-Z]*}}F
+  // CHECK: apply [[CONVERT]]<UnsafePointer<Int>, UnsafeRawPointer>
+  // CHECK: [[TAKES_CONST_VOID_POINTER:%.*]] = function_ref @$S18pointer_conversion21takesConstVoidPointeryySVF
+  // CHECK: apply [[TAKES_CONST_VOID_POINTER]]
+
+  takesConstRawPointer(cp)
+  // CHECK: [[CONVERT:%.*]] = function_ref @$Ss017_convertPointerToB8Argument{{[_0-9a-zA-Z]*}}F
+  // CHECK: apply [[CONVERT]]<UnsafePointer<Int>, UnsafeRawPointer>
+  // CHECK: [[TAKES_CONST_RAW_POINTER:%.*]] = function_ref @$S18pointer_conversion20takesConstRawPointeryySVF
+  // CHECK: apply [[TAKES_CONST_RAW_POINTER]]
+
+  takesConstRawPointer(mrp)
+  // CHECK: [[CONVERT:%.*]] = function_ref @$Ss017_convertPointerToB8Argument{{[_0-9a-zA-Z]*}}F
+  // CHECK: apply [[CONVERT]]<UnsafeMutableRawPointer, UnsafeRawPointer>
+  // CHECK: [[TAKES_CONST_RAW_POINTER:%.*]] = function_ref @$S18pointer_conversion20takesConstRawPointeryySVF
+  // CHECK: apply [[TAKES_CONST_RAW_POINTER]]
+}
+
+// CHECK-LABEL: sil hidden @$S18pointer_conversion14arrayToPointeryyF
+func arrayToPointer() {
+  var ints = [1,2,3]
+
+  takesMutablePointer(&ints)
+  // CHECK: [[CONVERT_MUTABLE:%.*]] = function_ref @$Ss37_convertMutableArrayToPointerArgument{{[_0-9a-zA-Z]*}}F
+  // CHECK: [[OWNER:%.*]] = apply [[CONVERT_MUTABLE]]<Int, UnsafeMutablePointer<Int>>([[POINTER_BUF:%[0-9]*]],
+  // CHECK: [[POINTER:%.*]] = load [trivial] [[POINTER_BUF]]
+  // CHECK: [[DEPENDENT:%.*]] = mark_dependence [[POINTER]] : $UnsafeMutablePointer<Int> on [[OWNER]]
+  // CHECK: [[TAKES_MUTABLE_POINTER:%.*]] = function_ref @$S18pointer_conversion19takesMutablePointer{{[_0-9a-zA-Z]*}}F
+  // CHECK: apply [[TAKES_MUTABLE_POINTER]]([[DEPENDENT]])
+  // CHECK: destroy_value [[OWNER]]
+
+  takesConstPointer(ints)
+  // CHECK: [[CONVERT_CONST:%.*]] = function_ref @$Ss35_convertConstArrayToPointerArgument{{[_0-9a-zA-Z]*}}F
+  // CHECK: [[OWNER:%.*]] = apply [[CONVERT_CONST]]<Int, UnsafePointer<Int>>([[POINTER_BUF:%[0-9]*]],
+  // CHECK: [[POINTER:%.*]] = load [trivial] [[POINTER_BUF]]
+  // CHECK: [[DEPENDENT:%.*]] = mark_dependence [[POINTER]] : $UnsafePointer<Int> on [[OWNER]]
+  // CHECK: [[TAKES_CONST_POINTER:%.*]] = function_ref @$S18pointer_conversion17takesConstPointeryySPySiGF
+  // CHECK: apply [[TAKES_CONST_POINTER]]([[DEPENDENT]])
+  // CHECK: destroy_value [[OWNER]]
+
+  takesMutableRawPointer(&ints)
+  // CHECK: [[CONVERT_MUTABLE:%.*]] = function_ref @$Ss37_convertMutableArrayToPointerArgument{{[_0-9a-zA-Z]*}}F
+  // CHECK: [[OWNER:%.*]] = apply [[CONVERT_MUTABLE]]<Int, UnsafeMutableRawPointer>([[POINTER_BUF:%[0-9]*]],
+  // CHECK: [[POINTER:%.*]] = load [trivial] [[POINTER_BUF]]
+  // CHECK: [[DEPENDENT:%.*]] = mark_dependence [[POINTER]] : $UnsafeMutableRawPointer on [[OWNER]]
+  // CHECK: [[TAKES_MUTABLE_RAW_POINTER:%.*]] = function_ref @$S18pointer_conversion22takesMutableRawPointeryySvF :
+  // CHECK: apply [[TAKES_MUTABLE_RAW_POINTER]]([[DEPENDENT]])
+  // CHECK: destroy_value [[OWNER]]
+
+  takesConstRawPointer(ints)
+  // CHECK: [[CONVERT_CONST:%.*]] = function_ref @$Ss35_convertConstArrayToPointerArgument{{[_0-9a-zA-Z]*}}F
+  // CHECK: [[OWNER:%.*]] = apply [[CONVERT_CONST]]<Int, UnsafeRawPointer>([[POINTER_BUF:%[0-9]*]],
+  // CHECK: [[POINTER:%.*]] = load [trivial] [[POINTER_BUF]]
+  // CHECK: [[DEPENDENT:%.*]] = mark_dependence [[POINTER]] : $UnsafeRawPointer on [[OWNER]]
+  // CHECK: [[TAKES_CONST_RAW_POINTER:%.*]] = function_ref @$S18pointer_conversion20takesConstRawPointeryySVF :
+  // CHECK: apply [[TAKES_CONST_RAW_POINTER]]([[DEPENDENT]])
+  // CHECK: destroy_value [[OWNER]]
+
+  takesOptConstPointer(ints, and: sideEffect1())
+  // CHECK: [[SIDE1:%.*]] = function_ref @$S18pointer_conversion11sideEffect1SiyF
+  // CHECK: [[RESULT1:%.*]] = apply [[SIDE1]]()
+  // CHECK: [[CONVERT_CONST:%.*]] = function_ref @$Ss35_convertConstArrayToPointerArgument{{[_0-9a-zA-Z]*}}F
+  // CHECK: [[OWNER:%.*]] = apply [[CONVERT_CONST]]<Int, UnsafePointer<Int>>([[POINTER_BUF:%[0-9]*]],
+  // CHECK: [[POINTER:%.*]] = load [trivial] [[POINTER_BUF]]
+  // CHECK: [[DEPENDENT:%.*]] = mark_dependence [[POINTER]] : $UnsafePointer<Int> on [[OWNER]]
+  // CHECK: [[OPTPTR:%.*]] = enum $Optional<UnsafePointer<Int>>, #Optional.some!enumelt.1, [[DEPENDENT]]
+  // CHECK: [[TAKES_OPT_CONST_POINTER:%.*]] = function_ref @$S18pointer_conversion20takesOptConstPointer_3andySPySiGSg_SitF :
+  // CHECK: apply [[TAKES_OPT_CONST_POINTER]]([[OPTPTR]], [[RESULT1]])
+  // CHECK: destroy_value [[OWNER]]
+}
+
+// CHECK-LABEL: sil hidden @$S18pointer_conversion15stringToPointeryySSF
+func stringToPointer(_ s: String) {
+  takesConstVoidPointer(s)
+  // CHECK: [[CONVERT_STRING:%.*]] = function_ref @$Ss40_convertConstStringToUTF8PointerArgument{{[_0-9a-zA-Z]*}}F
+  // CHECK: [[OWNER:%.*]] = apply [[CONVERT_STRING]]<UnsafeRawPointer>([[POINTER_BUF:%[0-9]*]],
+  // CHECK: [[POINTER:%.*]] = load [trivial] [[POINTER_BUF]]
+  // CHECK: [[DEPENDENT:%.*]] = mark_dependence [[POINTER]] : $UnsafeRawPointer on [[OWNER]]
+  // CHECK: [[TAKES_CONST_VOID_POINTER:%.*]] = function_ref @$S18pointer_conversion21takesConstVoidPointeryySV{{[_0-9a-zA-Z]*}}F
+  // CHECK: apply [[TAKES_CONST_VOID_POINTER]]([[DEPENDENT]])
+  // CHECK: destroy_value [[OWNER]]
+
+  takesConstRawPointer(s)
+  // CHECK: [[CONVERT_STRING:%.*]] = function_ref @$Ss40_convertConstStringToUTF8PointerArgument{{[_0-9a-zA-Z]*}}F
+  // CHECK: [[OWNER:%.*]] = apply [[CONVERT_STRING]]<UnsafeRawPointer>([[POINTER_BUF:%[0-9]*]],
+  // CHECK: [[POINTER:%.*]] = load [trivial] [[POINTER_BUF]]
+  // CHECK: [[DEPENDENT:%.*]] = mark_dependence [[POINTER]] : $UnsafeRawPointer on [[OWNER]]
+  // CHECK: [[TAKES_CONST_RAW_POINTER:%.*]] = function_ref @$S18pointer_conversion20takesConstRawPointeryySV{{[_0-9a-zA-Z]*}}F
+  // CHECK: apply [[TAKES_CONST_RAW_POINTER]]([[DEPENDENT]])
+  // CHECK: destroy_value [[OWNER]]
+
+  takesOptConstRawPointer(s, and: sideEffect1())
+  // CHECK: [[SIDE1:%.*]] = function_ref @$S18pointer_conversion11sideEffect1SiyF
+  // CHECK: [[RESULT1:%.*]] = apply [[SIDE1]]()
+  // CHECK: [[CONVERT_STRING:%.*]] = function_ref @$Ss40_convertConstStringToUTF8PointerArgument{{[_0-9a-zA-Z]*}}F
+  // CHECK: [[OWNER:%.*]] = apply [[CONVERT_STRING]]<UnsafeRawPointer>([[POINTER_BUF:%[0-9]*]],
+  // CHECK: [[POINTER:%.*]] = load [trivial] [[POINTER_BUF]]
+  // CHECK: [[DEPENDENT:%.*]] = mark_dependence [[POINTER]] : $UnsafeRawPointer on [[OWNER]]
+  // CHECK: [[OPTPTR:%.*]] = enum $Optional<UnsafeRawPointer>, #Optional.some!enumelt.1, [[DEPENDENT]]
+  // CHECK: [[TAKES_OPT_CONST_RAW_POINTER:%.*]] = function_ref @$S18pointer_conversion23takesOptConstRawPointer_3andySVSg_SitF :
+  // CHECK: apply [[TAKES_OPT_CONST_RAW_POINTER]]([[OPTPTR]], [[RESULT1]])
+  // CHECK: destroy_value [[OWNER]]
+}
+
+// CHECK-LABEL: sil hidden @$S18pointer_conversion14inoutToPointeryyF 
+func inoutToPointer() {
+  var int = 0
+  // CHECK: [[INT:%.*]] = alloc_box ${ var Int }
+  // CHECK: [[PB:%.*]] = project_box [[INT]]
+  takesMutablePointer(&int)
+  // CHECK: [[WRITE:%.*]] = begin_access [modify] [unknown] [[PB]]
+  // CHECK: [[POINTER:%.*]] = address_to_pointer [[WRITE]]
+  // CHECK: [[CONVERT:%.*]] = function_ref @$Ss30_convertInOutToPointerArgument{{[_0-9a-zA-Z]*}}F
+  // CHECK: apply [[CONVERT]]<UnsafeMutablePointer<Int>>({{%.*}}, [[POINTER]])
+  // CHECK: [[TAKES_MUTABLE:%.*]] = function_ref @$S18pointer_conversion19takesMutablePointer{{[_0-9a-zA-Z]*}}F
+  // CHECK: apply [[TAKES_MUTABLE]]
+
+  var logicalInt: Int {
+    get { return 0 }
+    set { }
+  }
+  takesMutablePointer(&logicalInt)
+  // CHECK: [[GETTER:%.*]] = function_ref @$S18pointer_conversion14inoutToPointeryyF10logicalIntL_Sivg
+  // CHECK: apply [[GETTER]]
+  // CHECK: [[CONVERT:%.*]] = function_ref @$Ss30_convertInOutToPointerArgument{{[_0-9a-zA-Z]*}}F
+  // CHECK: apply [[CONVERT]]<UnsafeMutablePointer<Int>>
+  // CHECK: [[TAKES_MUTABLE:%.*]] = function_ref @$S18pointer_conversion19takesMutablePointer{{[_0-9a-zA-Z]*}}F
+  // CHECK: apply [[TAKES_MUTABLE]]
+  // CHECK: [[SETTER:%.*]] = function_ref @$S18pointer_conversion14inoutToPointeryyF10logicalIntL_Sivs
+  // CHECK: apply [[SETTER]]
+
+  takesMutableRawPointer(&int)
+  // CHECK: [[WRITE:%.*]] = begin_access [modify] [unknown] [[PB]]
+  // CHECK: [[POINTER:%.*]] = address_to_pointer [[WRITE]]
+  // CHECK: [[CONVERT:%.*]] = function_ref @$Ss30_convertInOutToPointerArgument{{[_0-9a-zA-Z]*}}F
+  // CHECK: apply [[CONVERT]]<UnsafeMutableRawPointer>({{%.*}}, [[POINTER]])
+  // CHECK: [[TAKES_MUTABLE:%.*]] = function_ref @$S18pointer_conversion22takesMutableRawPointer{{[_0-9a-zA-Z]*}}F
+  // CHECK: apply [[TAKES_MUTABLE]]
+
+  takesMutableRawPointer(&logicalInt)
+  // CHECK: [[GETTER:%.*]] = function_ref @$S18pointer_conversion14inoutToPointeryyF10logicalIntL_Sivg
+  // CHECK: apply [[GETTER]]
+  // CHECK: [[CONVERT:%.*]] = function_ref @$Ss30_convertInOutToPointerArgument{{[_0-9a-zA-Z]*}}F
+  // CHECK: apply [[CONVERT]]<UnsafeMutableRawPointer>
+  // CHECK: [[TAKES_MUTABLE:%.*]] = function_ref @$S18pointer_conversion22takesMutableRawPointer{{[_0-9a-zA-Z]*}}F
+  // CHECK: apply [[TAKES_MUTABLE]]
+  // CHECK: [[SETTER:%.*]] = function_ref @$S18pointer_conversion14inoutToPointeryyF10logicalIntL_Sivs
+  // CHECK: apply [[SETTER]]
+}
+
+class C {}
+
+func takesPlusOnePointer(_ x: UnsafeMutablePointer<C>) {}
+func takesPlusZeroPointer(_ x: AutoreleasingUnsafeMutablePointer<C>) {}
+func takesPlusZeroOptionalPointer(_ x: AutoreleasingUnsafeMutablePointer<C?>) {}
+
+// CHECK-LABEL: sil hidden @$S18pointer_conversion19classInoutToPointeryyF
+func classInoutToPointer() {
+  var c = C()
+  // CHECK: [[VAR:%.*]] = alloc_box ${ var C }
+  // CHECK: [[PB:%.*]] = project_box [[VAR]]
+  takesPlusOnePointer(&c)
+  // CHECK: [[WRITE:%.*]] = begin_access [modify] [unknown] [[PB]]
+  // CHECK: [[POINTER:%.*]] = address_to_pointer [[WRITE]]
+  // CHECK: [[CONVERT:%.*]] = function_ref @$Ss30_convertInOutToPointerArgument{{[_0-9a-zA-Z]*}}F
+  // CHECK: apply [[CONVERT]]<UnsafeMutablePointer<C>>({{%.*}}, [[POINTER]])
+  // CHECK: [[TAKES_PLUS_ONE:%.*]] = function_ref @$S18pointer_conversion19takesPlusOnePointer{{[_0-9a-zA-Z]*}}F
+  // CHECK: apply [[TAKES_PLUS_ONE]]
+
+  takesPlusZeroPointer(&c)
+  // CHECK: [[WRITEBACK:%.*]] = alloc_stack $@sil_unmanaged C
+  // CHECK: [[OWNED:%.*]] = load_borrow [[PB]]
+  // CHECK: [[UNOWNED:%.*]] = ref_to_unmanaged [[OWNED]]
+  // CHECK: store [[UNOWNED]] to [trivial] [[WRITEBACK]]
+  // CHECK: [[POINTER:%.*]] = address_to_pointer [[WRITEBACK]]
+  // CHECK: [[CONVERT:%.*]] = function_ref @$Ss30_convertInOutToPointerArgument{{[_0-9a-zA-Z]*}}F
+  // CHECK: apply [[CONVERT]]<AutoreleasingUnsafeMutablePointer<C>>({{%.*}}, [[POINTER]])
+  // CHECK: [[TAKES_PLUS_ZERO:%.*]] = function_ref @$S18pointer_conversion20takesPlusZeroPointeryys026AutoreleasingUnsafeMutableF0VyAA1CCGF
+  // CHECK: apply [[TAKES_PLUS_ZERO]]
+  // CHECK: [[UNOWNED_OUT:%.*]] = load [trivial] [[WRITEBACK]]
+  // CHECK: [[OWNED_OUT:%.*]] = unmanaged_to_ref [[UNOWNED_OUT]]
+  // CHECK: [[OWNED_OUT_COPY:%.*]] = copy_value [[OWNED_OUT]]
+  // CHECK: assign [[OWNED_OUT_COPY]] to [[PB]]
+
+  var cq: C? = C()
+  takesPlusZeroOptionalPointer(&cq)
+}
+
+// Check that pointer types don't bridge anymore.
+@objc class ObjCMethodBridging : NSObject {
+  // CHECK-LABEL: sil hidden [thunk] @$S18pointer_conversion18ObjCMethodBridgingC0A4Args{{[_0-9a-zA-Z]*}}FTo : $@convention(objc_method) (UnsafeMutablePointer<Int>, UnsafePointer<Int>, AutoreleasingUnsafeMutablePointer<ObjCMethodBridging>, ObjCMethodBridging)
+  @objc func pointerArgs(_ x: UnsafeMutablePointer<Int>,
+                         y: UnsafePointer<Int>,
+                         z: AutoreleasingUnsafeMutablePointer<ObjCMethodBridging>) {}
+}
+
+// rdar://problem/21505805
+// CHECK-LABEL: sil hidden @$S18pointer_conversion22functionInoutToPointeryyF
+func functionInoutToPointer() {
+  // CHECK: [[BOX:%.*]] = alloc_box ${ var @callee_guaranteed () -> () }
+  var f: () -> () = {}
+
+  // CHECK: [[REABSTRACT_BUF:%.*]] = alloc_stack $@callee_guaranteed (@in_guaranteed ()) -> @out ()
+  // CHECK: address_to_pointer [[REABSTRACT_BUF]]
+  takesMutableVoidPointer(&f)
+}
+
+// rdar://problem/31781386
+// CHECK-LABEL: sil hidden @$S18pointer_conversion20inoutPointerOrderingyyF
+func inoutPointerOrdering() {
+  // CHECK: [[ARRAY_BOX:%.*]] = alloc_box ${ var Array<Int> }
+  // CHECK: [[ARRAY:%.*]] = project_box [[ARRAY_BOX]] :
+  // CHECK: store {{.*}} to [init] [[ARRAY]]
+  var array = [Int]()
+
+  // CHECK: [[SIDE1:%.*]] = function_ref @$S18pointer_conversion11sideEffect1SiyF
+  // CHECK: [[RESULT1:%.*]] = apply [[SIDE1]]()
+  // CHECK: [[SIDE2:%.*]] = function_ref @$S18pointer_conversion11sideEffect2SiyF
+  // CHECK: [[RESULT2:%.*]] = apply [[SIDE2]]()
+  // CHECK: [[ACCESS:%.*]] = begin_access [modify] [unknown] [[ARRAY]] : $*Array<Int>
+  // CHECK: [[TAKES_MUTABLE:%.*]] = function_ref @$S18pointer_conversion19takesMutablePointer_3andySpySiG_SitF
+  // CHECK: apply [[TAKES_MUTABLE]]({{.*}}, [[RESULT2]])
+  // CHECK: strong_unpin
+  // CHECK: end_access [[ACCESS]]
+  takesMutablePointer(&array[sideEffect1()], and: sideEffect2())
+
+  // CHECK: [[SIDE1:%.*]] = function_ref @$S18pointer_conversion11sideEffect1SiyF
+  // CHECK: [[RESULT1:%.*]] = apply [[SIDE1]]()
+  // CHECK: [[SIDE2:%.*]] = function_ref @$S18pointer_conversion11sideEffect2SiyF
+  // CHECK: [[RESULT2:%.*]] = apply [[SIDE2]]()
+  // CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] [[ARRAY]] : $*Array<Int>
+  // CHECK: [[TAKES_CONST:%.*]] = function_ref @$S18pointer_conversion17takesConstPointer_3andySPySiG_SitF
+  // CHECK: apply [[TAKES_CONST]]({{.*}}, [[RESULT2]])
+  // CHECK: end_access [[ACCESS]]
+  takesConstPointer(&array[sideEffect1()], and: sideEffect2())
+}
+
+// rdar://problem/31542269
+// CHECK-LABEL: sil hidden @$S18pointer_conversion20optArrayToOptPointer5arrayySaySiGSg_tF
+func optArrayToOptPointer(array: [Int]?) {
+  // CHECK:   [[COPY:%.*]] = copy_value %0
+  // CHECK:   [[SIDE1:%.*]] = function_ref @$S18pointer_conversion11sideEffect1SiyF
+  // CHECK:   [[RESULT1:%.*]] = apply [[SIDE1]]()
+  // CHECK:   [[T0:%.*]] = select_enum [[COPY]]
+  // CHECK:   cond_br [[T0]], [[SOME_BB:bb[0-9]+]], [[NONE_BB:bb[0-9]+]]
+  // CHECK: [[SOME_BB]]:
+  // CHECK:   [[SOME_VALUE:%.*]] = unchecked_enum_data [[COPY]]
+  // CHECK:   [[CONVERT:%.*]] = function_ref @$Ss35_convertConstArrayToPointerArgumentyyXlSg_q_tSayxGs01_E0R_r0_lF
+  // CHECK:   [[TEMP:%.*]] = alloc_stack $UnsafePointer<Int>
+  // CHECK:   [[OWNER:%.*]] = apply [[CONVERT]]<Int, UnsafePointer<Int>>([[TEMP:%.*]], [[SOME_VALUE]])
+  // CHECK:   [[PTR:%.*]] = load [trivial] [[TEMP]]
+  // CHECK:   [[DEP:%.*]] = mark_dependence [[PTR]] : $UnsafePointer<Int> on [[OWNER]]
+  // CHECK:   [[OPTPTR:%.*]] = enum $Optional<UnsafePointer<Int>>, #Optional.some!enumelt.1, [[DEP]]
+  // CHECK:   dealloc_stack [[TEMP]]
+  // CHECK:   br [[CONT_BB:bb[0-9]+]]([[OPTPTR]] : $Optional<UnsafePointer<Int>>, [[OWNER]] : $Optional<AnyObject>)
+  // CHECK: [[CONT_BB]]([[OPTPTR:%.*]] : $Optional<UnsafePointer<Int>>, [[OWNER:%.*]] : $Optional<AnyObject>):
+  // CHECK:   [[OPTDEP:%.*]] = mark_dependence [[OPTPTR]] : $Optional<UnsafePointer<Int>> on [[OWNER]]
+  // CHECK:   [[TAKES:%.*]] = function_ref @$S18pointer_conversion20takesOptConstPointer_3andySPySiGSg_SitF
+  // CHECK:   apply [[TAKES]]([[OPTDEP]], [[RESULT1]])
+  // CHECK:   destroy_value [[OWNER]]
+  // CHECK-NOT:   destroy_value %0
+  // CHECK: [[NONE_BB]]:
+  // CHECK:   [[NO_VALUE:%.*]] = enum $Optional<UnsafePointer<Int>>, #Optional.none
+  // CHECK:   [[NO_OWNER:%.*]] = enum $Optional<AnyObject>, #Optional.none
+  // CHECK:   br [[CONT_BB]]([[NO_VALUE]] : $Optional<UnsafePointer<Int>>, [[NO_OWNER]] : $Optional<AnyObject>)
+  takesOptConstPointer(array, and: sideEffect1())
+}
+
+// CHECK-LABEL: sil hidden @$S18pointer_conversion013optOptArrayTodD7Pointer5arrayySaySiGSgSg_tF
+func optOptArrayToOptOptPointer(array: [Int]??) {
+  // CHECK:   [[COPY:%.*]] = copy_value %0
+  // CHECK:   [[SIDE1:%.*]] = function_ref @$S18pointer_conversion11sideEffect1SiyF
+  // CHECK:   [[RESULT1:%.*]] = apply [[SIDE1]]()
+  // CHECK:   [[T0:%.*]] = select_enum [[COPY]]
+  // CHECK:   cond_br [[T0]], [[SOME_BB:bb[0-9]+]], [[NONE_BB:bb[0-9]+]]
+  // CHECK: [[SOME_BB]]:
+  // CHECK:   [[SOME_VALUE:%.*]] = unchecked_enum_data [[COPY]]
+  // CHECK:   [[T0:%.*]] = select_enum [[SOME_VALUE]]
+  // CHECK:   cond_br [[T0]], [[SOME_SOME_BB:bb[0-9]+]], [[SOME_NONE_BB:bb[0-9]+]]
+  // CHECK: [[SOME_NONE_BB]]:
+  // CHECK:   destroy_value [[SOME_VALUE]]
+  // CHECK:   br [[SOME_NONE_BB2:bb[0-9]+]]
+  // CHECK: [[SOME_SOME_BB]]:
+  // CHECK:   [[SOME_SOME_VALUE:%.*]] = unchecked_enum_data [[SOME_VALUE]]
+  // CHECK:   [[CONVERT:%.*]] = function_ref @$Ss35_convertConstArrayToPointerArgumentyyXlSg_q_tSayxGs01_E0R_r0_lF
+  // CHECK:   [[TEMP:%.*]] = alloc_stack $UnsafePointer<Int>
+  // CHECK:   [[OWNER:%.*]] = apply [[CONVERT]]<Int, UnsafePointer<Int>>([[TEMP:%.*]], [[SOME_SOME_VALUE]])
+  // CHECK:   [[PTR:%.*]] = load [trivial] [[TEMP]]
+  // CHECK:   [[DEP:%.*]] = mark_dependence [[PTR]] : $UnsafePointer<Int> on [[OWNER]]
+  // CHECK:   [[OPTPTR:%.*]] = enum $Optional<UnsafePointer<Int>>, #Optional.some!enumelt.1, [[DEP]]
+  // CHECK:   dealloc_stack [[TEMP]]
+  // CHECK:   br [[SOME_SOME_CONT_BB:bb[0-9]+]]([[OPTPTR]] : $Optional<UnsafePointer<Int>>, [[OWNER]] : $Optional<AnyObject>)
+  // CHECK: [[SOME_SOME_CONT_BB]]([[OPTPTR:%.*]] : $Optional<UnsafePointer<Int>>, [[OWNER:%.*]] : $Optional<AnyObject>):
+  // CHECK:   [[OPTDEP:%.*]] = mark_dependence [[OPTPTR]] : $Optional<UnsafePointer<Int>> on [[OWNER]]
+  // CHECK:   [[OPTOPTPTR:%.*]] = enum $Optional<Optional<UnsafePointer<Int>>>, #Optional.some!enumelt.1, [[OPTDEP]]
+  // CHECK:   br [[SOME_CONT_BB:bb[0-9]+]]([[OPTOPTPTR]] : $Optional<Optional<UnsafePointer<Int>>>, [[OWNER]] : $Optional<AnyObject>)
+  // CHECK: [[SOME_CONT_BB]]([[OPTOPTPTR:%.*]] : $Optional<Optional<UnsafePointer<Int>>>, [[OWNER:%.*]] : $Optional<AnyObject>):
+  // CHECK:   [[OPTOPTDEP:%.*]] = mark_dependence [[OPTOPTPTR]] : $Optional<Optional<UnsafePointer<Int>>> on [[OWNER]]
+  // CHECK:   [[TAKES:%.*]] = function_ref @$S18pointer_conversion08takesOptD12ConstPointer_3andySPySiGSgSg_SitF
+  // CHECK:   apply [[TAKES]]([[OPTOPTDEP]], [[RESULT1]])
+  // CHECK:   destroy_value [[OWNER]]
+  // CHECK-NOT:   destroy_value %0
+  // CHECK: [[SOME_NONE_BB2]]:
+  // CHECK:   [[NO_VALUE:%.*]] = enum $Optional<UnsafePointer<Int>>, #Optional.none
+  // CHECK:   [[NO_OWNER:%.*]] = enum $Optional<AnyObject>, #Optional.none
+  // CHECK:   br [[SOME_SOME_CONT_BB]]([[NO_VALUE]] : $Optional<UnsafePointer<Int>>, [[NO_OWNER]] : $Optional<AnyObject>)
+  // CHECK: [[NONE_BB]]:
+  // CHECK:   [[NO_VALUE:%.*]] = enum $Optional<Optional<UnsafePointer<Int>>>, #Optional.none
+  // CHECK:   [[NO_OWNER:%.*]] = enum $Optional<AnyObject>, #Optional.none
+  // CHECK:   br [[SOME_CONT_BB]]([[NO_VALUE]] : $Optional<Optional<UnsafePointer<Int>>>, [[NO_OWNER]] : $Optional<AnyObject>)
+  takesOptOptConstPointer(array, and: sideEffect1())
+}
+
+// CHECK-LABEL: sil hidden @$S18pointer_conversion21optStringToOptPointer6stringySSSg_tF
+func optStringToOptPointer(string: String?) {
+  // CHECK:   [[COPY:%.*]] = copy_value %0
+  // CHECK:   [[SIDE1:%.*]] = function_ref @$S18pointer_conversion11sideEffect1SiyF
+  // CHECK:   [[RESULT1:%.*]] = apply [[SIDE1]]()
+  // CHECK:   [[T0:%.*]] = select_enum [[COPY]]
+  // CHECK:   cond_br [[T0]], [[SOME_BB:bb[0-9]+]], [[NONE_BB:bb[0-9]+]]
+  // CHECK: [[SOME_BB]]:
+  // CHECK:   [[SOME_VALUE:%.*]] = unchecked_enum_data [[COPY]]
+  // CHECK:   [[CONVERT:%.*]] = function_ref @$Ss40_convertConstStringToUTF8PointerArgumentyyXlSg_xtSSs01_F0RzlF
+  // CHECK:   [[TEMP:%.*]] = alloc_stack $UnsafeRawPointer
+  // CHECK:   [[OWNER:%.*]] = apply [[CONVERT]]<UnsafeRawPointer>([[TEMP:%.*]], [[SOME_VALUE]])
+  // CHECK:   [[PTR:%.*]] = load [trivial] [[TEMP]]
+  // CHECK:   [[DEP:%.*]] = mark_dependence [[PTR]] : $UnsafeRawPointer on [[OWNER]]
+  // CHECK:   [[OPTPTR:%.*]] = enum $Optional<UnsafeRawPointer>, #Optional.some!enumelt.1, [[DEP]]
+  // CHECK:   dealloc_stack [[TEMP]]
+  // CHECK:   br [[CONT_BB:bb[0-9]+]]([[OPTPTR]] : $Optional<UnsafeRawPointer>, [[OWNER]] : $Optional<AnyObject>)
+  // CHECK: [[CONT_BB]]([[OPTPTR:%.*]] : $Optional<UnsafeRawPointer>, [[OWNER:%.*]] : $Optional<AnyObject>):
+  // CHECK:   [[OPTDEP:%.*]] = mark_dependence [[OPTPTR]] : $Optional<UnsafeRawPointer> on [[OWNER]]
+  // CHECK:   [[TAKES:%.*]] = function_ref @$S18pointer_conversion23takesOptConstRawPointer_3andySVSg_SitF
+  // CHECK:   apply [[TAKES]]([[OPTDEP]], [[RESULT1]])
+  // CHECK:   destroy_value [[OWNER]]
+  // CHECK-NOT:   destroy_value %0
+  // CHECK: [[NONE_BB]]:
+  // CHECK:   [[NO_VALUE:%.*]] = enum $Optional<UnsafeRawPointer>, #Optional.none
+  // CHECK:   [[NO_OWNER:%.*]] = enum $Optional<AnyObject>, #Optional.none
+  // CHECK:   br [[CONT_BB]]([[NO_VALUE]] : $Optional<UnsafeRawPointer>, [[NO_OWNER]] : $Optional<AnyObject>)
+  takesOptConstRawPointer(string, and: sideEffect1())
+}
+
+// CHECK-LABEL: sil hidden @$S18pointer_conversion014optOptStringTodD7Pointer6stringySSSgSg_tF
+func optOptStringToOptOptPointer(string: String??) {
+  // CHECK:   [[COPY:%.*]] = copy_value %0
+  // CHECK:   [[SIDE1:%.*]] = function_ref @$S18pointer_conversion11sideEffect1SiyF
+  // CHECK:   [[RESULT1:%.*]] = apply [[SIDE1]]()
+  // CHECK:   [[T0:%.*]] = select_enum [[COPY]]
+  //   FIXME: this should really go somewhere that will make nil, not some(nil)
+  // CHECK:   cond_br [[T0]], [[SOME_BB:bb[0-9]+]], [[NONE_BB:bb[0-9]+]]
+  // CHECK: [[SOME_BB]]:
+  // CHECK:   [[SOME_VALUE:%.*]] = unchecked_enum_data [[COPY]]
+  // CHECK:   [[T0:%.*]] = select_enum [[SOME_VALUE]]
+  // CHECK:   cond_br [[T0]], [[SOME_SOME_BB:bb[0-9]+]], [[SOME_NONE_BB:bb[0-9]+]]
+  // CHECK: [[SOME_NONE_BB]]:
+  // CHECK:   destroy_value [[SOME_VALUE]]
+  // CHECK:   br [[SOME_NONE_BB2:bb[0-9]+]]
+  // CHECK: [[SOME_SOME_BB]]:
+  // CHECK:   [[SOME_SOME_VALUE:%.*]] = unchecked_enum_data [[SOME_VALUE]]
+  // CHECK:   [[CONVERT:%.*]] = function_ref @$Ss40_convertConstStringToUTF8PointerArgumentyyXlSg_xtSSs01_F0RzlF
+  // CHECK:   [[TEMP:%.*]] = alloc_stack $UnsafeRawPointer
+  // CHECK:   [[OWNER:%.*]] = apply [[CONVERT]]<UnsafeRawPointer>([[TEMP:%.*]], [[SOME_SOME_VALUE]])
+  // CHECK:   [[PTR:%.*]] = load [trivial] [[TEMP]]
+  // CHECK:   [[DEP:%.*]] = mark_dependence [[PTR]] : $UnsafeRawPointer on [[OWNER]]
+  // CHECK:   [[OPTPTR:%.*]] = enum $Optional<UnsafeRawPointer>, #Optional.some!enumelt.1, [[DEP]]
+  // CHECK:   dealloc_stack [[TEMP]]
+  // CHECK:   br [[SOME_SOME_CONT_BB:bb[0-9]+]]([[OPTPTR]] : $Optional<UnsafeRawPointer>, [[OWNER]] : $Optional<AnyObject>)
+  // CHECK: [[SOME_SOME_CONT_BB]]([[OPTPTR:%.*]] : $Optional<UnsafeRawPointer>, [[OWNER:%.*]] : $Optional<AnyObject>):
+  // CHECK:   [[OPTDEP:%.*]] = mark_dependence [[OPTPTR]] : $Optional<UnsafeRawPointer> on [[OWNER]]
+  // CHECK:   [[OPTOPTPTR:%.*]] = enum $Optional<Optional<UnsafeRawPointer>>, #Optional.some!enumelt.1, [[OPTDEP]]
+  // CHECK:   br [[SOME_CONT_BB:bb[0-9]+]]([[OPTOPTPTR]] : $Optional<Optional<UnsafeRawPointer>>, [[OWNER]] : $Optional<AnyObject>)
+  // CHECK: [[SOME_CONT_BB]]([[OPTOPTPTR:%.*]] : $Optional<Optional<UnsafeRawPointer>>, [[OWNER:%.*]] : $Optional<AnyObject>):
+  // CHECK:   [[OPTOPTDEP:%.*]] = mark_dependence [[OPTOPTPTR]] : $Optional<Optional<UnsafeRawPointer>> on [[OWNER]]
+  // CHECK:   [[TAKES:%.*]] = function_ref @$S18pointer_conversion08takesOptD15ConstRawPointer_3andySVSgSg_SitF
+  // CHECK:   apply [[TAKES]]([[OPTOPTDEP]], [[RESULT1]])
+  // CHECK:   destroy_value [[OWNER]]
+  // CHECK:   end_borrow [[BORROW]]
+  // CHECK:   destroy_value %0
+  // CHECK: [[SOME_NONE_BB2]]:
+  // CHECK:   [[NO_VALUE:%.*]] = enum $Optional<UnsafeRawPointer>, #Optional.none
+  // CHECK:   [[NO_OWNER:%.*]] = enum $Optional<AnyObject>, #Optional.none
+  // CHECK:   br [[SOME_SOME_CONT_BB]]([[NO_VALUE]] : $Optional<UnsafeRawPointer>, [[NO_OWNER]] : $Optional<AnyObject>)
+  // CHECK: [[NONE_BB]]:
+  // CHECK:   [[NO_VALUE:%.*]] = enum $Optional<Optional<UnsafeRawPointer>>, #Optional.none
+  // CHECK:   [[NO_OWNER:%.*]] = enum $Optional<AnyObject>, #Optional.none
+  // CHECK:   br [[SOME_CONT_BB]]([[NO_VALUE]] : $Optional<Optional<UnsafeRawPointer>>, [[NO_OWNER]] : $Optional<AnyObject>)
+  takesOptOptConstRawPointer(string, and: sideEffect1())
+}
diff --git a/test/SILGen/plus_zero_properties.swift b/test/SILGen/plus_zero_properties.swift
new file mode 100644
index 0000000..76dd9c9
--- /dev/null
+++ b/test/SILGen/plus_zero_properties.swift
@@ -0,0 +1,1191 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -Xllvm -sil-full-demangle -parse-as-library -emit-silgen -disable-objc-attr-requires-foundation-module %s | %FileCheck %s
+
+var zero: Int = 0
+
+func use(_: Int) {}
+func use(_: Double) {}
+func getInt() -> Int { return zero }
+
+// CHECK-LABEL: sil hidden @{{.*}}physical_tuple_lvalue
+// CHECK: bb0(%0 : $Int):
+func physical_tuple_lvalue(_ c: Int) {
+  var x : (Int, Int)
+  // CHECK: [[BOX:%[0-9]+]] = alloc_box ${ var (Int, Int) }
+  // CHECK: [[MARKED_BOX:%[0-9]+]] = mark_uninitialized [var] [[BOX]]
+  // CHECK: [[XADDR:%.*]] = project_box [[MARKED_BOX]]
+  x.1 = c
+  // CHECK: [[WRITE:%.*]] = begin_access [modify] [unknown] [[XADDR]]
+  // CHECK: [[X_1:%[0-9]+]] = tuple_element_addr [[WRITE]] : {{.*}}, 1
+  // CHECK: assign %0 to [[X_1]]
+}
+
+func tuple_rvalue() -> (Int, Int) {}
+
+// CHECK-LABEL: sil hidden @{{.*}}physical_tuple_rvalue
+func physical_tuple_rvalue() -> Int {
+  return tuple_rvalue().1
+  // CHECK: [[FUNC:%[0-9]+]] = function_ref @$S10properties12tuple_rvalue{{[_0-9a-zA-Z]*}}F
+  // CHECK: [[TUPLE:%[0-9]+]] = apply [[FUNC]]()
+  // CHECK: [[RET:%[0-9]+]] = tuple_extract [[TUPLE]] : {{.*}}, 1
+  // CHECK: return [[RET]]
+}
+
+// CHECK-LABEL: sil hidden @$S10properties16tuple_assignment{{[_0-9a-zA-Z]*}}F
+func tuple_assignment(_ a: inout Int, b: inout Int) {
+  // CHECK: bb0([[A_ADDR:%[0-9]+]] : $*Int, [[B_ADDR:%[0-9]+]] : $*Int):
+  // CHECK: [[READ:%.*]] = begin_access [read] [unknown] [[B_ADDR]]
+  // CHECK: [[B:%[0-9]+]] = load [trivial] [[READ]]
+  // CHECK: [[READ:%.*]] = begin_access [read] [unknown] [[A_ADDR]]
+  // CHECK: [[A:%[0-9]+]] = load [trivial] [[READ]]
+  // CHECK: [[WRITE:%.*]] = begin_access [modify] [unknown] [[A_ADDR]]
+  // CHECK: assign [[B]] to [[WRITE]]
+  // CHECK: [[WRITE:%.*]] = begin_access [modify] [unknown] [[B_ADDR]]
+  // CHECK: assign [[A]] to [[WRITE]]
+  (a, b) = (b, a)
+}
+
+// CHECK-LABEL: sil hidden @$S10properties18tuple_assignment_2{{[_0-9a-zA-Z]*}}F
+func tuple_assignment_2(_ a: inout Int, b: inout Int, xy: (Int, Int)) {
+  // CHECK: bb0([[A_ADDR:%[0-9]+]] : $*Int, [[B_ADDR:%[0-9]+]] : $*Int, [[X:%[0-9]+]] : $Int, [[Y:%[0-9]+]] : $Int):
+  (a, b) = xy
+  // CHECK: [[XY2:%[0-9]+]] = tuple ([[X]] : $Int, [[Y]] : $Int)
+  // CHECK: [[X:%[0-9]+]] = tuple_extract [[XY2]] : {{.*}}, 0
+  // CHECK: [[Y:%[0-9]+]] = tuple_extract [[XY2]] : {{.*}}, 1
+  // CHECK: [[WRITE:%.*]] = begin_access [modify] [unknown] [[A_ADDR]]
+  // CHECK: assign [[X]] to [[WRITE]]
+  // CHECK: [[WRITE:%.*]] = begin_access [modify] [unknown] [[B_ADDR]]
+  // CHECK: assign [[Y]] to [[WRITE]]
+}
+
+class Ref {
+  var x, y : Int
+  var ref : Ref
+
+  var z: Int { get {} set {} }
+
+  var val_prop: Val { get {} set {} }
+
+  subscript(i: Int) -> Float { get {} set {} }
+
+  init(i: Int) {
+    x = i
+    y = i
+    ref = self
+  }
+}
+
+class RefSubclass : Ref {
+  var w : Int
+
+  override init (i: Int) {
+    w = i
+    super.init(i: i)
+  }
+}
+
+struct Val {
+  var x, y : Int
+  var ref : Ref
+
+  var z: Int { get {} set {} }
+
+  var z_tuple: (Int, Int) { get {} set {} }
+
+  subscript(i: Int) -> Float { get {} set {} }
+}
+
+// CHECK-LABEL: sil hidden @$S10properties22physical_struct_lvalue{{[_0-9a-zA-Z]*}}F
+func physical_struct_lvalue(_ c: Int) {
+  var v : Val
+  // CHECK: [[VADDR:%[0-9]+]] = alloc_box ${ var Val }
+  v.y = c
+  // CHECK: [[WRITE:%.*]] = begin_access [modify] [unknown]
+  // CHECK: [[YADDR:%.*]] = struct_element_addr [[WRITE]]
+  // CHECK: assign %0 to [[YADDR]]
+}
+
+// CHECK-LABEL: sil hidden @$S10properties21physical_class_lvalue{{[_0-9a-zA-Z]*}}F : $@convention(thin) (@guaranteed Ref, Int) -> ()
+// CHECK: bb0([[ARG0:%.*]] : $Ref,
+ func physical_class_lvalue(_ r: Ref, a: Int) {
+    r.y = a
+   // CHECK: [[FN:%[0-9]+]] = class_method [[ARG0]] : $Ref, #Ref.y!setter.1
+   // CHECK: apply [[FN]](%1, [[ARG0]]) : $@convention(method) (Int, @guaranteed Ref) -> ()
+  }
+
+
+// CHECK-LABEL: sil hidden @$S10properties24physical_subclass_lvalue{{[_0-9a-zA-Z]*}}F
+func physical_subclass_lvalue(_ r: RefSubclass, a: Int) {
+  // CHECK: bb0([[ARG1:%.*]] : $RefSubclass, [[ARG2:%.*]] : $Int):
+  r.y = a
+  // CHECK: [[ARG1_COPY:%.*]] = copy_value [[ARG1]] : $RefSubclass
+  // CHECK: [[R_SUP:%[0-9]+]] = upcast [[ARG1_COPY]] : $RefSubclass to $Ref
+  // CHECK: [[FN:%[0-9]+]] = class_method [[R_SUP]] : $Ref, #Ref.y!setter.1 : (Ref) -> (Int) -> (), $@convention(method) (Int, @guaranteed Ref) -> ()
+  // CHECK: apply [[FN]]([[ARG2]], [[R_SUP]]) :
+  // CHECK: destroy_value [[R_SUP]]
+  r.w = a
+
+  // CHECK: [[FN:%[0-9]+]] = class_method [[ARG1]] : $RefSubclass, #RefSubclass.w!setter.1
+  // CHECK: apply [[FN]](%1, [[ARG1]]) : $@convention(method) (Int, @guaranteed RefSubclass) -> ()
+  // CHECK-NOT: destroy_value [[ARG1]]
+  // CHECK: } // end sil function '$S10properties24physical_subclass_lvalue{{[_0-9a-zA-Z]*}}F'
+}
+  
+
+
+func struct_rvalue() -> Val {}
+
+// CHECK-LABEL: sil hidden @$S10properties22physical_struct_rvalue{{[_0-9a-zA-Z]*}}F
+func physical_struct_rvalue() -> Int {
+  return struct_rvalue().y
+  // CHECK: [[FUNC:%[0-9]+]] = function_ref @$S10properties13struct_rvalueAA3ValVyF
+  // CHECK: [[STRUCT:%[0-9]+]] = apply [[FUNC]]()
+  // CHECK: [[BORROWED_STRUCT:%.*]] = begin_borrow [[STRUCT]]
+  // CHECK: [[RET:%[0-9]+]] = struct_extract [[BORROWED_STRUCT]] : $Val, #Val.y
+  // CHECK: end_borrow [[BORROWED_STRUCT]] from [[STRUCT]]
+  // CHECK: destroy_value [[STRUCT]]
+  // CHECK: return [[RET]]
+}
+
+func class_rvalue() -> Ref {}
+
+// CHECK-LABEL: sil hidden @$S10properties21physical_class_rvalue{{[_0-9a-zA-Z]*}}F
+func physical_class_rvalue() -> Int {
+  return class_rvalue().y
+  // CHECK: [[FUNC:%[0-9]+]] = function_ref @$S10properties12class_rvalueAA3RefCyF
+  // CHECK: [[CLASS:%[0-9]+]] = apply [[FUNC]]()
+  // CHECK: [[FN:%[0-9]+]] = class_method [[CLASS]] : $Ref, #Ref.y!getter.1
+  // CHECK: [[RET:%[0-9]+]] = apply [[FN]]([[CLASS]])
+  // CHECK: return [[RET]]
+}
+
+// CHECK-LABEL: sil hidden @$S10properties18logical_struct_get{{[_0-9a-zA-Z]*}}F
+func logical_struct_get() -> Int {
+  return struct_rvalue().z
+  // CHECK: [[GET_RVAL:%[0-9]+]] = function_ref @$S10properties13struct_rvalue{{[_0-9a-zA-Z]*}}F
+  // CHECK: [[STRUCT:%[0-9]+]] = apply [[GET_RVAL]]()
+  // CHECK: [[GET_METHOD:%[0-9]+]] = function_ref @$S10properties3ValV1z{{[_0-9a-zA-Z]*}}vg
+  // CHECK: [[VALUE:%[0-9]+]] = apply [[GET_METHOD]]([[STRUCT]])
+  // CHECK: return [[VALUE]]
+}
+
+// CHECK-LABEL: sil hidden @$S10properties18logical_struct_set{{[_0-9a-zA-Z]*}}F
+func logical_struct_set(_ value: inout Val, z: Int) {
+  // CHECK: bb0([[VAL:%[0-9]+]] : $*Val, [[Z:%[0-9]+]] : $Int):
+  value.z = z
+  // CHECK: [[WRITE:%.*]] = begin_access [modify] [unknown] [[VAL]]
+  // CHECK: [[Z_SET_METHOD:%[0-9]+]] = function_ref @$S10properties3ValV1z{{[_0-9a-zA-Z]*}}vs
+  // CHECK: apply [[Z_SET_METHOD]]([[Z]], [[WRITE]])
+  // CHECK: return
+}
+
+// CHECK-LABEL: sil hidden @$S10properties27logical_struct_in_tuple_set{{[_0-9a-zA-Z]*}}F
+func logical_struct_in_tuple_set(_ value: inout (Int, Val), z: Int) {
+  // CHECK: bb0([[VAL:%[0-9]+]] : $*(Int, Val), [[Z:%[0-9]+]] : $Int):
+  value.1.z = z
+  // CHECK: [[WRITE:%.*]] = begin_access [modify] [unknown] [[VAL]]
+  // CHECK: [[VAL_1:%[0-9]+]] = tuple_element_addr [[WRITE]] : {{.*}}, 1
+  // CHECK: [[Z_SET_METHOD:%[0-9]+]] = function_ref @$S10properties3ValV1z{{[_0-9a-zA-Z]*}}vs
+  // CHECK: apply [[Z_SET_METHOD]]([[Z]], [[VAL_1]])
+  // CHECK: return
+}
+
+// CHECK-LABEL: sil hidden @$S10properties29logical_struct_in_reftype_set{{[_0-9a-zA-Z]*}}F
+func logical_struct_in_reftype_set(_ value: inout Val, z1: Int) {
+  // CHECK: bb0([[VAL:%[0-9]+]] : $*Val, [[Z1:%[0-9]+]] : $Int):
+  value.ref.val_prop.z_tuple.1 = z1
+  // -- val.ref
+  // CHECK: [[READ:%.*]] = begin_access [read] [unknown] [[VAL]]
+  // CHECK: [[VAL_REF_ADDR:%[0-9]+]] = struct_element_addr [[READ]] : $*Val, #Val.ref
+  // CHECK: [[VAL_REF:%[0-9]+]] = load [copy] [[VAL_REF_ADDR]]
+  // -- getters and setters
+  // -- val.ref.val_prop
+  // CHECK: [[STORAGE:%.*]] = alloc_stack $Builtin.UnsafeValueBuffer
+  // CHECK: [[VAL_REF_VAL_PROP_TEMP:%.*]] = alloc_stack $Val
+  // CHECK: [[VAL_REF_BORROWED:%.*]] = begin_borrow [[VAL_REF]]
+  // CHECK: [[T0:%.*]] = address_to_pointer [[VAL_REF_VAL_PROP_TEMP]] : $*Val to $Builtin.RawPointer
+  // CHECK: [[MAT_VAL_PROP_METHOD:%[0-9]+]] = class_method {{.*}} : $Ref, #Ref.val_prop!materializeForSet.1 : (Ref) -> (Builtin.RawPointer, inout Builtin.UnsafeValueBuffer) -> (Builtin.RawPointer, Builtin.RawPointer?)
+  // CHECK: [[MAT_RESULT:%[0-9]+]] = apply [[MAT_VAL_PROP_METHOD]]([[T0]], [[STORAGE]], [[VAL_REF_BORROWED]])
+  // CHECK: [[T0:%.*]] = tuple_extract [[MAT_RESULT]] : $(Builtin.RawPointer, Optional<Builtin.RawPointer>), 0
+  // CHECK: [[OPT_CALLBACK:%.*]] = tuple_extract [[MAT_RESULT]] : $(Builtin.RawPointer, Optional<Builtin.RawPointer>), 1  
+  // CHECK: [[T1:%[0-9]+]] = pointer_to_address [[T0]] : $Builtin.RawPointer to [strict] $*Val
+  // CHECK: [[VAL_REF_VAL_PROP_MAT:%.*]] = mark_dependence [[T1]] : $*Val on [[VAL_REF]]
+  // CHECK: end_borrow [[VAL_REF_BORROWED]] from [[VAL_REF]]
+  // -- val.ref.val_prop.z_tuple
+  // CHECK: [[V_R_VP_Z_TUPLE_MAT:%[0-9]+]] = alloc_stack $(Int, Int)
+  // CHECK: [[LD:%[0-9]+]] = load_borrow [[VAL_REF_VAL_PROP_MAT]]
+  // CHECK: [[A0:%.*]] = tuple_element_addr [[V_R_VP_Z_TUPLE_MAT]] : {{.*}}, 0
+  // CHECK: [[A1:%.*]] = tuple_element_addr [[V_R_VP_Z_TUPLE_MAT]] : {{.*}}, 1
+  // CHECK: [[GET_Z_TUPLE_METHOD:%[0-9]+]] = function_ref @$S10properties3ValV7z_tupleSi_Sitvg
+  // CHECK: [[V_R_VP_Z_TUPLE:%[0-9]+]] = apply [[GET_Z_TUPLE_METHOD]]([[LD]])
+  // CHECK: [[T0:%.*]] = tuple_extract [[V_R_VP_Z_TUPLE]] : {{.*}}, 0
+  // CHECK: [[T1:%.*]] = tuple_extract [[V_R_VP_Z_TUPLE]] : {{.*}}, 1
+  // CHECK: store [[T0]] to [trivial] [[A0]]
+  // CHECK: store [[T1]] to [trivial] [[A1]]
+  // CHECK: end_borrow [[LD]] from [[VAL_REF_VAL_PROP_MAT]]
+  // -- write to val.ref.val_prop.z_tuple.1
+  // CHECK: [[V_R_VP_Z_TUPLE_1:%[0-9]+]] = tuple_element_addr [[V_R_VP_Z_TUPLE_MAT]] : {{.*}}, 1
+  // CHECK: assign [[Z1]] to [[V_R_VP_Z_TUPLE_1]]
+  // -- writeback to val.ref.val_prop.z_tuple
+  // CHECK: [[WB_V_R_VP_Z_TUPLE:%[0-9]+]] = load [trivial] [[V_R_VP_Z_TUPLE_MAT]]
+  // CHECK: [[SET_Z_TUPLE_METHOD:%[0-9]+]] = function_ref @$S10properties3ValV7z_tupleSi_Sitvs
+  // CHECK: apply [[SET_Z_TUPLE_METHOD]]({{%[0-9]+, %[0-9]+}}, [[VAL_REF_VAL_PROP_MAT]])
+  // -- writeback to val.ref.val_prop
+  // CHECK: switch_enum [[OPT_CALLBACK]] : $Optional<Builtin.RawPointer>, case #Optional.some!enumelt.1: [[WRITEBACK:bb[0-9]+]], case #Optional.none!enumelt: [[CONT:bb[0-9]+]]
+  // CHECK: [[WRITEBACK]]([[CALLBACK_ADDR:%.*]] : $Builtin.RawPointer):
+  // CHECK: [[CALLBACK:%.*]] = pointer_to_thin_function [[CALLBACK_ADDR]] : $Builtin.RawPointer to $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout Ref, @thick Ref.Type) -> ()
+  // CHECK: [[REF_MAT:%.*]] = alloc_stack $Ref
+  // CHECK: store [[VAL_REF]] to [init] [[REF_MAT]]
+  // CHECK: [[T0:%.*]] = metatype $@thick Ref.Type
+  // CHECK: [[T1:%.*]] = address_to_pointer [[VAL_REF_VAL_PROP_MAT]]
+  // CHECK: apply [[CALLBACK]]([[T1]], [[STORAGE]], [[REF_MAT]], [[T0]])
+  // CHECK: br [[CONT]]
+  // CHECK: [[CONT]]:
+  // -- cleanup
+  // CHECK: dealloc_stack [[V_R_VP_Z_TUPLE_MAT]]
+  // CHECK: dealloc_stack [[VAL_REF_VAL_PROP_TEMP]]
+  // -- don't need to write back to val.ref because it's a ref type
+}
+
+func reftype_rvalue() -> Ref {}
+
+// CHECK-LABEL: sil hidden @$S10properties18reftype_rvalue_set{{[_0-9a-zA-Z]*}}F
+func reftype_rvalue_set(_ value: Val) {
+  reftype_rvalue().val_prop = value
+}
+
+// CHECK-LABEL: sil hidden @$S10properties27tuple_in_logical_struct_set{{[_0-9a-zA-Z]*}}F
+func tuple_in_logical_struct_set(_ value: inout Val, z1: Int) {
+  // CHECK: bb0([[VAL:%[0-9]+]] : $*Val, [[Z1:%[0-9]+]] : $Int):
+  value.z_tuple.1 = z1
+  // CHECK: [[WRITE:%.*]] = begin_access [modify] [unknown] [[VAL]]
+  // CHECK: [[Z_TUPLE_MATERIALIZED:%[0-9]+]] = alloc_stack $(Int, Int)
+  // CHECK: [[VAL1:%[0-9]+]] = load_borrow [[WRITE]]
+  // CHECK: [[A0:%.*]] = tuple_element_addr [[Z_TUPLE_MATERIALIZED]] : {{.*}}, 0
+  // CHECK: [[A1:%.*]] = tuple_element_addr [[Z_TUPLE_MATERIALIZED]] : {{.*}}, 1
+  // CHECK: [[Z_GET_METHOD:%[0-9]+]] = function_ref @$S10properties3ValV7z_tupleSi_Sitvg
+  // CHECK: [[Z_TUPLE:%[0-9]+]] = apply [[Z_GET_METHOD]]([[VAL1]])
+  // CHECK: [[T0:%.*]] = tuple_extract [[Z_TUPLE]] : {{.*}}, 0
+  // CHECK: [[T1:%.*]] = tuple_extract [[Z_TUPLE]] : {{.*}}, 1
+  // CHECK: store [[T0]] to [trivial] [[A0]]
+  // CHECK: store [[T1]] to [trivial] [[A1]]
+  // CHECK: end_borrow [[VAL1]] from [[WRITE]]
+  // CHECK: [[Z_TUPLE_1:%[0-9]+]] = tuple_element_addr [[Z_TUPLE_MATERIALIZED]] : {{.*}}, 1
+  // CHECK: assign [[Z1]] to [[Z_TUPLE_1]]
+  // CHECK: [[Z_TUPLE_MODIFIED:%[0-9]+]] = load [trivial] [[Z_TUPLE_MATERIALIZED]]
+  // CHECK: [[Z_SET_METHOD:%[0-9]+]] = function_ref @$S10properties3ValV7z_tupleSi_Sitvs
+  // CHECK: apply [[Z_SET_METHOD]]({{%[0-9]+, %[0-9]+}}, [[WRITE]])
+  // CHECK: dealloc_stack [[Z_TUPLE_MATERIALIZED]]
+  // CHECK: return
+}
+
+var global_prop : Int {
+  // CHECK-LABEL: sil hidden @$S10properties11global_prop{{[_0-9a-zA-Z]*}}vg
+  get {
+    return zero
+  }
+  // CHECK-LABEL: sil hidden @$S10properties11global_prop{{[_0-9a-zA-Z]*}}vs
+  set {
+    use(newValue)
+  }
+}
+
+// CHECK-LABEL: sil hidden @$S10properties18logical_global_get{{[_0-9a-zA-Z]*}}F
+func logical_global_get() -> Int {
+  return global_prop
+  // CHECK: [[GET:%[0-9]+]] = function_ref @$S10properties11global_prop{{[_0-9a-zA-Z]*}}vg
+  // CHECK: [[VALUE:%[0-9]+]] = apply [[GET]]()
+  // CHECK: return [[VALUE]]
+}
+
+// CHECK-LABEL: sil hidden @$S10properties18logical_global_set{{[_0-9a-zA-Z]*}}F
+func logical_global_set(_ x: Int) {
+  global_prop = x
+  // CHECK: [[SET:%[0-9]+]] = function_ref @$S10properties11global_prop{{[_0-9a-zA-Z]*}}vs
+  // CHECK: apply [[SET]](%0)
+}
+
+// CHECK-LABEL: sil hidden @$S10properties17logical_local_get{{[_0-9a-zA-Z]*}}F
+func logical_local_get(_ x: Int) -> Int {
+  var prop : Int {
+    get {
+      return x
+    }
+  }
+  // CHECK: [[GET_REF:%[0-9]+]] = function_ref [[PROP_GET_CLOSURE:@\$S10properties17logical_local_getyS2iF4propL_Sivg]]
+  // CHECK: apply [[GET_REF]](%0)
+  return prop
+}
+// CHECK-: sil private [[PROP_GET_CLOSURE]]
+// CHECK: bb0(%{{[0-9]+}} : $Int):
+
+func logical_generic_local_get<T>(_ x: Int, _: T) {
+  var prop1: Int {
+    get {
+      return x
+    }
+  }
+
+  _ = prop1
+
+  var prop2: Int {
+    get {
+      _ = T.self
+      return x
+    }
+  }
+
+  _ = prop2
+}
+
+// CHECK-LABEL: sil hidden @$S10properties26logical_local_captured_get{{[_0-9a-zA-Z]*}}F
+func logical_local_captured_get(_ x: Int) -> Int {
+  var prop : Int {
+    get {
+      return x
+    }
+  }
+  func get_prop() -> Int {
+    return prop
+  }
+
+  return get_prop()
+  // CHECK: [[FUNC_REF:%[0-9]+]] = function_ref @$S10properties26logical_local_captured_getyS2iF0E5_propL_SiyF
+  // CHECK: apply [[FUNC_REF]](%0)
+}
+// CHECK: sil private @$S10properties26logical_local_captured_get{{.*}}vg
+// CHECK: bb0(%{{[0-9]+}} : $Int):
+
+func inout_arg(_ x: inout Int) {}
+
+// CHECK-LABEL: sil hidden @$S10properties14physical_inout{{[_0-9a-zA-Z]*}}F
+func physical_inout(_ x: Int) {
+  var x = x
+  // CHECK: [[XADDR:%[0-9]+]] = alloc_box ${ var Int }
+  // CHECK: [[PB:%.*]] = project_box [[XADDR]]
+  inout_arg(&x)
+  // CHECK: [[WRITE:%.*]] = begin_access [modify] [unknown] [[PB]]
+  // CHECK: [[INOUT_ARG:%[0-9]+]] = function_ref @$S10properties9inout_arg{{[_0-9a-zA-Z]*}}F
+  // CHECK: apply [[INOUT_ARG]]([[WRITE]])
+}
+
+
+/* TODO check writeback to more complex logical prop, check that writeback
+ * reuses temporaries */
+
+// CHECK-LABEL: sil hidden @$S10properties17val_subscript_get{{[_0-9a-zA-Z]*}}F : $@convention(thin) (@guaranteed Val, Int) -> Float
+// CHECK: bb0([[VVAL:%[0-9]+]] : $Val, [[I:%[0-9]+]] : $Int):
+func val_subscript_get(_ v: Val, i: Int) -> Float {
+  return v[i]
+  // CHECK: [[SUBSCRIPT_GET_METHOD:%[0-9]+]] = function_ref @$S10properties3ValV{{[_0-9a-zA-Z]*}}ig
+  // CHECK: [[RET:%[0-9]+]] = apply [[SUBSCRIPT_GET_METHOD]]([[I]], [[VVAL]]) : $@convention(method) (Int, @guaranteed Val)
+  // CHECK: return [[RET]]
+}
+
+// CHECK-LABEL: sil hidden @$S10properties17val_subscript_set{{[_0-9a-zA-Z]*}}F
+// CHECK: bb0(%0 : $Val, [[I:%[0-9]+]] : $Int, [[X:%[0-9]+]] : $Float):
+func val_subscript_set(_ v: Val, i: Int, x: Float) {
+  var v = v
+  v[i] = x
+  // CHECK: [[VADDR:%[0-9]+]] = alloc_box ${ var Val }
+  // CHECK: [[PB:%.*]] = project_box [[VADDR]]
+  // CHECK: [[WRITE:%.*]] = begin_access [modify] [unknown] [[PB]]
+  // CHECK: [[SUBSCRIPT_SET_METHOD:%[0-9]+]] = function_ref @$S10properties3ValV{{[_0-9a-zA-Z]*}}is
+  // CHECK: apply [[SUBSCRIPT_SET_METHOD]]([[X]], [[I]], [[WRITE]])
+}
+
+struct Generic<T> {
+  var mono_phys:Int
+  var mono_log: Int { get {} set {} }
+  var typevar_member:T
+
+  subscript(x: Int) -> Float { get {} set {} }
+
+  subscript(x: T) -> T { get {} set {} }
+
+  // CHECK-LABEL: sil hidden @$S10properties7GenericV19copy_typevar_member{{[_0-9a-zA-Z]*}}F
+  mutating
+  func copy_typevar_member(_ x: Generic<T>) {
+    typevar_member = x.typevar_member
+  }
+}
+
+// CHECK-LABEL: sil hidden @$S10properties21generic_mono_phys_get{{[_0-9a-zA-Z]*}}F
+func generic_mono_phys_get<T>(_ g: Generic<T>) -> Int {
+  return g.mono_phys
+  // CHECK: struct_element_addr %{{.*}}, #Generic.mono_phys
+}
+
+// CHECK-LABEL: sil hidden @$S10properties20generic_mono_log_get{{[_0-9a-zA-Z]*}}F
+func generic_mono_log_get<T>(_ g: Generic<T>) -> Int {
+  return g.mono_log
+  // CHECK: [[GENERIC_GET_METHOD:%[0-9]+]] = function_ref @$S10properties7GenericV8mono_log{{[_0-9a-zA-Z]*}}vg
+  // CHECK: apply [[GENERIC_GET_METHOD]]<
+}
+
+// CHECK-LABEL: sil hidden @$S10properties20generic_mono_log_set{{[_0-9a-zA-Z]*}}F
+func generic_mono_log_set<T>(_ g: Generic<T>, x: Int) {
+  var g = g
+  g.mono_log = x
+  // CHECK: [[GENERIC_SET_METHOD:%[0-9]+]] = function_ref @$S10properties7GenericV8mono_log{{[_0-9a-zA-Z]*}}vs
+  // CHECK: apply [[GENERIC_SET_METHOD]]<
+}
+
+// CHECK-LABEL: sil hidden @$S10properties26generic_mono_subscript_get{{[_0-9a-zA-Z]*}}F
+func generic_mono_subscript_get<T>(_ g: Generic<T>, i: Int) -> Float {
+  return g[i]
+  // CHECK: [[GENERIC_GET_METHOD:%[0-9]+]] = function_ref @$S10properties7GenericV{{[_0-9a-zA-Z]*}}ig
+  // CHECK: apply [[GENERIC_GET_METHOD]]<
+}
+
+// CHECK-LABEL: sil hidden @{{.*}}generic_mono_subscript_set
+func generic_mono_subscript_set<T>(_ g: inout Generic<T>, i: Int, x: Float) {
+  g[i] = x
+  // CHECK: [[GENERIC_SET_METHOD:%[0-9]+]] = function_ref @$S10properties7GenericV{{[_0-9a-zA-Z]*}}is
+  // CHECK: apply [[GENERIC_SET_METHOD]]<
+}
+
+// CHECK-LABEL: sil hidden @{{.*}}bound_generic_mono_phys_get
+func bound_generic_mono_phys_get(_ g: inout Generic<UnicodeScalar>, x: Int) -> Int {
+  return g.mono_phys
+  // CHECK: struct_element_addr %{{.*}}, #Generic.mono_phys
+}
+
+// CHECK-LABEL: sil hidden @$S10properties26bound_generic_mono_log_get{{[_0-9a-zA-Z]*}}F
+func bound_generic_mono_log_get(_ g: Generic<UnicodeScalar>, x: Int) -> Int {
+  return g.mono_log
+// CHECK: [[GENERIC_GET_METHOD:%[0-9]+]] = function_ref @$S10properties7GenericV8mono_log{{[_0-9a-zA-Z]*}}vg
+  // CHECK: apply [[GENERIC_GET_METHOD]]<
+}
+
+// CHECK-LABEL: sil hidden @$S10properties22generic_subscript_type{{[_0-9a-zA-Z]*}}F
+func generic_subscript_type<T>(_ g: Generic<T>, i: T, x: T) -> T {
+  var g = g
+  g[i] = x
+  return g[i]
+}
+
+/*TODO: archetype and existential properties and subscripts */
+
+struct StaticProperty {
+  static var foo: Int {
+    get {
+      return zero
+    }
+    set {}
+  }
+}
+
+// CHECK-LABEL: sil hidden @$S10properties10static_get{{[_0-9a-zA-Z]*}}F
+// CHECK:   function_ref @$S10properties14StaticPropertyV3foo{{[_0-9a-zA-Z]*}}vgZ : $@convention(method) (@thin StaticProperty.Type) -> Int
+func static_get() -> Int {
+  return StaticProperty.foo
+}
+
+// CHECK-LABEL: sil hidden @$S10properties10static_set{{[_0-9a-zA-Z]*}}F
+// CHECK:   function_ref @$S10properties14StaticPropertyV3foo{{[_0-9a-zA-Z]*}}vsZ : $@convention(method) (Int, @thin StaticProperty.Type) -> ()
+func static_set(_ x: Int) {
+  StaticProperty.foo = x
+}
+
+func takeInt(_ a : Int) {}
+
+protocol ForceAccessors {
+  var a: Int { get set }
+}
+
+struct DidSetWillSetTests: ForceAccessors {
+  var a: Int {
+    willSet(newA) {
+      // CHECK-LABEL: // {{.*}}.DidSetWillSetTests.a.willset
+      // CHECK-NEXT: sil hidden @$S10properties010DidSetWillC5TestsV1a{{[_0-9a-zA-Z]*}}vw
+      // CHECK: bb0(%0 : $Int, %1 : $*DidSetWillSetTests):
+      // CHECK-NEXT: debug_value %0
+      // CHECK-NEXT: debug_value_addr %1 : $*DidSetWillSetTests
+
+      takeInt(a)
+
+      // CHECK: [[READ:%.*]] = begin_access [read] [unknown] %1
+      // CHECK-NEXT: [[FIELDPTR:%.*]] = struct_element_addr [[READ]] : $*DidSetWillSetTests, #DidSetWillSetTests.a
+      // CHECK-NEXT: [[A:%.*]] = load [trivial] [[FIELDPTR]] : $*Int
+      // CHECK-NEXT: end_access [[READ]]
+      // CHECK: [[TAKEINTFN:%.*]] = function_ref @$S10properties7takeInt{{[_0-9a-zA-Z]*}}F
+      // CHECK-NEXT: apply [[TAKEINTFN]]([[A]]) : $@convention(thin) (Int) -> ()
+
+      takeInt(newA)
+
+      // CHECK-NEXT: // function_ref properties.takeInt(Swift.Int) -> ()
+      // CHECK-NEXT: [[TAKEINTFN:%.*]] = function_ref @$S10properties7takeInt{{[_0-9a-zA-Z]*}}F
+      // CHECK-NEXT: apply [[TAKEINTFN]](%0) : $@convention(thin) (Int) -> ()
+    }
+
+    didSet {
+      // CHECK-LABEL: // {{.*}}.DidSetWillSetTests.a.didset
+      // CHECK-NEXT: sil hidden @$S10properties010DidSetWillC5TestsV1a{{[_0-9a-zA-Z]*}}vW
+      // CHECK: bb0(%0 : $Int, %1 : $*DidSetWillSetTests):
+      // CHECK-NEXT: debug
+      // CHECK-NEXT: debug_value_addr %1 : $*DidSetWillSetTests
+
+      takeInt(a)
+
+      // CHECK: [[READ:%.*]] = begin_access [read] [unknown] %1
+      // CHECK-NEXT: [[AADDR:%.*]] = struct_element_addr [[READ]] : $*DidSetWillSetTests, #DidSetWillSetTests.a
+      // CHECK-NEXT: [[A:%.*]] = load [trivial] [[AADDR]] : $*Int
+      // CHECK-NEXT: end_access [[READ]]
+      // CHECK-NEXT: // function_ref properties.takeInt(Swift.Int) -> ()
+      // CHECK-NEXT: [[TAKEINTFN:%.*]] = function_ref @$S10properties7takeInt{{[_0-9a-zA-Z]*}}F
+      // CHECK-NEXT: apply [[TAKEINTFN]]([[A]]) : $@convention(thin) (Int) -> ()
+
+      a = zero  // reassign, but don't infinite loop.
+
+      // CHECK-NEXT: // function_ref properties.zero.unsafeMutableAddressor : Swift.Int
+      // CHECK-NEXT: [[ZEROFN:%.*]] = function_ref @$S10properties4zero{{[_0-9a-zA-Z]*}}vau
+      // CHECK-NEXT: [[ZERORAW:%.*]] = apply [[ZEROFN]]() : $@convention(thin) () -> Builtin.RawPointer
+      // CHECK-NEXT: [[ZEROADDR:%.*]] = pointer_to_address [[ZERORAW]] : $Builtin.RawPointer to [strict] $*Int
+      // CHECK-NEXT: [[READ:%.*]] = begin_access [read] [dynamic] [[ZEROADDR]] : $*Int
+      // CHECK-NEXT: [[ZERO:%.*]] = load [trivial] [[READ]]
+      // CHECK-NEXT: end_access [[READ]] : $*Int
+      // CHECK-NEXT: [[WRITE:%.*]] = begin_access [modify] [unknown] %1
+      // CHECK-NEXT: [[AADDR:%.*]] = struct_element_addr [[WRITE]] : $*DidSetWillSetTests, #DidSetWillSetTests.a
+      // CHECK-NEXT: assign [[ZERO]] to [[AADDR]]
+    }
+  }
+
+  init(x : Int) {
+    // Accesses to didset/willset variables are direct in init methods and dtors.
+    a = x
+    a = x
+  }
+
+  // These are the synthesized getter and setter for the willset/didset variable.
+
+  // CHECK-LABEL: // {{.*}}.DidSetWillSetTests.a.getter
+  // CHECK-NEXT: sil hidden [transparent] @$S10properties010DidSetWillC5TestsV1aSivg
+  // CHECK: bb0(%0 : $DidSetWillSetTests):
+  // CHECK-NEXT:   debug_value %0
+  // CHECK-NEXT:   %2 = struct_extract %0 : $DidSetWillSetTests, #DidSetWillSetTests.a
+  // CHECK-NEXT:   return %2 : $Int{{.*}}                      // id: %3
+
+  // CHECK-LABEL: // {{.*}}.DidSetWillSetTests.a.setter
+  // CHECK-NEXT: sil hidden @$S10properties010DidSetWillC5TestsV1aSivs
+  // CHECK: bb0(%0 : $Int, %1 : $*DidSetWillSetTests):
+  // CHECK-NEXT: debug_value %0
+  // CHECK-NEXT: debug_value_addr %1
+
+  // CHECK-NEXT: [[READ:%.*]] = begin_access [read] [unknown] %1
+  // CHECK-NEXT: [[AADDR:%.*]] = struct_element_addr [[READ]] : $*DidSetWillSetTests, #DidSetWillSetTests.a
+  // CHECK-NEXT: [[OLDVAL:%.*]] = load [trivial] [[AADDR]] : $*Int
+  // CHECK-NEXT: end_access [[READ]]
+  // CHECK-NEXT: debug_value [[OLDVAL]] : $Int, let, name "tmp"
+
+  // CHECK: [[WRITE:%.*]] = begin_access [modify] [unknown] %1
+  // CHECK-NEXT: // function_ref {{.*}}.DidSetWillSetTests.a.willset : Swift.Int
+  // CHECK-NEXT: [[WILLSETFN:%.*]] = function_ref @$S10properties010DidSetWillC5TestsV1a{{[_0-9a-zA-Z]*}}vw
+  // CHECK-NEXT:  apply [[WILLSETFN]](%0, [[WRITE]]) : $@convention(method) (Int, @inout DidSetWillSetTests) -> ()
+  // CHECK-NEXT: end_access [[WRITE]]
+  // CHECK-NEXT: [[WRITE:%.*]] = begin_access [modify] [unknown] %1
+  // CHECK-NEXT: [[AADDR:%.*]] = struct_element_addr [[WRITE]] : $*DidSetWillSetTests, #DidSetWillSetTests.a
+  // CHECK-NEXT: assign %0 to [[AADDR]] : $*Int
+  // CHECK-NEXT: end_access [[WRITE]]
+  // CHECK-NEXT: [[WRITE:%.*]] = begin_access [modify] [unknown] %1
+  // CHECK-NEXT: // function_ref {{.*}}.DidSetWillSetTests.a.didset : Swift.Int
+  // CHECK-NEXT: [[DIDSETFN:%.*]] = function_ref @$S10properties010DidSetWillC5TestsV1a{{[_0-9a-zA-Z]*}}vW : $@convention(method) (Int, @inout DidSetWillSetTests) -> ()
+  // CHECK-NEXT: apply [[DIDSETFN]]([[OLDVAL]], [[WRITE]]) : $@convention(method) (Int, @inout DidSetWillSetTests) -> ()
+
+  // CHECK-LABEL: sil hidden @$S10properties010DidSetWillC5TestsV{{[_0-9a-zA-Z]*}}fC
+  // CHECK: bb0(%0 : $Int, %1 : $@thin DidSetWillSetTests.Type):
+  // CHECK:        [[SELF:%.*]] = mark_uninitialized [rootself]
+  // CHECK:        [[PB_SELF:%.*]] = project_box [[SELF]]
+  // CHECK:        [[WRITE:%.*]] = begin_access [modify] [unknown] [[PB_SELF]]
+  // CHECK:        [[P1:%.*]] = struct_element_addr [[WRITE]] : $*DidSetWillSetTests, #DidSetWillSetTests.a
+  // CHECK-NEXT:   assign %0 to [[P1]]
+  // CHECK:        [[WRITE:%.*]] = begin_access [modify] [unknown] [[PB_SELF]]
+  // CHECK:        [[P2:%.*]] = struct_element_addr [[WRITE]] : $*DidSetWillSetTests, #DidSetWillSetTests.a
+  // CHECK-NEXT:   assign %0 to [[P2]]
+}
+
+
+// Test global observing properties.
+
+var global_observing_property : Int = zero {
+  didSet {
+    takeInt(global_observing_property)
+  }
+}
+
+func force_global_observing_property_setter() {
+  let x = global_observing_property
+  global_observing_property = x
+}
+
+// The property is initialized with "zero".
+// CHECK-LABEL: sil private @globalinit_{{.*}}_func1 : $@convention(c) () -> () {
+// CHECK: bb0:
+// CHECK-NEXT: alloc_global @$S10properties25global_observing_propertySiv
+// CHECK-NEXT: %1 = global_addr @$S10properties25global_observing_propertySivp : $*Int
+// CHECK: properties.zero.unsafeMutableAddressor
+// CHECK: return
+
+// The didSet implementation needs to call takeInt.
+
+// CHECK-LABEL: sil hidden @$S10properties25global_observing_property{{[_0-9a-zA-Z]*}}vW
+// CHECK: function_ref properties.takeInt
+// CHECK-NEXT: function_ref @$S10properties7takeInt{{[_0-9a-zA-Z]*}}F
+
+// The setter needs to call didSet implementation.
+
+// CHECK-LABEL: sil hidden @$S10properties25global_observing_property{{[_0-9a-zA-Z]*}}vs
+// CHECK: function_ref properties.global_observing_property.unsafeMutableAddressor
+// CHECK-NEXT:  function_ref @$S10properties25global_observing_property{{[_0-9a-zA-Z]*}}vau
+// CHECK: function_ref properties.global_observing_property.didset
+// CHECK-NEXT: function_ref @$S10properties25global_observing_property{{[_0-9a-zA-Z]*}}vW
+
+
+// Test local observing properties.
+
+func local_observing_property(_ arg: Int) {
+  var localproperty: Int = arg {
+    didSet {
+      takeInt(localproperty)
+    }
+  }
+  
+  takeInt(localproperty)
+  localproperty = arg
+}
+
+// This is the local_observing_property function itself.  First alloc and 
+// initialize the property to the argument value.
+
+// CHECK-LABEL: sil hidden @{{.*}}local_observing_property
+// CHECK: bb0([[ARG:%[0-9]+]] : $Int)
+// CHECK: [[BOX:%[0-9]+]] = alloc_box ${ var Int }
+// CHECK: [[PB:%.*]] = project_box [[BOX]]
+// CHECK: store [[ARG]] to [trivial] [[PB]]
+
+func local_generic_observing_property<T>(_ arg: Int, _: T) {
+  var localproperty1: Int = arg {
+    didSet {
+      takeInt(localproperty1)
+    }
+  }
+  
+  takeInt(localproperty1)
+  localproperty1 = arg
+
+  var localproperty2: Int = arg {
+    didSet {
+      _ = T.self
+      takeInt(localproperty2)
+    }
+  }
+  
+  takeInt(localproperty2)
+  localproperty2 = arg
+}
+
+
+// <rdar://problem/16006333> observing properties don't work in @objc classes
+@objc
+class ObservingPropertyInObjCClass {
+  var bounds: Int {
+    willSet {}
+    didSet {}
+  }
+
+  init(b: Int) { bounds = b }
+}
+
+
+
+// Superclass init methods should not get direct access to be class properties.
+// rdar://16151899
+
+class rdar16151899Base {
+  var x: Int = zero {
+  willSet {
+    use(x)
+  }
+  }
+}
+
+class rdar16151899Derived : rdar16151899Base {
+    // CHECK-LABEL: sil hidden @$S10properties19rdar16151899DerivedC{{[_0-9a-zA-Z]*}}fc
+    override init() {
+        super.init()
+        // CHECK: upcast {{.*}} : $rdar16151899Derived to $rdar16151899Base
+        // CHECK: function_ref @$S10properties16rdar16151899BaseCACycfc : $@convention(method) (@owned rdar16151899Base) -> @owned rdar16151899Base
+
+        // This should not be a direct access, it should call the setter in the
+        // base.
+        x = zero
+        
+        // CHECK:  [[BASEPTR:%[0-9]+]] = upcast {{.*}} : $rdar16151899Derived to $rdar16151899Base
+        // CHECK: load{{.*}}Int
+        // CHECK-NEXT: end_access {{.*}} : $*Int
+        // CHECK-NEXT: [[SETTER:%[0-9]+]] = class_method {{.*}} : $rdar16151899Base, #rdar16151899Base.x!setter.1 : (rdar16151899Base)
+        // CHECK-NEXT: apply [[SETTER]]({{.*}}, [[BASEPTR]]) 
+    }
+}
+
+
+func propertyWithDidSetTakingOldValue() {
+  var p : Int = zero {
+    didSet(oldValue) {
+      // access to oldValue
+      use(oldValue)
+      // and newValue.
+      use(p)
+    }
+  }
+
+  p = zero
+}
+
+// CHECK: // setter of p #1 : Swift.Int in properties.propertyWithDidSetTakingOldValue()
+// CHECK-NEXT: sil {{.*}} @$S10properties32propertyWithDidSetTakingOldValueyyF1pL_Sivs
+// CHECK: bb0([[ARG1:%.*]] : $Int, [[ARG2:%.*]] : ${ var Int }):
+// CHECK-NEXT:  debug_value [[ARG1]] : $Int, let, name "newValue", argno 1
+// CHECK-NEXT:  [[ARG2_PB:%.*]] = project_box [[ARG2]]
+// CHECK-NEXT:  debug_value_addr [[ARG2_PB]] : $*Int, var, name "p", argno 2
+// CHECK-NEXT:  [[READ:%.*]] = begin_access [read] [unknown] [[ARG2_PB]]
+// CHECK-NEXT:  [[ARG2_PB_VAL:%.*]] = load [trivial] [[READ]] : $*Int
+// CHECK-NEXT:  end_access [[READ]]
+// CHECK-NEXT:  debug_value [[ARG2_PB_VAL]] : $Int
+// CHECK-NEXT:  [[WRITE:%.*]] = begin_access [modify] [unknown] [[ARG2_PB]]
+// CHECK-NEXT:  assign [[ARG1]] to [[WRITE]] : $*Int
+// CHECK-NEXT:  end_access [[WRITE]]
+// SEMANTIC ARC TODO: Another case where we need to put the mark_function_escape on a new projection after a copy.
+// CHECK-NEXT:  mark_function_escape [[ARG2_PB]]
+// CHECK-NEXT:  // function_ref
+// CHECK-NEXT:  [[FUNC:%.*]] = function_ref @$S10properties32propertyWithDidSetTakingOldValueyyF1pL_SivW : $@convention(thin) (Int, @guaranteed { var Int }) -> ()
+// CHECK-NEXT:  %{{.*}} = apply [[FUNC]]([[ARG2_PB_VAL]], [[ARG2]]) : $@convention(thin) (Int, @guaranteed { var Int }) -> ()
+// CHECK-NEXT:  %{{.*}} = tuple ()
+// CHECK-NEXT:  return %{{.*}} : $()
+// CHECK-NEXT:} // end sil function '$S10properties32propertyWithDidSetTakingOldValue{{[_0-9a-zA-Z]*}}'
+
+
+class BaseProperty {
+  var x : Int { get {} set {} }
+}
+
+class DerivedProperty : BaseProperty {
+  override var x : Int { get {} set {} }
+
+  func super_property_reference() -> Int {
+    return super.x
+  }
+}
+
+// rdar://16381392 - Super property references in non-objc classes should be direct.
+
+// CHECK-LABEL: sil hidden @$S10properties15DerivedPropertyC24super_property_referenceSiyF : $@convention(method) (@guaranteed DerivedProperty) -> Int {
+// CHECK: bb0([[SELF:%.*]] : $DerivedProperty):
+// CHECK:   [[SELF_COPY:%[0-9]+]] = copy_value [[SELF]]
+// CHECK:   [[BASEPTR:%[0-9]+]] = upcast [[SELF_COPY]] : $DerivedProperty to $BaseProperty
+// CHECK:   [[FN:%[0-9]+]] = function_ref @$S10properties12BasePropertyC1xSivg : $@convention(method) (@guaranteed BaseProperty) -> Int 
+// CHECK:   [[RESULT:%.*]] = apply [[FN]]([[BASEPTR]]) : $@convention(method) (@guaranteed BaseProperty) -> Int
+// CHECK:   destroy_value [[BASEPTR]]
+// CHECK:   return [[RESULT]] : $Int
+// CHECK: } // end sil function '$S10properties15DerivedPropertyC24super_property_referenceSiyF'
+
+
+// <rdar://problem/16411449> ownership qualifiers don't work with non-mutating struct property
+struct ReferenceStorageTypeRValues {
+  unowned var p1 : Ref
+
+  func testRValueUnowned() -> Ref {
+    return p1
+  }
+// CHECK: sil hidden @{{.*}}testRValueUnowned{{.*}} : $@convention(method) (@guaranteed ReferenceStorageTypeRValues) -> @owned Ref {
+// CHECK: bb0([[ARG:%.*]] : $ReferenceStorageTypeRValues):
+// CHECK-NEXT:   debug_value [[ARG]] : $ReferenceStorageTypeRValues
+// CHECK-NEXT:   [[UNOWNED_ARG_FIELD:%.*]] = struct_extract [[ARG]] : $ReferenceStorageTypeRValues, #ReferenceStorageTypeRValues.p1
+// CHECK-NEXT:   [[COPIED_VALUE:%.*]] = copy_unowned_value [[UNOWNED_ARG_FIELD]]
+// CHECK-NEXT:   return [[COPIED_VALUE]] : $Ref
+
+  init() {
+  }
+}
+
+
+// <rdar://problem/16406886> Observing properties don't work with ownership types
+struct ObservingPropertiesWithOwnershipTypes {
+  unowned var alwaysPresent : Ref {
+    didSet {
+    }
+  }
+
+  init(res: Ref) {
+    alwaysPresent = res
+  }
+}
+
+struct ObservingPropertiesWithOwnershipTypesInferred {
+  unowned var alwaysPresent = Ref(i: 0) {
+    didSet {
+    }
+  }
+
+  weak var maybePresent = nil as Ref? {
+    willSet {
+    }
+  }
+}
+
+// <rdar://problem/16554876> property accessor synthesization of weak variables doesn't work
+protocol WeakPropertyProtocol {
+ var maybePresent : Ref? { get set }
+}
+
+struct WeakPropertyStruct : WeakPropertyProtocol {
+ weak var maybePresent : Ref?
+
+  init() {
+    maybePresent = nil
+  }
+}
+
+// <rdar://problem/16629598> direct property accesses to generic struct
+// properties were being mischecked as computed property accesses.
+
+struct SomeGenericStruct<T> {
+  var x: Int
+}
+
+// CHECK-LABEL: sil hidden @$S10properties4getX{{[_0-9a-zA-Z]*}}F
+// CHECK:         struct_extract {{%.*}} : $SomeGenericStruct<T>, #SomeGenericStruct.x
+func getX<T>(_ g: SomeGenericStruct<T>) -> Int {
+  return g.x
+}
+
+
+// <rdar://problem/16189360> [DF] Assert on subscript with variadic parameter
+struct VariadicSubscript {
+  subscript(subs: Int...) -> Int {
+    get {
+      return 42
+    }
+  }
+
+  func test() {
+    var s = VariadicSubscript()
+    var x = s[0, 1, 2]
+  }
+}
+
+
+//<rdar://problem/16620121> Initializing constructor tries to initialize computed property overridden with willSet/didSet
+class ObservedBase {
+     var printInfo: Ref!
+}
+class ObservedDerived : ObservedBase {
+  override init() {}
+  override var printInfo: Ref! {
+    didSet { }
+  }
+}
+
+
+
+/// <rdar://problem/16953517> Class properties should be allowed in protocols, even without stored class properties
+protocol ProtoWithClassProp {
+  static var x: Int { get }
+}
+
+class ClassWithClassProp : ProtoWithClassProp {
+  class var x: Int {
+  return 42
+  }
+}
+
+struct StructWithClassProp : ProtoWithClassProp {
+  static var x: Int {
+  return 19
+  }
+}
+
+
+func getX<T : ProtoWithClassProp>(_ a : T) -> Int {
+  return T.x
+}
+
+func testClassPropertiesInProtocol() -> Int {
+  return getX(ClassWithClassProp())+getX(StructWithClassProp())
+}
+
+class GenericClass<T> {
+  var x: T
+  var y: Int
+  final let z: T
+
+  init() { fatalError("scaffold") }
+}
+
+// CHECK-LABEL: sil hidden @$S10properties12genericPropsyyAA12GenericClassCySSGF : $@convention(thin) (@guaranteed GenericClass<String>) -> () {
+func genericProps(_ x: GenericClass<String>) {
+  // CHECK: bb0([[ARG:%.*]] : $GenericClass<String>):
+  // CHECK:   class_method [[ARG]] : $GenericClass<String>, #GenericClass.x!getter.1
+  // CHECK:   apply {{.*}}<String>({{.*}}, [[ARG]]) : $@convention(method) <τ_0_0> (@guaranteed GenericClass<τ_0_0>) -> @out τ_0_0
+  let _ = x.x
+  // CHECK:   class_method [[ARG]] : $GenericClass<String>, #GenericClass.y!getter.1
+  // CHECK:   apply {{.*}}<String>([[ARG]]) : $@convention(method) <τ_0_0> (@guaranteed GenericClass<τ_0_0>) -> Int
+  let _ = x.y
+  // CHECK:   [[Z:%.*]] = ref_element_addr [[ARG]] : $GenericClass<String>, #GenericClass.z
+  // CHECK:   [[READ:%.*]] = begin_access [read] [dynamic] [[Z]] : $*String
+  // CHECK:   [[LOADED_Z:%.*]] = load [copy] [[READ]] : $*String
+  // CHECK:   destroy_value [[LOADED_Z]]
+  // CHECK-NOT:   destroy_value [[ARG]]
+  let _ = x.z
+}
+
+// CHECK-LABEL: sil hidden @$S10properties28genericPropsInGenericContext{{[_0-9a-zA-Z]*}}F
+func genericPropsInGenericContext<U>(_ x: GenericClass<U>) {
+  // CHECK: bb0([[ARG:%.*]] : $GenericClass<U>):
+  // CHECK:   [[Z:%.*]] = ref_element_addr [[ARG]] : $GenericClass<U>, #GenericClass.z
+  // CHECK:   [[READ:%.*]] = begin_access [read] [dynamic] [[Z]] : $*U
+  // CHECK:   copy_addr [[READ]] {{.*}} : $*U
+  let _ = x.z
+}
+
+
+// <rdar://problem/18275556> 'let' properties in a class should be implicitly final
+class ClassWithLetProperty {
+  let p = 42
+  dynamic let q = 97
+
+  // We shouldn't have any dynamic dispatch within this method, just load p.
+  func ReturnConstant() -> Int { return p }
+// CHECK-LABEL: sil hidden @$S10properties20ClassWithLetPropertyC14ReturnConstant{{[_0-9a-zA-Z]*}}F
+// CHECK:       bb0([[ARG:%.*]] : $ClassWithLetProperty):
+// CHECK-NEXT:    debug_value
+// CHECK-NEXT:    [[PTR:%[0-9]+]] = ref_element_addr [[ARG]] : $ClassWithLetProperty, #ClassWithLetProperty.p
+// CHECK-NEXT:    [[READ:%.*]] = begin_access [read] [dynamic] [[PTR]] : $*Int
+// CHECK-NEXT:    [[VAL:%[0-9]+]] = load [trivial] [[READ]] : $*Int
+// CHECK-NEXT:    end_access [[READ]] : $*Int
+// CHECK-NEXT:   return [[VAL]] : $Int
+
+
+  // This property is marked dynamic, so go through the getter, always.
+  func ReturnDynamicConstant() -> Int { return q }
+// CHECK-LABEL: sil hidden @$S10properties20ClassWithLetPropertyC21ReturnDynamicConstant{{[_0-9a-zA-Z]*}}F
+// CHECK: objc_method %0 : $ClassWithLetProperty, #ClassWithLetProperty.q!getter.1.foreign
+}
+
+
+// <rdar://problem/19254812> DI bug when referencing let member of a class
+class r19254812Base {}
+class r19254812Derived: r19254812Base{
+  let pi = 3.14159265359
+  
+  init(x : ()) {
+    use(pi)
+  }
+  
+// Accessing the "pi" property should not copy_value/release self.
+// CHECK-LABEL: sil hidden @$S10properties16r19254812DerivedC{{[_0-9a-zA-Z]*}}fc
+// CHECK: [[MARKED_SELF_BOX:%.*]] = mark_uninitialized [derivedself]
+// CHECK: [[PB_BOX:%.*]] = project_box [[MARKED_SELF_BOX]]
+
+// Initialization of the pi field: no copy_values/releases.
+// CHECK:  [[SELF:%[0-9]+]] = load_borrow [[PB_BOX]] : $*r19254812Derived
+// CHECK-NEXT:  [[PIPTR:%[0-9]+]] = ref_element_addr [[SELF]] : $r19254812Derived, #r19254812Derived.pi
+// CHECK-NEXT:  [[WRITE:%.*]] = begin_access [modify] [dynamic] [[PIPTR]] : $*Double
+// CHECK-NEXT:  assign {{.*}} to [[WRITE]] : $*Double
+
+// CHECK-NOT: destroy_value
+// CHECK-NOT: copy_value
+
+// Load of the pi field: no copy_values/releases.
+// CHECK:  [[SELF:%[0-9]+]] = load_borrow [[PB_BOX]] : $*r19254812Derived
+// CHECK-NEXT:  [[PIPTR:%[0-9]+]] = ref_element_addr [[SELF]] : $r19254812Derived, #r19254812Derived.pi
+// CHECK-NEXT:  [[READ:%.*]] = begin_access [read] [dynamic] [[PIPTR]] : $*Double
+// CHECK-NEXT:  {{.*}} = load [trivial] [[READ]] : $*Double
+// CHECK-NEXT:  end_access [[READ]] : $*Double
+// CHECK: return
+}
+
+
+class RedundantSelfRetains {
+  final var f : RedundantSelfRetains
+  
+  init() {
+    f = RedundantSelfRetains()
+  }
+  
+  // <rdar://problem/19275047> Extraneous copy_values/releases of self are bad
+  func testMethod1() {
+    f = RedundantSelfRetains()
+  }
+  // CHECK-LABEL: sil hidden @$S10properties20RedundantSelfRetainsC11testMethod1{{[_0-9a-zA-Z]*}}F
+  // CHECK: bb0(%0 : $RedundantSelfRetains):
+
+  // CHECK-NOT: copy_value
+  
+  // CHECK: [[FPTR:%[0-9]+]] = ref_element_addr %0 : $RedundantSelfRetains, #RedundantSelfRetains.f
+  // CHECK-NEXT: [[WRITE:%.*]] = begin_access [modify] [dynamic] [[FPTR]] : $*RedundantSelfRetains
+  // CHECK-NEXT: assign {{.*}} to [[WRITE]] : $*RedundantSelfRetains
+
+  // CHECK: return
+}
+
+class RedundantRetains {
+  final var field = 0
+}
+
+func testRedundantRetains() {
+  let a = RedundantRetains()
+  a.field = 4  // no copy_value/release of a necessary here.
+}
+
+// CHECK-LABEL: sil hidden @$S10properties20testRedundantRetainsyyF : $@convention(thin) () -> () {
+// CHECK: [[A:%[0-9]+]] = apply
+// CHECK-NOT: copy_value
+// CHECK: destroy_value [[A]] : $RedundantRetains
+// CHECK-NOT: copy_value
+// CHECK-NOT: destroy_value
+// CHECK: return
+
+struct AddressOnlyNonmutatingSet<T> {
+  var x: T
+  init(x: T) { self.x = x }
+  var prop: Int {
+    get { return 0 }
+    nonmutating set { }
+  }
+}
+
+func addressOnlyNonmutatingProperty<T>(_ x: AddressOnlyNonmutatingSet<T>)
+-> Int {
+  x.prop = 0
+  return x.prop
+}
+// CHECK-LABEL: sil hidden @$S10properties30addressOnlyNonmutatingProperty{{[_0-9a-zA-Z]*}}F
+// CHECK:         [[SET:%.*]] = function_ref @$S10properties25AddressOnlyNonmutatingSetV4propSivs
+// CHECK:         apply [[SET]]<T>({{%.*}}, [[TMP:%[0-9]*]])
+// CHECK:         destroy_addr [[TMP]]
+// CHECK:         dealloc_stack [[TMP]]
+// CHECK:         [[GET:%.*]] = function_ref @$S10properties25AddressOnlyNonmutatingSetV4propSivg
+// CHECK:         apply [[GET]]<T>([[TMP:%[0-9]*]])
+// CHECK:         destroy_addr [[TMP]]
+// CHECK:         dealloc_stack [[TMP]]
+
+protocol MakeAddressOnly {}
+struct AddressOnlyReadOnlySubscript {
+  var x: MakeAddressOnly?
+
+  subscript(z: Int) -> Int { return z }
+}
+
+// CHECK-LABEL: sil hidden @$S10properties015addressOnlyReadC24SubscriptFromMutableBase
+// CHECK:         [[BASE:%.*]] = alloc_box ${ var AddressOnlyReadOnlySubscript }
+// CHECK:         copy_addr [[BASE:%.*]] to [initialization] [[COPY:%.*]] :
+// CHECK:         [[GETTER:%.*]] = function_ref @$S10properties015AddressOnlyReadC9SubscriptV{{[_0-9a-zA-Z]*}}ig
+// CHECK:         apply [[GETTER]]({{%.*}}, [[COPY]])
+func addressOnlyReadOnlySubscriptFromMutableBase(_ x: Int) {
+  var base = AddressOnlyReadOnlySubscript()
+  _ = base[x]
+}
+
+
+
+/// <rdar://problem/20912019> passing unmaterialized r-value as inout argument
+struct MutatingGetterStruct {
+  var write: Int {
+    mutating get {  }
+  }
+
+  // CHECK-LABEL: sil hidden @$S10properties20MutatingGetterStructV4test
+  // CHECK: [[X:%.*]] = alloc_box ${ var MutatingGetterStruct }, var, name "x"
+  // CHECK-NEXT: [[PB:%.*]] = project_box [[X]]
+  // CHECK: store {{.*}} to [trivial] [[PB]] : $*MutatingGetterStruct
+  // CHECK: [[WRITE:%.*]] = begin_access [modify] [unknown] [[PB]]
+  // CHECK: apply {{%.*}}([[WRITE]]) : $@convention(method) (@inout MutatingGetterStruct) -> Int
+  static func test() {
+    var x = MutatingGetterStruct()
+    _ = x.write
+  }
+}
+
+
+protocol ProtocolWithReadWriteSubscript {
+  subscript(i: Int) -> Int { get set }
+}
+
+struct CrashWithUnnamedSubscript : ProtocolWithReadWriteSubscript {
+  subscript(_: Int) -> Int { get { } set { } }
+}
+
+
+/// <rdar://problem/26408353> crash when overriding internal property with
+/// public property
+
+public class BaseClassWithInternalProperty {
+  var x: () = ()
+}
+
+public class DerivedClassWithPublicProperty : BaseClassWithInternalProperty {
+  public override var x: () {
+    didSet {}
+  }
+}
+
+// CHECK-LABEL: sil hidden [transparent] @$S10properties29BaseClassWithInternalPropertyC1xytvg
+
+// CHECK-LABEL: sil [transparent] [serialized] @$S10properties30DerivedClassWithPublicPropertyC1xytvg
+// CHECK:       bb0([[SELF:%.*]] : $DerivedClassWithPublicProperty):
+// CHECK:         [[SELF_COPY:%.*]] = copy_value [[SELF]] : $DerivedClassWithPublicProperty
+// CHECK-NEXT:    [[SUPER:%.*]] = upcast [[SELF_COPY]] : $DerivedClassWithPublicProperty to $BaseClassWithInternalProperty
+// CHECK-NEXT:    [[BORROWED_SUPER:%.*]] = begin_borrow [[SUPER]]
+// CHECK-NEXT:    [[DOWNCAST_BORROWED_SUPER:%.*]] = unchecked_ref_cast [[BORROWED_SUPER]] : $BaseClassWithInternalProperty to $DerivedClassWithPublicProperty
+// CHECK-NEXT:    [[METHOD:%.*]] = super_method [[DOWNCAST_BORROWED_SUPER]] : $DerivedClassWithPublicProperty, #BaseClassWithInternalProperty.x!getter.1 : (BaseClassWithInternalProperty) -> () -> (), $@convention(method) (@guaranteed BaseClassWithInternalProperty) -> ()
+// CHECK-NEXT:    end_borrow [[BORROWED_SUPER]] from [[SUPER]]
+// CHECK-NEXT:    [[RESULT:%.*]] = apply [[METHOD]]([[SUPER]]) : $@convention(method) (@guaranteed BaseClassWithInternalProperty) -> ()
+// CHECK-NEXT:    destroy_value [[SUPER]] : $BaseClassWithInternalProperty
+// CHECK: } // end sil function '$S10properties30DerivedClassWithPublicPropertyC1xytvg'
+
+// Make sure that we can handle this AST:
+// (load_expr
+//   (open_existential_expr
+//     (opaque_expr A)
+//     ...
+//     (load_expr
+//        (opaque_expr  ))))
+
+class ReferenceType {
+  var p: NonmutatingProtocol
+  init(p: NonmutatingProtocol) { self.p = p }
+}
+
+protocol NonmutatingProtocol {
+  var x: Int { get nonmutating set }
+}
+
+// sil hidden @$S10properties19overlappingLoadExpr1cyAA13ReferenceTypeCz_tF : $@convention(thin) (@inout ReferenceType) -> () {
+// CHECK:        [[RESULT:%.*]] = alloc_stack $Int
+// CHECK-NEXT:   [[UNINIT:%.*]] = mark_uninitialized [var] [[RESULT]] : $*Int
+// CHECK-NEXT:   [[C_INOUT:%.*]] = begin_access [read] [unknown] %0 : $*ReferenceType
+// CHECK-NEXT:   [[C:%.*]] = load [copy] [[C_INOUT:%.*]] : $*ReferenceType
+// CHECK-NEXT:   end_access [[C_INOUT]] : $*ReferenceType
+// CHECK-NEXT:   [[C_FIELD_BOX:%.*]] = alloc_stack $NonmutatingProtocol
+// CHECK-NEXT:   [[GETTER:%.*]] = class_method [[C]] : $ReferenceType, #ReferenceType.p!getter.1 : (ReferenceType) -> () -> NonmutatingProtocol, $@convention(method) (@guaranteed ReferenceType) -> @out NonmutatingProtocol
+// CHECK-NEXT:   apply [[GETTER]]([[C_FIELD_BOX]], [[C]]) : $@convention(method) (@guaranteed ReferenceType) -> @out NonmutatingProtocol
+
+// CHECK-NEXT:   [[C_FIELD_PAYLOAD:%.*]] = open_existential_addr immutable_access [[C_FIELD_BOX]] : $*NonmutatingProtocol to $*@opened("{{.*}}") NonmutatingProtocol
+// CHECK-NEXT:   [[C_FIELD_COPY:%.*]] = alloc_stack $@opened("{{.*}}") NonmutatingProtocol
+// CHECK-NEXT:   copy_addr [[C_FIELD_PAYLOAD]] to [initialization] [[C_FIELD_COPY]] : $*@opened("{{.*}}") NonmutatingProtocol
+// CHECK-NEXT:   [[GETTER:%.*]] = witness_method $@opened("{{.*}}") NonmutatingProtocol, #NonmutatingProtocol.x!getter.1 : <Self where Self : NonmutatingProtocol> (Self) -> () -> Int, [[C_FIELD_PAYLOAD]] : $*@opened("{{.*}}") NonmutatingProtocol : $@convention(witness_method: NonmutatingProtocol) <τ_0_0 where τ_0_0 : NonmutatingProtocol> (@in_guaranteed τ_0_0) -> Int
+// CHECK-NEXT:   [[RESULT_VALUE:%.*]] = apply [[GETTER]]<@opened("{{.*}}") NonmutatingProtocol>([[C_FIELD_COPY]]) : $@convention(witness_method: NonmutatingProtocol) <τ_0_0 where τ_0_0 : NonmutatingProtocol> (@in_guaranteed τ_0_0) -> Int
+// CHECK-NEXT:   assign [[RESULT_VALUE]] to [[UNINIT]] : $*Int
+// CHECK-NEXT:   destroy_addr [[C_FIELD_COPY]] : $*@opened("{{.*}}") NonmutatingProtocol
+// CHECK-NEXT:   destroy_addr [[C_FIELD_BOX]] : $*NonmutatingProtocol
+// CHECK-NEXT:   destroy_value [[C]] : $ReferenceType
+// CHECK-NEXT:   dealloc_stack [[C_FIELD_COPY]] : $*@opened("{{.*}}") NonmutatingProtocol
+// CHECK-NEXT:   dealloc_stack [[C_FIELD_BOX]] : $*NonmutatingProtocol
+// CHECK-NEXT:   dealloc_stack [[RESULT]] : $*Int
+// CHECK-NEXT:   tuple ()
+// CHECK-NEXT:   return
+
+func overlappingLoadExpr(c: inout ReferenceType) {
+  _ = c.p.x
+}
diff --git a/test/SILGen/plus_zero_property_abstraction.swift b/test/SILGen/plus_zero_property_abstraction.swift
new file mode 100644
index 0000000..ab74768
--- /dev/null
+++ b/test/SILGen/plus_zero_property_abstraction.swift
@@ -0,0 +1,144 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -enable-sil-ownership -emit-silgen %s | %FileCheck %s
+
+struct Int {
+  mutating func foo() {}
+}
+
+struct Foo<T, U> {
+  var f: (T) -> U
+
+  var g: T
+}
+
+// CHECK-LABEL: sil hidden @$S20property_abstraction4getF{{[_0-9a-zA-Z]*}}Foo{{.*}}F : $@convention(thin) (@guaranteed Foo<Int, Int>) -> @owned @callee_guaranteed (Int) -> Int {
+// CHECK:       bb0([[X_ORIG:%.*]] : @guaranteed $Foo<Int, Int>):
+// CHECK:         [[F_ORIG:%.*]] = struct_extract [[X_ORIG]] : $Foo<Int, Int>, #Foo.f
+// CHECK:         [[F_ORIG_COPY:%.*]] = copy_value [[F_ORIG]]
+// CHECK:         [[REABSTRACT_FN:%.*]] = function_ref @$S{{.*}}TR :
+// CHECK:         [[F_SUBST:%.*]] = partial_apply [callee_guaranteed] [[REABSTRACT_FN]]([[F_ORIG_COPY]])
+// CHECK:         return [[F_SUBST]]
+// CHECK:       } // end sil function '$S20property_abstraction4getF{{[_0-9a-zA-Z]*}}F'
+func getF(_ x: Foo<Int, Int>) -> (Int) -> Int {
+  return x.f
+}
+
+// CHECK-LABEL: sil hidden @$S20property_abstraction4setF{{[_0-9a-zA-Z]*}}F
+// CHECK:         [[REABSTRACT_FN:%.*]] = function_ref @$S{{.*}}TR :
+// CHECK:         [[F_ORIG:%.*]] = partial_apply [callee_guaranteed] [[REABSTRACT_FN]]({{%.*}})
+// CHECK:         [[F_ADDR:%.*]] = struct_element_addr {{%.*}} : $*Foo<Int, Int>, #Foo.f
+// CHECK:         assign [[F_ORIG]] to [[F_ADDR]]
+func setF(_ x: inout Foo<Int, Int>, f: @escaping (Int) -> Int) {
+  x.f = f
+}
+
+func inOutFunc(_ f: inout ((Int) -> Int)) { }
+
+// CHECK-LABEL: sil hidden @$S20property_abstraction6inOutF{{[_0-9a-zA-Z]*}}F : 
+// CHECK: bb0([[ARG:%.*]] : @guaranteed $Foo<Int, Int>):
+// CHECK:   [[XBOX:%.*]] = alloc_box ${ var Foo<Int, Int> }, var, name "x"
+// CHECK:   [[XBOX_PB:%.*]] = project_box [[XBOX]] : ${ var Foo<Int, Int> }, 0
+// CHECK:   [[ARG_COPY:%.*]] = copy_value [[ARG]]
+// CHECK:   store [[ARG_COPY]] to [init] [[XBOX_PB]]
+// CHECK:   [[WRITE:%.*]] = begin_access [modify] [unknown] [[XBOX_PB]] : $*Foo<Int, Int>
+// CHECK:   [[F_ADDR:%.*]] = struct_element_addr [[WRITE]] : $*Foo<Int, Int>, #Foo.f
+// CHECK:   [[F_SUBST_MAT:%.*]] = alloc_stack
+// CHECK:   [[F_ORIG:%.*]] = load [copy] [[F_ADDR]]
+// CHECK:   [[REABSTRACT_FN:%.*]] = function_ref @$S{{.*}}TR :
+// CHECK:   [[F_SUBST_IN:%.*]] = partial_apply [callee_guaranteed] [[REABSTRACT_FN]]([[F_ORIG]])
+// CHECK:   store [[F_SUBST_IN]] to [init] [[F_SUBST_MAT]]
+// CHECK:   [[INOUTFUNC:%.*]] = function_ref @$S20property_abstraction9inOutFunc{{[_0-9a-zA-Z]*}}F
+// CHECK:   apply [[INOUTFUNC]]([[F_SUBST_MAT]])
+// CHECK:   [[F_SUBST_OUT:%.*]] = load [take] [[F_SUBST_MAT]]
+// CHECK:   [[REABSTRACT_FN:%.*]] = function_ref @$S{{.*}}TR :
+// CHECK:   [[F_ORIG:%.*]] = partial_apply [callee_guaranteed] [[REABSTRACT_FN]]([[F_SUBST_OUT]])
+// CHECK:   assign [[F_ORIG]] to [[F_ADDR]]
+// CHECK:   destroy_value [[XBOX]]
+// CHECK: } // end sil function '$S20property_abstraction6inOutF{{[_0-9a-zA-Z]*}}F'
+func inOutF(_ x: Foo<Int, Int>) {
+  var x = x
+  inOutFunc(&x.f)
+}
+
+// Don't produce a writeback for generic lvalues when there's no real
+// abstraction difference. <rdar://problem/16530674>
+// CHECK-LABEL: sil hidden @$S20property_abstraction23noAbstractionDifference{{[_0-9a-zA-Z]*}}F
+func noAbstractionDifference(_ x: Foo<Int, Int>) {
+  var x = x
+  // CHECK: [[ADDR:%.*]] = struct_element_addr {{%.*}}, #Foo.g
+  // CHECK: apply {{%.*}}([[ADDR]])
+  x.g.foo()
+}
+
+protocol P {}
+
+struct AddressOnlyLet<T> {
+  let f: (T) -> T
+  let makeAddressOnly: P
+}
+
+// CHECK-LABEL: sil hidden @$S20property_abstraction34getAddressOnlyReabstractedProperty{{[_0-9a-zA-Z]*}}F : $@convention(thin) (@in_guaranteed AddressOnlyLet<Int>) -> @owned @callee_guaranteed (Int) -> Int
+// CHECK: bb0([[ARG:%.*]] : @trivial $*AddressOnlyLet<Int>):
+// CHECK:   [[CLOSURE_ADDR:%.*]] = struct_element_addr {{%.*}} : $*AddressOnlyLet<Int>, #AddressOnlyLet.f
+// CHECK:   [[CLOSURE_ORIG:%.*]] = load [copy] [[CLOSURE_ADDR]]
+// CHECK:   [[REABSTRACT:%.*]] = function_ref
+// CHECK:   [[CLOSURE_SUBST:%.*]] = partial_apply [callee_guaranteed] [[REABSTRACT]]([[CLOSURE_ORIG]])
+// CHECK-NOT:   destroy_addr [[ARG]]
+// CHECK:   return [[CLOSURE_SUBST]]
+// CHECK: } // end sil function '$S20property_abstraction34getAddressOnlyReabstractedProperty{{[_0-9a-zA-Z]*}}F'
+func getAddressOnlyReabstractedProperty(_ x: AddressOnlyLet<Int>) -> (Int) -> Int {
+  return x.f
+}
+
+enum Bar<T, U> {
+  case F((T) -> U)
+}
+
+func getF(_ x: Bar<Int, Int>) -> (Int) -> Int {
+  switch x {
+  case .F(var f):
+    return f
+  }
+}
+
+func makeF(_ f: @escaping (Int) -> Int) -> Bar<Int, Int> {
+  return Bar.F(f)
+}
+
+struct ArrayLike<T> {
+  subscript(x: ()) -> T { get {} set {} }
+}
+
+typealias Test20341012 = (title: (), action: () -> ())
+
+struct T20341012 {
+    private var options: ArrayLike<Test20341012> { get {} set {} }
+
+    // CHECK-LABEL: sil hidden @$S20property_abstraction9T20341012V1t{{[_0-9a-zA-Z]*}}F
+    // CHECK:         [[TMP1:%.*]] = alloc_stack $(title: (), action: @callee_guaranteed (@in_guaranteed ()) -> @out ())
+    // CHECK:         apply {{.*}}<(title: (), action: () -> ())>([[TMP1]],
+    mutating func t() {
+        _ = self.options[].title
+    }
+}
+
+class MyClass {}
+
+// When simply assigning to a property, reabstract the r-value and assign
+// to the base instead of materializing and then assigning.
+protocol Factory {
+  associatedtype Product
+  var builder : () -> Product { get set }
+}
+func setBuilder<F: Factory where F.Product == MyClass>(_ factory: inout F) {
+  factory.builder = { return MyClass() }
+}
+// CHECK: sil hidden @$S20property_abstraction10setBuilder{{[_0-9a-zA-Z]*}}F : $@convention(thin) <F where F : Factory, F.Product == MyClass> (@inout F) -> ()
+// CHECK: bb0(%0 : @trivial $*F):
+// CHECK:   [[F0:%.*]] = function_ref @$S20property_abstraction10setBuilder{{[_0-9a-zA-Z]*}} : $@convention(thin) () -> @owned MyClass
+// CHECK:   [[F1:%.*]] = thin_to_thick_function [[F0]]
+// CHECK:   [[REABSTRACTOR:%.*]] = function_ref @$S{{.*}}TR :
+// CHECK:   [[F2:%.*]] = partial_apply [callee_guaranteed] [[REABSTRACTOR]]([[F1]])
+// CHECK:   [[WRITE:%.*]] = begin_access [modify] [unknown] %0 : $*F
+// CHECK:   [[SETTER:%.*]] = witness_method $F, #Factory.builder!setter.1
+// CHECK:   apply [[SETTER]]<F>([[F2]], [[WRITE]])
diff --git a/test/SILGen/plus_zero_protocol_extensions.swift b/test/SILGen/plus_zero_protocol_extensions.swift
new file mode 100644
index 0000000..ec1dd26
--- /dev/null
+++ b/test/SILGen/plus_zero_protocol_extensions.swift
@@ -0,0 +1,901 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -disable-objc-attr-requires-foundation-module -emit-silgen %s | %FileCheck %s
+
+public protocol P1 {
+  func reqP1a()
+  subscript(i: Int) -> Int { get set }
+}
+
+struct Box {
+  var number: Int
+}
+
+extension P1 {
+  // CHECK-LABEL: sil hidden @$S19protocol_extensions2P1PAAE6extP1a{{[_0-9a-zA-Z]*}}F : $@convention(method) <Self where Self : P1> (@in_guaranteed Self) -> () {
+  // CHECK: bb0([[SELF:%[0-9]+]] : $*Self):
+  func extP1a() {
+    // CHECK: [[WITNESS:%[0-9]+]] = witness_method $Self, #P1.reqP1a!1 : {{.*}} : $@convention(witness_method: P1) <τ_0_0 where τ_0_0 : P1> (@in_guaranteed τ_0_0) -> ()
+    // CHECK-NEXT: apply [[WITNESS]]<Self>([[SELF]]) : $@convention(witness_method: P1) <τ_0_0 where τ_0_0 : P1> (@in_guaranteed τ_0_0) -> ()
+    reqP1a()
+    // CHECK: return
+  }
+
+  // CHECK-LABEL: sil @$S19protocol_extensions2P1PAAE6extP1b{{[_0-9a-zA-Z]*}}F : $@convention(method) <Self where Self : P1> (@in_guaranteed Self) -> () {
+  // CHECK: bb0([[SELF:%[0-9]+]] : $*Self):
+  public func extP1b() {
+    // CHECK: [[FN:%[0-9]+]] = function_ref @$S19protocol_extensions2P1PAAE6extP1a{{[_0-9a-zA-Z]*}}F : $@convention(method) <τ_0_0 where τ_0_0 : P1> (@in_guaranteed τ_0_0) -> ()
+    // CHECK-NEXT: apply [[FN]]<Self>([[SELF]]) : $@convention(method) <τ_0_0 where τ_0_0 : P1> (@in_guaranteed τ_0_0) -> ()
+    extP1a()
+    // CHECK: return
+  }
+
+  subscript(i: Int) -> Int {
+    // materializeForSet can do static dispatch to peer accessors (tested later, in the emission of the concrete conformance)
+    get {
+      return 0
+    }
+    set {}
+  }
+
+  func callSubscript() -> Int {
+    // But here we have to do a witness method call:
+
+    // CHECK-LABEL: sil hidden @$S19protocol_extensions2P1PAAE13callSubscript{{[_0-9a-zA-Z]*}}F
+    // CHECK: bb0(%0 : $*Self):
+    // CHECK: witness_method $Self, #P1.subscript!getter.1
+    // CHECK: return
+    return self[0]
+  }
+
+  static var staticReadOnlyProperty: Int {
+    return 0
+  }
+
+  static var staticReadWrite1: Int {
+    get { return 0 }
+    set { }
+  }
+
+  static var staticReadWrite2: Box {
+    get { return Box(number: 0) }
+    set { }
+  }
+}
+
+// ----------------------------------------------------------------------------
+// Using protocol extension members with concrete types
+// ----------------------------------------------------------------------------
+class C : P1 {
+  func reqP1a() { }
+}
+
+//   (materializeForSet test from above)
+// CHECK-LABEL: sil private [transparent] [thunk] @$S19protocol_extensions1CCAA2P1A2aDPyS2icimTW
+// CHECK: bb0(%0 : $Builtin.RawPointer, %1 : $*Builtin.UnsafeValueBuffer, %2 : $Int, %3 : $*τ_0_0):
+// CHECK: function_ref @$S19protocol_extensions2P1PAAEyS2icig
+// CHECK: return
+
+class D : C { }
+
+struct S : P1 {
+  func reqP1a() { }
+}
+
+struct G<T> : P1 {
+  func reqP1a() { }
+}
+
+struct MetaHolder {
+  var d: D.Type = D.self
+  var s: S.Type = S.self
+}
+
+struct GenericMetaHolder<T> {
+  var g: G<T>.Type = G<T>.self
+}
+
+func inout_func(_ n: inout Int) {}
+
+// CHECK-LABEL: sil hidden @$S19protocol_extensions5testD_2dd1dyAA10MetaHolderV_AA1DCmAHtF : $@convention(thin) (MetaHolder, @thick D.Type, @guaranteed D) -> ()
+// CHECK: bb0([[M:%[0-9]+]] : $MetaHolder, [[DD:%[0-9]+]] : $@thick D.Type, [[D:%[0-9]+]] : $D):
+func testD(_ m: MetaHolder, dd: D.Type, d: D) {
+  // CHECK: [[D2:%[0-9]+]] = alloc_box ${ var D }
+  // CHECK: [[RESULT:%.*]] = project_box [[D2]]
+  // CHECK: [[MATERIALIZED_BORROWED_D:%[0-9]+]] = alloc_stack $D
+  // CHECK: store_borrow [[D]] to [[MATERIALIZED_BORROWED_D]]
+  // CHECK: [[FN:%[0-9]+]] = function_ref @$S19protocol_extensions2P1PAAE11returnsSelf{{[_0-9a-zA-Z]*}}F
+  // CHECK: apply [[FN]]<D>([[RESULT]], [[MATERIALIZED_BORROWED_D]]) : $@convention(method) <τ_0_0 where τ_0_0 : P1> (@in_guaranteed τ_0_0) -> @out τ_0_0
+  // CHECK-NEXT: dealloc_stack [[MATERIALIZED_BORROWED_D]]
+  var d2: D = d.returnsSelf()
+
+  // CHECK: metatype $@thick D.Type
+  // CHECK: function_ref @$S19protocol_extensions2P1PAAE22staticReadOnlyPropertySivgZ
+  let _ = D.staticReadOnlyProperty
+
+  // CHECK: metatype $@thick D.Type
+  // CHECK: function_ref @$S19protocol_extensions2P1PAAE16staticReadWrite1SivsZ
+  D.staticReadWrite1 = 1
+
+  // CHECK: metatype $@thick D.Type
+  // CHECK: alloc_stack $Int
+  // CHECK: function_ref @$S19protocol_extensions2P1PAAE16staticReadWrite1SivgZ
+  // CHECK: store
+  // CHECK: load
+  // CHECK: function_ref @$S19protocol_extensions2P1PAAE16staticReadWrite1SivsZ
+  // CHECK: dealloc_stack
+  D.staticReadWrite1 += 1
+
+  // CHECK: metatype $@thick D.Type
+  // CHECK: function_ref @$S19protocol_extensions2P1PAAE16staticReadWrite2AA3BoxVvsZ
+  D.staticReadWrite2 = Box(number: 2)
+
+  // CHECK: metatype $@thick D.Type
+  // CHECK: alloc_stack $Box
+  // CHECK: function_ref @$S19protocol_extensions2P1PAAE16staticReadWrite2AA3BoxVvgZ
+  // CHECK: store
+  // CHECK: load
+  // CHECK: function_ref @$S19protocol_extensions2P1PAAE16staticReadWrite2AA3BoxVvsZ
+  // CHECK: dealloc_stack
+  D.staticReadWrite2.number += 5
+
+  // CHECK: metatype $@thick D.Type
+  // CHECK: alloc_stack $Box
+  // CHECK: function_ref @$S19protocol_extensions2P1PAAE16staticReadWrite2AA3BoxVvgZ
+  // CHECK: store
+  // CHECK: function_ref @$S19protocol_extensions10inout_funcyySizF
+  // CHECK: load
+  // CHECK: function_ref @$S19protocol_extensions2P1PAAE16staticReadWrite2AA3BoxVvsZ
+  // CHECK: dealloc_stack
+  inout_func(&D.staticReadWrite2.number)
+
+  // CHECK: function_ref @$S19protocol_extensions2P1PAAE22staticReadOnlyPropertySivgZ
+  let _ = dd.staticReadOnlyProperty
+
+  // CHECK: function_ref @$S19protocol_extensions2P1PAAE16staticReadWrite1SivsZ
+  dd.staticReadWrite1 = 1
+
+  // CHECK: alloc_stack $Int
+  // CHECK: function_ref @$S19protocol_extensions2P1PAAE16staticReadWrite1SivgZ
+  // CHECK: store
+  // CHECK: load
+  // CHECK: function_ref @$S19protocol_extensions2P1PAAE16staticReadWrite1SivsZ
+  // CHECK: dealloc_stack
+  dd.staticReadWrite1 += 1
+
+  // CHECK: function_ref @$S19protocol_extensions2P1PAAE16staticReadWrite2AA3BoxVvsZ
+  dd.staticReadWrite2 = Box(number: 2)
+
+  // CHECK: alloc_stack $Box
+  // CHECK: function_ref @$S19protocol_extensions2P1PAAE16staticReadWrite2AA3BoxVvgZ
+  // CHECK: store
+  // CHECK: load
+  // CHECK: function_ref @$S19protocol_extensions2P1PAAE16staticReadWrite2AA3BoxVvsZ
+  // CHECK: dealloc_stack
+  dd.staticReadWrite2.number += 5
+
+  // CHECK: alloc_stack $Box
+  // CHECK: function_ref @$S19protocol_extensions2P1PAAE16staticReadWrite2AA3BoxVvgZ
+  // CHECK: store
+  // CHECK: function_ref @$S19protocol_extensions10inout_funcyySizF
+  // CHECK: load
+  // CHECK: function_ref @$S19protocol_extensions2P1PAAE16staticReadWrite2AA3BoxVvsZ
+  // CHECK: dealloc_stack
+  inout_func(&dd.staticReadWrite2.number)
+
+  // CHECK: function_ref @$S19protocol_extensions2P1PAAE22staticReadOnlyPropertySivgZ
+  let _ = m.d.staticReadOnlyProperty
+
+  // CHECK: function_ref @$S19protocol_extensions2P1PAAE16staticReadWrite1SivsZ
+  m.d.staticReadWrite1 = 1
+
+  // CHECK: alloc_stack $Int
+  // CHECK: function_ref @$S19protocol_extensions2P1PAAE16staticReadWrite1SivgZ
+  // CHECK: store
+  // CHECK: load
+  // CHECK: function_ref @$S19protocol_extensions2P1PAAE16staticReadWrite1SivsZ
+  // CHECK: dealloc_stack
+  m.d.staticReadWrite1 += 1
+
+  // CHECK: function_ref @$S19protocol_extensions2P1PAAE16staticReadWrite2AA3BoxVvsZ
+  m.d.staticReadWrite2 = Box(number: 2)
+
+  // CHECK: alloc_stack $Box
+  // CHECK: function_ref @$S19protocol_extensions2P1PAAE16staticReadWrite2AA3BoxVvgZ
+  // CHECK: store
+  // CHECK: load
+  // CHECK: function_ref @$S19protocol_extensions2P1PAAE16staticReadWrite2AA3BoxVvsZ
+  // CHECK: dealloc_stack
+  m.d.staticReadWrite2.number += 5
+
+  // CHECK: alloc_stack $Box
+  // CHECK: function_ref @$S19protocol_extensions2P1PAAE16staticReadWrite2AA3BoxVvgZ
+  // CHECK: store
+  // CHECK: function_ref @$S19protocol_extensions10inout_funcyySizF
+  // CHECK: load
+  // CHECK: function_ref @$S19protocol_extensions2P1PAAE16staticReadWrite2AA3BoxVvsZ
+  // CHECK: dealloc_stack
+  inout_func(&m.d.staticReadWrite2.number)
+
+  // CHECK: return
+}
+
+// CHECK-LABEL: sil hidden @$S19protocol_extensions5testS_2ssyAA10MetaHolderV_AA1SVmtF
+func testS(_ m: MetaHolder, ss: S.Type) {
+  // CHECK: metatype $@thick S.Type
+  // CHECK: function_ref @$S19protocol_extensions2P1PAAE22staticReadOnlyPropertySivgZ
+  let _ = S.staticReadOnlyProperty
+
+  // CHECK: metatype $@thick S.Type
+  // CHECK: function_ref @$S19protocol_extensions2P1PAAE16staticReadWrite1SivsZ
+  S.staticReadWrite1 = 1
+
+  // CHECK: alloc_stack $Int
+  // CHECK: metatype $@thick S.Type
+  // CHECK: function_ref @$S19protocol_extensions2P1PAAE16staticReadWrite1SivgZ
+  // CHECK: store
+  // CHECK: load
+  // CHECK: function_ref @$S19protocol_extensions2P1PAAE16staticReadWrite1SivsZ
+  // CHECK: dealloc_stack
+  S.staticReadWrite1 += 1
+
+  // CHECK: metatype $@thick S.Type
+  // CHECK: function_ref @$S19protocol_extensions2P1PAAE16staticReadWrite2AA3BoxVvsZ
+  S.staticReadWrite2 = Box(number: 2)
+
+  // CHECK: alloc_stack $Box
+  // CHECK: metatype $@thick S.Type
+  // CHECK: function_ref @$S19protocol_extensions2P1PAAE16staticReadWrite2AA3BoxVvgZ
+  // CHECK: store
+  // CHECK: load
+  // CHECK: function_ref @$S19protocol_extensions2P1PAAE16staticReadWrite2AA3BoxVvsZ
+  // CHECK: dealloc_stack
+  S.staticReadWrite2.number += 5
+
+  // CHECK: alloc_stack $Box
+  // CHECK: metatype $@thick S.Type
+  // CHECK: function_ref @$S19protocol_extensions2P1PAAE16staticReadWrite2AA3BoxVvgZ
+  // CHECK: store
+  // CHECK: function_ref @$S19protocol_extensions10inout_funcyySizF
+  // CHECK: load
+  // CHECK: function_ref @$S19protocol_extensions2P1PAAE16staticReadWrite2AA3BoxVvsZ
+  // CHECK: dealloc_stack
+  inout_func(&S.staticReadWrite2.number)
+
+  // CHECK: metatype $@thick S.Type
+  // CHECK: function_ref @$S19protocol_extensions2P1PAAE22staticReadOnlyPropertySivgZ
+  let _ = ss.staticReadOnlyProperty
+
+  // CHECK: metatype $@thick S.Type
+  // CHECK: function_ref @$S19protocol_extensions2P1PAAE16staticReadWrite1SivsZ
+  ss.staticReadWrite1 = 1
+
+  // CHECK: alloc_stack $Int
+  // CHECK: metatype $@thick S.Type
+  // CHECK: function_ref @$S19protocol_extensions2P1PAAE16staticReadWrite1SivgZ
+  // CHECK: store
+  // CHECK: load
+  // CHECK: function_ref @$S19protocol_extensions2P1PAAE16staticReadWrite1SivsZ
+  // CHECK: dealloc_stack
+  ss.staticReadWrite1 += 1
+
+  // CHECK: metatype $@thick S.Type
+  // CHECK: function_ref @$S19protocol_extensions2P1PAAE16staticReadWrite2AA3BoxVvsZ
+  ss.staticReadWrite2 = Box(number: 2)
+
+  // CHECK: alloc_stack $Box
+  // CHECK: metatype $@thick S.Type
+  // CHECK: function_ref @$S19protocol_extensions2P1PAAE16staticReadWrite2AA3BoxVvgZ
+  // CHECK: store
+  // CHECK: load
+  // CHECK: function_ref @$S19protocol_extensions2P1PAAE16staticReadWrite2AA3BoxVvsZ
+  // CHECK: dealloc_stack
+  ss.staticReadWrite2.number += 5
+
+  // CHECK: alloc_stack $Box
+  // CHECK: metatype $@thick S.Type
+  // CHECK: function_ref @$S19protocol_extensions2P1PAAE16staticReadWrite2AA3BoxVvgZ
+  // CHECK: store
+  // CHECK: function_ref @$S19protocol_extensions10inout_funcyySizF
+  // CHECK: load
+  // CHECK: function_ref @$S19protocol_extensions2P1PAAE16staticReadWrite2AA3BoxVvsZ
+  // CHECK: dealloc_stack
+  inout_func(&ss.staticReadWrite2.number)
+
+  // CHECK: metatype $@thick S.Type
+  // CHECK: function_ref @$S19protocol_extensions2P1PAAE22staticReadOnlyPropertySivgZ
+  let _ = m.s.staticReadOnlyProperty
+
+  // CHECK: metatype $@thick S.Type
+  // CHECK: function_ref @$S19protocol_extensions2P1PAAE16staticReadWrite1SivsZ
+  m.s.staticReadWrite1 = 1
+
+  // CHECK: alloc_stack $Int
+  // CHECK: metatype $@thick S.Type
+  // CHECK: function_ref @$S19protocol_extensions2P1PAAE16staticReadWrite1SivgZ
+  // CHECK: store
+  // CHECK: load
+  // CHECK: function_ref @$S19protocol_extensions2P1PAAE16staticReadWrite1SivsZ
+  // CHECK: dealloc_stack
+  m.s.staticReadWrite1 += 1
+
+  // CHECK: metatype $@thick S.Type
+  // CHECK: function_ref @$S19protocol_extensions2P1PAAE16staticReadWrite2AA3BoxVvsZ
+  m.s.staticReadWrite2 = Box(number: 2)
+
+  // CHECK: alloc_stack $Box
+  // CHECK: metatype $@thick S.Type
+  // CHECK: function_ref @$S19protocol_extensions2P1PAAE16staticReadWrite2AA3BoxVvgZ
+  // CHECK: store
+  // CHECK: load
+  // CHECK: function_ref @$S19protocol_extensions2P1PAAE16staticReadWrite2AA3BoxVvsZ
+  // CHECK: dealloc_stack
+  m.s.staticReadWrite2.number += 5
+
+  // CHECK: alloc_stack $Box
+  // CHECK: metatype $@thick S.Type
+  // CHECK: function_ref @$S19protocol_extensions2P1PAAE16staticReadWrite2AA3BoxVvgZ
+  // CHECK: store
+  // CHECK: function_ref @$S19protocol_extensions10inout_funcyySizF
+  // CHECK: load
+  // CHECK: function_ref @$S19protocol_extensions2P1PAAE16staticReadWrite2AA3BoxVvsZ
+  // CHECK: dealloc_stack
+  inout_func(&m.s.staticReadWrite2.number)
+
+  // CHECK: return
+}
+
+// CHECK-LABEL: sil hidden @$S19protocol_extensions5testG{{[_0-9a-zA-Z]*}}F
+func testG<T>(_ m: GenericMetaHolder<T>, gg: G<T>.Type) {
+  // CHECK: metatype $@thick G<T>.Type
+  // CHECK: function_ref @$S19protocol_extensions2P1PAAE22staticReadOnlyPropertySivgZ
+  let _ = G<T>.staticReadOnlyProperty
+
+  // CHECK: metatype $@thick G<T>.Type
+  // CHECK: function_ref @$S19protocol_extensions2P1PAAE16staticReadWrite1SivsZ
+  G<T>.staticReadWrite1 = 1
+
+  // CHECK: alloc_stack $Int
+  // CHECK: metatype $@thick G<T>.Type
+  // CHECK: function_ref @$S19protocol_extensions2P1PAAE16staticReadWrite1SivgZ
+  // CHECK: store
+  // CHECK: load
+  // CHECK: function_ref @$S19protocol_extensions2P1PAAE16staticReadWrite1SivsZ
+  // CHECK: dealloc_stack
+  G<T>.staticReadWrite1 += 1
+
+  // CHECK: metatype $@thick G<T>.Type
+  // CHECK: function_ref @$S19protocol_extensions2P1PAAE16staticReadWrite2AA3BoxVvsZ
+  G<T>.staticReadWrite2 = Box(number: 2)
+
+  // CHECK: alloc_stack $Box
+  // CHECK: metatype $@thick G<T>.Type
+  // CHECK: function_ref @$S19protocol_extensions2P1PAAE16staticReadWrite2AA3BoxVvgZ
+  // CHECK: store
+  // CHECK: load
+  // CHECK: function_ref @$S19protocol_extensions2P1PAAE16staticReadWrite2AA3BoxVvsZ
+  // CHECK: dealloc_stack
+  G<T>.staticReadWrite2.number += 5
+
+  // CHECK: alloc_stack $Box
+  // CHECK: metatype $@thick G<T>.Type
+  // CHECK: function_ref @$S19protocol_extensions2P1PAAE16staticReadWrite2AA3BoxVvgZ
+  // CHECK: store
+  // CHECK: function_ref @$S19protocol_extensions10inout_funcyySizF
+  // CHECK: load
+  // CHECK: function_ref @$S19protocol_extensions2P1PAAE16staticReadWrite2AA3BoxVvsZ
+  // CHECK: dealloc_stack
+  inout_func(&G<T>.staticReadWrite2.number)
+
+  // CHECK: metatype $@thick G<T>.Type
+  // CHECK: function_ref @$S19protocol_extensions2P1PAAE22staticReadOnlyPropertySivgZ
+  let _ = gg.staticReadOnlyProperty
+
+  // CHECK: metatype $@thick G<T>.Type
+  // CHECK: function_ref @$S19protocol_extensions2P1PAAE16staticReadWrite1SivsZ
+  gg.staticReadWrite1 = 1
+
+  // CHECK: alloc_stack $Int
+  // CHECK: metatype $@thick G<T>.Type
+  // CHECK: function_ref @$S19protocol_extensions2P1PAAE16staticReadWrite1SivgZ
+  // CHECK: store
+  // CHECK: load
+  // CHECK: function_ref @$S19protocol_extensions2P1PAAE16staticReadWrite1SivsZ
+  // CHECK: dealloc_stack
+  gg.staticReadWrite1 += 1
+
+  // CHECK: metatype $@thick G<T>.Type
+  // CHECK: function_ref @$S19protocol_extensions2P1PAAE16staticReadWrite2AA3BoxVvsZ
+  gg.staticReadWrite2 = Box(number: 2)
+
+  // CHECK: alloc_stack $Box
+  // CHECK: metatype $@thick G<T>.Type
+  // CHECK: function_ref @$S19protocol_extensions2P1PAAE16staticReadWrite2AA3BoxVvgZ
+  // CHECK: store
+  // CHECK: load
+  // CHECK: function_ref @$S19protocol_extensions2P1PAAE16staticReadWrite2AA3BoxVvsZ
+  // CHECK: dealloc_stack
+  gg.staticReadWrite2.number += 5
+
+  // CHECK: alloc_stack $Box
+  // CHECK: metatype $@thick G<T>.Type
+  // CHECK: function_ref @$S19protocol_extensions2P1PAAE16staticReadWrite2AA3BoxVvgZ
+  // CHECK: store
+  // CHECK: function_ref @$S19protocol_extensions10inout_funcyySizF
+  // CHECK: load
+  // CHECK: function_ref @$S19protocol_extensions2P1PAAE16staticReadWrite2AA3BoxVvsZ
+  // CHECK: dealloc_stack
+  inout_func(&gg.staticReadWrite2.number)
+
+  // CHECK: metatype $@thick G<T>.Type
+  // CHECK: function_ref @$S19protocol_extensions2P1PAAE22staticReadOnlyPropertySivgZ
+  let _ = m.g.staticReadOnlyProperty
+
+  // CHECK: metatype $@thick G<T>.Type
+  // CHECK: function_ref @$S19protocol_extensions2P1PAAE16staticReadWrite1SivsZ
+  m.g.staticReadWrite1 = 1
+
+  // CHECK: alloc_stack $Int
+  // CHECK: metatype $@thick G<T>.Type
+  // CHECK: function_ref @$S19protocol_extensions2P1PAAE16staticReadWrite1SivgZ
+  // CHECK: store
+  // CHECK: load
+  // CHECK: function_ref @$S19protocol_extensions2P1PAAE16staticReadWrite1SivsZ
+  // CHECK: dealloc_stack
+  m.g.staticReadWrite1 += 1
+
+  // CHECK: metatype $@thick G<T>.Type
+  // CHECK: function_ref @$S19protocol_extensions2P1PAAE16staticReadWrite2AA3BoxVvsZ
+  m.g.staticReadWrite2 = Box(number: 2)
+
+  // CHECK: alloc_stack $Box
+  // CHECK: metatype $@thick G<T>.Type
+  // CHECK: function_ref @$S19protocol_extensions2P1PAAE16staticReadWrite2AA3BoxVvgZ
+  // CHECK: store
+  // CHECK: load
+  // CHECK: function_ref @$S19protocol_extensions2P1PAAE16staticReadWrite2AA3BoxVvsZ
+  // CHECK: dealloc_stack
+  m.g.staticReadWrite2.number += 5
+
+  // CHECK: alloc_stack $Box
+  // CHECK: metatype $@thick G<T>.Type
+  // CHECK: function_ref @$S19protocol_extensions2P1PAAE16staticReadWrite2AA3BoxVvgZ
+  // CHECK: store
+  // CHECK: function_ref @$S19protocol_extensions10inout_funcyySizF
+  // CHECK: load
+  // CHECK: function_ref @$S19protocol_extensions2P1PAAE16staticReadWrite2AA3BoxVvsZ
+  // CHECK: dealloc_stack
+  inout_func(&m.g.staticReadWrite2.number)
+
+  // CHECK: return
+}
+
+// ----------------------------------------------------------------------------
+// Using protocol extension members with existentials
+// ----------------------------------------------------------------------------
+extension P1 {
+  func f1() { }
+
+  subscript (i: Int64) -> Bool {
+    get { return true }
+  }
+
+  var prop: Bool {
+    get { return true }
+  }
+
+  func returnsSelf() -> Self { return self }
+
+  var prop2: Bool {
+    get { return true }
+    set { }
+  }
+
+  subscript (b: Bool) -> Bool {
+    get { return b }
+    set { }
+  }
+}
+
+// CHECK-LABEL: sil hidden @$S19protocol_extensions17testExistentials1{{[_0-9a-zA-Z]*}}F
+// CHECK: bb0([[P:%[0-9]+]] : $*P1, [[B:%[0-9]+]] : $Bool, [[I:%[0-9]+]] : $Int64):
+func testExistentials1(_ p1: P1, b: Bool, i: Int64) {
+  // CHECK: [[POPENED:%[0-9]+]] = open_existential_addr immutable_access [[P]] : $*P1 to $*@opened([[UUID:".*"]])
+  // CHECK: [[F1:%[0-9]+]] = function_ref @$S19protocol_extensions2P1PAAE2f1{{[_0-9a-zA-Z]*}}F
+  // CHECK: apply [[F1]]<@opened([[UUID]]) P1>([[POPENED]]) : $@convention(method) <τ_0_0 where τ_0_0 : P1> (@in_guaranteed τ_0_0) -> ()
+  p1.f1()
+
+  // CHECK: [[POPENED:%[0-9]+]] = open_existential_addr immutable_access [[P]] : $*P1 to $*@opened([[UUID:".*"]]) P1
+  // CHECK: copy_addr [[POPENED]] to [initialization] [[POPENED_COPY:%.*]] :
+  // CHECK: [[GETTER:%[0-9]+]] = function_ref @$S19protocol_extensions2P1PAAEySbs5Int64Vcig
+  // CHECK: apply [[GETTER]]<@opened([[UUID]]) P1>([[I]], [[POPENED_COPY]]) : $@convention(method) <τ_0_0 where τ_0_0 : P1> (Int64, @in_guaranteed τ_0_0) -> Bool
+  // CHECK: store{{.*}} : $*Bool
+  // CHECK: destroy_addr [[POPENED_COPY]]
+  // CHECK: dealloc_stack [[POPENED_COPY]]
+  var b2 = p1[i]
+
+  // CHECK: [[POPENED:%[0-9]+]] = open_existential_addr immutable_access [[P]] : $*P1 to $*@opened([[UUID:".*"]]) P1
+  // CHECK: copy_addr [[POPENED]] to [initialization] [[POPENED_COPY:%.*]] :
+  // CHECK: [[GETTER:%[0-9]+]] = function_ref @$S19protocol_extensions2P1PAAE4propSbvg
+  // CHECK: apply [[GETTER]]<@opened([[UUID]]) P1>([[POPENED_COPY]]) : $@convention(method) <τ_0_0 where τ_0_0 : P1> (@in_guaranteed τ_0_0) -> Bool
+  // CHECK: store{{.*}} : $*Bool
+  // CHECK: dealloc_stack [[POPENED_COPY]]
+  var b3 = p1.prop
+}
+
+// CHECK-LABEL: sil hidden @$S19protocol_extensions17testExistentials2{{[_0-9a-zA-Z]*}}F
+// CHECK: bb0([[P:%[0-9]+]] : $*P1):
+func testExistentials2(_ p1: P1) {
+  // CHECK: [[P1A:%[0-9]+]] = alloc_box ${ var P1 }
+  // CHECK: [[PB:%.*]] = project_box [[P1A]]
+  // CHECK: [[POPENED:%[0-9]+]] = open_existential_addr immutable_access [[P]] : $*P1 to $*@opened([[UUID:".*"]]) P1
+  // CHECK: [[P1AINIT:%[0-9]+]] = init_existential_addr [[PB]] : $*P1, $@opened([[UUID2:".*"]]) P1
+  // CHECK: [[FN:%[0-9]+]] = function_ref @$S19protocol_extensions2P1PAAE11returnsSelf{{[_0-9a-zA-Z]*}}F
+  // CHECK: apply [[FN]]<@opened([[UUID]]) P1>([[P1AINIT]], [[POPENED]]) : $@convention(method) <τ_0_0 where τ_0_0 : P1> (@in_guaranteed τ_0_0) -> @out τ_0_0
+  var p1a: P1 = p1.returnsSelf()
+}
+
+// CHECK-LABEL: sil hidden @$S19protocol_extensions23testExistentialsGetters{{[_0-9a-zA-Z]*}}F
+// CHECK: bb0([[P:%[0-9]+]] : $*P1):
+func testExistentialsGetters(_ p1: P1) {
+  // CHECK: [[POPENED:%[0-9]+]] = open_existential_addr immutable_access [[P]] : $*P1 to $*@opened([[UUID:".*"]]) P1
+  // CHECK: copy_addr [[POPENED]] to [initialization] [[POPENED_COPY:%.*]] :
+  // CHECK: [[FN:%[0-9]+]] = function_ref @$S19protocol_extensions2P1PAAE5prop2Sbvg
+  // CHECK: [[B:%[0-9]+]] = apply [[FN]]<@opened([[UUID]]) P1>([[POPENED_COPY]]) : $@convention(method) <τ_0_0 where τ_0_0 : P1> (@in_guaranteed τ_0_0) -> Bool
+  let b: Bool = p1.prop2
+
+  // CHECK: [[POPENED:%[0-9]+]] = open_existential_addr immutable_access [[P]] : $*P1 to $*@opened([[UUID:".*"]]) P1
+  // CHECK: copy_addr [[POPENED]] to [initialization] [[POPENED_COPY:%.*]] :
+  // CHECK: [[GETTER:%[0-9]+]] = function_ref @$S19protocol_extensions2P1PAAEyS2bcig
+  // CHECK: apply [[GETTER]]<@opened([[UUID]]) P1>([[B]], [[POPENED_COPY]]) : $@convention(method) <τ_0_0 where τ_0_0 : P1> (Bool, @in_guaranteed τ_0_0) -> Bool
+  let b2: Bool = p1[b]
+}
+
+// CHECK-LABEL: sil hidden @$S19protocol_extensions22testExistentialSetters{{[_0-9a-zA-Z]*}}F
+// CHECK: bb0([[P:%[0-9]+]] : $*P1, [[B:%[0-9]+]] : $Bool):
+func testExistentialSetters(_ p1: P1, b: Bool) {
+  var p1 = p1
+  // CHECK: [[PBOX:%[0-9]+]] = alloc_box ${ var P1 }
+  // CHECK: [[PBP:%[0-9]+]] = project_box [[PBOX]]
+  // CHECK-NEXT: copy_addr [[P]] to [initialization] [[PBP]] : $*P1
+  // CHECK: [[WRITE:%.*]] = begin_access [modify] [unknown] [[PBP]]
+  // CHECK: [[POPENED:%[0-9]+]] = open_existential_addr mutable_access [[WRITE]] : $*P1 to $*@opened([[UUID:".*"]]) P1
+  // CHECK: [[GETTER:%[0-9]+]] = function_ref @$S19protocol_extensions2P1PAAE5prop2Sbvs
+  // CHECK: apply [[GETTER]]<@opened([[UUID]]) P1>([[B]], [[POPENED]]) : $@convention(method) <τ_0_0 where τ_0_0 : P1> (Bool, @inout τ_0_0) -> ()
+  // CHECK-NOT: deinit_existential_addr
+  p1.prop2 = b
+
+  // CHECK: [[WRITE:%.*]] = begin_access [modify] [unknown] [[PBP]]
+  // CHECK: [[POPENED:%[0-9]+]] = open_existential_addr mutable_access [[WRITE]] : $*P1 to $*@opened([[UUID:".*"]]) P1
+  // CHECK: [[SUBSETTER:%[0-9]+]] = function_ref @$S19protocol_extensions2P1PAAEyS2bcis
+  // CHECK: apply [[SUBSETTER]]<@opened([[UUID]]) P1>([[B]], [[B]], [[POPENED]]) : $@convention(method) <τ_0_0 where τ_0_0 : P1> (Bool, Bool, @inout τ_0_0) -> ()
+  // CHECK-NOT: deinit_existential_addr [[PB]] : $*P1
+  p1[b] = b
+
+  // CHECK: return
+}
+
+struct HasAP1 {
+  var p1: P1
+
+  var someP1: P1 {
+    get { return p1 }
+    set { p1 = newValue }
+  }
+}
+
+// CHECK-LABEL: sil hidden @$S19protocol_extensions29testLogicalExistentialSetters{{[_0-9a-zA-Z]*}}F
+// CHECK: bb0([[HASP1:%[0-9]+]] : $*HasAP1, [[B:%[0-9]+]] : $Bool)
+func testLogicalExistentialSetters(_ hasAP1: HasAP1, _ b: Bool) {
+  var hasAP1 = hasAP1
+  // CHECK: [[HASP1_BOX:%[0-9]+]] = alloc_box ${ var HasAP1 }
+  // CHECK: [[PBHASP1:%[0-9]+]] = project_box [[HASP1_BOX]]
+  // CHECK-NEXT: copy_addr [[HASP1]] to [initialization] [[PBHASP1]] : $*HasAP1
+  // CHECK: [[WRITE:%.*]] = begin_access [modify] [unknown] [[PBHASP1]]
+  // CHECK: [[P1_COPY:%[0-9]+]] = alloc_stack $P1
+  // CHECK-NEXT: [[HASP1_COPY:%[0-9]+]] = alloc_stack $HasAP1
+  // CHECK-NEXT: copy_addr [[WRITE]] to [initialization] [[HASP1_COPY]] : $*HasAP1
+  // CHECK: [[SOMEP1_GETTER:%[0-9]+]] = function_ref @$S19protocol_extensions6HasAP1V6someP1AA0F0_pvg : $@convention(method) (@in_guaranteed HasAP1) -> @out P1
+  // CHECK: [[RESULT:%[0-9]+]] = apply [[SOMEP1_GETTER]]([[P1_COPY]], [[HASP1_COPY]]) : $@convention(method) (@in_guaranteed HasAP1) -> @out P1
+  // CHECK: [[P1_OPENED:%[0-9]+]] = open_existential_addr mutable_access [[P1_COPY]] : $*P1 to $*@opened([[UUID:".*"]]) P1
+  // CHECK: [[PROP2_SETTER:%[0-9]+]] = function_ref @$S19protocol_extensions2P1PAAE5prop2Sbvs : $@convention(method) <τ_0_0 where τ_0_0 : P1> (Bool, @inout τ_0_0) -> ()
+  // CHECK: apply [[PROP2_SETTER]]<@opened([[UUID]]) P1>([[B]], [[P1_OPENED]]) : $@convention(method) <τ_0_0 where τ_0_0 : P1> (Bool, @inout τ_0_0) -> ()
+  // CHECK: [[SOMEP1_SETTER:%[0-9]+]] = function_ref @$S19protocol_extensions6HasAP1V6someP1AA0F0_pvs : $@convention(method) (@in P1, @inout HasAP1) -> ()
+  // CHECK: apply [[SOMEP1_SETTER]]([[P1_COPY]], [[WRITE]]) : $@convention(method) (@in P1, @inout HasAP1) -> ()
+  // CHECK-NOT: deinit_existential_addr
+  hasAP1.someP1.prop2 = b
+  // CHECK: return
+}
+
+func plusOneP1() -> P1 {}
+
+// CHECK-LABEL: sil hidden @$S19protocol_extensions38test_open_existential_semantics_opaque{{[_0-9a-zA-Z]*}}F
+func test_open_existential_semantics_opaque(_ guaranteed: P1,
+                                            immediate: P1) {
+  var immediate = immediate
+  // CHECK: [[IMMEDIATE_BOX:%.*]] = alloc_box ${ var P1 }
+  // CHECK: [[PB:%.*]] = project_box [[IMMEDIATE_BOX]]
+  // CHECK: [[VALUE:%.*]] = open_existential_addr immutable_access %0
+  // CHECK: [[METHOD:%.*]] = function_ref
+  // CHECK: apply [[METHOD]]<{{.*}}>([[VALUE]])
+
+  guaranteed.f1()
+  
+  // -- Need a guaranteed copy because it's immutable
+  // CHECK: [[READ:%.*]] = begin_access [read] [unknown] [[PB]]
+  // CHECK: copy_addr [[READ]] to [initialization] [[IMMEDIATE:%.*]] :
+  // CHECK: [[VALUE:%.*]] = open_existential_addr immutable_access [[IMMEDIATE]]
+  // CHECK: [[METHOD:%.*]] = function_ref
+  // -- Can consume the value from our own copy
+  // CHECK: apply [[METHOD]]<{{.*}}>([[VALUE]])
+  // CHECK: destroy_addr [[IMMEDIATE]]
+  // CHECK: dealloc_stack [[IMMEDIATE]]
+  immediate.f1()
+
+  // CHECK: [[PLUS_ONE:%.*]] = alloc_stack $P1
+  // CHECK: [[VALUE:%.*]] = open_existential_addr immutable_access [[PLUS_ONE]]
+  // CHECK: [[METHOD:%.*]] = function_ref
+  // -- Can consume the value from our own copy
+  // CHECK: apply [[METHOD]]<{{.*}}>([[VALUE]])
+  // CHECK: destroy_addr [[PLUS_ONE]]
+  // CHECK: dealloc_stack [[PLUS_ONE]]
+  plusOneP1().f1()
+}
+
+protocol CP1: class {}
+
+extension CP1 {
+  func f1() { }
+}
+
+func plusOneCP1() -> CP1 {}
+
+// CHECK-LABEL: sil hidden @$S19protocol_extensions37test_open_existential_semantics_class{{[_0-9a-zA-Z]*}}F
+// CHECK: bb0([[ARG0:%.*]] : $CP1, [[ARG1:%.*]] : $CP1):
+func test_open_existential_semantics_class(_ guaranteed: CP1,
+                                           immediate: CP1) {
+  var immediate = immediate
+  // CHECK: [[IMMEDIATE_BOX:%.*]] = alloc_box ${ var CP1 }
+  // CHECK: [[PB:%.*]] = project_box [[IMMEDIATE_BOX]]
+
+  // CHECK-NOT: copy_value [[ARG0]]
+  // CHECK: [[VALUE:%.*]] = open_existential_ref [[ARG0]]
+  // CHECK: [[METHOD:%.*]] = function_ref
+  // CHECK: apply [[METHOD]]<{{.*}}>([[VALUE]])
+  // CHECK-NOT: destroy_value [[VALUE]]
+  // CHECK-NOT: destroy_value [[ARG0]]
+  guaranteed.f1()
+
+  // CHECK: [[READ:%.*]] = begin_access [read] [unknown] [[PB]]
+  // CHECK: [[IMMEDIATE:%.*]] = load [copy] [[READ]]
+  // CHECK: [[VALUE:%.*]] = open_existential_ref [[IMMEDIATE]]
+  // CHECK: [[METHOD:%.*]] = function_ref
+  // CHECK: apply [[METHOD]]<{{.*}}>([[VALUE]])
+  // CHECK: destroy_value [[VALUE]]
+  // CHECK-NOT: destroy_value [[IMMEDIATE]]
+  immediate.f1()
+
+  // CHECK: [[F:%.*]] = function_ref {{.*}}plusOneCP1
+  // CHECK: [[PLUS_ONE:%.*]] = apply [[F]]()
+  // CHECK: [[VALUE:%.*]] = open_existential_ref [[PLUS_ONE]]
+  // CHECK: [[METHOD:%.*]] = function_ref
+  // CHECK: apply [[METHOD]]<{{.*}}>([[VALUE]])
+  // CHECK: destroy_value [[VALUE]]
+  // CHECK-NOT: destroy_value [[PLUS_ONE]]
+  plusOneCP1().f1()
+}
+// CHECK: } // end sil function '$S19protocol_extensions37test_open_existential_semantics_class{{[_0-9a-zA-Z]*}}F'
+
+protocol InitRequirement {
+  init(c: C)
+}
+
+extension InitRequirement {
+  // CHECK-LABEL: sil hidden @$S19protocol_extensions15InitRequirementPAAE1dxAA1DC_tcfC : $@convention(method) <Self where Self : InitRequirement> (@owned D, @thick Self.Type) -> @out Self
+  // CHECK:       bb0([[OUT:%.*]] : $*Self, [[ARG:%.*]] : $D, [[SELF_TYPE:%.*]] : $@thick Self.Type):
+  init(d: D) {
+    // CHECK:      [[SELF_BOX:%.*]] = alloc_box
+    // CHECK-NEXT: [[UNINIT_SELF:%.*]] = mark_uninitialized [delegatingself] [[SELF_BOX]]
+    // CHECK-NEXT: [[SELF_BOX_ADDR:%.*]] = project_box [[UNINIT_SELF]]
+    // CHECK:      [[SELF_BOX:%.*]] = alloc_stack $Self
+    // CHECK-NEXT: [[BORROWED_ARG:%.*]] = begin_borrow [[ARG]]
+    // CHECK-NEXT: [[ARG_COPY:%.*]] = copy_value [[BORROWED_ARG]]
+    // CHECK-NEXT: [[ARG_COPY_CAST:%.*]] = upcast [[ARG_COPY]]
+    // CHECK:      [[DELEGATEE:%.*]] = witness_method $Self, #InitRequirement.init!allocator.1 : {{.*}} : $@convention(witness_method: InitRequirement) <τ_0_0 where τ_0_0 : InitRequirement> (@owned C, @thick τ_0_0.Type) -> @out τ_0_0
+    // CHECK-NEXT: apply [[DELEGATEE]]<Self>([[SELF_BOX]], [[ARG_COPY_CAST]], [[SELF_TYPE]])
+    // CHECK-NEXT: end_borrow [[BORROWED_ARG]] from [[ARG]]
+    // CHECK-NEXT: copy_addr [take] [[SELF_BOX]] to [[SELF_BOX_ADDR]]
+    // CHECK-NEXT: dealloc_stack [[SELF_BOX]]
+    // CHECK-NEXT: copy_addr [[SELF_BOX_ADDR]] to [initialization] [[OUT]]
+    // CHECK-NEXT: destroy_value [[ARG]]
+    // CHECK-NEXT: destroy_value [[UNINIT_SELF]]
+    // CHECK:      return
+    self.init(c: d)
+  }
+
+  // CHECK-LABEL: sil hidden @$S19protocol_extensions15InitRequirementPAAE2d2xAA1DC_tcfC : $@convention(method)
+  // CHECK:       bb0([[OUT:%.*]] : $*Self, [[ARG:%.*]] : $D, [[SELF_TYPE:%.*]] : $@thick Self.Type):
+  init(d2: D) {
+    // CHECK:      [[SELF_BOX:%.*]] = alloc_box
+    // CHECK-NEXT: [[UNINIT_SELF:%.*]] = mark_uninitialized [delegatingself] [[SELF_BOX]]
+    // CHECK-NEXT: [[SELF_BOX_ADDR:%.*]] = project_box [[UNINIT_SELF]]
+    // CHECK:      [[SELF_BOX:%.*]] = alloc_stack $Self
+    // CHECK-NEXT: [[BORROWED_ARG:%.*]] = begin_borrow [[ARG]]
+    // CHECK-NEXT: [[ARG_COPY:%.*]] = copy_value [[BORROWED_ARG]]
+    // CHECK:      [[DELEGATEE:%.*]] = function_ref @$S19protocol_extensions15InitRequirementPAAE1dxAA1DC_tcfC
+    // CHECK-NEXT: apply [[DELEGATEE]]<Self>([[SELF_BOX]], [[ARG_COPY]], [[SELF_TYPE]])
+    // CHECK-NEXT: end_borrow [[BORROWED_ARG]] from [[ARG]]
+    // CHECK-NEXT: copy_addr [take] [[SELF_BOX]] to [[SELF_BOX_ADDR]]
+    // CHECK-NEXT: dealloc_stack [[SELF_BOX]]
+    // CHECK-NEXT: copy_addr [[SELF_BOX_ADDR]] to [initialization] [[OUT]]
+    // CHECK-NEXT: destroy_value [[ARG]]
+    // CHECK-NEXT: destroy_value [[UNINIT_SELF]]
+    // CHECK:      return
+    self.init(d: d2)
+  }
+
+  // CHECK-LABEL: sil hidden @$S19protocol_extensions15InitRequirementPAAE2c2xAA1CC_tcfC  : $@convention(method)
+  // CHECK:       bb0([[OUT:%.*]] : $*Self, [[ARG:%.*]] : $C, [[SELF_TYPE:%.*]] : $@thick Self.Type):
+  init(c2: C) {
+    // CHECK:      [[SELF_BOX:%.*]] = alloc_box
+    // CHECK-NEXT: [[UNINIT_SELF:%.*]] = mark_uninitialized [delegatingself] [[SELF_BOX]]
+    // CHECK-NEXT: [[SELF_BOX_ADDR:%.*]] = project_box [[UNINIT_SELF]]
+    // CHECK:      [[SELF_BOX:%.*]] = alloc_stack $Self
+    // CHECK-NEXT: [[SELF_TYPE:%.*]] = metatype $@thick Self.Type
+    // CHECK-NEXT: [[BORROWED_ARG:%.*]] = begin_borrow [[ARG]]
+    // CHECK-NEXT: [[ARG_COPY:%.*]] = copy_value [[BORROWED_ARG]]
+    // CHECK:      [[DELEGATEE:%.*]] = witness_method $Self, #InitRequirement.init!allocator.1
+    // CHECK-NEXT: apply [[DELEGATEE]]<Self>([[SELF_BOX]], [[ARG_COPY]], [[SELF_TYPE]])
+    // CHECK-NEXT: end_borrow [[BORROWED_ARG]] from [[ARG]]
+    // CHECK-NEXT: [[ACCESS:%.*]] = begin_access [modify] [unknown] [[SELF_BOX_ADDR]]
+    // CHECK-NEXT: copy_addr [take] [[SELF_BOX]] to [[ACCESS]]
+    // CHECK-NEXT: end_access [[ACCESS]]
+    // CHECK-NEXT: dealloc_stack [[SELF_BOX]]
+    // CHECK-NEXT: copy_addr [[SELF_BOX_ADDR]] to [initialization] [[OUT]]
+    // CHECK-NEXT: destroy_value [[ARG]]
+    // CHECK-NEXT: destroy_value [[UNINIT_SELF]]
+    // CHECK:      return
+    self = Self(c: c2)
+  }
+}
+
+protocol ClassInitRequirement: class {
+  init(c: C)
+}
+
+extension ClassInitRequirement {
+  // CHECK-LABEL: sil hidden @$S19protocol_extensions20ClassInitRequirementPAAE{{[_0-9a-zA-Z]*}}fC : $@convention(method) <Self where Self : ClassInitRequirement> (@owned D, @thick Self.Type) -> @owned Self
+  // CHECK:       bb0([[ARG:%.*]] : $D, [[SELF_TYPE:%.*]] : $@thick Self.Type):
+  // CHECK:         [[BORROWED_ARG:%.*]] = begin_borrow [[ARG]]
+  // CHECK:         [[ARG_COPY:%.*]] = copy_value [[BORROWED_ARG]]
+  // CHECK:         [[ARG_COPY_CAST:%.*]] = upcast [[ARG_COPY]]
+  // CHECK:         [[DELEGATEE:%.*]] = witness_method $Self, #ClassInitRequirement.init!allocator.1 : {{.*}} : $@convention(witness_method: ClassInitRequirement) <τ_0_0 where τ_0_0 : ClassInitRequirement> (@owned C, @thick τ_0_0.Type) -> @owned τ_0_0
+  // CHECK:         apply [[DELEGATEE]]<Self>([[ARG_COPY_CAST]], [[SELF_TYPE]])
+  // CHECK:         end_borrow [[BORROWED_ARG]] from [[ARG]]
+  
+  // CHECK: } // end sil function '$S19protocol_extensions20ClassInitRequirementPAAE{{[_0-9a-zA-Z]*}}fC'
+  init(d: D) {
+    self.init(c: d)
+  }
+}
+
+@objc class OC {}
+@objc class OD: OC {}
+
+@objc protocol ObjCInitRequirement {
+  init(c: OC, d: OC)
+}
+
+func foo(_ t: ObjCInitRequirement.Type, c: OC) -> ObjCInitRequirement {
+  return t.init(c: OC(), d: OC())
+}
+
+extension ObjCInitRequirement {
+  // CHECK-LABEL: sil hidden @$S19protocol_extensions19ObjCInitRequirementPAAE{{[_0-9a-zA-Z]*}}fC : $@convention(method) <Self where Self : ObjCInitRequirement> (@owned OD, @thick Self.Type) -> @owned Self
+  // CHECK:       bb0([[ARG:%.*]] : $OD, [[SELF_TYPE:%.*]] : $@thick Self.Type):
+  // CHECK:         [[OBJC_SELF_TYPE:%.*]] = thick_to_objc_metatype [[SELF_TYPE]]
+  // CHECK:         [[SELF:%.*]] = alloc_ref_dynamic [objc] [[OBJC_SELF_TYPE]] : $@objc_metatype Self.Type, $Self
+  // CHECK:         [[BORROWED_ARG_1:%.*]] = begin_borrow [[ARG]]
+  // CHECK:         [[BORROWED_ARG_1_UPCAST:%.*]] = upcast [[BORROWED_ARG_1]]
+  // CHECK:         [[BORROWED_ARG_2:%.*]] = begin_borrow [[ARG]]
+  // CHECK:         [[BORROWED_ARG_2_UPCAST:%.*]] = upcast [[BORROWED_ARG_2]]
+  // CHECK:         [[WITNESS:%.*]] = objc_method [[SELF]] : $Self, #ObjCInitRequirement.init!initializer.1.foreign : {{.*}}, $@convention(objc_method) <τ_0_0 where τ_0_0 : ObjCInitRequirement> (OC, OC, @owned τ_0_0) -> @owned τ_0_0
+  // CHECK:         apply [[WITNESS]]<Self>([[BORROWED_ARG_1_UPCAST]], [[BORROWED_ARG_2_UPCAST]], [[SELF]])
+  // CHECK:         end_borrow [[BORROWED_ARG_2]] from [[ARG]]
+  // CHECK:         end_borrow [[BORROWED_ARG_1]] from [[ARG]]
+  // CHECK: } // end sil function '$S19protocol_extensions19ObjCInitRequirementPAAE{{[_0-9a-zA-Z]*}}fC'
+  init(d: OD) {
+    self.init(c: d, d: d)
+  }
+}
+
+// rdar://problem/21370992 - delegation from an initializer in a
+// protocol extension to an @objc initializer in a class.
+class ObjCInitClass {
+  @objc required init() { }
+}
+
+protocol ProtoDelegatesToObjC { }
+
+extension ProtoDelegatesToObjC where Self : ObjCInitClass {
+  // CHECK-LABEL: sil hidden @$S19protocol_extensions20ProtoDelegatesToObjCPA2A0F10CInitClassC{{[_0-9a-zA-Z]*}}fC
+  // CHECK: bb0([[STR:%[0-9]+]] : $String, [[SELF_META:%[0-9]+]] : $@thick Self.Type):
+  init(string: String) {
+    // CHECK:   [[SELF_BOX:%[0-9]+]] = alloc_box $<τ_0_0 where τ_0_0 : ObjCInitClass, τ_0_0 : ProtoDelegatesToObjC> { var τ_0_0 } <Self>
+    // CHECK:   [[MARKED_SELF_BOX:%[0-9]+]] = mark_uninitialized [delegatingself] [[SELF_BOX]]
+    // CHECK:   [[PB_SELF_BOX:%.*]] = project_box [[MARKED_SELF_BOX]]
+    // CHECK:   [[SELF_META_OBJC:%[0-9]+]] = thick_to_objc_metatype [[SELF_META]] : $@thick Self.Type to $@objc_metatype Self.Type
+    // CHECK:   [[SELF_ALLOC:%[0-9]+]] = alloc_ref_dynamic [objc] [[SELF_META_OBJC]] : $@objc_metatype Self.Type, $Self
+    // CHECK:   [[SELF_ALLOC_C:%[0-9]+]] = upcast [[SELF_ALLOC]] : $Self to $ObjCInitClass
+    // CHECK:   [[OBJC_INIT:%[0-9]+]] = class_method [[SELF_ALLOC_C]] : $ObjCInitClass, #ObjCInitClass.init!initializer.1 : (ObjCInitClass.Type) -> () -> ObjCInitClass, $@convention(method) (@owned ObjCInitClass) -> @owned ObjCInitClass
+    // CHECK:   [[SELF_RESULT:%[0-9]+]] = apply [[OBJC_INIT]]([[SELF_ALLOC_C]]) : $@convention(method) (@owned ObjCInitClass) -> @owned ObjCInitClass
+    // CHECK:   [[SELF_RESULT_AS_SELF:%[0-9]+]] = unchecked_ref_cast [[SELF_RESULT]] : $ObjCInitClass to $Self
+    // CHECK:   assign [[SELF_RESULT_AS_SELF]] to [[PB_SELF_BOX]] : $*Self
+    self.init()
+  }
+}
+
+// Delegating from an initializer in a protocol extension where Self
+// has a superclass to a required initializer of that class.
+class RequiredInitClass {
+  required init() { }
+}
+
+protocol ProtoDelegatesToRequired { }
+
+extension ProtoDelegatesToRequired where Self : RequiredInitClass {
+  // CHECK-LABEL: sil hidden @$S19protocol_extensions24ProtoDelegatesToRequiredPA2A0F9InitClassC{{[_0-9a-zA-Z]*}}fC 
+  // CHECK: bb0([[STR:%[0-9]+]] : $String, [[SELF_META:%[0-9]+]] : $@thick Self.Type):
+  init(string: String) {
+  // CHECK:   [[SELF_BOX:%[0-9]+]] = alloc_box $<τ_0_0 where τ_0_0 : RequiredInitClass, τ_0_0 : ProtoDelegatesToRequired> { var τ_0_0 } <Self>
+  // CHECK:   [[MARKED_SELF_BOX:%[0-9]+]] = mark_uninitialized [delegatingself] [[SELF_BOX]]
+  // CHECK:   [[PB_SELF_BOX:%.*]] = project_box [[MARKED_SELF_BOX]]
+  // CHECK:   [[SELF_META_AS_CLASS_META:%[0-9]+]] = upcast [[SELF_META]] : $@thick Self.Type to $@thick RequiredInitClass.Type
+  // CHECK:   [[INIT:%[0-9]+]] = class_method [[SELF_META_AS_CLASS_META]] : $@thick RequiredInitClass.Type, #RequiredInitClass.init!allocator.1 : (RequiredInitClass.Type) -> () -> RequiredInitClass, $@convention(method) (@thick RequiredInitClass.Type) -> @owned RequiredInitClass
+  // CHECK:   [[SELF_RESULT:%[0-9]+]] = apply [[INIT]]([[SELF_META_AS_CLASS_META]]) : $@convention(method) (@thick RequiredInitClass.Type) -> @owned RequiredInitClass
+  // CHECK:   [[SELF_RESULT_AS_SELF:%[0-9]+]] = unchecked_ref_cast [[SELF_RESULT]] : $RequiredInitClass to $Self
+  // CHECK:   assign [[SELF_RESULT_AS_SELF]] to [[PB_SELF_BOX]] : $*Self
+    self.init()
+  }
+}
+
+// ----------------------------------------------------------------------------
+// Default implementations via protocol extensions
+// ----------------------------------------------------------------------------
+
+protocol P2 {
+  associatedtype A
+  func f1(_ a: A)
+  func f2(_ a: A)
+  var x: A { get }
+}
+
+extension P2 {
+  // CHECK-LABEL: sil hidden @$S19protocol_extensions2P2PAAE2f1{{[_0-9a-zA-Z]*}}F
+  // CHECK: witness_method $Self, #P2.f2!1
+  // CHECK: function_ref @$S19protocol_extensions2P2PAAE2f3{{[_0-9a-zA-Z]*}}F
+  // CHECK: return
+  func f1(_ a: A) {
+    f2(a)
+    f3(a)
+  }
+
+  // CHECK-LABEL: sil hidden @$S19protocol_extensions2P2PAAE2f2{{[_0-9a-zA-Z]*}}F
+  // CHECK: witness_method $Self, #P2.f1!1
+  // CHECK: function_ref @$S19protocol_extensions2P2PAAE2f3{{[_0-9a-zA-Z]*}}F
+  // CHECK: return
+  func f2(_ a: A) {
+    f1(a)
+    f3(a)
+  }
+
+  func f3(_ a: A) {}
+
+  // CHECK-LABEL: sil hidden @$S19protocol_extensions2P2PAAE2f4{{[_0-9a-zA-Z]*}}F
+  // CHECK: witness_method $Self, #P2.f1!1
+  // CHECK: witness_method $Self, #P2.f2!1
+  // CHECK: return
+  func f4() {
+    f1(x)
+    f2(x)
+  }
+}
diff --git a/test/SILGen/plus_zero_protocol_optional.swift b/test/SILGen/plus_zero_protocol_optional.swift
new file mode 100644
index 0000000..25e1dd6
--- /dev/null
+++ b/test/SILGen/plus_zero_protocol_optional.swift
@@ -0,0 +1,68 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -parse-as-library -emit-silgen -disable-objc-attr-requires-foundation-module -enable-sil-ownership %s | %FileCheck %s
+
+@objc protocol P1 {
+  @objc optional func method(_ x: Int)
+
+  @objc optional var prop: Int { get }
+
+  @objc optional subscript (i: Int) -> Int { get }
+}
+
+// CHECK-LABEL: sil hidden @$S17protocol_optional0B13MethodGeneric1tyx_tAA2P1RzlF : $@convention(thin) <T where T : P1> (@guaranteed T) -> ()
+func optionalMethodGeneric<T : P1>(t t : T) {
+  var t = t
+  // CHECK: bb0([[T:%[0-9]+]] : @guaranteed $T):
+  // CHECK:   [[TBOX:%[0-9]+]] = alloc_box $<τ_0_0 where τ_0_0 : P1> { var τ_0_0 } <T>
+  // CHECK:   [[PT:%[0-9]+]] = project_box [[TBOX]]
+  // CHECK:   [[T_COPY:%.*]] = copy_value [[T]]
+  // CHECK:   store [[T_COPY]] to [init] [[PT]] : $*T
+  // CHECK:   [[OPT_BOX:%[0-9]+]] = alloc_box ${ var Optional<@callee_guaranteed (Int) -> ()> }
+  // CHECK:   project_box [[OPT_BOX]]
+  // CHECK:   [[READ:%.*]] = begin_access [read] [unknown] [[PT]] : $*T
+  // CHECK:   [[T:%[0-9]+]] = load [copy] [[READ]] : $*T
+  // CHECK:   alloc_stack $Optional<@callee_guaranteed (Int) -> ()>
+  // CHECK:   dynamic_method_br [[T]] : $T, #P1.method!1.foreign
+  var methodRef = t.method
+}
+// CHECK: } // end sil function '$S17protocol_optional0B13MethodGeneric1tyx_tAA2P1RzlF'
+
+// CHECK-LABEL: sil hidden @$S17protocol_optional0B15PropertyGeneric{{[_0-9a-zA-Z]*}}F : $@convention(thin) <T where T : P1> (@guaranteed T) -> ()
+func optionalPropertyGeneric<T : P1>(t t : T) {
+  var t = t
+  // CHECK: bb0([[T:%[0-9]+]] : @guaranteed $T):
+  // CHECK:   [[TBOX:%[0-9]+]] = alloc_box $<τ_0_0 where τ_0_0 : P1> { var τ_0_0 } <T>
+  // CHECK:   [[PT:%[0-9]+]] = project_box [[TBOX]]
+  // CHECK:   [[T_COPY:%.*]] = copy_value [[T]]
+  // CHECK:   store [[T_COPY]] to [init] [[PT]] : $*T
+  // CHECK:   [[OPT_BOX:%[0-9]+]] = alloc_box ${ var Optional<Int> }
+  // CHECK:   project_box [[OPT_BOX]]
+  // CHECK:   [[READ:%.*]] = begin_access [read] [unknown] [[PT]] : $*T
+  // CHECK:   [[T:%[0-9]+]] = load [copy] [[READ]] : $*T
+  // CHECK:   alloc_stack $Optional<Int>
+  // CHECK:   dynamic_method_br [[T]] : $T, #P1.prop!getter.1.foreign
+  var propertyRef = t.prop
+}
+// CHECK: } // end sil function '$S17protocol_optional0B15PropertyGeneric{{[_0-9a-zA-Z]*}}F'
+
+// CHECK-LABEL: sil hidden @$S17protocol_optional0B16SubscriptGeneric{{[_0-9a-zA-Z]*}}F : $@convention(thin) <T where T : P1> (@guaranteed T) -> ()
+func optionalSubscriptGeneric<T : P1>(t t : T) {
+  var t = t
+  // CHECK: bb0([[T:%[0-9]+]] : @guaranteed $T):
+  // CHECK:   [[TBOX:%[0-9]+]] = alloc_box $<τ_0_0 where τ_0_0 : P1> { var τ_0_0 } <T>
+  // CHECK:   [[PT:%[0-9]+]] = project_box [[TBOX]]
+  // CHECK:   [[T_COPY:%.*]] = copy_value [[T]]
+  // CHECK:   store [[T_COPY]] to [init] [[PT]] : $*T
+  // CHECK:   [[OPT_BOX:%[0-9]+]] = alloc_box ${ var Optional<Int> }
+  // CHECK:   project_box [[OPT_BOX]]
+  // CHECK:   [[READ:%.*]] = begin_access [read] [unknown] [[PT]] : $*T
+  // CHECK:   [[T:%[0-9]+]] = load [copy] [[READ]] : $*T
+  // CHECK:   [[INT64:%[0-9]+]] = metatype $@thin Int.Type
+  // CHECK:   [[FIVELIT:%[0-9]+]] = integer_literal $Builtin.Int2048, 5
+  // CHECK:   [[INTCONV:%[0-9]+]] = function_ref @$SSi2{{[_0-9a-zA-Z]*}}fC
+  // CHECK:   [[FIVE:%[0-9]+]] = apply [[INTCONV]]([[FIVELIT]], [[INT64]]) : $@convention(method) (Builtin.Int2048, @thin Int.Type) -> Int
+  // CHECK:   alloc_stack $Optional<Int>
+  // CHECK:   dynamic_method_br [[T]] : $T, #P1.subscript!getter.1.foreign
+  var subscriptRef = t[5]
+}
+// CHECK: } // end sil function '$S17protocol_optional0B16SubscriptGeneric{{[_0-9a-zA-Z]*}}F'
diff --git a/test/SILGen/plus_zero_protocol_resilience.swift b/test/SILGen/plus_zero_protocol_resilience.swift
new file mode 100644
index 0000000..df24b0f
--- /dev/null
+++ b/test/SILGen/plus_zero_protocol_resilience.swift
@@ -0,0 +1,318 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %empty-directory(%t)
+// RUN: %target-swift-frontend -emit-module -enable-sil-ownership -enable-resilience -emit-module-path=%t/resilient_protocol.swiftmodule -module-name=resilient_protocol %S/../Inputs/resilient_protocol.swift
+// RUN: %target-swift-frontend -I %t -emit-silgen -enable-sil-ownership -enable-resilience %s | %FileCheck %s
+
+import resilient_protocol
+
+prefix operator ~~~ {}
+infix operator <*> {}
+infix operator <**> {}
+infix operator <===> {}
+
+public protocol P {}
+
+
+// Protocol is public -- needs resilient witness table
+public protocol ResilientMethods {
+  associatedtype AssocType : P
+
+  func defaultWitness()
+  func anotherDefaultWitness(_ x: Int) -> Self
+  func defaultWitnessWithAssociatedType(_ a: AssocType)
+  func defaultWitnessMoreAbstractThanRequirement(_ a: AssocType, b: Int)
+  func defaultWitnessMoreAbstractThanGenericRequirement<T>(_ a: AssocType, t: T)
+
+  func noDefaultWitness()
+  func defaultWitnessIsNotPublic()
+
+  static func staticDefaultWitness(_ x: Int) -> Self
+}
+
+extension ResilientMethods {
+
+// CHECK-LABEL: sil private [transparent] [thunk] @$S19protocol_resilience16ResilientMethodsP14defaultWitnessyyF
+// CHECK-LABEL: sil @$S19protocol_resilience16ResilientMethodsPAAE14defaultWitnessyyF
+  public func defaultWitness() {}
+
+// CHECK-LABEL: sil private [transparent] [thunk] @$S19protocol_resilience16ResilientMethodsP21anotherDefaultWitnessyxSiF
+// CHECK-LABEL: sil @$S19protocol_resilience16ResilientMethodsPAAE21anotherDefaultWitnessyxSiF
+  public func anotherDefaultWitness(_ x: Int) -> Self {}
+
+// CHECK-LABEL: sil private [transparent] [thunk] @$S19protocol_resilience16ResilientMethodsP32defaultWitnessWithAssociatedTypeyy05AssocI0QzF
+// CHECK-LABEL: sil @$S19protocol_resilience16ResilientMethodsPAAE32defaultWitnessWithAssociatedTypeyy05AssocI0QzF
+  public func defaultWitnessWithAssociatedType(_ a: AssocType) {}
+
+// CHECK-LABEL: sil private [transparent] [thunk] @$S19protocol_resilience16ResilientMethodsP41defaultWitnessMoreAbstractThanRequirement_1by9AssocTypeQz_SitF
+// CHECK-LABEL: sil @$S19protocol_resilience16ResilientMethodsPAAE41defaultWitnessMoreAbstractThanRequirement_1byqd___qd_0_tr0_lF
+  public func defaultWitnessMoreAbstractThanRequirement<A, T>(_ a: A, b: T) {}
+
+// CHECK-LABEL: sil private [transparent] [thunk] @$S19protocol_resilience16ResilientMethodsP48defaultWitnessMoreAbstractThanGenericRequirement_1ty9AssocTypeQz_qd__tlF
+// CHECK-LABEL: sil @$S19protocol_resilience16ResilientMethodsPAAE48defaultWitnessMoreAbstractThanGenericRequirement_1tyqd___qd_0_tr0_lF
+  public func defaultWitnessMoreAbstractThanGenericRequirement<A, T>(_ a: A, t: T) {}
+
+// CHECK-LABEL: sil private [transparent] [thunk] @$S19protocol_resilience16ResilientMethodsP20staticDefaultWitnessyxSiFZ
+// CHECK-LABEL: sil @$S19protocol_resilience16ResilientMethodsPAAE20staticDefaultWitnessyxSiFZ
+  public static func staticDefaultWitness(_ x: Int) -> Self {}
+
+// CHECK-LABEL: sil private @$S19protocol_resilience16ResilientMethodsPAAE25defaultWitnessIsNotPublic{{.*}}F
+  private func defaultWitnessIsNotPublic() {}
+
+}
+
+
+public protocol ResilientConstructors {
+  init(noDefault: ())
+  init(default: ())
+  init?(defaultIsOptional: ())
+  init?(defaultNotOptional: ())
+  init(optionalityMismatch: ())
+}
+
+extension ResilientConstructors {
+
+// CHECK-LABEL: sil private [transparent] [thunk] @$S19protocol_resilience21ResilientConstructorsP7defaultxyt_tcfC
+// CHECK-LABEL: sil @$S19protocol_resilience21ResilientConstructorsPAAE7defaultxyt_tcfC
+  public init(default: ()) {
+    self.init(noDefault: ())
+  }
+
+// CHECK-LABEL: sil private [transparent] [thunk] @$S19protocol_resilience21ResilientConstructorsP17defaultIsOptionalxSgyt_tcfC
+// CHECK-LABEL: sil @$S19protocol_resilience21ResilientConstructorsPAAE17defaultIsOptionalxSgyt_tcfC
+  public init?(defaultIsOptional: ()) {
+    self.init(noDefault: ())
+  }
+
+// CHECK-LABEL: sil @$S19protocol_resilience21ResilientConstructorsPAAE20defaultIsNotOptionalxyt_tcfC
+  public init(defaultIsNotOptional: ()) {
+    self.init(noDefault: ())
+  }
+
+// CHECK-LABEL: sil @$S19protocol_resilience21ResilientConstructorsPAAE19optionalityMismatchxSgyt_tcfC
+  public init?(optionalityMismatch: ()) {
+    self.init(noDefault: ())
+  }
+}
+
+
+public protocol ResilientStorage {
+  associatedtype T : ResilientConstructors
+
+  var propertyWithDefault: Int { get }
+  var propertyWithNoDefault: Int { get }
+  var mutablePropertyWithDefault: Int { get set }
+  var mutablePropertyNoDefault: Int { get set }
+  var mutableGenericPropertyWithDefault: T { get set }
+
+  subscript(x: T) -> T { get set }
+
+  var mutatingGetterWithNonMutatingDefault: Int { mutating get set }
+}
+
+extension ResilientStorage {
+
+// CHECK-LABEL: sil private [transparent] [thunk] @$S19protocol_resilience16ResilientStorageP19propertyWithDefaultSivg
+// CHECK-LABEL: sil @$S19protocol_resilience16ResilientStoragePAAE19propertyWithDefaultSivg
+  public var propertyWithDefault: Int {
+    get { return 0 }
+  }
+
+// CHECK-LABEL: sil private [transparent] [thunk] @$S19protocol_resilience16ResilientStorageP26mutablePropertyWithDefaultSivg
+// CHECK-LABEL: sil @$S19protocol_resilience16ResilientStoragePAAE26mutablePropertyWithDefaultSivg
+// CHECK-LABEL: sil private [transparent] [thunk] @$S19protocol_resilience16ResilientStorageP26mutablePropertyWithDefaultSivs
+// CHECK-LABEL: sil @$S19protocol_resilience16ResilientStoragePAAE26mutablePropertyWithDefaultSivs
+// CHECK-LABEL: sil private [transparent] @$S19protocol_resilience16ResilientStorageP26mutablePropertyWithDefaultSivmytfU_
+// CHECK-LABEL: sil private [transparent] [thunk] @$S19protocol_resilience16ResilientStorageP26mutablePropertyWithDefaultSivm
+  public var mutablePropertyWithDefault: Int {
+    get { return 0 }
+    set { }
+  }
+
+  public private(set) var mutablePropertyNoDefault: Int {
+    get { return 0 }
+    set { }
+  }
+
+// CHECK-LABEL: sil private [transparent] [thunk] @$S19protocol_resilience16ResilientStorageP33mutableGenericPropertyWithDefault1TQzvg
+// CHECK-LABEL: sil @$S19protocol_resilience16ResilientStoragePAAE33mutableGenericPropertyWithDefault1TQzvg
+// CHECK-LABEL: sil private [transparent] [thunk] @$S19protocol_resilience16ResilientStorageP33mutableGenericPropertyWithDefault1TQzvs
+// CHECK-LABEL: sil @$S19protocol_resilience16ResilientStoragePAAE33mutableGenericPropertyWithDefault1TQzvs
+// CHECK-LABEL: sil private [transparent] @$S19protocol_resilience16ResilientStorageP33mutableGenericPropertyWithDefault1TQzvmytfU_
+// CHECK-LABEL: sil private [transparent] [thunk] @$S19protocol_resilience16ResilientStorageP33mutableGenericPropertyWithDefault1TQzvm
+  public var mutableGenericPropertyWithDefault: T {
+    get {
+      return T(default: ())
+    }
+    set { }
+  }
+
+// CHECK-LABEL: sil private [transparent] [thunk] @$S19protocol_resilience16ResilientStoragePy1TQzAEcig
+// CHECK-LABEL: sil @$S19protocol_resilience16ResilientStoragePAAEy1TQzAEcig
+// CHECK-LABEL: sil private [transparent] [thunk] @$S19protocol_resilience16ResilientStoragePy1TQzAEcis
+// CHECK-LABEL: sil @$S19protocol_resilience16ResilientStoragePAAEy1TQzAEcis
+// CHECK-LABEL: sil private [transparent] @$S19protocol_resilience16ResilientStoragePy1TQzAEcimytfU_
+// CHECK-LABEL: sil private [transparent] [thunk] @$S19protocol_resilience16ResilientStoragePy1TQzAEcim
+  public subscript(x: T) -> T {
+    get {
+      return x
+    }
+    set { }
+  }
+
+// CHECK-LABEL: sil private [transparent] [thunk] @$S19protocol_resilience16ResilientStorageP36mutatingGetterWithNonMutatingDefaultSivg
+// CHECK-LABEL: sil @$S19protocol_resilience16ResilientStoragePAAE36mutatingGetterWithNonMutatingDefaultSivg
+// CHECK-LABEL: sil private [transparent] [thunk] @$S19protocol_resilience16ResilientStorageP36mutatingGetterWithNonMutatingDefaultSivs
+// CHECK-LABEL: sil @$S19protocol_resilience16ResilientStoragePAAE36mutatingGetterWithNonMutatingDefaultSivs
+// CHECK-LABEL: sil private [transparent] @$S19protocol_resilience16ResilientStorageP36mutatingGetterWithNonMutatingDefaultSivmytfU_
+// CHECK-LABEL: sil private [transparent] [thunk] @$S19protocol_resilience16ResilientStorageP36mutatingGetterWithNonMutatingDefaultSivm
+  public var mutatingGetterWithNonMutatingDefault: Int {
+    get {
+      return 0
+    }
+    set { }
+  }
+}
+
+
+public protocol ResilientOperators {
+  associatedtype AssocType : P
+
+  static prefix func ~~~(s: Self)
+  static func <*><T>(s: Self, t: T)
+  static func <**><T>(t: T, s: Self) -> AssocType
+  static func <===><T : ResilientOperators>(t: T, s: Self) -> T.AssocType
+}
+
+// CHECK-LABEL: sil private [transparent] [thunk] @$S19protocol_resilience18ResilientOperatorsP3tttopyyxFZ
+// CHECK-LABEL: sil @$S19protocol_resilience3tttopyyxlF
+public prefix func ~~~<S>(s: S) {}
+
+// CHECK-LABEL: sil private [transparent] [thunk] @$S19protocol_resilience18ResilientOperatorsP3lmgoiyyx_qd__tlFZ
+// CHECK-LABEL: sil @$S19protocol_resilience3lmgoiyyq__xtr0_lF
+public func <*><T, S>(s: S, t: T) {}
+
+// Swap the generic parameters to make sure we don't mix up our DeclContexts
+// when mapping interface types in and out
+
+// CHECK-LABEL: sil private [transparent] [thunk] @$S19protocol_resilience18ResilientOperatorsP4lmmgoiy9AssocTypeQzqd___xtlFZ
+// CHECK-LABEL: sil @$S19protocol_resilience4lmmgoiy9AssocTypeQzq__xtAA18ResilientOperatorsRzr0_lF
+public func <**><S : ResilientOperators, T>(t: T, s: S) -> S.AssocType {}
+
+// CHECK-LABEL: sil private [transparent] [thunk] @$S19protocol_resilience18ResilientOperatorsP5leeegoiy9AssocTypeQyd__qd___xtAaBRd__lFZ
+// CHECK-LABEL: sil @$S19protocol_resilience5leeegoiy9AssocTypeQzx_q_tAA18ResilientOperatorsRzAaER_r0_lF
+public func <===><T : ResilientOperators, S : ResilientOperators>(t: T, s: S) -> T.AssocType {}
+
+
+public protocol ReabstractSelfBase {
+  // No requirements
+}
+
+public protocol ReabstractSelfRefined : class, ReabstractSelfBase {
+  // A requirement with 'Self' abstracted as a class instance
+  var callback: (Self) -> Self { get set }
+}
+
+func id<T>(_ t: T) -> T {}
+
+extension ReabstractSelfBase {
+  // A witness for the above requirement, but with 'Self' maximally abstracted
+  public var callback: (Self) -> Self {
+    get { return id }
+    nonmutating set { }
+  }
+}
+
+// CHECK-LABEL: sil private [transparent] [thunk] @$S19protocol_resilience21ReabstractSelfRefinedP8callbackyxxcvg : $@convention(witness_method: ReabstractSelfRefined) <τ_0_0 where τ_0_0 : ReabstractSelfRefined> (@guaranteed τ_0_0) -> @owned @callee_guaranteed (@guaranteed τ_0_0) -> @owned τ_0_0
+// CHECK: [[SELF_BOX:%.*]] = alloc_stack $τ_0_0
+// CHECK-NEXT: [[SELF_COPY:%.*]] = copy_value %0 : $τ_0_0
+// CHECK-NEXT: store [[SELF_COPY]] to [init] [[SELF_BOX]] : $*τ_0_0
+// CHECK: [[WITNESS:%.*]] = function_ref @$S19protocol_resilience18ReabstractSelfBasePAAE8callbackyxxcvg
+// CHECK-NEXT: [[RESULT:%.*]] = apply [[WITNESS]]<τ_0_0>([[SELF_BOX]])
+// CHECK: [[THUNK_FN:%.*]] = function_ref @$SxxIegnr_xxIeggo_19protocol_resilience21ReabstractSelfRefinedRzlTR
+// CHECK-NEXT: [[THUNK:%.*]] = partial_apply [callee_guaranteed] [[THUNK_FN]]<τ_0_0>([[RESULT]])
+// CHECK-NEXT: destroy_addr [[SELF_BOX]]
+// CHECK-NEXT: dealloc_stack [[SELF_BOX]]
+// CHECK-NEXT: return [[THUNK]]
+
+final class X : ReabstractSelfRefined {}
+
+func inoutFunc(_ x: inout Int) {}
+
+// CHECK-LABEL: sil hidden @$S19protocol_resilience22inoutResilientProtocolyy010resilient_A005OtherdE0_pzF
+func inoutResilientProtocol(_ x: inout OtherResilientProtocol) {
+  // CHECK: function_ref @$S18resilient_protocol22OtherResilientProtocolPAAE19propertyInExtensionSivm
+  inoutFunc(&x.propertyInExtension)
+}
+
+struct OtherConformingType : OtherResilientProtocol {}
+
+// CHECK-LABEL: sil hidden @$S19protocol_resilience22inoutResilientProtocolyyAA19OtherConformingTypeVzF
+func inoutResilientProtocol(_ x: inout OtherConformingType) {
+  // CHECK: function_ref @$S18resilient_protocol22OtherResilientProtocolPAAE19propertyInExtensionSivm
+  inoutFunc(&x.propertyInExtension)
+
+  // CHECK: function_ref @$S18resilient_protocol22OtherResilientProtocolPAAE25staticPropertyInExtensionSivmZ
+  inoutFunc(&OtherConformingType.staticPropertyInExtension)
+}
+
+// CHECK-LABEL: sil_default_witness_table P {
+// CHECK-NEXT: }
+
+// CHECK-LABEL: sil_default_witness_table ResilientMethods {
+// CHECK-NEXT:    no_default
+// CHECK-NEXT:    no_default
+// CHECK-NEXT:    method #ResilientMethods.defaultWitness!1: {{.*}} : @$S19protocol_resilience16ResilientMethodsP14defaultWitnessyyF
+// CHECK-NEXT:    method #ResilientMethods.anotherDefaultWitness!1: {{.*}} : @$S19protocol_resilience16ResilientMethodsP21anotherDefaultWitnessyxSiF
+// CHECK-NEXT:    method #ResilientMethods.defaultWitnessWithAssociatedType!1: {{.*}} : @$S19protocol_resilience16ResilientMethodsP32defaultWitnessWithAssociatedTypeyy05AssocI0QzF
+// CHECK-NEXT:    method #ResilientMethods.defaultWitnessMoreAbstractThanRequirement!1: {{.*}} : @$S19protocol_resilience16ResilientMethodsP41defaultWitnessMoreAbstractThanRequirement_1by9AssocTypeQz_SitF
+// CHECK-NEXT:    method #ResilientMethods.defaultWitnessMoreAbstractThanGenericRequirement!1: {{.*}} : @$S19protocol_resilience16ResilientMethodsP48defaultWitnessMoreAbstractThanGenericRequirement_1ty9AssocTypeQz_qd__tlF
+// CHECK-NEXT:    no_default
+// CHECK-NEXT:    no_default
+// CHECK-NEXT:    method #ResilientMethods.staticDefaultWitness!1: {{.*}} : @$S19protocol_resilience16ResilientMethodsP20staticDefaultWitnessyxSiFZ
+// CHECK-NEXT: }
+
+// CHECK-LABEL: sil_default_witness_table ResilientConstructors {
+// CHECK-NEXT:    no_default
+// CHECK-NEXT:    method #ResilientConstructors.init!allocator.1: {{.*}} : @$S19protocol_resilience21ResilientConstructorsP7defaultxyt_tcfC
+// CHECK-NEXT:    method #ResilientConstructors.init!allocator.1: {{.*}} : @$S19protocol_resilience21ResilientConstructorsP17defaultIsOptionalxSgyt_tcfC
+// CHECK-NEXT:    no_default
+// CHECK-NEXT:    no_default
+// CHECK-NEXT: }
+
+// CHECK-LABEL: sil_default_witness_table ResilientStorage {
+// CHECK-NEXT:   no_default
+// CHECK-NEXT:   no_default
+// CHECK-NEXT:   method #ResilientStorage.propertyWithDefault!getter.1: {{.*}} : @$S19protocol_resilience16ResilientStorageP19propertyWithDefaultSivg
+// CHECK-NEXT:   no_default
+// CHECK-NEXT:   method #ResilientStorage.mutablePropertyWithDefault!getter.1: {{.*}} : @$S19protocol_resilience16ResilientStorageP26mutablePropertyWithDefaultSivg
+// CHECK-NEXT:   method #ResilientStorage.mutablePropertyWithDefault!setter.1: {{.*}} : @$S19protocol_resilience16ResilientStorageP26mutablePropertyWithDefaultSivs
+// CHECK-NEXT:   method #ResilientStorage.mutablePropertyWithDefault!materializeForSet.1: {{.*}} : @$S19protocol_resilience16ResilientStorageP26mutablePropertyWithDefaultSivm
+// CHECK-NEXT:   no_default
+// CHECK-NEXT:   no_default
+// CHECK-NEXT:   no_default
+// CHECK-NEXT:   method #ResilientStorage.mutableGenericPropertyWithDefault!getter.1: {{.*}} : @$S19protocol_resilience16ResilientStorageP33mutableGenericPropertyWithDefault1TQzvg
+// CHECK-NEXT:   method #ResilientStorage.mutableGenericPropertyWithDefault!setter.1: {{.*}} : @$S19protocol_resilience16ResilientStorageP33mutableGenericPropertyWithDefault1TQzvs
+// CHECK-NEXT:   method #ResilientStorage.mutableGenericPropertyWithDefault!materializeForSet.1: {{.*}} : @$S19protocol_resilience16ResilientStorageP33mutableGenericPropertyWithDefault1TQzvm
+// CHECK-NEXT:   method #ResilientStorage.subscript!getter.1: {{.*}} : @$S19protocol_resilience16ResilientStoragePy1TQzAEcig
+// CHECK-NEXT:   method #ResilientStorage.subscript!setter.1: {{.*}} : @$S19protocol_resilience16ResilientStoragePy1TQzAEcis
+// CHECK-NEXT:   method #ResilientStorage.subscript!materializeForSet.1: {{.*}} : @$S19protocol_resilience16ResilientStoragePy1TQzAEcim
+// CHECK-NEXT:   method #ResilientStorage.mutatingGetterWithNonMutatingDefault!getter.1: {{.*}} : @$S19protocol_resilience16ResilientStorageP36mutatingGetterWithNonMutatingDefaultSivg
+// CHECK-NEXT:   method #ResilientStorage.mutatingGetterWithNonMutatingDefault!setter.1: {{.*}} : @$S19protocol_resilience16ResilientStorageP36mutatingGetterWithNonMutatingDefaultSivs
+// CHECK-NEXT:   method #ResilientStorage.mutatingGetterWithNonMutatingDefault!materializeForSet.1: {{.*}} : @$S19protocol_resilience16ResilientStorageP36mutatingGetterWithNonMutatingDefaultSivm
+// CHECK-NEXT: }
+
+// CHECK-LABEL: sil_default_witness_table ResilientOperators {
+// CHECK-NEXT:    no_default
+// CHECK-NEXT:    no_default
+// CHECK-NEXT:    method #ResilientOperators."~~~"!1: {{.*}} : @$S19protocol_resilience18ResilientOperatorsP3tttopyyxFZ
+// CHECK-NEXT:    method #ResilientOperators."<*>"!1: {{.*}} : @$S19protocol_resilience18ResilientOperatorsP3lmgoiyyx_qd__tlFZ
+// CHECK-NEXT:    method #ResilientOperators."<**>"!1: {{.*}} : @$S19protocol_resilience18ResilientOperatorsP4lmmgoiy9AssocTypeQzqd___xtlFZ
+// CHECK-NEXT:    method #ResilientOperators."<===>"!1: {{.*}} : @$S19protocol_resilience18ResilientOperatorsP5leeegoiy9AssocTypeQyd__qd___xtAaBRd__lFZ
+// CHECK-NEXT: }
+
+// CHECK-LABEL: sil_default_witness_table ReabstractSelfRefined {
+// CHECK-NEXT:   no_default
+// CHECK-NEXT:   method #ReabstractSelfRefined.callback!getter.1: {{.*}} : @$S19protocol_resilience21ReabstractSelfRefinedP8callbackyxxcvg
+// CHECK-NEXT:   method #ReabstractSelfRefined.callback!setter.1: {{.*}} : @$S19protocol_resilience21ReabstractSelfRefinedP8callbackyxxcvs
+// CHECK-NEXT:   method #ReabstractSelfRefined.callback!materializeForSet.1: {{.*}} : @$S19protocol_resilience21ReabstractSelfRefinedP8callbackyxxcvm
+// CHECK-NEXT: }
diff --git a/test/SILGen/plus_zero_protocols.swift b/test/SILGen/plus_zero_protocols.swift
new file mode 100644
index 0000000..20cb940
--- /dev/null
+++ b/test/SILGen/plus_zero_protocols.swift
@@ -0,0 +1,472 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership %s | %FileCheck %s
+
+//===----------------------------------------------------------------------===//
+// Calling Existential Subscripts
+//===----------------------------------------------------------------------===//
+
+protocol SubscriptableGet {
+  subscript(a : Int) -> Int { get }
+}
+
+protocol SubscriptableGetSet {
+  subscript(a : Int) -> Int { get set }
+}
+
+var subscriptableGet : SubscriptableGet
+var subscriptableGetSet : SubscriptableGetSet
+
+func use_subscript_rvalue_get(_ i : Int) -> Int {
+  return subscriptableGet[i]
+}
+
+// CHECK-LABEL: sil hidden @{{.*}}use_subscript_rvalue_get
+// CHECK: bb0(%0 : @trivial $Int):
+// CHECK: [[GLOB:%[0-9]+]] = global_addr @$S9protocols16subscriptableGetAA013SubscriptableC0_pvp : $*SubscriptableGet
+// CHECK: [[READ:%.*]] = begin_access [read] [dynamic] [[GLOB]] : $*SubscriptableGet
+// CHECK: [[PROJ:%[0-9]+]] = open_existential_addr immutable_access [[READ]] : $*SubscriptableGet to $*[[OPENED:@opened(.*) SubscriptableGet]]
+// CHECK: [[ALLOCSTACK:%[0-9]+]] = alloc_stack $[[OPENED]]
+// CHECK: copy_addr [[PROJ]] to [initialization] [[ALLOCSTACK]] : $*[[OPENED]]
+// CHECK-NEXT: [[METH:%[0-9]+]] = witness_method $[[OPENED]], #SubscriptableGet.subscript!getter.1
+// CHECK-NEXT: [[RESULT:%[0-9]+]] = apply [[METH]]<[[OPENED]]>(%0, [[ALLOCSTACK]])
+// CHECK-NEXT: destroy_addr [[ALLOCSTACK]]
+// CHECK-NEXT: end_access [[READ]] : $*SubscriptableGet
+// CHECK-NEXT: dealloc_stack [[ALLOCSTACK]] : $*[[OPENED]]
+// CHECK-NEXT: return [[RESULT]]
+
+func use_subscript_lvalue_get(_ i : Int) -> Int {
+  return subscriptableGetSet[i]
+}
+
+// CHECK-LABEL: sil hidden @{{.*}}use_subscript_lvalue_get
+// CHECK: bb0(%0 : @trivial $Int):
+// CHECK: [[GLOB:%[0-9]+]] = global_addr @$S9protocols19subscriptableGetSetAA013SubscriptablecD0_pvp : $*SubscriptableGetSet
+// CHECK: [[READ:%.*]] = begin_access [read] [dynamic] [[GLOB]] : $*SubscriptableGetSet
+// CHECK: [[PROJ:%[0-9]+]] = open_existential_addr immutable_access [[READ]] : $*SubscriptableGetSet to $*[[OPENED:@opened(.*) SubscriptableGetSet]]
+// CHECK: [[ALLOCSTACK:%[0-9]+]] = alloc_stack $[[OPENED]]
+// CHECK: copy_addr [[PROJ]] to [initialization] [[ALLOCSTACK]] : $*[[OPENED]]
+// CHECK-NEXT: [[METH:%[0-9]+]] = witness_method $[[OPENED]], #SubscriptableGetSet.subscript!getter.1
+// CHECK-NEXT: [[RESULT:%[0-9]+]] = apply [[METH]]<[[OPENED]]>(%0, [[ALLOCSTACK]])
+// CHECK-NEXT: destroy_addr [[ALLOCSTACK]] : $*[[OPENED]]
+// CHECK-NEXT: end_access [[READ]] : $*SubscriptableGetSet
+// CHECK-NEXT: dealloc_stack [[ALLOCSTACK]] : $*[[OPENED]]
+// CHECK-NEXT: return [[RESULT]]
+
+func use_subscript_lvalue_set(_ i : Int) {
+  subscriptableGetSet[i] = i
+}
+
+// CHECK-LABEL: sil hidden @{{.*}}use_subscript_lvalue_set
+// CHECK: bb0(%0 : @trivial $Int):
+// CHECK: [[GLOB:%[0-9]+]] = global_addr @$S9protocols19subscriptableGetSetAA013SubscriptablecD0_pvp : $*SubscriptableGetSet
+// CHECK: [[READ:%.*]] = begin_access [modify] [dynamic] [[GLOB]] : $*SubscriptableGetSet
+// CHECK: [[PROJ:%[0-9]+]] = open_existential_addr mutable_access [[READ]] : $*SubscriptableGetSet to $*[[OPENED:@opened(.*) SubscriptableGetSet]]
+// CHECK-NEXT: [[METH:%[0-9]+]] = witness_method $[[OPENED]], #SubscriptableGetSet.subscript!setter.1
+// CHECK-NEXT: apply [[METH]]<[[OPENED]]>(%0, %0, [[PROJ]])
+
+
+//===----------------------------------------------------------------------===//
+// Calling Archetype Subscripts
+//===----------------------------------------------------------------------===//
+
+func use_subscript_archetype_rvalue_get<T : SubscriptableGet>(_ generic : T, idx : Int) -> Int {
+  return generic[idx]
+}
+// CHECK-LABEL: sil hidden @{{.*}}use_subscript_archetype_rvalue_get
+// CHECK: bb0(%0 : @trivial $*T, %1 : @trivial $Int):
+// CHECK: [[STACK:%[0-9]+]] = alloc_stack $T
+// CHECK: copy_addr %0 to [initialization] [[STACK]]
+// CHECK: [[METH:%[0-9]+]] = witness_method $T, #SubscriptableGet.subscript!getter.1
+// CHECK-NEXT: apply [[METH]]<T>(%1, [[STACK]])
+// CHECK-NEXT: destroy_addr [[STACK]] : $*T
+// CHECK-NEXT: dealloc_stack [[STACK]] : $*T
+// CHECK: } // end sil function '${{.*}}use_subscript_archetype_rvalue_get
+
+
+func use_subscript_archetype_lvalue_get<T : SubscriptableGetSet>(_ generic: inout T, idx : Int) -> Int {
+  return generic[idx]
+}
+// CHECK-LABEL: sil hidden @{{.*}}use_subscript_archetype_lvalue_get
+// CHECK: bb0(%0 : @trivial $*T, %1 : @trivial $Int):
+// CHECK: [[READ:%.*]] = begin_access [read] [unknown] %0 : $*T
+// CHECK: [[GUARANTEEDSTACK:%[0-9]+]] = alloc_stack $T
+// CHECK: copy_addr [[READ]] to [initialization] [[GUARANTEEDSTACK]] : $*T
+// CHECK: [[METH:%[0-9]+]] = witness_method $T, #SubscriptableGetSet.subscript!getter.1
+// CHECK-NEXT: [[APPLYRESULT:%[0-9]+]] = apply [[METH]]<T>(%1, [[GUARANTEEDSTACK]])
+// CHECK-NEXT: destroy_addr [[GUARANTEEDSTACK]] : $*T
+// CHECK-NEXT: end_access [[READ]]
+// CHECK-NEXT: dealloc_stack [[GUARANTEEDSTACK]] : $*T
+// CHECK: return [[APPLYRESULT]]
+
+
+func use_subscript_archetype_lvalue_set<T : SubscriptableGetSet>(_ generic: inout T, idx : Int) {
+  generic[idx] = idx
+}
+// CHECK-LABEL: sil hidden @{{.*}}use_subscript_archetype_lvalue_set
+// CHECK: bb0(%0 : @trivial $*T, %1 : @trivial $Int):
+// CHECK: [[WRITE:%.*]] = begin_access [modify] [unknown] %0 : $*T
+// CHECK: [[METH:%[0-9]+]] = witness_method $T, #SubscriptableGetSet.subscript!setter.1
+// CHECK-NEXT: apply [[METH]]<T>(%1, %1, [[WRITE]])
+
+
+//===----------------------------------------------------------------------===//
+// Calling Existential Properties
+//===----------------------------------------------------------------------===//
+
+protocol PropertyWithGetter {
+  var a : Int { get }
+}
+
+protocol PropertyWithGetterSetter {
+  var b : Int { get set }
+}
+
+
+var propertyGet : PropertyWithGetter
+var propertyGetSet : PropertyWithGetterSetter
+
+func use_property_rvalue_get() -> Int {
+  return propertyGet.a
+}
+// CHECK-LABEL: sil hidden @{{.*}}use_property_rvalue_get
+// CHECK: [[GLOB:%[0-9]+]] = global_addr @$S9protocols11propertyGetAA18PropertyWithGetter_pvp : $*PropertyWithGetter
+// CHECK: [[READ:%.*]] = begin_access [read] [dynamic] [[GLOB]] : $*PropertyWithGetter
+// CHECK: [[PROJ:%[0-9]+]] = open_existential_addr immutable_access [[READ]] : $*PropertyWithGetter to $*[[OPENED:@opened(.*) PropertyWithGetter]]
+// CHECK: [[COPY:%.*]] = alloc_stack $[[OPENED]]
+// CHECK-NEXT: copy_addr [[PROJ]] to [initialization] [[COPY]] : $*[[OPENED]]
+// CHECK-NEXT: [[METH:%[0-9]+]] = witness_method $[[OPENED]], #PropertyWithGetter.a!getter.1
+// CHECK-NEXT: apply [[METH]]<[[OPENED]]>([[COPY]])
+// CHECK: end_access [[READ]] : $*PropertyWithGetter
+
+func use_property_lvalue_get() -> Int {
+  return propertyGetSet.b
+}
+// CHECK-LABEL: sil hidden @{{.*}}use_property_lvalue_get
+// CHECK: [[GLOB:%[0-9]+]] = global_addr @$S9protocols14propertyGetSetAA24PropertyWithGetterSetter_pvp : $*PropertyWithGetterSetter
+// CHECK: [[READ:%.*]] = begin_access [read] [dynamic] [[GLOB]] : $*PropertyWithGetterSetter
+// CHECK: [[PROJ:%[0-9]+]] = open_existential_addr immutable_access [[READ]] : $*PropertyWithGetterSetter to $*[[OPENED:@opened(.*) PropertyWithGetterSetter]]
+// CHECK: [[STACK:%[0-9]+]] = alloc_stack $[[OPENED]]
+// CHECK: copy_addr [[PROJ]] to [initialization] [[STACK]]
+// CHECK-NEXT: [[METH:%[0-9]+]] = witness_method $[[OPENED]], #PropertyWithGetterSetter.b!getter.1
+// CHECK-NEXT: apply [[METH]]<[[OPENED]]>([[STACK]])
+
+func use_property_lvalue_set(_ x : Int) {
+  propertyGetSet.b = x
+}
+
+// CHECK-LABEL: sil hidden @{{.*}}use_property_lvalue_set
+// CHECK: bb0(%0 : @trivial $Int):
+// CHECK: [[GLOB:%[0-9]+]] = global_addr @$S9protocols14propertyGetSetAA24PropertyWithGetterSetter_pvp : $*PropertyWithGetterSetter
+// CHECK: [[READ:%.*]] = begin_access [modify] [dynamic] [[GLOB]] : $*PropertyWithGetterSetter
+// CHECK: [[PROJ:%[0-9]+]] = open_existential_addr mutable_access [[READ]] : $*PropertyWithGetterSetter to $*[[OPENED:@opened(.*) PropertyWithGetterSetter]]
+// CHECK-NEXT: [[METH:%[0-9]+]] = witness_method $[[OPENED]], #PropertyWithGetterSetter.b!setter.1
+// CHECK-NEXT: apply [[METH]]<[[OPENED]]>(%0, [[PROJ]])
+
+//===----------------------------------------------------------------------===//
+// Calling Archetype Properties
+//===----------------------------------------------------------------------===//
+
+func use_property_archetype_rvalue_get<T : PropertyWithGetter>(_ generic : T) -> Int {
+  return generic.a
+}
+
+// CHECK-LABEL: sil hidden @{{.*}}use_property_archetype_rvalue_get
+// CHECK: bb0(%0 : @trivial $*T):
+// CHECK: [[STACK:%[0-9]+]] = alloc_stack $T
+// CHECK: copy_addr %0 to [initialization] [[STACK]]
+// CHECK: [[METH:%[0-9]+]] = witness_method $T, #PropertyWithGetter.a!getter.1
+// CHECK-NEXT: apply [[METH]]<T>([[STACK]])
+// CHECK-NEXT: destroy_addr [[STACK]]
+// CHECK-NEXT: dealloc_stack [[STACK]]
+// CHECK: } // end sil function '{{.*}}use_property_archetype_rvalue_get
+
+
+func use_property_archetype_lvalue_get<T : PropertyWithGetterSetter>(_ generic : T) -> Int {
+  return generic.b
+}
+
+// CHECK-LABEL: sil hidden @{{.*}}use_property_archetype_lvalue_get
+// CHECK: bb0(%0 : @trivial $*T):
+// CHECK: [[STACK:%[0-9]+]] = alloc_stack $T
+// CHECK: copy_addr %0 to [initialization] [[STACK]] : $*T
+// CHECK: [[METH:%[0-9]+]] = witness_method $T, #PropertyWithGetterSetter.b!getter.1
+// CHECK-NEXT: apply [[METH]]<T>([[STACK]])
+// CHECK-NEXT: destroy_addr [[STACK]] : $*T
+// CHECK-NEXT: dealloc_stack [[STACK]] : $*T
+// CHECK: } // end sil function '${{.*}}use_property_archetype_lvalue_get
+
+
+func use_property_archetype_lvalue_set<T : PropertyWithGetterSetter>(_ generic: inout T, v : Int) {
+  generic.b = v
+}
+// CHECK-LABEL: sil hidden @{{.*}}use_property_archetype_lvalue_set
+// CHECK: bb0(%0 : @trivial $*T, %1 : @trivial $Int):
+// CHECK: [[WRITE:%.*]] = begin_access [modify] [unknown] %0 : $*T
+// CHECK: [[METH:%[0-9]+]] = witness_method $T, #PropertyWithGetterSetter.b!setter.1
+// CHECK-NEXT: apply [[METH]]<T>(%1, [[WRITE]])
+
+//===----------------------------------------------------------------------===//
+// Calling Initializers
+//===----------------------------------------------------------------------===//
+protocol Initializable {
+  init(int: Int)
+}
+
+// CHECK-LABEL: sil hidden @$S9protocols27use_initializable_archetype{{[_0-9a-zA-Z]*}}F
+func use_initializable_archetype<T: Initializable>(_ t: T, i: Int) {
+  // CHECK:   [[T_RESULT:%[0-9]+]] = alloc_stack $T
+  // CHECK:   [[T_META:%[0-9]+]] = metatype $@thick T.Type
+  // CHECK:   [[T_INIT:%[0-9]+]] = witness_method $T, #Initializable.init!allocator.1 : {{.*}} : $@convention(witness_method: Initializable) <τ_0_0 where τ_0_0 : Initializable> (Int, @thick τ_0_0.Type) -> @out τ_0_0
+  // CHECK:   [[T_RESULT_ADDR:%[0-9]+]] = apply [[T_INIT]]<T>([[T_RESULT]], %1, [[T_META]]) : $@convention(witness_method: Initializable) <τ_0_0 where τ_0_0 : Initializable> (Int, @thick τ_0_0.Type) -> @out τ_0_0
+  // CHECK:   destroy_addr [[T_RESULT]] : $*T
+  // CHECK:   dealloc_stack [[T_RESULT]] : $*T
+  // CHECK:   [[RESULT:%[0-9]+]] = tuple ()
+  // CHECK:   return [[RESULT]] : $()
+  T(int: i)
+}
+
+// CHECK: sil hidden @$S9protocols29use_initializable_existential{{[_0-9a-zA-Z]*}}F
+func use_initializable_existential(_ im: Initializable.Type, i: Int) {
+// CHECK: bb0([[IM:%[0-9]+]] : @trivial $@thick Initializable.Type, [[I:%[0-9]+]] : @trivial $Int):
+// CHECK:   [[ARCHETYPE_META:%[0-9]+]] = open_existential_metatype [[IM]] : $@thick Initializable.Type to $@thick (@opened([[N:".*"]]) Initializable).Type
+// CHECK:   [[TEMP_VALUE:%[0-9]+]] = alloc_stack $Initializable
+// CHECK:   [[TEMP_ADDR:%[0-9]+]] = init_existential_addr [[TEMP_VALUE]] : $*Initializable, $@opened([[N]]) Initializable
+// CHECK:   [[INIT_WITNESS:%[0-9]+]] = witness_method $@opened([[N]]) Initializable, #Initializable.init!allocator.1 : {{.*}}, [[ARCHETYPE_META]]{{.*}} : $@convention(witness_method: Initializable) <τ_0_0 where τ_0_0 : Initializable> (Int, @thick τ_0_0.Type) -> @out τ_0_0
+// CHECK:   [[INIT_RESULT:%[0-9]+]] = apply [[INIT_WITNESS]]<@opened([[N]]) Initializable>([[TEMP_ADDR]], [[I]], [[ARCHETYPE_META]]) : $@convention(witness_method: Initializable) <τ_0_0 where τ_0_0 : Initializable> (Int, @thick τ_0_0.Type) -> @out τ_0_0
+// CHECK:   destroy_addr [[TEMP_VALUE]] : $*Initializable
+// CHECK:   dealloc_stack [[TEMP_VALUE]] : $*Initializable
+  im.init(int: i)
+// CHECK:   [[RESULT:%[0-9]+]] = tuple ()
+// CHECK:   return [[RESULT]] : $()
+}
+
+//===----------------------------------------------------------------------===//
+// Protocol conformance and witness table generation
+//===----------------------------------------------------------------------===//
+
+class ClassWithGetter : PropertyWithGetter {
+  var a: Int {
+    get {
+      return 42
+    }
+  }
+}
+
+// Make sure we are generating a protocol witness that calls the class method on
+// ClassWithGetter.
+// CHECK-LABEL: sil private [transparent] [thunk] @$S9protocols15ClassWithGetterCAA08PropertycD0A2aDP1aSivgTW : $@convention(witness_method: PropertyWithGetter) (@in_guaranteed ClassWithGetter) -> Int {
+// CHECK: bb0([[C:%.*]] : @trivial $*ClassWithGetter):
+// CHECK-NEXT: [[CCOPY_LOADED:%.*]] = load_borrow %0
+// CHECK-NEXT: [[FUN:%.*]] = class_method [[CCOPY_LOADED]] : $ClassWithGetter, #ClassWithGetter.a!getter.1 : (ClassWithGetter) -> () -> Int, $@convention(method) (@guaranteed ClassWithGetter) -> Int
+// CHECK-NEXT: apply [[FUN]]([[CCOPY_LOADED]])
+// CHECK-NEXT: end_borrow [[CCOPY_LOADED]] from %0
+// CHECK-NEXT: return
+
+class ClassWithGetterSetter : PropertyWithGetterSetter, PropertyWithGetter {
+  var a: Int {
+    get {
+      return 1
+    }
+    set {}
+  }
+  var b: Int {
+    get {
+      return 2
+    }
+    set {}
+  }
+}
+
+// CHECK-LABEL: sil private [transparent] [thunk] @$S9protocols21ClassWithGetterSetterCAA08PropertycdE0A2aDP1bSivgTW : $@convention(witness_method: PropertyWithGetterSetter) (@in_guaranteed ClassWithGetterSetter) -> Int {
+// CHECK: bb0([[C:%.*]] : @trivial $*ClassWithGetterSetter):
+// CHECK-NEXT: [[CCOPY_LOADED:%.*]] = load_borrow %0
+// CHECK-NEXT: [[FUN:%.*]] = class_method [[CCOPY_LOADED]] : $ClassWithGetterSetter, #ClassWithGetterSetter.b!getter.1 : (ClassWithGetterSetter) -> () -> Int, $@convention(method) (@guaranteed ClassWithGetterSetter) -> Int
+// CHECK-NEXT: apply [[FUN]]([[CCOPY_LOADED]])
+// CHECK-NEXT: end_borrow [[CCOPY_LOADED]] from %0
+// CHECK-NEXT: return
+
+// Stored variables fulfilling property requirements
+//
+class ClassWithStoredProperty : PropertyWithGetter {
+  var a : Int = 0
+
+  // Make sure that accesses go through the generated accessors for classes.
+  func methodUsingProperty() -> Int {
+    return a
+  }
+  // CHECK-LABEL: sil hidden @$S9protocols23ClassWithStoredPropertyC011methodUsingE0SiyF
+  // CHECK: bb0([[ARG:%.*]] : @guaranteed $ClassWithStoredProperty):
+  // CHECK-NEXT: debug_value [[ARG]]
+  // CHECK-NOT: copy_value
+  // CHECK-NEXT: [[FUN:%.*]] = class_method [[ARG]] : $ClassWithStoredProperty, #ClassWithStoredProperty.a!getter.1 : (ClassWithStoredProperty) -> () -> Int, $@convention(method) (@guaranteed ClassWithStoredProperty) -> Int
+  // CHECK-NEXT: [[RESULT:%.*]] = apply [[FUN]]([[ARG]])
+  // CHECK-NOT: destroy_value
+  // CHECK-NEXT: return [[RESULT]] : $Int
+}
+
+struct StructWithStoredProperty : PropertyWithGetter {
+  var a : Int
+
+  // Make sure that accesses aren't going through the generated accessors.
+  func methodUsingProperty() -> Int {
+    return a
+  }
+  // CHECK-LABEL: sil hidden @$S9protocols24StructWithStoredPropertyV011methodUsingE0SiyF
+  // CHECK: bb0(%0 : @trivial $StructWithStoredProperty):
+  // CHECK-NEXT: debug_value %0
+  // CHECK-NEXT: %2 = struct_extract %0 : $StructWithStoredProperty, #StructWithStoredProperty.a
+  // CHECK-NEXT: return %2 : $Int
+}
+
+// Make sure that we generate direct function calls for out struct protocol
+// witness since structs don't do virtual calls for methods.
+//
+// *NOTE* Even though at first glance the copy_addr looks like a leak
+// here, StructWithStoredProperty is a trivial struct implying that no
+// leak is occurring. See the test with StructWithStoredClassProperty
+// that makes sure in such a case we don't leak. This is due to the
+// thunking code being too dumb but it is harmless to program
+// correctness.
+//
+// CHECK-LABEL: sil private [transparent] [thunk] @$S9protocols24StructWithStoredPropertyVAA0eC6GetterA2aDP1aSivgTW : $@convention(witness_method: PropertyWithGetter) (@in_guaranteed StructWithStoredProperty) -> Int {
+// CHECK: bb0([[C:%.*]] : @trivial $*StructWithStoredProperty):
+// CHECK-NEXT: [[CCOPY_LOADED:%.*]] = load [trivial] [[C]]
+// CHECK-NEXT: function_ref
+// CHECK-NEXT: [[FUN:%.*]] = function_ref @$S9protocols24StructWithStoredPropertyV1aSivg : $@convention(method) (StructWithStoredProperty) -> Int
+// CHECK-NEXT: apply [[FUN]]([[CCOPY_LOADED]])
+// CHECK-NEXT: return
+
+class C {}
+
+// Make sure that if the getter has a class property, we pass it in
+// in_guaranteed and don't leak.
+struct StructWithStoredClassProperty : PropertyWithGetter {
+  var a : Int
+  var c: C = C()
+
+  // Make sure that accesses aren't going through the generated accessors.
+  func methodUsingProperty() -> Int {
+    return a
+  }
+  // CHECK-LABEL: sil hidden @$S9protocols29StructWithStoredClassPropertyV011methodUsingF0SiyF
+  // CHECK: bb0(%0 : @guaranteed $StructWithStoredClassProperty):
+  // CHECK-NEXT: debug_value %0
+  // CHECK-NEXT: %2 = struct_extract %0 : $StructWithStoredClassProperty, #StructWithStoredClassProperty.a
+  // CHECK-NEXT: return %2 : $Int
+}
+
+// CHECK-LABEL: sil private [transparent] [thunk] @$S9protocols29StructWithStoredClassPropertyVAA0fC6GetterA2aDP1aSivgTW : $@convention(witness_method: PropertyWithGetter) (@in_guaranteed StructWithStoredClassProperty) -> Int {
+// CHECK: bb0([[C:%.*]] : @trivial $*StructWithStoredClassProperty):
+// CHECK-NEXT: [[CCOPY_LOADED:%.*]] = load_borrow [[C]]
+// CHECK-NEXT: function_ref
+// CHECK-NEXT: [[FUN:%.*]] = function_ref @$S9protocols29StructWithStoredClassPropertyV1aSivg : $@convention(method) (@guaranteed StructWithStoredClassProperty) -> Int
+// CHECK-NEXT: apply [[FUN]]([[CCOPY_LOADED]])
+// CHECK-NEXT: end_borrow [[CCOPY_LOADED]] from %0
+// CHECK-NEXT: return
+
+// rdar://22676810
+
+protocol ExistentialProperty {
+  var p: PropertyWithGetterSetter { get set }
+}
+
+func testExistentialPropertyRead<T: ExistentialProperty>(_ t: inout T) {
+    let b = t.p.b
+}
+// CHECK-LABEL: sil hidden @$S9protocols27testExistentialPropertyRead{{[_0-9a-zA-Z]*}}F
+// CHECK:      [[READ:%.*]] = begin_access [read] [unknown] %0 : $*T
+// CHECK:      [[P_TEMP:%.*]] = alloc_stack $PropertyWithGetterSetter
+// CHECK:      [[T_TEMP:%.*]] = alloc_stack $T
+// CHECK:      copy_addr [[READ]] to [initialization] [[T_TEMP]] : $*T
+// CHECK:      [[P_GETTER:%.*]] = witness_method $T, #ExistentialProperty.p!getter.1 :
+// CHECK-NEXT: apply [[P_GETTER]]<T>([[P_TEMP]], [[T_TEMP]])
+// CHECK-NEXT: destroy_addr [[T_TEMP]]
+// CHECK-NEXT: [[OPEN:%.*]] = open_existential_addr immutable_access [[P_TEMP]] : $*PropertyWithGetterSetter to $*[[P_OPENED:@opened(.*) PropertyWithGetterSetter]]
+// CHECK-NEXT: [[T0:%.*]] = alloc_stack $[[P_OPENED]]
+// CHECK-NEXT: copy_addr [[OPEN]] to [initialization] [[T0]]
+// CHECK-NEXT: [[B_GETTER:%.*]] = witness_method $[[P_OPENED]], #PropertyWithGetterSetter.b!getter.1
+// CHECK-NEXT: apply [[B_GETTER]]<[[P_OPENED]]>([[T0]])
+// CHECK-NEXT: debug_value
+// CHECK-NEXT: destroy_addr [[T0]]
+// CHECK-NOT:  witness_method
+// CHECK:      return
+
+func modify(_ x: inout Int) {}
+
+// Make sure we call the materializeForSet callback with the correct
+// generic signature.
+
+func modifyProperty<T : PropertyWithGetterSetter>(_ x: inout T) {
+  modify(&x.b)
+}
+// CHECK-LABEL: sil hidden @$S9protocols14modifyPropertyyyxzAA0C16WithGetterSetterRzlF
+// CHECK:      [[WRITE:%.*]] = begin_access [modify] [unknown] %0 : $*T
+// CHECK:      [[WITNESS_FN:%.*]] = witness_method $T, #PropertyWithGetterSetter.b!materializeForSet.1
+// CHECK:      [[RESULT:%.*]] = apply [[WITNESS_FN]]<T>
+// CHECK:      [[TEMPORARY:%.*]] = tuple_extract [[RESULT]]
+// CHECK:      [[CALLBACK:%.*]] = tuple_extract [[RESULT]]
+// CHECK:      [[TEMPORARY_ADDR_TMP:%.*]] = pointer_to_address [[TEMPORARY]] : $Builtin.RawPointer to [strict] $*Int
+// CHECK:      [[TEMPORARY_ADDR:%.*]] = mark_dependence [[TEMPORARY_ADDR_TMP]] : $*Int on [[WRITE]] : $*T
+// CHECK:      [[MODIFY_FN:%.*]] = function_ref @$S9protocols6modifyyySizF
+// CHECK:      apply [[MODIFY_FN]]([[TEMPORARY_ADDR]])
+// CHECK:      switch_enum [[CALLBACK]] : $Optional<Builtin.RawPointer>, case #Optional.some!enumelt.1: bb1, case #Optional.none!enumelt: bb2
+// CHECK:    bb1([[CALLBACK_ADDR:%.*]] : @trivial $Builtin.RawPointer):
+// CHECK:      [[CALLBACK:%.*]] = pointer_to_thin_function [[CALLBACK_ADDR]]
+// CHECK:      [[METATYPE:%.*]] = metatype $@thick T.Type
+// CHECK:      [[TEMPORARY:%.*]] = address_to_pointer [[TEMPORARY_ADDR]] : $*Int to $Builtin.RawPointer
+// CHECK:      apply [[CALLBACK]]<T>
+
+public struct Val {
+  public var x: Int = 0
+}
+
+public protocol Proto {
+  var val: Val { get nonmutating set}
+}
+
+public func test(_ p: Proto) {
+  p.val.x += 1
+}
+
+// CHECK-LABEL: sil @$S9protocols4testyyAA5Proto_pF : $@convention(thin) (@in_guaranteed Proto) -> ()
+// CHECK: [[OPEN:%.*]] = open_existential_addr immutable_access
+// CHECK: [[MAT:%.*]] = witness_method $@opened("{{.*}}") Proto, #Proto.val!materializeForSet
+// CHECK: [[BUF:%.*]] = apply [[MAT]]
+// CHECK: [[WB:%.*]] = pointer_to_thin_function
+// This use looks like it is mutating but really is not. We use to assert in the SIL verifier.
+// CHECK: apply [[WB]]{{.*}}({{.*}}[[OPEN]]
+// CHECK: return
+
+// CHECK-LABEL: sil_witness_table hidden ClassWithGetter: PropertyWithGetter module protocols {
+// CHECK-NEXT:  method #PropertyWithGetter.a!getter.1: {{.*}} : @$S9protocols15ClassWithGetterCAA08PropertycD0A2aDP1aSivgTW
+// CHECK-NEXT: }
+
+// CHECK-LABEL: sil_witness_table hidden ClassWithGetterSetter: PropertyWithGetterSetter module protocols {
+// CHECK-NEXT:  method #PropertyWithGetterSetter.b!getter.1: {{.*}} : @$S9protocols21ClassWithGetterSetterCAA08PropertycdE0A2aDP1bSivgTW
+// CHECK-NEXT:  method #PropertyWithGetterSetter.b!setter.1: {{.*}} : @$S9protocols21ClassWithGetterSetterCAA08PropertycdE0A2aDP1bSivsTW
+// CHECK-NEXT:  method #PropertyWithGetterSetter.b!materializeForSet.1: {{.*}} : @$S9protocols21ClassWithGetterSetterCAA08PropertycdE0A2aDP1bSivmTW
+// CHECK-NEXT: }
+
+// CHECK-LABEL: sil_witness_table hidden ClassWithGetterSetter: PropertyWithGetter module protocols {
+// CHECK-NEXT:  method #PropertyWithGetter.a!getter.1: {{.*}} : @$S9protocols21ClassWithGetterSetterCAA08PropertycD0A2aDP1aSivgTW
+// CHECK-NEXT: }
+
+// CHECK-LABEL: sil_witness_table hidden StructWithStoredProperty: PropertyWithGetter module protocols {
+// CHECK-NEXT:  method #PropertyWithGetter.a!getter.1: {{.*}} : @$S9protocols24StructWithStoredPropertyVAA0eC6GetterA2aDP1aSivgTW
+// CHECK-NEXT: }
+
+// CHECK-LABEL: sil_witness_table hidden StructWithStoredClassProperty: PropertyWithGetter module protocols {
+// CHECK-NEXT:  method #PropertyWithGetter.a!getter.1: {{.*}} : @$S9protocols29StructWithStoredClassPropertyVAA0fC6GetterA2aDP1aSivgTW
+// CHECK-NEXT: }
+
+//
+// rdar://problem/37031037
+//
+
+protocol MethodWithDefaultArgGenerator {}
+extension MethodWithDefaultArgGenerator {
+  mutating func foo(_ x: Int = 0) {}
+}
+func invokeMethodWithDefaultArg(x: inout MethodWithDefaultArgGenerator) {
+  x.foo()
+}
diff --git a/test/SILGen/plus_zero_reabstract-tuple.swift b/test/SILGen/plus_zero_reabstract-tuple.swift
new file mode 100644
index 0000000..8553bba
--- /dev/null
+++ b/test/SILGen/plus_zero_reabstract-tuple.swift
@@ -0,0 +1,63 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -enable-sil-ownership -emit-silgen -verify %s | %FileCheck %s
+
+// SR-3090:
+
+class Box<T> {
+    public let value: T
+    
+    public init(_ value: T) {
+        self.value = value
+    }
+}
+
+// CHECK: sil @$S4main7testBoxyyF : $@convention(thin) () -> () {
+// CHECK: bb0:
+// CHECK:   // function_ref closure #1 in testBox()
+// CHECK:   [[CLOSURE:%.*]] = function_ref @$S4main7testBoxyyFyycfU_ : $@convention(thin) () -> ()
+// CHECK:   [[THICK:%.*]] = thin_to_thick_function [[CLOSURE]] : $@convention(thin) () -> () to $@callee_guaranteed () -> ()
+// CHECK:   [[TUPLEA:%.*]] = tuple (%{{.*}} : $Int, [[THICK]] : $@callee_guaranteed () -> ())
+// CHECK:   ([[ELTA_0:%.*]], [[ELTA_1:%.*]]) = destructure_tuple [[TUPLEA]] : $(Int, @callee_guaranteed () -> ())
+// CHECK:   [[THUNK1:%.*]] = function_ref @$SIeg_ytytIegnr_TR : $@convention(thin) (@in_guaranteed (), @guaranteed @callee_guaranteed () -> ()) -> @out ()
+// CHECK:   [[PA:%.*]] = partial_apply [callee_guaranteed] [[THUNK1]]([[ELTA_1]]) : $@convention(thin) (@in_guaranteed (), @guaranteed @callee_guaranteed () -> ()) -> @out ()
+// CHECK:   [[TUPLEB:%.*]] = tuple ([[ELTA_0]] : $Int, [[PA]] : $@callee_guaranteed (@in_guaranteed ()) -> @out ())
+// CHECK:   [[BORROWB:%.*]] = begin_borrow [[TUPLEB]] : $(Int, @callee_guaranteed (@in_guaranteed ()) -> @out ())
+// CHECK:   [[TUPLEB_0:%.*]] = tuple_extract [[BORROWB]] : $(Int, @callee_guaranteed (@in_guaranteed ()) -> @out ()), 0
+// CHECK:   [[TUPLEB_1:%.*]] = tuple_extract [[BORROWB]] : $(Int, @callee_guaranteed (@in_guaranteed ()) -> @out ()), 1
+// CHECK:   [[COPYB_1:%.*]] = copy_value [[TUPLEB_1]] : $@callee_guaranteed (@in_guaranteed ()) -> @out ()
+// CHECK:   // function_ref Box.__allocating_init(_:)
+// CHECK:   [[INIT_F:%.*]] = function_ref @$S4main3BoxCyACyxGxcfC : $@convention(method) <τ_0_0> (@in τ_0_0, @thick Box<τ_0_0>.Type) -> @owned Box<τ_0_0>
+// CHECK:   [[CALL:%.*]] = apply [[INIT_F]]<(Int, () -> ())>(%{{.*}}, %{{.*}}) : $@convention(method) <τ_0_0> (@in τ_0_0, @thick Box<τ_0_0>.Type) -> @owned Box<τ_0_0>
+// CHECK:   end_borrow [[BORROWB]] from %{{.*}} : $(Int, @callee_guaranteed (@in_guaranteed ()) -> @out ()), $(Int, @callee_guaranteed (@in_guaranteed ()) -> @out ())
+// CHECK:   destroy_value [[TUPLEB]] : $(Int, @callee_guaranteed (@in_guaranteed ()) -> @out ())
+// CHECK:   [[BORROW_CALL:%.*]] = begin_borrow [[CALL]] : $Box<(Int, () -> ())> 
+// CHECK:   [[REF:%.*]] = ref_element_addr [[BORROW_CALL]] : $Box<(Int, () -> ())>, #Box.value
+// CHECK:   [[READ:%.*]] = begin_access [read] [dynamic] [[REF]] : $*(Int, @callee_guaranteed (@in_guaranteed ()) -> @out ())
+// CHECK:   [[TUPLEC:%.*]] = load [copy] [[READ]] : $*(Int, @callee_guaranteed (@in_guaranteed ()) -> @out ())
+// CHECK:   [[BORROW_TUPLEC:%.*]] = begin_borrow [[TUPLEC]] : $(Int, @callee_guaranteed (@in_guaranteed ()) -> @out ())
+// CHECK:   [[TUPLEC_0:%.*]] = tuple_extract [[BORROW_TUPLEC]] : $(Int, @callee_guaranteed (@in_guaranteed ()) -> @out ()), 0
+// CHECK:   [[TUPLEC_1:%.*]] = tuple_extract [[BORROW_TUPLEC]] : $(Int, @callee_guaranteed (@in_guaranteed ()) -> @out ()), 1
+// CHECK:   [[COPYC_1:%.*]] = copy_value [[TUPLEC_1]] : $@callee_guaranteed (@in_guaranteed ()) -> @out ()
+// CHECK:   [[THUNK2:%.*]] = function_ref @$SytytIegnr_Ieg_TR : $@convention(thin) (@guaranteed @callee_guaranteed (@in_guaranteed ()) -> @out ()) -> ()
+// CHECK:   [[PA2:%.*]] = partial_apply [callee_guaranteed] [[THUNK2]]([[COPYC_1]]) : $@convention(thin) (@guaranteed @callee_guaranteed (@in_guaranteed ()) -> @out ()) -> ()
+// CHECK:   end_access [[READ]] : $*(Int, @callee_guaranteed (@in_guaranteed ()) -> @out ())
+// CHECK:   destroy_value [[PA2]] : $@callee_guaranteed () -> ()    
+// CHECK:   end_borrow [[BORROW_TUPLEC]] from %{{.*}} : $(Int, @callee_guaranteed (@in_guaranteed ()) -> @out ()), $(Int, @callee_guaranteed (@in_guaranteed ()) -> @out ())
+// CHECK:   destroy_value [[TUPLEC]] : $(Int, @callee_guaranteed (@in_guaranteed ()) -> @out ())
+// CHECK:   end_borrow [[BORROW_CALL]] from %{{.*}} : $Box<(Int, () -> ())>, $Box<(Int, () -> ())>
+// CHECK-LABEL: } // end sil function '$S4main7testBoxyyF'
+public func testBox() {
+  let box = Box((22, { () in }))
+  let foo = box.value.0
+  print(foo)
+}
+
+
+// Another crash -- re-abstracting function type inside optional in tuple
+// in-place
+
+func g<T>() -> (Int, T)? { }
+
+func f<T>(t: T) {
+  let _: (Int, ((T) -> (), T))? = g()
+}
diff --git a/test/SILGen/plus_zero_reabstract.swift b/test/SILGen/plus_zero_reabstract.swift
new file mode 100644
index 0000000..03389c7
--- /dev/null
+++ b/test/SILGen/plus_zero_reabstract.swift
@@ -0,0 +1,82 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -Xllvm -sil-full-demangle -emit-silgen -enable-sil-ownership %s | %FileCheck %s
+
+func takeFn<T>(_ f : (T) -> T?) {}
+func liftOptional(_ x : Int) -> Int? { return x }
+
+func test0() {
+  takeFn(liftOptional)
+}
+// CHECK:    sil hidden @$S10reabstract5test0yyF : $@convention(thin) () -> () {
+//   Emit a generalized reference to liftOptional.
+//   TODO: just emit a globalized thunk
+// CHECK:      reabstract.liftOptional
+// CHECK-NEXT: [[T1:%.*]] = function_ref @$S10reabstract12liftOptional{{[_0-9a-zA-Z]*}}F
+// CHECK-NEXT: [[T2:%.*]] = thin_to_thick_function [[T1]]
+// CHECK-NEXT: [[CVT:%.*]] = convert_escape_to_noescape [[T2]]
+// CHECK-NEXT: reabstraction thunk
+// CHECK-NEXT: [[T3:%.*]] = function_ref [[THUNK:@.*]] :
+// CHECK-NEXT: [[T4:%.*]] = partial_apply [callee_guaranteed] [[T3]]([[CVT]])
+// CHECK-NEXT: [[CVT:%.*]] = convert_escape_to_noescape [[T4]]
+// CHECK:      [[T0:%.*]] = function_ref @$S10reabstract6takeFn{{[_0-9a-zA-Z]*}}F
+// CHECK-NEXT: apply [[T0]]<Int>([[CVT]])
+// CHECK-NEXT: destroy_value [[T2]]
+// CHECK-NEXT: destroy_value [[T4]]
+// CHECK-NEXT: tuple ()
+// CHECK-NEXT: return
+// CHECK-NEXT: } // end sil function '$S10reabstract5test0yyF'
+
+// CHECK:    sil shared [transparent] [serializable] [reabstraction_thunk] [[THUNK]] : $@convention(thin) (@in_guaranteed Int, @noescape @callee_guaranteed (Int) -> Optional<Int>) -> @out Optional<Int> {
+// CHECK:      [[T0:%.*]] = load [trivial] %1 : $*Int
+// CHECK-NEXT: [[T1:%.*]] = apply %2([[T0]])
+// CHECK-NEXT: store [[T1]] to [trivial] %0
+// CHECK-NEXT: tuple ()
+// CHECK-NEXT: return
+
+// CHECK-LABEL: sil hidden @$S10reabstract10testThrowsyyypF
+// CHECK:         function_ref @$SytytIegnr_Ieg_TR
+// CHECK:         function_ref @$Sytyts5Error_pIegnrzo_sAA_pIegzo_TR
+func testThrows(_ x: Any) {
+  _ = x as? () -> ()
+  _ = x as? () throws -> ()
+}
+
+// Make sure that we preserve inout-ness when lowering types with maximum
+// abstraction level -- <rdar://problem/21329377>
+class C {}
+
+struct Box<T> {
+  let t: T
+}
+
+func notFun(_ c: inout C, i: Int) {}
+
+func testInoutOpaque(_ c: C, i: Int) {
+  var c = c
+  let box = Box(t: notFun)
+  box.t(&c, i)
+}
+
+// CHECK-LABEL: sil hidden @$S10reabstract15testInoutOpaque_1iyAA1CC_SitF
+// CHECK:         function_ref @$S10reabstract6notFun_1iyAA1CCz_SitF
+// CHECK:         thin_to_thick_function {{%[0-9]+}}
+// CHECK:         function_ref @$S10reabstract1CCSiIegly_ACSiytIeglnr_TR
+// CHECK:         partial_apply
+// CHECK:         store
+// CHECK:         load
+// CHECK:         function_ref @$S10reabstract1CCSiytIeglnr_ACSiIegly_TR
+// CHECK:         partial_apply
+// CHECK:         apply
+// CHECK: } // end sil function '$S10reabstract15testInoutOpaque_1iyAA1CC_SitF'
+
+// CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] @$S10reabstract1CCSiIegly_ACSiytIeglnr_TR : $@convention(thin) (@inout C, @in_guaranteed Int, @guaranteed @callee_guaranteed (@inout C, Int) -> ()) -> @out () {
+// CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] @$S10reabstract1CCSiytIeglnr_ACSiIegly_TR : $@convention(thin) (@inout C, Int, @guaranteed @callee_guaranteed (@inout C, @in_guaranteed Int) -> @out ()) -> () {
+
+func closureTakingOptional(_ fn: (Int?) -> ()) {}
+closureTakingOptional({ (_: Any) -> () in })
+
+// CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] @$SypIgn_SiSgIegy_TR : $@convention(thin) (Optional<Int>, @noescape @callee_guaranteed (@in_guaranteed Any) -> ()) -> ()
+// CHECK:   [[ANYADDR:%.*]] = alloc_stack $Any
+// CHECK:   [[OPTADDR:%.*]] = init_existential_addr [[ANYADDR]] : $*Any, $Optional<Int>
+// CHECK:   store %0 to [trivial] [[OPTADDR]] : $*Optional<Int>
+// CHECK:   apply %1([[ANYADDR]]) : $@noescape @callee_guaranteed (@in_guaranteed Any) -> ()
diff --git a/test/SILGen/plus_zero_reabstract_lvalue.swift b/test/SILGen/plus_zero_reabstract_lvalue.swift
new file mode 100644
index 0000000..66a9907
--- /dev/null
+++ b/test/SILGen/plus_zero_reabstract_lvalue.swift
@@ -0,0 +1,48 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership %s | %FileCheck %s
+
+struct MyMetatypeIsThin {}
+
+// CHECK-LABEL: sil hidden @$S17reabstract_lvalue19consumeGenericInOut{{[_0-9a-zA-Z]*}}F : $@convention(thin) <T> (@inout T) -> ()
+func consumeGenericInOut<T>(_ x: inout T) {}
+
+// CHECK-LABEL: sil hidden @$S17reabstract_lvalue9transformySdSiF : $@convention(thin) (Int) -> Double
+func transform(_ i: Int) -> Double {
+  return Double(i)
+}
+
+// CHECK-LABEL: sil hidden @$S17reabstract_lvalue0A13FunctionInOutyyF : $@convention(thin) () -> ()
+func reabstractFunctionInOut() {
+  // CHECK: [[BOX:%.*]] = alloc_box ${ var @callee_guaranteed (Int) -> Double }
+  // CHECK: [[PB:%.*]] = project_box [[BOX]]
+  // CHECK: [[ARG:%.*]] = function_ref @$S17reabstract_lvalue9transformySdSiF
+  // CHECK: [[THICK_ARG:%.*]] = thin_to_thick_function [[ARG]]
+  // CHECK: store [[THICK_ARG:%.*]] to [init] [[PB]]
+  // CHECK:  [[WRITE:%.*]] = begin_access [modify] [unknown] [[PB]] : $*@callee_guaranteed (Int) -> Double
+  // CHECK: [[ABSTRACTED_BOX:%.*]] = alloc_stack $@callee_guaranteed (@in_guaranteed Int) -> @out Double
+  // CHECK: [[THICK_ARG:%.*]] = load [copy] [[WRITE]]
+  // CHECK: [[THUNK1:%.*]] = function_ref @$SSiSdIegyd_SiSdIegnr_TR
+  // CHECK: [[ABSTRACTED_ARG:%.*]] = partial_apply [callee_guaranteed] [[THUNK1]]([[THICK_ARG]])
+  // CHECK: store [[ABSTRACTED_ARG]] to [init] [[ABSTRACTED_BOX]]
+  // CHECK: [[FUNC:%.*]] = function_ref @$S17reabstract_lvalue19consumeGenericInOut{{[_0-9a-zA-Z]*}}F
+  // CHECK: apply [[FUNC]]<(Int) -> Double>([[ABSTRACTED_BOX]])
+  // CHECK: [[NEW_ABSTRACTED_ARG:%.*]] = load [take] [[ABSTRACTED_BOX]]
+  // CHECK: [[THUNK2:%.*]] = function_ref @$SSiSdIegnr_SiSdIegyd_TR
+  // CHECK: [[NEW_ARG:%.*]] = partial_apply [callee_guaranteed] [[THUNK2]]([[NEW_ABSTRACTED_ARG]])
+  var minimallyAbstracted = transform
+  consumeGenericInOut(&minimallyAbstracted)
+}
+
+// CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] @$SSiSdIegyd_SiSdIegnr_TR : $@convention(thin) (@in_guaranteed Int, @guaranteed @callee_guaranteed (Int) -> Double) -> @out Double
+// CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] @$SSiSdIegnr_SiSdIegyd_TR : $@convention(thin) (Int, @guaranteed @callee_guaranteed (@in_guaranteed Int) -> @out Double) -> Double
+
+// CHECK-LABEL: sil hidden @$S17reabstract_lvalue0A13MetatypeInOutyyF : $@convention(thin) () -> ()
+func reabstractMetatypeInOut() {
+  var thinMetatype = MyMetatypeIsThin.self
+  // CHECK: [[BOX:%.*]] = alloc_stack $@thick MyMetatypeIsThin.Type
+  // CHECK: [[THICK:%.*]] = metatype $@thick MyMetatypeIsThin.Type
+  // CHECK: store [[THICK]] to [trivial] [[BOX]]
+  // CHECK: [[FUNC:%.*]] = function_ref @$S17reabstract_lvalue19consumeGenericInOut{{[_0-9a-zA-Z]*}}F
+  // CHECK: apply [[FUNC]]<MyMetatypeIsThin.Type>([[BOX]])
+  consumeGenericInOut(&thinMetatype)
+}
diff --git a/test/SILGen/plus_zero_result_abstraction.swift b/test/SILGen/plus_zero_result_abstraction.swift
new file mode 100644
index 0000000..af83741
--- /dev/null
+++ b/test/SILGen/plus_zero_result_abstraction.swift
@@ -0,0 +1,60 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership %s | %FileCheck %s
+
+struct S {}
+struct R {}
+
+protocol ReturnsMetatype {
+  associatedtype Assoc
+  mutating
+  func getAssocMetatype() -> Assoc.Type
+}
+
+struct ConformsToReturnsMetatype : ReturnsMetatype {
+  // CHECK-LABEL: sil private [transparent] [thunk] @$S18result_abstraction25ConformsToReturnsMetatypeVAA0eF0A2aDP08getAssocF0{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method: ReturnsMetatype) (@inout ConformsToReturnsMetatype) -> @thick S.Type
+  // CHECK:         function_ref @$S18result_abstraction25ConformsToReturnsMetatypeV08getAssocF0{{[_0-9a-zA-Z]*}}F : $@convention(method) (@inout ConformsToReturnsMetatype) -> @thin S.Type
+  mutating
+  func getAssocMetatype() -> S.Type {
+    return S.self
+  }
+}
+
+protocol ReturnsFunction {
+  associatedtype Arg
+  associatedtype Result
+  func getFunc() -> (Arg) -> Result
+}
+
+struct ConformsToReturnsFunction : ReturnsFunction {
+  // CHECK-LABEL: sil private [transparent] [thunk] @$S18result_abstraction25ConformsToReturnsFunctionVAA0eF0A2aDP7getFunc{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method: ReturnsFunction) (@in_guaranteed ConformsToReturnsFunction) -> @owned @callee_guaranteed (@in_guaranteed S) -> @out R
+  // CHECK:         function_ref @$S18result_abstraction1SVAA1RVIegyd_AcEIegnr_TR : $@convention(thin) (@in_guaranteed S, @guaranteed @callee_guaranteed (S) -> R) -> @out R
+  func getFunc() -> (S) -> R {
+    return {s in R()}
+  }
+}
+
+protocol ReturnsAssoc {
+  associatedtype Assoc
+  mutating
+  func getAssoc() -> Assoc
+}
+
+struct ConformsToReturnsAssocWithMetatype : ReturnsAssoc {
+  typealias Assoc = S.Type
+  // CHECK-LABEL: sil private [transparent] [thunk] @$S18result_abstraction34ConformsToReturnsAssocWithMetatypeVAA0eF0A2aDP03getF0{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method: ReturnsAssoc) (@inout ConformsToReturnsAssocWithMetatype) -> @out @thick S.Type
+  // CHECK:         function_ref @$S18result_abstraction34ConformsToReturnsAssocWithMetatypeV03getF0{{[_0-9a-zA-Z]*}}F : $@convention(method) (@inout ConformsToReturnsAssocWithMetatype) -> @thin S.Type
+  mutating
+  func getAssoc() -> S.Type {
+    return S.self
+  }
+}
+
+struct ConformsToReturnsAssocWithFunction : ReturnsAssoc {
+  typealias Assoc = (S) -> R
+  // CHECK-LABEL: sil private [transparent] [thunk] @$S18result_abstraction34ConformsToReturnsAssocWithFunctionVAA0eF0A2aDP03getF0{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method: ReturnsAssoc) (@inout ConformsToReturnsAssocWithFunction) -> @out @callee_guaranteed (@in_guaranteed S) -> @out R
+  // CHECK:         function_ref @$S18result_abstraction34ConformsToReturnsAssocWithFunctionV03getF0{{[_0-9a-zA-Z]*}}F : $@convention(method) (@inout ConformsToReturnsAssocWithFunction) -> @owned @callee_guaranteed (S) -> R
+  mutating
+  func getAssoc() -> (S) -> R {
+    return {s in R()}
+  }
+}
diff --git a/test/SILGen/plus_zero_retaining_globals.swift b/test/SILGen/plus_zero_retaining_globals.swift
new file mode 100644
index 0000000..481a643
--- /dev/null
+++ b/test/SILGen/plus_zero_retaining_globals.swift
@@ -0,0 +1,75 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -import-objc-header %S/Inputs/globals.h -emit-silgen -enable-sil-ownership %s | %FileCheck %s
+// REQUIRES: objc_interop
+
+
+// This test makes sure loading from globals properly retains/releases loads from globals.
+// NSString was the only real problem, as the compiler treats NSString globals specially.
+// The rest of these are just hedges against future changes.
+
+// From header:
+// globalString: __strong NSString*
+// globalObject: __strong NSObject*
+// globalID: __strong id
+// globalArray: __strong NSArray*
+// globalConstArray: __strong NSArray *const
+
+func main() {
+  Globals.sharedInstance() // Initialize globals (dispatch_once)
+
+  // CHECK: global_addr @globalConstArray : $*Optional<NSArray>
+  // CHECK: global_addr @globalArray : $*Optional<NSArray>
+  // CHECK: global_addr @globalId : $*Optional<AnyObject>
+  // CHECK: global_addr @globalObject : $*Optional<NSObject>
+  // CHECK: global_addr @globalString : $*NSString
+
+
+
+  // CHECK: [[globalString:%.*]] = load [copy] {{%.*}} : $*NSString
+  // CHECK: [[bridgeStringFunc:%.*]] = function_ref @{{.*}} : $@convention(method) (@guaranteed Optional<NSString>, @thin String.Type) -> @owned String
+  // CHECK: [[wrappedString:%.*]] = enum $Optional<NSString>, #Optional.some!enumelt.1, [[globalString]] : $NSString
+  // CHECK: [[stringMetaType:%.*]] = metatype $@thin String.Type
+  // CHECK: [[bridgedString:%.*]] = apply [[bridgeStringFunc]]([[wrappedString]], [[stringMetaType]]) : $@convention(method) (@guaranteed Optional<NSString>, @thin String.Type) -> @owned String
+  let string = globalString // Problematic case, wasn't being retained
+
+  // CHECK: [[load_1:%.*]] = load [copy] {{%.*}} : $*Optional<NSObject>
+  let object = globalObject
+  
+  // CHECK: [[load_2:%.*]] = load [copy] {{%.*}} : $*Optional<AnyObject>
+  let id = globalId
+  
+  // CHECK: [[load_3:%.*]] = load [copy] {{%.*}} : $*Optional<NSArray>
+  let arr = globalArray
+  
+  // CHECK: [[load_4:%.*]] = load [copy] {{%.*}} : $*Optional<NSArray>
+  let constArr = globalConstArray
+
+  // Make sure there's no more copies
+  // CHECK-NOT: load [copy]
+
+  print(string as Any)
+  print(object as Any)
+  print(id as Any)
+  print(arr as Any)
+  print(constArr as Any)
+
+  // CHECK: [[PRINT_FUN:%.*]] = function_ref @$Ss5print_9separator10terminatoryypd_S2StF : $@convention(thin) (@guaranteed Array<Any>, @guaranteed String, @guaranteed String) -> ()
+  // CHECK: apply [[PRINT_FUN]]({{.*}})
+  // CHECK: destroy_value [[load_4]]
+  // CHECK: destroy_value [[load_3]]
+  // CHECK: destroy_value [[load_2]]
+  // CHECK: destroy_value [[load_1]]
+  // CHECK: destroy_value [[bridgedString]]
+
+  // Make sure there's no more destroys
+  // CHECK-NOT: destroy_value
+  // CHECK: } // end sil function '$S17retaining_globals4mainyyF'
+}
+
+
+main()
+main()  // Used to crash here, due to use-after-free.
+main()
+main()
+main()
+main()
diff --git a/test/SILGen/plus_zero_rethrows.swift b/test/SILGen/plus_zero_rethrows.swift
new file mode 100644
index 0000000..0b5dfe7
--- /dev/null
+++ b/test/SILGen/plus_zero_rethrows.swift
@@ -0,0 +1,90 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -enable-sil-ownership -emit-sil -verify %s | %FileCheck %s
+
+@discardableResult
+func rethrower(_ fn: () throws -> Int) rethrows -> Int {
+  return try fn()
+}
+func thrower() throws -> Int { return 0 }
+func nonthrower() -> Int { return 0 }
+
+// CHECK-LABEL: sil hidden @$S8rethrows5test0yyKF : $@convention(thin) () -> @error Error {
+// CHECK:       [[THROWER:%.*]] = function_ref @$S8rethrows7throwerSiyKF : $@convention(thin) () -> (Int, @error Error)
+// CHECK:       [[T0:%.*]] = thin_to_thick_function [[THROWER]]
+// CHECK:       [[CVT:%.*]] = convert_escape_to_noescape [[T0]]
+// CHECK:       [[RETHROWER:%.*]] = function_ref @$S8rethrows9rethroweryS2iyKXEKF : $@convention(thin) (@noescape @callee_guaranteed () -> (Int, @error Error)) -> (Int, @error Error)
+// CHECK:       try_apply [[RETHROWER]]([[CVT]]) : $@convention(thin) (@noescape @callee_guaranteed () -> (Int, @error Error)) -> (Int, @error Error), normal [[NORMAL:bb1]], error [[ERROR:bb2]]
+// CHECK:     [[NORMAL]]([[RESULT_T0:%.*]] : $Int):
+// FIXME - SR-6979: We should be able to eliminate this strong_release.
+// CHECK-NEXT:  strong_release [[T0]]
+// CHECK-NEXT:  [[T1:%.*]] = tuple ()
+// CHECK-NEXT:  return [[T1]]
+// CHECK:     [[ERROR]]([[RESULT_T0:%.*]] : $Error):
+// FIXME - SR-6979: We should be able to eliminate this strong_release.
+// CHECK-NEXT:  strong_release [[T0]]
+// CHECK-NEXT:  throw [[RESULT_T0]]
+func test0() throws {
+  try rethrower(thrower)
+}
+
+// CHECK-LABEL: sil hidden @$S8rethrows5test1yyKF : $@convention(thin) () -> @error Error {
+// CHECK:       [[CLOSURE:%.*]] = function_ref @$S8rethrows5test1yyKFSiyKXEfU_ : $@convention(thin) () -> (Int, @error Error)
+// CHECK:       [[CVT:%.*]] = convert_function [[CLOSURE]]
+// CHECK:       [[T0:%.*]] = thin_to_thick_function [[CVT]]
+// CHECK:       [[RETHROWER:%.*]] = function_ref @$S8rethrows9rethroweryS2iyKXEKF : $@convention(thin) (@noescape @callee_guaranteed () -> (Int, @error Error)) -> (Int, @error Error)
+// CHECK:       try_apply [[RETHROWER]]([[T0]]) : $@convention(thin) (@noescape @callee_guaranteed () -> (Int, @error Error)) -> (Int, @error Error), normal [[NORMAL:bb1]], error [[ERROR:bb2]]
+// CHECK:     [[NORMAL]]({{%.*}} : $Int):
+// CHECK-NEXT:  [[T1:%.*]] = tuple ()
+// CHECK-NEXT:  return [[T1]]
+// CHECK:     [[ERROR]]([[ERROR:%.*]] : $Error):
+// CHECK-NEXT:  throw [[ERROR]]
+//   Closure.
+// CHECK-LABEL: sil private @$S8rethrows5test1yyKFSiyKXEfU_ : $@convention(thin) () -> (Int, @error Error) {
+// CHECK:       [[THROWER:%.*]] = function_ref @$S8rethrows7throwerSiyKF : $@convention(thin) () -> (Int, @error Error)
+// CHECK:       [[T0:%.*]] = thin_to_thick_function [[THROWER]]
+// CHECK:       [[CVT:%.*]] = convert_escape_to_noescape [[T0]]
+// CHECK:       [[RETHROWER:%.*]] = function_ref @$S8rethrows9rethroweryS2iyKXEKF : $@convention(thin) (@noescape @callee_guaranteed () -> (Int, @error Error)) -> (Int, @error Error)
+// CHECK:       try_apply [[RETHROWER]]([[CVT]]) : $@convention(thin) (@noescape @callee_guaranteed () -> (Int, @error Error)) -> (Int, @error Error), normal [[NORMAL:bb1]], error [[ERROR:bb2]]
+// CHECK:     [[NORMAL]]([[RESULT:%.*]] : $Int):
+// CHECK-NEXT:  strong_release [[T0]]
+// CHECK-NEXT:  return [[RESULT]]
+// CHECK:     [[ERROR]]([[ERROR:%.*]] : $Error):
+// CHECK-NEXT:  strong_release [[T0]]
+// CHECK-NEXT:  throw [[ERROR]]
+func test1() throws {
+  try rethrower { try rethrower(thrower) }
+}
+
+// CHECK-LABEL: sil hidden @$S8rethrows5test2yyF : $@convention(thin) () -> () {
+// CHECK:       [[NONTHROWER:%.*]] = function_ref @$S8rethrows10nonthrowerSiyF : $@convention(thin) () -> Int
+// CHECK:       [[T0:%.*]] = thin_to_thick_function [[NONTHROWER]]
+// CHECK:       [[T1:%.*]] = convert_function [[T0]] : $@callee_guaranteed () -> Int to $@callee_guaranteed () -> (Int, @error Error)
+// CHECK:       [[T2:%.*]] = convert_escape_to_noescape [[T1]]
+// CHECK:       [[RETHROWER:%.*]] = function_ref @$S8rethrows9rethroweryS2iyKXEKF : $@convention(thin) (@noescape @callee_guaranteed () -> (Int, @error Error)) -> (Int, @error Error)
+// CHECK:       try_apply [[RETHROWER]]([[T2]]) : $@convention(thin) (@noescape @callee_guaranteed () -> (Int, @error Error)) -> (Int, @error Error), normal [[NORMAL:bb1]], error [[ERROR:bb2]]
+// CHECK:     [[NORMAL]]([[T0:%.*]] : $Int):
+// CHECK-NEXT:  strong_release [[T1]]
+// CHECK-NEXT:  [[RESULT:%.*]] = tuple ()
+// CHECK-NEXT:  return [[RESULT]]
+// CHECK:     [[ERROR]]([[T0:%.*]] : $Error):
+// CHECK-NEXT:  unreachable
+func test2() {
+  rethrower(nonthrower)
+}
+
+// CHECK-LABEL: sil hidden @$S8rethrows5test3yyF : $@convention(thin) () -> () {
+// CHECK:       [[CLOSURE:%.*]] = function_ref @$S8rethrows5test3yyFSiyXEfU_ : $@convention(thin) () -> Int
+// CHECK:       [[CVT:%.*]] = convert_function [[CLOSURE]] : $@convention(thin) () -> Int to $@convention(thin) @noescape () -> Int
+// CHECK:       [[T0:%.*]] = thin_to_thick_function [[CVT]]
+// CHECK:       [[T1:%.*]] = convert_function [[T0]] : $@noescape @callee_guaranteed () -> Int to $@noescape @callee_guaranteed () -> (Int, @error Error)
+// CHECK:       [[RETHROWER:%.*]] = function_ref @$S8rethrows9rethroweryS2iyKXEKF : $@convention(thin) (@noescape @callee_guaranteed () -> (Int, @error Error)) -> (Int, @error Error)
+// CHECK:       try_apply [[RETHROWER]]([[T1]]) : $@convention(thin) (@noescape @callee_guaranteed () -> (Int, @error Error)) -> (Int, @error Error), normal [[NORMAL:bb1]], error [[ERROR:bb2]]
+// CHECK:     [[NORMAL]]({{%.*}} : $Int):
+// CHECK-NEXT:  [[RESULT:%.*]] = tuple ()
+// CHECK-NEXT:  return [[RESULT]]
+// CHECK:     [[ERROR]]([[ERROR:%.*]] : $Error):
+// CHECK-NEXT:  unreachable
+// CHECK-LABEL: // end sil function '$S8rethrows5test3yyF'
+func test3() {
+  rethrower { rethrower(nonthrower) }
+}
diff --git a/test/SILGen/plus_zero_scalar_to_tuple_args.swift b/test/SILGen/plus_zero_scalar_to_tuple_args.swift
new file mode 100644
index 0000000..b6bfb8a
--- /dev/null
+++ b/test/SILGen/plus_zero_scalar_to_tuple_args.swift
@@ -0,0 +1,82 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership %s | %FileCheck %s
+
+func inoutWithDefaults(_ x: inout Int, y: Int = 0, z: Int = 0) {}
+func inoutWithCallerSideDefaults(_ x: inout Int, y: Int = #line) {}
+
+func scalarWithDefaults(_ x: Int, y: Int = 0, z: Int = 0) {}
+func scalarWithCallerSideDefaults(_ x: Int, y: Int = #line) {}
+
+func tupleWithDefaults(x x: (Int, Int), y: Int = 0, z: Int = 0) {}
+
+func variadicFirst(_ x: Int...) {}
+func variadicSecond(_ x: Int, _ y: Int...) {}
+
+var x = 0
+// CHECK: [[X_ADDR:%.*]] = global_addr @$S20scalar_to_tuple_args1xSivp : $*Int
+// CHECK: [[DEFAULT_Y:%.*]] = apply {{.*}} : $@convention(thin) () -> Int
+// CHECK: [[DEFAULT_Z:%.*]] = apply {{.*}} : $@convention(thin) () -> Int
+// CHECK: [[WRITE:%.*]] = begin_access [modify] [dynamic] [[X_ADDR]] : $*Int
+// CHECK: [[INOUT_WITH_DEFAULTS:%.*]] = function_ref @$S20scalar_to_tuple_args17inoutWithDefaults_1y1zySiz_S2itF
+// CHECK: apply [[INOUT_WITH_DEFAULTS]]([[WRITE]], [[DEFAULT_Y]], [[DEFAULT_Z]])
+inoutWithDefaults(&x)
+
+// CHECK: [[LINE_VAL:%.*]] = integer_literal
+// CHECK: [[LINE:%.*]] = apply {{.*}}([[LINE_VAL]]
+// CHECK: [[WRITE:%.*]] = begin_access [modify] [dynamic] [[X_ADDR]] : $*Int
+// CHECK: [[INOUT_WITH_CALLER_DEFAULTS:%.*]] = function_ref @$S20scalar_to_tuple_args27inoutWithCallerSideDefaults_1yySiz_SitF
+// CHECK: apply [[INOUT_WITH_CALLER_DEFAULTS]]([[WRITE]], [[LINE]])
+inoutWithCallerSideDefaults(&x)
+
+// CHECK: [[READ:%.*]] = begin_access [read] [dynamic] [[X_ADDR]] : $*Int
+// CHECK: [[X:%.*]] = load [trivial] [[READ]]
+// CHECK: [[DEFAULT_Y:%.*]] = apply {{.*}} : $@convention(thin) () -> Int
+// CHECK: [[DEFAULT_Z:%.*]] = apply {{.*}} : $@convention(thin) () -> Int
+// CHECK: [[SCALAR_WITH_DEFAULTS:%.*]] = function_ref @$S20scalar_to_tuple_args0A12WithDefaults_1y1zySi_S2itF
+// CHECK: apply [[SCALAR_WITH_DEFAULTS]]([[X]], [[DEFAULT_Y]], [[DEFAULT_Z]])
+scalarWithDefaults(x)
+
+// CHECK: [[X:%.*]] = load [trivial] [[X_ADDR]]
+// CHECK: [[LINE_VAL:%.*]] = integer_literal
+// CHECK: [[LINE:%.*]] = apply {{.*}}([[LINE_VAL]]
+// CHECK: [[SCALAR_WITH_CALLER_DEFAULTS:%.*]] = function_ref @$S20scalar_to_tuple_args0A22WithCallerSideDefaults_1yySi_SitF
+// CHECK: apply [[SCALAR_WITH_CALLER_DEFAULTS]]([[X]], [[LINE]])
+scalarWithCallerSideDefaults(x)
+
+// CHECK: [[READ:%.*]] = begin_access [read] [dynamic] [[X_ADDR]] : $*Int
+// CHECK: [[X1:%.*]] = load [trivial] [[READ]]
+// CHECK: [[READ:%.*]] = begin_access [read] [dynamic] [[X_ADDR]] : $*Int
+// CHECK: [[X2:%.*]] = load [trivial] [[READ]]
+// CHECK: [[DEFAULT_Y:%.*]] = apply {{.*}} : $@convention(thin) () -> Int
+// CHECK: [[DEFAULT_Z:%.*]] = apply {{.*}} : $@convention(thin) () -> Int
+// CHECK: [[TUPLE_WITH_DEFAULTS:%.*]] = function_ref @$S20scalar_to_tuple_args0C12WithDefaults1x1y1zySi_Sit_S2itF
+// CHECK: apply [[TUPLE_WITH_DEFAULTS]]([[X1]], [[X2]], [[DEFAULT_Y]], [[DEFAULT_Z]])
+tupleWithDefaults(x: (x,x))
+
+// CHECK: [[ALLOC_ARRAY:%.*]] = apply {{.*}} -> (@owned Array<τ_0_0>, Builtin.RawPointer)
+// CHECK: [[BORROWED_ALLOC_ARRAY:%.*]] = begin_borrow [[ALLOC_ARRAY]]
+// CHECK: [[BORROWED_ARRAY:%.*]] = tuple_extract [[BORROWED_ALLOC_ARRAY]] {{.*}}, 0
+// CHECK: [[ARRAY:%.*]] = copy_value [[BORROWED_ARRAY]]
+// CHECK: [[MEMORY:%.*]] = tuple_extract [[BORROWED_ALLOC_ARRAY]] {{.*}}, 1
+// CHECK: end_borrow [[BORROWED_ALLOC_ARRAY]] from [[ALLOC_ARRAY]]
+// CHECK: destroy_value [[ALLOC_ARRAY]]
+// CHECK: [[ADDR:%.*]] = pointer_to_address [[MEMORY]]
+// CHECK: [[READ:%.*]] = begin_access [read] [dynamic] [[X_ADDR]] : $*Int
+// CHECK: [[X:%.*]] = load [trivial] [[READ]]
+// CHECK: store [[X]] to [trivial] [[ADDR]]
+// CHECK: [[BORROWED_ARRAY:%.*]] = begin_borrow [[ARRAY]]
+// CHECK: [[VARIADIC_FIRST:%.*]] = function_ref @$S20scalar_to_tuple_args13variadicFirstyySid_tF
+// CHECK: apply [[VARIADIC_FIRST]]([[BORROWED_ARRAY]])
+variadicFirst(x)
+
+// CHECK: [[ALLOC_ARRAY:%.*]] = apply {{.*}} -> (@owned Array<τ_0_0>, Builtin.RawPointer)
+// CHECK: [[BORROWED_ALLOC_ARRAY:%.*]] = begin_borrow [[ALLOC_ARRAY]]
+// CHECK: [[BORROWED_ARRAY:%.*]] = tuple_extract [[BORROWED_ALLOC_ARRAY]] {{.*}}, 0
+// CHECK: [[ARRAY:%.*]] = copy_value [[BORROWED_ARRAY]]
+// CHECK: end_borrow [[BORROWED_ALLOC_ARRAY]] from [[ALLOC_ARRAY]]
+// CHECK: [[READ:%.*]] = begin_access [read] [dynamic] [[X_ADDR]] : $*Int
+// CHECK: [[X:%.*]] = load [trivial] [[READ]]
+// CHECK: [[BORROWED_ARRAY:%.*]] = begin_borrow [[ARRAY]]
+// CHECK: [[VARIADIC_SECOND:%.*]] = function_ref @$S20scalar_to_tuple_args14variadicSecondyySi_SidtF
+// CHECK: apply [[VARIADIC_SECOND]]([[X]], [[BORROWED_ARRAY]])
+variadicSecond(x)
diff --git a/test/SILGen/plus_zero_shared.swift b/test/SILGen/plus_zero_shared.swift
new file mode 100644
index 0000000..46ec6da
--- /dev/null
+++ b/test/SILGen/plus_zero_shared.swift
@@ -0,0 +1,184 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -Xllvm -sil-full-demangle -emit-silgen %s -disable-objc-attr-requires-foundation-module -enable-sil-ownership | %FileCheck %s
+
+// REQUIRES: owned_parameters
+
+class RefAggregate {}
+struct ValueAggregate { let x = RefAggregate() }
+
+
+// CHECK-LABEL: sil hidden @$S6shared0A10_arguments7trivial5value3refySih_AA14ValueAggregateVhAA03RefG0ChtF : $@convention(thin) (Int, @guaranteed ValueAggregate, @guaranteed RefAggregate) -> ()
+func shared_arguments(trivial : __shared Int, value : __shared ValueAggregate, ref : __shared RefAggregate) {
+  // CHECK: bb0([[TRIVIAL_VAL:%[0-9]+]] : @trivial $Int, [[VALUE_VAL:%[0-9]+]] : @guaranteed $ValueAggregate, [[REF_VAL:%[0-9]+]] : @guaranteed $RefAggregate):
+  // CHECK: [[COPY_VALUE_VAL:%[0-9]+]] = copy_value [[VALUE_VAL]] : $ValueAggregate
+  // CHECK: [[COPY_REF_VAL:%[0-9]+]] = copy_value [[REF_VAL]] : $RefAggregate
+  // CHECK: [[OWNED_FUNC:%[0-9]+]] = function_ref @$S6shared15owned_arguments7trivial5value3refySi_AA14ValueAggregateVAA03RefH0CtF
+  // CHECK: {{%.*}} = apply [[OWNED_FUNC]]([[TRIVIAL_VAL]], [[COPY_VALUE_VAL]], [[COPY_REF_VAL]]) : $@convention(thin) (Int, @owned ValueAggregate, @owned RefAggregate) -> ()
+  // CHECK: } // end sil function '$S6shared0A10_arguments7trivial5value3refySih_AA14ValueAggregateVhAA03RefG0ChtF'
+  return owned_arguments(trivial: trivial, value: value, ref: ref)
+}
+
+// CHECK-LABEL: sil hidden @$S6shared15owned_arguments7trivial5value3refySi_AA14ValueAggregateVAA03RefH0CtF : $@convention(thin) (Int, @owned ValueAggregate, @owned RefAggregate) -> ()
+func owned_arguments(trivial : Int, value : ValueAggregate, ref : RefAggregate) {
+  // CHECK: bb0([[TRIVIAL_VAL:%[0-9]+]] : @trivial $Int, [[VALUE_VAL:%[0-9]+]] : @owned $ValueAggregate, [[REF_VAL:%[0-9]+]] : @owned $RefAggregate):
+  // CHECK: [[BORROW_VALUE_VAL:%[0-9]+]] = begin_borrow [[VALUE_VAL]] : $ValueAggregate
+  // CHECK: [[BORROW_REF_VAL:%[0-9]+]] = begin_borrow [[REF_VAL]] : $RefAggregate
+  // CHECK: [[SHARED_FUNC:%[0-9]+]] = function_ref @$S6shared0A10_arguments7trivial5value3refySih_AA14ValueAggregateVhAA03RefG0ChtF
+  // CHECK: {{%.*}} = apply [[SHARED_FUNC]]([[TRIVIAL_VAL]], [[BORROW_VALUE_VAL]], [[BORROW_REF_VAL]])
+  // CHECK: end_borrow [[BORROW_REF_VAL]] from [[REF_VAL]] : $RefAggregate, $RefAggregate
+  // CHECK: end_borrow [[BORROW_VALUE_VAL]] from [[VALUE_VAL]] : $ValueAggregate, $ValueAggregate
+  // CHECK: destroy_value [[REF_VAL]] : $RefAggregate
+  // CHECK: destroy_value [[VALUE_VAL]] : $ValueAggregate
+  // CHECK: } // end sil function '$S6shared15owned_arguments7trivial5value3refySi_AA14ValueAggregateVAA03RefH0CtF'
+  return shared_arguments(trivial: trivial, value: value, ref: ref)
+}
+
+// CHECK-LABEL: sil hidden @$S6shared0A17_argument_capture7trivial5value3refySih_AA14ValueAggregateVhAA03RefH0ChtF : $@convention(thin) (Int, @guaranteed ValueAggregate, @guaranteed RefAggregate) -> ()
+func shared_argument_capture(trivial : __shared Int, value : __shared ValueAggregate, ref : __shared RefAggregate) {
+  // CHECK: bb0([[TRIVIAL_VAL:%[0-9]+]] : @trivial $Int, [[VALUE_VAL:%[0-9]+]] : @guaranteed $ValueAggregate, [[REF_VAL:%[0-9]+]] : @guaranteed $RefAggregate):
+  // CHECK: [[CLO_1:%[0-9]+]] = function_ref @$S6shared0A17_argument_capture7trivial5value3refySih_AA14ValueAggregateVhAA03RefH0ChtFyyXEfU_
+  // CHECK: {{%.*}} = apply [[CLO_1]]([[TRIVIAL_VAL]], [[VALUE_VAL]], [[REF_VAL]]) : $@convention(thin) (Int, @guaranteed ValueAggregate, @guaranteed RefAggregate) -> ()
+  _ = {
+    return shared_arguments(trivial: trivial, value: value, ref: ref)
+  }()
+  
+  // CHECK: [[CLO_2:%[0-9]+]] = function_ref @$S6shared0A17_argument_capture7trivial5value3refySih_AA14ValueAggregateVhAA03RefH0ChtFyyXEfU0_ : $@convention(thin) (Int, @guaranteed ValueAggregate, @guaranteed RefAggregate) -> ()
+  // CHECK: {{%.*}} = apply [[CLO_2]]([[TRIVIAL_VAL]], [[VALUE_VAL]], [[REF_VAL]]) : $@convention(thin) (Int, @guaranteed ValueAggregate, @guaranteed RefAggregate) -> ()
+  _ = {
+    return owned_arguments(trivial: trivial, value: value, ref: ref)
+  }()
+  
+  // CHECK: } // end sil function '$S6shared0A17_argument_capture7trivial5value3refySih_AA14ValueAggregateVhAA03RefH0ChtF'
+  
+  // ======== FIRST CLOSURE ==========
+
+  // CHECK-LABEL: sil private @$S6shared0A17_argument_capture7trivial5value3refySih_AA14ValueAggregateVhAA03RefH0ChtFyyXEfU_ : $@convention(thin) (Int, @guaranteed ValueAggregate, @guaranteed RefAggregate) -> ()
+  // CHECK: bb0([[TRIVIAL_VAL:%[0-9]+]] : @trivial $Int, [[VALUE_VAL:%[0-9]+]] : @guaranteed $ValueAggregate, [[REF_VAL:%[0-9]+]] : @guaranteed $RefAggregate):
+  // CHECK: [[SHARED_CALL:%[0-9]+]] = function_ref @$S6shared0A10_arguments7trivial5value3refySih_AA14ValueAggregateVhAA03RefG0ChtF : $@convention(thin) (Int, @guaranteed ValueAggregate, @guaranteed RefAggregate) -> ()
+  // CHECK: {{%.*}} = apply [[SHARED_CALL]]([[TRIVIAL_VAL]], [[VALUE_VAL]], [[REF_VAL]]) : $@convention(thin) (Int, @guaranteed ValueAggregate, @guaranteed RefAggregate) -> ()
+  // CHECK: } // end sil function '$S6shared0A17_argument_capture7trivial5value3refySih_AA14ValueAggregateVhAA03RefH0ChtFyyXEfU_'
+  
+  // ======== SECOND CLOSURE ==========
+  
+  // CHECK-LABEL:  sil private @$S6shared0A17_argument_capture7trivial5value3refySih_AA14ValueAggregateVhAA03RefH0ChtFyyXEfU0_ : $@convention(thin) (Int, @guaranteed ValueAggregate, @guaranteed RefAggregate) -> () {
+  // CHECK: bb0([[TRIVIAL_VAL:%[0-9]+]] : @trivial $Int, [[VALUE_VAL:%[0-9]+]] : @guaranteed $ValueAggregate, [[REF_VAL:%[0-9]+]] : @guaranteed $RefAggregate):
+  // CHECK: [[COPY_BORROW_VALUE_VAL:%[0-9]+]] = copy_value [[VALUE_VAL]] : $ValueAggregate
+  // CHECK: [[COPY_BORROW_REF_VAL:%[0-9]+]] = copy_value [[REF_VAL]] : $RefAggregate
+  // CHECK: [[OWNED_CALL:%[0-9]+]] = function_ref @$S6shared15owned_arguments7trivial5value3refySi_AA14ValueAggregateVAA03RefH0CtF : $@convention(thin) (Int, @owned ValueAggregate, @owned RefAggregate) -> ()
+  // CHECK: {{%.*}} = apply [[OWNED_CALL]]([[TRIVIAL_VAL]], [[COPY_BORROW_VALUE_VAL]], [[COPY_BORROW_REF_VAL]]) : $@convention(thin) (Int, @owned ValueAggregate, @owned RefAggregate) -> ()
+  // CHECK: } // end sil function '$S6shared0A17_argument_capture7trivial5value3refySih_AA14ValueAggregateVhAA03RefH0ChtFyyXEfU0_'
+}
+
+// CHECK-LABEL: sil hidden @$S6shared0A20_to_owned_conversionyyySih_AA14ValueAggregateVhAA03RefF0ChtXEF : $@convention(thin) (@noescape @callee_guaranteed (Int, @guaranteed ValueAggregate, @guaranteed RefAggregate) -> ()) -> ()
+func shared_to_owned_conversion(_ f : (__shared Int, __shared ValueAggregate, __shared RefAggregate) -> Void) {
+  // CHECK: bb0([[UNUSED_FUNC:%[0-9]+]] : @trivial $@noescape @callee_guaranteed (Int, @guaranteed ValueAggregate, @guaranteed RefAggregate) -> ()):
+  // CHECK: [[OWNED_THUNK:%[0-9]+]] = function_ref @$S6shared0A20_to_owned_conversionyyySih_AA14ValueAggregateVhAA03RefF0ChtXEFySi_AdFtXEfU_ : $@convention(thin) (Int, @owned ValueAggregate, @owned RefAggregate) -> ()
+  // CHECK: [[CONVERT:%.*]] = convert_function [[OWNED_THUNK]]
+  // CHECK: [[THICK_OWNED_THUNK:%[0-9]+]] = thin_to_thick_function [[CONVERT]] : $@convention(thin) @noescape (Int, @owned ValueAggregate, @owned RefAggregate) -> () to $@noescape @callee_guaranteed (Int, @owned ValueAggregate, @owned RefAggregate) -> ()
+  // CHECK: [[GUARANTEED_TO_OWNED_THUNK:%[0-9]+]] =  function_ref @$SSi6shared14ValueAggregateVAA03RefC0CIgyxx_SiAcEIegygg_TR : $@convention(thin) (Int, @guaranteed ValueAggregate, @guaranteed RefAggregate, @noescape @callee_guaranteed (Int, @owned ValueAggregate, @owned RefAggregate) -> ()) -> ()
+  // CHECK: [[APPLIED_THUNK:%[0-9]+]] = partial_apply [callee_guaranteed] [[GUARANTEED_TO_OWNED_THUNK]]([[THICK_OWNED_THUNK]]) : $@convention(thin) (Int, @guaranteed ValueAggregate, @guaranteed RefAggregate, @noescape @callee_guaranteed (Int, @owned ValueAggregate, @owned RefAggregate) -> ()) -> ()
+  // CHECK: [[CONVERT:%.*]] = convert_escape_to_noescape [[APPLIED_THUNK]]
+  // CHECK: [[RECUR_FN:%[0-9]+]] = function_ref @$S6shared0A20_to_owned_conversionyyySih_AA14ValueAggregateVhAA03RefF0ChtXEF : $@convention(thin) (@noescape @callee_guaranteed (Int, @guaranteed ValueAggregate, @guaranteed RefAggregate) -> ()) -> ()
+  // CHECK: {{%.*}} = apply [[RECUR_FN]]([[CONVERT]]) : $@convention(thin) (@noescape @callee_guaranteed (Int, @guaranteed ValueAggregate, @guaranteed RefAggregate) -> ()) -> ()
+  // CHECK-NOT: destroy_value [[UNUSED_FUNC]]
+  // CHECK: } // end sil function '$S6shared0A20_to_owned_conversionyyySih_AA14ValueAggregateVhAA03RefF0ChtXEF'
+  
+  // ======== REABSTRACTION THUNK =========
+  
+  // CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] @$SSi6shared14ValueAggregateVAA03RefC0CIgyxx_SiAcEIegygg_TR : $@convention(thin) (Int, @guaranteed ValueAggregate, @guaranteed RefAggregate, @noescape @callee_guaranteed (Int, @owned ValueAggregate, @owned RefAggregate) -> ()) -> ()
+  // CHECK: bb0([[TRIVIAL_VAL:%[0-9]+]] : @trivial $Int, [[VALUE_VAL:%[0-9]+]] : @guaranteed $ValueAggregate, [[REF_VAL:%[0-9]+]] : @guaranteed $RefAggregate, [[FUNC:%[0-9]+]] : @trivial $@noescape @callee_guaranteed (Int, @owned ValueAggregate, @owned RefAggregate) -> ()):
+  // CHECK: [[COPY_VALUE_VAL:%[0-9]+]] = copy_value [[VALUE_VAL]] : $ValueAggregate
+  // CHECK: [[COPY_REF_VAL:%[0-9]+]] = copy_value [[REF_VAL]] : $RefAggregate
+  // CHECK: {{%.*}} = apply [[FUNC]]([[TRIVIAL_VAL]], [[COPY_VALUE_VAL]], [[COPY_REF_VAL]]) : $@noescape @callee_guaranteed (Int, @owned ValueAggregate, @owned RefAggregate) -> ()
+  // CHECK: } // end sil function '$SSi6shared14ValueAggregateVAA03RefC0CIgyxx_SiAcEIegygg_TR'
+  
+  return shared_to_owned_conversion { (trivial : Int, val : ValueAggregate, ref : RefAggregate) in }
+}
+
+// CHECK-LABEL: sil hidden @$S6shared09owned_to_A11_conversionyyySi_AA14ValueAggregateVAA03RefF0CtXEF : $@convention(thin) (@noescape @callee_guaranteed (Int, @owned ValueAggregate, @owned RefAggregate) -> ()) -> ()
+func owned_to_shared_conversion(_ f : (Int, ValueAggregate, RefAggregate) -> Void) {
+  // CHECK: bb0([[UNUSED_FUNC:%[0-9]+]] : @trivial $@noescape @callee_guaranteed (Int, @owned ValueAggregate, @owned RefAggregate) -> ()):
+  // CHECK: [[SHARED_THUNK:%[0-9]+]] = function_ref @$S6shared09owned_to_A11_conversionyyySi_AA14ValueAggregateVAA03RefF0CtXEFySih_ADhAFhtXEfU_ : $@convention(thin) (Int, @guaranteed ValueAggregate, @guaranteed RefAggregate) -> ()
+  // CHECK: [[CONVERT:%.*]] = convert_function [[SHARED_THUNK]]
+  // CHECK: [[THICK_SHARED_THUNK:%[0-9]+]] = thin_to_thick_function [[CONVERT]] : $@convention(thin) @noescape (Int, @guaranteed ValueAggregate, @guaranteed RefAggregate) -> () to $@noescape @callee_guaranteed (Int, @guaranteed ValueAggregate, @guaranteed RefAggregate) -> ()
+  // CHECK: [[OWNED_TO_GUARANTEED_THUNK:%[0-9]+]] = function_ref @$SSi6shared14ValueAggregateVAA03RefC0CIgygg_SiAcEIegyxx_TR : $@convention(thin) (Int, @owned ValueAggregate, @owned RefAggregate, @noescape @callee_guaranteed (Int, @guaranteed ValueAggregate, @guaranteed RefAggregate) -> ()) -> ()
+  // CHECK: [[APPLIED_THUNK:%[0-9]+]] = partial_apply [callee_guaranteed] [[OWNED_TO_GUARANTEED_THUNK]]([[THICK_SHARED_THUNK]]) : $@convention(thin) (Int, @owned ValueAggregate, @owned RefAggregate, @noescape @callee_guaranteed (Int, @guaranteed ValueAggregate, @guaranteed RefAggregate) -> ()) -> ()
+  // CHECK: [[CONVERT:%.*]] = convert_escape_to_noescape [[APPLIED_THUNK]]
+  // CHECK: [[RECUR_FN:%[0-9]+]] = function_ref @$S6shared09owned_to_A11_conversionyyySi_AA14ValueAggregateVAA03RefF0CtXEF : $@convention(thin) (@noescape @callee_guaranteed (Int, @owned ValueAggregate, @owned RefAggregate) -> ()) -> ()
+  // CHECK: {{%.*}} = apply [[RECUR_FN]]([[CONVERT]]) : $@convention(thin) (@noescape @callee_guaranteed (Int, @owned ValueAggregate, @owned RefAggregate) -> ()) -> ()
+  // CHECK-NOT: destroy_value [[UNUSED_FUNC]]
+  // CHECK: } // end sil function '$S6shared09owned_to_A11_conversionyyySi_AA14ValueAggregateVAA03RefF0CtXEF'
+
+  // ======== REABSTRACTION THUNK =========
+
+  // CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] @$SSi6shared14ValueAggregateVAA03RefC0CIgygg_SiAcEIegyxx_TR : $@convention(thin) (Int, @owned ValueAggregate, @owned RefAggregate, @noescape @callee_guaranteed (Int, @guaranteed ValueAggregate, @guaranteed RefAggregate) -> ()) -> ()
+  // CHECK: bb0([[TRIVIAL_VAL:%[0-9]+]] : @trivial $Int, [[VALUE_VAL:%[0-9]+]] : @owned $ValueAggregate, [[REF_VAL:%[0-9]+]] : @owned $RefAggregate, [[FUNC:%[0-9]+]] : @trivial $@noescape @callee_guaranteed (Int, @guaranteed ValueAggregate, @guaranteed RefAggregate) -> ()):
+  // CHECK: [[BORROW_VALUE_VAL:%[0-9]+]] = begin_borrow [[VALUE_VAL]] : $ValueAggregate
+  // CHECK: [[BORROW_REF_VAL:%[0-9]+]] = begin_borrow [[REF_VAL]] : $RefAggregate
+  // CHECK: {{%.*}} = apply [[FUNC]]([[TRIVIAL_VAL]], [[BORROW_VALUE_VAL]], [[BORROW_REF_VAL]]) : $@noescape @callee_guaranteed (Int, @guaranteed ValueAggregate, @guaranteed RefAggregate) -> ()
+  // CHECK: end_borrow [[BORROW_REF_VAL]] from [[REF_VAL]] : $RefAggregate, $RefAggregate
+  // CHECK: end_borrow [[BORROW_VALUE_VAL]] from [[VALUE_VAL]] : $ValueAggregate, $ValueAggregate
+  // CHECK: destroy_value [[REF_VAL]] : $RefAggregate
+  // CHECK: destroy_value [[VALUE_VAL]] : $ValueAggregate
+  // CHECK: } // end sil function '$SSi6shared14ValueAggregateVAA03RefC0CIgygg_SiAcEIegyxx_TR'
+  
+  return owned_to_shared_conversion { (trivial : __shared Int, val : __shared ValueAggregate, ref : __shared RefAggregate) in }
+}
+
+// CHECK-LABEL: sil hidden @$S6shared0A17_closure_loweringyyySi_AA14ValueAggregateVAA03RefE0CtchF : $@convention(thin) (@guaranteed @callee_guaranteed (Int, @owned ValueAggregate, @owned RefAggregate) -> ()) -> ()
+func shared_closure_lowering(_ f : __shared (Int, ValueAggregate, RefAggregate) -> Void) {}
+
+struct Foo {
+    var x: ValueAggregate
+
+    // CHECK-LABEL: sil hidden @$S6shared3FooV21methodSharedArguments7trivial5value3refySih_AA14ValueAggregateVhAA03RefJ0ChtF : $@convention(method) (Int, @guaranteed ValueAggregate, @guaranteed RefAggregate, @guaranteed Foo) -> () {
+    func methodSharedArguments(trivial : __shared Int, value : __shared ValueAggregate, ref : __shared RefAggregate) {
+        // CHECK: bb0([[TRIVIAL_VAL:%[0-9]+]] : @trivial $Int, [[VALUE_VAL:%[0-9]+]] : @guaranteed $ValueAggregate, [[REF_VAL:%[0-9]+]] : @guaranteed $RefAggregate, [[SELF:%[0-9]+]] : @guaranteed $Foo):
+        // CHECK: [[COPY_VALUE_VAL:%[0-9]+]] = copy_value [[VALUE_VAL]] : $ValueAggregate
+        // CHECK: [[COPY_REF_VAL:%[0-9]+]] = copy_value [[REF_VAL]] : $RefAggregate
+        // CHECK: [[OWNED_FUNC:%[0-9]+]] = function_ref @$S6shared3FooV20methodOwnedArguments7trivial5value3refySi_AA14ValueAggregateVAA03RefJ0CtF
+        // CHECK: {{%.*}} = apply [[OWNED_FUNC]]([[TRIVIAL_VAL]], [[COPY_VALUE_VAL]], [[COPY_REF_VAL]], [[SELF]]) : $@convention(method) (Int, @owned ValueAggregate, @owned RefAggregate, @guaranteed Foo) -> ()
+        // CHECK: } // end sil function '$S6shared3FooV21methodSharedArguments7trivial5value3refySih_AA14ValueAggregateVhAA03RefJ0ChtF'
+        return methodOwnedArguments(trivial: trivial, value: value, ref: ref)
+    }
+
+    // CHECK-LABEL: sil hidden @$S6shared3FooV20methodOwnedArguments7trivial5value3refySi_AA14ValueAggregateVAA03RefJ0CtF : $@convention(method) (Int, @owned ValueAggregate, @owned RefAggregate, @guaranteed Foo) -> () {
+    func methodOwnedArguments(trivial : Int, value : ValueAggregate, ref : RefAggregate) {
+        // CHECK: bb0([[TRIVIAL_VAL:%[0-9]+]] : @trivial $Int, [[VALUE_VAL:%[0-9]+]] : @owned $ValueAggregate, [[REF_VAL:%[0-9]+]] : @owned $RefAggregate, [[SELF:%[0-9]+]] : @guaranteed $Foo):
+        // CHECK: [[BORROW_VALUE_VAL:%[0-9]+]] = begin_borrow [[VALUE_VAL]] : $ValueAggregate
+        // CHECK: [[BORROW_REF_VAL:%[0-9]+]] = begin_borrow [[REF_VAL]] : $RefAggregate
+        // CHECK: [[SHARED_FUNC:%[0-9]+]] = function_ref @$S6shared3FooV21methodSharedArguments7trivial5value3refySih_AA14ValueAggregateVhAA03RefJ0ChtF
+        // CHECK: {{%.*}} = apply [[SHARED_FUNC]]([[TRIVIAL_VAL]], [[BORROW_VALUE_VAL]], [[BORROW_REF_VAL]], [[SELF]])
+        // CHECK: end_borrow [[BORROW_REF_VAL]] from [[REF_VAL]] : $RefAggregate, $RefAggregate
+        // CHECK: end_borrow [[BORROW_VALUE_VAL]] from [[VALUE_VAL]] : $ValueAggregate, $ValueAggregate
+        // CHECK: destroy_value [[REF_VAL]] : $RefAggregate
+        // CHECK: destroy_value [[VALUE_VAL]] : $ValueAggregate
+        // CHECK: } // end sil function '$S6shared3FooV20methodOwnedArguments7trivial5value3refySi_AA14ValueAggregateVAA03RefJ0CtF'
+        return methodSharedArguments(trivial: trivial, value: value, ref: ref)
+    }
+
+    // CHECK-LABEL: sil hidden @$S6shared3FooV21staticSharedArguments7trivial5value3refySih_AA14ValueAggregateVhAA03RefJ0ChtFZ : $@convention(method) (Int, @guaranteed ValueAggregate, @guaranteed RefAggregate, @thin Foo.Type) -> () {
+    static func staticSharedArguments(trivial : __shared Int, value : __shared ValueAggregate, ref : __shared RefAggregate) {
+        // CHECK: bb0([[TRIVIAL_VAL:%[0-9]+]] : @trivial $Int, [[VALUE_VAL:%[0-9]+]] : @guaranteed $ValueAggregate, [[REF_VAL:%[0-9]+]] : @guaranteed $RefAggregate, [[SELF_METATYPE:%[0-9]+]] : @trivial $@thin Foo.Type):
+        // CHECK: [[COPY_VALUE_VAL:%[0-9]+]] = copy_value [[VALUE_VAL]] : $ValueAggregate
+        // CHECK: [[COPY_REF_VAL:%[0-9]+]] = copy_value [[REF_VAL]] : $RefAggregate
+        // CHECK: [[OWNED_FUNC:%[0-9]+]] = function_ref @$S6shared3FooV20staticOwnedArguments7trivial5value3refySi_AA14ValueAggregateVAA03RefJ0CtFZ
+        // CHECK: {{%.*}} = apply [[OWNED_FUNC]]([[TRIVIAL_VAL]], [[COPY_VALUE_VAL]], [[COPY_REF_VAL]], [[SELF_METATYPE]]) : $@convention(method) (Int, @owned ValueAggregate, @owned RefAggregate, @thin Foo.Type) -> ()
+        // CHECK: } // end sil function '$S6shared3FooV21staticSharedArguments7trivial5value3refySih_AA14ValueAggregateVhAA03RefJ0ChtFZ'
+        return staticOwnedArguments(trivial: trivial, value: value, ref: ref)
+    }
+    // CHECK-LABEL: sil hidden @$S6shared3FooV20staticOwnedArguments7trivial5value3refySi_AA14ValueAggregateVAA03RefJ0CtFZ : $@convention(method) (Int, @owned ValueAggregate, @owned RefAggregate, @thin Foo.Type) -> () {
+    static func staticOwnedArguments(trivial : Int, value : ValueAggregate, ref : RefAggregate) {
+        // CHECK: bb0([[TRIVIAL_VAL:%[0-9]+]] : @trivial $Int, [[VALUE_VAL:%[0-9]+]] : @owned $ValueAggregate, [[REF_VAL:%[0-9]+]] : @owned $RefAggregate, [[SELF_METATYPE:%[0-9]+]] : @trivial $@thin Foo.Type):
+        // CHECK: [[BORROW_VALUE_VAL:%[0-9]+]] = begin_borrow [[VALUE_VAL]] : $ValueAggregate
+        // CHECK: [[BORROW_REF_VAL:%[0-9]+]] = begin_borrow [[REF_VAL]] : $RefAggregate
+        // CHECK: [[SHARED_FUNC:%[0-9]+]] = function_ref @$S6shared3FooV21staticSharedArguments7trivial5value3refySih_AA14ValueAggregateVhAA03RefJ0ChtFZ
+        // CHECK: {{%.*}} = apply [[SHARED_FUNC]]([[TRIVIAL_VAL]], [[BORROW_VALUE_VAL]], [[BORROW_REF_VAL]], [[SELF_METATYPE]])
+        // CHECK: end_borrow [[BORROW_REF_VAL]] from [[REF_VAL]] : $RefAggregate, $RefAggregate
+        // CHECK: end_borrow [[BORROW_VALUE_VAL]] from [[VALUE_VAL]] : $ValueAggregate, $ValueAggregate
+        // CHECK: destroy_value [[REF_VAL]] : $RefAggregate
+        // CHECK: destroy_value [[VALUE_VAL]] : $ValueAggregate
+        // CHECK: } // end sil function '$S6shared3FooV20staticOwnedArguments7trivial5value3refySi_AA14ValueAggregateVAA03RefJ0CtFZ'
+        return staticSharedArguments(trivial: trivial, value: value, ref: ref)
+    }
+}
diff --git a/test/SILGen/plus_zero_sil_locations.swift b/test/SILGen/plus_zero_sil_locations.swift
new file mode 100644
index 0000000..19f9b55
--- /dev/null
+++ b/test/SILGen/plus_zero_sil_locations.swift
@@ -0,0 +1,400 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -emit-silgen -Xllvm -sil-print-debuginfo -emit-verbose-sil -enable-sil-ownership %s | %FileCheck %s
+
+// FIXME: Not sure if this an ideal source info for the branch - 
+// it points to if, not the last instruction in the block.
+func ifexpr() -> Int {
+  var x : Int = 0
+  if true {
+    x+=1
+  }
+  return x
+  // CHECK-LABEL: sil hidden @$S13sil_locations6ifexprSiyF
+  // CHECK: apply {{.*}}, loc "{{.*}}":[[@LINE-5]]:6
+  // CHECK: cond_br {{%.*}}, [[TRUE_BB:bb[0-9]+]], [[FALSE_BB:bb[0-9]+]], loc "{{.*}}":[[@LINE-6]]:6
+  // CHECK: br [[FALSE_BB]], loc "{{.*}}":[[@LINE-5]]:3
+  // CHECK: return {{.*}}, loc "{{.*}}":[[@LINE-5]]:3, {{.*}}:return
+}
+
+func ifelseexpr() -> Int {
+  var x : Int = 0
+  if true {
+    x+=1
+  } else {
+    x-=1
+  }
+  return x
+  // CHECK-LABEL: sil hidden @$S13sil_locations10ifelseexprSiyF
+  // CHECK: cond_br {{%.*}}, [[TRUE_BB:bb[0-9]+]], [[FALSE_BB:bb[0-9]+]], loc "{{.*}}":[[@LINE-7]]:6
+  // CHECK: [[TRUE_BB]]:
+  // CHECK: br bb{{[0-9]+}}, loc "{{.*}}":[[@LINE-7]]:3
+  // CHECK: [[FALSE_BB]]:
+  // CHECK: br bb{{[0-9]+}}, loc "{{.*}}":[[@LINE-7]]:3
+  // CHECK: return {{.*}}, loc "{{.*}}":[[@LINE-7]]:3, {{.*}}:return
+}
+
+// The source locations are handled differently here - since 
+// the return is unified, we keep the location of the return(not the if) 
+// in the branch.
+func ifexpr_return() -> Int {
+  if true {
+    return 5
+  }
+  return 6
+  // CHECK-LABEL: sil hidden @$S13sil_locations13ifexpr_returnSiyF
+  // CHECK: apply {{.*}}, loc "{{.*}}":[[@LINE-5]]:6
+  // CHECK: cond_br {{%.*}}, [[TRUE_BB:bb[0-9]+]], [[FALSE_BB:bb[0-9]+]], loc "{{.*}}":[[@LINE-6]]:6
+  // CHECK: [[TRUE_BB]]:
+  // CHECK: br bb{{[0-9]+}}({{%.*}}), loc "{{.*}}":[[@LINE-7]]:5, {{.*}}:return
+  // CHECK: [[FALSE_BB]]:
+  // CHECK: br bb{{[0-9]+}}({{%.*}}), loc "{{.*}}":[[@LINE-7]]:3, {{.*}}:return
+  // CHECK: return {{.*}}, loc "{{.*}}":[[@LINE+1]]:1, {{.*}}:cleanup
+}
+
+func ifexpr_rval() -> Int {
+  var x = true ? 5 : 6
+  return x
+  // CHECK-LABEL: sil hidden @$S13sil_locations11ifexpr_rvalSiyF
+  // CHECK: apply {{.*}}, loc "{{.*}}":[[@LINE-3]]:11
+  // CHECK: cond_br {{%.*}}, [[TRUE_BB:bb[0-9]+]], [[FALSE_BB:bb[0-9]+]], loc "{{.*}}":[[@LINE-4]]:11
+  // CHECK: [[TRUE_BB]]:
+  // CHECK: br bb{{[0-9]+}}({{%.*}}), loc "{{.*}}":[[@LINE-6]]:18
+  // CHECK: [[FALSE_BB]]:
+  // CHECK: br bb{{[0-9]+}}({{%.*}}), loc "{{.*}}":[[@LINE-8]]:22
+}
+
+// --- Test function calls.
+func simpleDirectCallTest(_ i: Int) -> Int {
+  return simpleDirectCallTest(i)
+  // CHECK-LABEL: sil hidden @$S13sil_locations20simpleDirectCallTestyS2iF
+  // CHECK: function_ref @$S13sil_locations20simpleDirectCallTestyS2iF : {{.*}}, loc "{{.*}}":[[@LINE-2]]:10
+  // CHECK: {{%.*}} apply {{%.*}} line:[[@LINE-3]]:10
+}
+
+func templateTest<T>(_ value: T) -> T {
+  return value
+}
+func useTemplateTest() -> Int {
+  return templateTest(5);
+  // CHECK-LABEL: sil hidden @$S13sil_locations15useTemplateTestSiyF
+  // CHECK: function_ref @$SSi2{{[_0-9a-zA-Z]*}}fC :{{.*}}, loc "{{.*}}":77
+}
+
+func foo(_ x: Int) -> Int {
+  func bar(_ y: Int) -> Int {
+    return x + y
+  }
+  return bar(1)
+  // CHECK-LABEL: sil hidden @$S13sil_locations3foo{{[_0-9a-zA-Z]*}}F
+  // CHECK: [[CLOSURE:%[0-9]+]] = function_ref {{.*}}, loc "{{.*}}":[[@LINE-2]]:10
+  // CHECK: apply [[CLOSURE:%[0-9]+]]
+}
+
+class LocationClass {
+  func mem() {}
+}
+func testMethodCall() {
+  var l: LocationClass
+  l.mem();
+  // CHECK-LABEL: sil hidden @$S13sil_locations14testMethodCallyyF
+  
+  // CHECK: class_method {{.[0-9]+}} : $LocationClass, #LocationClass.mem!1 {{.*}}, loc "{{.*}}":[[@LINE-3]]:5
+}
+
+func multipleReturnsImplicitAndExplicit() {
+  var x = 5+3
+  if x > 10 {
+    return
+  }
+  x += 1
+  // CHECK-LABEL: sil hidden @$S13sil_locations34multipleReturnsImplicitAndExplicityyF
+  // CHECK: cond_br
+  // CHECK: br bb{{[0-9]+}}, loc "{{.*}}":[[@LINE-5]]:5, {{.*}}:return
+  // CHECK: br bb{{[0-9]+}}, loc "{{.*}}":[[@LINE+2]]:1, {{.*}}:imp_return
+  // CHECK: return {{.*}}, loc "{{.*}}":[[@LINE+1]]:1, {{.*}}:cleanup
+}
+
+func simplifiedImplicitReturn() -> () {
+  var y = 0 
+  // CHECK-LABEL: sil hidden @$S13sil_locations24simplifiedImplicitReturnyyF
+  // CHECK: return {{.*}}, loc "{{.*}}":[[@LINE+1]]:1, {{.*}}:imp_return
+}
+
+func switchfoo() -> Int { return 0 }
+func switchbar() -> Int { return 0 }
+
+// CHECK-LABEL: sil hidden @$S13sil_locations10testSwitchyyF
+func testSwitch() {
+  var x:Int
+  x = 0
+  switch (switchfoo(), switchbar()) {
+  // CHECK: store {{.*}}, loc "{{.*}}":[[@LINE+1]]
+  case (1,2):
+  // CHECK: integer_literal $Builtin.Int2048, 2, loc "{{.*}}":[[@LINE-1]]:11
+  // FIXME: Location info is missing.
+  // CHECK: cond_br
+  //
+    var z: Int = 200
+  // CHECK: [[VAR_Z:%[0-9]+]] = alloc_box ${ var Int }, var, name "z"{{.*}}line:[[@LINE-1]]:9
+  // CHECK: integer_literal $Builtin.Int2048, 200, loc "{{.*}}":[[@LINE-2]]:18
+    x = z
+  // CHECK:  destroy_value [[VAR_Z]]{{.*}}, loc "{{.*}}":[[@LINE-1]]:9, {{.*}}:cleanup
+  case (3, let y):
+    x += 1
+  default:
+    ()
+  }
+}
+
+func testIf() {
+  if true {
+    var y:Int
+  } else {
+    var x:Int
+  }
+  // CHECK-LABEL: sil hidden @$S13sil_locations6testIfyyF
+  //
+  // FIXME: Missing location info here.
+  // CHECK: function_ref
+  // CHECK: apply
+  // 
+  //
+  //
+  // CHECK: br {{.*}}, loc "{{.*}}":[[@LINE-13]]:6
+}
+
+func testFor() {
+  for i in 0..<10 {
+    var y: Int = 300
+    y+=1
+    if true {
+      break
+    }
+    y-=1
+    continue
+  }
+
+  // CHECK-LABEL: sil hidden @$S13sil_locations7testForyyF
+  // CHECK: [[VAR_Y_IN_FOR:%[0-9]+]]  = alloc_box ${ var Int }, var, name "y", loc "{{.*}}":[[@LINE-10]]:9
+  // CHECK: integer_literal $Builtin.Int2048, 300, loc "{{.*}}":[[@LINE-11]]:18
+  // CHECK: destroy_value [[VAR_Y_IN_FOR]] : ${ var Int }
+  // CHECK: br bb{{.*}}, loc "{{.*}}":[[@LINE-10]]:7
+  // CHECK: destroy_value [[VAR_Y_IN_FOR]] : ${ var Int }
+  // CHECK: br bb{{.*}}, loc "{{.*}}":[[@LINE-9]]:5
+  
+  
+}
+
+func testTuples() {
+  var t = (2,3)
+  var tt = (2, (4,5))
+  var d = "foo"
+  // CHECK-LABEL: sil hidden @$S13sil_locations10testTuplesyyF
+  // CHECK: tuple_element_addr {{.*}}, loc "{{.*}}":[[@LINE-4]]:11
+  // CHECK: integer_literal $Builtin.Int2048, 2, loc "{{.*}}":[[@LINE-5]]:12
+  // CHECK: integer_literal $Builtin.Int2048, 3, loc "{{.*}}":[[@LINE-6]]:14
+  // CHECK: tuple_element_addr {{.*}}, loc "{{.*}}":[[@LINE-6]]:12
+  // CHECK: tuple_element_addr {{.*}}, loc "{{.*}}":[[@LINE-7]]:16  
+}
+
+// Test tuple imploding/exploding.
+protocol Ordinable {
+  func ord() -> Int
+}
+
+func b<T : Ordinable>(_ seq: T) -> (Int) -> Int {
+  return {i in i + seq.ord() }
+}
+
+func captures_tuple<T, U>(x: (T, U)) -> () -> (T, U) {
+  return {x}
+  // CHECK-LABEL: sil hidden @$S13sil_locations14captures_tuple{{[_0-9a-zA-Z]*}}F
+  // CHECK: tuple_element_addr {{.*}}, loc "{{.*}}":[[@LINE-3]]:27
+  // CHECK: copy_addr {{.*}}, loc "{{.*}}":[[@LINE-4]]:27
+  // CHECK: function_ref {{.*}}, loc "{{.*}}":[[@LINE-4]]:10
+
+  // CHECK-LABEL: sil private @$S13sil_locations14captures_tuple{{.*}}fU_
+  // CHECK: copy_addr {{.*}}, loc "{{.*}}":[[@LINE-7]]:11
+}
+
+func interpolated_string(_ x: Int, y: String) -> String {
+  return "The \(x) Million Dollar \(y)"
+  // CHECK-LABEL: sil hidden @$S13sil_locations19interpolated_string{{[_0-9a-zA-Z]*}}F
+  // CHECK: copy_value{{.*}}, loc "{{.*}}":[[@LINE-2]]:37
+}
+
+
+func int(_ x: Int) {}
+func tuple() -> (Int, Float) { return (1, 1.0) }  
+func tuple_element(_ x: (Int, Float)) {
+  int(tuple().0)
+  // CHECK-LABEL: sil hidden @$S13sil_locations13tuple_element{{[_0-9a-zA-Z]*}}F
+
+  // CHECK: apply {{.*}} line:[[@LINE-3]]:7
+  // CHECK: tuple_extract{{.*}}, 0, {{.*}}line:[[@LINE-4]]:7
+  // CHECK: tuple_extract{{.*}}, 1, {{.*}}line:[[@LINE-5]]:7
+  // CHECK: apply {{.*}} line:[[@LINE-6]]:3
+     
+}
+
+func containers() -> ([Int], Dictionary<String, Int>) {
+  return ([1, 2, 3], ["Ankeny": 1, "Burnside": 2, "Couch": 3])
+  // CHECK-LABEL: sil hidden @$S13sil_locations10containers{{[_0-9a-zA-Z]*}}F
+  // CHECK: apply {{%.*}}<(String, Int)>({{%.*}}), loc "{{.*}}":[[@LINE-2]]:22
+  
+  // CHECK: string_literal utf8 "Ankeny", loc "{{.*}}":[[@LINE-4]]:23
+
+  // CHECK: integer_literal $Builtin.Int2048, 1, loc "{{.*}}":[[@LINE-6]]:33
+  // CHECK: integer_literal $Builtin.Int2048, 2, loc "{{.*}}":[[@LINE-7]]:48
+
+  
+  
+}
+
+
+func a() {}
+func b() -> Int { return 0 }
+protocol P { func p() }
+struct X : P { func p() {} }
+func test_isa_2(_ p: P) {
+  switch (p, b()) {
+  case (is X, b()):
+    a()
+  case _:
+    a()
+  }
+  
+
+
+  // CHECK-LABEL: sil hidden @$S13sil_locations10test_isa_2{{[_0-9a-zA-Z]*}}F
+  // CHECK: alloc_stack $(P, Int), loc "{{.*}}":[[@LINE-10]]:10
+  // CHECK: tuple_element_addr{{.*}} $*(P, Int), 0, loc "{{.*}}":[[@LINE-11]]:10
+  // CHECK: tuple_element_addr{{.*}} $*(P, Int), 1, loc "{{.*}}":[[@LINE-12]]:10
+  // CHECK: load {{.*}}, loc "{{.*}}":[[@LINE-12]]:8
+  //
+  // CHECK: checked_cast_addr_br {{.*}}, loc "{{.*}}":[[@LINE-14]]:9
+  // CHECK: load {{.*}}, loc "{{.*}}":[[@LINE-15]]:9
+    
+}
+
+func runcibleWhy() {}
+protocol Runcible {
+  func runce()
+}
+enum SinglePayloadAddressOnly {
+  case x(Runcible)
+  case y
+}
+func printSinglePayloadAddressOnly(_ v:SinglePayloadAddressOnly) {
+  switch v {
+  case .x(let runcible):
+    runcible.runce()
+  case .y:
+    runcibleWhy()
+  }
+  
+  
+  // CHECK_LABEL: sil hidden @$S13sil_locations29printSinglePayloadAddressOnly{{[_0-9a-zA-Z]*}}F
+  // CHECK: bb0
+  // CHECK: switch_enum_addr {{.*}} [[FALSE_BB:bb[0-9]+]], {{.*}}line:[[@LINE-10]]:3
+  // CHECK: [[FALSE_BB]]:
+
+}
+
+
+func testStringForEachStmt() {
+  var i = 0
+  for index in 1..<20 {
+    i += 1
+    if i == 15 {
+      break
+    }
+  }
+  
+  // CHECK-LABEL: sil hidden @$S13sil_locations21testStringForEachStmtyyF
+  // CHECK: br {{.*}} line:[[@LINE-8]]:3
+  // CHECK: switch_enum {{.*}} line:[[@LINE-9]]:3
+  // CHECK: cond_br {{.*}} line:[[@LINE-8]]:8
+  // Break branch:
+  // CHECK: br {{.*}} line:[[@LINE-9]]:7
+  // Looping back branch:
+  // CHECK: br {{.*}} line:[[@LINE-9]]:3
+  // Condition is false branch:
+  // CHECK: br {{.*}} line:[[@LINE-16]]:3
+  
+  
+  
+  
+}
+
+
+func testForStmt() {
+  
+  var m = 0
+  for i in 0..<10 {
+    m += 1
+    if m == 15 {
+      break
+    } else {
+      continue
+    }
+
+  }
+
+
+
+  
+
+  
+  
+  
+  
+  
+  
+  
+
+  
+  
+}
+
+
+func testRepeatWhile() {
+  var m = 0
+  repeat {
+    m += 1
+  } while (m < 200)
+  
+  
+  // CHECK-LABEL: sil hidden @$S13sil_locations15testRepeatWhileyyF
+  // CHECK: br {{.*}} line:[[@LINE-6]]:3
+  // CHECK: cond_br {{.*}} line:[[@LINE-5]]:11
+  // Loop back branch:
+  // CHECK: br {{.*}} line:[[@LINE-7]]:11  
+}
+
+
+
+func testWhile() {
+  var m = 0
+  while m < 100 {
+    m += 1
+    if m > 5 {
+      break
+    }
+    m += 1
+  }
+  
+  // CHECK-LABEL: sil hidden @$S13sil_locations9testWhileyyF
+  // CHECK: br {{.*}} line:[[@LINE-9]]:3
+  // While loop conditional branch:
+  // CHECK: cond_br {{.*}} line:[[@LINE-11]]:9
+  // If stmt condition branch:
+  // CHECK: cond_br {{.*}} line:[[@LINE-11]]:8
+  // Break branch:
+  // CHECK: br {{.*}} line:[[@LINE-12]]:7
+  // Looping back branch:
+  // CHECK: br {{.*}} line:[[@LINE-11]]:3
+
+
+  
+}
diff --git a/test/SILGen/plus_zero_source_location.swift b/test/SILGen/plus_zero_source_location.swift
new file mode 100644
index 0000000..b61fef9
--- /dev/null
+++ b/test/SILGen/plus_zero_source_location.swift
@@ -0,0 +1,25 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -Xllvm -sil-full-demangle -Xllvm -sil-print-debuginfo -emit-silgen -enable-sil-ownership %s | %FileCheck %s
+
+func printSourceLocation(file: String = #file, line: Int = #line) {}
+
+#sourceLocation(file: "caller.swift", line: 10000)
+_ = printSourceLocation()
+// CHECK: [[CALLER_FILE_VAL:%.*]] = string_literal utf16 "caller.swift",
+// CHECK: [[CALLER_FILE:%.*]] = apply {{.*}}([[CALLER_FILE_VAL]],
+// CHECK: [[BORROWED_CALLER_FILE:%.*]] = begin_borrow [[CALLER_FILE]]
+// CHECK: [[CALLER_LINE_VAL:%.*]] = integer_literal $Builtin.Int{{[0-9]+}}, 10000,
+// CHECK: [[CALLER_LINE:%.*]] = apply {{.*}}([[CALLER_LINE_VAL]],
+// CHECK: [[PRINT_SOURCE_LOCATION:%.*]] = function_ref @$S15source_location19printSourceLocation4file4lineySS_SitF
+// CHECK: apply [[PRINT_SOURCE_LOCATION]]([[BORROWED_CALLER_FILE]], [[CALLER_LINE]])
+
+#sourceLocation(file: "inplace.swift", line: 20000)
+let FILE = #file, LINE = #line
+// CHECK: [[FILE_ADDR:%.*]] = global_addr @$S15source_location4FILESSv
+// CHECK: [[INPLACE_FILE_VAL:%.*]] = string_literal utf16 "inplace.swift",
+// CHECK: [[INPLACE_FILE:%.*]] = apply {{.*}}([[INPLACE_FILE_VAL]],
+// CHECK: store [[INPLACE_FILE]] to [init] [[FILE_ADDR]]
+// CHECK: [[LINE_ADDR:%.*]] = global_addr @$S15source_location4LINESiv
+// CHECK: [[INPLACE_LINE_VAL:%.*]] = integer_literal $Builtin.Int{{[0-9]+}}, 20000,
+// CHECK: [[INPLACE_LINE:%.*]] = apply {{.*}}([[INPLACE_LINE_VAL]],
+// CHECK: store [[INPLACE_LINE]] to [trivial] [[LINE_ADDR]]
diff --git a/test/SILGen/plus_zero_specialize_attr.swift b/test/SILGen/plus_zero_specialize_attr.swift
new file mode 100644
index 0000000..7ee8a18
--- /dev/null
+++ b/test/SILGen/plus_zero_specialize_attr.swift
@@ -0,0 +1,109 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership -emit-verbose-sil %s | %FileCheck %s
+
+// CHECK-LABEL: @_specialize(exported: false, kind: full, where T == Int, U == Float)
+// CHECK-NEXT: func specializeThis<T, U>(_ t: T, u: U)
+@_specialize(where T == Int, U == Float)
+func specializeThis<T, U>(_ t: T, u: U) {}
+
+public protocol PP {
+  associatedtype PElt
+}
+public protocol QQ {
+  associatedtype QElt
+}
+
+public struct RR : PP {
+  public typealias PElt = Float
+}
+public struct SS : QQ {
+  public typealias QElt = Int
+}
+
+public struct GG<T : PP> {}
+
+// CHECK-LABEL: public class CC<T> where T : PP {
+// CHECK-NEXT: @_specialize(exported: false, kind: full, where T == RR, U == SS)
+// CHECK-NEXT: @inline(never) public func foo<U>(_ u: U, g: GG<T>) -> (U, GG<T>) where U : QQ
+public class CC<T : PP> {
+  @inline(never)
+  @_specialize(where T == RR, U == SS)
+  public func foo<U : QQ>(_ u: U, g: GG<T>) -> (U, GG<T>) {
+    return (u, g)
+  }
+}
+
+// CHECK-LABEL: sil hidden [_specialize exported: false, kind: full, where T == Int, U == Float] @$S15specialize_attr0A4This_1uyx_q_tr0_lF : $@convention(thin) <T, U> (@in_guaranteed T, @in_guaranteed U) -> () {
+
+// CHECK-LABEL: sil [noinline] [_specialize exported: false, kind: full, where T == RR, U == SS] @$S15specialize_attr2CCC3foo_1gqd___AA2GGVyxGtqd___AHtAA2QQRd__lF : $@convention(method) <T where T : PP><U where U : QQ> (@in_guaranteed U, GG<T>, @guaranteed CC<T>) -> (@out U, GG<T>) {
+
+// -----------------------------------------------------------------------------
+// Test user-specialized subscript accessors.
+
+public protocol TestSubscriptable {
+  associatedtype Element
+  subscript(i: Int) -> Element { get set }
+}
+
+public class ASubscriptable<Element> : TestSubscriptable {
+  var storage: UnsafeMutablePointer<Element>
+
+  init(capacity: Int) {
+    storage = UnsafeMutablePointer<Element>.allocate(capacity: capacity)
+  }
+
+  public subscript(i: Int) -> Element {
+    @_specialize(where Element == Int)
+    get {
+      return storage[i]
+    }
+    @_specialize(where Element == Int)
+    set(rhs) {
+      storage[i] = rhs
+    }
+  }
+}
+
+// ASubscriptable.subscript.getter with _specialize
+// CHECK-LABEL: sil [_specialize exported: false, kind: full, where Element == Int] @$S15specialize_attr14ASubscriptableCyxSicig : $@convention(method) <Element> (Int, @guaranteed ASubscriptable<Element>) -> @out Element {
+
+// ASubscriptable.subscript.setter with _specialize
+// CHECK-LABEL: sil [_specialize exported: false, kind: full, where Element == Int] @$S15specialize_attr14ASubscriptableCyxSicis : $@convention(method) <Element> (@in Element, Int, @guaranteed ASubscriptable<Element>) -> () {
+
+// ASubscriptable.subscript.materializeForSet with no attribute
+// CHECK-LABEL: sil [transparent] [serialized] @$S15specialize_attr14ASubscriptableCyxSicim : $@convention(method) <Element> (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, Int, @guaranteed ASubscriptable<Element>) -> (Builtin.RawPointer, Optional<Builtin.RawPointer>) {
+
+public class Addressable<Element> : TestSubscriptable {
+  var storage: UnsafeMutablePointer<Element>
+
+  init(capacity: Int) {
+    storage = UnsafeMutablePointer<Element>.allocate(capacity: capacity)
+  }
+
+  public subscript(i: Int) -> Element {
+    @_specialize(where Element == Int)
+    unsafeAddress {
+      return UnsafePointer<Element>(storage + i)
+    }
+    @_specialize(where Element == Int)
+    unsafeMutableAddress {
+      return UnsafeMutablePointer<Element>(storage + i)
+    }
+  }
+}
+
+// Addressable.subscript.getter with no attribute
+// CHECK-LABEL: sil [transparent] [serialized] @$S15specialize_attr11AddressableCyxSicig : $@convention(method) <Element> (Int, @guaranteed Addressable<Element>) -> @out Element {
+
+// Addressable.subscript.unsafeAddressor with _specialize
+// CHECK-LABEL: sil [_specialize exported: false, kind: full, where Element == Int] @$S15specialize_attr11AddressableCyxSicilu : $@convention(method) <Element> (Int, @guaranteed Addressable<Element>) -> UnsafePointer<Element> {
+
+// Addressable.subscript.setter with no attribute
+// CHECK-LABEL: sil [transparent] [serialized] @$S15specialize_attr11AddressableCyxSicis : $@convention(method) <Element> (@in Element, Int, @guaranteed Addressable<Element>) -> () {
+
+// Addressable.subscript.unsafeMutableAddressor with _specialize
+// CHECK-LABEL: sil [_specialize exported: false, kind: full, where Element == Int] @$S15specialize_attr11AddressableCyxSiciau : $@convention(method) <Element> (Int, @guaranteed Addressable<Element>) -> UnsafeMutablePointer<Element> {
+
+// Addressable.subscript.materializeForSet with no attribute
+// CHECK-LABEL: sil [transparent] [serialized] @$S15specialize_attr11AddressableCyxSicim : $@convention(method) <Element> (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, Int, @guaranteed Addressable<Element>) -> (Builtin.RawPointer, Optional<Builtin.RawPointer>) {
+
diff --git a/test/SILGen/plus_zero_statements.swift b/test/SILGen/plus_zero_statements.swift
new file mode 100644
index 0000000..d3fe1bd
--- /dev/null
+++ b/test/SILGen/plus_zero_statements.swift
@@ -0,0 +1,697 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -Xllvm -sil-full-demangle -parse-as-library -emit-silgen -enable-sil-ownership -verify %s | %FileCheck %s
+
+class MyClass { 
+  func foo() { }
+}
+
+func markUsed<T>(_ t: T) {}
+
+func marker_1() {}
+func marker_2() {}
+func marker_3() {}
+
+class BaseClass {}
+class DerivedClass : BaseClass {}
+
+var global_cond: Bool = false
+
+func bar(_ x: Int) {}
+func foo(_ x: Int, _ y: Bool) {}
+
+func abort() -> Never { abort() }
+
+
+
+func assignment(_ x: Int, y: Int) {
+  var x = x
+  var y = y
+  x = 42
+  y = 57
+  _ = x
+  _ = y
+  (x, y) = (1,2)
+}
+
+// CHECK-LABEL: sil hidden @{{.*}}assignment
+// CHECK: integer_literal $Builtin.Int2048, 42
+// CHECK: assign
+// CHECK: integer_literal $Builtin.Int2048, 57
+// CHECK: assign
+
+func if_test(_ x: Int, y: Bool) {
+  if (y) {
+   bar(x);
+  }
+  bar(x);
+}
+
+// CHECK-LABEL: sil hidden @$S10statements7if_test{{[_0-9a-zA-Z]*}}F
+
+func if_else(_ x: Int, y: Bool) {
+  if (y) {
+   bar(x);
+  } else {
+   foo(x, y);
+  }
+  bar(x);
+}
+
+// CHECK-LABEL: sil hidden @$S10statements7if_else{{[_0-9a-zA-Z]*}}F
+
+func nested_if(_ x: Int, y: Bool, z: Bool) {
+  if (y) {
+    if (z) {
+      bar(x);
+    }
+  } else {
+    if (z) {
+      foo(x, y);
+    }
+  }
+  bar(x);
+}
+
+// CHECK-LABEL: sil hidden @$S10statements9nested_if{{[_0-9a-zA-Z]*}}F
+
+func nested_if_merge_noret(_ x: Int, y: Bool, z: Bool) {
+  if (y) {
+    if (z) {
+      bar(x);
+    }
+  } else {
+    if (z) {
+      foo(x, y);
+    }
+  }
+}
+
+// CHECK-LABEL: sil hidden @$S10statements21nested_if_merge_noret{{[_0-9a-zA-Z]*}}F
+
+func nested_if_merge_ret(_ x: Int, y: Bool, z: Bool) -> Int {
+  if (y) {
+    if (z) {
+      bar(x);
+    }
+    return 1
+  } else {
+    if (z) {
+      foo(x, y);
+    }
+  }
+  return 2
+}
+
+// CHECK-LABEL: sil hidden @$S10statements19nested_if_merge_ret{{[_0-9a-zA-Z]*}}F
+
+func else_break(_ x: Int, y: Bool, z: Bool) {
+  while z {
+    if y {
+    } else {
+      break
+    }
+  }
+}
+
+// CHECK-LABEL: sil hidden @$S10statements10else_break{{[_0-9a-zA-Z]*}}F
+
+func loop_with_break(_ x: Int, _ y: Bool, _ z: Bool) -> Int {
+  while (x > 2) {
+   if (y) {
+     bar(x);
+     break
+   }
+  }
+}
+
+// CHECK-LABEL: sil hidden @$S10statements15loop_with_break{{[_0-9a-zA-Z]*}}F
+
+func loop_with_continue(_ x: Int, y: Bool, z: Bool) -> Int {
+  while (x > 2) {
+    if (y) {
+     bar(x);
+     continue
+    }
+    _ = loop_with_break(x, y, z);
+  }
+  bar(x);
+}
+
+// CHECK-LABEL: sil hidden @$S10statements18loop_with_continue{{[_0-9a-zA-Z]*}}F
+
+func do_loop_with_continue(_ x: Int, y: Bool, z: Bool) -> Int {
+  repeat {
+    if (x < 42) {
+     bar(x);
+     continue
+    }
+    _ = loop_with_break(x, y, z);
+  }
+  while (x > 2);
+  bar(x);
+}
+
+// CHECK-LABEL: sil hidden @$S10statements21do_loop_with_continue{{[_0-9a-zA-Z]*}}F 
+
+
+// CHECK-LABEL: sil hidden @{{.*}}for_loops1
+func for_loops1(_ x: Int, c: Bool) {
+  for i in 1..<100 {
+    markUsed(i)
+  }
+
+}
+
+// CHECK-LABEL: sil hidden @{{.*}}for_loops2
+func for_loops2() {
+  // rdar://problem/19316670
+  // CHECK: alloc_stack $Optional<MyClass>
+  // CHECK-NEXT: [[WRITE:%.*]] = begin_access [modify] [unknown]
+  // CHECK: [[NEXT:%[0-9]+]] = function_ref @$Ss16IndexingIteratorV4next{{[_0-9a-zA-Z]*}}F
+  // CHECK-NEXT: apply [[NEXT]]<[MyClass]>
+  // CHECK: class_method [[OBJ:%[0-9]+]] : $MyClass, #MyClass.foo!1
+  let objects = [MyClass(), MyClass() ]
+  for obj in objects {
+    obj.foo()
+  }
+
+  return 
+}
+
+func void_return() {
+  let b:Bool
+  if b {
+    return
+  }
+}
+// CHECK-LABEL: sil hidden @$S10statements11void_return{{[_0-9a-zA-Z]*}}F
+// CHECK: cond_br {{%[0-9]+}}, [[BB1:bb[0-9]+]], [[BB2:bb[0-9]+]]
+// CHECK: [[BB1]]:
+// CHECK:   br [[EPILOG:bb[0-9]+]]
+// CHECK: [[BB2]]:
+// CHECK:   br [[EPILOG]]
+// CHECK: [[EPILOG]]:
+// CHECK:   [[R:%[0-9]+]] = tuple ()
+// CHECK:   return [[R]]
+
+func foo() {}
+
+// <rdar://problem/13549626>
+// CHECK-LABEL: sil hidden @$S10statements14return_from_if{{[_0-9a-zA-Z]*}}F
+func return_from_if(_ a: Bool) -> Int {
+  // CHECK: bb0(%0 : @trivial $Bool):
+  // CHECK: cond_br {{.*}}, [[THEN:bb[0-9]+]], [[ELSE:bb[0-9]+]]
+  if a {
+    // CHECK: [[THEN]]:
+    // CHECK: br [[EPILOG:bb[0-9]+]]({{%.*}})
+    return 1
+  } else {
+    // CHECK: [[ELSE]]:
+    // CHECK: br [[EPILOG]]({{%.*}})
+    return 0
+  }
+  // CHECK-NOT: function_ref @foo
+  // CHECK: [[EPILOG]]([[RET:%.*]] : @trivial $Int):
+  // CHECK:   return [[RET]]
+  foo()  // expected-warning {{will never be executed}}
+}
+
+class C {}
+
+func use(_ c: C) {}
+
+func for_each_loop(_ x: [C]) {
+  for i in x {
+    use(i)
+  }
+  _ = 0
+}
+
+// CHECK-LABEL: sil hidden @{{.*}}test_break
+func test_break(_ i : Int) {
+  switch i {
+  case (let x) where x != 17: 
+    if x == 42 { break } 
+    markUsed(x)
+  default:
+    break
+  }
+}
+
+
+// <rdar://problem/19150249> Allow labeled "break" from an "if" statement
+
+// CHECK-LABEL: sil hidden @$S10statements13test_if_breakyyAA1CCSgF : $@convention(thin) (@guaranteed Optional<C>) -> () {
+func test_if_break(_ c : C?) {
+// CHECK: bb0([[ARG:%.*]] : @guaranteed $Optional<C>):
+label1:
+  // CHECK: [[ARG_COPY:%.*]] = copy_value [[ARG]]
+  // CHECK: switch_enum [[ARG_COPY]] : $Optional<C>, case #Optional.some!enumelt.1: [[TRUE:bb[0-9]+]], case #Optional.none!enumelt: [[FALSE:bb[0-9]+]]
+  if let x = c {
+// CHECK: [[TRUE]]({{.*}} : @owned $C):
+
+    // CHECK: apply
+    foo()
+
+    // CHECK: destroy_value
+    // CHECK: br [[FALSE:bb[0-9]+]]
+    break label1
+    use(x)  // expected-warning {{will never be executed}}
+  }
+
+  // CHECK: [[FALSE]]:
+  // CHECK: return
+}
+
+// CHECK-LABEL: sil hidden @$S10statements18test_if_else_breakyyAA1CCSgF : $@convention(thin) (@guaranteed Optional<C>) -> () {
+func test_if_else_break(_ c : C?) {
+// CHECK: bb0([[ARG:%.*]] : @guaranteed $Optional<C>):
+label2:
+  // CHECK: [[ARG_COPY:%.*]] = copy_value [[ARG]]
+  // CHECK: switch_enum [[ARG_COPY]] : $Optional<C>, case #Optional.some!enumelt.1: [[TRUE:bb[0-9]+]], case #Optional.none!enumelt: [[FALSE:bb[0-9]+]]
+
+  // CHECK: [[FALSE]]:
+  // CHECK:   br [[AFTER_FALSE:bb[0-9]+]]
+  if let x = c {
+    // CHECK: [[TRUE]]({{.*}} : @owned $C):
+    use(x)
+    // CHECK:   br [[CONT:bb[0-9]+]]
+    // CHECK: [[CONT]]:
+    // CHECK:   br [[EPILOG:bb[0-9]+]]
+  } else {
+    // CHECK: [[AFTER_FALSE]]:
+    // CHECK: apply
+    // CHECK: br [[EPILOG]]
+    foo()
+    break label2
+    foo() // expected-warning {{will never be executed}}
+  }
+  // CHECK: [[EPILOG]]:
+  // CHECK: return
+}
+
+// CHECK-LABEL: sil hidden @$S10statements23test_if_else_then_breakyySb_AA1CCSgtF
+func test_if_else_then_break(_ a : Bool, _ c : C?) {
+label3:
+  // CHECK: bb0({{.*}}, [[ARG2:%.*]] : @guaranteed $Optional<C>):
+  // CHECK: [[ARG2_COPY:%.*]] = copy_value [[ARG2]]
+  // CHECK: switch_enum [[ARG2_COPY]] : $Optional<C>, case #Optional.some!enumelt.1: [[TRUE:bb[0-9]+]], case #Optional.none!enumelt: [[FALSE:bb[0-9]+]]
+
+  // CHECK: [[FALSE]]:
+  // CHECK:   br [[COND2:bb[0-9]+]]
+  if let x = c {
+    // CHECK: [[TRUE]]({{.*}} : @owned $C):
+    use(x)
+    // CHECK:   br [[TRUE_TRAMPOLINE:bb[0-9]+]]
+    //
+    // CHECK: [[TRUE_TRAMPOLINE]]:
+    // CHECK:   br [[EPILOG_BB:bb[0-9]+]]
+  } else if a {
+    // CHECK: [[COND2]]:
+    // CHECK:   cond_br {{.*}}, [[TRUE2:bb[0-9]+]], [[FALSE2:bb[0-9]+]]
+    //
+    // CHECK: [[TRUE2]]:
+    // CHECK:   apply
+    // CHECK:   br [[EPILOG_BB]]
+    foo()
+    break label3
+    foo()    // expected-warning {{will never be executed}}
+  }
+  // CHECK: [[FALSE2]]:
+  // CHECK: br [[EPILOG_BB]]
+
+  // CHECK: [[EPILOG_BB]]:
+  // CHECK: return
+
+
+}
+
+
+// CHECK-LABEL: sil hidden @$S10statements13test_if_breakyySbF
+func test_if_break(_ a : Bool) {
+  // CHECK: br [[LOOP:bb[0-9]+]]
+  // CHECK: [[LOOP]]:
+  // CHECK: function_ref @$SSb21_getBuiltinLogicValue{{[_0-9a-zA-Z]*}}F
+  // CHECK-NEXT: apply
+  // CHECK-NEXT: cond_br {{.*}}, [[LOOPTRUE:bb[0-9]+]], [[OUT:bb[0-9]+]]
+  while a {
+    if a {
+      foo()
+      break  // breaks out of while, not if.
+    }
+    foo()
+  }
+
+  // CHECK: [[LOOPTRUE]]:
+  // CHECK: function_ref @$SSb21_getBuiltinLogicValue{{[_0-9a-zA-Z]*}}F
+  // CHECK-NEXT: apply
+  // CHECK-NEXT: cond_br {{.*}}, [[IFTRUE:bb[0-9]+]], [[IFFALSE:bb[0-9]+]]
+
+  // [[IFTRUE]]:
+  // CHECK: function_ref statements.foo
+  // CHECK: br [[OUT]]
+
+  // CHECK: [[IFFALSE]]:
+  // CHECK: function_ref statements.foo
+  // CHECK: br [[LOOP]]
+
+  // CHECK: [[OUT]]:
+  // CHECK:   return
+}
+
+// CHECK-LABEL: sil hidden @$S10statements7test_doyyF
+func test_do() {
+  // CHECK: integer_literal $Builtin.Int2048, 0
+  // CHECK: [[BAR:%.*]] = function_ref @$S10statements3baryySiF
+  // CHECK: apply [[BAR]](
+  bar(0)
+  // CHECK-NOT: br bb
+  do {
+    // CHECK: [[CTOR:%.*]] = function_ref @$S10statements7MyClassC{{[_0-9a-zA-Z]*}}fC
+    // CHECK: [[OBJ:%.*]] = apply [[CTOR]](
+    let obj = MyClass()
+    _ = obj
+    
+    // CHECK: integer_literal $Builtin.Int2048, 1
+    // CHECK: [[BAR:%.*]] = function_ref @$S10statements3baryySiF
+    // CHECK: apply [[BAR]](
+    bar(1)
+
+    // CHECK-NOT: br bb
+    // CHECK: destroy_value [[OBJ]]
+    // CHECK-NOT: br bb
+  }
+
+  // CHECK: integer_literal $Builtin.Int2048, 2
+  // CHECK: [[BAR:%.*]] = function_ref @$S10statements3baryySiF
+  // CHECK: apply [[BAR]](
+  bar(2)
+}
+
+// CHECK-LABEL: sil hidden @$S10statements15test_do_labeledyyF
+func test_do_labeled() {
+  // CHECK: integer_literal $Builtin.Int2048, 0
+  // CHECK: [[BAR:%.*]] = function_ref @$S10statements3baryySiF
+  // CHECK: apply [[BAR]](
+  bar(0)
+  // CHECK: br bb1
+  // CHECK: bb1:
+  lbl: do {
+    // CHECK: [[CTOR:%.*]] = function_ref @$S10statements7MyClassC{{[_0-9a-zA-Z]*}}fC
+    // CHECK: [[OBJ:%.*]] = apply [[CTOR]](
+    let obj = MyClass()
+    _ = obj
+
+    // CHECK: integer_literal $Builtin.Int2048, 1
+    // CHECK: [[BAR:%.*]] = function_ref @$S10statements3baryySiF
+    // CHECK: apply [[BAR]](
+    bar(1)
+
+    // CHECK: [[GLOBAL:%.*]] = function_ref @$S10statements11global_condSbvau
+    // CHECK: cond_br {{%.*}}, bb2, bb3
+    if (global_cond) {
+      // CHECK: bb2:
+      // CHECK: destroy_value [[OBJ]]
+      // CHECK: br bb1
+      continue lbl
+    }
+
+    // CHECK: bb3:
+    // CHECK: integer_literal $Builtin.Int2048, 2
+    // CHECK: [[BAR:%.*]] = function_ref @$S10statements3baryySiF
+    // CHECK: apply [[BAR]](
+    bar(2)
+
+    // CHECK: [[GLOBAL:%.*]] = function_ref @$S10statements11global_condSbvau
+    // CHECK: cond_br {{%.*}}, bb4, bb5
+    if (global_cond) {
+      // CHECK: bb4:
+      // CHECK: destroy_value [[OBJ]]
+      // CHECK: br bb6
+      break lbl
+    }
+
+    // CHECK: bb5:
+    // CHECK: integer_literal $Builtin.Int2048, 3
+    // CHECK: [[BAR:%.*]] = function_ref @$S10statements3baryySiF
+    // CHECK: apply [[BAR]](
+    bar(3)
+
+    // CHECK: destroy_value [[OBJ]]
+    // CHECK: br bb6
+  }
+
+  // CHECK: integer_literal $Builtin.Int2048, 4
+  // CHECK: [[BAR:%.*]] = function_ref @$S10statements3baryySiF
+  // CHECK: apply [[BAR]](
+  bar(4)
+}
+
+
+func callee1() {}
+func callee2() {}
+func callee3() {}
+
+// CHECK-LABEL: sil hidden @$S10statements11defer_test1yyF
+func defer_test1() {
+  defer { callee1() }
+  defer { callee2() }
+  callee3()
+  
+  // CHECK: [[C3:%.*]] = function_ref @$S10statements7callee3yyF
+  // CHECK: apply [[C3]]
+  // CHECK: [[C2:%.*]] = function_ref @$S10statements11defer_test1yyF6
+  // CHECK: apply [[C2]]
+  // CHECK: [[C1:%.*]] = function_ref @$S10statements11defer_test1yyF6
+  // CHECK: apply [[C1]]
+}
+// CHECK: sil private @$S10statements11defer_test1yyF6
+// CHECK: function_ref @{{.*}}callee1yyF
+
+// CHECK: sil private @$S10statements11defer_test1yyF6
+// CHECK: function_ref @{{.*}}callee2yyF
+
+// CHECK-LABEL: sil hidden @$S10statements11defer_test2yySbF
+func defer_test2(_ cond : Bool) {
+  // CHECK: [[C3:%.*]] = function_ref @{{.*}}callee3yyF
+  // CHECK: apply [[C3]]
+  // CHECK: br [[LOOP:bb[0-9]+]]
+  callee3()
+  
+// CHECK: [[LOOP]]:
+// test the condition.
+// CHECK:  [[CONDTRUE:%.*]] = apply {{.*}}(%0)
+// CHECK: cond_br [[CONDTRUE]], [[BODY:bb[0-9]+]], [[EXIT:bb[0-9]+]]
+  while cond {
+// CHECK: [[BODY]]:
+  // CHECK: [[C2:%.*]] = function_ref @{{.*}}callee2yyF
+  // CHECK: apply [[C2]]
+
+  // CHECK: [[C1:%.*]] = function_ref @$S10statements11defer_test2yySbF6
+  // CHECK: apply [[C1]]
+  // CHECK: br [[EXIT]]
+    defer { callee1() }
+    callee2()
+    break
+  }
+  
+// CHECK: [[EXIT]]:
+// CHECK: [[C3:%.*]] = function_ref @{{.*}}callee3yyF
+// CHECK: apply [[C3]]
+
+  callee3()
+}
+
+func generic_callee_1<T>(_: T) {}
+func generic_callee_2<T>(_: T) {}
+func generic_callee_3<T>(_: T) {}
+
+// CHECK-LABEL: sil hidden @$S10statements16defer_in_generic{{[_0-9a-zA-Z]*}}F
+func defer_in_generic<T>(_ x: T) {
+  // CHECK: [[C3:%.*]] = function_ref @$S10statements16generic_callee_3{{[_0-9a-zA-Z]*}}F
+  // CHECK: apply [[C3]]<T>
+  // CHECK: [[C2:%.*]] = function_ref @$S10statements16defer_in_genericyyxlF6
+  // CHECK: apply [[C2]]<T>
+  // CHECK: [[C1:%.*]] = function_ref @$S10statements16defer_in_genericyyxlF6
+  // CHECK: apply [[C1]]<T>
+  defer { generic_callee_1(x) }
+  defer { generic_callee_2(x) }
+  generic_callee_3(x)
+}
+
+// CHECK-LABEL: sil hidden @$S10statements017defer_in_closure_C8_genericyyxlF : $@convention(thin) <T> (@in_guaranteed T) -> ()
+func defer_in_closure_in_generic<T>(_ x: T) {
+  // CHECK-LABEL: sil private @$S10statements017defer_in_closure_C8_genericyyxlFyycfU_ : $@convention(thin) <T> () -> ()
+  _ = {
+    // CHECK-LABEL: sil private @$S10statements017defer_in_closure_C8_genericyyxlFyycfU_6$deferL_yylF : $@convention(thin) <T> () -> ()
+    defer { generic_callee_1(T.self) }
+  }
+}
+
+// CHECK-LABEL: sil hidden @$S10statements13defer_mutableyySiF
+func defer_mutable(_ x: Int) {
+  var x = x
+  // CHECK: [[BOX:%.*]] = alloc_box ${ var Int }
+  // CHECK-NEXT: project_box [[BOX]]
+  // CHECK-NOT: [[BOX]]
+  // CHECK: function_ref @$S10statements13defer_mutableyySiF6$deferL_yyF : $@convention(thin) (@inout_aliasable Int) -> ()
+  // CHECK-NOT: [[BOX]]
+  // CHECK: destroy_value [[BOX]]
+  defer { _ = x }
+}
+
+protocol StaticFooProtocol { static func foo() }
+
+func testDeferOpenExistential(_ b: Bool, type: StaticFooProtocol.Type) {
+  defer { type.foo() }
+  if b { return }
+  return
+}
+
+
+
+
+// CHECK-LABEL: sil hidden @$S10statements22testRequireExprPatternyySiF
+
+func testRequireExprPattern(_ a : Int) {
+  marker_1()
+  // CHECK: [[M1:%[0-9]+]] = function_ref @$S10statements8marker_1yyF : $@convention(thin) () -> ()
+  // CHECK-NEXT: apply [[M1]]() : $@convention(thin) () -> ()
+
+  // CHECK: function_ref Swift.~= infix<A where A: Swift.Equatable>(A, A) -> Swift.Bool
+  // CHECK: cond_br {{.*}}, bb1, bb2
+  guard case 4 = a else { marker_2(); return }
+
+  // Fall through case comes first.
+
+  // CHECK: bb1:
+  // CHECK: [[M3:%[0-9]+]] = function_ref @$S10statements8marker_3yyF : $@convention(thin) () -> ()
+  // CHECK-NEXT: apply [[M3]]() : $@convention(thin) () -> ()
+  // CHECK-NEXT: br bb3
+  marker_3()
+
+  // CHECK: bb2:
+  // CHECK: [[M2:%[0-9]+]] = function_ref @$S10statements8marker_2yyF : $@convention(thin) () -> ()
+  // CHECK-NEXT: apply [[M2]]() : $@convention(thin) () -> ()
+  // CHECK-NEXT: br bb3
+
+  // CHECK: bb3:
+  // CHECK-NEXT: tuple ()
+  // CHECK-NEXT: return
+}
+
+
+// CHECK-LABEL: sil hidden @$S10statements20testRequireOptional1yS2iSgF
+// CHECK: bb0([[ARG:%.*]] : @trivial $Optional<Int>):
+// CHECK-NEXT:   debug_value [[ARG]] : $Optional<Int>, let, name "a"
+// CHECK-NEXT:   switch_enum [[ARG]] : $Optional<Int>, case #Optional.some!enumelt.1: [[SOME:bb[0-9]+]], case #Optional.none!enumelt: [[NONE:bb[0-9]+]]
+func testRequireOptional1(_ a : Int?) -> Int {
+
+  // CHECK: [[NONE]]:
+  // CHECK:   br [[ABORT:bb[0-9]+]]
+
+  // CHECK: [[SOME]]([[PAYLOAD:%.*]] : @trivial $Int):
+  // CHECK-NEXT:   debug_value [[PAYLOAD]] : $Int, let, name "t"
+  // CHECK-NEXT:   br [[EPILOG:bb[0-9]+]]
+  //
+  // CHECK: [[EPILOG]]:
+  // CHECK-NEXT:   return [[PAYLOAD]] : $Int
+  guard let t = a else { abort() }
+
+  // CHECK:  [[ABORT]]:
+  // CHECK-NEXT:    // function_ref statements.abort() -> Swift.Never
+  // CHECK-NEXT:    [[FUNC_REF:%.*]] = function_ref @$S10statements5aborts5NeverOyF
+  // CHECK-NEXT:    apply [[FUNC_REF]]() : $@convention(thin) () -> Never
+  // CHECK-NEXT:    unreachable
+  return t
+}
+
+// CHECK-LABEL: sil hidden @$S10statements20testRequireOptional2yS2SSgF
+// CHECK: bb0([[ARG:%.*]] : @guaranteed $Optional<String>):
+// CHECK-NEXT:   debug_value [[ARG]] : $Optional<String>, let, name "a"
+// CHECK-NEXT:   [[ARG_COPY:%.*]] = copy_value [[ARG]] : $Optional<String>
+// CHECK-NEXT:   switch_enum [[ARG_COPY]] : $Optional<String>, case #Optional.some!enumelt.1: [[SOME_BB:bb[0-9]+]], case #Optional.none!enumelt: [[NONE_BB:bb[0-9]+]]
+func testRequireOptional2(_ a : String?) -> String {
+  guard let t = a else { abort() }
+
+  // CHECK: [[NONE_BB]]:
+  // CHECK-NEXT: br [[ABORT_BB:bb[0-9]+]]
+  
+  // CHECK:  [[SOME_BB]]([[STR:%.*]] : @owned $String):
+  // CHECK-NEXT:   debug_value [[STR]] : $String, let, name "t"
+  // CHECK-NEXT:   br [[CONT_BB:bb[0-9]+]]
+  // CHECK:  [[CONT_BB]]:
+  // CHECK-NEXT:   [[BORROWED_STR:%.*]] = begin_borrow [[STR]]
+  // CHECK-NEXT:   [[RETURN:%.*]] = copy_value [[BORROWED_STR]]
+  // CHECK-NEXT:   end_borrow [[BORROWED_STR]] from [[STR]]
+  // CHECK-NEXT:   destroy_value [[STR]] : $String
+  // CHECK-NEXT:   return [[RETURN]] : $String
+
+  // CHECK:        [[ABORT_BB]]:
+  // CHECK-NEXT:   // function_ref statements.abort() -> Swift.Never
+  // CHECK-NEXT:   [[ABORT_FUNC:%.*]] = function_ref @$S10statements5aborts5NeverOyF
+  // CHECK-NEXT:   [[NEVER:%.*]] = apply [[ABORT_FUNC]]()
+  // CHECK-NEXT:   unreachable
+  return t
+}
+
+
+// CHECK-LABEL: sil hidden @$S10statements19testCleanupEmission{{[_0-9a-zA-Z]*}}F
+// <rdar://problem/20563234> let-else problem: cleanups for bound patterns shouldn't be run in the else block
+protocol MyProtocol {}
+func testCleanupEmission<T>(_ x: T) {
+  // SILGen shouldn't crash/verify abort on this example.
+  guard let x2 = x as? MyProtocol else { return }
+  _ = x2
+}
+
+
+// CHECK-LABEL: sil hidden @$S10statements15test_is_patternyyAA9BaseClassCF
+func test_is_pattern(_ y : BaseClass) {
+  // checked_cast_br %0 : $BaseClass to $DerivedClass
+  guard case is DerivedClass = y else { marker_1(); return }
+
+  marker_2()
+}
+
+// CHECK-LABEL: sil hidden @$S10statements15test_as_patternyAA12DerivedClassCAA04BaseF0CF
+func test_as_pattern(_ y : BaseClass) -> DerivedClass {
+  // CHECK: bb0([[ARG:%.*]] : @guaranteed $BaseClass):
+  // CHECK:   [[ARG_COPY:%.*]] = copy_value [[ARG]]
+  // CHECK:   checked_cast_br [[ARG_COPY]] : $BaseClass to $DerivedClass
+  guard case let result as DerivedClass = y else {  }
+  // CHECK: bb{{.*}}({{.*}} : @owned $DerivedClass):
+
+
+  // CHECK: bb{{.*}}([[PTR:%[0-9]+]] : @owned $DerivedClass):
+  // CHECK-NEXT: debug_value [[PTR]] : $DerivedClass, let, name "result"
+  // CHECK-NEXT: br [[CONT_BB:bb[0-9]+]]
+  // CHECK: [[CONT_BB]]:
+  // CHECK-NEXT: [[BORROWED_PTR:%.*]] = begin_borrow [[PTR]]
+  // CHECK-NEXT: [[RESULT:%.*]] = copy_value [[BORROWED_PTR]]
+  // CHECK-NEXT: end_borrow [[BORROWED_PTR]] from [[PTR]]
+  // CHECK-NEXT: destroy_value [[PTR]] : $DerivedClass
+  // CHECK-NEXT: return [[RESULT]] : $DerivedClass
+  return result
+}
+// CHECK-LABEL: sil hidden @$S10statements22let_else_tuple_bindingyS2i_SitSgF
+func let_else_tuple_binding(_ a : (Int, Int)?) -> Int {
+
+  // CHECK: bb0([[ARG:%.*]] : @trivial $Optional<(Int, Int)>):
+  // CHECK-NEXT:   debug_value [[ARG]] : $Optional<(Int, Int)>, let, name "a"
+  // CHECK-NEXT:   switch_enum [[ARG]] : $Optional<(Int, Int)>, case #Optional.some!enumelt.1: [[SOME_BB:bb[0-9]+]], case #Optional.none!enumelt: [[NONE_BB:bb[0-9]+]]
+
+  guard let (x, y) = a else { }
+  _ = y
+  return x
+
+  // CHECK: [[SOME_BB]]([[PAYLOAD:%.*]] : @trivial $(Int, Int)):
+  // CHECK-NEXT:   [[PAYLOAD_1:%.*]] = tuple_extract [[PAYLOAD]] : $(Int, Int), 0
+  // CHECK-NEXT:   debug_value [[PAYLOAD_1]] : $Int, let, name "x"
+  // CHECK-NEXT:   [[PAYLOAD_2:%.*]] = tuple_extract [[PAYLOAD]] : $(Int, Int), 1
+  // CHECK-NEXT:   debug_value [[PAYLOAD_2]] : $Int, let, name "y"
+  // CHECK-NEXT:   br [[CONT_BB:bb[0-9]+]]
+  // CHECK: [[CONT_BB]]:
+  // CHECK-NEXT:   return [[PAYLOAD_1]] : $Int
+}
+
diff --git a/test/SILGen/plus_zero_struct_resilience.swift b/test/SILGen/plus_zero_struct_resilience.swift
new file mode 100644
index 0000000..b11d502
--- /dev/null
+++ b/test/SILGen/plus_zero_struct_resilience.swift
@@ -0,0 +1,284 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %empty-directory(%t)
+// RUN: %target-swift-frontend -emit-module -enable-resilience -emit-module-path=%t/resilient_struct.swiftmodule -enable-sil-ownership -module-name=resilient_struct %S/../Inputs/resilient_struct.swift
+// RUN: %target-swift-frontend -I %t -enable-sil-ownership -emit-silgen -enable-resilience %s | %FileCheck %s
+
+import resilient_struct
+
+// Resilient structs are always address-only
+
+// CHECK-LABEL: sil hidden @$S17struct_resilience26functionWithResilientTypes_1f010resilient_A04SizeVAF_A2FXEtF : $@convention(thin) (@in_guaranteed Size, @noescape @callee_guaranteed (@in_guaranteed Size) -> @out Size) -> @out Size
+// CHECK:       bb0(%0 : @trivial $*Size, %1 : @trivial $*Size, %2 : @trivial $@noescape @callee_guaranteed (@in_guaranteed Size) -> @out Size):
+func functionWithResilientTypes(_ s: Size, f: (Size) -> Size) -> Size {
+
+  // Stored properties of resilient structs from outside our resilience
+  // domain are accessed through accessors
+
+// CHECK:         copy_addr %1 to [initialization] [[OTHER_SIZE_BOX:%[0-9]*]] : $*Size
+  var s2 = s
+
+// CHECK:         copy_addr %1 to [initialization] [[SIZE_BOX:%.*]] : $*Size
+// CHECK:         [[GETTER:%.*]] = function_ref @$S16resilient_struct4SizeV1wSivg : $@convention(method) (@in_guaranteed Size) -> Int
+// CHECK:         [[RESULT:%.*]] = apply [[GETTER]]([[SIZE_BOX]])
+// CHECK:         [[WRITE:%.*]] = begin_access [modify] [unknown] [[OTHER_SIZE_BOX]] : $*Size
+// CHECK:         [[SETTER:%.*]] = function_ref @$S16resilient_struct4SizeV1wSivs : $@convention(method) (Int, @inout Size) -> ()
+// CHECK:         apply [[SETTER]]([[RESULT]], [[WRITE]])
+  s2.w = s.w
+
+// CHECK:         copy_addr %1 to [initialization] [[SIZE_BOX:%.*]] : $*Size
+// CHECK:         [[FN:%.*]] = function_ref @$S16resilient_struct4SizeV1hSivg : $@convention(method) (@in_guaranteed Size) -> Int
+// CHECK:         [[RESULT:%.*]] = apply [[FN]]([[SIZE_BOX]])
+  _ = s.h
+
+// CHECK:         apply %2(%0, %1)
+// CHECK-NOT:         destroy_value %2
+// CHECK:         return
+  return f(s)
+}
+
+// Use materializeForSet for inout access of properties in resilient structs
+// from a different resilience domain
+
+public func inoutFunc(_ x: inout Int) {}
+
+// CHECK-LABEL: sil hidden @$S17struct_resilience18resilientInOutTestyy0c1_A04SizeVzF : $@convention(thin) (@inout Size) -> ()
+
+func resilientInOutTest(_ s: inout Size) {
+
+// CHECK:         function_ref @$S16resilient_struct4SizeV1wSivm
+// CHECK:         function_ref @$S17struct_resilience9inoutFuncyySizF
+
+  inoutFunc(&s.w)
+
+// CHECK: return
+}
+
+// Fixed-layout structs may be trivial or loadable
+
+// CHECK-LABEL: sil hidden @$S17struct_resilience28functionWithFixedLayoutTypes_1f010resilient_A05PointVAF_A2FXEtF : $@convention(thin) (Point, @noescape @callee_guaranteed (Point) -> Point) -> Point
+// CHECK:       bb0(%0 : @trivial $Point, %1 : @trivial $@noescape @callee_guaranteed (Point) -> Point):
+func functionWithFixedLayoutTypes(_ p: Point, f: (Point) -> Point) -> Point {
+
+  // Stored properties of fixed layout structs are accessed directly
+  var p2 = p
+
+// CHECK:         [[RESULT:%.*]] = struct_extract %0 : $Point, #Point.x
+// CHECK:         [[DEST:%.*]] = struct_element_addr [[POINT_BOX:%[0-9]*]] : $*Point, #Point.x
+// CHECK:         assign [[RESULT]] to [[DEST]] : $*Int
+  p2.x = p.x
+
+// CHECK:         [[RESULT:%.*]] = struct_extract %0 : $Point, #Point.y
+  _ = p.y
+
+// CHECK:         [[NEW_POINT:%.*]] = apply %1(%0)
+// CHECK:         return [[NEW_POINT]]
+  return f(p)
+}
+
+// Fixed-layout struct with resilient stored properties is still address-only
+
+// CHECK-LABEL: sil hidden @$S17struct_resilience39functionWithFixedLayoutOfResilientTypes_1f010resilient_A09RectangleVAF_A2FXEtF : $@convention(thin) (@in_guaranteed Rectangle, @noescape @callee_guaranteed (@in_guaranteed Rectangle) -> @out Rectangle) -> @out Rectangle
+// CHECK:        bb0(%0 : @trivial $*Rectangle, %1 : @trivial $*Rectangle, %2 : @trivial $@noescape @callee_guaranteed (@in_guaranteed Rectangle) -> @out Rectangle):
+func functionWithFixedLayoutOfResilientTypes(_ r: Rectangle, f: (Rectangle) -> Rectangle) -> Rectangle {
+  return f(r)
+}
+
+// Make sure we generate getters and setters for stored properties of
+// resilient structs
+
+public struct MySize {
+
+  // Static computed property
+
+// CHECK-LABEL: sil @$S17struct_resilience6MySizeV10expirationSivgZ : $@convention(method) (@thin MySize.Type) -> Int
+// CHECK-LABEL: sil @$S17struct_resilience6MySizeV10expirationSivsZ : $@convention(method) (Int, @thin MySize.Type) -> ()
+// CHECK-LABEL: sil @$S17struct_resilience6MySizeV10expirationSivmZ : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @thin MySize.Type) -> (Builtin.RawPointer, Optional<Builtin.RawPointer>)
+  public static var expiration: Int {
+    get { return copyright + 70 }
+    set { copyright = newValue - 70 }
+  }
+
+  // Instance computed property
+
+// CHECK-LABEL: sil @$S17struct_resilience6MySizeV1dSivg : $@convention(method) (@in_guaranteed MySize) -> Int
+// CHECK-LABEL: sil @$S17struct_resilience6MySizeV1dSivs : $@convention(method) (Int, @inout MySize) -> ()
+// CHECK-LABEL: sil @$S17struct_resilience6MySizeV1dSivm : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout MySize) -> (Builtin.RawPointer, Optional<Builtin.RawPointer>)
+  public var d: Int {
+    get { return 0 }
+    set { }
+  }
+
+  // Instance stored property
+
+// CHECK-LABEL: sil @$S17struct_resilience6MySizeV1wSivg : $@convention(method) (@in_guaranteed MySize) -> Int
+// CHECK-LABEL: sil @$S17struct_resilience6MySizeV1wSivs : $@convention(method) (Int, @inout MySize) -> ()
+// CHECK-LABEL: sil @$S17struct_resilience6MySizeV1wSivm : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout MySize) -> (Builtin.RawPointer, Optional<Builtin.RawPointer>)
+  public var w: Int
+
+  // Read-only instance stored property
+
+// CHECK-LABEL: sil @$S17struct_resilience6MySizeV1hSivg : $@convention(method) (@in_guaranteed MySize) -> Int
+  public let h: Int
+
+  // Static stored property
+
+// CHECK-LABEL: sil @$S17struct_resilience6MySizeV9copyrightSivgZ : $@convention(method) (@thin MySize.Type) -> Int
+// CHECK-LABEL: sil @$S17struct_resilience6MySizeV9copyrightSivsZ : $@convention(method) (Int, @thin MySize.Type) -> ()
+// CHECK-LABEL: sil @$S17struct_resilience6MySizeV9copyrightSivmZ : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @thin MySize.Type) -> (Builtin.RawPointer, Optional<Builtin.RawPointer>)
+  public static var copyright: Int = 0
+}
+
+// CHECK-LABEL: sil @$S17struct_resilience28functionWithMyResilientTypes_1fAA0E4SizeVAE_A2EXEtF : $@convention(thin) (@in_guaranteed MySize, @noescape @callee_guaranteed (@in_guaranteed MySize) -> @out MySize) -> @out MySize
+public func functionWithMyResilientTypes(_ s: MySize, f: (MySize) -> MySize) -> MySize {
+
+  // Stored properties of resilient structs from inside our resilience
+  // domain are accessed directly
+
+// CHECK:         copy_addr %1 to [initialization] [[SIZE_BOX:%[0-9]*]] : $*MySize
+  var s2 = s
+
+// CHECK:         [[SRC_ADDR:%.*]] = struct_element_addr %1 : $*MySize, #MySize.w
+// CHECK:         [[SRC:%.*]] = load [trivial] [[SRC_ADDR]] : $*Int
+// CHECK:         [[WRITE:%.*]] = begin_access [modify] [unknown] [[SIZE_BOX]] : $*MySize
+// CHECK:         [[DEST_ADDR:%.*]] = struct_element_addr [[WRITE]] : $*MySize, #MySize.w
+// CHECK:         assign [[SRC]] to [[DEST_ADDR]] : $*Int
+  s2.w = s.w
+
+// CHECK:         [[RESULT_ADDR:%.*]] = struct_element_addr %1 : $*MySize, #MySize.h
+// CHECK:         [[RESULT:%.*]] = load [trivial] [[RESULT_ADDR]] : $*Int
+  _ = s.h
+
+// CHECK:         apply %2(%0, %1)
+// CHECK-NOT:         destroy_value %2
+// CHECK:         return
+  return f(s)
+}
+
+// CHECK-LABEL: sil [transparent] [serialized] @$S17struct_resilience25publicTransparentFunctionySiAA6MySizeVF : $@convention(thin) (@in_guaranteed MySize) -> Int
+@_transparent public func publicTransparentFunction(_ s: MySize) -> Int {
+
+  // Since the body of a public transparent function might be inlined into
+  // other resilience domains, we have to use accessors
+
+// CHECK:         [[SELF:%.*]] = alloc_stack $MySize
+// CHECK-NEXT:    copy_addr %0 to [initialization] [[SELF]]
+
+// CHECK:         [[GETTER:%.*]] = function_ref @$S17struct_resilience6MySizeV1wSivg
+// CHECK-NEXT:    [[RESULT:%.*]] = apply [[GETTER]]([[SELF]])
+// CHECK-NEXT:    destroy_addr [[SELF]]
+// CHECK-NEXT:    dealloc_stack [[SELF]]
+// CHECK-NEXT:    return [[RESULT]]
+  return s.w
+}
+
+// CHECK-LABEL: sil [transparent] [serialized] @$S17struct_resilience30publicTransparentLocalFunctionySiycAA6MySizeVF : $@convention(thin) (@in_guaranteed MySize) -> @owned @callee_guaranteed () -> Int
+@_transparent public func publicTransparentLocalFunction(_ s: MySize) -> () -> Int {
+
+// CHECK-LABEL: sil shared [serialized] @$S17struct_resilience30publicTransparentLocalFunctionySiycAA6MySizeVFSiycfU_ : $@convention(thin) (@guaranteed { var MySize }) -> Int
+// CHECK: function_ref @$S17struct_resilience6MySizeV1wSivg : $@convention(method) (@in_guaranteed MySize) -> Int
+// CHECK: return {{.*}} : $Int
+
+  return { s.w }
+
+}
+
+// CHECK-LABEL: sil hidden [transparent] @$S17struct_resilience27internalTransparentFunctionySiAA6MySizeVF : $@convention(thin) (@in_guaranteed MySize) -> Int
+// CHECK: bb0([[ARG:%.*]] : @trivial $*MySize):
+@_transparent func internalTransparentFunction(_ s: MySize) -> Int {
+
+  // The body of an internal transparent function will not be inlined into
+  // other resilience domains, so we can access storage directly
+
+// CHECK:         [[W_ADDR:%.*]] = struct_element_addr [[ARG]] : $*MySize, #MySize.w
+// CHECK-NEXT:    [[RESULT:%.*]] = load [trivial] [[W_ADDR]] : $*Int
+// CHECK-NEXT:    return [[RESULT]]
+  return s.w
+}
+
+// CHECK-LABEL: sil [serialized] [always_inline] @$S17struct_resilience26publicInlineAlwaysFunctionySiAA6MySizeVF : $@convention(thin) (@in_guaranteed MySize) -> Int
+@inline(__always) public func publicInlineAlwaysFunction(_ s: MySize) -> Int {
+
+  // Since the body of a public transparent function might be inlined into
+  // other resilience domains, we have to use accessors
+
+// CHECK:         [[SELF:%.*]] = alloc_stack $MySize
+// CHECK-NEXT:    copy_addr %0 to [initialization] [[SELF]]
+
+// CHECK:         [[GETTER:%.*]] = function_ref @$S17struct_resilience6MySizeV1wSivg
+// CHECK-NEXT:    [[RESULT:%.*]] = apply [[GETTER]]([[SELF]])
+// CHECK-NEXT:    destroy_addr [[SELF]]
+// CHECK-NEXT:    dealloc_stack [[SELF]]
+// CHECK-NEXT:    return [[RESULT]]
+  return s.w
+
+}
+
+// Make sure that @_versioned entities can be resilient
+
+@_versioned struct VersionedResilientStruct {
+  @_versioned let x: Int
+  @_versioned let y: Int
+
+  @_versioned init(x: Int, y: Int) {
+    self.x = x
+    self.y = y
+  }
+
+  // Non-inlineable initializer, assigns to self -- treated as a root initializer
+
+  // CHECK-LABEL: sil @$S17struct_resilience24VersionedResilientStructV5otherA2C_tcfC : $@convention(method) (@in VersionedResilientStruct, @thin VersionedResilientStruct.Type) -> @out VersionedResilientStruct
+  // CHECK:      [[SELF_BOX:%.*]] = alloc_box ${ var VersionedResilientStruct }
+  // CHECK-NEXT: [[SELF_UNINIT:%.*]] = mark_uninitialized [rootself] [[SELF_BOX]]
+  // CHECK:      return
+  @_versioned init(other: VersionedResilientStruct) {
+    self = other
+  }
+
+  // Inlineable initializer, assigns to self -- treated as a delegating initializer
+
+  // CHECK-LABEL: sil [serialized] @$S17struct_resilience24VersionedResilientStructV6other2A2C_tcfC : $@convention(method) (@in VersionedResilientStruct, @thin VersionedResilientStruct.Type) -> @out VersionedResilientStruct
+  // CHECK:      [[SELF_BOX:%.*]] = alloc_box ${ var VersionedResilientStruct }
+  // CHECK-NEXT: [[SELF_UNINIT:%.*]] = mark_uninitialized [delegatingself] [[SELF_BOX]]
+  // CHECK:      return
+  @_versioned @_inlineable init(other2: VersionedResilientStruct) {
+    self = other2
+  }
+}
+
+// CHECK-LABEL: sil [transparent] [serialized] @$S17struct_resilience27useVersionedResilientStructyAA0deF0VADF : $@convention(thin) (@in_guaranteed VersionedResilientStruct) -> @out VersionedResilientStruct
+@_versioned
+@_transparent func useVersionedResilientStruct(_ s: VersionedResilientStruct)
+    -> VersionedResilientStruct {
+  // CHECK:       function_ref @$S17struct_resilience24VersionedResilientStructV1ySivg
+  // CHECK:       function_ref @$S17struct_resilience24VersionedResilientStructV1xSivg
+  // CHECK:       function_ref @$S17struct_resilience24VersionedResilientStructV1x1yACSi_SitcfC
+
+  return VersionedResilientStruct(x: s.y, y: s.x)
+
+  // CHECK:       return
+}
+
+// CHECK-LABEL: sil [serialized] @$S17struct_resilience19inlineableInoutTestyyAA6MySizeVzF : $@convention(thin) (@inout MySize) -> ()
+@_inlineable public func inlineableInoutTest(_ s: inout MySize) {
+  // Inlineable functions can be inlined in other resiliene domains.
+  //
+  // Make sure we use materializeForSet for an inout access of a resilient struct
+  // property inside an inlinable function.
+
+  // CHECK:       function_ref @$S17struct_resilience6MySizeV1wSivm
+  inoutFunc(&s.w)
+
+  // CHECK:       return
+}
+
+// Initializers for resilient structs
+extension Size {
+
+  // CHECK-LABEL: sil hidden @$S16resilient_struct4SizeV0B11_resilienceE5otherA2C_tcfC : $@convention(method) (@in Size, @thin Size.Type) -> @out Size
+  // CHECK:      [[SELF_BOX:%.*]] = alloc_box ${ var Size }
+  // CHECK-NEXT: [[SELF_UNINIT:%.*]] = mark_uninitialized [delegatingself] [[SELF_BOX]] : ${ var Size }
+  // CHECK:      return
+  init(other: Size) {
+    self = other
+  }
+}
diff --git a/test/SILGen/plus_zero_subclass_existentials.swift b/test/SILGen/plus_zero_subclass_existentials.swift
new file mode 100644
index 0000000..0189ede
--- /dev/null
+++ b/test/SILGen/plus_zero_subclass_existentials.swift
@@ -0,0 +1,469 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -Xllvm -sil-full-demangle -emit-silgen -parse-as-library -primary-file %s -verify | %FileCheck %s
+// RUN: %target-swift-frontend -emit-ir -parse-as-library -primary-file %s
+
+// Note: we pass -verify above to ensure there are no spurious
+// compiler warnings relating to casts.
+
+protocol Q {}
+
+class Base<T> : Q {
+  required init(classInit: ()) {}
+  func classSelfReturn() -> Self {
+    return self
+  }
+  static func classSelfReturn() -> Self {
+    return self.init(classInit: ())
+  }
+}
+
+protocol P {
+  init(protocolInit: ())
+  func protocolSelfReturn() -> Self
+  static func protocolSelfReturn() -> Self
+}
+
+class Derived : Base<Int>, P {
+  required init(protocolInit: ()) {
+    super.init(classInit: ())
+  }
+
+  required init(classInit: ()) {
+    super.init(classInit: ())
+  }
+
+  func protocolSelfReturn() -> Self {
+    return self
+  }
+  static func protocolSelfReturn() -> Self {
+    return self.init(classInit: ())
+  }
+}
+
+protocol R {}
+
+// CHECK-LABEL: sil hidden @$S21subclass_existentials11conversions8baseAndP7derived0fE1R0dE5PType0F4Type0fE5RTypeyAA1P_AA4BaseCySiGXc_AA7DerivedCAA1R_ANXcAaI_ALXcXpANmAaO_ANXcXptF : $@convention(thin) (@guaranteed Base<Int> & P, @guaranteed Derived, @guaranteed Derived & R, @thick (Base<Int> & P).Type, @thick Derived.Type, @thick (Derived & R).Type) -> () {
+// CHECK: bb0([[ARG0:%.*]] : $Base<Int> & P,
+
+func conversions(
+  baseAndP: Base<Int> & P,
+  derived: Derived,
+  derivedAndR: Derived & R,
+
+  baseAndPType: (Base<Int> & P).Type,
+  derivedType: Derived.Type,
+  derivedAndRType: (Derived & R).Type) {
+
+  // Values
+
+  // CHECK: [[PAYLOAD:%.*]] = open_existential_ref [[ARG0]] : $Base<Int> & P
+  // CHECK: [[REF:%.*]] = copy_value [[PAYLOAD]]
+  // CHECK: [[BASE:%.*]] = upcast [[REF]] : $@opened("{{.*}}") Base<Int> & P to $Base<Int>
+  // CHECK: destroy_value [[BASE]] : $Base<Int>
+  let _: Base<Int> = baseAndP
+
+  // CHECK: [[PAYLOAD:%.*]] = open_existential_ref [[ARG0]] : $Base<Int> & P
+  // CHECK: [[RESULT:%.*]] = alloc_stack $P
+  // CHECK: [[RESULT_PAYLOAD:%.*]] = init_existential_addr [[RESULT]] : $*P, $@opened("{{.*}}") Base<Int> & P
+  // CHECK: [[REF:%.*]] = copy_value [[PAYLOAD]]
+  // CHECK: store [[REF]] to [init] [[RESULT_PAYLOAD]]
+  // CHECK: destroy_addr [[RESULT]] : $*P
+  // CHECK: dealloc_stack [[RESULT]] : $*P
+  let _: P = baseAndP
+
+  // CHECK: [[PAYLOAD:%.*]] = open_existential_ref [[ARG0]] : $Base<Int> & P
+  // CHECK: [[RESULT:%.*]] = alloc_stack $Q
+  // CHECK: [[RESULT_PAYLOAD:%.*]] = init_existential_addr [[RESULT]] : $*Q, $@opened("{{.*}}") Base<Int> & P
+  // CHECK: [[REF:%.*]] = copy_value [[PAYLOAD]]
+  // CHECK: store [[REF]] to [init] [[RESULT_PAYLOAD]]
+  // CHECK: destroy_addr [[RESULT]] : $*Q
+  // CHECK: dealloc_stack [[RESULT]] : $*Q
+  let _: Q = baseAndP
+
+  // CHECK: [[PAYLOAD:%.*]] = open_existential_ref [[ARG2:%.*]] : $Derived & R
+  // CHECK: [[REF:%.*]] = copy_value [[PAYLOAD]]
+  // CHECK: [[RESULT:%.*]] = init_existential_ref [[REF]] : $@opened("{{.*}}") Derived & R : $@opened("{{.*}}") Derived & R, $Base<Int> & P
+  // CHECK: destroy_value [[RESULT]]
+  let _: Base<Int> & P = derivedAndR
+
+  // Metatypes
+
+  // CHECK: [[PAYLOAD:%.*]] = open_existential_metatype %3 : $@thick (Base<Int> & P).Type to $@thick (@opened("{{.*}}") (Base<Int> & P)).Type
+  // CHECK: [[RESULT:%.*]] = upcast [[PAYLOAD]] : $@thick (@opened("{{.*}}") (Base<Int> & P)).Type to $@thick Base<Int>.Type
+  let _: Base<Int>.Type = baseAndPType
+
+  // CHECK: [[PAYLOAD:%.*]] = open_existential_metatype %3 : $@thick (Base<Int> & P).Type to $@thick (@opened("{{.*}}") (Base<Int> & P)).Type
+  // CHECK: [[RESULT:%.*]] = init_existential_metatype [[PAYLOAD]] : $@thick (@opened("{{.*}}") (Base<Int> & P)).Type, $@thick P.Type
+  let _: P.Type = baseAndPType
+
+  // CHECK: [[PAYLOAD:%.*]] = open_existential_metatype %3 : $@thick (Base<Int> & P).Type to $@thick (@opened("{{.*}}") (Base<Int> & P)).Type
+  // CHECK: [[RESULT:%.*]] = init_existential_metatype [[PAYLOAD]] : $@thick (@opened("{{.*}}") (Base<Int> & P)).Type, $@thick Q.Type
+  let _: Q.Type = baseAndPType
+
+  // CHECK: [[RESULT:%.*]] = init_existential_metatype %4 : $@thick Derived.Type, $@thick (Base<Int> & P).Type
+  let _: (Base<Int> & P).Type = derivedType
+
+  // CHECK: [[PAYLOAD:%.*]] = open_existential_metatype %5 : $@thick (Derived & R).Type to $@thick (@opened("{{.*}}") (Derived & R)).Type
+  // CHECK: [[RESULT:%.*]] = init_existential_metatype [[PAYLOAD]] : $@thick (@opened("{{.*}}") (Derived & R)).Type, $@thick (Base<Int> & P).Type
+  let _: (Base<Int> & P).Type = derivedAndRType
+
+  // CHECK: return
+}
+
+// CHECK-LABEL: sil hidden @$S21subclass_existentials11methodCalls8baseAndP0eF5PTypeyAA1P_AA4BaseCySiGXc_AaE_AHXcXptF : $@convention(thin) (@guaranteed Base<Int> & P, @thick (Base<Int> & P).Type) -> () {
+
+func methodCalls(
+  baseAndP: Base<Int> & P,
+  baseAndPType: (Base<Int> & P).Type) {
+  // CHECK: bb0([[ARG0:%.*]] : $Base<Int> & P,
+  // CHECK: [[PAYLOAD:%.*]] = open_existential_ref [[ARG0]] : $Base<Int> & P to $@opened("{{.*}}") Base<Int> & P
+  // CHECK: [[REF:%.*]] = copy_value [[PAYLOAD]] : $@opened("{{.*}}") Base<Int> & P
+  // CHECK: [[CLASS_REF:%.*]] = upcast [[REF]] : $@opened("{{.*}}") Base<Int> & P to $Base<Int>
+  // CHECK: [[METHOD:%.*]] = class_method [[CLASS_REF]] : $Base<Int>, #Base.classSelfReturn!1 : <T> (Base<T>) -> () -> @dynamic_self Base<T>, $@convention(method) <τ_0_0> (@guaranteed Base<τ_0_0>) -> @owned Base<τ_0_0>
+  // CHECK: [[RESULT_CLASS_REF:%.*]] = apply [[METHOD]]<Int>([[CLASS_REF]]) : $@convention(method) <τ_0_0> (@guaranteed Base<τ_0_0>) -> @owned Base<τ_0_0>
+  // CHECK: destroy_value [[CLASS_REF]] : $Base<Int>
+  // CHECK: [[RESULT_REF:%.*]] = unchecked_ref_cast [[RESULT_CLASS_REF]] : $Base<Int> to $@opened("{{.*}}") Base<Int> & P
+  // CHECK: [[RESULT:%.*]] = init_existential_ref [[RESULT_REF]] : $@opened("{{.*}}") Base<Int> & P : $@opened("{{.*}}") Base<Int> & P, $Base<Int> & P
+  // CHECK: destroy_value [[RESULT]] : $Base<Int> & P
+  let _: Base<Int> & P = baseAndP.classSelfReturn()
+
+  // CHECK: [[PAYLOAD:%.*]] = open_existential_ref [[ARG0]] : $Base<Int> & P to $@opened("{{.*}}") Base<Int> & P
+  // CHECK: [[RESULT_BOX:%.*]] = alloc_stack $@opened("{{.*}}") Base<Int> & P
+  // CHECK: [[SELF_BOX:%.*]] = alloc_stack $@opened("{{.*}}") Base<Int> & P
+  // CHECK: store_borrow [[PAYLOAD]] to [[SELF_BOX]] : $*@opened("{{.*}}") Base<Int> & P
+  // CHECK: [[METHOD:%.*]] = witness_method $@opened("{{.*}}") Base<Int> & P, #P.protocolSelfReturn!1 : <Self where Self : P> (Self) -> () -> @dynamic_self Self, [[PAYLOAD]] : $@opened("{{.*}}") Base<Int> & P : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @out τ_0_0
+  // CHECK: apply [[METHOD]]<@opened("{{.*}}") Base<Int> & P>([[RESULT_BOX]], [[SELF_BOX]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @out τ_0_0
+  // CHECK: dealloc_stack [[SELF_BOX]] : $*@opened("{{.*}}") Base<Int> & P
+  // CHECK: [[RESULT_REF:%.*]] = load [take] [[RESULT_BOX]] : $*@opened("{{.*}}") Base<Int> & P
+  // CHECK: [[RESULT:%.*]] = init_existential_ref [[RESULT_REF]] : $@opened("{{.*}}") Base<Int> & P : $@opened("{{.*}}") Base<Int> & P, $Base<Int> & P
+  // CHECK: destroy_value [[RESULT]] : $Base<Int> & P
+  // CHECK: dealloc_stack [[RESULT_BOX]] : $*@opened("{{.*}}") Base<Int> & P
+  let _: Base<Int> & P = baseAndP.protocolSelfReturn()
+
+  // CHECK: [[METATYPE:%.*]] = open_existential_metatype %1 : $@thick (Base<Int> & P).Type to $@thick (@opened("{{.*}}") (Base<Int> & P)).Type
+  // CHECK: [[METATYPE_REF:%.*]] = upcast [[METATYPE]] : $@thick (@opened("{{.*}}") (Base<Int> & P)).Type to $@thick Base<Int>.Type
+  // CHECK: [[METHOD:%.*]] = function_ref @$S21subclass_existentials4BaseC15classSelfReturnACyxGXDyFZ : $@convention(method) <τ_0_0> (@thick Base<τ_0_0>.Type) -> @owned Base<τ_0_0>
+  // CHECK: [[RESULT_REF2:%.*]] = apply [[METHOD]]<Int>([[METATYPE_REF]])
+  // CHECK: [[RESULT_REF:%.*]] = unchecked_ref_cast [[RESULT_REF2]] : $Base<Int> to $@opened("{{.*}}") (Base<Int> & P)
+  // CHECK: [[RESULT:%.*]] = init_existential_ref [[RESULT_REF]] : $@opened("{{.*}}") (Base<Int> & P) : $@opened("{{.*}}") (Base<Int> & P), $Base<Int> & P
+  // CHECK: destroy_value [[RESULT]]
+  let _: Base<Int> & P = baseAndPType.classSelfReturn()
+
+  // CHECK: [[METATYPE:%.*]] = open_existential_metatype %1 : $@thick (Base<Int> & P).Type to $@thick (@opened("{{.*}}") (Base<Int> & P)).Type
+  // CHECK: [[RESULT:%.*]] = alloc_stack $@opened("{{.*}}") (Base<Int> & P)
+  // CHECK: [[METHOD:%.*]] = witness_method $@opened("{{.*}}") (Base<Int> & P), #P.protocolSelfReturn!1 : <Self where Self : P> (Self.Type) -> () -> @dynamic_self Self, [[METATYPE]] : $@thick (@opened("{{.*}}") (Base<Int> & P)).Type : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@thick τ_0_0.Type) -> @out τ_0_0
+  // CHECK: apply [[METHOD]]<@opened("{{.*}}") (Base<Int> & P)>([[RESULT]], [[METATYPE]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@thick τ_0_0.Type) -> @out τ_0_0
+  // CHECK: [[RESULT_REF:%.*]] = load [take] [[RESULT]] : $*@opened("{{.*}}") (Base<Int> & P)
+  // CHECK: [[RESULT_VALUE:%.*]] = init_existential_ref [[RESULT_REF]] : $@opened("{{.*}}") (Base<Int> & P) : $@opened("{{.*}}") (Base<Int> & P), $Base<Int> & P
+  // CHECK: destroy_value [[RESULT_VALUE]]
+  // CHECK: dealloc_stack [[RESULT]]
+  let _: Base<Int> & P = baseAndPType.protocolSelfReturn()
+
+  // Partial applications
+  let _: () -> (Base<Int> & P) = baseAndP.classSelfReturn
+  let _: () -> (Base<Int> & P) = baseAndP.protocolSelfReturn
+
+  let _: () -> (Base<Int> & P) = baseAndPType.classSelfReturn
+  let _: () -> (Base<Int> & P) = baseAndPType.protocolSelfReturn
+
+  let _: () -> (Base<Int> & P) = baseAndPType.init(classInit:)
+  let _: () -> (Base<Int> & P) = baseAndPType.init(protocolInit:)
+
+  // CHECK:      return
+  // CHECK-NEXT: }
+}
+
+protocol PropertyP {
+  var p: PropertyP & PropertyC { get set }
+
+  subscript(key: Int) -> Int { get set }
+}
+
+class PropertyC {
+  var c: PropertyP & PropertyC {
+    get {
+      return self as! PropertyP & PropertyC
+    }
+    set { }
+  }
+
+  subscript(key: (Int, Int)) -> Int {
+    get {
+      return 0
+    } set { }
+  }
+}
+
+// CHECK-LABEL: sil hidden @$S21subclass_existentials16propertyAccessesyyAA9PropertyP_AA0E1CCXcF : $@convention(thin) (@guaranteed PropertyC & PropertyP) -> () {
+func propertyAccesses(_ x: PropertyP & PropertyC) {
+  var xx = x
+  xx.p.p = x
+  xx.c.c = x
+
+  propertyAccesses(xx.p)
+  propertyAccesses(xx.c)
+
+  _ = xx[1]
+  xx[1] = 1
+  xx[1] += 1
+
+  _ = xx[(1, 2)]
+  xx[(1, 2)] = 1
+  xx[(1, 2)] += 1
+}
+
+// CHECK-LABEL: sil hidden @$S21subclass_existentials19functionConversions15returnsBaseAndP0efG5PType0E7Derived0eI4Type0eiG1R0eiG5RTypeyAA1P_AA0F0CySiGXcyc_AaI_ALXcXpycAA0I0CycANmycAA1R_ANXcycAaO_ANXcXpyctF : $@convention(thin) (@guaranteed @callee_guaranteed () -> @owned Base<Int> & P, @guaranteed @callee_guaranteed () -> @thick (Base<Int> & P).Type, @guaranteed @callee_guaranteed () -> @owned Derived, @guaranteed @callee_guaranteed () -> @thick Derived.Type, @guaranteed @callee_guaranteed () -> @owned Derived & R, @guaranteed @callee_guaranteed () -> @thick (Derived & R).Type) -> () {
+func functionConversions(
+  returnsBaseAndP: @escaping () -> (Base<Int> & P),
+  returnsBaseAndPType: @escaping () -> (Base<Int> & P).Type,
+  returnsDerived: @escaping () -> Derived,
+  returnsDerivedType: @escaping () -> Derived.Type,
+  returnsDerivedAndR: @escaping () -> Derived & R,
+  returnsDerivedAndRType: @escaping () -> (Derived & R).Type) {
+
+  let _: () -> Base<Int> = returnsBaseAndP
+  let _: () -> Base<Int>.Type = returnsBaseAndPType
+
+  let _: () -> P = returnsBaseAndP
+  let _: () -> P.Type = returnsBaseAndPType
+
+  let _: () -> (Base<Int> & P) = returnsDerived
+  let _: () -> (Base<Int> & P).Type = returnsDerivedType
+
+  let _: () -> Base<Int> = returnsDerivedAndR
+  let _: () -> Base<Int>.Type = returnsDerivedAndRType
+
+  let _: () -> (Base<Int> & P) = returnsDerivedAndR
+  let _: () -> (Base<Int> & P).Type = returnsDerivedAndRType
+
+  let _: () -> P = returnsDerivedAndR
+  let _: () -> P.Type = returnsDerivedAndRType
+
+  // CHECK:      return %
+  // CHECK-NEXT: }
+}
+
+// CHECK-LABEL: sil hidden @$S21subclass_existentials9downcasts8baseAndP7derived0dE5PType0F4TypeyAA1P_AA4BaseCySiGXc_AA7DerivedCAaG_AJXcXpALmtF : $@convention(thin) (@guaranteed Base<Int> & P, @guaranteed Derived, @thick (Base<Int> & P).Type, @thick Derived.Type) -> () {
+func downcasts(
+  baseAndP: Base<Int> & P,
+  derived: Derived,
+  baseAndPType: (Base<Int> & P).Type,
+  derivedType: Derived.Type) {
+  // CHECK: bb0([[ARG0:%.*]] : $Base<Int> & P, [[ARG1:%.*]] : $Derived, [[ARG2:%.*]] : $@thick (Base<Int> & P).Type, [[ARG3:%.*]] : $@thick Derived.Type):
+  // CHECK: [[COPIED:%.*]] = copy_value [[ARG0]] : $Base<Int> & P
+  // CHECK-NEXT: checked_cast_br [[COPIED]] : $Base<Int> & P to $Derived
+  let _ = baseAndP as? Derived
+
+  // CHECK: [[COPIED:%.*]] = copy_value [[ARG0]] : $Base<Int> & P
+  // CHECK-NEXT: unconditional_checked_cast [[COPIED]] : $Base<Int> & P to $Derived
+  let _ = baseAndP as! Derived
+
+  // CHECK: [[COPIED:%.*]] = copy_value [[ARG0]] : $Base<Int> & P
+  // CHECK-NEXT: checked_cast_br [[COPIED]] : $Base<Int> & P to $Derived & R
+  let _ = baseAndP as? (Derived & R)
+
+  // CHECK: [[COPIED:%.*]] = copy_value [[ARG0]] : $Base<Int> & P
+  // CHECK-NEXT: unconditional_checked_cast [[COPIED]] : $Base<Int> & P to $Derived & R
+  let _ = baseAndP as! (Derived & R)
+
+  // CHECK:      checked_cast_br %3 : $@thick Derived.Type to $@thick (Derived & R).Type
+  let _ = derivedType as? (Derived & R).Type
+
+  // CHECK:      unconditional_checked_cast %3 : $@thick Derived.Type to $@thick (Derived & R).Type
+  let _ = derivedType as! (Derived & R).Type
+
+  // CHECK:      checked_cast_br %2 : $@thick (Base<Int> & P).Type to $@thick Derived.Type
+  let _ = baseAndPType as? Derived.Type
+
+  // CHECK:      unconditional_checked_cast %2 : $@thick (Base<Int> & P).Type to $@thick Derived.Type
+  let _ = baseAndPType as! Derived.Type
+
+  // CHECK:      checked_cast_br %2 : $@thick (Base<Int> & P).Type to $@thick (Derived & R).Type
+  let _ = baseAndPType as? (Derived & R).Type
+
+  // CHECK:      unconditional_checked_cast %2 : $@thick (Base<Int> & P).Type to $@thick (Derived & R).Type
+  let _ = baseAndPType as! (Derived & R).Type
+
+  // CHECK:      return
+  // CHECK-NEXT: }
+}
+
+// CHECK-LABEL: sil hidden @$S21subclass_existentials16archetypeUpcasts9baseTAndP0E7IntAndP7derivedyq__q0_q1_tAA4BaseCyxGRb_AA1PR_AGySiGRb0_AaIR0_AA7DerivedCRb1_r2_lF : $@convention(thin) <T, BaseTAndP, BaseIntAndP, DerivedT where BaseTAndP : Base<T>, BaseTAndP : P, BaseIntAndP : Base<Int>, BaseIntAndP : P, DerivedT : Derived> (@guaranteed BaseTAndP, @guaranteed BaseIntAndP, @guaranteed DerivedT) -> () {
+func archetypeUpcasts<T,
+                      BaseTAndP : Base<T> & P,
+                      BaseIntAndP : Base<Int> & P,
+                      DerivedT : Derived>(
+  baseTAndP: BaseTAndP,
+  baseIntAndP : BaseIntAndP,
+  derived : DerivedT) {
+  // CHECK: bb0([[ARG0:%.*]] : $BaseTAndP, [[ARG1:%.*]] : $BaseIntAndP, [[ARG2:%.*]] : $DerivedT)
+  // CHECK: [[COPIED:%.*]] = copy_value [[ARG0]] : $BaseTAndP
+  // CHECK-NEXT: init_existential_ref [[COPIED]] : $BaseTAndP : $BaseTAndP, $Base<T> & P
+  let _: Base<T> & P = baseTAndP
+
+  // CHECK: [[COPIED:%.*]] = copy_value [[ARG1]] : $BaseIntAndP
+  // CHECK-NEXT: init_existential_ref [[COPIED]] : $BaseIntAndP : $BaseIntAndP, $Base<Int> & P
+  let _: Base<Int> & P = baseIntAndP
+
+  // CHECK: [[COPIED:%.*]] = copy_value [[ARG2]] : $DerivedT
+  // CHECK-NEXT: init_existential_ref [[COPIED]] : $DerivedT : $DerivedT, $Base<Int> & P
+  let _: Base<Int> & P = derived
+
+  // CHECK:      return
+  // CHECK-NEXT: }
+}
+
+// CHECK-LABEL: sil hidden @$S21subclass_existentials18archetypeDowncasts1s1t2pt5baseT0F3Int0f6TAndP_C00fg5AndP_C008derived_C00ji2R_C00fH10P_concrete0fgi2P_K0yx_q_q0_q1_q2_q3_q4_q5_AA1R_AA7DerivedCXcAA1P_AA4BaseCyq_GXcAaQ_ASySiGXctAaQR0_ATRb1_AURb2_ATRb3_AaQR3_AURb4_AaQR4_APRb5_r6_lF : $@convention(thin) <S, T, PT, BaseT, BaseInt, BaseTAndP, BaseIntAndP, DerivedT where PT : P, BaseT : Base<T>, BaseInt : Base<Int>, BaseTAndP : Base<T>, BaseTAndP : P, BaseIntAndP : Base<Int>, BaseIntAndP : P, DerivedT : Derived> (@in_guaranteed S, @in_guaranteed T, @in_guaranteed PT, @guaranteed BaseT, @guaranteed BaseInt, @guaranteed BaseTAndP, @guaranteed BaseIntAndP, @guaranteed DerivedT, @guaranteed Derived & R, @guaranteed Base<T> & P, @guaranteed Base<Int> & P) -> () {
+func archetypeDowncasts<S,
+                        T,
+                        PT : P,
+                        BaseT : Base<T>,
+                        BaseInt : Base<Int>,
+                        BaseTAndP : Base<T> & P,
+                        BaseIntAndP : Base<Int> & P,
+                        DerivedT : Derived>(
+  s: S,
+  t: T,
+  pt: PT,
+  baseT : BaseT,
+  baseInt : BaseInt,
+
+  baseTAndP_archetype: BaseTAndP,
+  baseIntAndP_archetype : BaseIntAndP,
+  derived_archetype : DerivedT,
+  derivedAndR_archetype : Derived & R,
+
+  baseTAndP_concrete: Base<T> & P,
+  baseIntAndP_concrete: Base<Int> & P) {
+
+  // CHECK: ([[ARG0:%.*]] : $*S, [[ARG1:%.*]] : $*T, [[ARG2:%.*]] : $*PT, [[ARG3:%.*]] : $BaseT, [[ARG4:%.*]] : $BaseInt, [[ARG5:%.*]] : $BaseTAndP, [[ARG6:%.*]] : $BaseIntAndP, [[ARG7:%.*]] : $DerivedT, [[ARG8:%.*]] : $Derived & R, [[ARG9:%.*]] : $Base<T> & P, [[ARG10:%.*]] : $Base<Int> & P)
+
+  // CHECK:      [[COPY:%.*]] = alloc_stack $S
+  // CHECK-NEXT: copy_addr %0 to [initialization] [[COPY]] : $*S
+  // CHECK-NEXT: [[RESULT:%.*]] = alloc_stack $Base<T> & P
+  // CHECK-NEXT: checked_cast_addr_br take_always S in [[COPY]] : $*S to Base<T> & P in [[RESULT]] : $*Base<T> & P
+  let _ = s as? (Base<T> & P)
+
+  // CHECK:      [[COPY:%.*]] = alloc_stack $S
+  // CHECK-NEXT: copy_addr [[ARG0]] to [initialization] [[COPY]] : $*S
+  // CHECK-NEXT: [[RESULT:%.*]] = alloc_stack $Base<T> & P
+  // CHECK-NEXT: unconditional_checked_cast_addr S in [[COPY]] : $*S to Base<T> & P in [[RESULT]] : $*Base<T> & P
+  let _ = s as! (Base<T> & P)
+
+  // CHECK:      [[COPY:%.*]] = alloc_stack $S
+  // CHECK-NEXT: copy_addr [[ARG0]] to [initialization] [[COPY]] : $*S
+  // CHECK-NEXT: [[RESULT:%.*]] = alloc_stack $Base<Int> & P
+  // CHECK-NEXT: checked_cast_addr_br take_always S in [[COPY]] : $*S to Base<Int> & P in [[RESULT]] : $*Base<Int> & P
+  let _ = s as? (Base<Int> & P)
+
+  // CHECK:      [[COPY:%.*]] = alloc_stack $S
+  // CHECK-NEXT: copy_addr [[ARG0]] to [initialization] [[COPY]] : $*S
+  // CHECK-NEXT: [[RESULT:%.*]] = alloc_stack $Base<Int> & P
+  // CHECK-NEXT: unconditional_checked_cast_addr S in [[COPY]] : $*S to Base<Int> & P in [[RESULT]] : $*Base<Int> & P
+  let _ = s as! (Base<Int> & P)
+
+  // CHECK: [[COPIED:%.*]] = copy_value [[ARG5]] : $BaseTAndP
+  // CHECK-NEXT: checked_cast_br [[COPIED]] : $BaseTAndP to $Derived & R
+  let _ = baseTAndP_archetype as? (Derived & R)
+
+  // CHECK: [[COPIED:%.*]] = copy_value [[ARG5]] : $BaseTAndP
+  // CHECK-NEXT: unconditional_checked_cast [[COPIED]] : $BaseTAndP to $Derived & R
+  let _ = baseTAndP_archetype as! (Derived & R)
+
+  // CHECK: [[COPIED:%.*]] = copy_value [[ARG9]] : $Base<T> & P
+  // CHECK-NEXT: [[COPY:%.*]] = alloc_stack $Base<T> & P
+  // CHECK-NEXT: store [[COPIED]] to [init] [[COPY]] : $*Base<T> & P
+  // CHECK-NEXT: [[RESULT:%.*]] = alloc_stack $Optional<S>
+  // CHECK-NEXT: [[PAYLOAD:%.*]] = init_enum_data_addr [[RESULT]] : $*Optional<S>, #Optional.some
+  // CHECK-NEXT: checked_cast_addr_br take_always Base<T> & P in [[COPY]] : $*Base<T> & P to S in [[PAYLOAD]] : $*S
+  let _ = baseTAndP_concrete as? S
+
+  // CHECK:      [[COPY:%.*]] = alloc_stack $Base<T> & P
+  // CHECK-NEXT: [[COPIED:%.*]] = copy_value [[ARG9]] : $Base<T> & P
+  // CHECK-NEXT: store [[COPIED]] to [init] [[COPY]] : $*Base<T> & P
+  // CHECK-NEXT: [[RESULT:%.*]] = alloc_stack $S
+  // CHECK-NEXT: unconditional_checked_cast_addr Base<T> & P in [[COPY]] : $*Base<T> & P to S in [[RESULT]] : $*S
+  let _ = baseTAndP_concrete as! S
+
+  // CHECK: [[COPIED:%.*]] = copy_value [[ARG9]] : $Base<T> & P
+  // CHECK-NEXT: checked_cast_br [[COPIED]] : $Base<T> & P to $BaseT
+  let _ = baseTAndP_concrete as? BaseT
+
+  // CHECK: [[COPIED:%.*]] = copy_value [[ARG9]] : $Base<T> & P
+  // CHECK-NEXT: unconditional_checked_cast [[COPIED]] : $Base<T> & P to $BaseT
+  let _ = baseTAndP_concrete as! BaseT
+
+  // CHECK: [[COPIED:%.*]] = copy_value [[ARG9]] : $Base<T> & P
+  // CHECK-NEXT: checked_cast_br [[COPIED]] : $Base<T> & P to $BaseInt
+  let _ = baseTAndP_concrete as? BaseInt
+
+  // CHECK: [[COPIED:%.*]] = copy_value [[ARG9]] : $Base<T> & P
+  // CHECK-NEXT: unconditional_checked_cast [[COPIED]] : $Base<T> & P to $BaseInt
+  let _ = baseTAndP_concrete as! BaseInt
+
+  // CHECK: [[COPIED:%.*]] = copy_value [[ARG9]] : $Base<T> & P
+  // CHECK-NEXT: checked_cast_br [[COPIED]] : $Base<T> & P to $BaseTAndP
+  let _ = baseTAndP_concrete as? BaseTAndP
+
+  // CHECK: [[COPIED:%.*]] = copy_value [[ARG9]] : $Base<T> & P
+  // CHECK-NEXT: unconditional_checked_cast [[COPIED]] : $Base<T> & P to $BaseTAndP
+  let _ = baseTAndP_concrete as! BaseTAndP
+
+  // CHECK: [[COPIED:%.*]] = copy_value [[ARG6]] : $BaseIntAndP
+  // CHECK-NEXT: checked_cast_br [[COPIED]] : $BaseIntAndP to $Derived & R
+  let _ = baseIntAndP_archetype as? (Derived & R)
+
+  // CHECK: [[COPIED:%.*]] = copy_value [[ARG6]] : $BaseIntAndP
+  // CHECK-NEXT: unconditional_checked_cast [[COPIED]] : $BaseIntAndP to $Derived & R
+  let _ = baseIntAndP_archetype as! (Derived & R)
+
+  // CHECK: [[COPIED:%.*]] = copy_value [[ARG10]] : $Base<Int> & P
+  // CHECK-NEXT: [[COPY:%.*]] = alloc_stack $Base<Int> & P
+  // CHECK-NEXT: store [[COPIED]] to [init] [[COPY]] : $*Base<Int> & P
+  // CHECK-NEXT: [[RESULT:%.*]] = alloc_stack $Optional<S>
+  // CHECK-NEXT: [[PAYLOAD:%.*]] = init_enum_data_addr [[RESULT]] : $*Optional<S>, #Optional.some
+  // CHECK-NEXT: checked_cast_addr_br take_always Base<Int> & P in [[COPY]] : $*Base<Int> & P to S in [[PAYLOAD]] : $*S
+  let _ = baseIntAndP_concrete as? S
+
+  // CHECK:      [[COPY:%.*]] = alloc_stack $Base<Int> & P
+  // CHECK-NEXT: [[COPIED:%.*]] = copy_value [[ARG10]] : $Base<Int> & P
+  // CHECK-NEXT: store [[COPIED]] to [init] [[COPY]] : $*Base<Int> & P
+  // CHECK-NEXT: [[RESULT:%.*]] = alloc_stack $S
+  // CHECK-NEXT: unconditional_checked_cast_addr Base<Int> & P in [[COPY]] : $*Base<Int> & P to S in [[RESULT]] : $*S
+  let _ = baseIntAndP_concrete as! S
+
+  // CHECK: [[COPIED:%.*]] = copy_value [[ARG10]] : $Base<Int> & P
+  // CHECK-NEXT: checked_cast_br [[COPIED]] : $Base<Int> & P to $DerivedT
+  let _ = baseIntAndP_concrete as? DerivedT
+
+  // CHECK: [[COPIED:%.*]] = copy_value [[ARG10]] : $Base<Int> & P
+  // CHECK-NEXT: unconditional_checked_cast [[COPIED]] : $Base<Int> & P to $DerivedT
+  let _ = baseIntAndP_concrete as! DerivedT
+
+  // CHECK: [[COPIED:%.*]] = copy_value [[ARG10]] : $Base<Int> & P
+  // CHECK-NEXT: checked_cast_br [[COPIED]] : $Base<Int> & P to $BaseT
+  let _ = baseIntAndP_concrete as? BaseT
+
+  // CHECK: [[COPIED:%.*]] = copy_value [[ARG10]] : $Base<Int> & P
+  // CHECK-NEXT: unconditional_checked_cast [[COPIED]] : $Base<Int> & P to $BaseT
+  let _ = baseIntAndP_concrete as! BaseT
+
+  // CHECK: [[COPIED:%.*]] = copy_value [[ARG10]] : $Base<Int> & P
+  // CHECK-NEXT: checked_cast_br [[COPIED]] : $Base<Int> & P to $BaseInt
+  let _ = baseIntAndP_concrete as? BaseInt
+
+  // CHECK: [[COPIED:%.*]] = copy_value [[ARG10]] : $Base<Int> & P
+  // CHECK-NEXT: unconditional_checked_cast [[COPIED]] : $Base<Int> & P to $BaseInt
+  let _ = baseIntAndP_concrete as! BaseInt
+
+  // CHECK: [[COPIED:%.*]] = copy_value [[ARG10]] : $Base<Int> & P
+  // CHECK-NEXT: checked_cast_br [[COPIED]] : $Base<Int> & P to $BaseTAndP
+  let _ = baseIntAndP_concrete as? BaseTAndP
+
+  // CHECK: [[COPIED:%.*]] = copy_value [[ARG10]] : $Base<Int> & P
+  // CHECK-NEXT: unconditional_checked_cast [[COPIED]] : $Base<Int> & P to $BaseTAndP
+  let _ = baseIntAndP_concrete as! BaseTAndP
+
+  // CHECK:      return
+  // CHECK-NEXT: }
+}
diff --git a/test/SILGen/plus_zero_super.swift b/test/SILGen/plus_zero_super.swift
new file mode 100644
index 0000000..5184967
--- /dev/null
+++ b/test/SILGen/plus_zero_super.swift
@@ -0,0 +1,202 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %empty-directory(%t)
+// RUN: %target-swift-frontend -I %t -emit-module -emit-module-path=%t/resilient_struct.swiftmodule -module-name resilient_struct %S/../Inputs/resilient_struct.swift
+// RUN: %target-swift-frontend -I %t -emit-module -emit-module-path=%t/resilient_class.swiftmodule -module-name resilient_class %S/../Inputs/resilient_class.swift
+// RUN: %target-swift-frontend -emit-silgen -parse-as-library -I %t %s | %FileCheck %s
+
+import resilient_class
+
+public class Parent {
+  public final var finalProperty: String {
+    return "Parent.finalProperty"
+  }
+
+  public var property: String {
+    return "Parent.property"
+  }
+
+  public final class var finalClassProperty: String {
+    return "Parent.finalProperty"
+  }
+
+  public class var classProperty: String {
+    return "Parent.property"
+  }
+
+  public func methodOnlyInParent() {}
+  public final func finalMethodOnlyInParent() {}
+  public func method() {}
+
+  public final class func finalClassMethodOnlyInParent() {}
+  public class func classMethod() {}
+}
+
+public class Child : Parent {
+  // CHECK-LABEL: sil @$S5super5ChildC8propertySSvg : $@convention(method) (@guaranteed Child) -> @owned String {
+  // CHECK:       bb0([[SELF:%.*]] : $Child):
+  // CHECK:         [[SELF_COPY:%.*]] = copy_value [[SELF]]
+  // CHECK:         [[CASTED_SELF_COPY:%[0-9]+]] = upcast [[SELF_COPY]] : $Child to $Parent
+  // CHECK:         [[SUPER_METHOD:%[0-9]+]] = function_ref @$S5super6ParentC8propertySSvg : $@convention(method) (@guaranteed Parent) -> @owned String
+  // CHECK:         [[RESULT:%.*]] = apply [[SUPER_METHOD]]([[CASTED_SELF_COPY]])
+  // CHECK:         destroy_value [[CASTED_SELF_COPY]]
+  // CHECK:         return [[RESULT]]
+  public override var property: String {
+    return super.property
+  }
+
+  // CHECK-LABEL: sil @$S5super5ChildC13otherPropertySSvg : $@convention(method) (@guaranteed Child) -> @owned String {
+  // CHECK:       bb0([[SELF:%.*]] : $Child):
+  // CHECK:         [[COPIED_SELF:%.*]] = copy_value [[SELF]]
+  // CHECK:         [[CASTED_SELF_COPY:%[0-9]+]] = upcast [[COPIED_SELF]] : $Child to $Parent
+  // CHECK:         [[SUPER_METHOD:%[0-9]+]] = function_ref @$S5super6ParentC13finalPropertySSvg
+  // CHECK:         [[RESULT:%.*]] = apply [[SUPER_METHOD]]([[CASTED_SELF_COPY]])
+  // CHECK:         destroy_value [[CASTED_SELF_COPY]]
+  // CHECK:         return [[RESULT]]
+  public var otherProperty: String {
+    return super.finalProperty
+  }
+}
+
+public class Grandchild : Child {
+  // CHECK-LABEL: sil @$S5super10GrandchildC06onlyInB0yyF
+  public func onlyInGrandchild() {
+    // CHECK: function_ref @$S5super6ParentC012methodOnlyInB0yyF : $@convention(method) (@guaranteed Parent) -> ()
+    super.methodOnlyInParent()
+    // CHECK: function_ref @$S5super6ParentC017finalMethodOnlyInB0yyF
+    super.finalMethodOnlyInParent()
+  }
+
+  // CHECK-LABEL: sil @$S5super10GrandchildC6methodyyF
+  public override func method() {
+    // CHECK: function_ref @$S5super6ParentC6methodyyF : $@convention(method) (@guaranteed Parent) -> ()
+    super.method()
+  }
+}
+
+public class GreatGrandchild : Grandchild {
+  // CHECK-LABEL: sil @$S5super15GreatGrandchildC6methodyyF
+  public override func method() {
+    // CHECK: function_ref @$S5super10GrandchildC6methodyyF : $@convention(method) (@guaranteed Grandchild) -> ()
+    super.method()
+  }
+}
+
+public class ChildToResilientParent : ResilientOutsideParent {
+  // CHECK-LABEL: sil @$S5super22ChildToResilientParentC6methodyyF : $@convention(method) (@guaranteed ChildToResilientParent) -> ()
+  public override func method() {
+    // CHECK: bb0([[SELF:%.*]] : $ChildToResilientParent):
+    // CHECK:   [[COPY_SELF:%.*]] = copy_value [[SELF]]
+    // CHECK:   [[UPCAST_SELF:%.*]] = upcast [[COPY_SELF]]
+    // CHECK:   [[BORROW_UPCAST_SELF:%.*]] = begin_borrow [[UPCAST_SELF]]
+    // CHECK:   [[CAST_BORROW_BACK_TO_BASE:%.*]] = unchecked_ref_cast [[BORROW_UPCAST_SELF]]
+    // CHECK:   [[FUNC:%.*]] = super_method [[CAST_BORROW_BACK_TO_BASE]] : $ChildToResilientParent, #ResilientOutsideParent.method!1 : (ResilientOutsideParent) -> () -> (), $@convention(method) (@guaranteed ResilientOutsideParent) -> ()
+    // CHECK:   end_borrow [[BORROW_UPCAST_SELF]] from [[UPCAST_SELF]]
+    // CHECK:   apply [[FUNC]]([[UPCAST_SELF]])
+    super.method()
+  }
+  // CHECK: } // end sil function '$S5super22ChildToResilientParentC6methodyyF'
+
+  // CHECK-LABEL: sil @$S5super22ChildToResilientParentC11classMethodyyFZ : $@convention(method) (@thick ChildToResilientParent.Type) -> ()
+  public override class func classMethod() {
+    // CHECK: bb0([[METASELF:%.*]] : $@thick ChildToResilientParent.Type):
+    // CHECK:   [[UPCAST_METASELF:%.*]] = upcast [[METASELF]]
+    // CHECK:   [[FUNC:%.*]] = super_method [[SELF]] : $@thick ChildToResilientParent.Type, #ResilientOutsideParent.classMethod!1 : (ResilientOutsideParent.Type) -> () -> (), $@convention(method) (@thick ResilientOutsideParent.Type) -> ()
+    // CHECK:   apply [[FUNC]]([[UPCAST_METASELF]])
+    super.classMethod()
+  }
+  // CHECK: } // end sil function '$S5super22ChildToResilientParentC11classMethodyyFZ'
+
+  // CHECK-LABEL: sil @$S5super22ChildToResilientParentC11returnsSelfACXDyFZ : $@convention(method) (@thick ChildToResilientParent.Type) -> @owned ChildToResilientParent
+  public class func returnsSelf() -> Self {
+    // CHECK: bb0([[METASELF:%.*]] : $@thick ChildToResilientParent.Type):
+    // CHECK:   [[CAST_METASELF:%.*]] = unchecked_trivial_bit_cast [[METASELF]] : $@thick ChildToResilientParent.Type to $@thick @dynamic_self ChildToResilientParent.Type
+    // CHECK:   [[UPCAST_CAST_METASELF:%.*]] = upcast [[CAST_METASELF]] : $@thick @dynamic_self ChildToResilientParent.Type to $@thick ResilientOutsideParent.Type
+    // CHECK:   [[FUNC:%.*]] = super_method [[METASELF]] : $@thick ChildToResilientParent.Type, #ResilientOutsideParent.classMethod!1 : (ResilientOutsideParent.Type) -> () -> ()
+    // CHECK:   apply [[FUNC]]([[UPCAST_CAST_METASELF]])
+    // CHECK: unreachable
+    super.classMethod()
+  }
+  // CHECK: } // end sil function '$S5super22ChildToResilientParentC11returnsSelfACXDyFZ'
+}
+
+public class ChildToFixedParent : OutsideParent {
+  // CHECK-LABEL: sil @$S5super18ChildToFixedParentC6methodyyF : $@convention(method) (@guaranteed ChildToFixedParent) -> ()
+  public override func method() {
+    // CHECK: bb0([[SELF:%.*]] : $ChildToFixedParent):
+    // CHECK:   [[COPY_SELF:%.*]] = copy_value [[SELF]]
+    // CHECK:   [[UPCAST_COPY_SELF:%.*]] = upcast [[COPY_SELF]]
+    // CHECK:   [[BORROWED_UPCAST_COPY_SELF:%.*]] = begin_borrow [[UPCAST_COPY_SELF]]
+    // CHECK:   [[DOWNCAST_BORROWED_UPCAST_COPY_SELF:%.*]] = unchecked_ref_cast [[BORROWED_UPCAST_COPY_SELF]] : $OutsideParent to $ChildToFixedParent
+    // CHECK:   [[FUNC:%.*]] = super_method [[DOWNCAST_BORROWED_UPCAST_COPY_SELF]] : $ChildToFixedParent, #OutsideParent.method!1 : (OutsideParent) -> () -> (), $@convention(method) (@guaranteed OutsideParent) -> ()
+    // CHECK:   end_borrow [[BORROWED_UPCAST_COPY_SELF]] from [[UPCAST_COPY_SELF]]
+    // CHECK:   apply [[FUNC]]([[UPCAST_COPY_SELF]])
+    super.method()
+  }
+  // CHECK: } // end sil function '$S5super18ChildToFixedParentC6methodyyF'
+
+  // CHECK-LABEL: sil @$S5super18ChildToFixedParentC11classMethodyyFZ : $@convention(method) (@thick ChildToFixedParent.Type) -> ()
+  public override class func classMethod() {
+    // CHECK: bb0([[SELF:%.*]] : $@thick ChildToFixedParent.Type):
+    // CHECK:   [[UPCAST_SELF:%.*]] = upcast [[SELF]]
+    // CHECK:   [[FUNC:%.*]] = super_method [[SELF]] : $@thick ChildToFixedParent.Type, #OutsideParent.classMethod!1 : (OutsideParent.Type) -> () -> (), $@convention(method) (@thick OutsideParent.Type) -> ()
+    // CHECK:   apply [[FUNC]]([[UPCAST_SELF]])
+    super.classMethod()
+  }
+  // CHECK: } // end sil function '$S5super18ChildToFixedParentC11classMethodyyFZ'
+
+  // CHECK-LABEL: sil @$S5super18ChildToFixedParentC11returnsSelfACXDyFZ : $@convention(method) (@thick ChildToFixedParent.Type) -> @owned ChildToFixedParent
+  public class func returnsSelf() -> Self {
+    // CHECK: bb0([[SELF:%.*]] : $@thick ChildToFixedParent.Type):
+    // CHECK:   [[FIRST_CAST:%.*]] = unchecked_trivial_bit_cast [[SELF]]
+    // CHECK:   [[SECOND_CAST:%.*]] = upcast [[FIRST_CAST]]
+    // CHECK:   [[FUNC:%.*]] = super_method [[SELF]] : $@thick ChildToFixedParent.Type, #OutsideParent.classMethod!1 : (OutsideParent.Type) -> () -> ()
+    // CHECK:   apply [[FUNC]]([[SECOND_CAST]])
+    // CHECK:   unreachable
+    super.classMethod()
+  }
+  // CHECK: } // end sil function '$S5super18ChildToFixedParentC11returnsSelfACXDyFZ'
+}
+
+public extension ResilientOutsideChild {
+  public func callSuperMethod() {
+    super.method()
+  }
+
+  public class func callSuperClassMethod() {
+    super.classMethod()
+  }
+}
+
+public class GenericBase<T> {
+  public func method() {}
+}
+
+public class GenericDerived<T> : GenericBase<T> {
+  public override func method() {
+    // CHECK-LABEL: sil private @$S5super14GenericDerivedC6methodyyFyyXEfU_ : $@convention(thin) <T> (@guaranteed GenericDerived<T>) -> ()
+    // CHECK: upcast {{.*}} : $GenericDerived<T> to $GenericBase<T>
+    // CHECK: return
+    {
+      super.method()
+    }()
+    // CHECK: } // end sil function '$S5super14GenericDerivedC6methodyyFyyXEfU_'
+
+    // CHECK-LABEL: sil private @$S5super14GenericDerivedC6methodyyF13localFunctionL_yylF : $@convention(thin) <T> (@guaranteed GenericDerived<T>) -> ()
+    // CHECK: upcast {{.*}} : $GenericDerived<T> to $GenericBase<T>
+    // CHECK: return
+    // CHECK: } // end sil function '$S5super14GenericDerivedC6methodyyF13localFunctionL_yylF'
+    func localFunction() {
+      super.method()
+    }
+    localFunction()
+
+    // CHECK-LABEL: sil private @$S5super14GenericDerivedC6methodyyF15genericFunctionL_yyqd__r__lF : $@convention(thin) <T><U> (@in_guaranteed U, @guaranteed GenericDerived<T>) -> ()
+    // CHECK: upcast {{.*}} : $GenericDerived<T> to $GenericBase<T>
+    // CHECK: return
+    func genericFunction<U>(_: U) {
+      super.method()
+    }
+    // CHECK: } // end sil function '$S5super14GenericDerivedC6methodyyF15genericFunctionL_yyqd__r__lF'
+    genericFunction(0)
+  }
+}
diff --git a/test/SILGen/plus_zero_switch.swift b/test/SILGen/plus_zero_switch.swift
new file mode 100644
index 0000000..e81e078
--- /dev/null
+++ b/test/SILGen/plus_zero_switch.swift
@@ -0,0 +1,1125 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -emit-silgen %s | %FileCheck %s
+
+func markUsed<T>(_ t: T) {}
+
+// TODO: Implement tuple equality in the library.
+// BLOCKED: <rdar://problem/13822406>
+func ~= (x: (Int, Int), y: (Int, Int)) -> Bool {
+  return x.0 == y.0 && x.1 == y.1
+}
+
+// Some fake predicates for pattern guards.
+func runced() -> Bool { return true }
+func funged() -> Bool { return true }
+func ansed() -> Bool { return true }
+
+func foo() -> Int { return 0 }
+func bar() -> Int { return 0 }
+func foobar() -> (Int, Int) { return (0, 0) }
+
+func a() {}
+func b() {}
+func c() {}
+func d() {}
+func e() {}
+func f() {}
+func g() {}
+
+// CHECK-LABEL: sil hidden @$S6switch5test1yyF
+func test1() {
+  switch foo() {
+  // CHECK:   function_ref @$S6switch3fooSiyF
+  case _:
+  // CHECK:   function_ref @$S6switch1ayyF
+  // CHECK:   br [[CONT:bb[0-9]+]]
+    a()
+  }
+  // CHECK: [[CONT]]:
+  // CHECK:   function_ref @$S6switch1byyF
+  b()
+}
+
+// CHECK-LABEL: sil hidden @$S6switch5test2yyF
+func test2() {
+  switch foo() {
+  // CHECK:   function_ref @$S6switch3fooSiyF
+  case _:
+  // CHECK:   function_ref @$S6switch1ayyF
+  // CHECK:   br [[CONT:bb[0-9]+]]
+    a()
+  case _: // The second case is unreachable.
+    b()
+  }
+  // CHECK: [[CONT]]:
+  // CHECK:   function_ref @$S6switch1cyyF
+  c()
+}
+
+// CHECK-LABEL: sil hidden @$S6switch5test3yyF
+func test3() {
+  switch foo() {
+  // CHECK:   function_ref @$S6switch3fooSiyF
+  // CHECK:   function_ref @$S6switch6runcedSbyF
+  // CHECK:   cond_br {{%.*}}, [[CASE1:bb[0-9]+]], [[NO_CASE2:bb[0-9]+]]
+
+  case _ where runced():
+  // CHECK: [[CASE1]]:
+  // CHECK:   function_ref @$S6switch1ayyF
+  // CHECK:   br [[CONT:bb[0-9]+]]
+    a()
+
+  // CHECK: [[NO_CASE2]]:
+  // CHECK:   br [[CASE2:bb[0-9]+]]
+  case _:
+  // CHECK: [[CASE2]]:
+  // CHECK:   function_ref @$S6switch1byyF
+  // CHECK:   br [[CONT]]
+    b()
+  }
+  // CHECK: [[CONT]]:
+  // CHECK:   function_ref @$S6switch1cyyF
+  c()
+}
+
+// CHECK-LABEL: sil hidden @$S6switch5test4yyF
+func test4() {
+  switch (foo(), bar()) {
+  // CHECK:   function_ref @$S6switch3fooSiyF
+  // CHECK:   function_ref @$S6switch3barSiyF
+  case _:
+  // CHECK:   function_ref @$S6switch1ayyF
+  // CHECK:   br [[CONT:bb[0-9]+]]
+    a()
+  }
+  // CHECK: [[CONT]]:
+  // CHECK:   function_ref @$S6switch1byyF
+  b()
+}
+
+// CHECK-LABEL: sil hidden @$S6switch5test5yyF
+func test5() {
+  switch (foo(), bar()) {
+  // CHECK:   function_ref @$S6switch3fooSiyF
+  // CHECK:   function_ref @$S6switch3barSiyF
+  // CHECK:   function_ref @$S6switch6runcedSbyF
+  // CHECK:   cond_br {{%.*}}, [[CASE1:bb[0-9]+]], [[NOT_CASE1:bb[0-9]+]]
+  case _ where runced():
+  // CHECK: [[CASE1]]:
+  // CHECK:   function_ref @$S6switch1ayyF
+  // CHECK:   br [[CONT:bb[0-9]+]]
+    a()
+
+  // CHECK: [[NOT_CASE1]]:
+  // CHECK:   function_ref @$S6switch6fungedSbyF
+  // CHECK:   cond_br {{%.*}}, [[YES_CASE2:bb[0-9]+]], [[NOT_CASE2:bb[0-9]+]]
+  // CHECK: [[YES_CASE2]]:
+  case (_, _) where funged():
+  // CHECK:   function_ref @$S6switch1byyF
+  // CHECK:   br [[CONT]]
+    b()
+
+  // CHECK: [[NOT_CASE2]]:
+  // CHECK:   br [[CASE3:bb[0-9]+]]
+  case _:
+  // CHECK: [[CASE3]]:
+  // CHECK:   function_ref @$S6switch1cyyF
+  // CHECK:   br [[CONT]]
+    c()
+  }
+  // CHECK: [[CONT]]:
+  // CHECK:   function_ref @$S6switch1dyyF
+  d()
+}
+
+// CHECK-LABEL: sil hidden @$S6switch5test6yyF
+func test6() {
+  switch (foo(), bar()) {
+  // CHECK:   function_ref @$S6switch3fooSiyF
+  // CHECK:   function_ref @$S6switch3barSiyF
+  case (_, _):
+  // CHECK:   function_ref @$S6switch1ayyF
+  // CHECK:   br [[CONT:bb[0-9]+]]
+    a()
+  case (_, _): // The second case is unreachable.
+    b()
+  }
+  // CHECK: [[CONT]]:
+  // CHECK:   function_ref @$S6switch1cyyF
+  c()
+}
+
+// CHECK-LABEL: sil hidden @$S6switch5test7yyF
+func test7() {
+  switch (foo(), bar()) {
+  // CHECK:   function_ref @$S6switch3fooSiyF
+  // CHECK:   function_ref @$S6switch3barSiyF
+  // CHECK:   function_ref @$S6switch6runcedSbyF
+  // CHECK:   cond_br {{%.*}}, [[YES_CASE1:bb[0-9]+]], [[NOT_CASE1:bb[0-9]+]]
+  // CHECK: [[YES_CASE1]]:
+  case (_, _) where runced():
+  // CHECK:   function_ref @$S6switch1ayyF
+  // CHECK:   br [[CONT:bb[0-9]+]]
+    a()
+
+  // CHECK: [[NOT_CASE1]]:
+  // CHECK:   br [[CASE2:bb[0-9]+]]
+  case (_, _):
+  // CHECK: [[CASE2]]:
+  // CHECK:   function_ref @$S6switch1byyF
+  // CHECK:   br [[CONT]]
+    b()
+  }
+  c()
+  // CHECK: [[CONT]]:
+  // CHECK:   function_ref @$S6switch1cyyF
+}
+
+// CHECK-LABEL: sil hidden @$S6switch5test8yyF
+func test8() {
+  switch (foo(), bar()) {
+  // CHECK:   function_ref @$S6switch3fooSiyF
+  // CHECK:   function_ref @$S6switch3barSiyF
+  // CHECK:   function_ref @$S6switch6foobarSi_SityF
+  // CHECK:   cond_br {{%.*}}, [[CASE1:bb[0-9]+]], [[NOT_CASE1:bb[0-9]+]]
+  case foobar():
+  // CHECK: [[CASE1]]:
+  // CHECK:   function_ref @$S6switch1ayyF
+  // CHECK:   br [[CONT:bb[0-9]+]]
+    a()
+
+  // CHECK: [[NOT_CASE1]]:
+  // CHECK:   function_ref @$S6switch3fooSiyF
+  // CHECK:   cond_br {{%.*}}, [[CASE2:bb[0-9]+]], [[NOT_CASE2:bb[0-9]+]]
+  case (foo(), _):
+  // CHECK: [[CASE2]]:
+  // CHECK:   function_ref @$S6switch1byyF
+  // CHECK:   br [[CONT]]
+    b()
+  // CHECK: [[NOT_CASE2]]:
+  // CHECK:   function_ref @$S6switch3barSiyF
+  // CHECK:   cond_br {{%.*}}, [[CASE3_GUARD:bb[0-9]+]], [[NOT_CASE3:bb[0-9]+]]
+  // CHECK: [[CASE3_GUARD]]:
+  // CHECK:   function_ref @$S6switch6runcedSbyF
+  // CHECK:   cond_br {{%.*}}, [[CASE3:bb[0-9]+]], [[NOT_CASE3_GUARD:bb[0-9]+]]
+  case (_, bar()) where runced():
+  // CHECK: [[CASE3]]:
+  // CHECK:   function_ref @$S6switch1cyyF
+  // CHECK:   br [[CONT]]
+    c()
+  // CHECK: [[NOT_CASE3_GUARD]]:
+  // CHECK: [[NOT_CASE3]]:
+  // CHECK:   function_ref @$S6switch3fooSiyF
+  // CHECK:   cond_br {{%.*}}, [[CASE4_GUARD_1:bb[0-9]+]], [[NOT_CASE4_1:bb[0-9]+]]
+  // CHECK: [[CASE4_GUARD_1]]:
+  // CHECK:   function_ref @$S6switch3barSiyF
+  // CHECK:   cond_br {{%.*}}, [[CASE4_GUARD_2:bb[0-9]+]], [[NOT_CASE4_2:bb[0-9]+]]
+  // CHECK: [[CASE4_GUARD_2]]:
+  // CHECK:   function_ref @$S6switch6fungedSbyF
+  // CHECK:   cond_br {{%.*}}, [[CASE4:bb[0-9]+]], [[NOT_CASE4_3:bb[0-9]+]]
+  case (foo(), bar()) where funged():
+  // CHECK: [[CASE4]]:
+  // CHECK:   function_ref @$S6switch1dyyF
+  // CHECK:   br [[CONT]]
+    d()
+  // CHECK: [[NOT_CASE4_3]]:
+  // CHECK: [[NOT_CASE4_2]]:
+  // CHECK: [[NOT_CASE4_1]]:
+  // CHECK:   function_ref @$S6switch3fooSiyF
+  // CHECK:   cond_br {{%.*}}, [[CASE5_GUARD_1:bb[0-9]+]], [[NOT_CASE5:bb[0-9]+]]
+  // CHECK: [[CASE5_GUARD_1]]:
+  // CHECK:   function_ref @$S6switch3barSiyF
+  // CHECK:   cond_br {{%.*}}, [[YES_CASE5:bb[0-9]+]], [[NOT_CASE5:bb[0-9]+]]
+  // CHECK: [[YES_CASE5]]:
+  case (foo(), bar()):
+  // CHECK:   function_ref @$S6switch1eyyF
+  // CHECK:   br [[CONT]]
+    e()
+  // CHECK: [[NOT_CASE5]]:
+  // CHECK:   br [[CASE6:bb[0-9]+]]
+  case _:
+  // CHECK: [[CASE6]]:
+  // CHECK:   function_ref @$S6switch1fyyF
+  // CHECK:   br [[CONT]]
+    f()
+  }
+  // CHECK: [[CONT]]:
+  // CHECK:   function_ref @$S6switch1gyyF
+  g()
+}
+
+// CHECK-LABEL: sil hidden @$S6switch5test9yyF
+func test9() {
+  switch (foo(), bar()) {
+  // CHECK:   function_ref @$S6switch3fooSiyF
+  // CHECK:   function_ref @$S6switch3barSiyF
+  // CHECK:   function_ref @$S6switch3fooSiyF
+  // CHECK:   cond_br {{%.*}}, [[YES_CASE1:bb[0-9]+]], [[NOT_CASE1:bb[0-9]+]]
+  // CHECK: [[YES_CASE1]]:
+  case (foo(), _):
+  // CHECK:   function_ref @$S6switch1ayyF
+  // CHECK:   br [[CONT:bb[0-9]+]]
+    a()
+
+  // CHECK: [[NOT_CASE1]]:
+  // CHECK:   function_ref @$S6switch6foobarSi_SityF
+  // CHECK:   cond_br {{%.*}}, [[CASE2:bb[0-9]+]], [[NOT_CASE2:bb[0-9]+]]
+  case foobar():
+  // CHECK: [[CASE2]]:
+  // CHECK:   function_ref @$S6switch1byyF
+  // CHECK:   br [[CONT]]
+    b()
+
+  // CHECK: [[NOT_CASE2]]:
+  // CHECK:   br [[CASE3:bb[0-9]+]]
+  case _:
+  // CHECK: [[CASE3]]:
+  // CHECK:   function_ref @$S6switch1cyyF
+  // CHECK:   br [[CONT]]
+    c()
+  }
+  // CHECK: [[CONT]]:
+  // CHECK:   function_ref @$S6switch1dyyF
+  d()
+}
+
+// CHECK-LABEL: sil hidden @$S6switch6test10yyF
+func test10() {
+  switch (foo(), bar()) {
+  // CHECK:   function_ref @$S6switch3fooSiyF
+  // CHECK:   function_ref @$S6switch3barSiyF
+  // CHECK:   cond_br {{%.*}}, [[YES_CASE1:bb[0-9]+]], [[NOT_CASE1:bb[0-9]+]]
+  // CHECK: [[YES_CASE1]]:
+  case (foo()...bar(), _):
+  // CHECK:   function_ref @$S6switch1ayyF
+  // CHECK:   br [[CONT:bb[0-9]+]]
+    a()
+
+  // CHECK: [[NOT_CASE1]]:
+  // CHECK:   br [[CASE2:bb[0-9]+]]
+  case _:
+  // CHECK: [[CASE2]]:
+  // CHECK:   function_ref @$S6switch1byyF
+  // CHECK:   br [[CONT]]
+    b()
+  }
+  // CHECK: [[CONT]]:
+  // CHECK:   function_ref @$S6switch1cyyF
+  c()
+}
+
+protocol P { func p() }
+
+struct X : P { func p() {} }
+struct Y : P { func p() {} }
+struct Z : P { func p() {} }
+
+// CHECK-LABEL: sil hidden @$S6switch10test_isa_11pyAA1P_p_tF
+func test_isa_1(p: P) {
+  // CHECK: [[PTMPBUF:%[0-9]+]] = alloc_stack $P
+  // CHECK-NEXT: copy_addr %0 to [initialization] [[PTMPBUF]] : $*P
+  switch p {
+    // CHECK: [[TMPBUF:%[0-9]+]] = alloc_stack $X
+  // CHECK:   checked_cast_addr_br copy_on_success P in [[P:%.*]] : $*P to X in [[TMPBUF]] : $*X, [[IS_X:bb[0-9]+]], [[IS_NOT_X:bb[0-9]+]]
+
+  case is X:
+  // CHECK: [[IS_X]]:
+  // CHECK-NEXT: load [trivial] [[TMPBUF]]
+  // CHECK-NEXT: dealloc_stack [[TMPBUF]]
+  // CHECK-NEXT: destroy_addr [[PTMPBUF]]
+  // CHECK-NEXT: dealloc_stack [[PTMPBUF]]
+    a()
+    // CHECK:   function_ref @$S6switch1ayyF
+    // CHECK:   br [[CONT:bb[0-9]+]]
+    
+  // CHECK: [[IS_NOT_X]]:
+  // CHECK:   checked_cast_addr_br copy_on_success P in [[P]] : $*P to Y in {{%.*}} : $*Y, [[IS_Y:bb[0-9]+]], [[IS_NOT_Y:bb[0-9]+]]
+
+// CHECK: [[IS_Y]]:
+  case is Y:
+  // CHECK:   function_ref @$S6switch1byyF
+  // CHECK:   br [[Y_CONT:bb[0-9]+]]
+    b()
+
+  // CHECK: [[IS_NOT_Y]]:
+  // CHECK:   checked_cast_addr_br copy_on_success P in [[P]] : $*P to Z in {{%.*}} : $*Z, [[IS_Z:bb[0-9]+]], [[IS_NOT_Z:bb[0-9]+]]
+
+  // CHECK: [[IS_Z]]:
+  case is Z:
+  // CHECK:   function_ref @$S6switch1cyyF
+  // CHECK:   br [[Z_CONT:bb[0-9]+]]
+    c()
+
+  // CHECK: [[IS_NOT_Z]]:
+  case _:
+  // CHECK:   function_ref @$S6switch1dyyF
+  // CHECK:   br [[CONT]]
+    d()
+  }
+  // CHECK: [[CONT]]:
+  // CHECK:   function_ref @$S6switch1eyyF
+  e()
+}
+
+// CHECK-LABEL: sil hidden @$S6switch10test_isa_21pyAA1P_p_tF
+func test_isa_2(p: P) {
+  switch (p, foo()) {
+  // CHECK:   checked_cast_addr_br copy_on_success P in [[P:%.*]] : $*P to X in {{%.*}} : $*X, [[IS_X:bb[0-9]+]], [[IS_NOT_X:bb[0-9]+]]
+
+  // CHECK: [[IS_X]]:
+  // CHECK:   function_ref @$S6switch3fooSiyF
+  // CHECK:   cond_br {{%.*}}, [[CASE1:bb[0-9]+]], [[NOT_CASE1:bb[0-9]+]]
+  case (is X, foo()):
+  // CHECK: [[CASE1]]:
+  // CHECK:   function_ref @$S6switch1ayyF
+  // CHECK:   br [[CONT:bb[0-9]+]]
+    a()
+
+  // CHECK: [[IS_NOT_X]]:
+  // CHECK:   checked_cast_addr_br copy_on_success P in [[P]] : $*P to Y in {{%.*}} : $*Y, [[IS_Y:bb[0-9]+]], [[IS_NOT_Y:bb[0-9]+]]
+
+  // CHECK: [[IS_Y]]:
+  // CHECK:   function_ref @$S6switch3fooSiyF
+  // CHECK:   cond_br {{%.*}}, [[CASE2:bb[0-9]+]], [[NOT_CASE2:bb[0-9]+]]
+  case (is Y, foo()):
+  // CHECK: [[CASE2]]:
+  // CHECK:   function_ref @$S6switch1byyF
+  // CHECK:   br [[CONT]]
+    b()
+
+  // CHECK: [[NOT_CASE2]]:
+  // CHECK: [[IS_NOT_Y]]:
+
+  // CHECK:   checked_cast_addr_br copy_on_success P in [[P:%.*]] : $*P to X in {{%.*}} : $*X, [[CASE3:bb[0-9]+]], [[IS_NOT_X:bb[0-9]+]]
+
+  case (is X, _):
+  // CHECK: [[CASE3]]:
+  // CHECK:   function_ref @$S6switch1cyyF
+  // CHECK:   br [[CONT]]
+    c()
+
+  // -- case (is Y, foo()):
+  // CHECK: [[IS_NOT_X]]:
+  // CHECK:   checked_cast_addr_br copy_on_success P in [[P]] : $*P to Y in {{%.*}} : $*Y, [[IS_Y:bb[0-9]+]], [[IS_NOT_Y:bb[0-9]+]]
+  // CHECK: [[IS_Y]]:
+  // CHECK:   function_ref @$S6switch3barSiyF
+  // CHECK:   cond_br {{%.*}}, [[CASE4:bb[0-9]+]], [[NOT_CASE4:bb[0-9]+]]
+  case (is Y, bar()):
+  // CHECK: [[CASE4]]:
+  // CHECK:   function_ref @$S6switch1dyyF
+  // CHECK:   br [[CONT]]
+    d()
+
+  // CHECK: [[NOT_CASE4]]:
+  // CHECK:   br [[CASE5:bb[0-9]+]]
+  // CHECK: [[IS_NOT_Y]]:
+  // CHECK:   br [[CASE5]]
+  case _:
+  // CHECK: [[CASE5]]:
+  // CHECK:   function_ref @$S6switch1eyyF
+  // CHECK:   br [[CONT]]
+    e()
+  }
+  // CHECK: [[CONT]]:
+  // CHECK:   function_ref @$S6switch1fyyF
+  f()
+}
+
+class B {}
+class C : B {}
+class D1 : C {}
+class D2 : D1 {}
+class E : C {}
+
+// CHECK-LABEL: sil hidden @$S6switch16test_isa_class_11xyAA1BC_tF : $@convention(thin) (@guaranteed B) -> () {
+func test_isa_class_1(x: B) {
+  // CHECK: bb0([[X:%.*]] : $B):
+  // CHECK:   [[X_COPY:%.*]] = copy_value [[X]]
+  // CHECK:   checked_cast_br [[X_COPY]] : $B to $D1, [[IS_D1:bb[0-9]+]], [[IS_NOT_D1:bb[0-9]+]]
+  switch x {
+
+  // CHECK: [[IS_D1]]([[CAST_D1:%.*]]):
+  // CHECK:   [[CAST_D1_COPY:%.*]] = copy_value [[CAST_D1]]
+  // CHECK:   function_ref @$S6switch6runcedSbyF : $@convention(thin) () -> Bool
+  // CHECK:   cond_br {{%.*}}, [[YES_CASE1:bb[0-9]+]], [[NO_CASE1:bb[0-9]+]]
+
+  // CHECK: [[YES_CASE1]]:
+  case is D1 where runced():
+  // CHECK:   destroy_value [[CAST_D1_COPY]]
+  // CHECK:   destroy_value [[X_COPY]]
+  // CHECK:   function_ref @$S6switch1ayyF
+  // CHECK:   br [[CONT:bb[0-9]+]]
+    a()
+
+  // CHECK: [[NO_CASE1]]:
+  // CHECK:   destroy_value [[CAST_D1_COPY]]
+  // CHECK:   br [[NEXT_CASE:bb5]]
+
+  // CHECK: [[IS_NOT_D1]]:
+  // CHECK:   br [[NEXT_CASE]]
+
+  // CHECK: [[NEXT_CASE]]
+  // CHECK:   checked_cast_br [[X_COPY]] : $B to $D2, [[IS_D2:bb[0-9]+]], [[IS_NOT_D2:bb[0-9]+]]
+  case is D2:
+  // CHECK: [[IS_D2]]([[CAST_D2:%.*]]):
+  // CHECK:   [[CAST_D2_COPY:%.*]] = copy_value [[CAST_D2]]
+  // CHECK:   destroy_value [[CAST_D2_COPY]]
+  // CHECK:   destroy_value [[X_COPY]]
+  // CHECK:   function_ref @$S6switch1byyF
+  // CHECK:   br [[CONT]]
+    b()
+
+  // CHECK: [[IS_NOT_D2]]:
+  // CHECK:   br [[NEXT_CASE:bb8]]
+
+  // CHECK: [[NEXT_CASE]]:
+  // CHECK:   checked_cast_br [[X_COPY]] : $B to $E, [[IS_E:bb[0-9]+]], [[IS_NOT_E:bb[0-9]+]]
+  case is E where funged():
+  // CHECK: [[IS_E]]([[CAST_E:%.*]]):
+  // CHECK:   [[CAST_E_COPY:%.*]] = copy_value [[CAST_E]]
+  // CHECK:   function_ref @$S6switch6fungedSbyF
+  // CHECK:   cond_br {{%.*}}, [[CASE3:bb[0-9]+]], [[NO_CASE3:bb[0-9]+]]
+
+  // CHECK: [[CASE3]]:
+  // CHECK:   destroy_value [[CAST_E_COPY]]
+  // CHECK:   destroy_value [[X_COPY]]
+  // CHECK:   function_ref @$S6switch1cyyF
+  // CHECK:   br [[CONT]]
+    c()
+
+  // CHECK: [[NO_CASE3]]:
+  // CHECK:   destroy_value [[CAST_E_COPY]]
+  // CHECK:   br [[NEXT_CASE:bb13]]
+
+  // CHECK: [[IS_NOT_E]]:
+  // CHECK:   br [[NEXT_CASE]]
+
+  // CHECK: [[NEXT_CASE]]
+  // CHECK:   checked_cast_br [[X_COPY]] : $B to $C, [[IS_C:bb[0-9]+]], [[IS_NOT_C:bb[0-9]+]]
+
+  case is C:
+  // CHECK: [[IS_C]]([[CAST_C:%.*]]):
+  // CHECK:   [[CAST_C_COPY:%.*]] = copy_value [[CAST_C]]
+  // CHECK:   destroy_value [[CAST_C_COPY]]
+  // CHECK:   destroy_value [[X_COPY]]
+  // CHECK:   function_ref @$S6switch1dyyF
+  // CHECK:   br [[CONT]]
+    d()
+
+  // CHECK: [[IS_NOT_C]]:
+  // CHECK:   br [[NEXT_CASE:bb16]]
+
+  // CHECK: [[NEXT_CASE]]:
+  default:
+  // CHECK:    destroy_value [[X_COPY]]
+  // CHECK:    function_ref @$S6switch1eyyF
+  // CHECK:    br [[CONT]]
+    e()
+  }
+  // CHECK: [[CONT]]:
+  // CHECK:   [[F_FUNC:%.*]] = function_ref @$S6switch1fyyF : $@convention(thin) () -> ()
+  // CHECK:   apply [[F_FUNC]]()
+  f()
+}
+// CHECK: } // end sil function '$S6switch16test_isa_class_11xyAA1BC_tF'
+
+// CHECK-LABEL: sil hidden @$S6switch16test_isa_class_21xyXlAA1BC_tF : $@convention(thin)
+func test_isa_class_2(x: B) -> AnyObject {
+  // CHECK: bb0([[X:%.*]] : $B):
+  // CHECK:   [[X_COPY:%.*]] = copy_value [[X]]
+  switch x {
+
+  // CHECK:   checked_cast_br [[X_COPY]] : $B to $D1, [[IS_D1:bb[0-9]+]], [[IS_NOT_D1:bb[0-9]+]]
+  case let y as D1 where runced():
+  // CHECK: [[IS_D1]]([[CAST_D1:%.*]] : $D1):
+  // CHECK:   [[CAST_D1_COPY:%.*]] = copy_value [[CAST_D1]]
+  // CHECK:   function_ref @$S6switch6runcedSbyF
+  // CHECK:   cond_br {{%.*}}, [[CASE1:bb[0-9]+]], [[NO_CASE1:bb[0-9]+]]
+
+  // CHECK: [[CASE1]]:
+  // CHECK:   function_ref @$S6switch1ayyF
+  // CHECK:   [[BORROWED_CAST_D1_COPY:%.*]] = begin_borrow [[CAST_D1_COPY]]
+  // CHECK:   [[CAST_D1_COPY_COPY:%.*]] = copy_value [[BORROWED_CAST_D1_COPY]]
+  // CHECK:   [[RET:%.*]] = init_existential_ref [[CAST_D1_COPY_COPY]]
+  // CHECK:   end_borrow [[BORROWED_CAST_D1_COPY]] from [[CAST_D1_COPY]]
+  // CHECK:   destroy_value [[CAST_D1_COPY]]
+  // CHECK:   destroy_value [[X_COPY]] : $B
+  // CHECK:   br [[CONT:bb[0-9]+]]([[RET]] : $AnyObject)
+    a()
+    return y
+
+  // CHECK: [[NO_CASE1]]:
+  // CHECK:   destroy_value [[CAST_D1_COPY]]
+  // CHECK:   br [[NEXT_CASE:bb5]]
+  
+  // CHECK: [[IS_NOT_D1]]:
+  // CHECK:   br [[NEXT_CASE]]
+
+  // CHECK: [[NEXT_CASE]]:
+  // CHECK:   checked_cast_br [[X_COPY]] : $B to $D2, [[CASE2:bb[0-9]+]], [[IS_NOT_D2:bb[0-9]+]]
+  case let y as D2:
+  // CHECK: [[CASE2]]([[CAST_D2:%.*]]):
+  // CHECK:   [[CAST_D2_COPY:%.*]] = copy_value [[CAST_D2]]
+  // CHECK:   function_ref @$S6switch1byyF
+  // CHECK:   [[BORROWED_CAST_D2_COPY:%.*]] = begin_borrow [[CAST_D2_COPY]]
+  // CHECK:   [[CAST_D2_COPY_COPY:%.*]] = copy_value [[BORROWED_CAST_D2_COPY]]
+  // CHECK:   [[RET:%.*]] = init_existential_ref [[CAST_D2_COPY_COPY]]
+  // CHECK:   end_borrow [[BORROWED_CAST_D2_COPY]] from [[CAST_D2_COPY]]
+  // CHECK:   destroy_value [[CAST_D2_COPY]]
+  // CHECK:   destroy_value [[X_COPY]]
+  // CHECK:   br [[CONT]]([[RET]] : $AnyObject)
+    b()
+    return y
+
+  // CHECK: [[IS_NOT_D2]]:
+  // CHECK:   br [[NEXT_CASE:bb8]]
+
+  // CHECK: [[NEXT_CASE]]:
+  // CHECK:   checked_cast_br [[X_COPY]] : $B to $E, [[IS_E:bb[0-9]+]], [[IS_NOT_E:bb[0-9]+]]
+  case let y as E where funged():
+  // CHECK: [[IS_E]]([[CAST_E:%.*]]):
+  // CHECK:   [[CAST_E_COPY:%.*]] = copy_value [[CAST_E]]
+  // CHECK:   function_ref @$S6switch6fungedSbyF
+  // CHECK:   cond_br {{%.*}}, [[CASE3:bb[0-9]+]], [[NO_CASE3:bb[0-9]+]]
+
+  // CHECK: [[CASE3]]:
+  // CHECK:   function_ref @$S6switch1cyyF
+  // CHECK:   [[BORROWED_CAST_E_COPY:%.*]] = begin_borrow [[CAST_E_COPY]]
+  // CHECK:   [[CAST_E_COPY_COPY:%.*]] = copy_value [[BORROWED_CAST_E_COPY]]
+  // CHECK:   [[RET:%.*]] = init_existential_ref [[CAST_E_COPY_COPY]]
+  // CHECK:   end_borrow [[BORROWED_CAST_E_COPY]] from [[CAST_E_COPY]]
+  // CHECK:   destroy_value [[CAST_E_COPY]]
+  // CHECK:   destroy_value [[X_COPY]] : $B
+  // CHECK:   br [[CONT]]([[RET]] : $AnyObject)
+    c()
+    return y
+
+  // CHECK: [[NO_CASE3]]:
+  // CHECK    destroy_value [[CAST_E_COPY]]
+  // CHECK:   br [[NEXT_CASE:bb13]]
+
+  // CHECK: [[IS_NOT_E]]:
+  // CHECK:   br [[NEXT_CASE]]
+
+  // CHECK: [[NEXT_CASE]]
+  // CHECK:   checked_cast_br [[X_COPY]] : $B to $C, [[CASE4:bb[0-9]+]], [[IS_NOT_C:bb[0-9]+]]
+  case let y as C:
+  // CHECK: [[CASE4]]([[CAST_C:%.*]]):
+  // CHECK:   [[CAST_C_COPY:%.*]] = copy_value [[CAST_C]]
+  // CHECK:   function_ref @$S6switch1dyyF
+  // CHECK:   [[BORROWED_CAST_C_COPY:%.*]] = begin_borrow [[CAST_C_COPY]]
+  // CHECK:   [[CAST_C_COPY_COPY:%.*]] = copy_value [[BORROWED_CAST_C_COPY]]
+  // CHECK:   [[RET:%.*]] = init_existential_ref [[CAST_C_COPY_COPY]]
+  // CHECK:   end_borrow [[BORROWED_CAST_C_COPY]] from [[CAST_C_COPY]]
+  // CHECK:   destroy_value [[CAST_C_COPY]]
+  // CHECK:   destroy_value [[X_COPY]]
+  // CHECK:   br [[CONT]]([[RET]] : $AnyObject)
+    d()
+    return y
+
+  // CHECK: [[IS_NOT_C]]:
+  // CHECK:   br [[NEXT_CASE:bb16]]
+
+  // CHECK: [[NEXT_CASE]]:
+  default:
+  // CHECK:   destroy_value [[X_COPY]]
+  // CHECK:   function_ref @$S6switch1eyyF
+  // CHECK:   [[X_COPY_2:%.*]] = copy_value [[X]]
+  // CHECK:   [[RET:%.*]] = init_existential_ref [[X_COPY_2]]
+  // CHECK:   br [[CONT]]([[RET]] : $AnyObject)
+    e()
+    return x
+  }
+
+  // CHECK: [[CONT]]([[T0:%.*]] : $AnyObject):
+  // CHECK:   return [[T0]]
+}
+// CHECK: } // end sil function '$S6switch16test_isa_class_21xyXlAA1BC_tF'
+
+enum MaybePair {
+  case Neither
+  case Left(Int)
+  case Right(String)
+  case Both(Int, String)
+}
+
+// CHECK-LABEL: sil hidden @$S6switch12test_union_11uyAA9MaybePairO_tF
+func test_union_1(u: MaybePair) {
+  switch u {
+  // CHECK: switch_enum [[SUBJECT:%.*]] : $MaybePair,
+  // CHECK:   case #MaybePair.Neither!enumelt: [[IS_NEITHER:bb[0-9]+]],
+  // CHECK:   case #MaybePair.Left!enumelt.1: [[IS_LEFT:bb[0-9]+]],
+  // CHECK:   case #MaybePair.Right!enumelt.1: [[IS_RIGHT:bb[0-9]+]],
+  // CHECK:   case #MaybePair.Both!enumelt.1: [[IS_BOTH:bb[0-9]+]]
+
+  // CHECK: [[IS_NEITHER]]:
+  // CHECK-NOT: destroy_value
+  case .Neither:
+  // CHECK:   function_ref @$S6switch1ayyF
+  // CHECK:   br [[CONT:bb[0-9]+]]
+    a()
+
+  // CHECK: [[IS_LEFT]]({{%.*}}):
+  // CHECK-NOT: destroy_value
+  case (.Left):
+  // CHECK:   function_ref @$S6switch1byyF
+  // CHECK:   br [[CONT]]
+    b()
+
+  // CHECK: [[IS_RIGHT]]([[STR:%.*]] : $String):
+  case var .Right:
+  // CHECK:   destroy_value [[STR]] : $String
+  // CHECK:   function_ref @$S6switch1cyyF
+  // CHECK:   br [[CONT]]
+    c()
+
+  // CHECK: [[IS_BOTH]]([[TUP:%.*]] : $(Int, String)):
+  case .Both:
+  // CHECK:   tuple_extract [[TUP]] : $(Int, String), 0
+  // CHECK:   [[TUP_STR:%.*]] = tuple_extract [[TUP]] : $(Int, String), 1
+  // CHECK:   destroy_value [[TUP_STR]] : $String
+  // CHECK:   function_ref @$S6switch1dyyF
+  // CHECK:   br [[CONT]]
+    d()
+  }
+
+  // CHECK: [[CONT]]:
+  // CHECK-NOT: switch_enum [[SUBJECT]]
+  // CHECK:   function_ref @$S6switch1eyyF
+  e()
+}
+
+// CHECK-LABEL: sil hidden @$S6switch12test_union_31uyAA9MaybePairO_tF : $@convention(thin) (@guaranteed MaybePair) -> () {
+func test_union_3(u: MaybePair) {
+  // CHECK: bb0([[ARG:%.*]] : $MaybePair):
+  // CHECK:   [[ARG_COPY:%.*]] = copy_value [[ARG]]
+  // CHECK:   switch_enum [[SUBJECT]] : $MaybePair,
+  // CHECK:     case #MaybePair.Neither!enumelt: [[IS_NEITHER:bb[0-9]+]],
+  // CHECK:     case #MaybePair.Left!enumelt.1: [[IS_LEFT:bb[0-9]+]],
+  // CHECK:     case #MaybePair.Right!enumelt.1: [[IS_RIGHT:bb[0-9]+]],
+  // CHECK:     default [[DEFAULT:bb[0-9]+]]
+  switch u {
+  // CHECK: [[IS_NEITHER]]:
+  case .Neither:
+  // CHECK:   function_ref @$S6switch1ayyF
+  // CHECK:   br [[CONT:bb[0-9]+]]
+    a()
+
+  // CHECK: [[IS_LEFT]]({{%.*}}):
+  case .Left:
+  // CHECK:   function_ref @$S6switch1byyF
+  // CHECK:   br [[CONT]]
+    b()
+
+  // CHECK: [[IS_RIGHT]]([[STR:%.*]] : $String):
+  case .Right:
+  // CHECK:   destroy_value [[STR]] : $String
+  // CHECK:   function_ref @$S6switch1cyyF
+  // CHECK:   br [[CONT]]
+    c()
+
+  // CHECK: [[DEFAULT]]:
+  // -- Ensure the fully-opaque value is destroyed in the default case.
+  // CHECK:   destroy_value [[ARG_COPY]] :
+  // CHECK:   function_ref @$S6switch1dyyF
+  // CHECK:   br [[CONT]]
+
+  default:
+    d()
+  }
+
+  // CHECK: [[CONT]]:
+  // CHECK-NOT: switch_enum [[ARG]]
+  // CHECK:   function_ref @$S6switch1eyyF
+  e()
+}
+
+// CHECK-LABEL: sil hidden @$S6switch12test_union_41uyAA9MaybePairO_tF
+func test_union_4(u: MaybePair) {
+  switch u {
+  // CHECK: switch_enum {{%.*}} : $MaybePair,
+  // CHECK:   case #MaybePair.Neither!enumelt: [[IS_NEITHER:bb[0-9]+]],
+  // CHECK:   case #MaybePair.Left!enumelt.1: [[IS_LEFT:bb[0-9]+]],
+  // CHECK:   case #MaybePair.Right!enumelt.1: [[IS_RIGHT:bb[0-9]+]],
+  // CHECK:   case #MaybePair.Both!enumelt.1: [[IS_BOTH:bb[0-9]+]]
+
+  // CHECK: [[IS_NEITHER]]:
+  case .Neither(_):
+  // CHECK:   function_ref @$S6switch1ayyF
+  // CHECK:   br [[CONT:bb[0-9]+]]
+    a()
+
+  // CHECK: [[IS_LEFT]]({{%.*}}):
+  case .Left(_):
+  // CHECK:   function_ref @$S6switch1byyF
+  // CHECK:   br [[CONT]]
+    b()
+
+  // CHECK: [[IS_RIGHT]]({{%.*}}):
+  case .Right(_):
+  // CHECK:   function_ref @$S6switch1cyyF
+  // CHECK:   br [[CONT]]
+    c()
+
+  // CHECK: [[IS_BOTH]]({{%.*}}):
+  case .Both(_):
+  // CHECK:   function_ref @$S6switch1dyyF
+  // CHECK:   br [[CONT]]
+    d()
+  }
+
+  // CHECK: [[CONT]]:
+  // CHECK:   function_ref @$S6switch1eyyF
+  e()
+}
+
+// CHECK-LABEL: sil hidden @$S6switch12test_union_51uyAA9MaybePairO_tF
+func test_union_5(u: MaybePair) {
+  switch u {
+  // CHECK: switch_enum {{%.*}} : $MaybePair,
+  // CHECK:   case #MaybePair.Neither!enumelt: [[IS_NEITHER:bb[0-9]+]],
+  // CHECK:   case #MaybePair.Left!enumelt.1: [[IS_LEFT:bb[0-9]+]],
+  // CHECK:   case #MaybePair.Right!enumelt.1: [[IS_RIGHT:bb[0-9]+]],
+  // CHECK:   case #MaybePair.Both!enumelt.1: [[IS_BOTH:bb[0-9]+]]
+
+  // CHECK: [[IS_NEITHER]]:
+  case .Neither():
+  // CHECK:   function_ref @$S6switch1ayyF
+  // CHECK:   br [[CONT:bb[0-9]+]]
+    a()
+
+  // CHECK: [[IS_LEFT]]({{%.*}}):
+  case .Left(_):
+  // CHECK:   function_ref @$S6switch1byyF
+  // CHECK:   br [[CONT]]
+    b()
+
+  // CHECK: [[IS_RIGHT]]({{%.*}}):
+  case .Right(_):
+  // CHECK:   function_ref @$S6switch1cyyF
+  // CHECK:   br [[CONT]]
+    c()
+
+  // CHECK: [[IS_BOTH]]({{%.*}}):
+  case .Both(_, _):
+  // CHECK:   function_ref @$S6switch1dyyF
+  // CHECK:   br [[CONT]]
+    d()
+  }
+
+  // CHECK: [[CONT]]:
+  // CHECK:   function_ref @$S6switch1eyyF
+  e()
+}
+
+enum MaybeAddressOnlyPair {
+  case Neither
+  case Left(P)
+  case Right(String)
+  case Both(P, String)
+}
+
+// CHECK-LABEL: sil hidden @$S6switch22test_union_addr_only_11uyAA20MaybeAddressOnlyPairO_tF
+func test_union_addr_only_1(u: MaybeAddressOnlyPair) {
+  switch u {
+  // CHECK: switch_enum_addr [[ENUM_ADDR:%.*]] : $*MaybeAddressOnlyPair,
+  // CHECK:   case #MaybeAddressOnlyPair.Neither!enumelt: [[IS_NEITHER:bb[0-9]+]],
+  // CHECK:   case #MaybeAddressOnlyPair.Left!enumelt.1: [[IS_LEFT:bb[0-9]+]],
+  // CHECK:   case #MaybeAddressOnlyPair.Right!enumelt.1: [[IS_RIGHT:bb[0-9]+]],
+  // CHECK:   case #MaybeAddressOnlyPair.Both!enumelt.1: [[IS_BOTH:bb[0-9]+]]
+
+  // CHECK: [[IS_NEITHER]]:
+  case .Neither:
+  // CHECK:   function_ref @$S6switch1ayyF
+  // CHECK:   br [[CONT:bb[0-9]+]]
+    a()
+
+  // CHECK: [[IS_LEFT]]:
+  // CHECK:   [[P:%.*]] = unchecked_take_enum_data_addr [[ENUM_ADDR]] : $*MaybeAddressOnlyPair, #MaybeAddressOnlyPair.Left!enumelt.1
+  case .Left(_):
+  // CHECK:   destroy_addr [[P]]
+  // CHECK:   function_ref @$S6switch1byyF
+  // CHECK:   br [[CONT]]
+    b()
+
+  // CHECK: [[IS_RIGHT]]:
+  // CHECK:   [[STR_ADDR:%.*]] = unchecked_take_enum_data_addr [[ENUM_ADDR]] : $*MaybeAddressOnlyPair, #MaybeAddressOnlyPair.Right!enumelt.1
+  // CHECK:   [[STR:%.*]] = load [take] [[STR_ADDR]]
+  case .Right(_):
+  // CHECK:   destroy_value [[STR]] : $String
+  // CHECK:   function_ref @$S6switch1cyyF
+  // CHECK:   br [[CONT]]
+    c()
+
+  // CHECK: [[IS_BOTH]]:
+  // CHECK:   [[P_STR_TUPLE:%.*]] = unchecked_take_enum_data_addr [[ENUM_ADDR]] : $*MaybeAddressOnlyPair, #MaybeAddressOnlyPair.Both!enumelt.1
+  case .Both(_):
+  // CHECK:   destroy_addr [[P_STR_TUPLE]]
+  // CHECK:   function_ref @$S6switch1dyyF
+  // CHECK:   br [[CONT]]
+    d()
+  }
+  // CHECK: [[CONT]]:
+  // CHECK:   function_ref @$S6switch1eyyF
+  e()
+}
+
+enum Generic<T, U> {
+  case Foo(T)
+  case Bar(U)
+}
+
+// Check that switching over a generic instance generates verified SIL.
+func test_union_generic_instance(u: Generic<Int, String>) {
+  switch u {
+  case .Foo(var x):
+    a()
+  case .Bar(var y):
+    b()
+  }
+  c()
+}
+
+enum Foo { case A, B }
+
+// CHECK-LABEL: sil hidden @$S6switch05test_A11_two_unions1x1yyAA3FooO_AFtF
+func test_switch_two_unions(x: Foo, y: Foo) {
+  // CHECK:   [[T0:%.*]] = tuple (%0 : $Foo, %1 : $Foo)
+  // CHECK:   [[X:%.*]] = tuple_extract [[T0]] : $(Foo, Foo), 0
+  // CHECK:   [[Y:%.*]] = tuple_extract [[T0]] : $(Foo, Foo), 1
+
+  // CHECK:   switch_enum [[Y]] : $Foo, case #Foo.A!enumelt: [[IS_CASE1:bb[0-9]+]], default [[IS_NOT_CASE1:bb[0-9]+]]
+
+  switch (x, y) {
+  // CHECK: [[IS_CASE1]]:
+  case (_, Foo.A):
+  // CHECK:   function_ref @$S6switch1ayyF
+    a()
+
+  // CHECK: [[IS_NOT_CASE1]]:
+  // CHECK:   switch_enum [[X]] : $Foo, case #Foo.B!enumelt: [[IS_CASE2:bb[0-9]+]], default [[IS_NOT_CASE2:bb[0-9]+]]
+  // CHECK: [[IS_CASE2]]:
+  case (Foo.B, _):
+  // CHECK:   function_ref @$S6switch1byyF
+    b()
+
+  // CHECK: [[IS_NOT_CASE2]]:
+  // CHECK:   switch_enum [[Y]] : $Foo, case #Foo.B!enumelt: [[IS_CASE3:bb[0-9]+]], default [[UNREACHABLE:bb[0-9]+]]
+  // CHECK: [[IS_CASE3]]:
+  case (_, Foo.B):
+  // CHECK:   function_ref @$S6switch1cyyF
+    c()
+
+  // CHECK: [[UNREACHABLE]]:
+  // CHECK:   unreachable
+  }
+}
+
+
+// <rdar://problem/14826416>
+func rdar14826416<T, U>(t: T, u: U) {
+  switch t {
+  case is Int: markUsed("Int")
+  case is U: markUsed("U")
+  case _: markUsed("other")
+  }
+}
+// CHECK-LABEL: sil hidden @$S6switch12rdar14826416{{[_0-9a-zA-Z]*}}F
+// CHECK:   checked_cast_addr_br copy_on_success T in {{%.*}} : $*T to Int in {{%.*}} : $*Int, [[IS_INT:bb[0-9]+]], [[ISNT_INT:bb[0-9]+]]
+// CHECK: [[ISNT_INT]]:
+// CHECK:   checked_cast_addr_br copy_on_success T in {{%.*}} : $*T to U in {{%.*}} : $*U, [[ISNT_INT_IS_U:bb[0-9]+]], [[ISNT_INT_ISNT_U:bb[0-9]+]]
+
+// <rdar://problem/14835992>
+class Rdar14835992 {}
+class SubRdar14835992 : Rdar14835992 {}
+
+// CHECK-LABEL: sil hidden @$S6switch12rdar14835992{{[_0-9a-zA-Z]*}}F
+func rdar14835992<T, U>(t: Rdar14835992, tt: T, uu: U) {
+  switch t {
+  case is SubRdar14835992: markUsed("Sub")
+  case is T: markUsed("T")
+  case is U: markUsed("U")
+  case _: markUsed("other")
+  }
+}
+
+
+
+
+// <rdar://problem/17272985>
+enum ABC { case A, B, C }
+
+// CHECK-LABEL: sil hidden @$S6switch18testTupleWildcardsyyAA3ABCO_ADtF
+// CHECK:         [[X:%.*]] = tuple_extract {{%.*}} : $(ABC, ABC), 0
+// CHECK:         [[Y:%.*]] = tuple_extract {{%.*}} : $(ABC, ABC), 1
+// CHECK:         switch_enum [[X]] : $ABC, case #ABC.A!enumelt: [[X_A:bb[0-9]+]], default [[X_NOT_A:bb[0-9]+]]
+// CHECK:       [[X_A]]:
+// CHECK:         function_ref @$S6switch1ayyF
+// CHECK:       [[X_NOT_A]]:
+// CHECK:         switch_enum [[Y]] : $ABC, case #ABC.A!enumelt: [[Y_A:bb[0-9]+]], case #ABC.B!enumelt: [[Y_B:bb[0-9]+]], case #ABC.C!enumelt: [[Y_C:bb[0-9]+]]
+// CHECK-NOT: default
+// CHECK:       [[Y_A]]:
+// CHECK:         function_ref @$S6switch1byyF
+// CHECK:       [[Y_B]]:
+// CHECK:         function_ref @$S6switch1cyyF
+// CHECK:       [[Y_C]]:
+// CHECK:         switch_enum [[X]] : $ABC, case #ABC.C!enumelt: [[X_C:bb[0-9]+]], default [[X_NOT_C:bb[0-9]+]]
+// CHECK:       [[X_C]]:
+// CHECK:         function_ref @$S6switch1dyyF
+// CHECK:       [[X_NOT_C]]:
+// CHECK:         function_ref @$S6switch1eyyF
+func testTupleWildcards(_ x: ABC, _ y: ABC) {
+  switch (x, y) {
+  case (.A, _):
+    a()
+  case (_, .A):
+    b()
+  case (_, .B):
+    c()
+  case (.C, .C):
+    d()
+  default:
+    e()
+  }
+}
+
+enum LabeledScalarPayload {
+  case Payload(name: Int)
+}
+
+// CHECK-LABEL: sil hidden @$S6switch24testLabeledScalarPayloadyypAA0cdE0OF
+func testLabeledScalarPayload(_ lsp: LabeledScalarPayload) -> Any {
+  // CHECK: switch_enum {{%.*}}, case #LabeledScalarPayload.Payload!enumelt.1: bb1
+  switch lsp {
+  // CHECK: bb1([[TUPLE:%.*]] : $(name: Int)):
+  // CHECK:   [[X:%.*]] = tuple_extract [[TUPLE]]
+  // CHECK:   [[ANY_X_ADDR:%.*]] = init_existential_addr {{%.*}}, $Int
+  // CHECK:   store [[X]] to [trivial] [[ANY_X_ADDR]]
+  case let .Payload(x):
+    return x
+  }
+}
+
+// There should be no unreachable generated.
+// CHECK-LABEL: sil hidden @$S6switch19testOptionalPatternyySiSgF
+func testOptionalPattern(_ value : Int?) {
+  // CHECK: switch_enum %0 : $Optional<Int>, case #Optional.some!enumelt.1: bb1, case #Optional.none!enumelt: [[NILBB:bb[0-9]+]]
+  switch value {
+  case 1?: a()
+  case 2?: b()
+  case nil: d()
+  default: e()
+  }
+}
+
+
+// x? and .none should both be considered "similar" and thus handled in the same
+// switch on the enum kind.  There should be no unreachable generated.
+// CHECK-LABEL: sil hidden @$S6switch19testOptionalEnumMixyS2iSgF
+func testOptionalEnumMix(_ a : Int?) -> Int {
+  // CHECK: debug_value %0 : $Optional<Int>, let, name "a"
+  // CHECK-NEXT: switch_enum %0 : $Optional<Int>, case #Optional.some!enumelt.1: [[SOMEBB:bb[0-9]+]], case #Optional.none!enumelt: [[NILBB:bb[0-9]+]]
+  switch a {
+  case let x?:
+    return 0
+
+  // CHECK: [[SOMEBB]](%3 : $Int):
+  // CHECK-NEXT: debug_value %3 : $Int, let, name "x"
+  // CHECK: integer_literal $Builtin.Int2048, 0
+
+  case .none:
+    return 42
+
+  // CHECK: [[NILBB]]:
+  // CHECK: integer_literal $Builtin.Int2048, 42
+  }
+}
+
+// x? and nil should both be considered "similar" and thus handled in the same
+// switch on the enum kind.  There should be no unreachable generated.
+// CHECK-LABEL: sil hidden @$S6switch26testOptionalEnumMixWithNilyS2iSgF
+func testOptionalEnumMixWithNil(_ a : Int?) -> Int {
+  // CHECK: debug_value %0 : $Optional<Int>, let, name "a"
+  // CHECK-NEXT: switch_enum %0 : $Optional<Int>, case #Optional.some!enumelt.1: [[SOMEBB:bb[0-9]+]], case #Optional.none!enumelt: [[NILBB:bb[0-9]+]]
+  switch a {
+  case let x?:
+    return 0
+
+  // CHECK: [[SOMEBB]](%3 : $Int):
+  // CHECK-NEXT: debug_value %3 : $Int, let, name "x"
+  // CHECK: integer_literal $Builtin.Int2048, 0
+
+  case nil:
+    return 42
+
+  // CHECK: [[NILBB]]:
+  // CHECK: integer_literal $Builtin.Int2048, 42
+  }
+}
+
+// SR-3518
+// CHECK-LABEL: sil hidden @$S6switch43testMultiPatternsWithOuterScopeSameNamedVar4base6filterySiSg_AEtF
+func testMultiPatternsWithOuterScopeSameNamedVar(base: Int?, filter: Int?) {
+  switch(base, filter) {
+    
+  case (.some(let base), .some(let filter)):
+    // CHECK: bb2(%10 : $Int):
+    // CHECK-NEXT: debug_value %8 : $Int, let, name "base"
+    // CHECK-NEXT: debug_value %10 : $Int, let, name "filter"
+    print("both: \(base), \(filter)")
+  case (.some(let base), .none), (.none, .some(let base)):
+    // CHECK: bb3:
+    // CHECK-NEXT: debug_value %8 : $Int, let, name "base"
+    // CHECK-NEXT: br bb6(%8 : $Int)
+
+    // CHECK: bb5([[OTHER_BASE:%.*]] : $Int)
+    // CHECK-NEXT: debug_value [[OTHER_BASE]] : $Int, let, name "base"
+    // CHECK-NEXT: br bb6([[OTHER_BASE]] : $Int)
+    
+    // CHECK: bb6([[ARG:%.*]] : $Int):
+    print("single: \(base)")
+  default:
+    print("default")
+  }
+}
+
+// All cases are unreachable, either structurally (tuples involving Never) or
+// nominally (empty enums).  We fold all of these to 'unreachable'.
+enum MyNever {}
+func ~= (_ : MyNever, _ : MyNever) -> Bool { return true }
+func myFatalError() -> MyNever { fatalError("asdf") }
+
+func testUninhabitedSwitchScrutinee() {
+  func test1(x : MyNever) {
+    // CHECK: bb0(%0 : $MyNever):
+    // CHECK-NEXT: debug_value %0 : $MyNever, let, name "x"
+    // CHECK-NEXT: unreachable
+    switch x {
+    case myFatalError(): break
+    case myFatalError(): break
+    case myFatalError(): break
+    }
+  }
+  func test2(x : Never) {
+    // CHECK: bb0(%0 : $Never):
+    // CHECK-NEXT: debug_value %0 : $Never, let, name "x"
+    // CHECK-NEXT: unreachable
+    switch (x, x) {}
+  }
+  func test3(x : Never) {
+    // CHECK: unreachable
+    // CHECK-NEXT: } // end sil function '$S6switch30testUninhabitedSwitchScrutineeyyF5test3L_1xys5NeverO_tF'
+    switch (x, 5, x) {}
+  }
+  func test4(x : Never) {
+    // CHECK: unreachable
+    // CHECK-NEXT: } // end sil function '$S6switch30testUninhabitedSwitchScrutineeyyF5test4L_1xys5NeverO_tF'
+    switch ((8, 6, 7), (5, 3, (0, x))) {}
+  }
+  func test5() {
+    // CHECK: %0 = function_ref @$S6switch12myFatalErrorAA7MyNeverOyF : $@convention(thin) () -> MyNever
+    // CHECK-NEXT: %1 = apply %0() : $@convention(thin) () -> MyNever
+    // CHECK-NEXT: unreachable
+    switch myFatalError() {}
+  }
+}
diff --git a/test/SILGen/plus_zero_switch_abstraction.swift b/test/SILGen/plus_zero_switch_abstraction.swift
new file mode 100644
index 0000000..86ebbc9
--- /dev/null
+++ b/test/SILGen/plus_zero_switch_abstraction.swift
@@ -0,0 +1,46 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership -parse-stdlib %s | %FileCheck %s
+
+struct A {}
+
+enum Optionable<T> {
+  case Summn(T)
+  case Nuttn
+}
+
+// CHECK-LABEL: sil hidden @$S18switch_abstraction18enum_reabstraction1x1ayAA10OptionableOyAA1AVAHcG_AHtF : $@convention(thin) (@guaranteed Optionable<(A) -> A>, A) -> ()
+// CHECK: switch_enum {{%.*}} : $Optionable<(A) -> A>, case #Optionable.Summn!enumelt.1: [[DEST:bb[0-9]+]]
+// CHECK: [[DEST]]([[ORIG:%.*]] : @owned $@callee_guaranteed (@in_guaranteed A) -> @out A):
+// CHECK:   [[REABSTRACT:%.*]] = function_ref @$S{{.*}}TR :
+// CHECK:   [[SUBST:%.*]] = partial_apply [callee_guaranteed] [[REABSTRACT]]([[ORIG]])
+func enum_reabstraction(x x: Optionable<(A) -> A>, a: A) {
+  switch x {
+  case .Summn(var f):
+    f(a)
+  case .Nuttn:
+    ()
+  }
+}
+
+enum Wacky<A, B> {
+  case Foo(A)
+  case Bar((B) -> A)
+}
+
+// CHECK-LABEL: sil hidden @$S18switch_abstraction45enum_addr_only_to_loadable_with_reabstraction{{[_0-9a-zA-Z]*}}F : $@convention(thin) <T> (@in_guaranteed Wacky<T, A>, A) -> @out T {
+// CHECK: switch_enum_addr [[ENUM:%.*]] : $*Wacky<T, A>, {{.*}} case #Wacky.Bar!enumelt.1: [[DEST:bb[0-9]+]]
+// CHECK: [[DEST]]:
+// CHECK:   [[ORIG_ADDR:%.*]] = unchecked_take_enum_data_addr [[ENUM]] : $*Wacky<T, A>, #Wacky.Bar
+// CHECK:   [[ORIG:%.*]] = load [take] [[ORIG_ADDR]]
+// CHECK:   [[REABSTRACT:%.*]] = function_ref @$S{{.*}}TR :
+// CHECK:   [[SUBST:%.*]] = partial_apply [callee_guaranteed] [[REABSTRACT]]<T>([[ORIG]])
+func enum_addr_only_to_loadable_with_reabstraction<T>(x x: Wacky<T, A>, a: A)
+  -> T
+{
+  switch x {
+  case .Foo(var b):
+    return b
+  case .Bar(var f):
+    return f(a)
+  }
+}
diff --git a/test/SILGen/plus_zero_switch_isa.swift b/test/SILGen/plus_zero_switch_isa.swift
new file mode 100644
index 0000000..7ad4e70
--- /dev/null
+++ b/test/SILGen/plus_zero_switch_isa.swift
@@ -0,0 +1,74 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -emit-silgen %s | %FileCheck %s
+
+func markUsed<T>(_ t: T) {}
+
+// rdar://17772217
+func testSwitchOnExistential(_ value: Any) {
+  switch value {
+    case true as Bool: markUsed("true")
+    case false as Bool: markUsed("false")
+    default: markUsed("default")
+  }
+}
+
+// CHECK-LABEL: sil hidden @$S10switch_isa23testSwitchOnExistentialyyypF :
+// CHECK:   [[ANY:%.*]] = alloc_stack $Any
+// CHECK:   copy_addr %0 to [initialization] [[ANY]]
+// CHECK:   [[BOOL:%.*]] = alloc_stack $Bool
+// CHECK:   checked_cast_addr_br copy_on_success Any in [[ANY]] : $*Any to Bool in [[BOOL]] : $*Bool, [[IS_BOOL:bb[0-9]+]], [[IS_NOT_BOOL:bb[0-9]+]]
+// CHECK: [[IS_BOOL]]:
+// CHECK:   [[T0:%.*]] = load [trivial] [[BOOL]]
+
+enum Foo {
+  case A
+}
+enum Bar<T> {
+  case B(T)
+}
+func testSwitchEnumOnExistential(_ value: Any) {
+  switch value {
+  case Foo.A:
+    ()
+  case Bar<Int>.B(let i):
+    ()
+  case Bar<Foo>.B(let f):
+    ()
+  default:
+    ()
+  }
+}
+
+// CHECK-LABEL: sil hidden @$S10switch_isa27testSwitchEnumOnExistentialyyypF : $@convention(thin) (@in_guaranteed Any) -> ()
+// CHECK:   checked_cast_addr_br copy_on_success Any in {{%.*}} : $*Any to Foo
+// CHECK:   checked_cast_addr_br copy_on_success Any in {{%.*}} : $*Any to Bar<Int>
+// CHECK:   checked_cast_addr_br copy_on_success Any in {{%.*}} : $*Any to Bar<Foo>
+
+class B {}
+class D: B {}
+
+func guardFn(_ l: D, _ r: D) -> Bool { return true }
+
+// rdar://problem/21087371
+// CHECK-LABEL: sil hidden @$S10switch_isa32testSwitchTwoIsPatternsWithGuard_1ryAA1BC_AEtF
+// CHECK:         checked_cast_br {{%.*}} : $B to $D, [[R_CAST_YES:bb[0-9]+]], [[R_CAST_NO:bb[0-9]+]]
+// CHECK:       [[R_CAST_YES]]({{.*}}):
+// CHECK:         checked_cast_br {{%.*}} : $B to $D, [[L_CAST_YES:bb[0-9]+]], [[L_CAST_NO:bb[0-9]+]]
+// CHECK:       [[L_CAST_YES]]({{.*}}):
+// CHECK:         function_ref @$S10switch_isa7guardFnySbAA1DC_ADtF
+// CHECK:         cond_br {{%.*}}, [[GUARD_YES:bb[0-9]+]], [[GUARD_NO:bb[0-9]+]]
+// CHECK:       [[GUARD_NO]]:
+// CHECK-NEXT:    destroy_value [[R2:%.*]] : $D
+// CHECK-NEXT:    destroy_value [[L2:%.*]] : $D
+// CHECK-NEXT:    br [[CONT:bb[0-9]+]]
+// CHECK:       [[L_CAST_NO]]:
+// CHECK-NEXT:    destroy_value [[R2:%.*]] : $D
+// CHECK-NEXT:    br [[CONT]]
+func testSwitchTwoIsPatternsWithGuard(_ l: B, r: B) {
+  switch (l, r) {
+  case (let l2 as D, let r2 as D) where guardFn(l2, r2):
+    break
+  default:
+    break
+  }
+}
diff --git a/test/SILGen/plus_zero_switch_multiple_entry_address_only.swift b/test/SILGen/plus_zero_switch_multiple_entry_address_only.swift
new file mode 100644
index 0000000..1e70918
--- /dev/null
+++ b/test/SILGen/plus_zero_switch_multiple_entry_address_only.swift
@@ -0,0 +1,190 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend %s -emit-silgen | %FileCheck %s
+
+enum E {
+case a(Any)
+case b(Any)
+case c(Any)
+}
+
+// CHECK-LABEL: sil hidden @$S34switch_multiple_entry_address_only8takesAnyyyypF : $@convention(thin) (@in_guaranteed Any) -> ()
+func takesAny(_ x: Any) {}
+
+// CHECK-LABEL: sil hidden @$S34switch_multiple_entry_address_only0B9LabelsLet1eyAA1EO_tF : $@convention(thin) (@in_guaranteed E) -> ()
+func multipleLabelsLet(e: E) {
+  // CHECK:      bb0
+  // CHECK:      [[X_PHI:%.*]] = alloc_stack $Any
+  // CHECK-NEXT: [[E_COPY:%.*]] = alloc_stack $E
+  // CHECK-NEXT: copy_addr %0 to [initialization] [[E_COPY]]
+  // CHECK-NEXT: switch_enum_addr [[E_COPY]] : $*E, case #E.a!enumelt.1: bb1, case #E.b!enumelt.1: bb2, default bb4
+
+  // CHECK:      bb1:
+  // CHECK-NEXT: [[E_PAYLOAD:%.*]] = unchecked_take_enum_data_addr [[E_COPY]] : $*E, #E.a!enumelt.1
+  // CHECK-NEXT: [[ANY_BOX:%.*]] = alloc_stack $Any
+  // CHECK-NEXT: copy_addr [take] [[E_PAYLOAD]] to [initialization] [[ANY_BOX]]
+  // CHECK-NEXT: copy_addr [[ANY_BOX]] to [initialization] [[X_PHI]]
+  // CHECK-NEXT: destroy_addr [[ANY_BOX]]
+  // CHECK-NEXT: dealloc_stack [[ANY_BOX]]
+  // CHECK-NEXT: dealloc_stack [[E_COPY]]
+  // CHECK-NEXT: br bb3
+
+  // CHECK:      bb2:
+  // CHECK-NEXT: [[E_PAYLOAD:%.*]] = unchecked_take_enum_data_addr [[E_COPY]] : $*E, #E.b!enumelt.1
+  // CHECK-NEXT: [[ANY_BOX:%.*]] = alloc_stack $Any
+  // CHECK-NEXT: copy_addr [take] [[E_PAYLOAD]] to [initialization] [[ANY_BOX]]
+  // CHECK-NEXT: copy_addr [[ANY_BOX]] to [initialization] [[X_PHI]]
+  // CHECK-NEXT: destroy_addr [[ANY_BOX]]
+  // CHECK-NEXT: dealloc_stack [[ANY_BOX]]
+  // CHECK-NEXT: dealloc_stack [[E_COPY]]
+  // CHECK-NEXT: br bb3
+
+  // CHECK:      bb3:
+  // CHECK:      [[FN:%.*]] = function_ref @$S34switch_multiple_entry_address_only8takesAnyyyypF
+  // CHECK-NEXT: apply [[FN]]([[X_PHI]]
+  // CHECK-NEXT: destroy_addr [[X_PHI]]
+  // CHECK-NEXT: br bb6
+
+  // CHECK:      bb4:
+  // CHECK-NEXT: br bb5
+
+  // CHECK:      bb5:
+  // CHECK-NEXT: destroy_addr [[E_COPY]]
+  // CHECK-NEXT: dealloc_stack [[E_COPY]]
+  // CHECK-NEXT: br bb6
+
+  // CHECK:      bb6:
+  // CHECK-NEXT: dealloc_stack [[X_PHI]]
+  // CHECK-NEXT: tuple ()
+  // CHECK-NEXT: return
+
+  switch e {
+  case .a(let x), .b(let x):
+    takesAny(x)
+  default:
+    break
+  }
+}
+
+// CHECK-LABEL: sil hidden @$S34switch_multiple_entry_address_only0B9LabelsVar1eyAA1EO_tF : $@convention(thin) (@in_guaranteed E) -> ()
+func multipleLabelsVar(e: E) {
+  // CHECK:      bb0
+  // CHECK:      [[X_PHI:%.*]] = alloc_stack $Any
+  // CHECK-NEXT: [[E_COPY:%.*]] = alloc_stack $E
+  // CHECK-NEXT: copy_addr %0 to [initialization] [[E_COPY]]
+  // CHECK-NEXT: switch_enum_addr [[E_COPY]] : $*E, case #E.a!enumelt.1: bb1, case #E.b!enumelt.1: bb2, default bb4
+
+  // CHECK:      bb1:
+  // CHECK-NEXT: [[E_PAYLOAD:%.*]] = unchecked_take_enum_data_addr [[E_COPY]] : $*E, #E.a!enumelt.1
+  // CHECK-NEXT: [[ANY_BOX:%.*]] = alloc_stack $Any
+  // CHECK-NEXT: copy_addr [take] [[E_PAYLOAD]] to [initialization] [[ANY_BOX]]
+  // CHECK-NEXT: copy_addr [[ANY_BOX]] to [initialization] [[X_PHI]]
+  // CHECK-NEXT: destroy_addr [[ANY_BOX]]
+  // CHECK-NEXT: dealloc_stack [[ANY_BOX]]
+  // CHECK-NEXT: dealloc_stack [[E_COPY]]
+  // CHECK-NEXT: br bb3
+
+  // CHECK:      bb2:
+  // CHECK-NEXT: [[E_PAYLOAD:%.*]] = unchecked_take_enum_data_addr [[E_COPY]] : $*E, #E.b!enumelt.1
+  // CHECK-NEXT: [[ANY_BOX:%.*]] = alloc_stack $Any
+  // CHECK-NEXT: copy_addr [take] [[E_PAYLOAD]] to [initialization] [[ANY_BOX]]
+  // CHECK-NEXT: copy_addr [[ANY_BOX]] to [initialization] [[X_PHI]]
+  // CHECK-NEXT: destroy_addr [[ANY_BOX]]
+  // CHECK-NEXT: dealloc_stack [[ANY_BOX]]
+  // CHECK-NEXT: dealloc_stack [[E_COPY]]
+  // CHECK-NEXT: br bb3
+
+  // CHECK:      bb3:
+  // CHECK-NEXT: [[ANY_BOX:%.*]] = alloc_box ${ var Any }, var, name "x"
+  // CHECK-NEXT: [[BOX_PAYLOAD:%.*]] = project_box [[ANY_BOX]] : ${ var Any }, 0
+  // CHECK-NEXT: copy_addr [take] [[X_PHI]] to [initialization] [[BOX_PAYLOAD]]
+  // CHECK-NEXT: [[ACCESS:%.*]] = begin_access [read] [unknown] [[BOX_PAYLOAD]]
+  // CHECK-NEXT: [[ANY_STACK:%.*]] = alloc_stack $Any
+  // CHECK-NEXT: copy_addr [[ACCESS]] to [initialization] [[ANY_STACK]]
+  // CHECK-NEXT: end_access [[ACCESS]]
+  // CHECK:      [[FN:%.*]] = function_ref @$S34switch_multiple_entry_address_only8takesAnyyyypF
+  // CHECK-NEXT: apply [[FN]]([[ANY_STACK]]
+  // CHECK-NEXT: destroy_addr [[ANY_STACK]]
+  // CHECK-NEXT: dealloc_stack [[ANY_STACK]]
+  // CHECK-NEXT: destroy_value [[ANY_BOX]]
+  // CHECK-NEXT: br bb6
+
+  // CHECK:      bb4:
+  // CHECK-NEXT: br bb5
+
+  // CHECK:      bb5:
+  // CHECK-NEXT: destroy_addr [[E_COPY]]
+  // CHECK-NEXT: dealloc_stack [[E_COPY]]
+  // CHECK-NEXT: br bb6
+
+  // CHECK:      bb6:
+  // CHECK-NEXT: dealloc_stack [[X_PHI]]
+  // CHECK-NEXT: tuple ()
+  // CHECK-NEXT: return
+
+  switch e {
+  case .a(var x), .b(var x):
+    takesAny(x)
+  default:
+    break
+  }
+}
+
+// CHECK-LABEL: sil hidden @$S34switch_multiple_entry_address_only20fallthroughWithValue1eyAA1EO_tF : $@convention(thin) (@in_guaranteed E) -> ()
+func fallthroughWithValue(e: E) {
+  // CHECK:      bb0
+  // CHECK:      [[X_PHI:%.*]] = alloc_stack $Any
+  // CHECK-NEXT: [[E_COPY:%.*]] = alloc_stack $E
+  // CHECK-NEXT: copy_addr %0 to [initialization] [[E_COPY]]
+  // CHECK-NEXT: switch_enum_addr [[E_COPY]] : $*E, case #E.a!enumelt.1: bb1, case #E.b!enumelt.1: bb2, default bb4
+  
+  // CHECK:      bb1:
+  // CHECK-NEXT: [[E_PAYLOAD:%.*]] = unchecked_take_enum_data_addr [[E_COPY]] : $*E, #E.a!enumelt.1
+  // CHECK-NEXT: [[ORIGINAL_ANY_BOX:%.*]] = alloc_stack $Any
+  // CHECK-NEXT: copy_addr [take] [[E_PAYLOAD]] to [initialization] [[ORIGINAL_ANY_BOX]]
+  // CHECK:      [[FN1:%.*]] = function_ref @$S34switch_multiple_entry_address_only8takesAnyyyypF
+  // CHECK-NEXT: apply [[FN1]]([[ORIGINAL_ANY_BOX]]
+  // CHECK-NEXT: copy_addr [[ORIGINAL_ANY_BOX]] to [initialization] [[X_PHI]]
+  // CHECK-NEXT: destroy_addr [[ORIGINAL_ANY_BOX]]
+  // CHECK-NEXT: dealloc_stack [[ORIGINAL_ANY_BOX]]
+  // CHECK-NEXT: dealloc_stack [[E_COPY]]
+  // CHECK-NEXT: br bb3
+  
+  // CHECK:      bb2:
+  // CHECK-NEXT: [[E_PAYLOAD:%.*]] = unchecked_take_enum_data_addr [[E_COPY]] : $*E, #E.b!enumelt.1
+  // CHECK-NEXT: [[ANY_BOX:%.*]] = alloc_stack $Any
+  // CHECK-NEXT: copy_addr [take] [[E_PAYLOAD]] to [initialization] [[ANY_BOX]]
+  // CHECK-NEXT: copy_addr [[ANY_BOX]] to [initialization] [[X_PHI]]
+  // CHECK-NEXT: destroy_addr [[ANY_BOX]]
+  // CHECK-NEXT: dealloc_stack [[ANY_BOX]]
+  // CHECK-NEXT: dealloc_stack [[E_COPY]]
+  // CHECK-NEXT: br bb3
+  
+  // CHECK:      bb3:
+  // CHECK:      [[FN2:%.*]] = function_ref @$S34switch_multiple_entry_address_only8takesAnyyyypF
+  // CHECK-NEXT: apply [[FN2]]([[X_PHI]]
+  // CHECK-NEXT: destroy_addr [[X_PHI]]
+  // CHECK-NEXT: br bb6
+  
+  // CHECK:      bb4:
+  // CHECK-NEXT: br bb5
+  
+  // CHECK:      bb5:
+  // CHECK-NEXT: destroy_addr [[E_COPY]]
+  // CHECK-NEXT: dealloc_stack [[E_COPY]]
+  // CHECK-NEXT: br bb6
+  
+  // CHECK:      bb6:
+  // CHECK-NEXT: dealloc_stack [[X_PHI]]
+  // CHECK-NEXT: tuple ()
+  // CHECK-NEXT: return
+  
+  switch e {
+  case .a(let x):
+    takesAny(x)
+    fallthrough
+  case .b(let x):
+    takesAny(x)
+  default:
+    break
+  }
+}
diff --git a/test/SILGen/plus_zero_switch_var.swift b/test/SILGen/plus_zero_switch_var.swift
new file mode 100644
index 0000000..becf093
--- /dev/null
+++ b/test/SILGen/plus_zero_switch_var.swift
@@ -0,0 +1,750 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -emit-silgen %s | %FileCheck %s
+
+// TODO: Implement tuple equality in the library.
+// BLOCKED: <rdar://problem/13822406>
+func ~= (x: (Int, Int), y: (Int, Int)) -> Bool {
+  return x.0 == y.0 && x.1 == y.1
+}
+
+// Some fake predicates for pattern guards.
+func runced() -> Bool { return true }
+func funged() -> Bool { return true }
+func ansed() -> Bool { return true }
+
+func runced(x x: Int) -> Bool { return true }
+func funged(x x: Int) -> Bool { return true }
+func ansed(x x: Int) -> Bool { return true }
+
+func foo() -> Int { return 0 }
+func bar() -> Int { return 0 }
+func foobar() -> (Int, Int) { return (0, 0) }
+
+func foos() -> String { return "" }
+func bars() -> String { return "" }
+
+func a() {}
+func b() {}
+func c() {}
+func d() {}
+func e() {}
+func f() {}
+func g() {}
+
+func a(x x: Int) {}
+func b(x x: Int) {}
+func c(x x: Int) {}
+func d(x x: Int) {}
+
+func a(x x: String) {}
+func b(x x: String) {}
+
+func aa(x x: (Int, Int)) {}
+func bb(x x: (Int, Int)) {}
+func cc(x x: (Int, Int)) {}
+
+// CHECK-LABEL: sil hidden @$S10switch_var05test_B2_1yyF
+func test_var_1() {
+  // CHECK:   function_ref @$S10switch_var3fooSiyF
+  switch foo() {
+  // CHECK:   [[XADDR:%.*]] = alloc_box ${ var Int }
+  // CHECK:   [[X:%.*]] = project_box [[XADDR]]
+  // CHECK-NOT: br bb
+  case var x:
+  // CHECK:   [[READ:%.*]] = begin_access [read] [unknown] [[X]]
+  // CHECK:   load [trivial] [[READ]]
+  // CHECK:   function_ref @$S10switch_var1a1xySi_tF
+  // CHECK:   destroy_value [[XADDR]]
+  // CHECK:   br [[CONT:bb[0-9]+]]
+    a(x: x)
+  }
+  // CHECK: [[CONT]]:
+  // CHECK:   function_ref @$S10switch_var1byyF
+  b()
+}
+
+// CHECK-LABEL: sil hidden @$S10switch_var05test_B2_2yyF
+func test_var_2() {
+  // CHECK:   function_ref @$S10switch_var3fooSiyF
+  switch foo() {
+  // CHECK:   [[XADDR:%.*]] = alloc_box ${ var Int }
+  // CHECK:   [[X:%.*]] = project_box [[XADDR]]
+  // CHECK:   [[READ:%.*]] = begin_access [read] [unknown] [[X]]
+  // CHECK:   load [trivial] [[READ]]
+  // CHECK:   function_ref @$S10switch_var6runced1xSbSi_tF
+  // CHECK:   cond_br {{%.*}}, [[CASE1:bb[0-9]+]], [[NO_CASE1:bb[0-9]+]]
+  // -- TODO: Clean up these empty waypoint bbs.
+  case var x where runced(x: x):
+  // CHECK: [[CASE1]]:
+  // CHECK:   [[READ:%.*]] = begin_access [read] [unknown] [[X]]
+  // CHECK:   load [trivial] [[READ]]
+  // CHECK:   function_ref @$S10switch_var1a1xySi_tF
+  // CHECK:   destroy_value [[XADDR]]
+  // CHECK:   br [[CONT:bb[0-9]+]]
+    a(x: x)
+  // CHECK: [[NO_CASE1]]:
+  // CHECK:   [[YADDR:%.*]] = alloc_box ${ var Int }
+  // CHECK:   [[Y:%.*]] = project_box [[YADDR]]
+  // CHECK:   [[READ:%.*]] = begin_access [read] [unknown] [[Y]]
+  // CHECK:   load [trivial] [[READ]]
+  // CHECK:   function_ref @$S10switch_var6funged1xSbSi_tF
+  // CHECK:   cond_br {{%.*}}, [[CASE2:bb[0-9]+]], [[NO_CASE2:bb[0-9]+]]
+  case var y where funged(x: y):
+  // CHECK: [[CASE2]]:
+  // CHECK:   [[READ:%.*]] = begin_access [read] [unknown] [[Y]]
+  // CHECK:   load [trivial] [[READ]]
+  // CHECK:   function_ref @$S10switch_var1b1xySi_tF
+  // CHECK:   destroy_value [[YADDR]]
+  // CHECK:   br [[CONT]]
+    b(x: y)
+  // CHECK: [[NO_CASE2]]:
+  // CHECK:   br [[CASE3:bb[0-9]+]]
+  case var z:
+  // CHECK: [[CASE3]]:
+  // CHECK:   [[ZADDR:%.*]] = alloc_box ${ var Int }
+  // CHECK:   [[Z:%.*]] = project_box [[ZADDR]]
+  // CHECK:   [[READ:%.*]] = begin_access [read] [unknown] [[Z]]
+  // CHECK:   load [trivial] [[READ]]
+  // CHECK:   function_ref @$S10switch_var1c1xySi_tF
+  // CHECK:   destroy_value [[ZADDR]]
+  // CHECK:   br [[CONT]]
+    c(x: z)
+  }
+  // CHECK: [[CONT]]:
+  // CHECK:   function_ref @$S10switch_var1dyyF
+  d()
+}
+
+// CHECK-LABEL: sil hidden @$S10switch_var05test_B2_3yyF
+func test_var_3() {
+  // CHECK:   function_ref @$S10switch_var3fooSiyF
+  // CHECK:   function_ref @$S10switch_var3barSiyF
+  switch (foo(), bar()) {
+  // CHECK:   [[XADDR:%.*]] = alloc_box ${ var (Int, Int) }
+  // CHECK:   [[X:%.*]] = project_box [[XADDR]]
+  // CHECK:   [[READ:%.*]] = begin_access [read] [unknown] [[X]]
+  // CHECK:   tuple_element_addr [[READ]] : {{.*}}, 0
+  // CHECK:   function_ref @$S10switch_var6runced1xSbSi_tF
+  // CHECK:   cond_br {{%.*}}, [[CASE1:bb[0-9]+]], [[NO_CASE1:bb[0-9]+]]
+  case var x where runced(x: x.0):
+  // CHECK: [[CASE1]]:
+  // CHECK:   [[READ:%.*]] = begin_access [read] [unknown] [[X]]
+  // CHECK:   load [trivial] [[READ]]
+  // CHECK:   function_ref @$S10switch_var2aa1xySi_Sit_tF
+  // CHECK:   destroy_value [[XADDR]]
+  // CHECK:   br [[CONT:bb[0-9]+]]
+    aa(x: x)
+  // CHECK: [[NO_CASE1]]:
+  // CHECK:   br [[NO_CASE1_TARGET:bb[0-9]+]]
+
+  // CHECK: [[NO_CASE1_TARGET]]:
+  // CHECK:   [[YADDR:%.*]] = alloc_box ${ var Int }
+  // CHECK:   [[Y:%.*]] = project_box [[YADDR]]
+  // CHECK:   [[ZADDR:%.*]] = alloc_box ${ var Int }
+  // CHECK:   [[Z:%.*]] = project_box [[ZADDR]]
+  // CHECK:   [[READ:%.*]] = begin_access [read] [unknown] [[Y]]
+  // CHECK:   load [trivial] [[READ]]
+  // CHECK:   function_ref @$S10switch_var6funged1xSbSi_tF
+  // CHECK:   cond_br {{%.*}}, [[CASE2:bb[0-9]+]], [[NO_CASE2:bb[0-9]+]]
+  case (var y, var z) where funged(x: y):
+  // CHECK: [[CASE2]]:
+  // CHECK:   [[READ:%.*]] = begin_access [read] [unknown] [[Y]]
+  // CHECK:   load [trivial] [[READ]]
+  // CHECK:   function_ref @$S10switch_var1a1xySi_tF
+  // CHECK:   [[READ:%.*]] = begin_access [read] [unknown] [[Z]]
+  // CHECK:   load [trivial] [[READ]]
+  // CHECK:   function_ref @$S10switch_var1b1xySi_tF
+  // CHECK:   destroy_value [[ZADDR]]
+  // CHECK:   destroy_value [[YADDR]]
+  // CHECK:   br [[CONT]]
+    a(x: y)
+    b(x: z)
+  // CHECK: [[NO_CASE2]]:
+  // CHECK:   [[WADDR:%.*]] = alloc_box ${ var (Int, Int) }
+  // CHECK:   [[W:%.*]] = project_box [[WADDR]]
+  // CHECK:   [[READ:%.*]] = begin_access [read] [unknown] [[W]]
+  // CHECK:   tuple_element_addr [[READ]] : {{.*}}, 0
+  // CHECK:   function_ref @$S10switch_var5ansed1xSbSi_tF
+  // CHECK:   cond_br {{%.*}}, [[CASE3:bb[0-9]+]], [[NO_CASE3:bb[0-9]+]]
+  case var w where ansed(x: w.0):
+  // CHECK: [[CASE3]]:
+  // CHECK:   [[READ:%.*]] = begin_access [read] [unknown] [[W]]
+  // CHECK:   load [trivial] [[READ]]
+  // CHECK:   function_ref @$S10switch_var2bb1xySi_Sit_tF
+  // CHECK:   br [[CONT]]
+    bb(x: w)
+  // CHECK: [[NO_CASE3]]:
+  // CHECK:   destroy_value [[WADDR]]
+  // CHECK:   br [[CASE4:bb[0-9]+]]
+  case var v:
+  // CHECK: [[CASE4]]:
+  // CHECK:   [[VADDR:%.*]] = alloc_box ${ var (Int, Int) } 
+  // CHECK:   [[V:%.*]] = project_box [[VADDR]]
+  // CHECK:   [[READ:%.*]] = begin_access [read] [unknown] [[V]]
+  // CHECK:   load [trivial] [[READ]]
+  // CHECK:   function_ref @$S10switch_var2cc1xySi_Sit_tF
+  // CHECK:   destroy_value [[VADDR]]
+  // CHECK:   br [[CONT]]
+    cc(x: v)
+  }
+  // CHECK: [[CONT]]:
+  // CHECK:   function_ref @$S10switch_var1dyyF
+  d()
+}
+
+protocol P { func p() }
+
+struct X : P { func p() {} }
+struct Y : P { func p() {} }
+struct Z : P { func p() {} }
+
+// CHECK-LABEL: sil hidden @$S10switch_var05test_B2_41pyAA1P_p_tF
+func test_var_4(p p: P) {
+  // CHECK:   function_ref @$S10switch_var3fooSiyF
+  switch (p, foo()) {
+  // CHECK:   [[PAIR:%.*]] = alloc_stack $(P, Int)
+  // CHECK:   store
+  // CHECK:   [[PAIR_0:%.*]] = tuple_element_addr [[PAIR]] : $*(P, Int), 0
+  // CHECK:   [[T0:%.*]] = tuple_element_addr [[PAIR]] : $*(P, Int), 1
+  // CHECK:   [[PAIR_1:%.*]] = load [trivial] [[T0]] : $*Int
+  // CHECK:   [[TMP:%.*]] = alloc_stack $X
+  // CHECK:   checked_cast_addr_br copy_on_success P in [[PAIR_0]] : $*P to X in [[TMP]] : $*X, [[IS_X:bb[0-9]+]], [[IS_NOT_X:bb[0-9]+]]
+
+  // CHECK: [[IS_X]]:
+  // CHECK:   [[T0:%.*]] = load [trivial] [[TMP]] : $*X
+  // CHECK:   [[XADDR:%.*]] = alloc_box ${ var Int }
+  // CHECK:   [[X:%.*]] = project_box [[XADDR]]
+  // CHECK:   store [[PAIR_1]] to [trivial] [[X]]
+  // CHECK:   [[READ:%.*]] = begin_access [read] [unknown] [[X]]
+  // CHECK:   load [trivial] [[READ]]
+  // CHECK:   function_ref @$S10switch_var6runced1xSbSi_tF
+  // CHECK:   cond_br {{%.*}}, [[CASE1:bb[0-9]+]], [[NO_CASE1:bb[0-9]+]]
+  case (is X, var x) where runced(x: x):
+  // CHECK: [[CASE1]]:
+  // CHECK:   function_ref @$S10switch_var1a1xySi_tF
+  // CHECK:   destroy_value [[XADDR]]
+  // CHECK:   dealloc_stack [[TMP]]
+  // CHECK:   destroy_addr [[PAIR_0]] : $*P
+  // CHECK:   dealloc_stack [[PAIR]]
+  // CHECK:   br [[CONT:bb[0-9]+]]
+    a(x: x)
+
+  // CHECK: [[NO_CASE1]]:
+  // CHECK:   destroy_value [[XADDR]]
+  // CHECK:   dealloc_stack [[TMP]]
+  // CHECK:   br [[NEXT:bb[0-9]+]]
+  // CHECK: [[IS_NOT_X]]:
+  // CHECK:   dealloc_stack [[TMP]]
+  // CHECK:   br [[NEXT]]
+
+  // CHECK: [[NEXT]]:
+  // CHECK:   [[TMP:%.*]] = alloc_stack $Y
+  // CHECK:   checked_cast_addr_br copy_on_success P in [[PAIR_0]] : $*P to Y in [[TMP]] : $*Y, [[IS_Y:bb[0-9]+]], [[IS_NOT_Y:bb[0-9]+]]
+
+  // CHECK: [[IS_Y]]:
+  // CHECK:   [[T0:%.*]] = load [trivial] [[TMP]] : $*Y
+  // CHECK:   [[YADDR:%.*]] = alloc_box ${ var Int }
+  // CHECK:   [[Y:%.*]] = project_box [[YADDR]]
+  // CHECK:   store [[PAIR_1]] to [trivial] [[Y]]
+  // CHECK:   [[READ:%.*]] = begin_access [read] [unknown] [[Y]]
+  // CHECK:   load [trivial] [[READ]]
+  // CHECK:   function_ref @$S10switch_var6funged1xSbSi_tF
+  // CHECK:   cond_br {{%.*}}, [[CASE2:bb[0-9]+]], [[NO_CASE2:bb[0-9]+]]
+
+  case (is Y, var y) where funged(x: y):
+  // CHECK: [[CASE2]]:
+  // CHECK:   [[READ:%.*]] = begin_access [read] [unknown] [[Y]]
+  // CHECK:   load [trivial] [[READ]]
+  // CHECK:   function_ref @$S10switch_var1b1xySi_tF
+  // CHECK:   destroy_value [[YADDR]]
+  // CHECK:   dealloc_stack [[TMP]]
+  // CHECK:   destroy_addr [[PAIR_0]] : $*P
+  // CHECK:   dealloc_stack [[PAIR]]
+  // CHECK:   br [[CONT]]
+    b(x: y)
+
+  // CHECK: [[NO_CASE2]]:
+  // CHECK:   destroy_value [[YADDR]]
+  // CHECK:   dealloc_stack [[TMP]]
+  // CHECK:   br [[NEXT:bb[0-9]+]]
+  // CHECK: [[IS_NOT_Y]]:
+  // CHECK:   dealloc_stack [[TMP]]
+  // CHECK:   br [[NEXT]]
+
+  // CHECK: [[NEXT]]:
+  // CHECK:   [[ZADDR:%.*]] = alloc_box ${ var (P, Int) }
+  // CHECK:   [[Z:%.*]] = project_box [[ZADDR]]
+  // CHECK:   [[READ:%.*]] = begin_access [read] [unknown] [[Z]]
+  // CHECK:   tuple_element_addr [[READ]] : {{.*}}, 1
+  // CHECK:   function_ref @$S10switch_var5ansed1xSbSi_tF
+  // CHECK:   cond_br {{%.*}}, [[CASE3:bb[0-9]+]], [[DFLT_NO_CASE3:bb[0-9]+]]
+  case var z where ansed(x: z.1):
+  // CHECK: [[CASE3]]:
+  // CHECK:   [[READ:%.*]] = begin_access [read] [unknown] [[Z]]
+  // CHECK:   tuple_element_addr [[READ]] : {{.*}}, 1
+  // CHECK:   function_ref @$S10switch_var1c1xySi_tF
+  // CHECK:   destroy_value [[ZADDR]]
+  // CHECK-NEXT: dealloc_stack [[PAIR]]
+  // CHECK:   br [[CONT]]
+    c(x: z.1)
+
+  // CHECK: [[DFLT_NO_CASE3]]:
+  // CHECK:   destroy_value [[ZADDR]]
+  // CHECK:   br [[CASE4:bb[0-9]+]]
+  case (_, var w):
+  // CHECK: [[CASE4]]:
+  // CHECK:   [[PAIR_0:%.*]] = tuple_element_addr [[PAIR]] : $*(P, Int), 0
+  // CHECK:   [[WADDR:%.*]] = alloc_box ${ var Int }
+  // CHECK:   [[W:%.*]] = project_box [[WADDR]]
+  // CHECK:   [[READ:%.*]] = begin_access [read] [unknown] [[W]]
+  // CHECK:   load [trivial] [[READ]]
+  // CHECK:   function_ref @$S10switch_var1d1xySi_tF
+  // CHECK:   destroy_value [[WADDR]]
+  // CHECK:   destroy_addr [[PAIR_0]] : $*P
+  // CHECK:   dealloc_stack [[PAIR]]
+  // CHECK:   br [[CONT]]
+    d(x: w)
+  }
+  e()
+}
+
+// CHECK-LABEL: sil hidden @$S10switch_var05test_B2_5yyF : $@convention(thin) () -> () {
+func test_var_5() {
+  // CHECK:   function_ref @$S10switch_var3fooSiyF
+  // CHECK:   function_ref @$S10switch_var3barSiyF
+  switch (foo(), bar()) {
+  // CHECK:   [[XADDR:%.*]] = alloc_box ${ var (Int, Int) }
+  // CHECK:   [[X:%.*]] = project_box [[XADDR]]
+  // CHECK:   cond_br {{%.*}}, [[CASE1:bb[0-9]+]], [[NO_CASE1:bb[0-9]+]]
+  case var x where runced(x: x.0):
+  // CHECK: [[CASE1]]:
+  // CHECK:   br [[CONT:bb[0-9]+]]
+    a()
+  // CHECK: [[NO_CASE1]]:
+  // CHECK:   [[YADDR:%[0-9]+]] = alloc_box ${ var Int }
+  // CHECK:   [[Y:%[0-9]+]] = project_box [[YADDR]]
+  // CHECK:   [[ZADDR:%[0-9]+]] = alloc_box ${ var Int }
+  // CHECK:   [[Z:%[0-9]+]] = project_box [[ZADDR]]
+  // CHECK:   cond_br {{%.*}}, [[CASE2:bb[0-9]+]], [[NO_CASE2:bb[0-9]+]]
+  case (var y, var z) where funged(x: y):
+  // CHECK: [[CASE2]]:
+  // CHECK:   destroy_value [[ZADDR]]
+  // CHECK:   destroy_value [[YADDR]]
+  // CHECK:   br [[CONT]]
+    b()
+  // CHECK: [[NO_CASE2]]:
+  // CHECK:   destroy_value [[ZADDR]]
+  // CHECK:   destroy_value [[YADDR]]
+  // CHECK:   cond_br {{%.*}}, [[CASE3:bb[0-9]+]], [[NO_CASE3:bb[0-9]+]]
+  case (_, _) where runced():
+  // CHECK: [[CASE3]]:
+  // CHECK:   br [[CONT]]
+    c()
+  // CHECK: [[NO_CASE3]]:
+  // CHECK:   br [[CASE4:bb[0-9]+]]
+  case _:
+  // CHECK: [[CASE4]]:
+  // CHECK:   br [[CONT]]
+    d()
+  }
+  // CHECK: [[CONT]]:
+  e()
+}
+
+// CHECK-LABEL: sil hidden @$S10switch_var05test_B7_returnyyF : $@convention(thin) () -> () {
+func test_var_return() {
+  switch (foo(), bar()) {
+  case var x where runced():
+    // CHECK: [[XADDR:%[0-9]+]] = alloc_box ${ var (Int, Int) }
+    // CHECK: [[X:%[0-9]+]] = project_box [[XADDR]]
+    // CHECK: function_ref @$S10switch_var1ayyF
+    // CHECK: destroy_value [[XADDR]]
+    // CHECK: br [[EPILOG:bb[0-9]+]]
+    a()
+    return
+  // CHECK: [[YADDR:%[0-9]+]] = alloc_box ${ var Int }
+  // CHECK: [[Y:%[0-9]+]] = project_box [[YADDR]]
+  // CHECK: [[ZADDR:%[0-9]+]] = alloc_box ${ var Int }
+  // CHECK: [[Z:%[0-9]+]] = project_box [[ZADDR]]
+  case (var y, var z) where funged():
+    // CHECK: function_ref @$S10switch_var1byyF
+    // CHECK: destroy_value [[ZADDR]]
+    // CHECK: destroy_value [[YADDR]]
+    // CHECK: br [[EPILOG]]
+    b()
+    return
+  case var w where ansed():
+    // CHECK: [[WADDR:%[0-9]+]] = alloc_box ${ var (Int, Int) }
+    // CHECK: [[W:%[0-9]+]] = project_box [[WADDR]]
+    // CHECK: function_ref @$S10switch_var1cyyF
+    // CHECK-NOT: destroy_value [[ZADDR]]
+    // CHECK-NOT: destroy_value [[YADDR]]
+    // CHECK: destroy_value [[WADDR]]
+    // CHECK: br [[EPILOG]]
+    c()
+    return
+  case var v:
+    // CHECK: [[VADDR:%[0-9]+]] = alloc_box ${ var (Int, Int) }
+    // CHECK: [[V:%[0-9]+]] = project_box [[VADDR]]
+    // CHECK: function_ref @$S10switch_var1dyyF
+    // CHECK-NOT: destroy_value [[ZADDR]]
+    // CHECK-NOT: destroy_value [[YADDR]]
+    // CHECK: destroy_value [[VADDR]]
+    // CHECK: br [[EPILOG]]
+    d()
+    return
+  }
+}
+
+// When all of the bindings in a column are immutable, don't emit a mutable
+// box. <rdar://problem/15873365>
+// CHECK-LABEL: sil hidden @$S10switch_var8test_letyyF : $@convention(thin) () -> () {
+func test_let() {
+  // CHECK: [[FOOS:%.*]] = function_ref @$S10switch_var4foosSSyF
+  // CHECK: [[VAL:%.*]] = apply [[FOOS]]()
+  // CHECK: [[VAL_COPY:%.*]] = copy_value [[VAL]]
+  // CHECK: function_ref @$S10switch_var6runcedSbyF
+  // CHECK: cond_br {{%.*}}, [[CASE1:bb[0-9]+]], [[NO_CASE1:bb[0-9]+]]
+  switch foos() {
+  case let x where runced():
+  // CHECK: [[CASE1]]:
+  // CHECK:   [[BORROWED_VAL_COPY:%.*]] = begin_borrow [[VAL_COPY]]
+  // CHECK:   [[A:%.*]] = function_ref @$S10switch_var1a1xySS_tF
+  // CHECK:   apply [[A]]([[BORROWED_VAL_COPY]])
+  // CHECK:   destroy_value [[VAL_COPY]]
+  // CHECK:   destroy_value [[VAL]]
+  // CHECK:   br [[CONT:bb[0-9]+]]
+    a(x: x)
+  // CHECK: [[NO_CASE1]]:
+  // CHECK:   destroy_value [[VAL_COPY]]
+  // CHECK:   br [[TRY_CASE2:bb[0-9]+]]
+  // CHECK: [[TRY_CASE2]]:
+  // CHECK:   [[VAL_COPY_2:%.*]] = copy_value [[VAL]]
+  // CHECK:   function_ref @$S10switch_var6fungedSbyF
+  // CHECK:   cond_br {{%.*}}, [[CASE2:bb[0-9]+]], [[NO_CASE2:bb[0-9]+]]
+  case let y where funged():
+  // CHECK: [[CASE2]]:
+  // CHECK:   [[BORROWED_VAL_COPY_2:%.*]] = begin_borrow [[VAL_COPY_2]]
+  // CHECK:   [[B:%.*]] = function_ref @$S10switch_var1b1xySS_tF
+  // CHECK:   apply [[B]]([[BORROWED_VAL_COPY_2]])
+  // CHECK:   destroy_value [[VAL_COPY_2]]
+  // CHECK:   destroy_value [[VAL]]
+  // CHECK:   br [[CONT]]
+    b(x: y)
+  // CHECK: [[NO_CASE2]]:
+  // CHECK:   destroy_value [[VAL_COPY_2]]
+  // CHECK:   br [[NEXT_CASE:bb6]]
+
+  // CHECK: [[NEXT_CASE]]:
+  // CHECK:   [[VAL_COPY_3:%.*]] = copy_value [[VAL]]
+  // CHECK:   function_ref @$S10switch_var4barsSSyF
+  // CHECK:   [[BORROWED_VAL_COPY_3:%.*]] = begin_borrow [[VAL_COPY_3]]
+  // CHECK:   store_borrow [[BORROWED_VAL_COPY_3]] to [[IN_ARG:%.*]] :
+  // CHECK:   apply {{%.*}}<String>({{.*}}, [[IN_ARG]])
+  // CHECK:   cond_br {{%.*}}, [[YES_CASE3:bb[0-9]+]], [[NO_CASE3:bb[0-9]+]]
+  // ExprPatterns implicitly contain a 'let' binding.
+  case bars():
+  // CHECK: [[YES_CASE3]]:
+  // CHECK:   destroy_value [[VAL_COPY_3]]
+  // CHECK:   destroy_value [[VAL]]
+  // CHECK:   function_ref @$S10switch_var1cyyF
+  // CHECK:   br [[CONT]]
+    c()
+  // CHECK: [[NO_CASE3]]:
+  // CHECK:   destroy_value [[VAL_COPY_3]]
+  // CHECK:   br [[NEXT_CASE:bb9+]]
+
+  // CHECK: [[NEXT_CASE]]:
+  case _:
+    // CHECK:   destroy_value [[VAL]]
+    // CHECK:   function_ref @$S10switch_var1dyyF
+    // CHECK:   br [[CONT]]
+    d()
+  }
+  // CHECK: [[CONT]]:
+  // CHECK:   return
+}
+// CHECK: } // end sil function '$S10switch_var8test_letyyF'
+
+// If one of the bindings is a "var", allocate a box for the column.
+// CHECK-LABEL: sil hidden @$S10switch_var015test_mixed_let_B0yyF : $@convention(thin) () -> () {
+func test_mixed_let_var() {
+  // CHECK: bb0:
+  // CHECK:   [[FOOS:%.*]] = function_ref @$S10switch_var4foosSSyF
+  // CHECK:   [[VAL:%.*]] = apply [[FOOS]]()
+  switch foos() {
+
+  // First pattern.
+  // CHECK:   [[BOX:%.*]] = alloc_box ${ var String }, var, name "x"
+  // CHECK:   [[PBOX:%.*]] = project_box [[BOX]]
+  // CHECK:   [[VAL_COPY:%.*]] = copy_value [[VAL]]
+  // CHECK:   store [[VAL_COPY]] to [init] [[PBOX]]
+  // CHECK:   cond_br {{.*}}, [[CASE1:bb[0-9]+]], [[NOCASE1:bb[0-9]+]]
+  case var x where runced():
+  // CHECK: [[CASE1]]:
+  // CHECK:   [[READ:%.*]] = begin_access [read] [unknown] [[PBOX]]
+  // CHECK:   [[X:%.*]] = load [copy] [[READ]]
+  // CHECK:   [[A:%.*]] = function_ref @$S10switch_var1a1xySS_tF
+  // CHECK:   apply [[A]]([[X]])
+  // CHECK:   destroy_value [[BOX]]
+  // CHECK:   br [[CONT:bb[0-9]+]]
+    a(x: x)
+
+  // CHECK: [[NOCASE1]]:
+  // CHECK:   destroy_value [[BOX]]
+  // CHECK:   br [[NEXT_PATTERN:bb[0-9]+]]
+
+  // CHECK: [[NEXT_PATTERN]]:
+  // CHECK:   [[VAL_COPY:%.*]] = copy_value [[VAL]]
+  // CHECK:   cond_br {{.*}}, [[CASE2:bb[0-9]+]], [[NOCASE2:bb[0-9]+]]
+  case let y where funged():
+
+  // CHECK: [[CASE2]]:
+  // CHECK:   [[BORROWED_VAL_COPY:%.*]] = begin_borrow [[VAL_COPY]]
+  // CHECK:   [[B:%.*]] = function_ref @$S10switch_var1b1xySS_tF
+  // CHECK:   apply [[B]]([[BORROWED_VAL_COPY]])
+  // CHECK:   end_borrow [[BORROWED_VAL_COPY]] from [[VAL_COPY]]
+  // CHECK:   destroy_value [[VAL_COPY]]
+  // CHECK:   destroy_value [[VAL]]
+  // CHECK:   br [[CONT]]  
+  b(x: y)
+
+  // CHECK: [[NOCASE2]]:
+  // CHECK:   destroy_value [[VAL_COPY]]
+  // CHECK:   br [[NEXT_CASE:bb[0-9]+]]
+
+  // CHECK: [[NEXT_CASE]]
+  // CHECK:   [[VAL_COPY:%.*]] = copy_value [[VAL]]
+  // CHECK:   [[BORROWED_VAL_COPY:%.*]] = begin_borrow [[VAL_COPY]]
+  // CHECK:   store_borrow [[BORROWED_VAL_COPY]] to [[TMP_VAL_COPY_ADDR:%.*]] :
+  // CHECK:   apply {{.*}}<String>({{.*}}, [[TMP_VAL_COPY_ADDR]])
+  // CHECK:   cond_br {{.*}}, [[CASE3:bb[0-9]+]], [[NOCASE3:bb[0-9]+]]
+  case bars():
+  // CHECK: [[CASE3]]:
+  // CHECK:   destroy_value [[VAL_COPY]]
+  // CHECK:   destroy_value [[VAL]]
+  // CHECK:   [[FUNC:%.*]] = function_ref @$S10switch_var1cyyF : $@convention(thin) () -> ()
+  // CHECK:   apply [[FUNC]]()
+  // CHECK:   br [[CONT]]
+    c()
+
+  // CHECK: [[NOCASE3]]:
+  // CHECK:   destroy_value [[VAL_COPY]]
+  // CHECK:   br [[NEXT_CASE:bb[0-9]+]]
+
+  // CHECK: [[NEXT_CASE]]:
+  // CHECK:   destroy_value [[VAL]]
+  // CHECK:   [[D_FUNC:%.*]] = function_ref @$S10switch_var1dyyF : $@convention(thin) () -> ()
+  // CHECK:   apply [[D_FUNC]]()
+  // CHECK:   br [[CONT]]
+  case _:
+    d()
+  }
+
+  // CHECK: [[CONT]]:
+  // CHECK:   return
+}
+// CHECK: } // end sil function '$S10switch_var015test_mixed_let_B0yyF'
+
+// CHECK-LABEL: sil hidden @$S10switch_var23test_multiple_patterns1yyF : $@convention(thin) () -> () {
+func test_multiple_patterns1() {
+  // CHECK:   function_ref @$S10switch_var6foobarSi_SityF
+  switch foobar() {
+  // CHECK-NOT: br bb
+  case (0, let x), (let x, 0):
+    // CHECK:   cond_br {{%.*}}, [[FIRST_MATCH_CASE:bb[0-9]+]], [[FIRST_FAIL:bb[0-9]+]]
+    // CHECK:   [[FIRST_MATCH_CASE]]:
+    // CHECK:     debug_value [[FIRST_X:%.*]] :
+    // CHECK:     br [[CASE_BODY:bb[0-9]+]]([[FIRST_X]] : $Int)
+    // CHECK:   [[FIRST_FAIL]]:
+    // CHECK:     cond_br {{%.*}}, [[SECOND_MATCH_CASE:bb[0-9]+]], [[SECOND_FAIL:bb[0-9]+]]
+    // CHECK:   [[SECOND_MATCH_CASE]]:
+    // CHECK:     debug_value [[SECOND_X:%.*]] :
+    // CHECK:     br [[CASE_BODY]]([[SECOND_X]] : $Int)
+    // CHECK:   [[CASE_BODY]]([[BODY_VAR:%.*]] : $Int):
+    // CHECK:     [[A:%.*]] = function_ref @$S10switch_var1a1xySi_tF
+    // CHECK:     apply [[A]]([[BODY_VAR]])
+    a(x: x)
+  default:
+    // CHECK:   [[SECOND_FAIL]]:
+    // CHECK:     function_ref @$S10switch_var1byyF
+    b()
+  }
+}
+
+// FIXME(integers): the following checks should be updated for the new integer
+// protocols. <rdar://problem/29939484>
+// XCHECK-LABEL: sil hidden @$S10switch_var23test_multiple_patterns2yyF : $@convention(thin) () -> () {
+func test_multiple_patterns2() {
+  let t1 = 2
+  let t2 = 4
+  // XCHECK:   debug_value [[T1:%.*]] :
+  // XCHECK:   debug_value [[T2:%.*]] :
+  switch (0,0) {
+    // XCHECK-NOT: br bb
+  case (_, let x) where x > t1, (let x, _) where x > t2:
+    // XCHECK:   [[FIRST_X:%.*]] = tuple_extract {{%.*}} : $(Int, Int), 1
+    // XCHECK:   debug_value [[FIRST_X]] :
+    // XCHECK:   apply {{%.*}}([[FIRST_X]], [[T1]])
+    // XCHECK:   cond_br {{%.*}}, [[FIRST_MATCH_CASE:bb[0-9]+]], [[FIRST_FAIL:bb[0-9]+]]
+    // XCHECK:   [[FIRST_MATCH_CASE]]:
+    // XCHECK:     br [[CASE_BODY:bb[0-9]+]]([[FIRST_X]] : $Int)
+    // XCHECK:   [[FIRST_FAIL]]:
+    // XCHECK:     debug_value [[SECOND_X:%.*]] :
+    // XCHECK:     apply {{%.*}}([[SECOND_X]], [[T2]])
+    // XCHECK:     cond_br {{%.*}}, [[SECOND_MATCH_CASE:bb[0-9]+]], [[SECOND_FAIL:bb[0-9]+]]
+    // XCHECK:   [[SECOND_MATCH_CASE]]:
+    // XCHECK:     br [[CASE_BODY]]([[SECOND_X]] : $Int)
+    // XCHECK:   [[CASE_BODY]]([[BODY_VAR:%.*]] : $Int):
+    // XCHECK:     [[A:%.*]] = function_ref @$S10switch_var1aySi1x_tF
+    // XCHECK:     apply [[A]]([[BODY_VAR]])
+    a(x: x)
+  default:
+    // XCHECK:   [[SECOND_FAIL]]:
+    // XCHECK:     function_ref @$S10switch_var1byyF
+    b()
+  }
+}
+
+enum Foo {
+  case A(Int, Double)
+  case B(Double, Int)
+  case C(Int, Int, Double)
+}
+
+// CHECK-LABEL: sil hidden @$S10switch_var23test_multiple_patterns3yyF : $@convention(thin) () -> () {
+func test_multiple_patterns3() {
+  let f = Foo.C(0, 1, 2.0)
+  switch f {
+    // CHECK:   switch_enum {{%.*}} : $Foo, case #Foo.A!enumelt.1: [[A:bb[0-9]+]], case #Foo.B!enumelt.1: [[B:bb[0-9]+]], case #Foo.C!enumelt.1: [[C:bb[0-9]+]]
+  case .A(let x, let n), .B(let n, let x), .C(_, let x, let n):
+    // CHECK:   [[A]]({{%.*}} : $(Int, Double)):
+    // CHECK:     [[A_X:%.*]] = tuple_extract
+    // CHECK:     [[A_N:%.*]] = tuple_extract
+    // CHECK:     br [[CASE_BODY:bb[0-9]+]]([[A_X]] : $Int, [[A_N]] : $Double)
+    
+    // CHECK:   [[B]]({{%.*}} : $(Double, Int)):
+    // CHECK:     [[B_N:%.*]] = tuple_extract
+    // CHECK:     [[B_X:%.*]] = tuple_extract
+    // CHECK:     br [[CASE_BODY]]([[B_X]] : $Int, [[B_N]] : $Double)
+
+    // CHECK:   [[C]]({{%.*}} : $(Int, Int, Double)):
+    // CHECK:     [[C__:%.*]] = tuple_extract
+    // CHECK:     [[C_X:%.*]] = tuple_extract
+    // CHECK:     [[C_N:%.*]] = tuple_extract
+    // CHECK:     br [[CASE_BODY]]([[C_X]] : $Int, [[C_N]] : $Double)
+
+    // CHECK:   [[CASE_BODY]]([[BODY_X:%.*]] : $Int, [[BODY_N:%.*]] : $Double):
+    // CHECK:     [[FUNC_A:%.*]] = function_ref @$S10switch_var1a1xySi_tF
+    // CHECK:     apply [[FUNC_A]]([[BODY_X]])
+    a(x: x)
+  }
+}
+
+enum Bar {
+  case Y(Foo, Int)
+  case Z(Int, Foo)
+}
+
+// CHECK-LABEL: sil hidden @$S10switch_var23test_multiple_patterns4yyF : $@convention(thin) () -> () {
+func test_multiple_patterns4() {
+  let b = Bar.Y(.C(0, 1, 2.0), 3)
+  switch b {
+    // CHECK:   switch_enum {{%.*}} : $Bar, case #Bar.Y!enumelt.1: [[Y:bb[0-9]+]], case #Bar.Z!enumelt.1: [[Z:bb[0-9]+]]
+  case .Y(.A(let x, _), _), .Y(.B(_, let x), _), .Y(.C, let x), .Z(let x, _):
+    // CHECK:   [[Y]]({{%.*}} : $(Foo, Int)):
+    // CHECK:     [[Y_F:%.*]] = tuple_extract
+    // CHECK:     [[Y_X:%.*]] = tuple_extract
+    // CHECK:     switch_enum [[Y_F]] : $Foo, case #Foo.A!enumelt.1: [[A:bb[0-9]+]], case #Foo.B!enumelt.1: [[B:bb[0-9]+]], case #Foo.C!enumelt.1: [[C:bb[0-9]+]]
+    
+    // CHECK:   [[A]]({{%.*}} : $(Int, Double)):
+    // CHECK:     [[A_X:%.*]] = tuple_extract
+    // CHECK:     [[A_N:%.*]] = tuple_extract
+    // CHECK:     br [[CASE_BODY:bb[0-9]+]]([[A_X]] : $Int)
+    
+    // CHECK:   [[B]]({{%.*}} : $(Double, Int)):
+    // CHECK:     [[B_N:%.*]] = tuple_extract
+    // CHECK:     [[B_X:%.*]] = tuple_extract
+    // CHECK:     br [[CASE_BODY]]([[B_X]] : $Int)
+    
+    // CHECK:   [[C]]({{%.*}} : $(Int, Int, Double)):
+    // CHECK:     br [[CASE_BODY]]([[Y_X]] : $Int)
+
+    // CHECK:   [[Z]]({{%.*}} : $(Int, Foo)):
+    // CHECK:     [[Z_X:%.*]] = tuple_extract
+    // CHECK:     [[Z_F:%.*]] = tuple_extract
+    // CHECK:     br [[CASE_BODY]]([[Z_X]] : $Int)
+
+    // CHECK:   [[CASE_BODY]]([[BODY_X:%.*]] : $Int):
+    // CHECK:     [[FUNC_A:%.*]] = function_ref @$S10switch_var1a1xySi_tF
+    // CHECK:     apply [[FUNC_A]]([[BODY_X]])
+    a(x: x)
+  }
+}
+
+func aaa(x x: inout Int) {}
+
+// CHECK-LABEL: sil hidden @$S10switch_var23test_multiple_patterns5yyF : $@convention(thin) () -> () {
+func test_multiple_patterns5() {
+  let b = Bar.Y(.C(0, 1, 2.0), 3)
+  switch b {
+    // CHECK:   switch_enum {{%.*}} : $Bar, case #Bar.Y!enumelt.1: [[Y:bb[0-9]+]], case #Bar.Z!enumelt.1: [[Z:bb[0-9]+]]
+  case .Y(.A(var x, _), _), .Y(.B(_, var x), _), .Y(.C, var x), .Z(var x, _):
+    // CHECK:   [[Y]]({{%.*}} : $(Foo, Int)):
+    // CHECK:     [[Y_F:%.*]] = tuple_extract
+    // CHECK:     [[Y_X:%.*]] = tuple_extract
+    // CHECK:     switch_enum [[Y_F]] : $Foo, case #Foo.A!enumelt.1: [[A:bb[0-9]+]], case #Foo.B!enumelt.1: [[B:bb[0-9]+]], case #Foo.C!enumelt.1: [[C:bb[0-9]+]]
+    
+    // CHECK:   [[A]]({{%.*}} : $(Int, Double)):
+    // CHECK:     [[A_X:%.*]] = tuple_extract
+    // CHECK:     [[A_N:%.*]] = tuple_extract
+    // CHECK:     br [[CASE_BODY:bb[0-9]+]]([[A_X]] : $Int)
+    
+    // CHECK:   [[B]]({{%.*}} : $(Double, Int)):
+    // CHECK:     [[B_N:%.*]] = tuple_extract
+    // CHECK:     [[B_X:%.*]] = tuple_extract
+    // CHECK:     br [[CASE_BODY]]([[B_X]] : $Int)
+    
+    // CHECK:   [[C]]({{%.*}} : $(Int, Int, Double)):
+    // CHECK:     br [[CASE_BODY]]([[Y_X]] : $Int)
+    
+    // CHECK:   [[Z]]({{%.*}} : $(Int, Foo)):
+    // CHECK:     [[Z_X:%.*]] = tuple_extract
+    // CHECK:     [[Z_F:%.*]] = tuple_extract
+    // CHECK:     br [[CASE_BODY]]([[Z_X]] : $Int)
+    
+    // CHECK:   [[CASE_BODY]]([[BODY_X:%.*]] : $Int):
+    // CHECK:     store [[BODY_X]] to [trivial] [[BOX_X:%.*]] : $*Int
+    // CHECK:     [[WRITE:%.*]] = begin_access [modify] [unknown] [[BOX_X]]
+    // CHECK:     [[FUNC_AAA:%.*]] = function_ref @$S10switch_var3aaa1xySiz_tF
+    // CHECK:     apply [[FUNC_AAA]]([[WRITE]])
+    aaa(x: &x)
+  }
+}
+
+// rdar://problem/29252758 -- local decls must not be reemitted.
+func test_against_reemission(x: Bar) {
+  switch x {
+  case .Y(let a, _), .Z(_, let a):
+    let b = a
+  }
+}
+
+class C    {}
+class D: C {}
+func f(_: D) -> Bool { return true }
+
+// CHECK-LABEL: sil hidden @{{.*}}test_multiple_patterns_value_semantics
+func test_multiple_patterns_value_semantics(_ y: C) {
+  switch y {
+    // CHECK:   checked_cast_br {{%.*}} : $C to $D, [[AS_D:bb[0-9]+]], [[NOT_AS_D:bb[0-9]+]]
+    // CHECK: [[AS_D]]({{.*}}):
+    // CHECK:   cond_br {{%.*}}, [[F_TRUE:bb[0-9]+]], [[F_FALSE:bb[0-9]+]]
+    // CHECK: [[F_TRUE]]:
+    // CHECK:   [[BINDING:%.*]] = copy_value [[ORIG:%.*]] :
+    // CHECK:   destroy_value [[ORIG]]
+    // CHECK:   br {{bb[0-9]+}}([[BINDING]]
+    case let x as D where f(x), let x as D: break
+    default: break
+  }
+}
diff --git a/test/SILGen/plus_zero_testable-multifile-other.swift b/test/SILGen/plus_zero_testable-multifile-other.swift
new file mode 100644
index 0000000..b517849
--- /dev/null
+++ b/test/SILGen/plus_zero_testable-multifile-other.swift
@@ -0,0 +1,45 @@
+// REQUIRES: plus_zero_runtime
+// This test is paired with testable-multifile.swift.
+
+// RUN: %empty-directory(%t)
+// RUN: %target-swift-frontend -emit-module %S/Inputs/TestableMultifileHelper.swift -enable-testing -o %t
+
+// RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership -I %t %s %S/testable-multifile.swift -module-name main | %FileCheck %s
+// RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership -I %t %S/testable-multifile.swift %s -module-name main | %FileCheck %s
+// RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership -I %t -primary-file %s %S/testable-multifile.swift -module-name main | %FileCheck %s
+
+// Just make sure we don't crash later on.
+// RUN: %target-swift-frontend -emit-ir -enable-sil-ownership -I %t -primary-file %s %S/testable-multifile.swift -module-name main -o /dev/null
+// RUN: %target-swift-frontend -emit-ir -enable-sil-ownership -I %t -O -primary-file %s %S/testable-multifile.swift -module-name main -o /dev/null
+
+func use<F: Fooable>(_ f: F) { f.foo() }
+func test(internalFoo: FooImpl, publicFoo: PublicFooImpl) {
+  use(internalFoo)
+  use(publicFoo)
+
+  internalFoo.foo()
+  publicFoo.foo()
+}
+
+// CHECK-LABEL: sil hidden @$S4main4test11internalFoo06publicD0yAA0D4ImplV_AA06PublicdF0VtF
+// CHECK: [[USE_1:%.+]] = function_ref @$S4main3useyyxAA7FooableRzlF
+// CHECK: = apply [[USE_1]]<FooImpl>({{%.+}}) : $@convention(thin) <τ_0_0 where τ_0_0 : Fooable> (@in_guaranteed τ_0_0) -> ()
+// CHECK: [[USE_2:%.+]] = function_ref @$S4main3useyyxAA7FooableRzlF
+// CHECK: = apply [[USE_2]]<PublicFooImpl>({{%.+}}) : $@convention(thin) <τ_0_0 where τ_0_0 : Fooable> (@in_guaranteed τ_0_0) -> ()
+// CHECK: [[IMPL_1:%.+]] = function_ref @$S23TestableMultifileHelper13HasDefaultFooPAAE3fooyyF
+// CHECK: = apply [[IMPL_1]]<FooImpl>({{%.+}}) : $@convention(method) <τ_0_0 where τ_0_0 : HasDefaultFoo> (@in_guaranteed τ_0_0) -> ()
+// CHECK: [[IMPL_2:%.+]] = function_ref @$S23TestableMultifileHelper13HasDefaultFooPAAE3fooyyF
+// CHECK: = apply [[IMPL_2]]<PublicFooImpl>({{%.+}}) : $@convention(method) <τ_0_0 where τ_0_0 : HasDefaultFoo> (@in_guaranteed τ_0_0) -> ()
+// CHECK: } // end sil function '$S4main4test11internalFoo06publicD0yAA0D4ImplV_AA06PublicdF0VtF'
+
+func test(internalSub: Sub, publicSub: PublicSub) {
+  internalSub.foo()
+  publicSub.foo()
+}
+
+// CHECK-LABEL: sil hidden @$S4main4test11internalSub06publicD0yAA0D0C_AA06PublicD0CtF
+// CHECK: bb0([[ARG0:%.*]] : @guaranteed $Sub, [[ARG1:%.*]] : @guaranteed $PublicSub):
+// CHECK: = class_method [[ARG0]] : $Sub, #Sub.foo!1
+// CHECK: = class_method [[ARG1]] : $PublicSub, #PublicSub.foo!1
+// CHECK: } // end sil function '$S4main4test11internalSub06publicD0yAA0D0C_AA06PublicD0CtF'
+
diff --git a/test/SILGen/plus_zero_tuples.swift b/test/SILGen/plus_zero_tuples.swift
new file mode 100644
index 0000000..c0e0a3d
--- /dev/null
+++ b/test/SILGen/plus_zero_tuples.swift
@@ -0,0 +1,166 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership %s | %FileCheck %s
+class C {}
+
+enum Foo {
+  case X(C, Int)
+}
+
+// <rdar://problem/16020428>
+// CHECK-LABEL: sil hidden @$S6tuples8matchFoo1xyAA0C0O_tF
+func matchFoo(x x: Foo) {
+  switch x {
+  case .X(let x):
+    ()
+  }
+}
+
+protocol P { func foo() }
+struct A : P { func foo() {} }
+
+func make_int() -> Int { return 0 }
+func make_p() -> P { return A() }
+func make_xy() -> (x: Int, y: P) { return (make_int(), make_p()) }
+
+// CHECK-LABEL: sil hidden @$S6tuples17testShuffleOpaqueyyF
+func testShuffleOpaque() {
+  // CHECK: [[X:%.*]] = alloc_box ${ var P }
+  // CHECK-NEXT: [[PBX:%.*]] = project_box [[X]]
+  // CHECK: [[Y:%.*]] = alloc_box ${ var Int }
+  // CHECK-NEXT: [[PBY:%.*]] = project_box [[Y]]
+
+  // CHECK:      [[T0:%.*]] = function_ref @$S6tuples7make_xySi1x_AA1P_p1ytyF
+  // CHECK-NEXT: [[T1:%.*]] = apply [[T0]]([[PBX]])
+  // CHECK-NEXT: store [[T1]] to [trivial] [[PBY]]
+  var (x,y) : (y:P, x:Int) = make_xy()
+
+  // CHECK-NEXT: [[PAIR:%.*]] = alloc_box ${ var (y: P, x: Int) }
+  // CHECK-NEXT: [[PBPAIR:%.*]] = project_box [[PAIR]]
+  // CHECK-NEXT: [[PAIR_0:%.*]] = tuple_element_addr [[PBPAIR]] : $*(y: P, x: Int), 0
+  // CHECK-NEXT: [[PAIR_1:%.*]] = tuple_element_addr [[PBPAIR]] : $*(y: P, x: Int), 1
+  // CHECK-NEXT: // function_ref
+  // CHECK-NEXT: [[T0:%.*]] = function_ref @$S6tuples7make_xySi1x_AA1P_p1ytyF
+  // CHECK-NEXT: [[T1:%.*]] = apply [[T0]]([[PAIR_0]])
+  // CHECK-NEXT: store [[T1]] to [trivial] [[PAIR_1]]
+  var pair : (y:P, x:Int) = make_xy()
+
+  // CHECK-NEXT: [[TEMP:%.*]] = alloc_stack $P
+  // CHECK-NEXT: // function_ref
+  // CHECK-NEXT: [[T0:%.*]] = function_ref @$S6tuples7make_xySi1x_AA1P_p1ytyF
+  // CHECK-NEXT: [[T1:%.*]] = apply [[T0]]([[TEMP]])
+  // CHECK-NEXT: [[WRITE:%.*]] = begin_access [modify] [unknown] [[PBPAIR]] : $*(y: P, x: Int)
+  // CHECK-NEXT: [[PAIR_0:%.*]] = tuple_element_addr [[WRITE]] : $*(y: P, x: Int), 0
+  // CHECK-NEXT: copy_addr [take] [[TEMP]] to [[PAIR_0]]
+  // CHECK-NEXT: [[PAIR_1:%.*]] = tuple_element_addr [[WRITE]] : $*(y: P, x: Int), 1
+  // CHECK-NEXT: assign [[T1]] to [[PAIR_1]]
+  // CHECK-NEXT: end_access [[WRITE]] : $*(y: P, x: Int)
+  // CHECK-NEXT: dealloc_stack [[TEMP]]
+  pair = make_xy()
+}
+
+// CHECK-LABEL: testShuffleTuple
+func testShuffleTuple() {
+  // CHECK: [[X:%.*]] = alloc_box ${ var P }
+  // CHECK-NEXT: [[PBX:%.*]] = project_box [[X]]
+  // CHECK: [[Y:%.*]] = alloc_box ${ var Int }
+  // CHECK-NEXT: [[PBY:%.*]] = project_box [[Y]]
+
+  // CHECK:      [[T0:%.*]] = function_ref @$S6tuples8make_intSiyF
+  // CHECK-NEXT: [[T1:%.*]] = apply [[T0]]()
+  // CHECK-NEXT: store [[T1]] to [trivial] [[PBY]]
+  // CHECK-NEXT: // function_ref
+  // CHECK-NEXT: [[T0:%.*]] = function_ref @$S6tuples6make_pAA1P_pyF 
+  // CHECK-NEXT: apply [[T0]]([[PBX]])
+  var (x,y) : (y:P, x:Int) = (x: make_int(), y: make_p())
+
+  // CHECK-NEXT: [[PAIR:%.*]] = alloc_box ${ var (y: P, x: Int) }
+  // CHECK-NEXT: [[PBPAIR:%.*]] = project_box [[PAIR]]
+  // CHECK-NEXT: [[PAIR_0:%.*]] = tuple_element_addr [[PBPAIR]] : $*(y: P, x: Int), 0
+  // CHECK-NEXT: [[PAIR_1:%.*]] = tuple_element_addr [[PBPAIR]] : $*(y: P, x: Int), 1
+  // CHECK-NEXT: // function_ref
+  // CHECK:      [[T0:%.*]] = function_ref @$S6tuples8make_intSiyF
+  // CHECK-NEXT: [[T1:%.*]] = apply [[T0]]()
+  // CHECK-NEXT: store [[T1]] to [trivial] [[PAIR_1]]
+  // CHECK-NEXT: // function_ref
+  // CHECK-NEXT: [[T0:%.*]] = function_ref @$S6tuples6make_pAA1P_pyF 
+    // CHECK-NEXT: apply [[T0]]([[PAIR_0]])
+  var pair : (y:P, x:Int) = (x: make_int(), y: make_p())
+
+  //   This isn't really optimal; we should be evaluating make_p directly
+  //   into the temporary.
+  // CHECK-NEXT: // function_ref
+  // CHECK:      [[T0:%.*]] = function_ref @$S6tuples8make_intSiyF
+  // CHECK-NEXT: [[INT:%.*]] = apply [[T0]]()
+  // CHECK-NEXT: [[TEMP:%.*]] = alloc_stack $P
+  // CHECK-NEXT: // function_ref
+  // CHECK-NEXT: [[T0:%.*]] = function_ref @$S6tuples6make_pAA1P_pyF 
+  // CHECK-NEXT: apply [[T0]]([[TEMP]])
+  // CHECK-NEXT: [[WRITE:%.*]] = begin_access [modify] [unknown] [[PBPAIR]] : $*(y: P, x: Int)
+  // CHECK-NEXT: [[PAIR_0:%.*]] = tuple_element_addr [[WRITE]] : $*(y: P, x: Int), 0
+  // CHECK-NEXT: copy_addr [take] [[TEMP]] to [[PAIR_0]]
+  // CHECK-NEXT: [[PAIR_1:%.*]] = tuple_element_addr [[WRITE]] : $*(y: P, x: Int), 1
+  // CHECK-NEXT: assign [[INT]] to [[PAIR_1]]
+  // CHECK-NEXT: end_access [[WRITE]] : $*(y: P, x: Int)
+  // CHECK-NEXT: dealloc_stack [[TEMP]]
+  pair = (x: make_int(), y: make_p())
+}
+
+enum GenericEnum<T> {
+  case one(T)
+
+  static var callback: (T) -> Void { fatalError() }
+}
+
+// CHECK-LABEL: $S6tuples16testTupleUnsplatyyF
+func testTupleUnsplat() {
+  // CHECK: debug_value [[X:%.+]] : $Int, let, name "x"
+  // CHECK: debug_value [[Y:%.+]] : $Int, let, name "y"
+  let x = 1, y = 2
+
+  // CHECK: [[TUPLE:%.+]] = tuple ([[X]] : $Int, [[Y]] : $Int)
+  // CHECK: enum $GenericEnum<(Int, Int)>, #GenericEnum.one!enumelt.1, [[TUPLE]]
+  _ = GenericEnum<(Int, Int)>.one((x, y))
+  // CHECK: [[TUPLE:%.+]] = tuple ([[X]] : $Int, [[Y]] : $Int)
+  // CHECK: enum $GenericEnum<(Int, Int)>, #GenericEnum.one!enumelt.1, [[TUPLE]]
+  _ = GenericEnum<(Int, Int)>.one(x, y)
+
+  // CHECK: [[THUNK:%.+]] = function_ref @$SSi_SitIegn_S2iIegyy_TR
+  // CHECK: [[REABSTRACTED:%.+]] = partial_apply [callee_guaranteed] [[THUNK]]({{%.+}})
+  // CHECK: [[BORROW:%.*]] = begin_borrow [[REABSTRACTED]]
+  // CHECK: apply [[BORROW]]([[X]], [[Y]])
+  _ = GenericEnum<(Int, Int)>.callback((x, y))
+  // CHECK: [[THUNK:%.+]] = function_ref @$SSi_SitIegn_S2iIegyy_TR
+  // CHECK: [[REABSTRACTED:%.+]] = partial_apply [callee_guaranteed] [[THUNK]]({{%.+}})
+  // CHECK: [[BORROW:%.*]] = begin_borrow [[REABSTRACTED]]
+  // CHECK: apply [[BORROW]]([[X]], [[Y]])
+  _ = GenericEnum<(Int, Int)>.callback(x, y)
+} // CHECK: end sil function '$S6tuples16testTupleUnsplatyyF'
+
+// Make sure that we use a load_borrow instead of a load [take] when RValues are
+// formed with isGuaranteed set.
+extension P {
+  // CHECK-LABEL: sil hidden @$S6tuples1PPAAE12immutableUse5tupleyAA1CC5index_x5valuet_tFZ
+  // CHECK: bb0([[TUP0:%.*]] : @guaranteed $C, [[TUP1:%.*]] : @trivial $*Self
+  // Allocate space for the RValue.
+  // CHECK:   [[RVALUE:%.*]] = alloc_stack $(index: C, value: Self), let, name "tuple"
+  //
+  // Initialize the RValue. (This is here to help pattern matching).
+  // CHECK:   [[ZERO_ADDR:%.*]] = tuple_element_addr [[RVALUE]] : $*(index: C, value: Self), 0
+  // CHECK:   [[TUP0_COPY:%.*]] = copy_value [[TUP0]]
+  // CHECK:   store [[TUP0_COPY]] to [init] [[ZERO_ADDR]]
+  // CHECK:   [[ONE_ADDR:%.*]] = tuple_element_addr [[RVALUE]] : $*(index: C, value: Self), 1
+  // CHECK:   copy_addr [[TUP1]] to [initialization] [[ONE_ADDR]]
+  //
+  // What we are actually trying to check. Note that there is no actual use of
+  // LOADED_CLASS. This is b/c of the nature of the RValue we are working with.
+  // CHECK:   [[ZERO_ADDR:%.*]] = tuple_element_addr [[RVALUE]] : $*(index: C, value: Self), 0
+  // CHECK:   [[LOADED_CLASS:%.*]] = load_borrow [[ZERO_ADDR]]
+  // CHECK:   [[ONE_ADDR:%.*]] = tuple_element_addr [[RVALUE]] : $*(index: C, value: Self), 1
+  // CHECK:   apply {{.*}}([[ONE_ADDR]]) : $@convention(witness_method: P)
+  // CHECK:   end_borrow [[LOADED_CLASS]] from [[ZERO_ADDR]]
+  // CHECK:   destroy_addr [[RVALUE]]
+  // CHECK:   dealloc_stack [[RVALUE]]
+  public static func immutableUse(tuple: (index: C, value: Self)) -> () {
+    return tuple.value.foo()
+  }
+}
diff --git a/test/SILGen/plus_zero_types.swift b/test/SILGen/plus_zero_types.swift
new file mode 100644
index 0000000..ff5aae4
--- /dev/null
+++ b/test/SILGen/plus_zero_types.swift
@@ -0,0 +1,105 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -parse-as-library -emit-silgen -enable-sil-ownership %s | %FileCheck %s
+
+class C {
+  var member: Int = 0
+
+  // Methods have method calling convention.
+  // CHECK-LABEL: sil hidden @$S5types1CC3foo1xySi_tF : $@convention(method) (Int, @guaranteed C) -> () {
+  func foo(x x: Int) {
+    // CHECK: bb0([[X:%[0-9]+]] : @trivial $Int, [[THIS:%[0-9]+]] : @guaranteed $C):
+    member = x
+
+    // CHECK-NOT: copy_value
+    // CHECK: [[FN:%[0-9]+]] = class_method %1 : $C, #C.member!setter.1
+    // CHECK: apply [[FN]](%0, %1) : $@convention(method) (Int, @guaranteed C) -> ()
+    // CHECK-NOT: destroy_value
+  }
+  // CHECK: } // end sil function '$S5types1CC3foo1xySi_tF'
+}
+
+struct S {
+  var member: Int
+
+  // CHECK-LABEL: sil hidden @{{.*}}1SV3foo{{.*}} : $@convention(method) (Int, @inout S) -> ()
+  mutating
+  func foo(x x: Int) {
+    var x = x
+    // CHECK: bb0([[X:%[0-9]+]] : @trivial $Int, [[THIS:%[0-9]+]] : @trivial $*S):
+    member = x
+    // CHECK: [[XBOX:%[0-9]+]] = alloc_box ${ var Int }
+    // CHECK: [[XADDR:%[0-9]+]] = project_box [[XBOX]]
+    // CHECK: [[READ:%.*]] = begin_access [read] [unknown] [[XADDR]] : $*Int
+    // CHECK: [[X:%.*]] = load [trivial] [[READ]] : $*Int
+    // CHECK: [[WRITE:%.*]] = begin_access [modify] [unknown] [[THIS]] : $*S
+    // CHECK: [[MEMBER:%[0-9]+]] = struct_element_addr [[WRITE]] : $*S, #S.member
+    // CHECK: assign [[X]] to [[MEMBER]] : $*Int
+  }
+
+  class SC {
+    // CHECK-LABEL: sil hidden @$S5types1SV2SCC3bar{{.*}}
+    func bar() {}
+  }
+}
+
+func f() {
+  class FC {
+    func zim() {}
+  }
+}
+
+func g(b b : Bool) {
+  if (b) {
+    class FC {
+      func zim() {}
+    }
+  } else {
+    class FC {
+      func zim() {}
+    }
+  }
+}
+
+struct ReferencedFromFunctionStruct {
+  let f: (ReferencedFromFunctionStruct) -> () = {x in ()}
+  let g: (ReferencedFromFunctionEnum) -> () = {x in ()}
+}
+
+enum ReferencedFromFunctionEnum {
+  case f((ReferencedFromFunctionEnum) -> ())
+  case g((ReferencedFromFunctionStruct) -> ())
+}
+
+// CHECK-LABEL: sil hidden @$S5types34referencedFromFunctionStructFieldsyyAA010ReferencedcdE0Vc_yAA0gcD4EnumOctADF{{.*}} : $@convention(thin) (@guaranteed ReferencedFromFunctionStruct) -> (@owned @callee_guaranteed (@guaranteed ReferencedFromFunctionStruct) -> (), @owned @callee_guaranteed (@guaranteed ReferencedFromFunctionEnum) -> ()) {
+// CHECK: bb0([[X:%.*]] : @guaranteed $ReferencedFromFunctionStruct):
+// CHECK:   [[F:%.*]] = struct_extract [[X]] : $ReferencedFromFunctionStruct, #ReferencedFromFunctionStruct.f
+// CHECK:   [[COPIED_F:%.*]] = copy_value [[F]] : $@callee_guaranteed (@guaranteed ReferencedFromFunctionStruct) -> ()
+// CHECK:   [[G:%.*]] = struct_extract [[X]] : $ReferencedFromFunctionStruct, #ReferencedFromFunctionStruct.g
+// CHECK:   [[COPIED_G:%.*]] = copy_value [[G]] : $@callee_guaranteed (@guaranteed ReferencedFromFunctionEnum) -> ()
+// CHECK:   [[RESULT:%.*]] = tuple ([[COPIED_F]] : {{.*}}, [[COPIED_G]] : {{.*}})
+// CHECK:   return [[RESULT]]
+// CHECK: } // end sil function '$S5types34referencedFromFunctionStructFieldsyyAA010ReferencedcdE0Vc_yAA0gcD4EnumOctADF'
+func referencedFromFunctionStructFields(_ x: ReferencedFromFunctionStruct)
+    -> ((ReferencedFromFunctionStruct) -> (), (ReferencedFromFunctionEnum) -> ()) {
+  return (x.f, x.g)
+}
+
+// CHECK-LABEL: sil hidden @$S5types32referencedFromFunctionEnumFieldsyyAA010ReferencedcdE0OcSg_yAA0gcD6StructVcSgtADF
+// CHECK:       bb{{[0-9]+}}([[F:%.*]] : @owned $@callee_guaranteed (@guaranteed ReferencedFromFunctionEnum) -> ()):
+// CHECK:       bb{{[0-9]+}}([[G:%.*]] : @owned $@callee_guaranteed (@guaranteed ReferencedFromFunctionStruct) -> ()):
+func referencedFromFunctionEnumFields(_ x: ReferencedFromFunctionEnum)
+    -> (
+      ((ReferencedFromFunctionEnum) -> ())?,
+      ((ReferencedFromFunctionStruct) -> ())?
+    ) {
+  switch x {
+  case .f(let f):
+    return (f, nil)
+  case .g(let g):
+    return (nil, g)
+  }
+}
+
+// CHECK-LABEL: sil private @$S5types1fyyF2FCL_C3zimyyF
+// CHECK-LABEL: sil private @$S5types1g1bySb_tF2FCL_C3zimyyF
+// CHECK-LABEL: sil private @$S5types1g1bySb_tF2FCL0_C3zimyyF
diff --git a/test/SILGen/plus_zero_unmanaged.swift b/test/SILGen/plus_zero_unmanaged.swift
new file mode 100644
index 0000000..0a8d7b2
--- /dev/null
+++ b/test/SILGen/plus_zero_unmanaged.swift
@@ -0,0 +1,57 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -enable-sil-ownership -emit-sil %s | %FileCheck %s
+
+class C {}
+
+struct Holder {
+  unowned(unsafe) var value: C
+}
+_ = Holder(value: C())
+// CHECK-LABEL:sil hidden @$S9unmanaged6HolderV{{[_0-9a-zA-Z]*}}fC : $@convention(method) (@owned C, @thin Holder.Type) -> Holder
+// CHECK: bb0([[T0:%.*]] : $C,
+// CHECK-NEXT:   [[T1:%.*]] = ref_to_unmanaged [[T0]] : $C to $@sil_unmanaged C
+// CHECK-NEXT:   strong_release [[T0]] : $C
+// CHECK-NEXT:   [[T2:%.*]] = struct $Holder ([[T1]] : $@sil_unmanaged C)
+// CHECK-NEXT:   return [[T2]] : $Holder
+
+func set(holder holder: inout Holder) {
+  holder.value = C()
+}
+// CHECK-LABEL:sil hidden @$S9unmanaged3set6holderyAA6HolderVz_tF : $@convention(thin) (@inout Holder) -> ()
+// CHECK: bb0([[ADDR:%.*]] : $*Holder):
+// CHECK:        [[T0:%.*]] = function_ref @$S9unmanaged1CC{{[_0-9a-zA-Z]*}}fC
+// CHECK:        [[C:%.*]] = apply [[T0]](
+// CHECK-NEXT:   [[WRITE:%.*]] = begin_access [modify] [static] [[ADDR]] : $*Holder
+// CHECK-NEXT:   [[T0:%.*]] = struct_element_addr [[WRITE]] : $*Holder, #Holder.value
+// CHECK-NEXT:   [[T1:%.*]] = ref_to_unmanaged [[C]]
+// CHECK-NEXT:   store [[T1]] to [[T0]]
+// CHECK-NEXT:   strong_release [[C]]
+// CHECK-NEXT:   end_access [[WRITE]] : $*Holder
+// CHECK-NEXT:   tuple ()
+// CHECK-NEXT:   return
+
+func get(holder holder: inout Holder) -> C {
+  return holder.value
+}
+// CHECK-LABEL:sil hidden @$S9unmanaged3get6holderAA1CCAA6HolderVz_tF : $@convention(thin) (@inout Holder) -> @owned C
+// CHECK: bb0([[ADDR:%.*]] : $*Holder):
+// CHECK-NEXT:   debug_value_addr %0 : $*Holder, var, name "holder", argno 1 
+// CHECK-NEXT:   [[READ:%.*]] = begin_access [read] [static] [[ADDR]] : $*Holder
+// CHECK-NEXT:   [[T0:%.*]] = struct_element_addr [[READ]] : $*Holder, #Holder.value
+// CHECK-NEXT:   [[T1:%.*]] = load [[T0]] : $*@sil_unmanaged C
+// CHECK-NEXT:   [[T2:%.*]] = unmanaged_to_ref [[T1]]
+// CHECK-NEXT:   strong_retain [[T2]]
+// CHECK-NEXT:   end_access [[READ]] : $*Holder
+// CHECK-NEXT:   return [[T2]]
+
+func project(fn fn: () -> Holder) -> C {
+  return fn().value
+}
+// CHECK-LABEL: sil hidden @$S9unmanaged7project2fnAA1CCAA6HolderVyXE_tF : $@convention(thin) (@noescape @callee_guaranteed () -> Holder) -> @owned C
+// CHECK: bb0([[FN:%.*]] : $@noescape @callee_guaranteed () -> Holder):
+// CHECK-NEXT: debug_value
+// CHECK-NEXT: [[T0:%.*]] = apply [[FN]]()
+// CHECK-NEXT: [[T1:%.*]] = struct_extract [[T0]] : $Holder, #Holder.value
+// CHECK-NEXT: [[T2:%.*]] = unmanaged_to_ref [[T1]]
+// CHECK-NEXT: strong_retain [[T2]]
+// CHECK-NEXT: return [[T2]]
diff --git a/test/SILGen/plus_zero_unmanaged_ownership.swift b/test/SILGen/plus_zero_unmanaged_ownership.swift
new file mode 100644
index 0000000..8384266
--- /dev/null
+++ b/test/SILGen/plus_zero_unmanaged_ownership.swift
@@ -0,0 +1,69 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -enable-sil-ownership -parse-stdlib -module-name Swift -emit-silgen %s | %FileCheck %s
+
+class C {}
+
+enum Optional<T> {
+case none
+case some(T)
+}
+
+precedencegroup AssignmentPrecedence {
+  assignment: true
+  associativity: right
+}
+
+struct Holder {
+  unowned(unsafe) var value: C
+}
+
+_ = Holder(value: C())
+// CHECK-LABEL:sil hidden @$Ss6HolderV{{[_0-9a-zA-Z]*}}fC : $@convention(method) (@owned C, @thin Holder.Type) -> Holder
+// CHECK: bb0([[T0:%.*]] : @owned $C,
+// CHECK-NEXT:   [[T1:%.*]] = ref_to_unmanaged [[T0]] : $C to $@sil_unmanaged C
+// CHECK-NEXT:   destroy_value [[T0]] : $C
+// CHECK-NEXT:   [[T2:%.*]] = struct $Holder ([[T1]] : $@sil_unmanaged C)
+// CHECK-NEXT:   return [[T2]] : $Holder
+// CHECK-NEXT: } // end sil function '$Ss6HolderV5valueABs1CC_tcfC'
+func set(holder holder: inout Holder) {
+  holder.value = C()
+}
+
+// CHECK-LABEL: sil hidden @$Ss3set6holderys6HolderVz_tF : $@convention(thin) (@inout Holder) -> () {
+// CHECK: bb0([[ADDR:%.*]] : @trivial $*Holder):
+// CHECK:        [[T0:%.*]] = function_ref @$Ss1CC{{[_0-9a-zA-Z]*}}fC
+// CHECK:        [[C:%.*]] = apply [[T0]](
+// CHECK-NEXT:   [[WRITE:%.*]] = begin_access [modify] [unknown] [[ADDR]] : $*Holder
+// CHECK-NEXT:   [[T0:%.*]] = struct_element_addr [[WRITE]] : $*Holder, #Holder.value
+// CHECK-NEXT:   [[T1:%.*]] = ref_to_unmanaged [[C]]
+// CHECK-NEXT:   assign [[T1]] to [[T0]]
+// CHECK-NEXT:   destroy_value [[C]]
+// CHECK-NEXT:   end_access [[WRITE]] : $*Holder
+// CHECK: } // end sil function '$Ss3set6holderys6HolderVz_tF'
+
+func get(holder holder: inout Holder) -> C {
+  return holder.value
+}
+// CHECK-LABEL: sil hidden @$Ss3get6holders1CCs6HolderVz_tF : $@convention(thin) (@inout Holder) -> @owned C {
+// CHECK: bb0([[ADDR:%.*]] : @trivial $*Holder):
+// CHECK-NEXT:   debug_value_addr %0 : $*Holder, var, name "holder", argno 1 
+// CHECK-NEXT:   [[READ:%.*]] = begin_access [read] [unknown] [[ADDR]] : $*Holder
+// CHECK-NEXT:   [[T0:%.*]] = struct_element_addr [[READ]] : $*Holder, #Holder.value
+// CHECK-NEXT:   [[T1:%.*]] = load [trivial] [[T0]] : $*@sil_unmanaged C
+// CHECK-NEXT:   [[T2:%.*]] = unmanaged_to_ref [[T1]]
+// CHECK-NEXT:   [[T2_COPY:%.*]] = copy_value [[T2]]
+// CHECK-NEXT:   end_access [[READ]] : $*Holder
+// CHECK-NEXT:   return [[T2_COPY]]
+
+func project(fn fn: () -> Holder) -> C {
+  return fn().value
+}
+// CHECK-LABEL: sil hidden @$Ss7project2fns1CCs6HolderVyXE_tF : $@convention(thin) (@noescape @callee_guaranteed () -> Holder) -> @owned C {
+// CHECK: bb0([[FN:%.*]] : @trivial $@noescape @callee_guaranteed () -> Holder):
+// CHECK-NEXT: debug_value
+// CHECK-NEXT: [[T0:%.*]] = apply [[FN]]()
+// CHECK-NEXT: [[T1:%.*]] = struct_extract [[T0]] : $Holder, #Holder.value
+// CHECK-NEXT: [[T2:%.*]] = unmanaged_to_ref [[T1]]
+// CHECK-NEXT: [[COPIED_T2:%.*]] = copy_value [[T2]]
+// CHECK-NOT: destroy_value [[BORROWED_FN_COPY]]
+// CHECK-NEXT: return [[COPIED_T2]]
diff --git a/test/SILGen/plus_zero_unowned.swift b/test/SILGen/plus_zero_unowned.swift
new file mode 100644
index 0000000..ff712fb
--- /dev/null
+++ b/test/SILGen/plus_zero_unowned.swift
@@ -0,0 +1,162 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership %s | %FileCheck %s
+
+func takeClosure(_ fn: () -> Int) {}
+
+class C {
+  func f() -> Int { return 42 }
+}
+
+struct A {
+  unowned var x: C
+}
+_ = A(x: C())
+// CHECK-LABEL: sil hidden @$S7unowned1AV{{[_0-9a-zA-Z]*}}fC
+// CHECK: bb0([[X:%.*]] : @owned $C, %1 : @trivial $@thin A.Type):
+// CHECK:   [[X_UNOWNED:%.*]] = ref_to_unowned [[X]] : $C to $@sil_unowned C
+// CHECK:   [[X_UNOWNED_COPY:%.*]] = copy_value [[X_UNOWNED]]
+// CHECK:   destroy_value [[X]]
+// CHECK:   [[A:%.*]] = struct $A ([[X_UNOWNED_COPY]] : $@sil_unowned C)
+// CHECK:   return [[A]]
+// CHECK: }
+
+protocol P {}
+struct X: P {}
+
+struct AddressOnly {
+  unowned var x: C
+  var p: P
+}
+_ = AddressOnly(x: C(), p: X())
+// CHECK-LABEL: sil hidden @$S7unowned11AddressOnlyV{{[_0-9a-zA-Z]*}}fC
+// CHECK: bb0([[RET:%.*]] : @trivial $*AddressOnly, [[X:%.*]] : @owned $C, {{.*}}):
+// CHECK:   [[X_ADDR:%.*]] = struct_element_addr [[RET]] : $*AddressOnly, #AddressOnly.x
+// CHECK:   [[X_UNOWNED:%.*]] = ref_to_unowned [[X]] : $C to $@sil_unowned C
+// CHECK:   [[X_UNOWNED_COPY:%.*]] = copy_value [[X_UNOWNED]] : $@sil_unowned C
+// CHECK:   store [[X_UNOWNED_COPY]] to [init] [[X_ADDR]]
+// CHECK:   destroy_value [[X]]
+// CHECK: }
+
+// CHECK-LABEL:    sil hidden @$S7unowned5test01cyAA1CC_tF : $@convention(thin) (@guaranteed C) -> () {
+func test0(c c: C) {
+  // CHECK: bb0([[ARG:%.*]] : @guaranteed $C):
+
+  var a: A
+  // CHECK:   [[A1:%.*]] = alloc_box ${ var A }, var, name "a"
+  // CHECK:   [[MARKED_A1:%.*]] = mark_uninitialized [var] [[A1]]
+  // CHECK:   [[PBA:%.*]] = project_box [[MARKED_A1]]
+
+  unowned var x = c
+  // CHECK:   [[X:%.*]] = alloc_box ${ var @sil_unowned C }
+  // CHECK:   [[PBX:%.*]] = project_box [[X]]
+  // CHECK:   [[ARG_COPY:%.*]] = copy_value [[ARG]]
+  // CHECK:   [[T2:%.*]] = ref_to_unowned [[ARG_COPY]] : $C  to $@sil_unowned C
+  // CHECK:   [[T2_COPY:%.*]] = copy_value [[T2]] : $@sil_unowned C
+  // CHECK:   store [[T2_COPY]] to [init] [[PBX]] : $*@sil_unowned C
+  // CHECK:   destroy_value [[ARG_COPY]]
+
+  a.x = c
+  // CHECK:   [[ARG_COPY:%.*]] = copy_value [[ARG]]
+  // CHECK:   [[WRITE:%.*]] = begin_access [modify] [unknown] [[PBA]]
+  // CHECK:   [[T1:%.*]] = struct_element_addr [[WRITE]] : $*A, #A.x
+  // CHECK:   [[T2:%.*]] = ref_to_unowned [[ARG_COPY]] : $C
+  // CHECK:   [[T2_COPY:%.*]] = copy_value [[T2]] : $@sil_unowned C
+  // CHECK:   assign [[T2_COPY]] to [[T1]] : $*@sil_unowned C
+  // CHECK:   destroy_value [[ARG_COPY]]
+
+  a.x = x
+  // CHECK:   [[READ:%.*]] = begin_access [read] [unknown] [[PBX]]
+  // CHECK:   [[T2:%.*]] = load_borrow [[READ]] : $*@sil_unowned C     
+  // CHECK:   [[T3:%.*]] = copy_unowned_value  [[T2]] : $@sil_unowned C  
+  // CHECK:   end_borrow [[T2]] from [[READ]]
+  // CHECK:   [[WRITE:%.*]] = begin_access [modify] [unknown] [[PBA]]
+  // CHECK:   [[XP:%.*]] = struct_element_addr [[WRITE]] : $*A, #A.x
+  // CHECK:   [[T4:%.*]] = ref_to_unowned [[T3]] : $C to $@sil_unowned C
+  // CHECK:   [[T4_COPY:%.*]] = copy_value [[T4]] : $@sil_unowned C  
+  // CHECK:   assign [[T4_COPY]] to [[XP]] : $*@sil_unowned C
+  // CHECK:   destroy_value [[T3]] : $C
+  // CHECK:   destroy_value [[X]]
+  // CHECK:   destroy_value [[MARKED_A1]]
+}
+// CHECK: } // end sil function '$S7unowned5test01cyAA1CC_tF'
+
+// CHECK-LABEL: sil hidden @{{.*}}testunowned_local
+func testunowned_local() -> C {
+  // CHECK: [[C:%.*]] = apply
+  let c = C()
+
+  // CHECK: [[UC:%.*]] = alloc_box ${ var @sil_unowned C }, let, name "uc"
+  // CHECK: [[PB_UC:%.*]] = project_box [[UC]]
+  // CHECK: [[BORROWED_C:%.*]] = begin_borrow [[C]]
+  // CHECK: [[C_COPY:%.*]] = copy_value [[BORROWED_C]]
+  // CHECK: [[tmp1:%.*]] = ref_to_unowned [[C_COPY]] : $C to $@sil_unowned C
+  // CHECK: [[tmp1_copy:%.*]] = copy_value [[tmp1]]
+  // CHECK: store [[tmp1_copy]] to [init] [[PB_UC]]
+  // CHECK: destroy_value [[C_COPY]]
+  // CHECK: end_borrow [[BORROWED_C]] from [[C]]
+  unowned let uc = c
+
+  // CHECK: [[tmp2:%.*]] = load_borrow [[PB_UC]]
+  // CHECK: [[tmp3:%.*]] = copy_unowned_value [[tmp2]]
+  // CHECK: end_borrow [[tmp2]] from [[PB_UC]]
+  return uc
+
+  // CHECK: destroy_value [[UC]]
+  // CHECK: destroy_value [[C]]
+  // CHECK: return [[tmp3]]
+}
+
+// <rdar://problem/16877510> capturing an unowned let crashes in silgen
+func test_unowned_let_capture(_ aC : C) {
+  unowned let bC = aC
+  takeClosure { bC.f() }
+}
+
+// CHECK-LABEL: sil private @$S7unowned05test_A12_let_captureyyAA1CCFSiyXEfU_ : $@convention(thin) (@guaranteed @sil_unowned C) -> Int {
+// CHECK: bb0([[ARG:%.*]] : @guaranteed $@sil_unowned C):
+// CHECK-NEXT:   debug_value %0 : $@sil_unowned C, let, name "bC", argno 1
+// CHECK-NEXT:   [[UNOWNED_ARG:%.*]] = copy_unowned_value [[ARG]] : $@sil_unowned C
+// CHECK-NEXT:   [[BORROWED_UNOWNED_ARG:%.*]] = begin_borrow [[UNOWNED_ARG]]
+// CHECK-NEXT:   [[FUN:%.*]] = class_method [[BORROWED_UNOWNED_ARG]] : $C, #C.f!1 : (C) -> () -> Int, $@convention(method) (@guaranteed C) -> Int
+// CHECK-NEXT:   [[RESULT:%.*]] = apply [[FUN]]([[BORROWED_UNOWNED_ARG]]) : $@convention(method) (@guaranteed C) -> Int
+// CHECK-NEXT:   end_borrow [[BORROWED_UNOWNED_ARG]]
+// CHECK-NEXT:   destroy_value [[UNOWNED_ARG]]
+// CHECK-NEXT:   return [[RESULT]] : $Int
+
+
+
+// <rdar://problem/16880044> unowned let properties don't work as struct and class members
+class TestUnownedMember {
+  unowned let member : C
+  init(inval: C) {
+    self.member = inval
+  }
+}
+
+// CHECK-LABEL: sil hidden @$S7unowned17TestUnownedMemberC5invalAcA1CC_tcfc :
+// CHECK: bb0([[ARG1:%.*]] : @owned $C, [[SELF_PARAM:%.*]] : @owned $TestUnownedMember):
+// CHECK:   [[SELF:%.*]] = mark_uninitialized [rootself] [[SELF_PARAM]] : $TestUnownedMember
+// CHECK:   [[BORROWED_SELF:%.*]] = begin_borrow [[SELF]]
+// CHECK:   [[BORROWED_ARG1:%.*]] = begin_borrow [[ARG1]]
+// CHECK:   [[ARG1_COPY:%.*]] = copy_value [[BORROWED_ARG1]]
+// CHECK:   [[FIELDPTR:%.*]] = ref_element_addr [[BORROWED_SELF]] : $TestUnownedMember, #TestUnownedMember.member
+// CHECK:   [[WRITE:%.*]] = begin_access [modify] [dynamic] [[FIELDPTR]] : $*@sil_unowned C
+// CHECK:   [[INVAL:%.*]] = ref_to_unowned [[ARG1_COPY]] : $C to $@sil_unowned C
+// CHECK:   [[INVAL_COPY:%.*]] = copy_value [[INVAL]] : $@sil_unowned C
+// CHECK:   assign [[INVAL_COPY]] to [[WRITE]] : $*@sil_unowned C
+// CHECK:   destroy_value [[ARG1_COPY]] : $C
+// CHECK:   end_borrow [[BORROWED_ARG1]] from [[ARG1]]
+// CHECK:   end_borrow [[BORROWED_SELF]] from [[SELF]]
+// CHECK:   [[RET_SELF:%.*]] = copy_value [[SELF]]
+// CHECK:   destroy_value [[SELF]]
+// CHECK:   destroy_value [[ARG1]]
+// CHECK:   return [[RET_SELF]] : $TestUnownedMember
+// CHECK: } // end sil function '$S7unowned17TestUnownedMemberC5invalAcA1CC_tcfc'
+
+// Just verify that lowering an unowned reference to a type parameter
+// doesn't explode.
+struct Unowned<T: AnyObject> {
+  unowned var object: T
+}
+func takesUnownedStruct(_ z: Unowned<C>) {}
+// CHECK-LABEL: sil hidden @$S7unowned18takesUnownedStructyyAA0C0VyAA1CCGF : $@convention(thin) (@guaranteed Unowned<C>) -> ()
diff --git a/test/SILGen/plus_zero_vtable_thunks_reabstraction_final.swift b/test/SILGen/plus_zero_vtable_thunks_reabstraction_final.swift
new file mode 100644
index 0000000..4cd5aee
--- /dev/null
+++ b/test/SILGen/plus_zero_vtable_thunks_reabstraction_final.swift
@@ -0,0 +1,49 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership %s | %FileCheck %s
+
+protocol Fooable {
+  func foo(_ x: Int) -> Int?
+}
+
+protocol Barrable {
+  associatedtype Bar
+  func foo(_ x: Bar) -> Bar?
+}
+
+class GenericSuper<T> {
+  func foo(_ x: T) -> T? {
+    return nil
+  }
+}
+
+class NongenericSub: GenericSuper<Int>, Fooable {
+  override func foo(_ x: Int) -> Int? {
+    return 6502
+  }
+}
+
+// CHECK-LABEL: sil private [transparent] [thunk] @$S33vtable_thunks_reabstraction_final13NongenericSubCAA7FooableA2aDP3foo{{[_0-9a-zA-Z]*}}FTW
+// CHECK:         class_method {{%.*}} : $NongenericSub, #NongenericSub.foo!1 {{.*}}, $@convention(method) (@in_guaranteed Int, @guaranteed NongenericSub) -> @out Optional<Int>
+
+class GenericSub<U: AnyObject>: GenericSuper<U>, Barrable {
+  override func foo(_ x: U) -> U? {
+    return x
+  }
+}
+
+// CHECK-LABEL: sil private [transparent] [thunk] @$S33vtable_thunks_reabstraction_final10GenericSubCyxGAA8BarrableA2aEP3fooy3BarQzSgAIFTW
+// CHECK:         class_method {{%.*}} : $GenericSub<τ_0_0>, #GenericSub.foo!1 {{.*}}, $@convention(method) <τ_0_0 where τ_0_0 : AnyObject> (@in_guaranteed τ_0_0, @guaranteed GenericSub<τ_0_0>) -> @out Optional<τ_0_0>
+
+class C {}
+
+// CHECK-LABEL: sil hidden @$S33vtable_thunks_reabstraction_final4testyyF
+func test() {
+  // CHECK: class_method {{%.*}} : $NongenericSub, #NongenericSub.foo!1 {{.*}}, $@convention(method) (@in_guaranteed Int, @guaranteed NongenericSub) -> @out Optional<Int>
+  NongenericSub().foo(0)
+
+  // FIXME: rdar://problem/21167978
+  // let f = NongenericSub().curried(0)
+
+  // CHECK:         class_method {{%.*}} : $GenericSub<C>, #GenericSub.foo!1 {{.*}}, $@convention(method) <τ_0_0 where τ_0_0 : AnyObject> (@in_guaranteed τ_0_0, @guaranteed GenericSub<τ_0_0>) -> @out Optional<τ_0_0>
+  GenericSub<C>().foo(C())
+}
diff --git a/test/SILGen/plus_zero_vtables_objc.swift b/test/SILGen/plus_zero_vtables_objc.swift
new file mode 100644
index 0000000..ef5fbb0
--- /dev/null
+++ b/test/SILGen/plus_zero_vtables_objc.swift
@@ -0,0 +1,95 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -enable-sil-ownership -sdk %S/Inputs -emit-silgen -I %S/Inputs -enable-source-import %s -disable-objc-attr-requires-foundation-module | %FileCheck %s
+
+// REQUIRES: objc_interop
+
+import gizmo
+
+// Test ObjC base class
+
+class Hoozit : Gizmo {
+  // Overrides Gizmo.frob
+  override func frob() {}
+
+  // Overrides Gizmo.funge
+  override func funge() {}
+
+  // Overrides Gizmo.foo
+  final override func foo() {}
+
+  func anse() {}
+  func incorrige() {}
+}
+
+// CHECK-LABEL: sil hidden @$S12vtables_objc10callHoozityyAA0D0CF : $@convention(thin) (@guaranteed Hoozit) -> ()
+func callHoozit(_ h: Hoozit) {
+  // CHECK: objc_method {{.*}} : $Hoozit, #Hoozit.frob!1.foreign
+  h.frob()
+  // CHECK: function_ref @$S12vtables_objc6HoozitC3fooyyF
+  h.foo()
+  // CHECK: class_method {{.*}} : $Hoozit, #Hoozit.anse!1
+  h.anse()
+  // CHECK: return
+}
+
+class Wotsit : Hoozit {
+  // Overrides Gizmo.funge
+  override func funge() {}
+
+  // Overrides Hoozit.incorrige
+  override func incorrige() {}
+
+  // Overrides Gizmo.frob
+  final override func frob() {}
+}
+
+// CHECK-LABEL: sil hidden @$S12vtables_objc10callWotsityyAA0D0CF : $@convention(thin) (@guaranteed Wotsit) -> ()
+func callWotsit(_ w: Wotsit) {
+  // CHECK: objc_method {{.*}} : $Wotsit, #Wotsit.funge!1.foreign
+  w.funge()
+  // CHECK: class_method {{.*}} : $Wotsit, #Wotsit.incorrige!1
+  w.incorrige()
+  // CHECK: function_ref @$S12vtables_objc6WotsitC4frobyyF
+  w.frob()
+  // CHECK: return
+}
+
+// Entries only exist for native Swift methods
+
+// CHECK: sil_vtable Hoozit {
+// CHECK-NEXT:   #Hoozit.anse!1: {{.*}} : @$S12vtables_objc6HoozitC4anse{{[_0-9a-zA-Z]*}}F
+// CHECK-NEXT:   #Hoozit.incorrige!1: {{.*}} : @$S12vtables_objc6HoozitC9incorrige{{[_0-9a-zA-Z]*}}F
+// CHECK-NEXT:   #Hoozit.init!initializer.1: (Hoozit.Type) -> () -> Hoozit? : @$S12vtables_objc6HoozitCACSgycfc
+// CHECK-NEXT:   #Hoozit.init!initializer.1: (Hoozit.Type) -> (Int) -> Hoozit? : @$S12vtables_objc6HoozitC7bellsOnACSgSi_tcfc
+// CHECK-NEXT:   #Hoozit.deinit!deallocator: @$S12vtables_objc6HoozitCfD
+// CHECK-NEXT: }
+
+// CHECK: sil_vtable Wotsit {
+// CHECK-NEXT:   #Hoozit.anse!1: {{.*}} : @$S12vtables_objc6HoozitC4anse{{[_0-9a-zA-Z]*}}F
+// CHECK-NEXT:   #Hoozit.incorrige!1: {{.*}} : @$S12vtables_objc6WotsitC9incorrige{{[_0-9a-zA-Z]*}}F
+// CHECK-NEXT:   #Hoozit.init!initializer.1: (Hoozit.Type) -> () -> Hoozit? : @$S12vtables_objc6WotsitCACSgycfc
+// CHECK-NEXT:   #Hoozit.init!initializer.1: (Hoozit.Type) -> (Int) -> Hoozit? : @$S12vtables_objc6WotsitC7bellsOnACSgSi_tcfc
+// CHECK-NEXT:   #Wotsit.deinit!deallocator: @$S12vtables_objc6WotsitCfD
+// CHECK-NEXT: }
+
+// <rdar://problem/15282548>
+// CHECK: sil_vtable Base {
+// CHECK:   #Base.init!initializer.1: {{.*}} : @$S12vtables_objc4BaseC{{[_0-9a-zA-Z]*}}fc
+// CHECK: }
+// CHECK: sil_vtable Derived {
+// CHECK:   #Base.init!initializer.1: {{.*}} : @$S12vtables_objc7DerivedC{{[_0-9a-zA-Z]*}}fc
+// CHECK: }
+@objc class Base {}
+
+extension Base {
+  // note: does not have a vtable slot, because it is from an extension
+  func identify() -> Int {
+    return 0
+  }
+}
+
+class Derived : Base {
+  override func identify() -> Int {
+    return 1
+  }
+}
diff --git a/test/SILGen/plus_zero_weak.swift b/test/SILGen/plus_zero_weak.swift
new file mode 100644
index 0000000..919a55f
--- /dev/null
+++ b/test/SILGen/plus_zero_weak.swift
@@ -0,0 +1,87 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -Xllvm -sil-full-demangle -emit-silgen -enable-sil-ownership %s | %FileCheck %s
+
+class C {
+  func f() -> Int { return 42 }
+}
+
+func takeClosure(fn: @escaping () -> Int) {}
+
+struct A {
+  weak var x: C?
+}
+
+// CHECK:    sil hidden @$S4weak5test01cyAA1CC_tF : $@convention(thin) (@guaranteed C) -> () {
+func test0(c c: C) {
+  var c = c
+// CHECK:    bb0(%0 : @guaranteed $C):
+// CHECK:      [[C:%.*]] = alloc_box ${ var C }
+// CHECK-NEXT: [[PBC:%.*]] = project_box [[C]]
+
+  var a: A
+// CHECK:      [[A1:%.*]] = alloc_box ${ var A }
+// CHECK:      [[MARKED_A1:%.*]] = mark_uninitialized [var] [[A1]]
+// CHECK-NEXT: [[PBA:%.*]] = project_box [[MARKED_A1]]
+
+  weak var x = c
+// CHECK:      [[X:%.*]] = alloc_box ${ var @sil_weak Optional<C> }, var, name "x"
+// CHECK-NEXT: [[PBX:%.*]] = project_box [[X]]
+//   Implicit conversion
+// CHECK-NEXT: [[READ:%.*]] = begin_access [read] [unknown] [[PBC]]
+// CHECK-NEXT: [[TMP:%.*]] = load [copy] [[READ]] : $*C
+// CHECK-NEXT: end_access [[READ]]
+// CHECK-NEXT: [[OPTVAL:%.*]] = enum $Optional<C>, #Optional.some!enumelt.1, [[TMP]] : $C
+// CHECK-NEXT: store_weak [[OPTVAL]] to [initialization] [[PBX]] : $*@sil_weak Optional<C>
+// CHECK-NEXT: destroy_value [[OPTVAL]] : $Optional<C>
+
+  a.x = c
+//   Implicit conversion
+// CHECK-NEXT: [[READ:%.*]] = begin_access [read] [unknown] [[PBC]]
+// CHECK-NEXT: [[TMP:%.*]] = load [copy] [[READ]] : $*C
+// CHECK-NEXT:  end_access [[READ]]
+// CHECK-NEXT: [[OPTVAL:%.*]] = enum $Optional<C>, #Optional.some!enumelt.1, [[TMP]] : $C
+
+//   Drill to a.x
+// CHECK-NEXT: [[WRITE:%.*]] = begin_access [modify] [unknown] [[PBA]]
+// CHECK-NEXT: [[A_X:%.*]] = struct_element_addr [[WRITE]] : $*A, #A.x
+
+//   Store to a.x.
+// CHECK-NEXT: store_weak [[OPTVAL]] to [[A_X]] : $*@sil_weak Optional<C>
+// CHECK-NEXT: destroy_value [[OPTVAL]] : $Optional<C>
+}
+
+// <rdar://problem/16871284> silgen crashes on weak capture
+// CHECK: closure #1 () -> Swift.Int in weak.testClosureOverWeak() -> ()
+// CHECK-LABEL: sil private @$S4weak19testClosureOverWeakyyFSiycfU_ : $@convention(thin) (@guaranteed { var @sil_weak Optional<C> }) -> Int {
+// CHECK: bb0(%0 : @guaranteed ${ var @sil_weak Optional<C> }):
+// CHECK-NEXT:  %1 = project_box %0
+// CHECK-NEXT:  debug_value_addr %1 : $*@sil_weak Optional<C>, var, name "bC", argno 1
+// CHECK-NEXT:  [[READ:%.*]] = begin_access [read] [unknown] %1
+// CHECK-NEXT:  [[STK:%.*]] = alloc_stack $Optional<C>
+// CHECK-NEXT:  [[VAL:%.*]] = load_weak [[READ]] : $*@sil_weak Optional<C>
+// CHECK-NEXT:  store [[VAL]] to [init] [[STK]] : $*Optional<C>
+func testClosureOverWeak() {
+  weak var bC = C()
+  takeClosure { bC!.f() }
+}
+
+class CC {
+  weak var x: CC?
+
+  // CHECK-LABEL: sil hidden @$S4weak2CCC{{[_0-9a-zA-Z]*}}fc : $@convention(method) (@owned CC) -> @owned CC {
+  // CHECK:  bb0([[SELF:%.*]] : @owned $CC):
+  // CHECK:    [[UNINIT_SELF:%.*]] = mark_uninitialized [rootself] [[SELF]] : $CC
+  // CHECK:    [[FOO:%.*]] = alloc_box ${ var Optional<CC> }, var, name "foo"
+  // CHECK:    [[PB:%.*]] = project_box [[FOO]]
+  // CHECK:    [[BORROWED_UNINIT_SELF:%.*]] = begin_borrow [[UNINIT_SELF]]
+  // CHECK:    [[X:%.*]] = ref_element_addr [[BORROWED_UNINIT_SELF]] : $CC, #CC.x
+  // CHECK:    [[READ:%.*]] = begin_access [read] [dynamic] [[X]] : $*@sil_weak Optional<CC>
+  // CHECK:    [[VALUE:%.*]] = load_weak [[READ]] : $*@sil_weak Optional<CC>
+  // CHECK:    store [[VALUE]] to [init] [[PB]] : $*Optional<CC>
+  // CHECK:    end_borrow [[BORROWED_UNINIT_SELF]] from [[UNINIT_SELF]]
+  // CHECK:    destroy_value [[FOO]]
+  // CHECK: } // end sil function '$S4weak2CCC{{[_0-9a-zA-Z]*}}fc'
+  init() {
+    var foo = x
+  }
+}
diff --git a/test/SILGen/plus_zero_weak_multiple_modules.swift b/test/SILGen/plus_zero_weak_multiple_modules.swift
new file mode 100644
index 0000000..2c97546
--- /dev/null
+++ b/test/SILGen/plus_zero_weak_multiple_modules.swift
@@ -0,0 +1,23 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %empty-directory(%t)
+// RUN: %target-swift-frontend -emit-module -emit-module-path=%t/weak_other.swiftmodule -module-name=weak_other %S/Inputs/weak_other.swift
+// RUN: %target-swift-frontend -I %t -emit-silgen -enable-sil-ownership %s | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%target-runtime
+
+import weak_other
+
+// CHECK-LABEL: sil hidden @$S21weak_multiple_modules11doSomething2uiSb0A6_other2UIC_tF : $@convention(thin) (@guaranteed UI) -> Bool
+func doSomething(ui: UI) -> Bool {
+  // CHECK: ref_element_addr
+  // CHECK-objc: load_unowned
+  // CHECK-native: load_borrow
+  // CHECK-native: copy_unowned_value
+  // CHECK-native: end_borrow
+  // CHECK: open_existential_ref
+  // CHECK: witness_method
+  // CHECK: apply
+  // CHECK: open_existential_ref
+  // CHECK: function_ref
+  // CHECK: apply
+  // CHECK: return
+  return ui.environment.router.flags.asBoolean()
+}
diff --git a/test/SILGen/plus_zero_without_actually_escaping.swift b/test/SILGen/plus_zero_without_actually_escaping.swift
new file mode 100644
index 0000000..cce3e9c
--- /dev/null
+++ b/test/SILGen/plus_zero_without_actually_escaping.swift
@@ -0,0 +1,46 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership %s | %FileCheck %s
+
+var escapeHatch: Any = 0
+
+// CHECK-LABEL: sil hidden @$S25without_actually_escaping9letEscape1fyycyyXE_tF
+func letEscape(f: () -> ()) -> () -> () {
+  // CHECK: bb0([[ARG:%.*]] : @trivial $@noescape @callee_guaranteed () -> ()):
+  // TODO: Use a canary wrapper instead of just copying the nonescaping value
+  // CHECK: [[ESCAPABLE_COPY:%.*]] = partial_apply [callee_guaranteed] {{%.*}}([[ARG]])
+  // CHECK: [[MD_ESCAPABLE_COPY:%.*]] = mark_dependence [[ESCAPABLE_COPY]]
+  // CHECK: [[BORROW_MD_ESCAPABLE_COPY:%.*]] = begin_borrow [[MD_ESCAPABLE_COPY]]
+  // CHECK: [[SUB_CLOSURE:%.*]] = function_ref @
+  // CHECK: [[RESULT:%.*]] = apply [[SUB_CLOSURE]]([[BORROW_MD_ESCAPABLE_COPY]])
+  // CHECK: destroy_value [[MD_ESCAPABLE_COPY]]
+  // CHECK: return [[RESULT]]
+  return withoutActuallyEscaping(f) { return $0 }
+}
+
+
+// CHECK-LABEL: sil hidden @$S25without_actually_escaping14letEscapeThrow1fyycyycyKXE_tKF
+// CHECK: bb0([[ARG:%.*]] : @trivial $@noescape @callee_guaranteed () -> (@owned @callee_guaranteed () -> (), @error Error)):
+// CHECK: [[CVT:%.*]] = function_ref @$SIeg_s5Error_pIgozo_Ieg_sAA_pIegozo_TR
+// CHECK: [[CLOSURE:%.*]] = partial_apply [callee_guaranteed] [[CVT]]([[ARG]])
+// CHECK:  [[MD:%.*]] = mark_dependence [[CLOSURE]] : {{.*}} on [[ARG]]
+// CHECK:  [[BORROW:%.*]] = begin_borrow [[MD]]
+// CHECK:  [[COPY:%.*]] = copy_value [[BORROW]]
+// CHECK:  [[USER:%.*]] = function_ref @$S25without_actually_escaping14letEscapeThrow1fyycyycyKXE_tKFyycyycyKcKXEfU_
+// CHECK:  try_apply [[USER]]([[COPY]]) : {{.*}}, normal bb1, error bb2
+//
+// CHECK: bb1([[RES:%.*]] : @owned $@callee_guaranteed () -> ()):
+// CHECK:   [[ESCAPED:%.*]] = is_escaping_closure [[BORROW]]
+// CHECK:   cond_fail [[ESCAPED]] : $Builtin.Int1
+// CHECK:   end_borrow [[BORROW]] from [[MD]]
+// CHECK:   destroy_value [[MD]]
+// CHECK:   return [[RES]]
+//
+// CHECK: bb2([[ERR:%.*]] : @owned $Error):
+// CHECK:   end_borrow [[BORROW]] from [[MD]]
+// CHECK:   destroy_value [[MD]]
+// CHECK:   throw [[ERR]] : $Error
+// CHECK: }
+
+func letEscapeThrow(f: () throws -> () -> ()) throws -> () -> () {
+  return try withoutActuallyEscaping(f) { return try $0() }
+}
diff --git a/test/SILGen/plus_zero_witness_same_type.swift b/test/SILGen/plus_zero_witness_same_type.swift
new file mode 100644
index 0000000..93335d1
--- /dev/null
+++ b/test/SILGen/plus_zero_witness_same_type.swift
@@ -0,0 +1,35 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership %s | %FileCheck %s
+// RUN: %target-swift-frontend -enable-sil-ownership -emit-ir %s
+
+protocol Fooable {
+  associatedtype Bar
+
+  func foo<T: Fooable where T.Bar == Self.Bar>(x x: T) -> Self.Bar
+}
+
+struct X {}
+
+// Ensure that the protocol witness for requirements with same-type constraints
+// is set correctly. <rdar://problem/16369105>
+// CHECK-LABEL: sil private [transparent] [thunk] @$S17witness_same_type3FooVAA7FooableA2aDP3foo1x3BarQzqd___tAaDRd__AHQyd__AIRSlFTW : $@convention(witness_method: Fooable) <τ_0_0 where τ_0_0 : Fooable, τ_0_0.Bar == X> (@in_guaranteed τ_0_0, @in_guaranteed Foo) -> @out X
+struct Foo: Fooable {
+  typealias Bar = X
+
+  func foo<T: Fooable where T.Bar == X>(x x: T) -> X { return X() }
+}
+
+// rdar://problem/19049566
+// CHECK-LABEL: sil shared [transparent] [serialized] [thunk] @$S17witness_same_type14LazySequenceOfVyxq_Gs0E0AAsAEP12makeIterator0H0QzyFTW : $@convention(witness_method: Sequence) <τ_0_0, τ_0_1 where τ_0_0 : Sequence, τ_0_1 == τ_0_0.Element> (@in_guaranteed LazySequenceOf<τ_0_0, τ_0_1>) -> @out AnyIterator<τ_0_1>
+public struct LazySequenceOf<SS : Sequence, A where SS.Iterator.Element == A> : Sequence {
+  public func makeIterator() -> AnyIterator<A> { 
+    var opt: AnyIterator<A>?
+    return opt!
+  }
+	public subscript(i : Int) -> A { 
+    get { 
+      var opt: A?
+      return opt!
+    } 
+  }
+}
diff --git a/test/SILGen/plus_zero_witness_tables.swift b/test/SILGen/plus_zero_witness_tables.swift
new file mode 100644
index 0000000..e188c03
--- /dev/null
+++ b/test/SILGen/plus_zero_witness_tables.swift
@@ -0,0 +1,551 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership -I %S/Inputs -enable-source-import %s -disable-objc-attr-requires-foundation-module > %t.sil
+// RUN: %FileCheck -check-prefix=TABLE -check-prefix=TABLE-ALL %s < %t.sil
+// RUN: %FileCheck -check-prefix=SYMBOL %s < %t.sil
+
+// RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership -I %S/Inputs -enable-source-import %s -disable-objc-attr-requires-foundation-module -enable-testing > %t.testable.sil
+// RUN: %FileCheck -check-prefix=TABLE-TESTABLE -check-prefix=TABLE-ALL %s < %t.testable.sil
+// RUN: %FileCheck -check-prefix=SYMBOL-TESTABLE %s < %t.testable.sil
+
+import witness_tables_b
+
+struct Arg {}
+
+@objc class ObjCClass {}
+
+infix operator <~>
+
+protocol AssocReqt {
+  func requiredMethod()
+}
+
+protocol ArchetypeReqt {
+  func requiredMethod()
+}
+
+protocol AnyProtocol {
+  associatedtype AssocType
+  associatedtype AssocWithReqt: AssocReqt
+
+  func method(x: Arg, y: Self)
+  func generic<A: ArchetypeReqt>(x: A, y: Self)
+
+  func assocTypesMethod(x: AssocType, y: AssocWithReqt)
+
+  static func staticMethod(x: Self)
+
+  static func <~>(x: Self, y: Self)
+}
+
+protocol ClassProtocol : class {
+  associatedtype AssocType
+  associatedtype AssocWithReqt: AssocReqt
+
+  func method(x: Arg, y: Self)
+  func generic<B: ArchetypeReqt>(x: B, y: Self)
+
+  func assocTypesMethod(x: AssocType, y: AssocWithReqt)
+
+  static func staticMethod(x: Self)
+
+  static func <~>(x: Self, y: Self)
+}
+
+@objc protocol ObjCProtocol {
+  func method(x: ObjCClass)
+  static func staticMethod(y: ObjCClass)
+}
+
+class SomeAssoc {}
+
+struct ConformingAssoc : AssocReqt {
+  func requiredMethod() {}
+}
+// TABLE-LABEL: sil_witness_table hidden ConformingAssoc: AssocReqt module witness_tables {
+// TABLE-TESTABLE-LABEL: sil_witness_table [serialized] ConformingAssoc: AssocReqt module witness_tables {
+// TABLE-ALL-NEXT:    method #AssocReqt.requiredMethod!1: {{.*}} : @$S14witness_tables15ConformingAssocVAA0D4ReqtA2aDP14requiredMethod{{[_0-9a-zA-Z]*}}FTW
+// TABLE-ALL-NEXT:  }
+// SYMBOL:      sil private [transparent] [thunk] @$S14witness_tables15ConformingAssocVAA0D4ReqtA2aDP14requiredMethod{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method: AssocReqt) (@in_guaranteed ConformingAssoc) -> ()
+// SYMBOL-TESTABLE:      sil shared [transparent] [serialized] [thunk] @$S14witness_tables15ConformingAssocVAA0D4ReqtA2aDP14requiredMethod{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method: AssocReqt) (@in_guaranteed ConformingAssoc) -> ()
+
+struct ConformingStruct : AnyProtocol {
+  typealias AssocType = SomeAssoc
+  typealias AssocWithReqt = ConformingAssoc
+  
+  func method(x: Arg, y: ConformingStruct) {}
+  func generic<D: ArchetypeReqt>(x: D, y: ConformingStruct) {}
+
+  func assocTypesMethod(x: SomeAssoc, y: ConformingAssoc) {}
+
+  static func staticMethod(x: ConformingStruct) {}
+}
+func <~>(x: ConformingStruct, y: ConformingStruct) {}
+// TABLE-LABEL: sil_witness_table hidden ConformingStruct: AnyProtocol module witness_tables {
+// TABLE-NEXT:    associated_type AssocType: SomeAssoc
+// TABLE-NEXT:    associated_type AssocWithReqt: ConformingAssoc
+// TABLE-NEXT:    associated_type_protocol (AssocWithReqt: AssocReqt): ConformingAssoc: AssocReqt module witness_tables
+// TABLE-NEXT:    method #AnyProtocol.method!1: {{.*}} : @$S14witness_tables16ConformingStructVAA11AnyProtocolA2aDP6method{{[_0-9a-zA-Z]*}}FTW
+// TABLE-NEXT:    method #AnyProtocol.generic!1: {{.*}} : @$S14witness_tables16ConformingStructVAA11AnyProtocolA2aDP7generic{{[_0-9a-zA-Z]*}}FTW
+// TABLE-NEXT:    method #AnyProtocol.assocTypesMethod!1: {{.*}} : @$S14witness_tables16ConformingStructVAA11AnyProtocolA2aDP16assocTypesMethod{{[_0-9a-zA-Z]*}}FTW
+// TABLE-NEXT:    method #AnyProtocol.staticMethod!1: {{.*}} : @$S14witness_tables16ConformingStructVAA11AnyProtocolA2aDP12staticMethod{{[_0-9a-zA-Z]*}}FZTW
+// TABLE-NEXT:    method #AnyProtocol."<~>"!1: {{.*}} : @$S14witness_tables16ConformingStructVAA11AnyProtocolA2aDP3ltgoi{{[_0-9a-zA-Z]*}}FZTW
+// TABLE-NEXT:  }
+// SYMBOL:      sil private [transparent] [thunk] @$S14witness_tables16ConformingStructVAA11AnyProtocolA2aDP6method{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method: AnyProtocol) (Arg, @in_guaranteed ConformingStruct, @in_guaranteed ConformingStruct) -> ()
+// SYMBOL:      sil private [transparent] [thunk] @$S14witness_tables16ConformingStructVAA11AnyProtocolA2aDP7generic{{[_0-9a-zA-Z]*}}FTW {{.*}}: ArchetypeReqt> (@in_guaranteed τ_0_0, @in_guaranteed ConformingStruct, @in_guaranteed ConformingStruct) -> ()
+// SYMBOL:      sil private [transparent] [thunk] @$S14witness_tables16ConformingStructVAA11AnyProtocolA2aDP16assocTypesMethod{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method: AnyProtocol) (@in_guaranteed SomeAssoc, @in_guaranteed ConformingAssoc, @in_guaranteed ConformingStruct) -> ()
+// SYMBOL:      sil private [transparent] [thunk] @$S14witness_tables16ConformingStructVAA11AnyProtocolA2aDP12staticMethod{{[_0-9a-zA-Z]*}}FZTW : $@convention(witness_method: AnyProtocol) (@in_guaranteed ConformingStruct, @thick ConformingStruct.Type) -> ()
+// SYMBOL:      sil private [transparent] [thunk] @$S14witness_tables16ConformingStructVAA11AnyProtocolA2aDP3ltgoi{{[_0-9a-zA-Z]*}}FZTW : $@convention(witness_method: AnyProtocol) (@in_guaranteed ConformingStruct, @in_guaranteed ConformingStruct, @thick ConformingStruct.Type) -> ()
+// SYMBOL-TESTABLE:      sil shared [transparent] [serialized] [thunk] @$S14witness_tables16ConformingStructVAA11AnyProtocolA2aDP6method{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method: AnyProtocol) (Arg, @in_guaranteed ConformingStruct, @in_guaranteed ConformingStruct) -> ()
+// SYMBOL-TESTABLE:      sil shared [transparent] [serialized] [thunk] @$S14witness_tables16ConformingStructVAA11AnyProtocolA2aDP7generic{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method: AnyProtocol) <τ_0_0 where τ_0_0 : ArchetypeReqt> (@in_guaranteed τ_0_0, @in_guaranteed ConformingStruct, @in_guaranteed ConformingStruct) -> ()
+// SYMBOL-TESTABLE:      sil shared [transparent] [serialized] [thunk] @$S14witness_tables16ConformingStructVAA11AnyProtocolA2aDP16assocTypesMethod{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method: AnyProtocol) (@in_guaranteed SomeAssoc, @in_guaranteed ConformingAssoc, @in_guaranteed ConformingStruct) -> ()
+// SYMBOL-TESTABLE:      sil shared [transparent] [serialized] [thunk] @$S14witness_tables16ConformingStructVAA11AnyProtocolA2aDP12staticMethod{{[_0-9a-zA-Z]*}}FZTW : $@convention(witness_method: AnyProtocol) (@in_guaranteed ConformingStruct, @thick ConformingStruct.Type) -> ()
+// SYMBOL-TESTABLE:      sil shared [transparent] [serialized] [thunk] @$S14witness_tables16ConformingStructVAA11AnyProtocolA2aDP3ltgoi{{[_0-9a-zA-Z]*}}FZTW : $@convention(witness_method: AnyProtocol) (@in_guaranteed ConformingStruct, @in_guaranteed ConformingStruct, @thick ConformingStruct.Type) -> ()
+
+protocol AddressOnly {}
+
+struct ConformingAddressOnlyStruct : AnyProtocol {
+  var p: AddressOnly // force address-only layout with a protocol-type field
+
+  typealias AssocType = SomeAssoc
+  typealias AssocWithReqt = ConformingAssoc
+  
+  func method(x: Arg, y: ConformingAddressOnlyStruct) {}
+  func generic<E: ArchetypeReqt>(x: E, y: ConformingAddressOnlyStruct) {}
+
+  func assocTypesMethod(x: SomeAssoc, y: ConformingAssoc) {}
+
+  static func staticMethod(x: ConformingAddressOnlyStruct) {}
+}
+func <~>(x: ConformingAddressOnlyStruct, y: ConformingAddressOnlyStruct) {}
+// TABLE-LABEL: sil_witness_table hidden ConformingAddressOnlyStruct: AnyProtocol module witness_tables {
+// TABLE-NEXT:    associated_type AssocType: SomeAssoc
+// TABLE-NEXT:    associated_type AssocWithReqt: ConformingAssoc
+// TABLE-NEXT:    associated_type_protocol (AssocWithReqt: AssocReqt): ConformingAssoc: AssocReqt module witness_tables
+// TABLE-NEXT:    method #AnyProtocol.method!1: {{.*}} : @$S14witness_tables27ConformingAddressOnlyStructVAA11AnyProtocolA2aDP6method{{[_0-9a-zA-Z]*}}FTW
+// TABLE-NEXT:    method #AnyProtocol.generic!1: {{.*}} : @$S14witness_tables27ConformingAddressOnlyStructVAA11AnyProtocolA2aDP7generic{{[_0-9a-zA-Z]*}}FTW
+// TABLE-NEXT:    method #AnyProtocol.assocTypesMethod!1: {{.*}} : @$S14witness_tables27ConformingAddressOnlyStructVAA11AnyProtocolA2aDP16assocTypesMethod{{[_0-9a-zA-Z]*}}FTW
+// TABLE-NEXT:    method #AnyProtocol.staticMethod!1: {{.*}} : @$S14witness_tables27ConformingAddressOnlyStructVAA11AnyProtocolA2aDP12staticMethod{{[_0-9a-zA-Z]*}}FZTW
+// TABLE-NEXT:    method #AnyProtocol."<~>"!1: {{.*}} : @$S14witness_tables27ConformingAddressOnlyStructVAA11AnyProtocolA2aDP3ltgoi{{[_0-9a-zA-Z]*}}FZTW
+// TABLE-NEXT:  }
+// SYMBOL:      sil private [transparent] [thunk] @$S14witness_tables27ConformingAddressOnlyStructVAA11AnyProtocolA2aDP6method{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method: AnyProtocol) (Arg, @in_guaranteed ConformingAddressOnlyStruct, @in_guaranteed ConformingAddressOnlyStruct) -> ()
+// SYMBOL:      sil private [transparent] [thunk] @$S14witness_tables27ConformingAddressOnlyStructVAA11AnyProtocolA2aDP7generic{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method: AnyProtocol) <τ_0_0 where τ_0_0 : ArchetypeReqt> (@in_guaranteed τ_0_0, @in_guaranteed ConformingAddressOnlyStruct, @in_guaranteed ConformingAddressOnlyStruct) -> ()
+// SYMBOL:      sil private [transparent] [thunk] @$S14witness_tables27ConformingAddressOnlyStructVAA11AnyProtocolA2aDP16assocTypesMethod{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method: AnyProtocol) (@in_guaranteed SomeAssoc, @in_guaranteed ConformingAssoc, @in_guaranteed ConformingAddressOnlyStruct) -> ()
+// SYMBOL:      sil private [transparent] [thunk] @$S14witness_tables27ConformingAddressOnlyStructVAA11AnyProtocolA2aDP12staticMethod{{[_0-9a-zA-Z]*}}FZTW : $@convention(witness_method: AnyProtocol) (@in_guaranteed ConformingAddressOnlyStruct, @thick ConformingAddressOnlyStruct.Type) -> ()
+// SYMBOL:      sil private [transparent] [thunk] @$S14witness_tables27ConformingAddressOnlyStructVAA11AnyProtocolA2aDP3ltgoi{{[_0-9a-zA-Z]*}}FZTW : $@convention(witness_method: AnyProtocol) (@in_guaranteed ConformingAddressOnlyStruct, @in_guaranteed ConformingAddressOnlyStruct, @thick ConformingAddressOnlyStruct.Type) -> ()
+
+class ConformingClass : AnyProtocol {
+  typealias AssocType = SomeAssoc
+  typealias AssocWithReqt = ConformingAssoc
+  
+  func method(x: Arg, y: ConformingClass) {}
+  func generic<F: ArchetypeReqt>(x: F, y: ConformingClass) {}
+
+  func assocTypesMethod(x: SomeAssoc, y: ConformingAssoc) {}
+
+  class func staticMethod(x: ConformingClass) {}
+}
+func <~>(x: ConformingClass, y: ConformingClass) {}
+// TABLE-LABEL: sil_witness_table hidden ConformingClass: AnyProtocol module witness_tables {
+// TABLE-NEXT:    associated_type AssocType: SomeAssoc
+// TABLE-NEXT:    associated_type AssocWithReqt: ConformingAssoc
+// TABLE-NEXT:    associated_type_protocol (AssocWithReqt: AssocReqt): ConformingAssoc: AssocReqt module witness_tables
+// TABLE-NEXT:    method #AnyProtocol.method!1: {{.*}} : @$S14witness_tables15ConformingClassCAA11AnyProtocolA2aDP6method{{[_0-9a-zA-Z]*}}FTW
+// TABLE-NEXT:    method #AnyProtocol.generic!1: {{.*}} : @$S14witness_tables15ConformingClassCAA11AnyProtocolA2aDP7generic{{[_0-9a-zA-Z]*}}FTW
+// TABLE-NEXT:    method #AnyProtocol.assocTypesMethod!1: {{.*}} : @$S14witness_tables15ConformingClassCAA11AnyProtocolA2aDP16assocTypesMethod{{[_0-9a-zA-Z]*}}FTW
+// TABLE-NEXT:    method #AnyProtocol.staticMethod!1: {{.*}} : @$S14witness_tables15ConformingClassCAA11AnyProtocolA2aDP12staticMethod{{[_0-9a-zA-Z]*}}FZTW
+// TABLE-NEXT:    method #AnyProtocol."<~>"!1: {{.*}} : @$S14witness_tables15ConformingClassCAA11AnyProtocolA2aDP3ltgoi{{[_0-9a-zA-Z]*}}FZTW
+// TABLE-NEXT:  }
+// SYMBOL:      sil private [transparent] [thunk] @$S14witness_tables15ConformingClassCAA11AnyProtocolA2aDP6method{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method: AnyProtocol) (Arg, @in_guaranteed ConformingClass, @in_guaranteed ConformingClass) -> ()
+// SYMBOL:      sil private [transparent] [thunk] @$S14witness_tables15ConformingClassCAA11AnyProtocolA2aDP7generic{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method: AnyProtocol) <τ_0_0 where τ_0_0 : ArchetypeReqt> (@in_guaranteed τ_0_0, @in_guaranteed ConformingClass, @in_guaranteed ConformingClass) -> ()
+// SYMBOL:      sil private [transparent] [thunk] @$S14witness_tables15ConformingClassCAA11AnyProtocolA2aDP16assocTypesMethod{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method: AnyProtocol) (@in_guaranteed SomeAssoc, @in_guaranteed ConformingAssoc, @in_guaranteed ConformingClass) -> ()
+// SYMBOL:      sil private [transparent] [thunk] @$S14witness_tables15ConformingClassCAA11AnyProtocolA2aDP12staticMethod{{[_0-9a-zA-Z]*}}FZTW : $@convention(witness_method: AnyProtocol) (@in_guaranteed ConformingClass, @thick ConformingClass.Type) -> ()
+// SYMBOL:      sil private [transparent] [thunk] @$S14witness_tables15ConformingClassCAA11AnyProtocolA2aDP3ltgoi{{[_0-9a-zA-Z]*}}FZTW : $@convention(witness_method: AnyProtocol) (@in_guaranteed ConformingClass, @in_guaranteed ConformingClass, @thick ConformingClass.Type) -> ()
+
+struct ConformsByExtension {}
+extension ConformsByExtension : AnyProtocol {
+  typealias AssocType = SomeAssoc
+  typealias AssocWithReqt = ConformingAssoc
+  
+  func method(x: Arg, y: ConformsByExtension) {}
+  func generic<G: ArchetypeReqt>(x: G, y: ConformsByExtension) {}
+
+  func assocTypesMethod(x: SomeAssoc, y: ConformingAssoc) {}
+
+  static func staticMethod(x: ConformsByExtension) {}
+}
+func <~>(x: ConformsByExtension, y: ConformsByExtension) {}
+// TABLE-LABEL: sil_witness_table hidden ConformsByExtension: AnyProtocol module witness_tables {
+// TABLE-NEXT:    associated_type AssocType: SomeAssoc
+// TABLE-NEXT:    associated_type AssocWithReqt: ConformingAssoc
+// TABLE-NEXT:    associated_type_protocol (AssocWithReqt: AssocReqt): ConformingAssoc: AssocReqt module witness_tables
+// TABLE-NEXT:    method #AnyProtocol.method!1: {{.*}} : @$S14witness_tables19ConformsByExtensionVAA11AnyProtocolA2aDP6method{{[_0-9a-zA-Z]*}}FTW
+// TABLE-NEXT:    method #AnyProtocol.generic!1: {{.*}} : @$S14witness_tables19ConformsByExtensionVAA11AnyProtocolA2aDP7generic{{[_0-9a-zA-Z]*}}FTW
+// TABLE-NEXT:    method #AnyProtocol.assocTypesMethod!1: {{.*}} : @$S14witness_tables19ConformsByExtensionVAA11AnyProtocolA2aDP16assocTypesMethod{{[_0-9a-zA-Z]*}}FTW
+// TABLE-NEXT:    method #AnyProtocol.staticMethod!1: {{.*}} : @$S14witness_tables19ConformsByExtensionVAA11AnyProtocolA2aDP12staticMethod{{[_0-9a-zA-Z]*}}FZTW
+// TABLE-NEXT:    method #AnyProtocol."<~>"!1: {{.*}} : @$S14witness_tables19ConformsByExtensionVAA11AnyProtocolA2aDP3ltgoi{{[_0-9a-zA-Z]*}}FZTW
+// TABLE-NEXT:  }
+// SYMBOL:      sil private [transparent] [thunk] @$S14witness_tables19ConformsByExtensionVAA11AnyProtocolA2aDP6method{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method: AnyProtocol) (Arg, @in_guaranteed ConformsByExtension, @in_guaranteed ConformsByExtension) -> ()
+// SYMBOL:      sil private [transparent] [thunk] @$S14witness_tables19ConformsByExtensionVAA11AnyProtocolA2aDP7generic{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method: AnyProtocol) <τ_0_0 where τ_0_0 : ArchetypeReqt> (@in_guaranteed τ_0_0, @in_guaranteed ConformsByExtension, @in_guaranteed ConformsByExtension) -> ()
+// SYMBOL:      sil private [transparent] [thunk] @$S14witness_tables19ConformsByExtensionVAA11AnyProtocolA2aDP16assocTypesMethod{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method: AnyProtocol) (@in_guaranteed SomeAssoc, @in_guaranteed ConformingAssoc, @in_guaranteed ConformsByExtension) -> ()
+// SYMBOL:      sil private [transparent] [thunk] @$S14witness_tables19ConformsByExtensionVAA11AnyProtocolA2aDP12staticMethod{{[_0-9a-zA-Z]*}}FZTW : $@convention(witness_method: AnyProtocol) (@in_guaranteed ConformsByExtension, @thick ConformsByExtension.Type) -> ()
+// SYMBOL:      sil private [transparent] [thunk] @$S14witness_tables19ConformsByExtensionVAA11AnyProtocolA2aDP3ltgoi{{[_0-9a-zA-Z]*}}FZTW : $@convention(witness_method: AnyProtocol) (@in_guaranteed ConformsByExtension, @in_guaranteed ConformsByExtension, @thick ConformsByExtension.Type) -> ()
+
+extension OtherModuleStruct : AnyProtocol {
+  typealias AssocType = SomeAssoc
+  typealias AssocWithReqt = ConformingAssoc
+  
+  func method(x: Arg, y: OtherModuleStruct) {}
+  func generic<H: ArchetypeReqt>(x: H, y: OtherModuleStruct) {}
+
+  func assocTypesMethod(x: SomeAssoc, y: ConformingAssoc) {}
+
+  static func staticMethod(x: OtherModuleStruct) {}
+}
+func <~>(x: OtherModuleStruct, y: OtherModuleStruct) {}
+// TABLE-LABEL: sil_witness_table hidden OtherModuleStruct: AnyProtocol module witness_tables {
+// TABLE-NEXT:    associated_type AssocType: SomeAssoc
+// TABLE-NEXT:    associated_type AssocWithReqt: ConformingAssoc
+// TABLE-NEXT:    associated_type_protocol (AssocWithReqt: AssocReqt): ConformingAssoc: AssocReqt module witness_tables
+// TABLE-NEXT:    method #AnyProtocol.method!1: {{.*}} : @$S16witness_tables_b17OtherModuleStructV0a1_B011AnyProtocolA2dEP6method{{[_0-9a-zA-Z]*}}FTW
+// TABLE-NEXT:    method #AnyProtocol.generic!1: {{.*}} : @$S16witness_tables_b17OtherModuleStructV0a1_B011AnyProtocolA2dEP7generic{{[_0-9a-zA-Z]*}}FTW
+// TABLE-NEXT:    method #AnyProtocol.assocTypesMethod!1: {{.*}} : @$S16witness_tables_b17OtherModuleStructV0a1_B011AnyProtocolA2dEP16assocTypesMethod{{[_0-9a-zA-Z]*}}FTW
+// TABLE-NEXT:    method #AnyProtocol.staticMethod!1: {{.*}} : @$S16witness_tables_b17OtherModuleStructV0a1_B011AnyProtocolA2dEP12staticMethod{{[_0-9a-zA-Z]*}}FZTW
+// TABLE-NEXT:    method #AnyProtocol."<~>"!1: {{.*}} : @$S16witness_tables_b17OtherModuleStructV0a1_B011AnyProtocolA2dEP3ltgoi{{[_0-9a-zA-Z]*}}FZTW
+// TABLE-NEXT:  }
+// SYMBOL:      sil private [transparent] [thunk] @$S16witness_tables_b17OtherModuleStructV0a1_B011AnyProtocolA2dEP6method{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method: AnyProtocol) (Arg, @in_guaranteed OtherModuleStruct, @in_guaranteed OtherModuleStruct) -> ()
+// SYMBOL:      sil private [transparent] [thunk] @$S16witness_tables_b17OtherModuleStructV0a1_B011AnyProtocolA2dEP7generic{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method: AnyProtocol) <τ_0_0 where τ_0_0 : ArchetypeReqt> (@in_guaranteed τ_0_0, @in_guaranteed OtherModuleStruct, @in_guaranteed OtherModuleStruct) -> ()
+// SYMBOL:      sil private [transparent] [thunk] @$S16witness_tables_b17OtherModuleStructV0a1_B011AnyProtocolA2dEP16assocTypesMethod{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method: AnyProtocol) (@in_guaranteed SomeAssoc, @in_guaranteed ConformingAssoc, @in_guaranteed OtherModuleStruct) -> ()
+// SYMBOL:      sil private [transparent] [thunk] @$S16witness_tables_b17OtherModuleStructV0a1_B011AnyProtocolA2dEP12staticMethod{{[_0-9a-zA-Z]*}}FZTW : $@convention(witness_method: AnyProtocol) (@in_guaranteed OtherModuleStruct, @thick OtherModuleStruct.Type) -> ()
+// SYMBOL:      sil private [transparent] [thunk] @$S16witness_tables_b17OtherModuleStructV0a1_B011AnyProtocolA2dEP3ltgoi{{[_0-9a-zA-Z]*}}FZTW : $@convention(witness_method: AnyProtocol) (@in_guaranteed OtherModuleStruct, @in_guaranteed OtherModuleStruct, @thick OtherModuleStruct.Type) -> ()
+
+protocol OtherProtocol {}
+
+struct ConformsWithMoreGenericWitnesses : AnyProtocol, OtherProtocol {
+  typealias AssocType = SomeAssoc
+  typealias AssocWithReqt = ConformingAssoc
+  
+  func method<I, J>(x: I, y: J) {}
+  func generic<K, L>(x: K, y: L) {}
+
+  func assocTypesMethod<M, N>(x: M, y: N) {}
+
+  static func staticMethod<O>(x: O) {}
+}
+func <~> <P: OtherProtocol>(x: P, y: P) {}
+// TABLE-LABEL: sil_witness_table hidden ConformsWithMoreGenericWitnesses: AnyProtocol module witness_tables {
+// TABLE-NEXT:    associated_type AssocType: SomeAssoc
+// TABLE-NEXT:    associated_type AssocWithReqt: ConformingAssoc
+// TABLE-NEXT:    associated_type_protocol (AssocWithReqt: AssocReqt): ConformingAssoc: AssocReqt module witness_tables
+// TABLE-NEXT:    method #AnyProtocol.method!1: {{.*}} : @$S14witness_tables32ConformsWithMoreGenericWitnessesVAA11AnyProtocolA2aDP6method{{[_0-9a-zA-Z]*}}FTW
+// TABLE-NEXT:    method #AnyProtocol.generic!1: {{.*}} : @$S14witness_tables32ConformsWithMoreGenericWitnessesVAA11AnyProtocolA2aDP7generic{{[_0-9a-zA-Z]*}}FTW
+// TABLE-NEXT:    method #AnyProtocol.assocTypesMethod!1: {{.*}} : @$S14witness_tables32ConformsWithMoreGenericWitnessesVAA11AnyProtocolA2aDP16assocTypesMethod{{[_0-9a-zA-Z]*}}FTW
+// TABLE-NEXT:    method #AnyProtocol.staticMethod!1: {{.*}} : @$S14witness_tables32ConformsWithMoreGenericWitnessesVAA11AnyProtocolA2aDP12staticMethod{{[_0-9a-zA-Z]*}}FZTW
+// TABLE-NEXT:    method #AnyProtocol."<~>"!1: {{.*}} : @$S14witness_tables32ConformsWithMoreGenericWitnessesVAA11AnyProtocolA2aDP3ltgoi{{[_0-9a-zA-Z]*}}FZTW
+// TABLE-NEXT:  }
+// SYMBOL:      sil private [transparent] [thunk] @$S14witness_tables32ConformsWithMoreGenericWitnessesVAA11AnyProtocolA2aDP6method{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method: AnyProtocol) (Arg, @in_guaranteed ConformsWithMoreGenericWitnesses, @in_guaranteed ConformsWithMoreGenericWitnesses) -> ()
+// SYMBOL:      sil private [transparent] [thunk] @$S14witness_tables32ConformsWithMoreGenericWitnessesVAA11AnyProtocolA2aDP7generic{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method: AnyProtocol) <τ_0_0 where τ_0_0 : ArchetypeReqt> (@in_guaranteed τ_0_0, @in_guaranteed ConformsWithMoreGenericWitnesses, @in_guaranteed ConformsWithMoreGenericWitnesses) -> ()
+// SYMBOL:      sil private [transparent] [thunk] @$S14witness_tables32ConformsWithMoreGenericWitnessesVAA11AnyProtocolA2aDP16assocTypesMethod{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method: AnyProtocol) (@in_guaranteed SomeAssoc, @in_guaranteed ConformingAssoc, @in_guaranteed ConformsWithMoreGenericWitnesses) -> ()
+// SYMBOL:      sil private [transparent] [thunk] @$S14witness_tables32ConformsWithMoreGenericWitnessesVAA11AnyProtocolA2aDP12staticMethod{{[_0-9a-zA-Z]*}}FZTW : $@convention(witness_method: AnyProtocol) (@in_guaranteed ConformsWithMoreGenericWitnesses, @thick ConformsWithMoreGenericWitnesses.Type) -> ()
+// SYMBOL:      sil private [transparent] [thunk] @$S14witness_tables32ConformsWithMoreGenericWitnessesVAA11AnyProtocolA2aDP3ltgoi{{[_0-9a-zA-Z]*}}FZTW : $@convention(witness_method: AnyProtocol) (@in_guaranteed ConformsWithMoreGenericWitnesses, @in_guaranteed ConformsWithMoreGenericWitnesses, @thick ConformsWithMoreGenericWitnesses.Type) -> ()
+
+class ConformingClassToClassProtocol : ClassProtocol {
+  typealias AssocType = SomeAssoc
+  typealias AssocWithReqt = ConformingAssoc
+  
+  func method(x: Arg, y: ConformingClassToClassProtocol) {}
+  func generic<Q: ArchetypeReqt>(x: Q, y: ConformingClassToClassProtocol) {}
+
+  func assocTypesMethod(x: SomeAssoc, y: ConformingAssoc) {}
+
+  class func staticMethod(x: ConformingClassToClassProtocol) {}
+}
+func <~>(x: ConformingClassToClassProtocol,
+         y: ConformingClassToClassProtocol) {}
+// TABLE-LABEL: sil_witness_table hidden ConformingClassToClassProtocol: ClassProtocol module witness_tables {
+// TABLE-NEXT:    associated_type AssocType: SomeAssoc
+// TABLE-NEXT:    associated_type AssocWithReqt: ConformingAssoc
+// TABLE-NEXT:    associated_type_protocol (AssocWithReqt: AssocReqt): ConformingAssoc: AssocReqt module witness_tables
+// TABLE-NEXT:    method #ClassProtocol.method!1: {{.*}} : @$S14witness_tables017ConformingClassToD8ProtocolCAA0dF0A2aDP6method{{[_0-9a-zA-Z]*}}FTW
+// TABLE-NEXT:    method #ClassProtocol.generic!1: {{.*}} : @$S14witness_tables017ConformingClassToD8ProtocolCAA0dF0A2aDP7generic{{[_0-9a-zA-Z]*}}FTW
+// TABLE-NEXT:    method #ClassProtocol.assocTypesMethod!1: {{.*}} : @$S14witness_tables017ConformingClassToD8ProtocolCAA0dF0A2aDP16assocTypesMethod{{[_0-9a-zA-Z]*}}FTW
+// TABLE-NEXT:    method #ClassProtocol.staticMethod!1: {{.*}} : @$S14witness_tables017ConformingClassToD8ProtocolCAA0dF0A2aDP12staticMethod{{[_0-9a-zA-Z]*}}FZTW
+// TABLE-NEXT:    method #ClassProtocol."<~>"!1: {{.*}} : @$S14witness_tables017ConformingClassToD8ProtocolCAA0dF0A2aDP3ltgoi{{[_0-9a-zA-Z]*}}FZTW
+// TABLE-NEXT:  }
+// SYMBOL:  sil private [transparent] [thunk] @$S14witness_tables017ConformingClassToD8ProtocolCAA0dF0A2aDP6method{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method: ClassProtocol) (Arg, @guaranteed ConformingClassToClassProtocol, @guaranteed ConformingClassToClassProtocol) -> ()
+// SYMBOL:  sil private [transparent] [thunk] @$S14witness_tables017ConformingClassToD8ProtocolCAA0dF0A2aDP7generic{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method: ClassProtocol) <τ_0_0 where τ_0_0 : ArchetypeReqt> (@in_guaranteed τ_0_0, @guaranteed ConformingClassToClassProtocol, @guaranteed ConformingClassToClassProtocol) -> ()
+// SYMBOL:  sil private [transparent] [thunk] @$S14witness_tables017ConformingClassToD8ProtocolCAA0dF0A2aDP16assocTypesMethod{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method: ClassProtocol) (@in_guaranteed SomeAssoc, @in_guaranteed ConformingAssoc, @guaranteed ConformingClassToClassProtocol) -> ()
+// SYMBOL:  sil private [transparent] [thunk] @$S14witness_tables017ConformingClassToD8ProtocolCAA0dF0A2aDP12staticMethod{{[_0-9a-zA-Z]*}}FZTW : $@convention(witness_method: ClassProtocol) (@guaranteed ConformingClassToClassProtocol, @thick ConformingClassToClassProtocol.Type) -> ()
+// SYMBOL:  sil private [transparent] [thunk] @$S14witness_tables017ConformingClassToD8ProtocolCAA0dF0A2aDP3ltgoi{{[_0-9a-zA-Z]*}}FZTW : $@convention(witness_method: ClassProtocol) (@guaranteed ConformingClassToClassProtocol, @guaranteed ConformingClassToClassProtocol, @thick ConformingClassToClassProtocol.Type) -> ()
+
+class ConformingClassToObjCProtocol : ObjCProtocol {
+  @objc func method(x: ObjCClass) {}
+  @objc class func staticMethod(y: ObjCClass) {}
+}
+// TABLE-NOT:  sil_witness_table hidden ConformingClassToObjCProtocol
+
+struct ConformingGeneric<R: AssocReqt> : AnyProtocol {
+  typealias AssocType = SomeAssoc
+  typealias AssocWithReqt = R
+
+  func method(x: Arg, y: ConformingGeneric) {}
+  func generic<Q: ArchetypeReqt>(x: Q, y: ConformingGeneric) {}
+
+  func assocTypesMethod(x: SomeAssoc, y: R) {}
+
+  static func staticMethod(x: ConformingGeneric) {}
+}
+func <~> <R: AssocReqt>(x: ConformingGeneric<R>, y: ConformingGeneric<R>) {}
+// TABLE-LABEL: sil_witness_table hidden <R where R : AssocReqt> ConformingGeneric<R>: AnyProtocol module witness_tables {
+// TABLE-NEXT:    associated_type AssocType: SomeAssoc
+// TABLE-NEXT:    associated_type AssocWithReqt: R
+// TABLE-NEXT:    associated_type_protocol (AssocWithReqt: AssocReqt): dependent
+// TABLE-NEXT:    method #AnyProtocol.method!1: {{.*}} : @$S14witness_tables17ConformingGenericVyxGAA11AnyProtocolA2aEP6method{{[_0-9a-zA-Z]*}}FTW
+// TABLE-NEXT:    method #AnyProtocol.generic!1: {{.*}} : @$S14witness_tables17ConformingGenericVyxGAA11AnyProtocolA2aEP7generic{{[_0-9a-zA-Z]*}}FTW
+// TABLE-NEXT:    method #AnyProtocol.assocTypesMethod!1: {{.*}} : @$S14witness_tables17ConformingGenericVyxGAA11AnyProtocolA2aEP16assocTypesMetho{{[_0-9a-zA-Z]*}}FTW
+// TABLE-NEXT:    method #AnyProtocol.staticMethod!1: {{.*}} : @$S14witness_tables17ConformingGenericVyxGAA11AnyProtocolA2aEP12staticMethod{{[_0-9a-zA-Z]*}}FZTW
+// TABLE-NEXT:    method #AnyProtocol."<~>"!1: {{.*}} : @$S14witness_tables17ConformingGenericVyxGAA11AnyProtocolA2aEP3ltgoi{{[_0-9a-zA-Z]*}}FZTW
+// TABLE-NEXT:  }
+
+protocol AnotherProtocol {}
+
+struct ConformingGenericWithMoreGenericWitnesses<S: AssocReqt>
+  : AnyProtocol, AnotherProtocol
+{
+  typealias AssocType = SomeAssoc
+  typealias AssocWithReqt = S
+
+  func method<T, U>(x: T, y: U) {}
+  func generic<V, W>(x: V, y: W) {}
+
+  func assocTypesMethod<X, Y>(x: X, y: Y) {}
+
+  static func staticMethod<Z>(x: Z) {}
+}
+func <~> <AA: AnotherProtocol, BB: AnotherProtocol>(x: AA, y: BB) {}
+// TABLE-LABEL: sil_witness_table hidden <S where S : AssocReqt> ConformingGenericWithMoreGenericWitnesses<S>: AnyProtocol module witness_tables {
+// TABLE-NEXT:    associated_type AssocType: SomeAssoc
+// TABLE-NEXT:    associated_type AssocWithReqt: S
+// TABLE-NEXT:    associated_type_protocol (AssocWithReqt: AssocReqt): dependent
+// TABLE-NEXT:    method #AnyProtocol.method!1: {{.*}} : @$S14witness_tables025ConformingGenericWithMoreD9WitnessesVyxGAA11AnyProtocolA2aEP6method{{[_0-9a-zA-Z]*}}FTW
+// TABLE-NEXT:    method #AnyProtocol.generic!1: {{.*}} : @$S14witness_tables025ConformingGenericWithMoreD9WitnessesVyxGAA11AnyProtocolA2aEP7{{[_0-9a-zA-Z]*}}FTW
+// TABLE-NEXT:    method #AnyProtocol.assocTypesMethod!1: {{.*}} : @$S14witness_tables025ConformingGenericWithMoreD9WitnessesVyxGAA11AnyProtocolA2aEP16assocTypesMethod{{[_0-9a-zA-Z]*}}FTW
+// TABLE-NEXT:    method #AnyProtocol.staticMethod!1: {{.*}} : @$S14witness_tables025ConformingGenericWithMoreD9WitnessesVyxGAA11AnyProtocolA2aEP12staticMethod{{[_0-9a-zA-Z]*}}FZTW
+// TABLE-NEXT:    method #AnyProtocol."<~>"!1: {{.*}} : @$S14witness_tables025ConformingGenericWithMoreD9WitnessesVyxGAA11AnyProtocolA2aEP3ltgoi{{[_0-9a-zA-Z]*}}FZTW
+// TABLE-NEXT:  }
+
+protocol InheritedProtocol1 : AnyProtocol {
+  func inheritedMethod()
+}
+
+protocol InheritedProtocol2 : AnyProtocol {
+  func inheritedMethod()
+}
+
+protocol InheritedClassProtocol : class, AnyProtocol {
+  func inheritedMethod()
+}
+
+struct InheritedConformance : InheritedProtocol1 {
+  typealias AssocType = SomeAssoc
+  typealias AssocWithReqt = ConformingAssoc
+
+  func method(x: Arg, y: InheritedConformance) {}
+  func generic<H: ArchetypeReqt>(x: H, y: InheritedConformance) {}
+
+  func assocTypesMethod(x: SomeAssoc, y: ConformingAssoc) {}
+
+  static func staticMethod(x: InheritedConformance) {}
+
+  func inheritedMethod() {}
+}
+func <~>(x: InheritedConformance, y: InheritedConformance) {}
+// TABLE-LABEL: sil_witness_table hidden InheritedConformance: InheritedProtocol1 module witness_tables {
+// TABLE-NEXT:    base_protocol AnyProtocol: InheritedConformance: AnyProtocol module witness_tables
+// TABLE-NEXT:    method #InheritedProtocol1.inheritedMethod!1: {{.*}} : @$S14witness_tables20InheritedConformanceVAA0C9Protocol1A2aDP15inheritedMethod{{[_0-9a-zA-Z]*}}FTW
+// TABLE-NEXT:  }
+// TABLE-LABEL: sil_witness_table hidden InheritedConformance: AnyProtocol module witness_tables {
+// TABLE-NEXT:    associated_type AssocType: SomeAssoc
+// TABLE-NEXT:    associated_type AssocWithReqt: ConformingAssoc
+// TABLE-NEXT:    associated_type_protocol (AssocWithReqt: AssocReqt): ConformingAssoc: AssocReqt module witness_tables
+// TABLE-NEXT:    method #AnyProtocol.method!1: {{.*}} : @$S14witness_tables20InheritedConformanceVAA11AnyProtocolA2aDP6method{{[_0-9a-zA-Z]*}}FTW
+// TABLE-NEXT:    method #AnyProtocol.generic!1: {{.*}} : @$S14witness_tables20InheritedConformanceVAA11AnyProtocolA2aDP7generic{{[_0-9a-zA-Z]*}}FTW
+// TABLE-NEXT:    method #AnyProtocol.assocTypesMethod!1: {{.*}} : @$S14witness_tables20InheritedConformanceVAA11AnyProtocolA2aDP16assocTypesMethod{{[_0-9a-zA-Z]*}}FTW
+// TABLE-NEXT:    method #AnyProtocol.staticMethod!1: {{.*}} : @$S14witness_tables20InheritedConformanceVAA11AnyProtocolA2aDP12staticMethod{{[_0-9a-zA-Z]*}}FZTW
+// TABLE-NEXT:    method #AnyProtocol."<~>"!1: {{.*}} : @$S14witness_tables20InheritedConformanceVAA11AnyProtocolA2aDP3ltgoi{{[_0-9a-zA-Z]*}}FZTW
+// TABLE-NEXT:  }
+
+struct RedundantInheritedConformance : InheritedProtocol1, AnyProtocol {
+  typealias AssocType = SomeAssoc
+  typealias AssocWithReqt = ConformingAssoc
+
+  func method(x: Arg, y: RedundantInheritedConformance) {}
+  func generic<H: ArchetypeReqt>(x: H, y: RedundantInheritedConformance) {}
+
+  func assocTypesMethod(x: SomeAssoc, y: ConformingAssoc) {}
+
+  static func staticMethod(x: RedundantInheritedConformance) {}
+
+  func inheritedMethod() {}
+}
+func <~>(x: RedundantInheritedConformance, y: RedundantInheritedConformance) {}
+// TABLE-LABEL: sil_witness_table hidden RedundantInheritedConformance: InheritedProtocol1 module witness_tables {
+// TABLE-NEXT:    base_protocol AnyProtocol: RedundantInheritedConformance: AnyProtocol module witness_tables
+// TABLE-NEXT:    method #InheritedProtocol1.inheritedMethod!1: {{.*}} : @$S14witness_tables29RedundantInheritedConformanceVAA0D9Protocol1A2aDP15inheritedMethod{{[_0-9a-zA-Z]*}}FTW
+// TABLE-NEXT:  }
+// TABLE-LABEL: sil_witness_table hidden RedundantInheritedConformance: AnyProtocol module witness_tables {
+// TABLE-NEXT:    associated_type AssocType: SomeAssoc
+// TABLE-NEXT:    associated_type AssocWithReqt: ConformingAssoc
+// TABLE-NEXT:    associated_type_protocol (AssocWithReqt: AssocReqt): ConformingAssoc: AssocReqt module witness_tables
+// TABLE-NEXT:    method #AnyProtocol.method!1: {{.*}} : @$S14witness_tables29RedundantInheritedConformanceVAA11AnyProtocolA2aDP6method{{[_0-9a-zA-Z]*}}FTW
+// TABLE-NEXT:    method #AnyProtocol.generic!1: {{.*}} : @$S14witness_tables29RedundantInheritedConformanceVAA11AnyProtocolA2aDP7generic{{[_0-9a-zA-Z]*}}FTW
+// TABLE-NEXT:    method #AnyProtocol.assocTypesMethod!1: {{.*}} : @$S14witness_tables29RedundantInheritedConformanceVAA11AnyProtocolA2aDP16assocTypesMethod{{[_0-9a-zA-Z]*}}FTW
+// TABLE-NEXT:    method #AnyProtocol.staticMethod!1: {{.*}} : @$S14witness_tables29RedundantInheritedConformanceVAA11AnyProtocolA2aDP12staticMethod{{[_0-9a-zA-Z]*}}FZTW
+// TABLE-NEXT:    method #AnyProtocol."<~>"!1: {{.*}} : @$S14witness_tables29RedundantInheritedConformanceVAA11AnyProtocolA2aDP3ltgoi{{[_0-9a-zA-Z]*}}FZTW
+// TABLE-NEXT:  }
+
+struct DiamondInheritedConformance : InheritedProtocol1, InheritedProtocol2 {
+  typealias AssocType = SomeAssoc
+  typealias AssocWithReqt = ConformingAssoc
+
+  func method(x: Arg, y: DiamondInheritedConformance) {}
+  func generic<H: ArchetypeReqt>(x: H, y: DiamondInheritedConformance) {}
+
+  func assocTypesMethod(x: SomeAssoc, y: ConformingAssoc) {}
+
+  static func staticMethod(x: DiamondInheritedConformance) {}
+
+  func inheritedMethod() {}
+}
+func <~>(x: DiamondInheritedConformance, y: DiamondInheritedConformance) {}
+// TABLE-LABEL: sil_witness_table hidden DiamondInheritedConformance: InheritedProtocol1 module witness_tables {
+// TABLE-NEXT:    base_protocol AnyProtocol: DiamondInheritedConformance: AnyProtocol module witness_tables
+// TABLE-NEXT:    method #InheritedProtocol1.inheritedMethod!1: {{.*}} : @$S14witness_tables27DiamondInheritedConformanceVAA0D9Protocol1A2aDP15inheritedMethod{{[_0-9a-zA-Z]*}}FTW
+// TABLE-NEXT:  }
+// TABLE-LABEL: sil_witness_table hidden DiamondInheritedConformance: InheritedProtocol2 module witness_tables {
+// TABLE-NEXT:    base_protocol AnyProtocol: DiamondInheritedConformance: AnyProtocol module witness_tables
+// TABLE-NEXT:    method #InheritedProtocol2.inheritedMethod!1: {{.*}} : @$S14witness_tables27DiamondInheritedConformanceVAA0D9Protocol2A2aDP15inheritedMethod{{[_0-9a-zA-Z]*}}FTW
+// TABLE-NEXT:  }
+// TABLE-LABEL: sil_witness_table hidden DiamondInheritedConformance: AnyProtocol module witness_tables {
+// TABLE-NEXT:    associated_type AssocType: SomeAssoc
+// TABLE-NEXT:    associated_type AssocWithReqt: ConformingAssoc
+// TABLE-NEXT:    associated_type_protocol (AssocWithReqt: AssocReqt): ConformingAssoc: AssocReqt module witness_tables
+// TABLE-NEXT:    method #AnyProtocol.method!1: {{.*}} : @$S14witness_tables27DiamondInheritedConformanceVAA11AnyProtocolA2aDP6method{{[_0-9a-zA-Z]*}}FTW
+// TABLE-NEXT:    method #AnyProtocol.generic!1: {{.*}} : @$S14witness_tables27DiamondInheritedConformanceVAA11AnyProtocolA2aDP7generic{{[_0-9a-zA-Z]*}}FTW
+// TABLE-NEXT:    method #AnyProtocol.assocTypesMethod!1: {{.*}} : @$S14witness_tables27DiamondInheritedConformanceVAA11AnyProtocolA2aDP16assocTypesMethod{{[_0-9a-zA-Z]*}}FTW
+// TABLE-NEXT:    method #AnyProtocol.staticMethod!1: {{.*}} : @$S14witness_tables27DiamondInheritedConformanceVAA11AnyProtocolA2aDP12staticMethod{{[_0-9a-zA-Z]*}}FZTW
+// TABLE-NEXT:    method #AnyProtocol."<~>"!1: {{.*}} : @$S14witness_tables27DiamondInheritedConformanceVAA11AnyProtocolA2aDP3ltgoi{{[_0-9a-zA-Z]*}}FZTW
+// TABLE-NEXT:  }
+
+class ClassInheritedConformance : InheritedClassProtocol {
+  typealias AssocType = SomeAssoc
+  typealias AssocWithReqt = ConformingAssoc
+
+  func method(x: Arg, y: ClassInheritedConformance) {}
+  func generic<H: ArchetypeReqt>(x: H, y: ClassInheritedConformance) {}
+
+  func assocTypesMethod(x: SomeAssoc, y: ConformingAssoc) {}
+
+  class func staticMethod(x: ClassInheritedConformance) {}
+
+  func inheritedMethod() {}
+}
+func <~>(x: ClassInheritedConformance, y: ClassInheritedConformance) {}
+// TABLE-LABEL: sil_witness_table hidden ClassInheritedConformance: InheritedClassProtocol module witness_tables {
+// TABLE-NEXT:    base_protocol AnyProtocol: ClassInheritedConformance: AnyProtocol module witness_tables
+// TABLE-NEXT:    method #InheritedClassProtocol.inheritedMethod!1: {{.*}} : @$S14witness_tables25ClassInheritedConformanceCAA0dC8ProtocolA2aDP15inheritedMethod{{[_0-9a-zA-Z]*}}FTW
+// TABLE-NEXT:  }
+// TABLE-LABEL: sil_witness_table hidden ClassInheritedConformance: AnyProtocol module witness_tables {
+// TABLE-NEXT:    associated_type AssocType: SomeAssoc
+// TABLE-NEXT:    associated_type AssocWithReqt: ConformingAssoc
+// TABLE-NEXT:    associated_type_protocol (AssocWithReqt: AssocReqt): ConformingAssoc: AssocReqt module witness_tables
+// TABLE-NEXT:    method #AnyProtocol.method!1: {{.*}} : @$S14witness_tables25ClassInheritedConformanceCAA11AnyProtocolA2aDP6method{{[_0-9a-zA-Z]*}}FTW
+// TABLE-NEXT:    method #AnyProtocol.generic!1: {{.*}} : @$S14witness_tables25ClassInheritedConformanceCAA11AnyProtocolA2aDP7generic{{[_0-9a-zA-Z]*}}FTW
+// TABLE-NEXT:    method #AnyProtocol.assocTypesMethod!1: {{.*}} : @$S14witness_tables25ClassInheritedConformanceCAA11AnyProtocolA2aDP16assocTypesMethod{{[_0-9a-zA-Z]*}}FTW
+// TABLE-NEXT:    method #AnyProtocol.staticMethod!1: {{.*}} : @$S14witness_tables25ClassInheritedConformanceCAA11AnyProtocolA2aDP12staticMethod{{[_0-9a-zA-Z]*}}FZTW
+// TABLE-NEXT:    method #AnyProtocol."<~>"!1: {{.*}} : @$S14witness_tables25ClassInheritedConformanceCAA11AnyProtocolA2aDP3ltgoi{{[_0-9a-zA-Z]*}}FZTW
+// TABLE-NEXT:  }
+// -- Witnesses have the 'self' abstraction level of their protocol.
+//    AnyProtocol has no class bound, so its witnesses treat Self as opaque.
+//    InheritedClassProtocol has a class bound, so its witnesses treat Self as
+//    a reference value.
+// SYMBOL:      sil private [transparent] [thunk] @$S14witness_tables25ClassInheritedConformanceCAA0dC8ProtocolA2aDP15inheritedMethod{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method: InheritedClassProtocol) (@guaranteed ClassInheritedConformance) -> ()
+// SYMBOL:      sil private [transparent] [thunk] @$S14witness_tables25ClassInheritedConformanceCAA11AnyProtocolA2aDP6method{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method: AnyProtocol) (Arg, @in_guaranteed ClassInheritedConformance, @in_guaranteed ClassInheritedConformance) -> ()
+
+struct GenericAssocType<T> : AssocReqt {
+  func requiredMethod() {}
+}
+
+protocol AssocTypeWithReqt {
+  associatedtype AssocType : AssocReqt
+}
+
+struct ConformsWithDependentAssocType1<CC: AssocReqt> : AssocTypeWithReqt {
+  typealias AssocType = CC
+}
+// TABLE-LABEL: sil_witness_table hidden <CC where CC : AssocReqt> ConformsWithDependentAssocType1<CC>: AssocTypeWithReqt module witness_tables {
+// TABLE-NEXT:    associated_type AssocType: CC
+// TABLE-NEXT:    associated_type_protocol (AssocType: AssocReqt): dependent
+// TABLE-NEXT:  }
+
+struct ConformsWithDependentAssocType2<DD> : AssocTypeWithReqt {
+  typealias AssocType = GenericAssocType<DD>
+}
+// TABLE-LABEL: sil_witness_table hidden <DD> ConformsWithDependentAssocType2<DD>: AssocTypeWithReqt module witness_tables {
+// TABLE-NEXT:    associated_type AssocType: GenericAssocType<DD>
+// TABLE-NEXT:    associated_type_protocol (AssocType: AssocReqt): <T> GenericAssocType<T>: AssocReqt module witness_tables
+// TABLE-NEXT:  }
+
+protocol InheritedFromObjC : ObjCProtocol {
+  func inheritedMethod()
+}
+
+class ConformsInheritedFromObjC : InheritedFromObjC {
+  @objc func method(x: ObjCClass) {}
+  @objc class func staticMethod(y: ObjCClass) {}
+  func inheritedMethod() {}
+}
+// TABLE-LABEL: sil_witness_table hidden ConformsInheritedFromObjC: InheritedFromObjC module witness_tables {
+// TABLE-NEXT:    method #InheritedFromObjC.inheritedMethod!1: {{.*}} : @$S14witness_tables25ConformsInheritedFromObjCCAA0deF1CA2aDP15inheritedMethod{{[_0-9a-zA-Z]*}}FTW
+// TABLE-NEXT:  }
+
+protocol ObjCAssoc {
+  associatedtype AssocType : ObjCProtocol
+}
+
+struct HasObjCAssoc : ObjCAssoc {
+  typealias AssocType = ConformsInheritedFromObjC
+}
+// TABLE-LABEL: sil_witness_table hidden HasObjCAssoc: ObjCAssoc module witness_tables {
+// TABLE-NEXT:    associated_type AssocType: ConformsInheritedFromObjC
+// TABLE-NEXT:  }
+
+protocol Initializer {
+  init(arg: Arg)
+}
+
+// TABLE-LABEL: sil_witness_table hidden HasInitializerStruct: Initializer module witness_tables {
+// TABLE-NEXT:  method #Initializer.init!allocator.1: {{.*}} : @$S14witness_tables20HasInitializerStructVAA0D0A2aDP{{[_0-9a-zA-Z]*}}fCTW
+// TABLE-NEXT: }
+// SYMBOL: sil private [transparent] [thunk] @$S14witness_tables20HasInitializerStructVAA0D0A2aDP{{[_0-9a-zA-Z]*}}fCTW : $@convention(witness_method: Initializer) (Arg, @thick HasInitializerStruct.Type) -> @out HasInitializerStruct
+struct HasInitializerStruct : Initializer { 
+  init(arg: Arg) { }
+}
+
+// TABLE-LABEL: sil_witness_table hidden HasInitializerClass: Initializer module witness_tables {
+// TABLE-NEXT:  method #Initializer.init!allocator.1: {{.*}} : @$S14witness_tables19HasInitializerClassCAA0D0A2aDP{{[_0-9a-zA-Z]*}}fCTW
+// TABLE-NEXT: }
+// SYMBOL: sil private [transparent] [thunk] @$S14witness_tables19HasInitializerClassCAA0D0A2aDP{{[_0-9a-zA-Z]*}}fCTW : $@convention(witness_method: Initializer) (Arg, @thick HasInitializerClass.Type) -> @out HasInitializerClass
+class HasInitializerClass : Initializer {
+  required init(arg: Arg) { }
+}
+
+// TABLE-LABEL: sil_witness_table hidden HasInitializerEnum: Initializer module witness_tables {
+// TABLE-NEXT:  method #Initializer.init!allocator.1: {{.*}} : @$S14witness_tables18HasInitializerEnumOAA0D0A2aDP{{[_0-9a-zA-Z]*}}fCTW
+// TABLE-NEXT: }
+// SYMBOL: sil private [transparent] [thunk] @$S14witness_tables18HasInitializerEnumOAA0D0A2aDP{{[_0-9a-zA-Z]*}}fCTW : $@convention(witness_method: Initializer) (Arg, @thick HasInitializerEnum.Type) -> @out HasInitializerEnum
+enum HasInitializerEnum : Initializer {
+  case A
+
+  init(arg: Arg) { self = .A }
+}
+  
diff --git a/test/SILGen/plus_zero_witnesses.swift b/test/SILGen/plus_zero_witnesses.swift
new file mode 100644
index 0000000..f618418
--- /dev/null
+++ b/test/SILGen/plus_zero_witnesses.swift
@@ -0,0 +1,513 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -Xllvm -sil-full-demangle -emit-silgen %s -disable-objc-attr-requires-foundation-module -enable-sil-ownership | %FileCheck %s
+
+infix operator <~> {}
+
+func archetype_method<T: X>(x: T, y: T) -> T {
+  var x = x
+  var y = y
+  return x.selfTypes(x: y)
+}
+// CHECK-LABEL: sil hidden @$S9witnesses16archetype_method{{[_0-9a-zA-Z]*}}F{{.*}} : $@convention(thin) <T where T : X> (@in_guaranteed T, @in_guaranteed T) -> @out T {
+// CHECK:         [[METHOD:%.*]] = witness_method $T, #X.selfTypes!1 : {{.*}} : $@convention(witness_method: X) <τ_0_0 where τ_0_0 : X> (@in_guaranteed τ_0_0, @inout τ_0_0) -> @out τ_0_0
+// CHECK:         apply [[METHOD]]<T>({{%.*}}, {{%.*}}, {{%.*}}) : $@convention(witness_method: X) <τ_0_0 where τ_0_0 : X> (@in_guaranteed τ_0_0, @inout τ_0_0) -> @out τ_0_0
+// CHECK:       }
+
+func archetype_generic_method<T: X>(x: T, y: Loadable) -> Loadable {
+  var x = x
+  return x.generic(x: y)
+}
+// CHECK-LABEL: sil hidden @$S9witnesses24archetype_generic_method{{[_0-9a-zA-Z]*}}F{{.*}} : $@convention(thin) <T where T : X> (@in_guaranteed T, Loadable) -> Loadable {
+// CHECK:         [[METHOD:%.*]] = witness_method $T, #X.generic!1 : {{.*}} : $@convention(witness_method: X) <τ_0_0 where τ_0_0 : X><τ_1_0> (@in_guaranteed τ_1_0, @inout τ_0_0) -> @out τ_1_0
+// CHECK:         apply [[METHOD]]<T, Loadable>({{%.*}}, {{%.*}}, {{%.*}}) : $@convention(witness_method: X) <τ_0_0 where τ_0_0 : X><τ_1_0> (@in_guaranteed τ_1_0, @inout τ_0_0) -> @out τ_1_0
+// CHECK:       }
+
+// CHECK-LABEL: sil hidden @$S9witnesses32archetype_associated_type_method{{[_0-9a-zA-Z]*}}F : $@convention(thin) <T where T : WithAssoc> (@in_guaranteed T, @in_guaranteed T.AssocType) -> @out T
+// CHECK:         apply %{{[0-9]+}}<T>
+func archetype_associated_type_method<T: WithAssoc>(x: T, y: T.AssocType) -> T {
+  return x.useAssocType(x: y)
+}
+
+protocol StaticMethod { static func staticMethod() }
+
+// CHECK-LABEL: sil hidden @$S9witnesses23archetype_static_method{{[_0-9a-zA-Z]*}}F : $@convention(thin) <T where T : StaticMethod> (@in_guaranteed T) -> ()
+func archetype_static_method<T: StaticMethod>(x: T) {
+  // CHECK: [[METHOD:%.*]] = witness_method $T, #StaticMethod.staticMethod!1 : {{.*}} : $@convention(witness_method: StaticMethod) <τ_0_0 where τ_0_0 : StaticMethod> (@thick τ_0_0.Type) -> ()
+  // CHECK: apply [[METHOD]]<T>
+  T.staticMethod()
+}
+
+protocol Existentiable {
+  func foo() -> Loadable
+  func generic<T>() -> T
+}
+
+func protocol_method(x: Existentiable) -> Loadable {
+  return x.foo()
+}
+// CHECK-LABEL: sil hidden @$S9witnesses15protocol_method1xAA8LoadableVAA13Existentiable_p_tF : $@convention(thin) (@in_guaranteed Existentiable) -> Loadable {
+// CHECK:         [[METHOD:%.*]] = witness_method $[[OPENED:@opened(.*) Existentiable]], #Existentiable.foo!1
+// CHECK:         apply [[METHOD]]<[[OPENED]]>({{%.*}})
+// CHECK:       }
+
+func protocol_generic_method(x: Existentiable) -> Loadable {
+  return x.generic()
+}
+// CHECK-LABEL: sil hidden @$S9witnesses23protocol_generic_method1xAA8LoadableVAA13Existentiable_p_tF : $@convention(thin) (@in_guaranteed Existentiable) -> Loadable {
+// CHECK:         [[METHOD:%.*]] = witness_method $[[OPENED:@opened(.*) Existentiable]], #Existentiable.generic!1
+// CHECK:         apply [[METHOD]]<[[OPENED]], Loadable>({{%.*}}, {{%.*}})
+// CHECK:       }
+
+@objc protocol ObjCAble {
+  func foo()
+}
+
+// CHECK-LABEL: sil hidden @$S9witnesses20protocol_objc_method1xyAA8ObjCAble_p_tF : $@convention(thin) (@guaranteed ObjCAble) -> ()
+// CHECK:         objc_method {{%.*}} : $@opened({{.*}}) ObjCAble, #ObjCAble.foo!1.foreign
+func protocol_objc_method(x: ObjCAble) {
+  x.foo()
+}
+
+struct Loadable {}
+protocol AddrOnly {}
+protocol Classes : class {}
+
+protocol X {
+  mutating
+  func selfTypes(x: Self) -> Self
+  mutating
+  func loadable(x: Loadable) -> Loadable
+  mutating
+  func addrOnly(x: AddrOnly) -> AddrOnly
+  mutating
+  func generic<A>(x: A) -> A
+  mutating
+  func classes<A2: Classes>(x: A2) -> A2
+  static func <~>(_ x: Self, y: Self) -> Self
+}
+protocol Y {}
+
+protocol WithAssoc {
+  associatedtype AssocType
+  func useAssocType(x: AssocType) -> Self
+}
+
+protocol ClassBounded : class {
+  func selfTypes(x: Self) -> Self
+}
+
+struct ConformingStruct : X {
+  mutating
+  func selfTypes(x: ConformingStruct) -> ConformingStruct { return x }
+  // CHECK-LABEL: sil private [transparent] [thunk] @$S9witnesses16ConformingStructVAA1XA2aDP9selfTypes{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method: X) (@in_guaranteed ConformingStruct, @inout ConformingStruct) -> @out ConformingStruct {
+  // CHECK:       bb0(%0 : @trivial $*ConformingStruct, %1 : @trivial $*ConformingStruct, %2 : @trivial $*ConformingStruct):
+  // CHECK-NEXT:    %3 = load [trivial] %1 : $*ConformingStruct
+  // CHECK-NEXT:    // function_ref
+  // CHECK-NEXT:    %4 = function_ref @$S9witnesses16ConformingStructV9selfTypes{{[_0-9a-zA-Z]*}}F : $@convention(method) (ConformingStruct, @inout ConformingStruct) -> ConformingStruct
+  // CHECK-NEXT:    %5 = apply %4(%3, %2) : $@convention(method) (ConformingStruct, @inout ConformingStruct) -> ConformingStruct
+  // CHECK-NEXT:    store %5 to [trivial] %0 : $*ConformingStruct
+  // CHECK-NEXT:    %7 = tuple ()
+  // CHECK-NEXT:    return %7 : $()
+  // CHECK-NEXT:  }
+  
+  mutating
+  func loadable(x: Loadable) -> Loadable { return x }
+  // CHECK-LABEL: sil private [transparent] [thunk] @$S9witnesses16ConformingStructVAA1XA2aDP8loadable{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method: X) (Loadable, @inout ConformingStruct) -> Loadable {
+  // CHECK:       bb0(%0 : @trivial $Loadable, %1 : @trivial $*ConformingStruct):
+  // CHECK-NEXT:    // function_ref
+  // CHECK-NEXT:    %2 = function_ref @$S9witnesses16ConformingStructV8loadable{{[_0-9a-zA-Z]*}}F : $@convention(method) (Loadable, @inout ConformingStruct) -> Loadable
+  // CHECK-NEXT:    %3 = apply %2(%0, %1) : $@convention(method) (Loadable, @inout ConformingStruct) -> Loadable
+  // CHECK-NEXT:    return %3 : $Loadable
+  // CHECK-NEXT:  }
+  
+  mutating
+  func addrOnly(x: AddrOnly) -> AddrOnly { return x }
+  // CHECK-LABEL: sil private [transparent] [thunk] @$S9witnesses16ConformingStructVAA1XA2aDP8addrOnly{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method: X) (@in_guaranteed AddrOnly, @inout ConformingStruct) -> @out AddrOnly {
+  // CHECK:       bb0(%0 : @trivial $*AddrOnly, %1 : @trivial $*AddrOnly, %2 : @trivial $*ConformingStruct):
+  // CHECK-NEXT:    // function_ref
+  // CHECK-NEXT:    %3 = function_ref @$S9witnesses16ConformingStructV8addrOnly{{[_0-9a-zA-Z]*}}F : $@convention(method) (@in_guaranteed AddrOnly, @inout ConformingStruct) -> @out AddrOnly
+  // CHECK-NEXT:    %4 = apply %3(%0, %1, %2) : $@convention(method) (@in_guaranteed AddrOnly, @inout ConformingStruct) -> @out AddrOnly
+  // CHECK-NEXT:    %5 = tuple ()
+  // CHECK-NEXT:    return %5 : $()
+  // CHECK-NEXT:  }
+  
+  mutating
+  func generic<C>(x: C) -> C { return x }
+  // CHECK-LABEL: sil private [transparent] [thunk] @$S9witnesses16ConformingStructVAA1XA2aDP7generic{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method: X) <τ_0_0> (@in_guaranteed τ_0_0, @inout ConformingStruct) -> @out τ_0_0 {
+  // CHECK:       bb0(%0 : @trivial $*τ_0_0, %1 : @trivial $*τ_0_0, %2 : @trivial $*ConformingStruct):
+  // CHECK-NEXT:    // function_ref
+  // CHECK-NEXT:    %3 = function_ref @$S9witnesses16ConformingStructV7generic{{[_0-9a-zA-Z]*}}F : $@convention(method) <τ_0_0> (@in_guaranteed τ_0_0, @inout ConformingStruct) -> @out τ_0_0
+  // CHECK-NEXT:    %4 = apply %3<τ_0_0>(%0, %1, %2) : $@convention(method) <τ_0_0> (@in_guaranteed τ_0_0, @inout ConformingStruct) -> @out τ_0_0
+  // CHECK-NEXT:    %5 = tuple ()
+  // CHECK-NEXT:    return %5 : $()
+  // CHECK-NEXT:  }
+  mutating
+  func classes<C2: Classes>(x: C2) -> C2 { return x }
+  // CHECK-LABEL: sil private [transparent] [thunk] @$S9witnesses16ConformingStructVAA1XA2aDP7classes{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method: X) <τ_0_0 where τ_0_0 : Classes> (@guaranteed τ_0_0, @inout ConformingStruct) -> @owned τ_0_0 {
+  // CHECK:       bb0(%0 : @guaranteed $τ_0_0, %1 : @trivial $*ConformingStruct):
+  // CHECK-NEXT:    // function_ref
+  // CHECK-NEXT:    %2 = function_ref @$S9witnesses16ConformingStructV7classes{{[_0-9a-zA-Z]*}}F : $@convention(method) <τ_0_0 where τ_0_0 : Classes> (@guaranteed τ_0_0, @inout ConformingStruct) -> @owned τ_0_0
+  // CHECK-NEXT:    %3 = apply %2<τ_0_0>(%0, %1) : $@convention(method) <τ_0_0 where τ_0_0 : Classes> (@guaranteed τ_0_0, @inout ConformingStruct) -> @owned τ_0_0
+  // CHECK-NEXT:    return %3 : $τ_0_0
+  // CHECK-NEXT:  }
+}
+func <~>(_ x: ConformingStruct, y: ConformingStruct) -> ConformingStruct { return x }
+// CHECK-LABEL: sil private [transparent] [thunk] @$S9witnesses16ConformingStructVAA1XA2aDP3ltgoi{{[_0-9a-zA-Z]*}}FZTW : $@convention(witness_method: X) (@in_guaranteed ConformingStruct, @in_guaranteed ConformingStruct, @thick ConformingStruct.Type) -> @out ConformingStruct {
+// CHECK:       bb0([[ARG1:%.*]] : @trivial $*ConformingStruct, [[ARG2:%.*]] : @trivial $*ConformingStruct, [[ARG3:%.*]] : @trivial $*ConformingStruct, [[ARG4:%.*]] : @trivial $@thick ConformingStruct.Type):
+// CHECK-NEXT:    [[LOADED_ARG2:%.*]] = load [trivial] [[ARG2]] : $*ConformingStruct
+// CHECK-NEXT:    [[LOADED_ARG3:%.*]] = load [trivial] [[ARG3]] : $*ConformingStruct
+// CHECK-NEXT:    // function_ref
+// CHECK-NEXT:    [[FUNC:%.*]] = function_ref @$S9witnesses3ltgoiyAA16ConformingStructVAD_ADtF : $@convention(thin) (ConformingStruct, ConformingStruct) -> ConformingStruct
+// CHECK-NEXT:    [[FUNC_RESULT:%.*]] = apply [[FUNC]]([[LOADED_ARG2]], [[LOADED_ARG3]]) : $@convention(thin) (ConformingStruct, ConformingStruct) -> ConformingStruct
+// CHECK-NEXT:    store [[FUNC_RESULT]] to [trivial] [[ARG1]] : $*ConformingStruct
+// CHECK-NEXT:    %9 = tuple ()
+// CHECK-NEXT:    return %9 : $()
+// CHECK-NEXT:  }
+
+final class ConformingClass : X {
+  func selfTypes(x: ConformingClass) -> ConformingClass { return x }
+  // CHECK-LABEL: sil private [transparent] [thunk] @$S9witnesses15ConformingClassCAA1XA2aDP9selfTypes{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method: X) (@in_guaranteed ConformingClass, @inout ConformingClass) -> @out ConformingClass {
+  // CHECK:  bb0([[ARG1:%.*]] : @trivial $*ConformingClass, [[ARG2:%.*]] : @trivial $*ConformingClass, [[ARG3:%.*]] : @trivial $*ConformingClass):
+  // -- load and copy_value 'self' from inout witness 'self' parameter
+  // CHECK:    [[ARG2_LOADED:%.*]] = load_borrow [[ARG2]] : $*ConformingClass
+  // CHECK:    [[ARG3_LOADED:%.*]] = load_borrow [[ARG3]] : $*ConformingClass
+  // CHECK:    [[FUNC:%.*]] = function_ref @$S9witnesses15ConformingClassC9selfTypes{{[_0-9a-zA-Z]*}}F
+  // CHECK:    [[FUNC_RESULT:%.*]] = apply [[FUNC]]([[ARG2_LOADED]], [[ARG3_LOADED]]) : $@convention(method) (@guaranteed ConformingClass, @guaranteed ConformingClass) -> @owned ConformingClass
+  // CHECK:    store [[FUNC_RESULT]] to [init] [[ARG1]] : $*ConformingClass
+  // CHECK:    end_borrow [[ARG3_LOADED]] from [[ARG3]]
+  // CHECK:  } // end sil function '$S9witnesses15ConformingClassCAA1XA2aDP9selfTypes{{[_0-9a-zA-Z]*}}FTW'
+  func loadable(x: Loadable) -> Loadable { return x }
+  func addrOnly(x: AddrOnly) -> AddrOnly { return x }
+  func generic<D>(x: D) -> D { return x }
+  func classes<D2: Classes>(x: D2) -> D2 { return x }
+}
+func <~>(_ x: ConformingClass, y: ConformingClass) -> ConformingClass { return x }
+
+extension ConformingClass : ClassBounded { }
+// CHECK-LABEL: sil private [transparent] [thunk] @$S9witnesses15ConformingClassCAA0C7BoundedA2aDP9selfTypes{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method: ClassBounded) (@guaranteed ConformingClass, @guaranteed ConformingClass) -> @owned ConformingClass {
+// CHECK:  bb0([[C0:%.*]] : @guaranteed $ConformingClass, [[C1:%.*]] : @guaranteed $ConformingClass):
+// CHECK-NEXT:    function_ref
+// CHECK-NEXT:    [[FUN:%.*]] = function_ref @$S9witnesses15ConformingClassC9selfTypes{{[_0-9a-zA-Z]*}}F
+// CHECK-NEXT:    [[RESULT:%.*]] = apply [[FUN]]([[C0]], [[C1]]) : $@convention(method) (@guaranteed ConformingClass, @guaranteed ConformingClass) -> @owned ConformingClass
+// CHECK-NEXT:    return [[RESULT]] : $ConformingClass
+// CHECK-NEXT:  }
+
+struct ConformingAOStruct : X {
+  var makeMeAO : AddrOnly
+
+  mutating
+  func selfTypes(x: ConformingAOStruct) -> ConformingAOStruct { return x }
+  // CHECK-LABEL: sil private [transparent] [thunk] @$S9witnesses18ConformingAOStructVAA1XA2aDP9selfTypes{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method: X) (@in_guaranteed ConformingAOStruct, @inout ConformingAOStruct) -> @out ConformingAOStruct {
+  // CHECK:       bb0(%0 : @trivial $*ConformingAOStruct, %1 : @trivial $*ConformingAOStruct, %2 : @trivial $*ConformingAOStruct):
+  // CHECK-NEXT:    // function_ref
+  // CHECK-NEXT:    %3 = function_ref @$S9witnesses18ConformingAOStructV9selfTypes{{[_0-9a-zA-Z]*}}F : $@convention(method) (@in_guaranteed ConformingAOStruct, @inout ConformingAOStruct) -> @out ConformingAOStruct
+  // CHECK-NEXT:    %4 = apply %3(%0, %1, %2) : $@convention(method) (@in_guaranteed ConformingAOStruct, @inout ConformingAOStruct) -> @out ConformingAOStruct
+  // CHECK-NEXT:    %5 = tuple ()
+  // CHECK-NEXT:    return %5 : $()
+  // CHECK-NEXT:  }
+  func loadable(x: Loadable) -> Loadable { return x }
+  func addrOnly(x: AddrOnly) -> AddrOnly { return x }
+  func generic<D>(x: D) -> D { return x }
+  func classes<D2: Classes>(x: D2) -> D2 { return x }
+}
+func <~>(_ x: ConformingAOStruct, y: ConformingAOStruct) -> ConformingAOStruct { return x }
+
+struct ConformsWithMoreGeneric : X, Y {
+  mutating
+  func selfTypes<E>(x: E) -> E { return x }
+  // CHECK-LABEL: sil private [transparent] [thunk] @$S9witnesses23ConformsWithMoreGenericVAA1XA2aDP9selfTypes{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method: X) (@in_guaranteed ConformsWithMoreGeneric, @inout ConformsWithMoreGeneric) -> @out ConformsWithMoreGeneric {
+  // CHECK:       bb0(%0 : @trivial $*ConformsWithMoreGeneric, %1 : @trivial $*ConformsWithMoreGeneric, %2 : @trivial $*ConformsWithMoreGeneric):
+  // CHECK-NEXT:    // function_ref
+  // CHECK-NEXT:    [[WITNESS_FN:%.*]] = function_ref @$S9witnesses23ConformsWithMoreGenericV9selfTypes{{[_0-9a-zA-Z]*}}F : $@convention(method) <τ_0_0> (@in_guaranteed τ_0_0, @inout ConformsWithMoreGeneric) -> @out τ_0_0
+  // CHECK-NEXT:    [[RESULT:%.*]] = apply [[WITNESS_FN]]<ConformsWithMoreGeneric>(%0, %1, %2) : $@convention(method) <τ_0_0> (@in_guaranteed τ_0_0, @inout ConformsWithMoreGeneric) -> @out τ_0_0
+  // CHECK-NEXT:    [[RESULT:%.*]] = tuple ()
+  // CHECK-NEXT:    return [[RESULT]] : $()
+  // CHECK-NEXT:  }
+  func loadable<F>(x: F) -> F { return x }
+  mutating
+  func addrOnly<G>(x: G) -> G { return x }
+  // CHECK-LABEL: sil private [transparent] [thunk] @$S9witnesses23ConformsWithMoreGenericVAA1XA2aDP8addrOnly{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method: X) (@in_guaranteed AddrOnly, @inout ConformsWithMoreGeneric) -> @out AddrOnly {
+  // CHECK:       bb0(%0 : @trivial $*AddrOnly, %1 : @trivial $*AddrOnly, %2 : @trivial $*ConformsWithMoreGeneric):
+  // CHECK-NEXT:    // function_ref
+  // CHECK-NEXT:    %3 = function_ref @$S9witnesses23ConformsWithMoreGenericV8addrOnly{{[_0-9a-zA-Z]*}}F : $@convention(method) <τ_0_0> (@in_guaranteed τ_0_0, @inout ConformsWithMoreGeneric) -> @out τ_0_0
+  // CHECK-NEXT:    %4 = apply %3<AddrOnly>(%0, %1, %2) : $@convention(method) <τ_0_0> (@in_guaranteed τ_0_0, @inout ConformsWithMoreGeneric) -> @out τ_0_0
+  // CHECK-NEXT:    [[RESULT:%.*]] = tuple ()
+  // CHECK-NEXT:    return [[RESULT]] : $()
+  // CHECK-NEXT:  }
+
+  mutating
+  func generic<H>(x: H) -> H { return x }
+  // CHECK-LABEL: sil private [transparent] [thunk] @$S9witnesses23ConformsWithMoreGenericVAA1XA2aDP7generic{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method: X) <τ_0_0> (@in_guaranteed τ_0_0, @inout ConformsWithMoreGeneric) -> @out τ_0_0 {
+  // CHECK:       bb0(%0 : @trivial $*τ_0_0, %1 : @trivial $*τ_0_0, %2 : @trivial $*ConformsWithMoreGeneric):
+  // CHECK-NEXT:    // function_ref
+  // CHECK-NEXT:    %3 = function_ref @$S9witnesses23ConformsWithMoreGenericV7generic{{[_0-9a-zA-Z]*}}F : $@convention(method) <τ_0_0> (@in_guaranteed τ_0_0, @inout ConformsWithMoreGeneric) -> @out τ_0_0
+  // CHECK-NEXT:    %4 = apply %3<τ_0_0>(%0, %1, %2) : $@convention(method) <τ_0_0> (@in_guaranteed τ_0_0, @inout ConformsWithMoreGeneric) -> @out τ_0_0
+  // CHECK-NEXT:    [[RESULT:%.*]] = tuple ()
+  // CHECK-NEXT:    return [[RESULT]] : $()
+  // CHECK-NEXT:  }
+
+  mutating
+  func classes<I>(x: I) -> I { return x }
+  // CHECK-LABEL: sil private [transparent] [thunk] @$S9witnesses23ConformsWithMoreGenericVAA1XA2aDP7classes{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method: X) <τ_0_0 where τ_0_0 : Classes> (@guaranteed τ_0_0, @inout ConformsWithMoreGeneric) -> @owned τ_0_0 {
+  // CHECK:       bb0([[ARG0:%.*]] : @guaranteed $τ_0_0, [[ARG1:%.*]] : @trivial $*ConformsWithMoreGeneric):
+  // CHECK-NEXT:    [[SELF_BOX:%.*]] = alloc_stack $τ_0_0
+  // CHECK-NEXT:    [[ARG0_COPY:%.*]] = copy_value [[ARG0]]
+  // CHECK-NEXT:    store [[ARG0_COPY]] to [init] [[SELF_BOX]] : $*τ_0_0
+  // CHECK-NEXT:    // function_ref witnesses.ConformsWithMoreGeneric.classes
+  // CHECK-NEXT:    [[WITNESS_FN:%.*]] = function_ref @$S9witnesses23ConformsWithMoreGenericV7classes{{[_0-9a-zA-Z]*}}F : $@convention(method) <τ_0_0> (@in_guaranteed τ_0_0, @inout ConformsWithMoreGeneric) -> @out τ_0_0
+  // CHECK-NEXT:    [[RESULT_BOX:%.*]] = alloc_stack $τ_0_0
+  // CHECK-NEXT:    [[RESULT:%.*]] = apply [[WITNESS_FN]]<τ_0_0>([[RESULT_BOX]], [[SELF_BOX]], %1) : $@convention(method) <τ_0_0> (@in_guaranteed τ_0_0, @inout ConformsWithMoreGeneric) -> @out τ_0_0
+  // CHECK-NEXT:    [[RESULT:%.*]] = load [take] [[RESULT_BOX]] : $*τ_0_0
+  // CHECK-NEXT:    dealloc_stack [[RESULT_BOX]] : $*τ_0_0
+  // CHECK-NEXT:    destroy_addr [[SELF_BOX]]
+  // CHECK-NEXT:    dealloc_stack [[SELF_BOX]] : $*τ_0_0
+  // CHECK-NEXT:    return [[RESULT]] : $τ_0_0
+  // CHECK-NEXT:  }
+}
+func <~> <J: Y, K: Y>(_ x: J, y: K) -> K { return y }
+// CHECK-LABEL: sil private [transparent] [thunk] @$S9witnesses23ConformsWithMoreGenericVAA1XA2aDP3ltgoi{{[_0-9a-zA-Z]*}}FZTW : $@convention(witness_method: X) (@in_guaranteed ConformsWithMoreGeneric, @in_guaranteed ConformsWithMoreGeneric, @thick ConformsWithMoreGeneric.Type) -> @out ConformsWithMoreGeneric {
+// CHECK:       bb0(%0 : @trivial $*ConformsWithMoreGeneric, %1 : @trivial $*ConformsWithMoreGeneric, %2 : @trivial $*ConformsWithMoreGeneric, %3 : @trivial $@thick ConformsWithMoreGeneric.Type):
+// CHECK-NEXT:    // function_ref
+// CHECK-NEXT:    [[WITNESS_FN:%.*]] = function_ref @$S9witnesses3ltgoi{{[_0-9a-zA-Z]*}}F : $@convention(thin) <τ_0_0, τ_0_1 where τ_0_0 : Y, τ_0_1 : Y> (@in_guaranteed τ_0_0, @in_guaranteed τ_0_1) -> @out τ_0_1
+// CHECK-NEXT:    [[RESULT:%.*]] = apply [[WITNESS_FN]]<ConformsWithMoreGeneric, ConformsWithMoreGeneric>(%0, %1, %2) : $@convention(thin) <τ_0_0, τ_0_1 where τ_0_0 : Y, τ_0_1 : Y> (@in_guaranteed τ_0_0, @in_guaranteed τ_0_1) -> @out τ_0_1
+// CHECK-NEXT:    [[RESULT:%.*]] = tuple ()
+// CHECK-NEXT:    return [[RESULT]] : $()
+// CHECK-NEXT:  }
+
+protocol LabeledRequirement {
+  func method(x: Loadable)
+}
+
+struct UnlabeledWitness : LabeledRequirement {
+  // CHECK-LABEL: sil private [transparent] [thunk] @$S9witnesses16UnlabeledWitnessVAA18LabeledRequirementA2aDP6method{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method: LabeledRequirement) (Loadable, @in_guaranteed UnlabeledWitness) -> ()
+  func method(x _: Loadable) {}
+}
+
+protocol LabeledSelfRequirement {
+  func method(x: Self)
+}
+
+struct UnlabeledSelfWitness : LabeledSelfRequirement {
+  // CHECK-LABEL: sil private [transparent] [thunk] @$S9witnesses20UnlabeledSelfWitnessVAA07LabeledC11RequirementA2aDP6method{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method: LabeledSelfRequirement) (@in_guaranteed UnlabeledSelfWitness, @in_guaranteed UnlabeledSelfWitness) -> ()
+  func method(x _: UnlabeledSelfWitness) {}
+}
+
+protocol UnlabeledRequirement {
+  func method(x _: Loadable)
+}
+
+struct LabeledWitness : UnlabeledRequirement {
+  // CHECK-LABEL: sil private [transparent] [thunk] @$S9witnesses14LabeledWitnessVAA20UnlabeledRequirementA2aDP6method{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method: UnlabeledRequirement) (Loadable, @in_guaranteed LabeledWitness) -> ()
+  func method(x: Loadable) {}
+}
+
+protocol UnlabeledSelfRequirement {
+  func method(_: Self)
+}
+
+struct LabeledSelfWitness : UnlabeledSelfRequirement {
+  // CHECK-LABEL: sil private [transparent] [thunk] @$S9witnesses18LabeledSelfWitnessVAA09UnlabeledC11RequirementA2aDP6method{{[_0-9a-zA-Z]*}}FTW : $@convention(witness_method: UnlabeledSelfRequirement) (@in_guaranteed LabeledSelfWitness, @in_guaranteed LabeledSelfWitness) -> ()
+  func method(_ x: LabeledSelfWitness) {}
+}
+
+protocol ReadOnlyRequirement {
+  var prop: String { get }
+  static var prop: String { get }
+}
+
+struct ImmutableModel: ReadOnlyRequirement {
+  // CHECK-LABEL: sil private [transparent] [thunk] @$S9witnesses14ImmutableModelVAA19ReadOnlyRequirementA2aDP4propSSvgTW : $@convention(witness_method: ReadOnlyRequirement) (@in_guaranteed ImmutableModel) -> @owned String
+  let prop: String = "a"
+  // CHECK-LABEL: sil private [transparent] [thunk] @$S9witnesses14ImmutableModelVAA19ReadOnlyRequirementA2aDP4propSSvgZTW : $@convention(witness_method: ReadOnlyRequirement) (@thick ImmutableModel.Type) -> @owned String
+  static let prop: String = "b"
+}
+
+protocol FailableRequirement {
+  init?(foo: Int)
+}
+
+protocol NonFailableRefinement: FailableRequirement {
+  init(foo: Int)
+}
+
+protocol IUOFailableRequirement {
+  init!(foo: Int)
+}
+
+struct NonFailableModel: FailableRequirement, NonFailableRefinement, IUOFailableRequirement {
+  // CHECK-LABEL: sil private [transparent] [thunk] @$S9witnesses16NonFailableModelVAA0C11Requirement{{[_0-9a-zA-Z]*}}fCTW : $@convention(witness_method: FailableRequirement) (Int, @thick NonFailableModel.Type) -> @out Optional<NonFailableModel>
+  // CHECK-LABEL: sil private [transparent] [thunk] @$S9witnesses16NonFailableModelVAA0bC10Refinement{{[_0-9a-zA-Z]*}}fCTW : $@convention(witness_method: NonFailableRefinement) (Int, @thick NonFailableModel.Type) -> @out NonFailableModel
+  // CHECK-LABEL: sil private [transparent] [thunk] @$S9witnesses16NonFailableModelVAA22IUOFailableRequirement{{[_0-9a-zA-Z]*}}fCTW : $@convention(witness_method: FailableRequirement) (Int, @thick NonFailableModel.Type) -> @out Optional<NonFailableModel>
+  init(foo: Int) {}
+}
+
+struct FailableModel: FailableRequirement, IUOFailableRequirement {
+  // CHECK-LABEL: sil private [transparent] [thunk] @$S9witnesses13FailableModelVAA0B11Requirement{{[_0-9a-zA-Z]*}}fCTW
+
+  // CHECK-LABEL: sil private [transparent] [thunk] @$S9witnesses13FailableModelVAA22IUOFailableRequirement{{[_0-9a-zA-Z]*}}fCTW
+  // CHECK: bb0([[SELF:%[0-9]+]] : @trivial $*Optional<FailableModel>, [[FOO:%[0-9]+]] : @trivial $Int, [[META:%[0-9]+]] : @trivial $@thick FailableModel.Type):
+  // CHECK: [[FN:%.*]] = function_ref @$S9witnesses13FailableModelV{{[_0-9a-zA-Z]*}}fC
+  // CHECK: [[INNER:%.*]] = apply [[FN]](
+  // CHECK: store [[INNER]] to [trivial] [[SELF]]
+  // CHECK: return
+  init?(foo: Int) {}
+}
+
+struct IUOFailableModel : NonFailableRefinement, IUOFailableRequirement {
+  // CHECK-LABEL: sil private [transparent] [thunk] @$S9witnesses16IUOFailableModelVAA21NonFailableRefinement{{[_0-9a-zA-Z]*}}fCTW
+  // CHECK: bb0([[SELF:%[0-9]+]] : @trivial $*IUOFailableModel, [[FOO:%[0-9]+]] : @trivial $Int, [[META:%[0-9]+]] : @trivial $@thick IUOFailableModel.Type):
+  // CHECK:   [[META:%[0-9]+]] = metatype $@thin IUOFailableModel.Type
+  // CHECK:   [[INIT:%[0-9]+]] = function_ref @$S9witnesses16IUOFailableModelV{{[_0-9a-zA-Z]*}}fC : $@convention(method) (Int, @thin IUOFailableModel.Type) -> Optional<IUOFailableModel>
+  // CHECK:   [[IUO_RESULT:%[0-9]+]] = apply [[INIT]]([[FOO]], [[META]]) : $@convention(method) (Int, @thin IUOFailableModel.Type) -> Optional<IUOFailableModel>
+  // CHECK: bb2([[RESULT:%.*]] : @trivial $IUOFailableModel):
+  // CHECK:   store [[RESULT]] to [trivial] [[SELF]] : $*IUOFailableModel
+  // CHECK:   return
+  init!(foo: Int) { return nil }
+}
+
+protocol FailableClassRequirement: class {
+  init?(foo: Int)
+}
+
+protocol NonFailableClassRefinement: FailableClassRequirement {
+  init(foo: Int)
+}
+
+protocol IUOFailableClassRequirement: class {
+  init!(foo: Int)
+}
+
+final class NonFailableClassModel: FailableClassRequirement, NonFailableClassRefinement, IUOFailableClassRequirement {
+  // CHECK-LABEL: sil private [transparent] [thunk] @$S9witnesses21NonFailableClassModelCAA0cD11Requirement{{[_0-9a-zA-Z]*}}fCTW : $@convention(witness_method: FailableClassRequirement) (Int, @thick NonFailableClassModel.Type) -> @owned Optional<NonFailableClassModel>
+  // CHECK-LABEL: sil private [transparent] [thunk] @$S9witnesses21NonFailableClassModelCAA0bcD10Refinement{{[_0-9a-zA-Z]*}}fCTW : $@convention(witness_method: NonFailableClassRefinement) (Int, @thick NonFailableClassModel.Type) -> @owned NonFailableClassModel
+  // CHECK-LABEL: sil private [transparent] [thunk] @$S9witnesses21NonFailableClassModelCAA011IUOFailableD11Requirement{{[_0-9a-zA-Z]*}}fCTW : $@convention(witness_method: FailableClassRequirement) (Int, @thick NonFailableClassModel.Type) -> @owned Optional<NonFailableClassModel>
+  init(foo: Int) {}
+}
+
+final class FailableClassModel: FailableClassRequirement, IUOFailableClassRequirement {
+  // CHECK-LABEL: sil private [transparent] [thunk] @$S9witnesses18FailableClassModelCAA0bC11Requirement{{[_0-9a-zA-Z]*}}fCTW
+
+  // CHECK-LABEL: sil private [transparent] [thunk] @$S9witnesses18FailableClassModelCAA011IUOFailableC11Requirement{{[_0-9a-zA-Z]*}}fCTW
+  // CHECK: [[FUNC:%.*]] = function_ref @$S9witnesses18FailableClassModelC{{[_0-9a-zA-Z]*}}fC
+  // CHECK: [[INNER:%.*]] = apply [[FUNC]](%0, %1)
+  // CHECK: return [[INNER]] : $Optional<FailableClassModel>
+  init?(foo: Int) {}
+}
+
+final class IUOFailableClassModel: NonFailableClassRefinement, IUOFailableClassRequirement {
+  // CHECK-LABEL: sil private [transparent] [thunk] @$S9witnesses21IUOFailableClassModelCAA011NonFailableC10Refinement{{[_0-9a-zA-Z]*}}fCTW
+  // CHECK: bb0({{.*}}):
+  // CHECK:   [[FUNC:%.*]] = function_ref @$S9witnesses21IUOFailableClassModelC3fooACSgSi_tcfC : $@convention(method) (Int, @thick IUOFailableClassModel.Type) -> @owned Optional<IUOFailableClassModel>
+  // CHECK:   [[VALUE:%.*]] = apply [[FUNC]]({{.*}})
+  // CHECK:   switch_enum [[VALUE]] : $Optional<IUOFailableClassModel>, case #Optional.some!enumelt.1: [[SOMEBB:bb[0-9]+]], case #Optional.none!enumelt: [[NONEBB:bb[0-9]+]]
+  //
+  // CHECK: [[NONEBB]]:
+  // CHECK:   unreachable
+  //
+  // CHECK: [[SOMEBB]]([[RESULT:%.*]] : @owned $IUOFailableClassModel)
+  // CHECK: return [[RESULT]] : $IUOFailableClassModel
+  // CHECK: } // end sil function '$S9witnesses21IUOFailableClassModelCAA011NonFailableC10Refinement{{[_0-9a-zA-Z]*}}fCTW'
+
+  // CHECK-LABEL: sil private [transparent] [thunk] @$S9witnesses21IUOFailableClassModelCAA0bC11Requirement{{[_0-9a-zA-Z]*}}fCTW
+  init!(foo: Int) {}
+
+  // CHECK-LABEL: sil private [transparent] [thunk] @$S9witnesses21IUOFailableClassModelCAA08FailableC11Requirement{{[_0-9a-zA-Z]*}}fCTW
+  // CHECK: [[FUNC:%.*]] = function_ref @$S9witnesses21IUOFailableClassModelC{{[_0-9a-zA-Z]*}}fC
+  // CHECK: [[INNER:%.*]] = apply [[FUNC]](%0, %1)
+  // CHECK: return [[INNER]] : $Optional<IUOFailableClassModel>
+}
+
+protocol HasAssoc {
+  associatedtype Assoc
+}
+
+protocol GenericParameterNameCollisionProtocol {
+  func foo<T>(_ x: T)
+  associatedtype Assoc2
+  func bar<T>(_ x: (T) -> Assoc2)
+}
+
+struct GenericParameterNameCollision<T: HasAssoc> :
+    GenericParameterNameCollisionProtocol {
+
+  // CHECK-LABEL: sil private [transparent] [thunk] @$S9witnesses29GenericParameterNameCollisionVyxGAA0bcdE8ProtocolA2aEP3fooyyqd__lFTW : $@convention(witness_method: GenericParameterNameCollisionProtocol) <τ_0_0 where τ_0_0 : HasAssoc><τ_1_0> (@in_guaranteed τ_1_0, @in_guaranteed GenericParameterNameCollision<τ_0_0>) -> () {
+  // CHECK:       bb0(%0 : @trivial $*τ_1_0, %1 : @trivial $*GenericParameterNameCollision<τ_0_0>):
+  // CHECK:         apply {{%.*}}<τ_0_0, τ_1_0>
+  func foo<U>(_ x: U) {}
+
+  // CHECK-LABEL: sil private [transparent] [thunk] @$S9witnesses29GenericParameterNameCollisionVyxGAA0bcdE8ProtocolA2aEP3baryy6Assoc2Qzqd__XElFTW : $@convention(witness_method: GenericParameterNameCollisionProtocol) <τ_0_0 where τ_0_0 : HasAssoc><τ_1_0> (@noescape @callee_guaranteed (@in_guaranteed τ_1_0) -> @out τ_0_0.Assoc, @in_guaranteed GenericParameterNameCollision<τ_0_0>) -> () {
+  // CHECK:       bb0(%0 : @trivial $@noescape @callee_guaranteed (@in_guaranteed τ_1_0) -> @out τ_0_0.Assoc, %1 : @trivial $*GenericParameterNameCollision<τ_0_0>):
+  // CHECK:         apply {{%.*}}<τ_0_0, τ_1_0>
+  func bar<V>(_ x: (V) -> T.Assoc) {}
+}
+
+protocol PropertyRequirement {
+  var width: Int { get set }
+  static var height: Int { get set }
+  var depth: Int { get set }
+}
+
+class PropertyRequirementBase {
+  var width: Int = 12
+  static var height: Int = 13
+}
+
+class PropertyRequirementWitnessFromBase : PropertyRequirementBase, PropertyRequirement {
+  var depth: Int = 14
+
+  // Make sure the contravariant return type in materializeForSet works correctly
+
+  // If the witness is in a base class of the conforming class, make sure we have a bit_cast in there:
+
+  // CHECK-LABEL: sil private [transparent] [thunk] @$S9witnesses34PropertyRequirementWitnessFromBaseCAA0bC0A2aDP5widthSivmTW : {{.*}} {
+  // CHECK: bb0({{.*}} : @trivial $Builtin.RawPointer, {{.*}} : @trivial $*Builtin.UnsafeValueBuffer, [[ARG2:%.*]] : @trivial $*PropertyRequirementWitnessFromBase):
+  // CHECK-NEXT: [[ARG2_LOADED:%[0-9][0-9]*]] = load_borrow [[ARG2]]
+  // CHECK-NEXT: [[CAST_ARG2_LOADED:%[0-9][0-9]*]] = upcast [[ARG2_LOADED]] : $PropertyRequirementWitnessFromBase to $PropertyRequirementBase
+  // CHECK-NEXT: [[METH:%.*]] = class_method [[CAST_ARG2_LOADED]] : $PropertyRequirementBase, #PropertyRequirementBase.width!materializeForSet.1
+  // CHECK-NEXT: [[RES:%.*]] = apply [[METH]]({{.*}}, {{.*}}, [[CAST_ARG2_LOADED]]) : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @guaranteed PropertyRequirementBase) -> (Builtin.RawPointer, Optional<Builtin.RawPointer>)
+  // CHECK-NEXT: [[CAR:%.*]] = tuple_extract [[RES]] : $({{.*}}), 0
+  // CHECK-NEXT: [[CADR:%.*]] = tuple_extract [[RES]] : $({{.*}}), 1
+  // CHECK-NEXT: [[TUPLE:%.*]] = tuple ([[CAR]] : {{.*}}, [[CADR]] : {{.*}})
+  // CHECK-NEXT: end_borrow [[ARG2_LOADED]] from [[ARG2]]
+  // CHECK-NEXT: return [[TUPLE]]
+
+  // CHECK-LABEL: sil private [transparent] [thunk] @$S9witnesses34PropertyRequirementWitnessFromBaseCAA0bC0A2aDP6heightSivmZTW : {{.*}} {
+  // CHECK: [[OBJ:%.*]] = upcast %2 : $@thick PropertyRequirementWitnessFromBase.Type to $@thick PropertyRequirementBase.Type
+  // CHECK: [[METH:%.*]] = function_ref @$S9witnesses23PropertyRequirementBaseC6heightSivmZ
+  // CHECK-NEXT: [[RES:%.*]] = apply [[METH]]
+  // CHECK-NEXT: [[CAR:%.*]] = tuple_extract [[RES]] : $({{.*}}), 0
+  // CHECK-NEXT: [[CADR:%.*]] = tuple_extract [[RES]] : $({{.*}}), 1
+  // CHECK-NEXT: [[TUPLE:%.*]] = tuple ([[CAR]] : {{.*}}, [[CADR]] : {{.*}})
+  // CHECK-NEXT: return [[TUPLE]]
+
+  // CHECK-LABEL: sil private [transparent] [thunk] @$S9witnesses34PropertyRequirementWitnessFromBaseCAA0bC0A2aDP5depthSivmTW
+  // CHECK: bb0({{.*}} : @trivial $Builtin.RawPointer, {{.*}} : @trivial $*Builtin.UnsafeValueBuffer, [[ARG2:%.*]] : @trivial $*PropertyRequirementWitnessFromBase):
+  // CHECK: [[ARG2_LOADED:%[0-9][0-9]*]] = load_borrow [[ARG2]]
+  // CHECK: [[METH:%.*]] = class_method [[ARG2_LOADED]] : $PropertyRequirementWitnessFromBase, #PropertyRequirementWitnessFromBase.depth!materializeForSet.1
+  // CHECK-NEXT: [[RES:%.*]] = apply [[METH]]({{.*}}, {{.*}}, [[ARG2_LOADED]]) : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @guaranteed PropertyRequirementWitnessFromBase) -> (Builtin.RawPointer, Optional<Builtin.RawPointer>)
+  // CHECK-NEXT: tuple_extract
+  // CHECK-NEXT: tuple_extract
+  // CHECK-NEXT: [[RES:%.*]] = tuple
+  // CHECK-NEXT: end_borrow [[ARG2_LOADED]] from [[ARG2]]
+  // CHECK-NEXT: return [[RES]]
+}
+
+protocol Crashable {
+  func crash()
+}
+
+class CrashableBase {
+  func crash() {}
+}
+
+// CHECK-LABEL: sil private [transparent] [thunk] @$S9witnesses16GenericCrashableCyxGAA0C0A2aEP5crashyyFTW : $@convention(witness_method: Crashable) <τ_0_0> (@in_guaranteed GenericCrashable<τ_0_0>) -> ()
+// CHECK:       bb0(%0 : @trivial $*GenericCrashable<τ_0_0>):
+// CHECK-NEXT: [[SELF:%.*]] = load_borrow %0 : $*GenericCrashable<τ_0_0>
+// CHECK-NEXT: [[BASE:%.*]] = upcast [[SELF]] : $GenericCrashable<τ_0_0> to $CrashableBase
+// CHECK-NEXT: [[FN:%.*]] = class_method [[BASE]] : $CrashableBase, #CrashableBase.crash!1 : (CrashableBase) -> () -> (), $@convention(method) (@guaranteed CrashableBase) -> ()
+// CHECK-NEXT: apply [[FN]]([[BASE]]) : $@convention(method) (@guaranteed CrashableBase) -> ()
+// CHECK-NEXT: [[RESULT:%.*]] = tuple ()
+// CHECK-NEXT: end_borrow [[SELF]] from %0
+// CHECK-NEXT: return [[RESULT]] : $()
+
+class GenericCrashable<T> : CrashableBase, Crashable {}
diff --git a/test/SILGen/plus_zero_witnesses_class.swift b/test/SILGen/plus_zero_witnesses_class.swift
new file mode 100644
index 0000000..3ec494b
--- /dev/null
+++ b/test/SILGen/plus_zero_witnesses_class.swift
@@ -0,0 +1,104 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -enable-sil-ownership -emit-silgen %s | %FileCheck %s
+
+protocol Fooable: class {
+  func foo()
+  static func bar()
+  init()
+}
+
+class Foo: Fooable {
+  
+  func foo() { }
+  // CHECK-LABEL: sil private [transparent] [thunk] @$S15witnesses_class3FooCAA7FooableA2aDP3foo{{[_0-9a-zA-Z]*}}FTW
+  // CHECK-NOT:     function_ref
+  // CHECK:         class_method
+
+  class func bar() {}
+  // CHECK-LABEL: sil private [transparent] [thunk] @$S15witnesses_class3FooCAA7FooableA2aDP3bar{{[_0-9a-zA-Z]*}}FZTW
+  // CHECK-NOT:     function_ref
+  // CHECK:         class_method
+
+  required init() {}
+  // CHECK-LABEL: sil private [transparent] [thunk] @$S15witnesses_class3FooCAA7FooableA2aDP{{[_0-9a-zA-Z]*}}fCTW
+  // CHECK-NOT:     function_ref
+  // CHECK:         class_method
+}
+
+// CHECK-LABEL: sil hidden @$S15witnesses_class3genyyxAA7FooableRzlF
+// CHECK:         bb0([[SELF:%.*]] : @guaranteed $T)
+// CHECK-NOT:     copy_value [[SELF]]
+// CHECK:         [[METHOD:%.*]] = witness_method $T
+// CHECK:         apply [[METHOD]]<T>([[SELF]])
+// CHECK-NOT:         destroy_value [[SELF]]
+// CHECK:         return
+func gen<T: Fooable>(_ foo: T) {
+  foo.foo()
+}
+
+// CHECK-LABEL: sil hidden @$S15witnesses_class2exyyAA7Fooable_pF
+// CHECK: bb0([[SELF:%[0-0]+]] : @guaranteed $Fooable):
+// CHECK:         [[SELF_PROJ:%.*]] = open_existential_ref [[SELF]]
+// CHECK:         [[METHOD:%.*]] = witness_method $[[OPENED:@opened(.*) Fooable]],
+// CHECK-NOT:     copy_value [[SELF_PROJ]] : $
+// CHECK:         apply [[METHOD]]<[[OPENED]]>([[SELF_PROJ]])
+// CHECK-NOT:     destroy_value [[SELF]]
+// CHECK:         return
+func ex(_ foo: Fooable) {
+  foo.foo()
+}
+
+// Default implementations in a protocol extension
+protocol HasDefaults {
+  associatedtype T = Self
+
+  func hasDefault()
+
+  func hasDefaultTakesT(_: T)
+
+  func hasDefaultGeneric<U : Fooable>(_: U)
+
+  func hasDefaultGenericTakesT<U : Fooable>(_: T, _: U)
+}
+
+extension HasDefaults {
+  func hasDefault() {}
+
+  func hasDefaultTakesT(_: T) {}
+
+  func hasDefaultGeneric<U : Fooable>(_: U) {}
+
+  func hasDefaultGenericTakesT<U : Fooable>(_: T, _: U) {}
+}
+
+protocol Barable {}
+
+class UsesDefaults<X : Barable> : HasDefaults {}
+
+// Covariant Self:
+
+// CHECK-LABEL: sil private [transparent] [thunk] @$S15witnesses_class12UsesDefaultsCyxGAA03HasD0A2aEP10hasDefaultyyFTW : $@convention(witness_method: HasDefaults) <τ_0_0><τ_1_0 where τ_0_0 : UsesDefaults<τ_1_0>, τ_1_0 : Barable> (@in_guaranteed τ_0_0) -> ()
+// CHECK: [[FN:%.*]] = function_ref @$S15witnesses_class11HasDefaultsPAAE10hasDefaultyyF : $@convention(method) <τ_0_0 where τ_0_0 : HasDefaults> (@in_guaranteed τ_0_0) -> ()
+// CHECK: apply [[FN]]<τ_0_0>(
+// CHECK: return
+
+// Invariant Self, since type signature contains an associated type:
+
+// CHECK-LABEL: sil private [transparent] [thunk] @$S15witnesses_class12UsesDefaultsCyxGAA03HasD0A2aEP16hasDefaultTakesTyy1TQzFTW : $@convention(witness_method: HasDefaults) <τ_0_0 where τ_0_0 : Barable> (@in_guaranteed UsesDefaults<τ_0_0>, @in_guaranteed UsesDefaults<τ_0_0>) -> ()
+// CHECK: [[FN:%.*]] = function_ref @$S15witnesses_class11HasDefaultsPAAE16hasDefaultTakesTyy1TQzF : $@convention(method) <τ_0_0 where τ_0_0 : HasDefaults> (@in_guaranteed τ_0_0.T, @in_guaranteed τ_0_0) -> ()
+// CHECK: apply [[FN]]<UsesDefaults<τ_0_0>>(
+// CHECK: return
+
+// Covariant Self:
+
+// CHECK-LABEL: sil private [transparent] [thunk] @$S15witnesses_class12UsesDefaultsCyxGAA03HasD0A2aEP17hasDefaultGenericyyqd__AA7FooableRd__lFTW : $@convention(witness_method: HasDefaults) <τ_0_0><τ_1_0 where τ_0_0 : UsesDefaults<τ_1_0>, τ_1_0 : Barable><τ_2_0 where τ_2_0 : Fooable> (@guaranteed τ_2_0, @in_guaranteed τ_0_0) -> ()
+// CHECK: [[FN:%.*]] = function_ref @$S15witnesses_class11HasDefaultsPAAE17hasDefaultGenericyyqd__AA7FooableRd__lF : $@convention(method) <τ_0_0 where τ_0_0 : HasDefaults><τ_1_0 where τ_1_0 : Fooable> (@guaranteed τ_1_0, @in_guaranteed τ_0_0) -> ()
+// CHECK: apply [[FN]]<τ_0_0, τ_2_0>(
+// CHECK: return
+
+// Invariant Self, since type signature contains an associated type:
+
+// CHECK-LABEL: sil private [transparent] [thunk] @$S15witnesses_class12UsesDefaultsCyxGAA03HasD0A2aEP23hasDefaultGenericTakesTyy1TQz_qd__tAA7FooableRd__lFTW : $@convention(witness_method: HasDefaults) <τ_0_0 where τ_0_0 : Barable><τ_1_0 where τ_1_0 : Fooable> (@in_guaranteed UsesDefaults<τ_0_0>, @guaranteed τ_1_0, @in_guaranteed UsesDefaults<τ_0_0>) -> ()
+// CHECK: [[FN:%.*]] = function_ref @$S15witnesses_class11HasDefaultsPAAE23hasDefaultGenericTakesTyy1TQz_qd__tAA7FooableRd__lF : $@convention(method) <τ_0_0 where τ_0_0 : HasDefaults><τ_1_0 where τ_1_0 : Fooable> (@in_guaranteed τ_0_0.T, @guaranteed τ_1_0, @in_guaranteed τ_0_0) -> ()
+// CHECK: apply [[FN]]<UsesDefaults<τ_0_0>, τ_1_0>(
+// CHECK: return
diff --git a/test/SILGen/pointer_conversion.swift b/test/SILGen/pointer_conversion.swift
index c47f89c..9d540d2 100644
--- a/test/SILGen/pointer_conversion.swift
+++ b/test/SILGen/pointer_conversion.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -emit-silgen -sdk %S/Inputs -I %S/Inputs -enable-source-import %s | %FileCheck %s
 
 // FIXME: rdar://problem/19648117 Needs splitting objc parts out
diff --git a/test/SILGen/properties.swift b/test/SILGen/properties.swift
index d108a13..841c8b8 100644
--- a/test/SILGen/properties.swift
+++ b/test/SILGen/properties.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -Xllvm -sil-full-demangle -parse-as-library -emit-silgen -disable-objc-attr-requires-foundation-module %s | %FileCheck %s
 
 var zero: Int = 0
@@ -238,7 +239,7 @@
   // -- writeback to val.ref.val_prop
   // CHECK: switch_enum [[OPT_CALLBACK]] : $Optional<Builtin.RawPointer>, case #Optional.some!enumelt.1: [[WRITEBACK:bb[0-9]+]], case #Optional.none!enumelt: [[CONT:bb[0-9]+]]
   // CHECK: [[WRITEBACK]]([[CALLBACK_ADDR:%.*]] : $Builtin.RawPointer):
-  // CHECK: [[CALLBACK:%.*]] = pointer_to_thin_function [[CALLBACK_ADDR]] : $Builtin.RawPointer to $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout Ref, @thick Ref.Type) -> ()
+  // CHECK: [[CALLBACK:%.*]] = pointer_to_thin_function [[CALLBACK_ADDR]] : $Builtin.RawPointer to $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @in_guaranteed Ref, @thick Ref.Type) -> ()
   // CHECK: [[REF_MAT:%.*]] = alloc_stack $Ref
   // CHECK: store [[VAL_REF]] to [init] [[REF_MAT]]
   // CHECK: [[T0:%.*]] = metatype $@thick Ref.Type
diff --git a/test/SILGen/property_abstraction.swift b/test/SILGen/property_abstraction.swift
index 6499fc7..beb71e7 100644
--- a/test/SILGen/property_abstraction.swift
+++ b/test/SILGen/property_abstraction.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -enable-sil-ownership -emit-silgen %s | %FileCheck %s
 
 struct Int {
diff --git a/test/SILGen/protocol_extensions.swift b/test/SILGen/protocol_extensions.swift
index b125092..f01358e 100644
--- a/test/SILGen/protocol_extensions.swift
+++ b/test/SILGen/protocol_extensions.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -disable-objc-attr-requires-foundation-module -emit-silgen %s | %FileCheck %s
 
 public protocol P1 {
diff --git a/test/SILGen/protocol_optional.swift b/test/SILGen/protocol_optional.swift
index 72e7f7c..550908f 100644
--- a/test/SILGen/protocol_optional.swift
+++ b/test/SILGen/protocol_optional.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -parse-as-library -emit-silgen -disable-objc-attr-requires-foundation-module -enable-sil-ownership %s | %FileCheck %s
 
 @objc protocol P1 {
diff --git a/test/SILGen/protocol_resilience.swift b/test/SILGen/protocol_resilience.swift
index 04cef96..f28b215 100644
--- a/test/SILGen/protocol_resilience.swift
+++ b/test/SILGen/protocol_resilience.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %empty-directory(%t)
 // RUN: %target-swift-frontend -emit-module -enable-sil-ownership -enable-resilience -emit-module-path=%t/resilient_protocol.swiftmodule -module-name=resilient_protocol %S/../Inputs/resilient_protocol.swift
 // RUN: %target-swift-frontend -I %t -emit-silgen -enable-sil-ownership -enable-resilience %s | %FileCheck %s
diff --git a/test/SILGen/protocols.swift b/test/SILGen/protocols.swift
index 11072b7..15ff6b3 100644
--- a/test/SILGen/protocols.swift
+++ b/test/SILGen/protocols.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership %s | %FileCheck %s
 
 //===----------------------------------------------------------------------===//
diff --git a/test/SILGen/reabstract-tuple.swift b/test/SILGen/reabstract-tuple.swift
index 13cada1..d3cfb5d 100644
--- a/test/SILGen/reabstract-tuple.swift
+++ b/test/SILGen/reabstract-tuple.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -enable-sil-ownership -emit-silgen -verify %s | %FileCheck %s
 
 // SR-3090:
diff --git a/test/SILGen/reabstract.swift b/test/SILGen/reabstract.swift
index 5c51858..8736780 100644
--- a/test/SILGen/reabstract.swift
+++ b/test/SILGen/reabstract.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -Xllvm -sil-full-demangle -emit-silgen -enable-sil-ownership %s | %FileCheck %s
 
 func takeFn<T>(_ f : (T) -> T?) {}
diff --git a/test/SILGen/reabstract_lvalue.swift b/test/SILGen/reabstract_lvalue.swift
index 63d8a74..8cbd9b8 100644
--- a/test/SILGen/reabstract_lvalue.swift
+++ b/test/SILGen/reabstract_lvalue.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership %s | %FileCheck %s
 
 struct MyMetatypeIsThin {}
diff --git a/test/SILGen/result_abstraction.swift b/test/SILGen/result_abstraction.swift
index a15924d..e2b49e1 100644
--- a/test/SILGen/result_abstraction.swift
+++ b/test/SILGen/result_abstraction.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership %s | %FileCheck %s
 
 struct S {}
diff --git a/test/SILGen/retaining_globals.swift b/test/SILGen/retaining_globals.swift
index 211070e..87756cc 100644
--- a/test/SILGen/retaining_globals.swift
+++ b/test/SILGen/retaining_globals.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -import-objc-header %S/Inputs/globals.h -emit-silgen -enable-sil-ownership %s | %FileCheck %s
 // REQUIRES: objc_interop
 
diff --git a/test/SILGen/rethrows.swift b/test/SILGen/rethrows.swift
index 908fb03..ad23e4a 100644
--- a/test/SILGen/rethrows.swift
+++ b/test/SILGen/rethrows.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -enable-sil-ownership -emit-sil -verify %s | %FileCheck %s
 
 @discardableResult
diff --git a/test/SILGen/scalar_to_tuple_args.swift b/test/SILGen/scalar_to_tuple_args.swift
index 41476ee..8fd38f6 100644
--- a/test/SILGen/scalar_to_tuple_args.swift
+++ b/test/SILGen/scalar_to_tuple_args.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership %s | %FileCheck %s
 
 func inoutWithDefaults(_ x: inout Int, y: Int = 0, z: Int = 0) {}
diff --git a/test/SILGen/shared.swift b/test/SILGen/shared.swift
index dd3c974..c0af68e 100644
--- a/test/SILGen/shared.swift
+++ b/test/SILGen/shared.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -Xllvm -sil-full-demangle -emit-silgen %s -disable-objc-attr-requires-foundation-module -enable-sil-ownership | %FileCheck %s
 
 class RefAggregate {}
diff --git a/test/SILGen/sil_locations.swift b/test/SILGen/sil_locations.swift
index e43cf3d..7614fb1 100644
--- a/test/SILGen/sil_locations.swift
+++ b/test/SILGen/sil_locations.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -emit-silgen -Xllvm -sil-print-debuginfo -emit-verbose-sil -enable-sil-ownership %s | %FileCheck %s
 
 // FIXME: Not sure if this an ideal source info for the branch - 
@@ -76,7 +77,7 @@
 func useTemplateTest() -> Int {
   return templateTest(5);
   // CHECK-LABEL: sil hidden @$S13sil_locations15useTemplateTestSiyF
-  // CHECK: function_ref @$SSi2{{[_0-9a-zA-Z]*}}fC :{{.*}}, loc "{{.*}}":77
+  // CHECK: function_ref @$SSi2{{[_0-9a-zA-Z]*}}fC :{{.*}}, loc "{{.*}}":78
 }
 
 func foo(_ x: Int) -> Int {
diff --git a/test/SILGen/source_location.swift b/test/SILGen/source_location.swift
index 85a7296..67916ef 100644
--- a/test/SILGen/source_location.swift
+++ b/test/SILGen/source_location.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -Xllvm -sil-full-demangle -Xllvm -sil-print-debuginfo -emit-silgen -enable-sil-ownership %s | %FileCheck %s
 
 func printSourceLocation(file: String = #file, line: Int = #line) {}
diff --git a/test/SILGen/specialize_attr.swift b/test/SILGen/specialize_attr.swift
index ac5b27d..0c45041 100644
--- a/test/SILGen/specialize_attr.swift
+++ b/test/SILGen/specialize_attr.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership -emit-verbose-sil %s | %FileCheck %s
 
 // CHECK-LABEL: @_specialize(exported: false, kind: full, where T == Int, U == Float)
diff --git a/test/SILGen/statements.swift b/test/SILGen/statements.swift
index 8b86759..212f42e 100644
--- a/test/SILGen/statements.swift
+++ b/test/SILGen/statements.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -Xllvm -sil-full-demangle -parse-as-library -emit-silgen -enable-sil-ownership -verify %s | %FileCheck %s
 
 class MyClass { 
diff --git a/test/SILGen/struct_resilience.swift b/test/SILGen/struct_resilience.swift
index 40d578e..5d50e67 100644
--- a/test/SILGen/struct_resilience.swift
+++ b/test/SILGen/struct_resilience.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %empty-directory(%t)
 // RUN: %target-swift-frontend -emit-module -enable-resilience -emit-module-path=%t/resilient_struct.swiftmodule -enable-sil-ownership -module-name=resilient_struct %S/../Inputs/resilient_struct.swift
 // RUN: %target-swift-frontend -I %t -enable-sil-ownership -emit-silgen -enable-resilience %s | %FileCheck %s
diff --git a/test/SILGen/subclass_existentials.swift b/test/SILGen/subclass_existentials.swift
index efcbdbf..dbd0cba 100644
--- a/test/SILGen/subclass_existentials.swift
+++ b/test/SILGen/subclass_existentials.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -Xllvm -sil-full-demangle -emit-silgen -parse-as-library -primary-file %s -verify | %FileCheck %s
 // RUN: %target-swift-frontend -emit-ir -parse-as-library -primary-file %s
 
diff --git a/test/SILGen/super.swift b/test/SILGen/super.swift
index f762ee1..c00184c 100644
--- a/test/SILGen/super.swift
+++ b/test/SILGen/super.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %empty-directory(%t)
 // RUN: %target-swift-frontend -I %t -emit-module -emit-module-path=%t/resilient_struct.swiftmodule -module-name resilient_struct %S/../Inputs/resilient_struct.swift
 // RUN: %target-swift-frontend -I %t -emit-module -emit-module-path=%t/resilient_class.swiftmodule -module-name resilient_class %S/../Inputs/resilient_class.swift
diff --git a/test/SILGen/switch.swift b/test/SILGen/switch.swift
index b64ab66..175a476 100644
--- a/test/SILGen/switch.swift
+++ b/test/SILGen/switch.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -emit-silgen %s | %FileCheck %s
 
 func markUsed<T>(_ t: T) {}
diff --git a/test/SILGen/switch_abstraction.swift b/test/SILGen/switch_abstraction.swift
index c4bdccd..3b8e042 100644
--- a/test/SILGen/switch_abstraction.swift
+++ b/test/SILGen/switch_abstraction.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership -parse-stdlib %s | %FileCheck %s
 
 struct A {}
diff --git a/test/SILGen/switch_isa.swift b/test/SILGen/switch_isa.swift
index a7eca4d..4977f99 100644
--- a/test/SILGen/switch_isa.swift
+++ b/test/SILGen/switch_isa.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -emit-silgen %s | %FileCheck %s
 
 func markUsed<T>(_ t: T) {}
diff --git a/test/SILGen/switch_multiple_entry_address_only.swift b/test/SILGen/switch_multiple_entry_address_only.swift
index 735c9ec..2a94457 100644
--- a/test/SILGen/switch_multiple_entry_address_only.swift
+++ b/test/SILGen/switch_multiple_entry_address_only.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend %s -emit-silgen | %FileCheck %s
 
 enum E {
diff --git a/test/SILGen/switch_var.swift b/test/SILGen/switch_var.swift
index 4660bf1..cc8b022 100644
--- a/test/SILGen/switch_var.swift
+++ b/test/SILGen/switch_var.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -emit-silgen %s | %FileCheck %s
 
 // TODO: Implement tuple equality in the library.
diff --git a/test/SILGen/testable-multifile-other.swift b/test/SILGen/testable-multifile-other.swift
index 792d3ae..e33d15c 100644
--- a/test/SILGen/testable-multifile-other.swift
+++ b/test/SILGen/testable-multifile-other.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // This test is paired with testable-multifile.swift.
 
 // RUN: %empty-directory(%t)
diff --git a/test/SILGen/tuples.swift b/test/SILGen/tuples.swift
index e9b4714..a05a467 100644
--- a/test/SILGen/tuples.swift
+++ b/test/SILGen/tuples.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership %s | %FileCheck %s
 class C {}
 
diff --git a/test/SILGen/types.swift b/test/SILGen/types.swift
index b30c8c2..d996b3e 100644
--- a/test/SILGen/types.swift
+++ b/test/SILGen/types.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -parse-as-library -emit-silgen -enable-sil-ownership %s | %FileCheck %s
 
 class C {
diff --git a/test/SILGen/unmanaged.swift b/test/SILGen/unmanaged.swift
index 9e939f9..c8d98ea 100644
--- a/test/SILGen/unmanaged.swift
+++ b/test/SILGen/unmanaged.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -enable-sil-ownership -emit-sil %s | %FileCheck %s
 
 class C {}
diff --git a/test/SILGen/unmanaged_ownership.swift b/test/SILGen/unmanaged_ownership.swift
index ecb0309..21d447b 100644
--- a/test/SILGen/unmanaged_ownership.swift
+++ b/test/SILGen/unmanaged_ownership.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -enable-sil-ownership -parse-stdlib -module-name Swift -emit-silgen %s | %FileCheck %s
 
 class C {}
diff --git a/test/SILGen/unowned.swift b/test/SILGen/unowned.swift
index d55585f..7c7e8a8 100644
--- a/test/SILGen/unowned.swift
+++ b/test/SILGen/unowned.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership %s | %FileCheck %s
 
 func takeClosure(_ fn: () -> Int) {}
diff --git a/test/SILGen/vtable_thunks_reabstraction_final.swift b/test/SILGen/vtable_thunks_reabstraction_final.swift
index 0d31336..68e4b6b 100644
--- a/test/SILGen/vtable_thunks_reabstraction_final.swift
+++ b/test/SILGen/vtable_thunks_reabstraction_final.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership %s | %FileCheck %s
 
 protocol Fooable {
diff --git a/test/SILGen/vtables_objc.swift b/test/SILGen/vtables_objc.swift
index c0d32a7..eb45a91 100644
--- a/test/SILGen/vtables_objc.swift
+++ b/test/SILGen/vtables_objc.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -enable-sil-ownership -sdk %S/Inputs -emit-silgen -I %S/Inputs -enable-source-import %s -disable-objc-attr-requires-foundation-module | %FileCheck %s
 
 // REQUIRES: objc_interop
diff --git a/test/SILGen/weak.swift b/test/SILGen/weak.swift
index f9fe4a7..0e2567c 100644
--- a/test/SILGen/weak.swift
+++ b/test/SILGen/weak.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -Xllvm -sil-full-demangle -emit-silgen -enable-sil-ownership %s | %FileCheck %s
 
 class C {
diff --git a/test/SILGen/weak_multiple_modules.swift b/test/SILGen/weak_multiple_modules.swift
index fe5bd5c..dcfdd34 100644
--- a/test/SILGen/weak_multiple_modules.swift
+++ b/test/SILGen/weak_multiple_modules.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %empty-directory(%t)
 // RUN: %target-swift-frontend -emit-module -emit-module-path=%t/weak_other.swiftmodule -module-name=weak_other %S/Inputs/weak_other.swift
 // RUN: %target-swift-frontend -I %t -emit-silgen -enable-sil-ownership %s | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%target-runtime
diff --git a/test/SILGen/without_actually_escaping.swift b/test/SILGen/without_actually_escaping.swift
index cd91ae1..1719770 100644
--- a/test/SILGen/without_actually_escaping.swift
+++ b/test/SILGen/without_actually_escaping.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership %s | %FileCheck %s
 
 var escapeHatch: Any = 0
diff --git a/test/SILGen/witness_same_type.swift b/test/SILGen/witness_same_type.swift
index 69bf55e..b5659c5 100644
--- a/test/SILGen/witness_same_type.swift
+++ b/test/SILGen/witness_same_type.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership %s | %FileCheck %s
 // RUN: %target-swift-frontend -enable-sil-ownership -emit-ir %s
 
diff --git a/test/SILGen/witness_tables.swift b/test/SILGen/witness_tables.swift
index d5ae931..9e0f98b 100644
--- a/test/SILGen/witness_tables.swift
+++ b/test/SILGen/witness_tables.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership -I %S/Inputs -enable-source-import %s -disable-objc-attr-requires-foundation-module > %t.sil
 // RUN: %FileCheck -check-prefix=TABLE -check-prefix=TABLE-ALL %s < %t.sil
 // RUN: %FileCheck -check-prefix=SYMBOL %s < %t.sil
diff --git a/test/SILGen/witnesses.swift b/test/SILGen/witnesses.swift
index bf8da17..e78392d 100644
--- a/test/SILGen/witnesses.swift
+++ b/test/SILGen/witnesses.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -Xllvm -sil-full-demangle -emit-silgen %s -disable-objc-attr-requires-foundation-module -enable-sil-ownership | %FileCheck %s
 
 infix operator <~> {}
diff --git a/test/SILGen/witnesses_class.swift b/test/SILGen/witnesses_class.swift
index 461c980..64ca7a1 100644
--- a/test/SILGen/witnesses_class.swift
+++ b/test/SILGen/witnesses_class.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -enable-sil-ownership -emit-silgen %s | %FileCheck %s
 
 protocol Fooable: class {
diff --git a/test/SILOptimizer/Inputs/TestMod.sil b/test/SILOptimizer/Inputs/TestMod.sil
index 3e12d13..9ae4a7a 100644
--- a/test/SILOptimizer/Inputs/TestMod.sil
+++ b/test/SILOptimizer/Inputs/TestMod.sil
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // Test module for the specialize_cg_update_crash.sil test.
 
 sil_stage canonical
diff --git a/test/SILOptimizer/Inputs/plus_zero_TestMod.sil b/test/SILOptimizer/Inputs/plus_zero_TestMod.sil
new file mode 100644
index 0000000..62126fb
--- /dev/null
+++ b/test/SILOptimizer/Inputs/plus_zero_TestMod.sil
@@ -0,0 +1,64 @@
+// REQUIRES: plus_zero_runtime
+// Test module for the specialize_cg_update_crash.sil test.
+
+sil_stage canonical
+
+import Builtin
+
+func genlibfunc<X>(x: X) -> X
+
+func genlibfunc2<X>(x: X) -> X
+
+func genlibfunc3<X>(x: X) -> X
+
+class MyClass {
+  init()
+  func mymethod<X>(x: X) -> X
+   deinit
+}
+
+sil @_TFC7TestMod7MyClassD : $@convention(method) (@owned MyClass) -> ()
+sil @_TFC7TestMod7MyClasscfMS0_FT_S0_ : $@convention(method) (@owned MyClass) -> @owned MyClass
+
+sil @_TF7TestMod11genlibfunc3urFq_q_ : $@convention(thin) <X> (@in_guaranteed X) -> @out X {
+bb0(%0 : $*X, %1 : $*X):
+  %4 = tuple ()
+  return %4 : $()
+}
+
+sil @_TF7TestMod11genlibfunc2urFq_q_ : $@convention(thin) <X> (@in_guaranteed X) -> @out X {
+bb0(%0 : $*X, %1 : $*X):
+  %3 = function_ref @_TF7TestMod11genlibfunc3urFq_q_ : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> @out τ_0_0
+  %9 = tuple ()
+  return %9 : $()
+}
+
+sil @_TFC7TestMod7MyClass8mymethodurfS0_Fq_q_ : $@convention(method) <X> (@in_guaranteed X, @guaranteed MyClass) -> @out X {
+bb0(%0 : $*X, %1 : $*X, %2 : $MyClass):
+  %5 = function_ref @_TF7TestMod11genlibfunc3urFq_q_ : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> @out τ_0_0
+  %11 = tuple ()
+  return %11 : $()
+}
+
+// This is the critical function.
+sil @_TF7TestMod10genlibfuncurFq_q_ : $@convention(thin) <X> (@in_guaranteed X) -> @out X {
+bb0(%0 : $*X, %1 : $*X):
+
+  // First reference the method, which lets the method be deserialized, but not processed.
+  %x0 = function_ref @_TFC7TestMod7MyClass8mymethodurfS0_Fq_q_ : $@convention(method) <X> (@in_guaranteed X, @guaranteed MyClass) -> @out X
+
+  // Then reference the metatype which reads the vtable and processes the method.
+  // The bug was that during reading the vtable (and processing the vtable functions),
+  // the callback (to update the CG) was lost.
+  %x4 = metatype $@thick MyClass.Type
+
+  %17 = tuple ()
+  return %17 : $()
+}
+
+sil_vtable MyClass {
+  #MyClass.init!initializer.1: @_TFC7TestMod7MyClasscfMS0_FT_S0_	// TestMod.MyClass.init (TestMod.MyClass.Type)() -> TestMod.MyClass
+  #MyClass.mymethod!1: @_TFC7TestMod7MyClass8mymethodurfS0_Fq_q_	// TestMod.MyClass.mymethod <A> (TestMod.MyClass)(A) -> A
+  #MyClass.deinit!deallocator: @_TFC7TestMod7MyClassD	// TestMod.MyClass.__deallocating_deinit
+}
+
diff --git a/test/SILOptimizer/access_enforcement_noescape.swift b/test/SILOptimizer/access_enforcement_noescape.swift
index b9930d6..ef753a5 100644
--- a/test/SILOptimizer/access_enforcement_noescape.swift
+++ b/test/SILOptimizer/access_enforcement_noescape.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -enable-sil-ownership -enforce-exclusivity=checked -Onone -emit-sil -swift-version 4 -verify -parse-as-library %s
 // RUN: %target-swift-frontend -enable-sil-ownership -enforce-exclusivity=checked -Onone -emit-sil -swift-version 3 -parse-as-library %s | %FileCheck %s
 // REQUIRES: asserts
diff --git a/test/SILOptimizer/access_marker_mandatory.swift b/test/SILOptimizer/access_marker_mandatory.swift
index 3f01c45..be19716 100644
--- a/test/SILOptimizer/access_marker_mandatory.swift
+++ b/test/SILOptimizer/access_marker_mandatory.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -enable-sil-ownership -parse-as-library -Xllvm -sil-full-demangle -emit-sil -Onone -enforce-exclusivity=checked %s | %FileCheck %s
 
 public struct S {
diff --git a/test/SILOptimizer/access_marker_verify.swift b/test/SILOptimizer/access_marker_verify.swift
index 3ef80fa..3e7cd7f 100644
--- a/test/SILOptimizer/access_marker_verify.swift
+++ b/test/SILOptimizer/access_marker_verify.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -enable-verify-exclusivity -enforce-exclusivity=checked -enable-sil-ownership -emit-silgen -swift-version 4 -parse-as-library %s | %FileCheck %s
 // RUN: %target-swift-frontend -enable-verify-exclusivity -enforce-exclusivity=checked -enable-sil-ownership -Onone -emit-sil -swift-version 4 -parse-as-library %s
 // RUN: %target-swift-frontend -enable-verify-exclusivity -enforce-exclusivity=checked -enable-sil-ownership -O -emit-sil -swift-version 4 -parse-as-library %s
@@ -754,7 +755,7 @@
 // CHECK-NOT: begin_access
 // CHECK:   store [[PA]] to [init] [[ADR]] : $*@callee_guaranteed () -> @out Int
 // CHECK:   [[PTR:%.*]] = address_to_pointer [[ADR]] : $*@callee_guaranteed () -> @out Int to $Builtin.RawPointer
-// CHECK:   [[FPTR:%.*]] = thin_function_to_pointer %{{.*}} : $@convention(witness_method: Abstractable) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout C, @thick C.Type) -> () to $Builtin.RawPointer
+// CHECK:   [[FPTR:%.*]] = thin_function_to_pointer %{{.*}} : $@convention(witness_method: Abstractable) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @in_guaranteed C, @thick C.Type) -> () to $Builtin.RawPointer
 // CHECK:   [[ENUM:%.*]] = enum $Optional<Builtin.RawPointer>, #Optional.some!enumelt.1, [[FPTR]] : $Builtin.RawPointer
 // CHECK:   [[R:%.*]] = tuple ([[PTR]] : $Builtin.RawPointer, [[ENUM]] : $Optional<Builtin.RawPointer>)
 // CHECK:   return [[R]] : $(Builtin.RawPointer, Optional<Builtin.RawPointer>)
diff --git a/test/SILOptimizer/array_element_propagation.sil b/test/SILOptimizer/array_element_propagation.sil
index 55a6515..438b01a 100644
--- a/test/SILOptimizer/array_element_propagation.sil
+++ b/test/SILOptimizer/array_element_propagation.sil
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil -array-element-propagation %s | %FileCheck %s
 sil_stage canonical
 
diff --git a/test/SILOptimizer/bridged_casts_folding.swift b/test/SILOptimizer/bridged_casts_folding.swift
index 9623da3..1716b1f 100644
--- a/test/SILOptimizer/bridged_casts_folding.swift
+++ b/test/SILOptimizer/bridged_casts_folding.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -O -emit-sil %s | %FileCheck %s
 
 // REQUIRES: objc_interop
diff --git a/test/SILOptimizer/capture_promotion_generic_context.sil b/test/SILOptimizer/capture_promotion_generic_context.sil
index 845eedf..7287e75 100644
--- a/test/SILOptimizer/capture_promotion_generic_context.sil
+++ b/test/SILOptimizer/capture_promotion_generic_context.sil
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -assume-parsing-unqualified-ownership-sil -emit-sil -O -Xllvm -sil-fso-enable-generics=false %s | %FileCheck %s
 
 sil_stage raw
diff --git a/test/SILOptimizer/capture_promotion_generic_context_ownership.sil b/test/SILOptimizer/capture_promotion_generic_context_ownership.sil
index c456d05..e2dc783 100644
--- a/test/SILOptimizer/capture_promotion_generic_context_ownership.sil
+++ b/test/SILOptimizer/capture_promotion_generic_context_ownership.sil
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -enable-sil-ownership -emit-sil -O -Xllvm -sil-fso-enable-generics=false %s | %FileCheck %s
 
 sil_stage raw
diff --git a/test/SILOptimizer/cast_folding_no_bridging.sil b/test/SILOptimizer/cast_folding_no_bridging.sil
index 54f6d27..ed7a539 100644
--- a/test/SILOptimizer/cast_folding_no_bridging.sil
+++ b/test/SILOptimizer/cast_folding_no_bridging.sil
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -assume-parsing-unqualified-ownership-sil -O -emit-sil %s | %FileCheck %s
 // REQUIRES: objc_interop
 
diff --git a/test/SILOptimizer/cast_folding_objc_generics.swift b/test/SILOptimizer/cast_folding_objc_generics.swift
index 1dd55c6..d6ad317 100644
--- a/test/SILOptimizer/cast_folding_objc_generics.swift
+++ b/test/SILOptimizer/cast_folding_objc_generics.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -O -emit-sil %s | %FileCheck %s
 // REQUIRES: objc_interop
 
diff --git a/test/SILOptimizer/cast_folding_objc_no_foundation.swift b/test/SILOptimizer/cast_folding_objc_no_foundation.swift
index b5304ff..17a88ee 100644
--- a/test/SILOptimizer/cast_folding_objc_no_foundation.swift
+++ b/test/SILOptimizer/cast_folding_objc_no_foundation.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -O -emit-sil %s | %FileCheck %s
 // REQUIRES: objc_interop
 
diff --git a/test/SILOptimizer/dead_code_elimination.sil b/test/SILOptimizer/dead_code_elimination.sil
index fdc3742..535cd1a 100644
--- a/test/SILOptimizer/dead_code_elimination.sil
+++ b/test/SILOptimizer/dead_code_elimination.sil
@@ -1,5 +1,7 @@
 // RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil -enable-sil-verify-all -dce %s | %FileCheck %s
 
+// REQUIRES: rdar34013900
+
 sil_stage canonical
 
 import Builtin
diff --git a/test/SILOptimizer/devirt_covariant_return.swift b/test/SILOptimizer/devirt_covariant_return.swift
index a1f838d..be2da43 100644
--- a/test/SILOptimizer/devirt_covariant_return.swift
+++ b/test/SILOptimizer/devirt_covariant_return.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -Xllvm -sil-full-demangle -O -Xllvm -disable-sil-cm-rr-cm=0   -Xllvm -sil-inline-generics=false -primary-file %s -emit-sil -sil-inline-threshold 1000 -Xllvm -sil-disable-pass=ObjectOutliner -sil-verify-all | %FileCheck %s
 
 // Make sure that we can dig all the way through the class hierarchy and
diff --git a/test/SILOptimizer/devirt_default_case.swift b/test/SILOptimizer/devirt_default_case.swift
index f5a2126..5d86209 100644
--- a/test/SILOptimizer/devirt_default_case.swift
+++ b/test/SILOptimizer/devirt_default_case.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -O -module-name devirt_default_case -emit-sil %s | %FileCheck -check-prefix=CHECK -check-prefix=CHECK-NORMAL %s
 // RUN: %target-swift-frontend -O -module-name devirt_default_case -emit-sil -enable-testing %s | %FileCheck -check-prefix=CHECK -check-prefix=CHECK-TESTABLE %s
 
diff --git a/test/SILOptimizer/devirt_nested_class.swift b/test/SILOptimizer/devirt_nested_class.swift
index e4e1fd9..520ffc6 100644
--- a/test/SILOptimizer/devirt_nested_class.swift
+++ b/test/SILOptimizer/devirt_nested_class.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -emit-sil -O %s | %FileCheck %s
 
 fileprivate class Outer<T> {
diff --git a/test/SILOptimizer/devirt_protocol_method_invocations.swift b/test/SILOptimizer/devirt_protocol_method_invocations.swift
index 92d38bf..d05e1ba 100644
--- a/test/SILOptimizer/devirt_protocol_method_invocations.swift
+++ b/test/SILOptimizer/devirt_protocol_method_invocations.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -O -emit-sil %s | %FileCheck %s
 
 protocol PPP {
diff --git a/test/SILOptimizer/devirt_speculative_nested.swift b/test/SILOptimizer/devirt_speculative_nested.swift
index ea35da2..41bbdfa 100644
--- a/test/SILOptimizer/devirt_speculative_nested.swift
+++ b/test/SILOptimizer/devirt_speculative_nested.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend %s -parse-as-library -O -emit-sil | %FileCheck %s
 // RUN: %target-swift-frontend %s -parse-as-library -Osize -emit-sil
 //
diff --git a/test/SILOptimizer/devirt_value_metatypes.swift b/test/SILOptimizer/devirt_value_metatypes.swift
index 93d6b01..69ce24f 100644
--- a/test/SILOptimizer/devirt_value_metatypes.swift
+++ b/test/SILOptimizer/devirt_value_metatypes.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -emit-sil -O %s | %FileCheck %s
 
 open class A {
diff --git a/test/SILOptimizer/devirt_witness_method_conformance.swift b/test/SILOptimizer/devirt_witness_method_conformance.swift
index 61cb7ae..b8f8c66 100644
--- a/test/SILOptimizer/devirt_witness_method_conformance.swift
+++ b/test/SILOptimizer/devirt_witness_method_conformance.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -O -emit-ir  -primary-file %s | %FileCheck %s
 // This is a swift file because the crash doesn't reproduce with SIL.
 @inline(never)
diff --git a/test/SILOptimizer/globalopt-iter.sil b/test/SILOptimizer/globalopt-iter.sil
index b69962d..9daabd7 100644
--- a/test/SILOptimizer/globalopt-iter.sil
+++ b/test/SILOptimizer/globalopt-iter.sil
@@ -8,7 +8,8 @@
 
 // CHECK: sil @patatino : $@convention(thin) () -> () {
 // CHECK: bb0:
-// CHECK-NEXT:   %0 = global_value @patatinoTv_ : $B
+// CHECK-NEXT:   integer_literal
+// CHECK-NEXT:   global_value @patatinoTv_ : $B
 // CHECK-NEXT:   strong_retain
 // CHECK-NEXT:   strong_release
 // CHECK-NEXT:   tuple ()
@@ -16,9 +17,10 @@
 // CHECK-NEXT: }
 
 sil @patatino : $@convention(thin) () -> () {
-  %1 = alloc_ref [stack] $B
+  %0 = integer_literal $Builtin.Word, 0
+  %1 = alloc_ref [tail_elems $Int64 * %0 : $Builtin.Word] $B
   set_deallocating %1 : $B
-  dealloc_ref [stack] %1 : $B
+  dealloc_ref %1 : $B
   %45 = tuple ()
   return %45 : $()
 }
diff --git a/test/SILOptimizer/let_properties_opts.swift b/test/SILOptimizer/let_properties_opts.swift
index 9351c22..d0c96e8 100644
--- a/test/SILOptimizer/let_properties_opts.swift
+++ b/test/SILOptimizer/let_properties_opts.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend %s -O -emit-sil | %FileCheck -check-prefix=CHECK-WMO %s
 // RUN: %target-swift-frontend -primary-file %s -O -emit-sil | %FileCheck %s
 
diff --git a/test/SILOptimizer/mandatory_inlining.swift b/test/SILOptimizer/mandatory_inlining.swift
index a765c18..0f5d34d 100644
--- a/test/SILOptimizer/mandatory_inlining.swift
+++ b/test/SILOptimizer/mandatory_inlining.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -enable-sil-ownership -sil-verify-all -primary-file %s -emit-sil -o - -verify | %FileCheck %s
 
 // These tests are deliberately shallow, because I do not want to depend on the
diff --git a/test/SILOptimizer/objectoutliner.sil b/test/SILOptimizer/objectoutliner.sil
index 7e94f44..c13e622 100644
--- a/test/SILOptimizer/objectoutliner.sil
+++ b/test/SILOptimizer/objectoutliner.sil
@@ -35,9 +35,10 @@
 // CHECK: return
 sil @outline_global_simple : $@convention(thin) () -> () {
 bb0:
+  %0 = integer_literal $Builtin.Word, 0
   %1 = integer_literal $Builtin.Int64, 1
   %4 = struct $Int64 (%1 : $Builtin.Int64)
-  %7 = alloc_ref $Obj
+  %7 = alloc_ref [tail_elems $Int64 * %0 : $Builtin.Word] $Obj
   %9 = ref_element_addr %7 : $Obj, #Obj.value
   store %4 to %9 : $*Int64
   strong_release %7 : $Obj
@@ -83,9 +84,10 @@
 // CHECK-NEXT: return
 sil @handle_deallocation : $@convention(thin) () -> () {
 bb0:
+  %0 = integer_literal $Builtin.Word, 0
   %3 = integer_literal $Builtin.Int64, 3
   %4 = struct $Int64 (%3 : $Builtin.Int64)
-  %5 = alloc_ref $Obj
+  %5 = alloc_ref [tail_elems $Int64 * %0 : $Builtin.Word] $Obj
   %6 = ref_element_addr %5 : $Obj, #Obj.value
   store %4 to %6 : $*Int64
   set_deallocating %5 : $Obj
@@ -94,15 +96,32 @@
   return %r : $()
 }
 
+// CHECK-LABEL: sil @dont_outline_without_tail_elems
+// CHECK: alloc_ref
+// CHECK: store
+// CHECK: return
+sil @dont_outline_without_tail_elems : $@convention(thin) () -> () {
+bb0:
+  %1 = integer_literal $Builtin.Int64, 1
+  %4 = struct $Int64 (%1 : $Builtin.Int64)
+  %7 = alloc_ref $Obj
+  %9 = ref_element_addr %7 : $Obj, #Obj.value
+  store %4 to %9 : $*Int64
+  strong_release %7 : $Obj
+  %r = tuple ()
+  return %r : $()
+}
+
 // CHECK-LABEL: sil @dont_outline_global_double_store
 // CHECK: alloc_ref
 // CHECK: store
 // CHECK: return
 sil @dont_outline_global_double_store : $@convention(thin) () -> () {
 bb0:
+  %0 = integer_literal $Builtin.Word, 0
   %1 = integer_literal $Builtin.Int64, 1
   %4 = struct $Int64 (%1 : $Builtin.Int64)
-  %7 = alloc_ref $Obj
+  %7 = alloc_ref [tail_elems $Int64 * %0 : $Builtin.Word] $Obj
   %9 = ref_element_addr %7 : $Obj, #Obj.value
   store %4 to %9 : $*Int64
   store %4 to %9 : $*Int64
@@ -116,9 +135,10 @@
 // CHECK: return
 sil @dont_outline_global_missing_store : $@convention(thin) () -> () {
 bb0:
+  %0 = integer_literal $Builtin.Word, 0
   %1 = integer_literal $Builtin.Int64, 1
   %4 = struct $Int64 (%1 : $Builtin.Int64)
-  %7 = alloc_ref $Obj
+  %7 = alloc_ref [tail_elems $Int64 * %0 : $Builtin.Word] $Obj
   %9 = ref_element_addr %7 : $Obj, #Obj.value
   strong_release %7 : $Obj
   %r = tuple ()
@@ -148,9 +168,10 @@
 // CHECK: return
 sil @dont_outline_global_unknown_addr_use : $@convention(thin) () -> () {
 bb0:
+  %0 = integer_literal $Builtin.Word, 0
   %1 = integer_literal $Builtin.Int64, 1
   %4 = struct $Int64 (%1 : $Builtin.Int64)
-  %7 = alloc_ref $Obj
+  %7 = alloc_ref [tail_elems $Int64 * %0 : $Builtin.Word] $Obj
   %9 = ref_element_addr %7 : $Obj, #Obj.value
   store %4 to %9 : $*Int64
   %10 = address_to_pointer %9 : $*Int64 to $Builtin.RawPointer
@@ -167,8 +188,9 @@
 sil @dont_outline_global_escaping_obj : $@convention(thin) (@inout Obj) -> () {
 bb0(%0: $*Obj):
   %1 = integer_literal $Builtin.Int64, 1
+  %2 = integer_literal $Builtin.Word, 0
   %4 = struct $Int64 (%1 : $Builtin.Int64)
-  %7 = alloc_ref $Obj
+  %7 = alloc_ref [tail_elems $Int64 * %2 : $Builtin.Word] $Obj
   %9 = ref_element_addr %7 : $Obj, #Obj.value
   store %4 to %9 : $*Int64
   store %7 to %0 : $*Obj
diff --git a/test/SILOptimizer/performance_inliner.sil b/test/SILOptimizer/performance_inliner.sil
index 6984d00..acdedf0 100644
--- a/test/SILOptimizer/performance_inliner.sil
+++ b/test/SILOptimizer/performance_inliner.sil
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil -enable-sil-verify-all %s -inline -sil-combine | %FileCheck %s
 
 sil_stage canonical
diff --git a/test/SILOptimizer/plus_zero_access_enforcement_noescape.swift b/test/SILOptimizer/plus_zero_access_enforcement_noescape.swift
new file mode 100644
index 0000000..07fb511
--- /dev/null
+++ b/test/SILOptimizer/plus_zero_access_enforcement_noescape.swift
@@ -0,0 +1,593 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -enable-sil-ownership -enforce-exclusivity=checked -Onone -emit-sil -swift-version 4 -verify -parse-as-library %s
+// RUN: %target-swift-frontend -enable-sil-ownership -enforce-exclusivity=checked -Onone -emit-sil -swift-version 3 -parse-as-library %s | %FileCheck %s
+// REQUIRES: asserts
+
+// This tests SILGen and AccessEnforcementSelection as a single set of tests.
+// (Some static/dynamic enforcement selection is done in SILGen, and some is
+// deferred. That may change over time but we want the outcome to be the same).
+//
+// These tests attempt to fully cover the possibilities of reads and
+// modifications to captures along with `inout` arguments on both the caller and
+// callee side.
+
+// Helper
+func doOne(_ f: () -> ()) {
+  f()
+}
+
+// Helper
+func doTwo(_: ()->(), _: ()->()) {}
+
+// Helper
+func doOneInout(_: ()->(), _: inout Int) {}
+
+// Error: Cannot capture nonescaping closure.
+// This triggers an early diagnostics, so it's handled in inout_capture_disgnostics.swift.
+// func reentrantCapturedNoescape(fn: (() -> ()) -> ()) {
+//   let c = { fn {} }
+//   fn(c)
+// }
+
+// Helper
+struct Frob {
+  mutating func outerMut() { doOne { innerMut() } }
+  mutating func innerMut() {}
+}
+
+// Allow nested mutable access via closures.
+func nestedNoEscape(f: inout Frob) {
+  doOne { f.outerMut() }
+}
+// CHECK-LABEL: sil hidden @$S27access_enforcement_noescape14nestedNoEscape1fyAA4FrobVz_tF : $@convention(thin) (@inout Frob) -> () {
+// CHECK-NOT: begin_access
+// CHECK-LABEL: } // end sil function '$S27access_enforcement_noescape14nestedNoEscape1fyAA4FrobVz_tF'
+
+// closure #1 in nestedNoEscape(f:)
+// CHECK-LABEL: sil private @$S27access_enforcement_noescape14nestedNoEscape1fyAA4FrobVz_tFyyXEfU_ : $@convention(thin) (@inout_aliasable Frob) -> () {
+// CHECK: [[ACCESS:%.*]] = begin_access [modify] [static] %0 : $*Frob
+// CHECK: %{{.*}} = apply %{{.*}}([[ACCESS]]) : $@convention(method) (@inout Frob) -> ()
+// CHECK: end_access [[ACCESS]] : $*Frob
+// CHECK-LABEL: } // end sil function '$S27access_enforcement_noescape14nestedNoEscape1fyAA4FrobVz_tFyyXEfU_'
+
+// Allow aliased noescape reads.
+func readRead() {
+  var x = 3
+  // Inside each closure: [read] [static]
+  doTwo({ _ = x }, { _ = x })
+  x = 42
+}
+// CHECK-LABEL: sil hidden @$S27access_enforcement_noescape8readReadyyF : $@convention(thin) () -> () {
+// CHECK: [[ALLOC:%.*]] = alloc_stack $Int, var, name "x"
+// CHECK-NOT: begin_access
+// CHECK: apply
+// CHECK-LABEL: } // end sil function '$S27access_enforcement_noescape8readReadyyF'
+
+// closure #1 in readRead()
+// CHECK-LABEL: sil private @$S27access_enforcement_noescape8readReadyyFyyXEfU_ : $@convention(thin) (@inout_aliasable Int) -> () {
+// CHECK-NOT: begin_access [read] [dynamic]
+// CHECK: [[ACCESS:%.*]] = begin_access [read] [static] %0 : $*Int
+// CHECK: end_access [[ACCESS]] 
+// CHECK-LABEL: } // end sil function '$S27access_enforcement_noescape8readReadyyFyyXEfU_'
+
+// closure #2 in readRead()
+// CHECK-LABEL: sil private @$S27access_enforcement_noescape8readReadyyFyyXEfU0_ : $@convention(thin) (@inout_aliasable Int) -> () {
+// CHECK-NOT: begin_access [read] [dynamic]
+// CHECK: [[ACCESS:%.*]] = begin_access [read] [static] %0 : $*Int
+// CHECK: end_access [[ACCESS]] 
+// CHECK-LABEL: } // end sil function '$S27access_enforcement_noescape8readReadyyFyyXEfU0_'
+
+// Allow aliased noescape reads of an `inout` arg.
+func inoutReadRead(x: inout Int) {
+  // Inside each closure: [read] [static]
+  doTwo({ _ = x }, { _ = x })
+}
+// CHECK-LABEL: sil hidden @$S27access_enforcement_noescape09inoutReadE01xySiz_tF : $@convention(thin) (@inout Int) -> () {
+// CHECK: [[PA1:%.*]] = partial_apply [callee_guaranteed]
+// CHECK: [[CVT1:%.*]] = convert_escape_to_noescape [[PA1]] : $@callee_guaranteed () -> () to $@noescape @callee_guaranteed () -> ()
+// CHECK: [[PA2:%.*]] = partial_apply [callee_guaranteed]
+// CHECK: [[CVT2:%.*]] = convert_escape_to_noescape [[PA2]] : $@callee_guaranteed () -> () to $@noescape @callee_guaranteed () -> ()
+// CHECK-NOT: begin_access
+// CHECK: apply %{{.*}}([[CVT1]], [[CVT2]])
+// CHECK-LABEL: } // end sil function '$S27access_enforcement_noescape09inoutReadE01xySiz_tF'
+
+// closure #1 in inoutReadRead(x:)
+// CHECK-LABEL: sil private @$S27access_enforcement_noescape09inoutReadE01xySiz_tFyyXEfU_ : $@convention(thin) (@inout_aliasable Int) -> () {
+// CHECK-NOT: begin_access [read] [dynamic]
+// CHECK: [[ACCESS:%.*]] = begin_access [read] [static] %0 : $*Int
+// CHECK: end_access [[ACCESS]] 
+// CHECK-LABEL: } // end sil function '$S27access_enforcement_noescape09inoutReadE01xySiz_tFyyXEfU_'
+
+// closure #2 in inoutReadRead(x:)
+// CHECK-LABEL: sil private @$S27access_enforcement_noescape09inoutReadE01xySiz_tFyyXEfU0_ : $@convention(thin) (@inout_aliasable Int) -> () {
+// CHECK-NOT: begin_access [read] [dynamic]
+// CHECK: [[ACCESS:%.*]] = begin_access [read] [static] %0 : $*Int
+// CHECK: end_access [[ACCESS]] 
+// CHECK-LABEL: } // end sil function '$S27access_enforcement_noescape09inoutReadE01xySiz_tFyyXEfU0_'
+
+// Allow aliased noescape read + boxed read.
+func readBoxRead() {
+  var x = 3
+  let c = { _ = x }
+  // Inside may-escape closure `c`: [read] [dynamic]
+  // Inside never-escape closure: [read] [dynamic]
+  doTwo(c, { _ = x })
+  x = 42
+}
+// CHECK-LABEL: sil hidden @$S27access_enforcement_noescape11readBoxReadyyF : $@convention(thin) () -> () {
+// CHECK: [[PA1:%.*]] = partial_apply [callee_guaranteed]
+// CHECK: [[CVT1:%.*]] = convert_escape_to_noescape [[PA1]] : $@callee_guaranteed () -> () to $@noescape @callee_guaranteed () -> ()
+// CHECK: [[PA2:%.*]] = partial_apply [callee_guaranteed]
+// CHECK: [[CVT2:%.*]] = convert_escape_to_noescape [[PA2]] : $@callee_guaranteed () -> () to $@noescape @callee_guaranteed () -> ()
+// CHECK-NOT: begin_access
+// CHECK: apply %{{.*}}([[CVT1]], [[CVT2]])
+// CHECK-LABEL: } // end sil function '$S27access_enforcement_noescape11readBoxReadyyF'
+
+// closure #1 in readBoxRead()
+// CHECK-LABEL: sil private @$S27access_enforcement_noescape11readBoxReadyyFyycfU_ : $@convention(thin) (@guaranteed { var Int }) -> () {
+// CHECK: [[ADDR:%.*]] = project_box %0 : ${ var Int }, 0
+// CHECK: [[ACCESS:%.*]] = begin_access [read] [dynamic] [[ADDR]] : $*Int
+// CHECK: end_access [[ACCESS]] 
+// CHECK-LABEL: } // end sil function '$S27access_enforcement_noescape11readBoxReadyyFyycfU_'
+
+// closure #2 in readBoxRead()
+// CHECK-LABEL: sil private @$S27access_enforcement_noescape11readBoxReadyyFyyXEfU0_ : $@convention(thin) (@inout_aliasable Int) -> () {
+// CHECK: [[ACCESS:%.*]] = begin_access [read] [dynamic] %0 : $*Int
+// CHECK: end_access [[ACCESS]] 
+// CHECK-LABEL: } // end sil function '$S27access_enforcement_noescape11readBoxReadyyFyyXEfU0_'
+
+// Error: cannout capture inout.
+//
+// func inoutReadReadBox(x: inout Int) {
+//   let c = { _ = x }
+//   doTwo({ _ = x }, c)
+// }
+
+// Allow aliased noescape read + write.
+func readWrite() {
+  var x = 3
+  // Inside closure 1: [read] [static]
+  // Inside closure 2: [modify] [static]
+  doTwo({ _ = x }, { x = 42 })
+}
+// CHECK-LABEL: sil hidden @$S27access_enforcement_noescape9readWriteyyF : $@convention(thin) () -> () {
+// CHECK: [[PA1:%.*]] = partial_apply [callee_guaranteed]
+// CHECK: [[CVT1:%.*]] = convert_escape_to_noescape [[PA1]] : $@callee_guaranteed () -> () to $@noescape @callee_guaranteed () -> ()
+// CHECK: [[PA2:%.*]] = partial_apply [callee_guaranteed]
+// CHECK: [[CVT2:%.*]] = convert_escape_to_noescape [[PA2]] : $@callee_guaranteed () -> () to $@noescape @callee_guaranteed () -> ()
+// CHECK-NOT: begin_access
+// CHECK: apply %{{.*}}([[CVT1]], [[CVT2]])
+// CHECK-LABEL: } // end sil function '$S27access_enforcement_noescape9readWriteyyF'
+
+// closure #1 in readWrite()
+// CHECK-LABEL: sil private @$S27access_enforcement_noescape9readWriteyyFyyXEfU_ : $@convention(thin) (@inout_aliasable Int) -> () {
+// CHECK-NOT: [[ACCESS:%.*]] = begin_access [read] [dynamic]
+// CHECK: [[ACCESS:%.*]] = begin_access [read] [static] %0 : $*Int
+// CHECK: end_access [[ACCESS]] 
+// CHECK-LABEL: } // end sil function '$S27access_enforcement_noescape9readWriteyyFyyXEfU_'
+
+// closure #2 in readWrite()
+// CHECK-LABEL: sil private @$S27access_enforcement_noescape9readWriteyyFyyXEfU0_ : $@convention(thin) (@inout_aliasable Int) -> () {
+// CHECK-NOT: [[ACCESS:%.*]] = begin_access [modify] [dynamic]
+// CHECK: [[ACCESS:%.*]] = begin_access [modify] [static] %0 : $*Int
+// CHECK: end_access [[ACCESS]] 
+// CHECK-LABEL: } // end sil function '$S27access_enforcement_noescape9readWriteyyFyyXEfU0_'
+
+// Allow aliased noescape read + write of an `inout` arg.
+func inoutReadWrite(x: inout Int) {
+  // Inside closure 1: [read] [static]
+  // Inside closure 2: [modify] [static]
+  doTwo({ _ = x }, { x = 3 })
+}
+
+// CHECK-LABEL: sil hidden @$S27access_enforcement_noescape14inoutReadWrite1xySiz_tF : $@convention(thin) (@inout Int) -> () {
+// CHECK: [[PA1:%.*]] = partial_apply [callee_guaranteed]
+// CHECK: [[CVT1:%.*]] = convert_escape_to_noescape [[PA1]] : $@callee_guaranteed () -> () to $@noescape @callee_guaranteed () -> ()
+// CHECK: [[PA2:%.*]] = partial_apply [callee_guaranteed]
+// CHECK: [[CVT2:%.*]] = convert_escape_to_noescape [[PA2]] : $@callee_guaranteed () -> () to $@noescape @callee_guaranteed () -> ()
+// CHECK: apply %{{.*}}([[CVT1]], [[CVT2]])
+// CHECK-LABEL: } // end sil function '$S27access_enforcement_noescape14inoutReadWrite1xySiz_tF'
+
+// closure #1 in inoutReadWrite(x:)
+// CHECK-LABEL: sil private @$S27access_enforcement_noescape14inoutReadWrite1xySiz_tFyyXEfU_ : $@convention(thin) (@inout_aliasable Int) -> () {
+// CHECK: [[ACCESS:%.*]] = begin_access [read] [static] %0 : $*Int
+// CHECK: end_access [[ACCESS]] 
+// CHECK-LABEL: } // end sil function '$S27access_enforcement_noescape14inoutReadWrite1xySiz_tFyyXEfU_'
+
+// closure #2 in inoutReadWrite(x:)
+// CHECK-LABEL: sil private @$S27access_enforcement_noescape14inoutReadWrite1xySiz_tFyyXEfU0_ : $@convention(thin) (@inout_aliasable Int) -> () {
+// CHECK: [[ACCESS:%.*]] = begin_access [modify] [static] %0 : $*Int
+// CHECK: end_access [[ACCESS]] 
+// CHECK-LABEL: } // end sil function '$S27access_enforcement_noescape14inoutReadWrite1xySiz_tFyyXEfU0_'
+
+
+func readBoxWrite() {
+  var x = 3
+  let c = { _ = x }
+  // Inside may-escape closure `c`: [read] [dynamic]
+  // Inside never-escape closure: [modify] [dynamic]
+  doTwo(c, { x = 42 })
+}
+// CHECK-LABEL: sil hidden @$S27access_enforcement_noescape12readBoxWriteyyF : $@convention(thin) () -> () {
+// CHECK: [[PA1:%.*]] = partial_apply [callee_guaranteed]
+// CHECK: [[CVT1:%.*]] = convert_escape_to_noescape [[PA1]] : $@callee_guaranteed () -> () to $@noescape @callee_guaranteed () -> ()
+// CHECK: [[PA2:%.*]] = partial_apply [callee_guaranteed]
+// CHECK: [[CVT2:%.*]] = convert_escape_to_noescape [[PA2]] : $@callee_guaranteed () -> () to $@noescape @callee_guaranteed () -> ()
+// CHECK-NOT: begin_access
+// CHECK: apply %{{.*}}([[CVT1]], [[CVT2]])
+// CHECK-LABEL: } // end sil function '$S27access_enforcement_noescape12readBoxWriteyyF'
+
+// closure #1 in readBoxWrite()
+// CHECK-LABEL: sil private @$S27access_enforcement_noescape12readBoxWriteyyFyycfU_ : $@convention(thin) (@guaranteed { var Int }) -> () {
+// CHECK: [[ADDR:%.*]] = project_box %0 : ${ var Int }, 0
+// CHECK: [[ACCESS:%.*]] = begin_access [read] [dynamic] [[ADDR]] : $*Int
+// CHECK: end_access [[ACCESS]] 
+// CHECK-LABEL: } // end sil function '$S27access_enforcement_noescape12readBoxWriteyyFyycfU_'
+
+// closure #2 in readBoxWrite()
+// CHECK-LABEL: sil private @$S27access_enforcement_noescape12readBoxWriteyyFyyXEfU0_ : $@convention(thin) (@inout_aliasable Int) -> () {
+// CHECK: [[ACCESS:%.*]] = begin_access [modify] [dynamic] %0 : $*Int
+// CHECK: end_access [[ACCESS]] 
+// CHECK-LABEL: } // end sil function '$S27access_enforcement_noescape12readBoxWriteyyFyyXEfU0_'
+
+// Error: cannout capture inout.
+// func inoutReadBoxWrite(x: inout Int) {
+//   let c = { _ = x }
+//    doTwo({ x = 42 }, c)
+// }
+
+func readWriteBox() {
+  var x = 3
+  let c = { x = 42 }
+  // Inside may-escape closure `c`: [modify] [dynamic]
+  // Inside never-escape closure: [read] [dynamic]
+  doTwo({ _ = x }, c)
+}
+
+// CHECK-LABEL: sil hidden @$S27access_enforcement_noescape12readWriteBoxyyF : $@convention(thin) () -> () {
+// CHECK: [[PA1:%.*]] = partial_apply [callee_guaranteed]
+// CHECK: [[PA2:%.*]] = partial_apply [callee_guaranteed]
+// CHECK: [[CVT2:%.*]] = convert_escape_to_noescape [[PA2]] : $@callee_guaranteed () -> () to $@noescape @callee_guaranteed () -> ()
+// CHECK: [[CVT1:%.*]] = convert_escape_to_noescape [[PA1]] : $@callee_guaranteed () -> () to $@noescape @callee_guaranteed () -> ()
+// CHECK-NOT: begin_access
+// CHECK: apply %{{.*}}([[CVT2]], [[CVT1]])
+// CHECK-LABEL: } // end sil function '$S27access_enforcement_noescape12readWriteBoxyyF'
+
+// closure #1 in readWriteBox()
+// CHECK-LABEL: sil private @$S27access_enforcement_noescape12readWriteBoxyyFyycfU_ : $@convention(thin) (@guaranteed { var Int }) -> () {
+// CHECK: [[ADDR:%.*]] = project_box %0 : ${ var Int }, 0
+// CHECK: [[ACCESS:%.*]] = begin_access [modify] [dynamic] [[ADDR]] : $*Int
+// CHECK: end_access [[ACCESS]] 
+// CHECK-LABEL: } // end sil function '$S27access_enforcement_noescape12readWriteBoxyyFyycfU_'
+
+// closure #2 in readWriteBox()
+// CHECK-LABEL: sil private @$S27access_enforcement_noescape12readWriteBoxyyFyyXEfU0_ : $@convention(thin) (@inout_aliasable Int) -> () {
+// CHECK: [[ACCESS:%.*]] = begin_access [read] [dynamic] %0 : $*Int
+// CHECK: end_access [[ACCESS]] 
+// CHECK-LABEL: } // end sil function '$S27access_enforcement_noescape12readWriteBoxyyFyyXEfU0_'
+
+// Error: cannout capture inout.
+// func inoutReadWriteBox(x: inout Int) {
+//   let c = { x = 42 }
+//   doTwo({ _ = x }, c)
+// }
+
+// Error: noescape read + write inout.
+func readWriteInout() {
+  var x = 3
+  // Around the call: [modify] [static]
+  // Inside closure: [modify] [static]
+  // expected-error@+2{{overlapping accesses to 'x', but modification requires exclusive access; consider copying to a local variable}}
+  // expected-note@+1{{conflicting access is here}}
+  doOneInout({ _ = x }, &x)
+}
+
+// CHECK-LABEL: sil hidden @$S27access_enforcement_noescape14readWriteInoutyyF : $@convention(thin) () -> () {
+// CHECK: [[PA1:%.*]] = partial_apply [callee_guaranteed]
+// CHECK: [[CVT:%.*]] = convert_escape_to_noescape [[PA1]] : $@callee_guaranteed () -> () to $@noescape @callee_guaranteed () -> ()
+// CHECK: [[ACCESS2:%.*]] = begin_access [modify] [static] %0 : $*Int
+// CHECK: apply %{{.*}}([[CVT]], [[ACCESS2]])
+// CHECK: end_access [[ACCESS2]]
+// CHECK-LABEL: } // end sil function '$S27access_enforcement_noescape14readWriteInoutyyF'
+
+// closure #1 in readWriteInout()
+// CHECK-LABEL: sil private @$S27access_enforcement_noescape14readWriteInoutyyFyyXEfU_ : $@convention(thin) (@inout_aliasable Int) -> () {
+// CHECK: [[ACCESS:%.*]] = begin_access [read] [static] %0 : $*Int
+// CHECK: end_access [[ACCESS]] 
+// CHECK-LABEL: } // end sil function '$S27access_enforcement_noescape14readWriteInoutyyFyyXEfU_'
+
+// Error: noescape read + write inout of an inout.
+func inoutReadWriteInout(x: inout Int) {
+  // Around the call: [modify] [static]
+  // Inside closure: [modify] [static]
+  // expected-error@+2{{overlapping accesses to 'x', but modification requires exclusive access; consider copying to a local variable}}
+  // expected-note@+1{{conflicting access is here}}
+  doOneInout({ _ = x }, &x)
+}
+
+// CHECK-LABEL: sil hidden @$S27access_enforcement_noescape19inoutReadWriteInout1xySiz_tF : $@convention(thin) (@inout Int) -> () {
+// CHECK: [[PA1:%.*]] = partial_apply [callee_guaranteed]
+// CHECK: [[CVT:%.*]] = convert_escape_to_noescape [[PA1]] : $@callee_guaranteed () -> () to $@noescape @callee_guaranteed () -> ()
+// CHECK: [[ACCESS2:%.*]] = begin_access [modify] [static] %0 : $*Int
+// CHECK: apply %{{.*}}([[CVT]], [[ACCESS2]])
+// CHECK: end_access [[ACCESS2]]
+// CHECK-LABEL: } // end sil function '$S27access_enforcement_noescape19inoutReadWriteInout1xySiz_tF'
+
+// closure #1 in inoutReadWriteInout(x:)
+// CHECK-LABEL: sil private @$S27access_enforcement_noescape19inoutReadWriteInout1xySiz_tFyyXEfU_ : $@convention(thin) (@inout_aliasable Int) -> () {
+// CHECK: [[ACCESS:%.*]] = begin_access [read] [static] %0 : $*Int
+// CHECK: end_access [[ACCESS]] 
+// CHECK-LABEL: } // end sil function '$S27access_enforcement_noescape19inoutReadWriteInout1xySiz_tFyyXEfU_'
+
+// Traps on boxed read + write inout.
+// Covered by Interpreter/enforce_exclusive_access.swift.
+func readBoxWriteInout() {
+  var x = 3
+  let c = { _ = x }
+  // Around the call: [modify] [dynamic]
+  // Inside closure: [read] [dynamic]
+  doOneInout(c, &x)
+}
+
+// CHECK-LABEL: sil hidden @$S27access_enforcement_noescape17readBoxWriteInoutyyF : $@convention(thin) () -> () {
+// CHECK: [[PA1:%.*]] = partial_apply [callee_guaranteed]
+// CHECK: [[CVT:%.*]] = convert_escape_to_noescape [[PA1]] : $@callee_guaranteed () -> () to $@noescape @callee_guaranteed () -> ()
+// CHECK: [[ACCESS:%.*]] = begin_access [modify] [dynamic] %1 : $*Int
+// CHECK: apply %{{.*}}([[CVT]], [[ACCESS]])
+// CHECK: end_access [[ACCESS]]
+// CHECK-LABEL: } // end sil function '$S27access_enforcement_noescape17readBoxWriteInoutyyF'
+
+// closure #1 in readBoxWriteInout()
+// CHECK-LABEL: sil private @$S27access_enforcement_noescape17readBoxWriteInoutyyFyycfU_ : $@convention(thin) (@guaranteed { var Int }) -> () {
+// CHECK: [[ADDR:%.*]] = project_box %0 : ${ var Int }, 0
+// CHECK: [[ACCESS:%.*]] = begin_access [read] [dynamic] [[ADDR]] : $*Int
+// CHECK: end_access [[ACCESS]] 
+// CHECK-LABEL: } // end sil function '$S27access_enforcement_noescape17readBoxWriteInoutyyFyycfU_'
+
+// Error: inout cannot be captured.
+// This triggers an early diagnostics, so it's handled in inout_capture_disgnostics.swift.
+// func inoutReadBoxWriteInout(x: inout Int) {
+//   let c = { _ = x }
+//   doOneInout(c, &x)
+// }
+
+// Allow aliased noescape write + write.
+func writeWrite() {
+  var x = 3
+  // Inside closure 1: [modify] [static]
+  // Inside closure 2: [modify] [static]
+  doTwo({ x = 42 }, { x = 87 })
+  _ = x
+}
+
+// CHECK-LABEL: sil hidden @$S27access_enforcement_noescape10writeWriteyyF : $@convention(thin) () -> () {
+// CHECK: [[PA1:%.*]] = partial_apply [callee_guaranteed]
+// CHECK: [[CVT1:%.*]] = convert_escape_to_noescape [[PA1]] : $@callee_guaranteed () -> () to $@noescape @callee_guaranteed () -> ()
+// CHECK: [[PA2:%.*]] = partial_apply [callee_guaranteed]
+// CHECK: [[CVT2:%.*]] = convert_escape_to_noescape [[PA2]] : $@callee_guaranteed () -> () to $@noescape @callee_guaranteed () -> ()
+// CHECK-NOT: begin_access
+// CHECK: apply %{{.*}}([[CVT1]], [[CVT2]])
+// CHECK-LABEL: } // end sil function '$S27access_enforcement_noescape10writeWriteyyF'
+
+// closure #1 in writeWrite()
+// CHECK-LABEL: sil private @$S27access_enforcement_noescape10writeWriteyyFyyXEfU_ : $@convention(thin) (@inout_aliasable Int) -> () {
+// CHECK: [[ACCESS:%.*]] = begin_access [modify] [static] %0 : $*Int
+// CHECK: end_access [[ACCESS]] 
+// CHECK-LABEL: } // end sil function '$S27access_enforcement_noescape10writeWriteyyFyyXEfU_'
+
+// closure #2 in writeWrite()
+// CHECK-LABEL: sil private @$S27access_enforcement_noescape10writeWriteyyFyyXEfU0_ : $@convention(thin) (@inout_aliasable Int) -> () {
+// CHECK: [[ACCESS:%.*]] = begin_access [modify] [static] %0 : $*Int
+// CHECK: end_access [[ACCESS]] 
+// CHECK-LABEL: } // end sil function '$S27access_enforcement_noescape10writeWriteyyFyyXEfU0_'
+
+  
+// Allow aliased noescape write + write of an `inout` arg.
+func inoutWriteWrite(x: inout Int) {
+  // Inside closure 1: [modify] [static]
+  // Inside closure 2: [modify] [static]
+  doTwo({ x = 42}, { x = 87 })
+}
+
+// CHECK-LABEL: sil hidden @$S27access_enforcement_noescape010inoutWriteE01xySiz_tF : $@convention(thin) (@inout Int) -> () {
+// CHECK: [[PA1:%.*]] = partial_apply [callee_guaranteed]
+// CHECK: [[CVT1:%.*]] = convert_escape_to_noescape [[PA1]] : $@callee_guaranteed () -> () to $@noescape @callee_guaranteed () -> ()
+// CHECK: [[PA2:%.*]] = partial_apply [callee_guaranteed]
+// CHECK: [[CVT2:%.*]] = convert_escape_to_noescape [[PA2]] : $@callee_guaranteed () -> () to $@noescape @callee_guaranteed () -> ()
+// CHECK-NOT: begin_access
+// CHECK: apply %{{.*}}([[CVT1]], [[CVT2]])
+// CHECK-LABEL: } // end sil function '$S27access_enforcement_noescape010inoutWriteE01xySiz_tF'
+
+// closure #1 in inoutWriteWrite(x:)
+// CHECK-LABEL: sil private @$S27access_enforcement_noescape010inoutWriteE01xySiz_tFyyXEfU_ : $@convention(thin) (@inout_aliasable Int) -> () {
+// CHECK: [[ACCESS:%.*]] = begin_access [modify] [static] %0 : $*Int
+// CHECK: end_access [[ACCESS]] 
+// CHECK-LABEL: } // end sil function '$S27access_enforcement_noescape010inoutWriteE01xySiz_tFyyXEfU_'
+
+// closure #2 in inoutWriteWrite(x:)
+// CHECK-LABEL: sil private @$S27access_enforcement_noescape010inoutWriteE01xySiz_tFyyXEfU0_ : $@convention(thin) (@inout_aliasable Int) -> () {
+// CHECK: [[ACCESS:%.*]] = begin_access [modify] [static] %0 : $*Int
+// CHECK: end_access [[ACCESS]] 
+// CHECK-LABEL: } // end sil function '$S27access_enforcement_noescape010inoutWriteE01xySiz_tFyyXEfU0_'
+
+// Traps on aliased boxed write + noescape write.
+// Covered by Interpreter/enforce_exclusive_access.swift.
+func writeWriteBox() {
+  var x = 3
+  let c = { x = 87 }
+  // Inside may-escape closure `c`: [modify] [dynamic]
+  // Inside never-escape closure: [modify] [dynamic]
+  doTwo({ x = 42 }, c)
+  _ = x
+}
+
+// CHECK-LABEL: sil hidden @$S27access_enforcement_noescape13writeWriteBoxyyF : $@convention(thin) () -> () {
+// CHECK: [[PA1:%.*]] = partial_apply [callee_guaranteed]
+// CHECK: [[PA2:%.*]] = partial_apply [callee_guaranteed]
+// CHECK: [[CVT2:%.*]] = convert_escape_to_noescape [[PA2]] : $@callee_guaranteed () -> () to $@noescape @callee_guaranteed () -> ()
+// CHECK: [[CVT1:%.*]] = convert_escape_to_noescape [[PA1]] : $@callee_guaranteed () -> () to $@noescape @callee_guaranteed () -> ()
+// CHECK-NOT: begin_access
+// CHECK: apply %{{.*}}([[CVT2]], [[CVT1]])
+// CHECK-LABEL: } // end sil function '$S27access_enforcement_noescape13writeWriteBoxyyF'
+
+// closure #1 in writeWriteBox()
+// CHECK-LABEL: sil private @$S27access_enforcement_noescape13writeWriteBoxyyFyycfU_ : $@convention(thin) (@guaranteed { var Int }) -> () {
+// CHECK: [[ADDR:%.*]] = project_box %0 : ${ var Int }, 0
+// CHECK: [[ACCESS:%.*]] = begin_access [modify] [dynamic] [[ADDR]] : $*Int
+// CHECK: end_access [[ACCESS]] 
+// CHECK-LABEL: } // end sil function '$S27access_enforcement_noescape13writeWriteBoxyyFyycfU_'
+
+// closure #2 in writeWriteBox()
+// CHECK-LABEL: sil private @$S27access_enforcement_noescape13writeWriteBoxyyFyyXEfU0_ : $@convention(thin) (@inout_aliasable Int) -> () {
+// CHECK: [[ACCESS:%.*]] = begin_access [modify] [dynamic] %0 : $*Int
+// CHECK: end_access [[ACCESS]] 
+// CHECK-LABEL: } // end sil function '$S27access_enforcement_noescape13writeWriteBoxyyFyyXEfU0_'
+
+// Error: inout cannot be captured.
+// func inoutWriteWriteBox(x: inout Int) {
+//   let c = { x = 87 }
+//   doTwo({ x = 42 }, c)
+// }
+
+// Error: on noescape write + write inout.
+func writeWriteInout() {
+  var x = 3
+  // Around the call: [modify] [static]
+  // Inside closure: [modify] [static]
+  // expected-error@+2{{overlapping accesses to 'x', but modification requires exclusive access; consider copying to a local variable}}
+  // expected-note@+1{{conflicting access is here}}
+  doOneInout({ x = 42 }, &x)
+}
+
+// CHECK-LABEL: sil hidden @$S27access_enforcement_noescape15writeWriteInoutyyF : $@convention(thin) () -> () {
+// CHECK: [[PA1:%.*]] = partial_apply [callee_guaranteed]
+// CHECK: [[CVT:%.*]] = convert_escape_to_noescape [[PA1]] : $@callee_guaranteed () -> () to $@noescape @callee_guaranteed () -> ()
+// CHECK: [[ACCESS2:%.*]] = begin_access [modify] [static] %0 : $*Int
+// CHECK: apply %{{.*}}([[CVT]], [[ACCESS2]])
+// CHECK: end_access [[ACCESS2]]
+// CHECK-LABEL: } // end sil function '$S27access_enforcement_noescape15writeWriteInoutyyF'
+
+// closure #1 in writeWriteInout()
+// CHECK-LABEL: sil private @$S27access_enforcement_noescape15writeWriteInoutyyFyyXEfU_ : $@convention(thin) (@inout_aliasable Int) -> () {
+// CHECK: [[ACCESS:%.*]] = begin_access [modify] [static] %0 : $*Int
+// CHECK: end_access [[ACCESS]] 
+// CHECK-LABEL: } // end sil function '$S27access_enforcement_noescape15writeWriteInoutyyFyyXEfU_'
+
+// Error: on noescape write + write inout.
+func inoutWriteWriteInout(x: inout Int) {
+  // Around the call: [modify] [static]
+  // Inside closure: [modify] [static]
+  // expected-error@+2{{overlapping accesses to 'x', but modification requires exclusive access; consider copying to a local variable}}
+  // expected-note@+1{{conflicting access is here}}
+  doOneInout({ x = 42 }, &x)
+}
+
+// inoutWriteWriteInout(x:)
+// CHECK-LABEL: sil hidden @$S27access_enforcement_noescape010inoutWriteE5Inout1xySiz_tF : $@convention(thin) (@inout Int) -> () {
+// CHECK: [[PA1:%.*]] = partial_apply [callee_guaranteed]
+// CHECK: [[CVT:%.*]] = convert_escape_to_noescape [[PA1]] : $@callee_guaranteed () -> () to $@noescape @callee_guaranteed () -> ()
+// CHECK: [[ACCESS2:%.*]] = begin_access [modify] [static] %0 : $*Int
+// CHECK: apply %{{.*}}([[CVT]], [[ACCESS2]])
+// CHECK: end_access [[ACCESS2]]
+// CHECK-LABEL: // end sil function '$S27access_enforcement_noescape010inoutWriteE5Inout1xySiz_tF'
+
+// closure #1 in inoutWriteWriteInout(x:)
+// CHECK-LABEL: sil private @$S27access_enforcement_noescape010inoutWriteE5Inout1xySiz_tFyyXEfU_ : $@convention(thin) (@inout_aliasable Int) -> () {
+// CHECK: [[ACCESS:%.*]] = begin_access [modify] [static] %0 : $*Int
+// CHECK: end_access [[ACCESS]] 
+// CHECK-LABEL: } // end sil function '$S27access_enforcement_noescape010inoutWriteE5Inout1xySiz_tFyyXEfU_'
+
+// Traps on boxed write + write inout.
+// Covered by Interpreter/enforce_exclusive_access.swift.
+func writeBoxWriteInout() {
+  var x = 3
+  let c = { x = 42 }
+  // Around the call: [modify] [dynamic]
+  // Inside closure: [modify] [dynamic]
+  doOneInout(c, &x)
+}
+
+// CHECK-LABEL: sil hidden @$S27access_enforcement_noescape18writeBoxWriteInoutyyF : $@convention(thin) () -> () {
+// CHECK: [[PA1:%.*]] = partial_apply [callee_guaranteed]
+// CHECK: [[CVT:%.*]] = convert_escape_to_noescape [[PA1]] : $@callee_guaranteed () -> () to $@noescape @callee_guaranteed () -> ()
+// CHECK: [[ACCESS:%.*]] = begin_access [modify] [dynamic] %1 : $*Int
+// CHECK: apply %{{.*}}([[CVT]], [[ACCESS]])
+// CHECK: end_access [[ACCESS]]
+// CHECK-LABEL: } // end sil function '$S27access_enforcement_noescape18writeBoxWriteInoutyyF'
+
+// closure #1 in writeBoxWriteInout()
+// CHECK-LABEL: sil private @$S27access_enforcement_noescape18writeBoxWriteInoutyyFyycfU_ : $@convention(thin) (@guaranteed { var Int }) -> () {
+// CHECK: [[ADDR:%.*]] = project_box %0 : ${ var Int }, 0
+// CHECK: [[ACCESS:%.*]] = begin_access [modify] [dynamic] [[ADDR]] : $*Int
+// CHECK: end_access [[ACCESS]]
+// CHECK-LABEL: } // end sil function '$S27access_enforcement_noescape18writeBoxWriteInoutyyFyycfU_'
+
+// Error: Cannot capture inout
+// This triggers an early diagnostics, so it's handled in inout_capture_disgnostics.swift.
+// func inoutWriteBoxWriteInout(x: inout Int) {
+//   let c = { x = 42 }
+//   doOneInout(c, &x)
+// }
+
+// Helper
+func doBlockInout(_: @convention(block) ()->(), _: inout Int) {}
+
+func readBlockWriteInout() {
+  var x = 3
+  // Around the call: [modify] [static]
+  // Inside closure: [read] [static]
+  // expected-warning@+2{{overlapping accesses to 'x', but modification requires exclusive access; consider copying to a local variable}}
+  // expected-note@+1{{conflicting access is here}}
+  doBlockInout({ _ = x }, &x)
+}
+
+// CHECK-LABEL: sil hidden @$S27access_enforcement_noescape19readBlockWriteInoutyyF : $@convention(thin) () -> () {
+// CHECK: [[F1:%.*]] = function_ref @$S27access_enforcement_noescape19readBlockWriteInoutyyFyyXEfU_ : $@convention(thin) (@inout_aliasable Int) -> ()
+// CHECK: [[PA:%.*]] = partial_apply [callee_guaranteed] [[F1]](%0) : $@convention(thin) (@inout_aliasable Int) -> ()
+// CHECK-NOT: begin_access
+// CHECK: [[WRITE:%.*]] = begin_access [modify] [static] %0 : $*Int
+// CHECK: apply
+// CHECK: end_access [[WRITE]] : $*Int
+// CHECK-LABEL: } // end sil function '$S27access_enforcement_noescape19readBlockWriteInoutyyF'
+
+// CHECK-LABEL: sil private @$S27access_enforcement_noescape19readBlockWriteInoutyyFyyXEfU_ : $@convention(thin) (@inout_aliasable Int) -> () {
+// CHECK: begin_access [read] [static] %0 : $*Int
+// CHECK-LABEL: } // end sil function '$S27access_enforcement_noescape19readBlockWriteInoutyyFyyXEfU_'
+
+// Test AccessSummaryAnalysis.
+//
+// The captured @inout_aliasable argument to `doOne` is re-partially applied,
+// then stored is a box before passing it to doBlockInout.
+func noEscapeBlock() {
+  var x = 3
+  doOne {
+    // expected-warning@+2{{overlapping accesses to 'x', but modification requires exclusive access; consider copying to a local variable}}
+    // expected-note@+1{{conflicting access is here}}
+    doBlockInout({ _ = x }, &x)
+  }
+}
+// CHECK-LABEL: sil hidden @$S27access_enforcement_noescape13noEscapeBlockyyF : $@convention(thin) () -> () {
+// CHECK: partial_apply [callee_guaranteed]
+// CHECK-NOT: begin_access
+// CHECK: apply
+// CHECK-LABEL: } // end sil function '$S27access_enforcement_noescape13noEscapeBlockyyF'
+
+// CHECK-LABEL: sil private @$S27access_enforcement_noescape13noEscapeBlockyyFyyXEfU_ : $@convention(thin) (@inout_aliasable Int) -> () {
+// CHECK: [[F1:%.*]] = function_ref @$S27access_enforcement_noescape13noEscapeBlockyyFyyXEfU_yyXEfU_ : $@convention(thin) (@inout_aliasable Int) -> ()
+// CHECK: [[PA:%.*]] = partial_apply [callee_guaranteed] [[F1]](%0) : $@convention(thin) (@inout_aliasable Int) -> ()
+// CHECK: [[CVT:%.*]] = convert_escape_to_noescape [[PA]] : $@callee_guaranteed () -> () to $@noescape @callee_guaranteed () -> ()
+// CHECK: [[STORAGE:%.*]] = alloc_stack $@block_storage @noescape @callee_guaranteed () -> ()
+// CHECK: [[ADDR:%.*]] = project_block_storage [[STORAGE]] : $*@block_storage @noescape @callee_guaranteed () -> ()
+// CHECK: store [[CVT]] to [[ADDR]] : $*@noescape @callee_guaranteed () -> ()
+// CHECK: [[F2:%.*]] = function_ref @$SIg_IyB_TR : $@convention(c) (@inout_aliasable @block_storage @noescape @callee_guaranteed () -> ()) -> ()
+// CHECK: [[BLOCK:%.*]] = init_block_storage_header [[STORAGE]] : $*@block_storage @noescape @callee_guaranteed () -> (), invoke [[F2]] : $@convention(c) (@inout_aliasable @block_storage @noescape @callee_guaranteed () -> ()) -> (), type $@convention(block) @noescape () -> ()
+// CHECK: [[ARG:%.*]] = copy_block [[BLOCK]] : $@convention(block) @noescape () -> ()
+// CHECK: [[WRITE:%.*]] = begin_access [modify] [static] %0 : $*Int
+// CHECK: apply %{{.*}}([[ARG]], [[WRITE]]) : $@convention(thin) (@guaranteed @convention(block) @noescape () -> (), @inout Int) -> ()
+// CHECK: end_access [[WRITE]] : $*Int
+// CHECK: dealloc_stack [[STORAGE]] : $*@block_storage @noescape @callee_guaranteed () -> ()
+// CHECK-LABEL: } // end sil function '$S27access_enforcement_noescape13noEscapeBlockyyFyyXEfU_'
+
+// CHECK-LABEL: sil private @$S27access_enforcement_noescape13noEscapeBlockyyFyyXEfU_yyXEfU_ : $@convention(thin) (@inout_aliasable Int) -> () {
+// CHECK: begin_access [read] [static] %0 : $*Int
+// CHECK-LABEL: } // end sil function '$S27access_enforcement_noescape13noEscapeBlockyyFyyXEfU_yyXEfU_'
diff --git a/test/SILOptimizer/plus_zero_access_marker_mandatory.swift b/test/SILOptimizer/plus_zero_access_marker_mandatory.swift
new file mode 100644
index 0000000..dde3001
--- /dev/null
+++ b/test/SILOptimizer/plus_zero_access_marker_mandatory.swift
@@ -0,0 +1,86 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -enable-sil-ownership -parse-as-library -Xllvm -sil-full-demangle -emit-sil -Onone -enforce-exclusivity=checked %s | %FileCheck %s
+
+public struct S {
+  var i: Int
+  var o: AnyObject
+}
+
+// CHECK-LABEL: sil [noinline] @$S23access_marker_mandatory5initSyAA1SVSi_yXltF : $@convention(thin) (Int, @guaranteed AnyObject) -> @owned S {
+// CHECK: bb0(%0 : $Int, %1 : $AnyObject):
+// CHECK: [[STK:%.*]] = alloc_stack $S, var, name "s"
+// CHECK: cond_br %{{.*}}, bb1, bb2
+// CHECK: bb1:
+// CHECK: [[WRITE:%.*]] = begin_access [modify] [static] [[STK]] : $*S
+// CHECK: store %{{.*}} to [[WRITE]] : $*S
+// CHECK: end_access [[WRITE]]
+// CHECK: bb2:
+// CHECK: [[WRITE:%.*]] = begin_access [modify] [static] [[STK]] : $*S
+// CHECK: store %{{.*}} to [[WRITE]] : $*S
+// CHECK: end_access [[WRITE]]
+// CHECK: bb3:
+// CHECK: [[READ:%.*]] = begin_access [read] [static] [[STK]] : $*S
+// CHECK: [[RET:%.*]] = load [[READ]] : $*S
+// CHECK: end_access [[READ]]
+// CHECK: destroy_addr [[STK]]
+// CHECK: dealloc_stack [[STK]]
+// CHECK: return [[RET]] : $S
+// CHECK-LABEL: } // end sil function '$S23access_marker_mandatory5initSyAA1SVSi_yXltF'
+@inline(never)
+public func initS(_ x: Int, _ o: AnyObject) -> S {
+  var s: S
+  if x == 0 {
+    s = S(i: 1, o: o)
+  } else {
+    s = S(i: x, o: o)
+  }
+  return s
+}
+
+@inline(never)
+func takeS(_ s: S) {}
+
+// CHECK-LABEL: sil @$S23access_marker_mandatory14modifyAndReadS1oyyXl_tF : $@convention(thin) (@guaranteed AnyObject) -> () {
+// CHECK: bb0(%0 : $AnyObject):
+// CHECK: [[STK:%.*]] = alloc_stack $S, var, name "s"
+// CHECK: [[FINIT:%.*]] = function_ref @$S23access_marker_mandatory5initSyAA1SVSi_yXltF : $@convention(thin) (Int, @guaranteed AnyObject) -> @owned S
+// CHECK: [[INITS:%.*]] = apply [[FINIT]](%{{.*}}, %0) : $@convention(thin) (Int, @guaranteed AnyObject) -> @owned S
+// CHECK: store [[INITS]] to [[STK]] : $*S
+// CHECK: [[WRITE:%.*]] = begin_access [modify] [static] [[STK]] : $*S
+// CHECK: [[ADDRI:%.*]] = struct_element_addr [[WRITE]] : $*S, #S.i
+// CHECK: store %{{.*}} to [[ADDRI]] : $*Int
+// CHECK: end_access [[WRITE]]
+// CHECK: [[READ:%.*]] = begin_access [read] [static] [[STK]] : $*S
+// CHECK: end_access [[READ]]
+// CHECK: [[FTAKE:%.*]] = function_ref @$S23access_marker_mandatory5takeSyyAA1SVF : $@convention(thin) (@guaranteed S) -> ()
+// CHECK: apply [[FTAKE]](%{{.*}}) : $@convention(thin) (@guaranteed S) -> ()
+// CHECK-LABEL: } // end sil function '$S23access_marker_mandatory14modifyAndReadS1oyyXl_tF'
+public func modifyAndReadS(o: AnyObject) {
+  var s = initS(3, o)
+  s.i = 42
+  takeS(s)
+}
+
+// Test capture promotion followed by stack promotion.
+// Access enforcement selection must run after capture promotion
+// so that we never stack promote something with dynamic access.
+// Otherwise, we may try to convert the access to [deinit] which
+// doesn't make sense dynamically.
+//
+// CHECK-LABEL: sil hidden @$S23access_marker_mandatory19captureStackPromoteSiycyF : $@convention(thin) () -> @owned @callee_guaranteed () -> Int {
+// CHECK-LABEL: bb0:
+// CHECK: [[STK:%.*]] = alloc_stack $Int, var, name "x"
+// CHECK: [[WRITE:%.*]] = begin_access [modify] [static] [[STK]] : $*Int
+// CHECK: store %{{.*}} to [[WRITE]] : $*Int
+// CHECK: end_access [[WRITE]] : $*Int
+// CHECK: [[F:%.*]] = function_ref @$S23access_marker_mandatory19captureStackPromoteSiycyFSiycfU_Tf2i_n : $@convention(thin) (Int) -> Int
+// CHECK: [[C:%.*]] = partial_apply [callee_guaranteed] [[F]](%{{.*}}) : $@convention(thin) (Int) -> Int
+// CHECK: dealloc_stack [[STK]] : $*Int
+// CHECK: return [[C]] : $@callee_guaranteed () -> Int
+// CHECK-LABEL: } // end sil function '$S23access_marker_mandatory19captureStackPromoteSiycyF'
+func captureStackPromote() -> () -> Int {
+  var x = 1
+  x = 2
+  let f = { x }
+  return f
+}
diff --git a/test/SILOptimizer/plus_zero_access_marker_verify.swift b/test/SILOptimizer/plus_zero_access_marker_verify.swift
new file mode 100644
index 0000000..f24f230
--- /dev/null
+++ b/test/SILOptimizer/plus_zero_access_marker_verify.swift
@@ -0,0 +1,1000 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -enable-verify-exclusivity -enforce-exclusivity=checked -enable-sil-ownership -emit-silgen -swift-version 4 -parse-as-library %s | %FileCheck %s
+// RUN: %target-swift-frontend -enable-verify-exclusivity -enforce-exclusivity=checked -enable-sil-ownership -Onone -emit-sil -swift-version 4 -parse-as-library %s
+// RUN: %target-swift-frontend -enable-verify-exclusivity -enforce-exclusivity=checked -enable-sil-ownership -O -emit-sil -swift-version 4 -parse-as-library %s
+// REQUIRES: asserts
+
+// Test the combination of SILGen + DiagnoseStaticExclusivity with verification.
+//
+// This is a collection of tests that cover SILGen cases that require special
+// handling for exclusivity verification. SILGen must generate access markers,
+// possibly unenforced, to satisfy the verification run during the
+// DiagnoseStaticExclusivity pass.
+//
+// These cases are mostly covered by existing SILGen tests, but need to be
+// repeated here to ensure they are run with exclusivity verification enabled.
+import SwiftShims
+
+protocol P {}
+struct StructP : P {}
+
+protocol PBar {
+  func bar()
+}
+
+class BaseClass  {
+  init() {}
+}
+class SubClass : BaseClass {
+  override required init() {}
+}
+
+enum E {
+case V(Int)
+}
+
+func takesClosure(_ f: () -> ()) {
+  f()
+}
+
+// --- struct initialization.
+struct StructOfInt {
+  var i: Int
+
+  init() {
+    i = 1
+  }
+
+  mutating func changeMe() {
+    i = 3
+  }
+}
+// The verifier ignores the load of the self box.
+// CHECK-LABEL: sil hidden @$S20access_marker_verify11StructOfIntVACycfC : $@convention(method) (@thin StructOfInt.Type) -> StructOfInt {
+// CHECK: bb0(%0 : @trivial $@thin StructOfInt.Type):
+// CHECK:   [[BOX:%.*]] = alloc_box ${ var StructOfInt }, var, name "self"
+// CHECK:   [[UNINIT:%.*]] = mark_uninitialized [rootself] [[BOX]] : ${ var StructOfInt }
+// CHECK:   [[PROJ:%.*]] = project_box [[UNINIT]] : ${ var StructOfInt }, 0
+// CHECK:   [[ACCESS:%.*]] = begin_access [modify] [unknown] [[PROJ]] : $*StructOfInt
+// CHECK:   [[ADR:%.*]] = struct_element_addr [[ACCESS]] : $*StructOfInt, #StructOfInt.i
+// CHECK:   assign %{{.*}} to [[ADR]] : $*Int
+// CHECK:   end_access [[ACCESS]] : $*StructOfInt
+// CHECK-NOT: begin_access
+// CHECK:   [[VAL:%.*]] = load [trivial] [[PROJ]] : $*StructOfInt
+// CHECK:   destroy_value [[UNINIT]] : ${ var StructOfInt }
+// CHECK:   return [[VAL]] : $StructOfInt
+// CHECK-LABEL: } // end sil function '$S20access_marker_verify11StructOfIntVACycfC'
+
+// --- class initialization.
+class SuperHasInt {
+  var i: Int
+
+  init() {
+    i = 3
+  }
+}
+
+class SubHasInt : SuperHasInt {
+  var j: Int
+  
+  override init() {
+    j = 4
+    super.init()
+  }
+
+  init(x: Int) {
+    j = x
+    super.init()
+  }
+}
+// CHECK-LABEL: sil hidden @$S20access_marker_verify11SuperHasIntCACycfc : $@convention(method) (@owned SuperHasInt) -> @owned SuperHasInt {
+// CHECK:   bb0(%0 : @owned $SuperHasInt):
+// CHECK:   [[UNINIT:%.*]] = mark_uninitialized [rootself] %0 : $SuperHasInt
+// CHECK:   [[BORROW:%.*]] = begin_borrow [[UNINIT]] : $SuperHasInt
+// CHECK:   [[ADR:%.*]] = ref_element_addr [[BORROW]] : $SuperHasInt, #SuperHasInt.i
+// CHECK:   [[ACCESS:%.*]] = begin_access [modify] [dynamic] [[ADR]] : $*Int
+// CHECK:   assign %{{.*}} to [[ACCESS]] : $*Int
+// CHECK:   end_access [[ACCESS]] : $*Int
+// CHECK:   end_borrow [[BORROW]] from [[UNINIT]] : $SuperHasInt, $SuperHasInt
+// CHECK-NOT: begin_access
+// CHECK:   [[VAL:%.*]] = copy_value [[UNINIT]] : $SuperHasInt
+// CHECK:   destroy_value [[UNINIT]] : $SuperHasInt
+// CHECK:   return [[VAL]] : $SuperHasInt
+// CHECK-LABEL: } // end sil function '$S20access_marker_verify11SuperHasIntCACycfc'
+
+// CHECK-LABEL: sil hidden @$S20access_marker_verify9SubHasIntCACycfc : $@convention(method) (@owned SubHasInt) -> @owned SubHasInt {
+// CHECK: bb0(%0 : @owned $SubHasInt):
+// CHECK:   [[BOX:%.*]] = alloc_box ${ var SubHasInt }, let, name "self"
+// CHECK:   [[UNINIT:%.*]] = mark_uninitialized [derivedself] [[BOX]] : ${ var SubHasInt }
+// CHECK:   [[PROJ:%.*]] = project_box [[UNINIT]] : ${ var SubHasInt }, 0
+// CHECK-NOT: begin_access
+// CHECK:   store %0 to [init] [[PROJ]] : $*SubHasInt
+// CHECK-NOT: begin_access
+// CHECK:   [[BORROW:%.*]] = load_borrow [[PROJ]] : $*SubHasInt
+// CHECK:   [[ADR:%.*]] = ref_element_addr [[BORROW]] : $SubHasInt, #SubHasInt.j
+// CHECK:   [[ACCESS:%.*]] = begin_access [modify] [dynamic] [[ADR]] : $*Int
+// CHECK:   assign %{{.*}} to [[ACCESS]] : $*Int
+// CHECK:   end_access [[ACCESS]] : $*Int
+// CHECK:   end_borrow [[BORROW]] from [[PROJ]] : $SubHasInt, $*SubHasInt
+// CHECK-NOT: begin_access
+// CHECK:   load [take] [[PROJ]] : $*SubHasInt
+// CHECK:   upcast %{{.*}} : $SubHasInt to $SuperHasInt
+// CHECK:   function_ref @$S20access_marker_verify11SuperHasIntCACycfc : $@convention(method) (@owned SuperHasInt) -> @owned SuperHasInt
+// CHECK:   apply
+// CHECK:   unchecked_ref_cast %{{.*}} : $SuperHasInt to $SubHasInt
+// CHECK-NOT: begin_access
+// CHECK:   store %{{.*}} to [init] [[PROJ]] : $*SubHasInt
+// CHECK:   [[VAL:%.*]] = load [copy] [[PROJ]] : $*SubHasInt
+// CHECK:   destroy_value [[UNINIT]] : ${ var SubHasInt }
+// CHECK:   return [[VAL]] : $SubHasInt
+// CHECK-LABEL: } // end sil function '$S20access_marker_verify9SubHasIntCACycfc'
+
+// CHECK-LABEL: sil hidden @$S20access_marker_verify9SubHasIntC1xACSi_tcfc : $@convention(method) (Int, @owned SubHasInt) -> @owned SubHasInt {
+// CHECK: bb0(%0 : @trivial $Int, %1 : @owned $SubHasInt):
+// CHECK:   [[BOX:%.*]] = alloc_box ${ var SubHasInt }, let, name "self"
+// CHECK:   [[UNINIT:%.*]] = mark_uninitialized [derivedself] [[BOX]] : ${ var SubHasInt }
+// CHECK:   [[PROJ:%.*]] = project_box [[UNINIT]] : ${ var SubHasInt }, 0
+// CHECK-NOT: begin_access
+// CHECK:   store %{{.*}} to [init] [[PROJ]] : $*SubHasInt
+// CHECK-NOT: begin_access
+// CHECK:   [[BORROW:%.*]] = load_borrow [[PROJ]] : $*SubHasInt
+// CHECK:   [[ADR:%.*]] = ref_element_addr [[BORROW]] : $SubHasInt, #SubHasInt.j
+// CHECK:   [[ACCESS:%.*]] = begin_access [modify] [dynamic] [[ADR]] : $*Int
+// CHECK:   assign %0 to [[ACCESS]] : $*Int
+// CHECK:   end_access [[ACCESS]] : $*Int
+// CHECK:   end_borrow [[BORROW]] from [[PROJ]] : $SubHasInt, $*SubHasInt
+// CHECK-NOT: begin_access
+// CHECK:   load [take] [[PROJ]] : $*SubHasInt
+// CHECK:   upcast %{{.*}} : $SubHasInt to $SuperHasInt
+// CHECK:   function_ref @$S20access_marker_verify11SuperHasIntCACycfc : $@convention(method) (@owned SuperHasInt) -> @owned SuperHasInt
+// CHECK:   apply
+// CHECK:   unchecked_ref_cast %{{.*}} : $SuperHasInt to $SubHasInt
+// CHECK-NOT: begin_access
+// CHECK:   store %{{.*}} to [init] [[PROJ]] : $*SubHasInt
+// CHECK:   [[VAL:%.*]] = load [copy] [[PROJ]] : $*SubHasInt
+// CHECK:   destroy_value [[UNINIT]] : ${ var SubHasInt }
+// CHECK:   return [[VAL]] : $SubHasInt
+// CHECK-LABEL: } // end sil function '$S20access_marker_verify9SubHasIntC1xACSi_tcfc'
+
+// --- access `let` property.
+class LetClass {
+  let x = 3
+}
+
+// FIXME: should be a [unknown] access.
+//
+// CHECK-LABEL: sil hidden @$S20access_marker_verify10testGetLet1cSiAA0F5ClassC_tF : $@convention(thin) (@guaranteed LetClass) -> Int {
+// CHECK: bb0(%0 : @guaranteed $LetClass):
+// CHECK:   ref_element_addr
+// CHECK:   begin_access [read] [dynamic]
+// CHECK:   load [trivial]
+// CHECK:   end_access
+// CHECK:   return
+// CHECK-LABEL: } // end sil function '$S20access_marker_verify10testGetLet1cSiAA0F5ClassC_tF'
+func testGetLet(c: LetClass) -> Int {
+  return c.x
+}
+
+// --- initialize let property and superclass.
+struct IntWrapper {
+  var x: Int
+}
+
+final class SubWrapper : BaseClass {
+  let val: IntWrapper
+
+  init(_ val: IntWrapper) {
+    self.val = val
+    super.init()
+  }
+}
+// CHECK-LABEL: sil hidden @$S20access_marker_verify10SubWrapperCyAcA03IntE0Vcfc : $@convention(method) (IntWrapper, @owned SubWrapper) -> @owned SubWrapper {
+// CHECK: bb0(%0 : @trivial $IntWrapper, %1 : @owned $SubWrapper):
+// CHECK:   alloc_box ${ var SubWrapper }, let, name "self"
+// CHECK:   mark_uninitialized [derivedself]
+// CHECK:   project_box
+// CHECK-NOT: begin_access
+// CHECK:   store %1 to [init]
+// CHECK-NOT: begin_access
+// CHECK:   load_borrow
+// CHECK:   ref_element_addr
+// CHECK:   begin_access [modify] [dynamic]
+// CHECK:   assign %0 to
+// CHECK:   end_access
+// CHECK:   end_borrow
+// CHECK-NOT: begin_access
+// CHECK:   load [take]
+// CHECK-NOT: begin_access
+// CHECK:   store %{{.*}} to [init]
+// CHECK:   [[VAL:%.*]] = load [copy]
+// CHECK:   destroy_value %{{.*}} : ${ var SubWrapper }
+// CHECK:   return [[VAL]] : $SubWrapper
+// CHECK-LABEL: } // end sil function '$S20access_marker_verify10SubWrapperCyAcA03IntE0Vcfc'
+
+// --- captured local.
+func testCaptureLocal() -> ()->() {
+  var x = 1
+  let f = { x = 3 }
+  _ = x
+  return f
+}
+// CHECK-LABEL: sil hidden @$S20access_marker_verify16testCaptureLocalyycyF : $@convention(thin) () -> @owned @callee_guaranteed () -> () {
+// CHECK: bb0:
+// CHECK:   alloc_box ${ var Int }, var, name "x"
+// CHECK:   [[PROJ:%.*]] = project_box
+// CHECK:   [[ACCESS:%.*]] = begin_access [modify] [unsafe] [[PROJ]] : $*Int
+// CHECK:   store %{{.*}} to [trivial] [[ACCESS]]
+// CHECK:   end_access
+// CHECK:   [[CAPTURE:%.*]] = copy_value %0 : ${ var Int }
+// CHECK:   partial_apply [callee_guaranteed] %{{.*}}([[CAPTURE]]) : $@convention(thin) (@guaranteed { var Int }) -> ()
+// CHECK:   alloc_stack $Int
+// CHECK:   [[UNINIT:%.*]] = mark_uninitialized [var]
+// CHECK:   begin_access [read] [unknown] [[PROJ]]
+// CHECK:   [[VAL:%.*]] = load [trivial]
+// CHECK:   end_access
+// CHECK-NOT: begin_access
+// CHECK:   assign [[VAL]] to [[UNINIT]] : $*Int
+// CHECK:   return {{.*}} : $@callee_guaranteed () -> ()
+// CHECK-LABEL: } // end sil function '$S20access_marker_verify16testCaptureLocalyycyF'
+
+// --- mutating struct.
+func testModifyS(_ arg: StructOfInt) -> StructOfInt {
+  var lhs: StructOfInt
+  lhs = arg
+  lhs.changeMe()
+  return lhs
+}
+// CHECK-LABEL: sil hidden @$S20access_marker_verify11testModifySyAA11StructOfIntVADF : $@convention(thin) (StructOfInt) -> StructOfInt {
+// CHECK: bb0(%0 : @trivial $StructOfInt):
+// CHECK:   alloc_box ${ var StructOfInt }, var, name "lhs"
+// CHECK:   mark_uninitialized [var]
+// CHECK:   project_box
+// CHECK:   begin_access [modify] [unknown]
+// CHECK:   assign
+// CHECK:   end_access
+// CHECK:   begin_access [modify] [unknown]
+// CHECK:   function_ref @$S20access_marker_verify11StructOfIntV8changeMeyyF : $@convention(method) (@inout StructOfInt) -> ()
+// CHECK:   apply
+// CHECK:   end_access
+// CHECK:   begin_access [read] [unknown]
+// CHECK:   load [trivial]
+// CHECK:   end_access
+// CHECK-LABEL: } // end sil function '$S20access_marker_verify11testModifySyAA11StructOfIntVADF'
+
+// --- initialize LValue.
+protocol HasIntGetter {
+  var x: Int { get }
+}
+func testInitLValue(p: HasIntGetter) -> Int {
+  var x = p.x
+  return x
+}
+// CHECK-LABEL: sil hidden @$S20access_marker_verify14testInitLValue1pSiAA12HasIntGetter_p_tF : $@convention(thin) (@in_guaranteed HasIntGetter) -> Int {
+// CHECK: bb0(%0 : @trivial $*HasIntGetter):
+// CHECK:   alloc_box ${ var Int }, var, name "x"
+// CHECK:   [[PROJ:%.*]] = project_box
+// CHECK:   [[OPENED:%.*]] = open_existential_addr immutable_access %0
+// CHECK:   [[X:%.*]] = alloc_stack $@opened
+// CHECK-NOT: begin_access
+// CHECK:   copy_addr %{{.*}} to [initialization] [[X]] : $*@opened
+// CHECK:   witness_method $@opened
+// CHECK:   apply %{{.*}}<@opened("{{.*}}") HasIntGetter>([[X]]) : $@convention(witness_method: HasIntGetter) <τ_0_0 where τ_0_0 : HasIntGetter> (@in_guaranteed τ_0_0) -> Int
+// CHECK:   [[ACCESS:%.*]] = begin_access [modify] [unsafe] [[PROJ]] : $*Int
+// CHECK:   store %{{.*}} to [trivial] [[ACCESS]] : $*Int
+// CHECK:   end_access
+// CHECK:   destroy_addr
+// CHECK:   dealloc_stack
+// CHECK:   begin_access [read] [unknown] [[PROJ]]
+// CHECK:   load [trivial]
+// CHECK:   end_access
+// CHECK-LABEL: } // end sil function '$S20access_marker_verify14testInitLValue1pSiAA12HasIntGetter_p_tF'
+
+// --- initialize let.
+func testCopyS(_ arg: StructOfInt) -> StructOfInt {
+  let lhs: StructOfInt
+  lhs = arg
+  return lhs
+}
+// CHECK-LABEL: sil hidden @$S20access_marker_verify9testCopySyAA11StructOfIntVADF : $@convention(thin) (StructOfInt) -> StructOfInt {
+// CHECK: bb0(%0 : @trivial $StructOfInt):
+// CHECK:   alloc_stack $StructOfInt, let, name "lhs"
+// CHECK:   [[UNINIT:%.*]] = mark_uninitialized [var]
+// CHECK-NOT: begin_access
+// CHECK:   assign %0 to [[UNINIT]] : $*StructOfInt
+// CHECK-NOT: begin_access
+// CHECK:   %5 = load [trivial] [[UNINIT]] : $*StructOfInt
+// CHECK-LABEL: } // end sil function '$S20access_marker_verify9testCopySyAA11StructOfIntVADF'
+
+// --- local var init (single buffer).
+func testLocalVarInit(_ arg: StructOfInt) -> Int {
+  var lhs = arg
+  return lhs.i
+}
+// CHECK-LABEL: sil hidden @$S20access_marker_verify16testLocalVarInitySiAA11StructOfIntVF : $@convention(thin) (StructOfInt) -> Int {
+// CHECK: bb0(%0 : @trivial $StructOfInt):
+// CHECK:   alloc_box ${ var StructOfInt }, var, name "lhs"
+// CHECK:   [[BOX:%.*]] = project_box
+// CHECK:   [[ACCESS:%.*]] = begin_access [modify] [unsafe] [[BOX]]
+// CHECK:   store %0 to [trivial] [[ACCESS]]
+// CHECK:   end_access
+// CHECK-LABEL: } // end sil function '$S20access_marker_verify16testLocalVarInitySiAA11StructOfIntVF'
+
+// --- init generic enum
+enum GenericEnum<T> {
+case V(T)
+
+  init?(t: T) {
+    self = .V(t)
+  }
+}
+
+func testInitGenericEnum<T>(t: T) -> GenericEnum<T>? {
+  return GenericEnum(t: t)
+}
+// CHECK-LABEL: sil hidden @$S20access_marker_verify11GenericEnumO1tACyxGSgx_tcfC : $@convention(method) <T> (@in T, @thin GenericEnum<T>.Type) -> @out Optional<GenericEnum<T>> {
+// CHECK: bb0(%0 : @trivial $*Optional<GenericEnum<T>>, %1 : @trivial $*T, %2 : @trivial $@thin GenericEnum<T>.Type):
+// CHECK:   alloc_box $<τ_0_0> { var GenericEnum<τ_0_0> } <T>, var, name "self"
+// CHECK:   mark_uninitialized [delegatingself] %3 : $<τ_0_0> { var GenericEnum<τ_0_0> } <T>
+// CHECK:   [[PROJ:%.*]] = project_box
+// CHECK:   [[STK:%.*]] = alloc_stack $GenericEnum<T>
+// CHECK:   [[ADR1:%.*]] = init_enum_data_addr [[STK]]
+// CHECK-NOT: begin_access
+// CHECK:   copy_addr %1 to [initialization] [[ADR1]] : $*T
+// CHECK:   inject_enum_addr
+// CHECK:   [[ACCESS:%.*]] = begin_access [modify] [unknown] [[PROJ]]
+// CHECK:   copy_addr [take] %{{.*}} to [[ACCESS]] : $*GenericEnum<T>
+// CHECK:   end_access [[ACCESS]] : $*GenericEnum<T>
+// CHECK:   [[ADR2:%.*]] = init_enum_data_addr %0
+// CHECK-NOT: begin_access
+// CHECK:   copy_addr %{{.*}} to [initialization] [[ADR2]] : $*GenericEnum<T>
+// CHECK:   inject_enum_addr %0 : $*Optional<GenericEnum<T>>, #Optional.some!enumelt.1
+// CHECK-LABEL: } // end sil function '$S20access_marker_verify11GenericEnumO1tACyxGSgx_tcfC'
+
+// -- initialize indirect enum.
+enum IndirectEnum {
+  indirect case V(Int)
+}
+
+func testIndirectEnum() -> IndirectEnum {
+  return IndirectEnum.V(3)
+}
+// CHECK-LABEL: sil hidden @$S20access_marker_verify16testIndirectEnumAA0eF0OyF : $@convention(thin) () -> @owned IndirectEnum {
+// CHECK: bb0:
+// CHECK:   alloc_box ${ var Int }
+// CHECK:   [[PROJ:%.*]] = project_box
+// CHECK:   apply
+// CHECK:   [[ACCESS:%.*]] = begin_access [modify] [unsafe] [[PROJ]]
+// CHECK:   store %{{.*}} to [trivial] [[ACCESS]] : $*Int
+// CHECK:   end_access
+// CHECK:   enum $IndirectEnum, #IndirectEnum.V!enumelt.1
+// CHECK:   return
+// CHECK-LABEL: } // end sil function '$S20access_marker_verify16testIndirectEnumAA0eF0OyF'
+
+// -- indirect enum with getter.
+enum IntEnum {
+  indirect case int(Int)
+
+  var getValue: Int {
+    switch self {
+    case .int(let x): return x
+    }
+  }
+}
+// CHECK-LABEL: sil hidden @$S20access_marker_verify7IntEnumO8getValueSivg : $@convention(method) (@guaranteed IntEnum) -> Int {
+// CHECK: bb0(%0 : @guaranteed $IntEnum):
+// CHECK:   switch_enum %{{.*}} : $IntEnum, case #IntEnum.int!enumelt.1: bb1
+// CHECK: bb1(%{{.*}} : @owned ${ var Int }):
+// CHECK:   [[PROJ:%.*]] = project_box
+// CHECK-NOT: begin_access
+// CHECK:   load [trivial] [[PROJ]] : $*Int
+// CHECK-LABEL: } // end sil function '$S20access_marker_verify7IntEnumO8getValueSivg'
+
+// -- indirect enum reference.
+enum RefEnum {
+  indirect case ref(BaseClass)
+
+  var getValue: BaseClass {
+    switch self {
+    case .ref(let c): return c
+    }
+  }
+}
+// CHECK-LABEL: sil hidden @$S20access_marker_verify7RefEnumO8getValueAA9BaseClassCvg : $@convention(method) (@guaranteed RefEnum) -> @owned BaseClass {
+// CHECK: bb0(%0 : @guaranteed $RefEnum):
+// CHECK:   switch_enum %{{.*}} : $RefEnum, case #RefEnum.ref!enumelt.1: bb1
+// CHECK: bb1(%{{.*}} : @owned ${ var BaseClass }):
+// CHECK:   [[PROJ:%.*]] = project_box %{{.*}} : ${ var BaseClass }, 0
+// CHECK-NOT: begin_access
+// CHECK:   load_borrow [[PROJ]] : $*BaseClass
+// CHECK-LABEL: } // end sil function '$S20access_marker_verify7RefEnumO8getValueAA9BaseClassCvg'
+
+// --- indirect enum pattern.
+func testEnumPattern(ie: IndirectEnum) -> Bool {
+  guard case .V(let kind) = ie else {
+    return false
+  }
+  _ = kind
+  return true
+}
+// CHECK-LABEL: sil hidden @$S20access_marker_verify15testEnumPattern2ieSbAA08IndirectE0O_tF : $@convention(thin) (@guaranteed IndirectEnum) -> Bool {
+// CHECK: bb0(%0 : @guaranteed $IndirectEnum):
+// CHECK:   switch_enum %{{.*}} : $IndirectEnum, case #IndirectEnum.V!enumelt.1: [[BBV:bb.*]], default bb
+// CHECK: [[BBV]](%{{.*}} : @owned ${ var Int }):
+// CHECK:   [[PROJ:%.*]] = project_box
+// CHECK-NOT: begin_access
+// CHECK:   load [trivial] [[PROJ]] : $*Int
+// CHECK-LABEL: } // end sil function '$S20access_marker_verify15testEnumPattern2ieSbAA08IndirectE0O_tF'
+
+// --- enum LValue.
+struct StructOfEnum {
+  var e: E
+  var f: E
+}
+func enumLValueHelper(_: inout E, _: inout E) {}
+
+// CHECK-LABEL: sil hidden @$S20access_marker_verify14testEnumLValue1syAA08StructOfE0Vz_tF : $@convention(thin) (@inout StructOfEnum) -> () {
+// CHECK: bb0(%0 : @trivial $*StructOfEnum):
+// CHECK:   begin_access [modify] [unknown] %0 : $*StructOfEnum
+// CHECK:   struct_element_addr %2 : $*StructOfEnum, #StructOfEnum.e
+// CHECK:   begin_access [modify] [unknown] %0 : $*StructOfEnum
+// CHECK:   struct_element_addr %4 : $*StructOfEnum, #StructOfEnum.f
+// CHECK:   function_ref @$S20access_marker_verify16enumLValueHelperyyAA1EOz_ADztF : $@convention(thin) (@inout E, @inout E) -> ()
+// CHECK:   apply %6(%3, %5) : $@convention(thin) (@inout E, @inout E) -> ()
+// CHECK:   end_access %4 : $*StructOfEnum
+// CHECK:   end_access %2 : $*StructOfEnum
+// CHECK:   %10 = tuple ()
+// CHECK:   return %10 : $()
+// CHECK-LABEL: } // end sil function '$S20access_marker_verify14testEnumLValue1syAA08StructOfE0Vz_tF'
+func testEnumLValue(s: inout StructOfEnum) {
+  enumLValueHelper(&s.e, &s.f)
+}
+
+// --- Optional access.
+func accessOptionalArray(_ dict : [Int : [Int]] = [:]) {
+  var dict = dict
+  dict[1]?.append(2)
+}
+// CHECK-LABEL: sil hidden @$S20access_marker_verify0A13OptionalArrayyys10DictionaryVySiSaySiGGF : $@convention(thin) (@guaranteed Dictionary<Int, Array<Int>>) -> () {
+// CHECK: bb0(%0 : @guaranteed $Dictionary<Int, Array<Int>>):
+// CHECK:   alloc_box ${ var Dictionary<Int, Array<Int>> }, var, name "dict"
+// CHECK:   [[PROJ:%.*]] = project_box
+// ----- initialize the box.
+// CHECK:   [[INITACCESS:%.*]] = begin_access [modify] [unsafe] [[PROJ]]
+// CHECK:   store %{{.*}} to [init] [[INITACCESS]]
+// CHECK:   end_access [[INITACCESS]]
+// ----- begin formal access for Dictionary.subscript.setter
+// CHECK:   [[BOXACCESS:%.*]] = begin_access [modify] [unknown] [[PROJ]]
+// CHECK:   [[TEMP:%.*]] = alloc_stack $Optional<Array<Int>>
+// CHECK:   load_borrow [[BOXACCESS]] : $*Dictionary<Int, Array<Int>>
+// ----- Initialize some trivial temporaries.
+// CHECK:   alloc_stack $Int
+// CHECK-NOT: begin_access
+// CHECK:   store %{{.*}} to [trivial]
+// ----- Call Dictionary.subscript.getter.
+// CHECK-NOT: begin_access
+// CHECK:   apply %{{.*}}<Int, [Int]>
+// ----- access the temporary array result of the getter
+// CHECK:   [[TEMPACCESS:%.*]] = begin_access [modify] [unsafe] [[TEMP]]
+// CHECK:   select_enum_addr [[TEMPACCESS]] : $*Optional<Array<Int>>, case #Optional.some!enumelt.1
+// CHECK:   cond_br %{{.*}}, bb2, bb1
+//
+// CHECK: bb1:
+// CHECK:   [[TEMPARRAY:%.*]] = load [copy] [[TEMPACCESS]]
+// CHECK:   [[WRITEBACK:%.*]] = alloc_stack $Optional<Array<Int>>
+// CHECK-NOT: begin_access
+// CHECK:   store [[TEMPARRAY]] to [init] [[WRITEBACK]]
+// CHECK:   alloc_stack $Int
+// CHECK-NOT: begin_access
+// CHECK:   store %{{.*}} to [trivial] %29 : $*Int
+// Call Dictionary.subscript.setter
+// CHECK:   apply %{{.*}}<Int, [Int]>([[WRITEBACK]], %{{.*}}, [[BOXACCESS]]) : $@convention(method) <τ_0_0, τ_0_1 where τ_0_0 : Hashable> (@in Optional<τ_0_1>, @in τ_0_0, @inout Dictionary<τ_0_0, τ_0_1>) -> ()
+// CHECK:   end_access [[TEMPACCESS]] : $*Optional<Array<Int>>
+// CHECK:   end_access [[BOXACCESS]] : $*Dictionary<Int, Array<Int>>
+// CHECK:   br
+//
+// CHECK: bb2:
+// CHECK-NOT: begin_access
+// CHECK:   [[TEMPARRAYADR:%.*]] = unchecked_take_enum_data_addr [[TEMPACCESS]] : $*Optional<Array<Int>>, #Optional.some!enumelt.1
+// ----- call Array.append
+// CHECK:   alloc_stack $Int
+// CHECK:   store %{{.*}} to [trivial]
+// CHECK:   function_ref @$SSa6appendyyxF : $@convention(method) <τ_0_0> (@in_guaranteed τ_0_0, @inout Array<τ_0_0>) -> ()
+// CHECK:   apply %{{.*}}<Int>(%{{.*}}, [[TEMPARRAYADR]]) : $@convention(method) <τ_0_0> (@in_guaranteed τ_0_0, @inout Array<τ_0_0>) -> ()
+// CHECK:   [[TEMPARRAYVAL:%.*]] = load [take] [[TEMPACCESS]] : $*Optional<Array<Int>>
+// CHECK:   [[ARRAYCOPY:%.*]] = alloc_stack $Optional<Array<Int>>
+// CHECK:   store [[TEMPARRAYVAL]] to [init] [[ARRAYCOPY]] : $*Optional<Array<Int>>
+// CHECK:   alloc_stack $Int
+// CHECK:   store %{{.*}} to [trivial]
+// ----- call Dictionary.subscript.setter
+// CHECK: apply %{{.*}}<Int, [Int]>([[ARRAYCOPY]], %{{.*}}, [[BOXACCESS]]) : $@convention(method) <τ_0_0, τ_0_1 where τ_0_0 : Hashable> (@in Optional<τ_0_1>, @in τ_0_0, @inout Dictionary<τ_0_0, τ_0_1>) -> ()
+// CHECK-LABEL: } // end sil function '$S20access_marker_verify0A13OptionalArrayyys10DictionaryVySiSaySiGGF'
+
+// --- Optional map.
+enum OptionalWithMap<Wrapped> {
+  case none
+
+  case some(Wrapped)
+
+  init(_ some: Wrapped) { self = .some(some) }
+
+  func map<U>(
+    _ transform: (Wrapped) throws -> U
+  ) rethrows -> U? {
+    switch self {
+    case .some(let y):
+      return .some(try transform(y))
+    case .none:
+      return .none
+    }
+  }
+}
+// CHECK-LABEL: sil hidden @$S20access_marker_verify15OptionalWithMapO3mapyqd__Sgqd__xKXEKlF : $@convention(method) <Wrapped><U> (@noescape @callee_guaranteed (@in_guaranteed Wrapped) -> (@out U, @error Error), @in_guaranteed OptionalWithMap<Wrapped>) -> (@out Optional<U>, @error Error) {
+// CHECK: bb0(%0 : @trivial $*Optional<U>, %1 : @trivial $@noescape @callee_guaranteed (@in_guaranteed Wrapped) -> (@out U, @error Error), %2 : @trivial $*OptionalWithMap<Wrapped>):
+// CHECK: [[STK:%.]] = alloc_stack $OptionalWithMap<Wrapped>
+// CHECK-NOT: begin_access
+// CHECK: copy_addr %2 to [initialization] [[STK]] : $*OptionalWithMap<Wrapped>
+// CHECK: switch_enum_addr [[STK]] : $*OptionalWithMap<Wrapped>, case #OptionalWithMap.some!enumelt.1: [[BBSOME:bb.*]], case #OptionalWithMap.none!enumelt: bb
+//
+// CHECK: [[BBSOME]]:
+// CHECK-NOT: begin_access
+// CHECK: [[ADR:%.*]] = unchecked_take_enum_data_addr [[STK]]
+// CHECK: alloc_stack $Wrapped, let, name "y"
+// CHECK-NOT: begin_access
+// CHECK: copy_addr [take] [[ADR]] to [initialization]
+// ----- call transform.
+// CHECK: try_apply
+// CHECK-LABEL: } // end sil function '$S20access_marker_verify15OptionalWithMapO3mapyqd__Sgqd__xKXEKlF'
+
+// --- delegating initializer.
+struct DelegatingInit {
+  var i: Int
+  init(i: Int) {
+    self.i = i
+  }
+  init() {
+    self.init(i: 4)
+  }
+}
+// CHECK-LABEL: sil hidden @$S20access_marker_verify14DelegatingInitV1iACSi_tcfC : $@convention(method) (Int, @thin DelegatingInit.Type) -> DelegatingInit {
+// CHECK: bb0(%0 : @trivial $Int, %1 : @trivial $@thin DelegatingInit.Type):
+// CHECK:   alloc_box ${ var DelegatingInit }, var, name "self"
+// CHECK:   mark_uninitialized [rootself] %2 : ${ var DelegatingInit }
+// CHECK:   [[BOX:%.*]] = project_box
+// CHECK:   begin_access [modify] [unknown]
+// CHECK:   struct_element_addr
+// CHECK:   assign
+// CHECK:   end_access
+// CHECK-NOT: begin_access
+// CHECK:   load [trivial] [[BOX]] : $*DelegatingInit
+// CHECK:   destroy_value
+// CHECK:   return %10 : $DelegatingInit
+// CHECK-LABEL: } // end sil function '$S20access_marker_verify14DelegatingInitV1iACSi_tcfC'
+
+// --- addressor.
+func testAddressor(p: UnsafePointer<Int>) -> Int {
+  return p.pointee
+}
+// CHECK-LABEL: sil hidden @$S20access_marker_verify13testAddressor1pSiSPySiG_tF : $@convention(thin) (UnsafePointer<Int>) -> Int {
+// CHECK: bb0(%0 : @trivial $UnsafePointer<Int>):
+// CHECK:   apply
+// CHECK:   struct_extract
+// CHECK:   [[ADR:%.*]] = pointer_to_address
+// CHECK-NOT: begin_access
+// CHECK:   load [trivial] [[ADR]] : $*Int
+// CHECK:   return
+// CHECK-LABEL: } // end sil function '$S20access_marker_verify13testAddressor1pSiSPySiG_tF'
+
+// --- shims.
+func testShims() -> UInt32 {
+  return _SwiftKeyPathBufferHeader_SizeMask
+}
+// CHECK-LABEL: sil hidden @$S20access_marker_verify9testShimss6UInt32VyF : $@convention(thin) () -> UInt32 {
+// CHECK: bb0:
+// CHECK:   [[GA:%.*]] = global_addr @_SwiftKeyPathBufferHeader_SizeMask : $*UInt32
+// CHECK-NOT: begin_access
+// CHECK:   load [trivial] [[GA]] : $*UInt32
+// CHECK:   return
+// CHECK-LABEL: } // end sil function '$S20access_marker_verify9testShimss6UInt32VyF'
+
+// --- global variable initialization.
+var globalString1 = "⓪" // start non-empty
+// CHECK-LABEL: sil private @globalinit_33_{{.*}}_func0 : $@convention(c) () -> () {
+// CHECK: alloc_global @$S20access_marker_verify13globalString1SSvp
+// CHECK: [[GA:%.*]] = global_addr @$S20access_marker_verify13globalString1SSvp : $*String
+// CHECK: apply
+// CHECK: [[ACCESS:%.*]] = begin_access [modify] [unsafe] [[GA]] : $*String
+// CHECK: store %{{.*}} to [init] [[ACCESS]] : $*String
+// CHECK: end_access
+// CHECK-LABEL: } // end sil function 'globalinit_33_180BF7B9126DB0C8C6C26F15ACD01908_func0'
+
+var globalString2 = globalString1
+// CHECK-LABEL: sil private @globalinit_33_180BF7B9126DB0C8C6C26F15ACD01908_func1 : $@convention(c) () -> () {
+// CHECK: alloc_global @$S20access_marker_verify13globalString2SSvp
+// CHECK: [[GA:%.*]] = global_addr @$S20access_marker_verify13globalString2SSvp : $*String
+// CHECK: apply
+// CHECK: [[PTR:%.*]] = pointer_to_address
+// CHECK: [[ACCESS:%.*]] = begin_access [read] [dynamic] [[PTR]] : $*String
+// CHECK-NOT: begin_access
+// CHECK: copy_addr [[ACCESS]] to [initialization] [[GA]] : $*String
+// CHECK: end_access [[ACCESS]] : $*String
+// CHECK-NOT: end_access
+// CHECK-LABEL: } // end sil function 'globalinit_33_180BF7B9126DB0C8C6C26F15ACD01908_func1'
+
+
+// --- getter.
+struct GenericStructWithGetter<T> {
+  var t: T
+  var val: Int
+
+  struct Value {
+    internal var val: Int
+    
+    internal init(_ val: Int) { self.val = val }
+  }
+  var value : Value {
+    get { return Value(val) }
+  }
+}
+// CHECK-LABEL: sil hidden @$S20access_marker_verify23GenericStructWithGetterV5valueAC5ValueVyx_Gvg : $@convention(method) <T> (@in_guaranteed GenericStructWithGetter<T>) -> GenericStructWithGetter<T>.Value {
+// CHECK: bb0(%0 : @trivial $*GenericStructWithGetter<T>):
+// CHECK:   [[ADR:%.*]] = struct_element_addr %0 : $*GenericStructWithGetter<T>, #GenericStructWithGetter.val
+// CHECK-NOT: begin_access
+// CHECK:   load [trivial] [[ADR]] : $*Int
+// CHECK:   apply
+// CHECK-LABEL: } // end sil function '$S20access_marker_verify23GenericStructWithGetterV5valueAC5ValueVyx_Gvg'
+
+// --- setter.
+struct StructWithSetter {
+  var _val: Int
+
+  internal var val: Int {
+    get {
+      return _val
+    }
+    set {
+      _val = newValue
+    }
+  }
+
+  mutating func inc(incVal: Int) {
+    val += incVal
+  }
+}
+// CHECK-LABEL: sil hidden @$S20access_marker_verify16StructWithSetterV3inc0G3ValySi_tF : $@convention(method) (Int, @inout StructWithSetter) -> () {
+// CHECK: bb0(%0 : @trivial $Int, %1 : @trivial $*StructWithSetter):
+// CHECK: [[FORMALACCESS:%.*]] = begin_access [modify] [unknown] %1
+// CHECK: alloc_stack $Int
+// CHECK: load [trivial] [[FORMALACCESS]] : $*StructWithSetter
+// CHECK: [[GETTER:%.*]] = function_ref @$S20access_marker_verify16StructWithSetterV3valSivg
+// CHECK: apply [[GETTER]]
+// CHECK: begin_access [modify] [unsafe]
+// CHECK: store %{{.*}} to [trivial]
+// CHECK: end_access
+// CHECK: begin_access [modify] [unsafe]
+// CHECK: [[INC:%.*]] = function_ref @$SSi2peoiyySiz_SitFZ
+// CHECK: apply [[INC]]
+// CHECK: load [trivial] %13 : $*Int
+// CHECK: [[SETTER:%.*]] = function_ref @$S20access_marker_verify16StructWithSetterV3valSivs
+// CHECK: apply [[SETTER]]
+// CHECK: end_access
+// CHECK: end_access [[FORMALACCESS]]
+// CHECK-LABEL: } // end sil function '$S20access_marker_verify16StructWithSetterV3inc0G3ValySi_tF'
+
+// --- lazy inout.
+func increment(_ x: inout Int) { x += 1 }
+
+final class LazyFinalClassProperty {
+  lazy var cat: Int = 5
+}
+
+func inoutWriteOfLazyFinalClassProperty(l: inout LazyFinalClassProperty) {
+  increment(&l.cat)
+}
+// CHECK-LABEL: sil hidden @$S20access_marker_verify34inoutWriteOfLazyFinalClassProperty1lyAA0ghiJ0Cz_tF : $@convention(thin) (@inout LazyFinalClassProperty) -> () {
+// CHECK: bb0(%0 : @trivial $*LazyFinalClassProperty):
+// CHECK:   [[FORMALACCESS:%.*]] = begin_access [read] [unknown] %0 : $*LazyFinalClassProperty
+// CHECK:   load [copy] [[FORMALACCESS]] : $*LazyFinalClassProperty
+// CHECK:   end_access [[FORMALACCESS]] : $*LazyFinalClassProperty
+// CHECK:   // function_ref LazyFinalClassProperty.cat.getter
+// CHECK:   [[GETTER:%.*]] = function_ref @$S20access_marker_verify22LazyFinalClassPropertyC3catSivg
+// CHECK:   apply [[GETTER]]
+// CHECK:   begin_access [modify] [unsafe]
+// CHECK:   store %{{.*}} to [trivial]
+// CHECK:   end_access
+// CHECK:   [[TEMPACCESS:%.*]] = begin_access [modify] [unsafe] %5 : $*Int
+// CHECK:   [[INC:%.*]] = function_ref @$S20access_marker_verify9incrementyySizF : $@convention(thin) (@inout Int) -> ()
+// CHECK:   apply [[INC]]([[TEMPACCESS]]) : $@convention(thin) (@inout Int) -> ()
+// CHECK:   load [trivial] [[TEMPACCESS]] : $*Int
+// CHECK:   [[SETTER:%.*]] = function_ref @$S20access_marker_verify22LazyFinalClassPropertyC3catSivs
+// CHECK:   apply [[SETTER]]
+// CHECK:   end_access [[TEMPACCESS]] : $*Int
+// CHECK-LABEL: } // end sil function '$S20access_marker_verify34inoutWriteOfLazyFinalClassProperty1lyAA0ghiJ0Cz_tF'
+
+// --- lazy getter.
+func inoutAccessOfLazyFinalClassProperty(
+  l: inout LazyFinalClassProperty
+) -> Int {
+  return l.cat
+}
+// CHECK-LABEL: sil hidden @$S20access_marker_verify35inoutAccessOfLazyFinalClassProperty1lSiAA0ghiJ0Cz_tF : $@convention(thin) (@inout LazyFinalClassProperty) -> Int {
+// CHECK: bb0(%0 : @trivial $*LazyFinalClassProperty):
+// CHECK:   begin_access [read] [unknown] %0
+// CHECK:   load [copy]
+// CHECK:   end_access
+// CHECK:   [[GETTER:%.*]] = function_ref @$S20access_marker_verify22LazyFinalClassPropertyC3catSivg : $@convention(method) (@guaranteed LazyFinalClassProperty) -> Int
+// CHECK:   apply [[GETTER]]
+// CHECK-LABEL: } // end sil function '$S20access_marker_verify35inoutAccessOfLazyFinalClassProperty1lSiAA0ghiJ0Cz_tF'
+
+// --- polymorphic getter
+protocol Abstractable {
+  associatedtype Result
+  var storedFunction: () -> Result { get set }
+}
+
+class C : Abstractable {
+  var storedFunction: () -> Int = { 0 }
+}
+// CHECK-LABEL: sil private [transparent] [thunk] @$S20access_marker_verify1CCAA12AbstractableA2aDP14storedFunction6ResultQzycvmTW : $@convention(witness_method: Abstractable) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout C) -> (Builtin.RawPointer, Optional<Builtin.RawPointer>) {
+// CHECK: bb0(%0 : @trivial $Builtin.RawPointer, %1 : @trivial $*Builtin.UnsafeValueBuffer, %2 : @trivial $*C):
+// CHECK:   [[ADR:%.*]] = pointer_to_address %0 : $Builtin.RawPointer to [strict] $*@callee_guaranteed () -> @out Int
+// CHECK:   [[TEMP:%.*]] = alloc_stack $@callee_guaranteed () -> Int
+// CHECK:   [[GETTER:%.*]] = apply
+// CHECK:   [[ACCESS:%.*]] = begin_access [modify] [unsafe] [[TEMP]] : $*@callee_guaranteed () -> Int
+// CHECK:   store %{{.*}} to [init] [[ACCESS]] : $*@callee_guaranteed () -> Int
+// CHECK:   end_access [[ACCESS]] : $*@callee_guaranteed () -> Int
+// CHECK-NOT: begin_access
+// CHECK:   load [copy] [[TEMP]] : $*@callee_guaranteed () -> Int
+// CHECK:   [[PA:%.*]] = partial_apply
+// CHECK:   destroy_addr [[TEMP]] : $*@callee_guaranteed () -> Int
+// CHECK-NOT: begin_access
+// CHECK:   store [[PA]] to [init] [[ADR]] : $*@callee_guaranteed () -> @out Int
+// CHECK:   [[PTR:%.*]] = address_to_pointer [[ADR]] : $*@callee_guaranteed () -> @out Int to $Builtin.RawPointer
+// CHECK:   [[FPTR:%.*]] = thin_function_to_pointer %{{.*}} : $@convention(witness_method: Abstractable) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout C, @thick C.Type) -> () to $Builtin.RawPointer
+// CHECK:   [[ENUM:%.*]] = enum $Optional<Builtin.RawPointer>, #Optional.some!enumelt.1, [[FPTR]] : $Builtin.RawPointer
+// CHECK:   [[R:%.*]] = tuple ([[PTR]] : $Builtin.RawPointer, [[ENUM]] : $Optional<Builtin.RawPointer>)
+// CHECK:   return [[R]] : $(Builtin.RawPointer, Optional<Builtin.RawPointer>)
+// CHECK-LABEL: } // end sil function '$S20access_marker_verify1CCAA12AbstractableA2aDP14storedFunction6ResultQzycvmTW'
+
+// --- writeback address-only.
+var addressOnly: P {
+  get {
+    return StructP()
+  }
+  set {}
+}
+
+func takesInoutP(x: inout P) {}
+
+func testWriteback() {
+  takesInoutP(x: &addressOnly)
+}
+// CHECK-LABEL: sil hidden @$S20access_marker_verify13testWritebackyyF : $@convention(thin) () -> () {
+// CHECK: bb0:
+// CHECK:   %0 = alloc_stack $P
+// CHECK: [[GETTER:%.*]] = apply
+// CHECK: [[ACCESS:%.*]] = begin_access [modify] [unsafe] %0 : $*P
+// Call takesInoutP
+// CHECK: apply %{{.*}}([[ACCESS]]) : $@convention(thin) (@inout P) -> ()
+// Call addressOnly.setter
+// CHECK: apply %{{.*}}([[ACCESS]]) : $@convention(thin) (@in P) -> ()
+// CHECK: end_access [[ACCESS]] : $*P
+// CHECK-LABEL: } // end sil function '$S20access_marker_verify13testWritebackyyF'
+
+// --- writeback temp.
+struct MutableStorage {
+  mutating func push() {}
+}
+
+class Container {
+  var storage: MutableStorage
+
+  init() {
+    storage = MutableStorage()
+  }
+
+  func testWritebackTemp() {
+    self.storage.push()
+  }
+}
+// CHECK-LABEL: sil hidden @$S20access_marker_verify9ContainerC17testWritebackTempyyF : $@convention(method) (@guaranteed Container) -> () {
+// CHECK: bb0(%0 : @guaranteed $Container):
+// call storage.materializeForSet
+// CHECK: [[MATSET:%.*]] = class_method %0 : $Container, #Container.storage!materializeForSet.1
+// CHECK: apply [[MATSET]]
+// call MutableStorage.push()
+// CHECK: apply %{{.*}}(%{{.*}}) : $@convention(method) (@inout MutableStorage) -> ()
+// CHECK: switch_enum %{{.*}} : $Optional<Builtin.RawPointer>, case #Optional.some!enumelt.1: [[BBSOME:bb.*]], case #Optional.none!enumelt: bb
+// CHECK: [[BBSOME]]([[WB:%.*]] : @trivial $Builtin.RawPointer):
+// CHECK: [[WBF:%.*]] = pointer_to_thin_function [[WB]]
+// CHECK: [[TEMP:%.*]] = alloc_stack $Container
+// CHECK: [[ACCESS:%.*]] = begin_access [modify] [unsafe] [[TEMP]] : $*Container
+// CHECK: store_borrow %0 to [[ACCESS]] : $*Container
+// writeback
+// CHECK: apply [[WBF]]
+// CHECK: end_access [[ACCESS]] : $*Container
+// CHECK-LABEL: } // end sil function '$S20access_marker_verify9ContainerC17testWritebackTempyyF'
+
+// --- return mixed tuple
+protocol HasClassGetter {
+  var c: BaseClass { get }
+}
+func testMixedTuple(p: HasClassGetter) -> (BaseClass, Any) {
+  return (p.c, p.c)
+}
+// CHECK-LABEL: sil hidden @$S20access_marker_verify14testMixedTuple1pAA9BaseClassC_yptAA03HasH6Getter_p_tF : $@convention(thin) (@in_guaranteed HasClassGetter) -> (@owned BaseClass, @out Any) {
+// CHECK: bb0(%0 : @trivial $*Any, %1 : @trivial $*HasClassGetter):
+// CHECK: [[P1:%.*]] = open_existential_addr immutable_access %1 : $*HasClassGetter to $*@opened
+// CHECK: [[TEMP1:%.*]] = alloc_stack $@opened
+// CHECK-NOT: begin_access
+// CHECK: copy_addr [[P1]] to [initialization] [[TEMP1]] : $*@opened
+// CHECK-NOT: begin_access
+// CHECK: [[OUTC:%.*]] = apply {{.*}} $@convention(witness_method: HasClassGetter) <τ_0_0 where τ_0_0 : HasClassGetter> (@in_guaranteed τ_0_0) -> @owned BaseClass
+// CHECK: [[OUTANY:%.*]] = init_existential_addr %0 : $*Any, $BaseClass
+// CHECK: [[P2:%.*]] = open_existential_addr immutable_access %1 : $*HasClassGetter to $*@opened
+// CHECK: [[TEMP2:%.*]] = alloc_stack $@opened
+// CHECK-NOT: begin_access
+// CHECK: copy_addr [[P2]] to [initialization] [[TEMP2]] : $*@opened
+// CHECK-NOT: begin_access
+// CHECK: apply {{.*}} $@convention(witness_method: HasClassGetter) <τ_0_0 where τ_0_0 : HasClassGetter> (@in_guaranteed τ_0_0) -> @owned BaseClass
+// CHECK: store %{{.*}} to [init] [[OUTANY]] : $*BaseClass
+// CHECK: return [[OUTC]] : $BaseClass
+// CHECK-LABEL: } // end sil function '$S20access_marker_verify14testMixedTuple1pAA9BaseClassC_yptAA03HasH6Getter_p_tF'
+
+// --- existential cast.
+internal protocol CanCast {
+  func unbox<T : Hashable>() -> T?
+}
+
+internal struct CanCastStruct<Base : Hashable> : CanCast {
+  internal var base: Base
+
+  internal func unbox<T : Hashable>() -> T? {
+    return (self as CanCast as? CanCastStruct<T>)?.base
+  }
+}
+// CHECK-LABEL: sil hidden @$S20access_marker_verify13CanCastStructV5unboxqd__Sgys8HashableRd__lF : $@convention(method) <Base where Base : Hashable><T where T : Hashable> (@in_guaranteed CanCastStruct<Base>) -> @out Optional<T> {
+// CHECK: bb0(%0 : @trivial $*Optional<T>, %1 : @trivial $*CanCastStruct<Base>):
+// CHECK: [[OUT_ENUM:%.*3]] = init_enum_data_addr %0 : $*Optional<T>, #Optional.some!enumelt.1
+// CHECK: [[TEMP_SUB:%.*]] = alloc_stack $Optional<CanCastStruct<T>>
+// CHECK: [[TEMP_BASE:%.*]] = alloc_stack $CanCast
+// CHECK: [[TEMP_BASE_ADR:%.*]] = init_existential_addr [[TEMP_BASE]] : $*CanCast, $CanCastStruct<Base>
+// CHECK-NOT: begin_access
+// CHECK: copy_addr %1 to [initialization] [[TEMP_BASE_ADR]] : $*CanCastStruct<Base>
+// CHECK-NOT: begin_access
+// CHECK: [[TEMP_SUB_ADR:%.*]] = init_enum_data_addr [[TEMP_SUB]] : $*Optional<CanCastStruct<T>>, #Optional.some!enumelt.1
+// CHECK-NOT: begin_access
+// CHECK: checked_cast_addr_br take_always CanCast in [[TEMP_BASE]] : $*CanCast to CanCastStruct<T> in [[TEMP_SUB_ADR]] : $*CanCastStruct<T>
+// CHECK-NOT: begin_access
+// CHECK: [[TEMP_DATA:%.*]] = unchecked_take_enum_data_addr [[TEMP_SUB]] : $*Optional<CanCastStruct<T>>, #Optional.some!enumelt.1
+// CHECK: [[ACCESS:%.*]] = begin_access [read] [unsafe] [[TEMP_DATA]] : $*CanCastStruct<T>
+// CHECK: [[BASE_ADR:%.*]] = struct_element_addr [[ACCESS]] : $*CanCastStruct<T>, #CanCastStruct.base
+// CHECK-NOT: begin_access
+// CHECK: copy_addr [[BASE_ADR]] to [initialization] [[OUT_ENUM]] : $*T
+// CHECK: end_access [[ACCESS]] : $*CanCastStruct<T>
+// CHECK-NOT: begin_access
+// CHECK: inject_enum_addr %0 : $*Optional<T>, #Optional.some!enumelt.1
+// CHECK-LABEL: } // end sil function '$S20access_marker_verify13CanCastStructV5unboxqd__Sgys8HashableRd__lF'
+
+// --- open existential
+protocol Q : PBar {}
+
+func testOpenExistential(p: PBar) {
+  let q0 = p as? Q
+  if q0 != nil, let q = q0 {
+    q.bar()
+  }
+}
+// CHECK-LABEL: sil hidden @$S20access_marker_verify19testOpenExistential1pyAA4PBar_p_tF : $@convention(thin) (@in_guaranteed PBar) -> () {
+// CHECK: bb0(%0 : @trivial $*PBar):
+// CHECK: [[Q0:%.*]] = alloc_stack $Optional<Q>, let, name "q0"
+// CHECK: [[PBAR:%.*]] = alloc_stack $PBar
+// CHECK-NOT: begin_access
+// CHECK: copy_addr %0 to [initialization] [[PBAR]] : $*PBar
+// CHECK-NOT: begin_access
+// CHECK: [[Q0_DATA:%.*]] = init_enum_data_addr [[Q0]] : $*Optional<Q>, #Optional.some!enumelt.1
+// CHECK-NOT: begin_access
+// CHECK: checked_cast_addr_br take_always PBar in [[PBAR]] : $*PBar to Q in [[Q0_DATA]] : $*Q, bb1, bb2
+// CHECK-NOT: begin_access
+// CHECK: inject_enum_addr [[Q0]] : $*Optional<Q>, #Optional.some!enumelt.1
+// CHECK-NOT: begin_access
+// CHECK: apply %{{.*}}<Q>([[Q0]], {{.*}}) : $@convention(method) <τ_0_0> (@in_guaranteed Optional<τ_0_0>, _OptionalNilComparisonType, @thin Optional<τ_0_0>.Type) -> Bool
+// CHECK: [[Q:%.*]] = alloc_stack $Q, let, name "q"
+// CHECK: [[OPT_Q:%.*]] = alloc_stack $Optional<Q>
+// CHECK-NOT: begin_access
+// CHECK: copy_addr [[Q0]] to [initialization] [[OPT_Q]] : $*Optional<Q>
+// CHECK-NOT: begin_access
+// CHECK: switch_enum_addr [[OPT_Q]] : $*Optional<Q>, case #Optional.some!enumelt.1: bb
+// CHECK-NOT: begin_access
+// CHECK: [[OPT_Q_ADR:%.*]] = unchecked_take_enum_data_addr [[OPT_Q]] : $*Optional<Q>, #Optional.some!enumelt.1
+// CHECK-NOT: begin_access
+// CHECK: copy_addr [take] [[OPT_Q_ADR]] to [initialization] [[Q]] : $*Q
+// CHECK-NOT: begin_access
+// CHECK: [[Q_ADR:%.*]] = open_existential_addr immutable_access [[Q]] : $*Q to $*@opened("{{.*}}") Q
+// CHECK: witness_method $@opened("{{.*}}") Q, #PBar.bar!1
+// CHECK: apply %{{.*}}<@opened("{{.*}}") Q>([[Q_ADR]])
+// CHECK-LABEL: } // end sil function '$S20access_marker_verify19testOpenExistential1pyAA4PBar_p_tF'
+
+// --- local existential
+func getP() -> P {
+  struct S : P {}
+  return S()
+}
+
+func testLocalExistential() {
+  var p = getP()
+  takesClosure { p = getP() }
+  _ = p
+}
+// CHECK-LABEL: sil hidden @$S20access_marker_verify20testLocalExistentialyyF : $@convention(thin) () -> () {
+// CHECK: alloc_box ${ var P }, var, name "p"
+// CHECK: [[PROJ:%.*]] = project_box %{{.*}} : ${ var P }, 0
+// CHECK-NOT: begin_access
+// CHECK: apply %{{.*}}([[PROJ]]) : $@convention(thin) () -> @out P
+// CHECK-NOT: begin_access
+// CHECK: partial_apply [callee_guaranteed] %{{.*}}([[PROJ]]) : $@convention(thin) (@inout_aliasable P) -> ()
+// CHECK-NOT: begin_access
+// CHECK: apply
+// CHECK: [[TMP:%.*]] = alloc_stack $P
+// CHECK: [[UNINIT:%.*]] = mark_uninitialized [var] [[TMP]] : $*P
+// CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] [[PROJ]] : $*P
+// CHECK: [[COPY:%.*]] = alloc_stack $P
+// CHECK-NOT: begin_access
+// CHECK: copy_addr [[ACCESS]] to [initialization] [[COPY]] : $*P
+// CHECK: end_access
+// CHECK-NOT: begin_access
+// CHECK: copy_addr [take] [[COPY]] to [[UNINIT]] : $*P
+// CHECK-LABEL: } // end sil function '$S20access_marker_verify20testLocalExistentialyyF'
+
+// --- address-only argument.
+protocol UsesSelf {
+  func bar(_: Self)
+}
+
+extension UsesSelf {
+  static func testSelf(a: Self, b: Self) {
+    a.bar(b)
+  }
+}
+// CHECK-LABEL: sil hidden @$S20access_marker_verify8UsesSelfPAAE04testE01a1byx_xtFZ : $@convention(method) <Self where Self : UsesSelf> (@in_guaranteed Self, @in_guaranteed Self, @thick Self.Type) -> () {
+// CHECK: bb0(%0 : @trivial $*Self, %1 : @trivial $*Self, %2 : @trivial $@thick Self.Type):
+// CHECK: apply %{{.*}}<Self>(%1, %0) : $@convention(witness_method: UsesSelf) <τ_0_0 where τ_0_0 : UsesSelf> (@in_guaranteed τ_0_0, @in_guaranteed τ_0_0) -> ()
+// CHECK-LABEL: } // end sil function '$S20access_marker_verify8UsesSelfPAAE04testE01a1byx_xtFZ'
+
+// --- autoclosure
+struct StructWithLayout {
+  internal init() {
+    _sanityCheck(MemoryLayout.size(ofValue: self) >= 0)
+  }
+}
+// CHECK-LABEL: sil hidden @$S20access_marker_verify16StructWithLayoutVACycfC : $@convention(method) (@thin StructWithLayout.Type) -> StructWithLayout {
+// CHECK: bb0(%0 : @trivial $@thin StructWithLayout.Type):
+// CHECK: alloc_box ${ var StructWithLayout }, var, name "self"
+// CHECK: mark_uninitialized [rootself] %{{.*}} : ${ var StructWithLayout }
+// CHECK: [[PROJ:%.*]] = project_box %{{.*}} : ${ var StructWithLayout }, 0
+// CHECK: [[PA:%.*]] = partial_apply [callee_guaranteed] %{{.*}}([[PROJ]]) : $@convention(thin) (@inout_aliasable StructWithLayout) -> Bool
+// CHECK: [[CLOSURE:%.*]] = convert_escape_to_noescape [[PA]] : $@callee_guaranteed () -> Bool to $@noescape @callee_guaranteed () -> Bool
+// call default argument
+// CHECK: apply %{{.*}}() : $@convention(thin) () -> StaticString
+// call StaticString.init
+// CHECK: apply
+// call UInt.init(_builtinIntegerLiteral:)
+// CHECK: apply
+// call _sanityCheck(_:_:file:line:)
+// CHECK: apply %{{.*}}([[CLOSURE]], {{.*}})
+// CHECK: load [trivial] [[PROJ]] : $*StructWithLayout
+// CHECK-LABEL: } // end sil function '$S20access_marker_verify16StructWithLayoutVACycfC'
+
+// --- pointer_to_address
+// Verification should ignore this case.
+func testPointerInit(x: Int, y: UnsafeMutablePointer<Int>) {
+  y.pointee = x
+}
+// CHECK-LABEL: sil hidden @$S20access_marker_verify15testPointerInit1x1yySi_SpySiGtF : $@convention(thin) (Int, UnsafeMutablePointer<Int>) -> () {
+// CHECK: bb0(%0 : @trivial $Int, %1 : @trivial $UnsafeMutablePointer<Int>):
+// call addressor
+// CHECK: [[POINTEE:%.*]] = apply %{{.*}}<Int>(%1) : $@convention(method) <τ_0_0> (UnsafeMutablePointer<τ_0_0>) -> UnsafeMutablePointer<τ_0_0>
+// CHECK: [[RAWPTR:%.*]] = struct_extract [[POINTEE]] : $UnsafeMutablePointer<Int>, #UnsafeMutablePointer._rawValue
+// CHECK: [[ADR:%.*]] = pointer_to_address [[RAWPTR]] : $Builtin.RawPointer to [strict] $*Int
+// CHECK-NOT: begin_access
+// CHECK: assign %0 to [[ADR]] : $*Int
+// CHECK-LABEL: } // end sil function '$S20access_marker_verify15testPointerInit1x1yySi_SpySiGtF'
diff --git a/test/SILOptimizer/plus_zero_array_element_propagation.sil b/test/SILOptimizer/plus_zero_array_element_propagation.sil
new file mode 100644
index 0000000..8973b9a
--- /dev/null
+++ b/test/SILOptimizer/plus_zero_array_element_propagation.sil
@@ -0,0 +1,387 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil -array-element-propagation %s | %FileCheck %s
+sil_stage canonical
+
+import Builtin
+import Swift
+
+struct MyInt {
+  @sil_stored var _value: Builtin.Int64
+}
+
+struct MyBool {}
+struct _MyDependenceToken {}
+
+struct _MyBridgeStorage {
+  @sil_stored var rawValue : Builtin.BridgeObject
+}
+
+struct _MyArrayBuffer<T> {
+  @sil_stored var _storage : _MyBridgeStorage
+}
+
+
+struct MyArray<T> {
+  @sil_stored var _buffer : _MyArrayBuffer<T>
+}
+
+sil @swift_bufferAllocate : $@convention(thin)() -> @owned AnyObject
+sil [_semantics "array.uninitialized"] @adoptStorage : $@convention(thin) (@owned AnyObject, MyInt, @thin MyArray<MyInt>.Type) -> @owned (MyArray<MyInt>, UnsafeMutablePointer<MyInt>)
+sil [_semantics "array.props.isNativeTypeChecked"] @hoistableIsNativeTypeChecked : $@convention(method) (@guaranteed MyArray<MyInt>) -> MyBool
+sil [_semantics "array.check_subscript"] @checkSubscript : $@convention(method) (MyInt, MyBool, @guaranteed MyArray<MyInt>) -> _MyDependenceToken
+sil [_semantics "array.get_element"] @getElement : $@convention(method) (MyInt, MyBool, _MyDependenceToken, @guaranteed MyArray<MyInt>) -> @out MyInt
+sil [_semantics "array.get_element"] @getElement2 : $@convention(method) (MyInt, MyBool, _MyDependenceToken, @guaranteed MyArray<MyInt>) -> MyInt
+sil @unknown_array_use : $@convention(method) (@guaranteed MyArray<MyInt>) -> MyBool
+sil [_semantics "array.uninitialized"] @arrayAdoptStorage : $@convention(thin) (@owned AnyObject, MyInt, @thin Array<MyInt>.Type) -> @owned (Array<MyInt>, UnsafeMutablePointer<MyInt>)
+sil @arrayInit : $@convention(method) (@thin Array<MyInt>.Type) -> @owned Array<MyInt>
+sil [_semantics "array.append_contentsOf"] @arrayAppendContentsOf : $@convention(method) (@owned Array<MyInt>, @inout Array<MyInt>) -> ()
+
+// CHECK-LABEL: sil @propagate01
+// CHECK:    struct $MyInt
+// CHECK:   [[V0:%.*]] = integer_literal $Builtin.Int64, 0
+// CHECK:   [[I0:%.*]] = struct $MyInt ([[V0]] : $Builtin.Int64)
+// CHECK:   [[V1:%.*]] = integer_literal $Builtin.Int64, 1
+// CHECK:   [[I1:%.*]] = struct $MyInt ([[V1]] : $Builtin.Int64)
+// CHECK:   [[V2:%.*]] = integer_literal $Builtin.Int64, 2
+// CHECK:   [[I2:%.*]] = struct $MyInt ([[V2]] : $Builtin.Int64)
+// CHECK:   [[S0:%.*]] = alloc_stack $MyInt
+// CHECK:   [[HFUN:%.*]] = function_ref @hoistableIsNativeTypeChecked
+// CHECK-NOT: apply [[HFUN]]
+// CHECK:   [[CFUN:%.*]] = function_ref @checkSubscript
+// CHECK-NOT: apply [[CFUN]]
+// CHECK:   [[GFUN:%.*]] = function_ref @getElement
+// CHECK-NOT: apply [[GFUN]]
+// CHECK-NOT: apply [[HFUN]]
+// CHECK-NOT: apply [[CFUN]]
+// CHECK-NOT: apply [[GFUN]]
+// CHECK:   store [[I0]] to [[S0]]
+// CHECK:   [[S1:%.*]] = alloc_stack $MyInt
+// CHECK:   store [[I1]] to [[S1]]
+// CHECK:   [[S2:%.*]] = alloc_stack $MyInt
+// CHECK:   store [[I2]] to [[S2]]
+// CHECK: return
+
+sil @propagate01 : $@convention(thin) () -> () {
+  %0 = function_ref @swift_bufferAllocate : $@convention(thin) () -> @owned AnyObject
+  %1 = integer_literal $Builtin.Int64, 3
+  %2 = struct $MyInt (%1 : $Builtin.Int64)
+  %3 = apply %0() : $@convention(thin) () -> @owned AnyObject
+  %4 = metatype $@thin MyArray<MyInt>.Type
+  %5 = function_ref @adoptStorage : $@convention(thin) (@owned AnyObject, MyInt, @thin MyArray<MyInt>.Type) -> @owned (MyArray<MyInt>, UnsafeMutablePointer<MyInt>)
+  %6 = apply %5(%3, %2, %4) : $@convention(thin) (@owned AnyObject, MyInt, @thin MyArray<MyInt>.Type) -> @owned (MyArray<MyInt>, UnsafeMutablePointer<MyInt>)
+  %7 = tuple_extract %6 : $(MyArray<MyInt>, UnsafeMutablePointer<MyInt>), 0
+  %8 = tuple_extract %6 : $(MyArray<MyInt>, UnsafeMutablePointer<MyInt>), 1
+  debug_value %7 : $MyArray<MyInt>
+  debug_value %8 : $UnsafeMutablePointer<MyInt>
+  %9 = struct_extract %8 : $UnsafeMutablePointer<MyInt>, #UnsafeMutablePointer._rawValue
+  %10 = pointer_to_address %9 : $Builtin.RawPointer to [strict] $*MyInt
+  %11 = integer_literal $Builtin.Int64, 0
+  %12 = struct $MyInt (%11 : $Builtin.Int64)
+  store %12 to %10 : $*MyInt
+  %13 = integer_literal $Builtin.Word, 1
+  %14 = index_addr %10 : $*MyInt, %13 : $Builtin.Word
+  %15 = integer_literal $Builtin.Int64, 1
+  %16 = struct $MyInt (%15 : $Builtin.Int64)
+  store %16 to %14 : $*MyInt
+  %17 = integer_literal $Builtin.Word, 2
+  %18 = index_addr %10 : $*MyInt, %17 : $Builtin.Word
+  %19 = integer_literal $Builtin.Int64, 2
+  %20 = struct $MyInt (%19 : $Builtin.Int64)
+  store %20 to %18 : $*MyInt
+  %23 = struct_extract %7 : $MyArray<MyInt>, #MyArray._buffer
+  %24 = struct_extract %23 : $_MyArrayBuffer<MyInt>, #_MyArrayBuffer._storage
+  %25 = struct_extract %24 : $_MyBridgeStorage, #_MyBridgeStorage.rawValue
+  %26 = alloc_stack $MyInt
+  debug_value %7 : $MyArray<MyInt>
+  %27 = function_ref @hoistableIsNativeTypeChecked : $@convention(method) (@guaranteed MyArray<MyInt>) -> MyBool
+  %28 = apply %27(%7) : $@convention(method) (@guaranteed MyArray<MyInt>) -> MyBool
+  debug_value %28 : $MyBool                        // id: %104
+  %29 = function_ref @checkSubscript : $@convention(method) (MyInt, MyBool, @guaranteed MyArray<MyInt>) -> _MyDependenceToken
+  %30 = apply %29(%12, %28, %7) : $@convention(method) (MyInt, MyBool, @guaranteed MyArray<MyInt>) -> _MyDependenceToken
+  debug_value %30 : $_MyDependenceToken
+  %31 = function_ref @getElement : $@convention(method) (MyInt, MyBool, _MyDependenceToken, @guaranteed MyArray<MyInt>) -> @out MyInt
+  %32 = apply %31(%26, %12, %28, %30, %7) : $@convention(method) (MyInt, MyBool, _MyDependenceToken, @guaranteed MyArray<MyInt>) -> @out MyInt
+  %35 = alloc_stack $MyInt
+  debug_value %16 : $MyInt
+  debug_value %7 : $MyArray<MyInt>
+  debug_value %28 : $MyBool
+  strong_retain %25 : $Builtin.BridgeObject
+  %36 = apply %29(%16, %28, %7) : $@convention(method) (MyInt, MyBool, @guaranteed MyArray<MyInt>) -> _MyDependenceToken
+  debug_value %36 : $_MyDependenceToken
+  %37 = apply %31(%35, %16, %28, %36, %7) : $@convention(method) (MyInt, MyBool, _MyDependenceToken, @guaranteed MyArray<MyInt>) -> @out MyInt
+  strong_release %25 : $Builtin.BridgeObject
+  %44 = alloc_stack $MyInt
+  debug_value %7 : $MyArray<MyInt>
+  debug_value %28 : $MyBool
+  strong_retain %25 : $Builtin.BridgeObject
+  %45 = apply %29(%20, %28, %7) : $@convention(method) (MyInt, MyBool, @guaranteed MyArray<MyInt>) -> _MyDependenceToken
+  debug_value %45 : $_MyDependenceToken
+  %46 = apply %31(%44, %20, %28, %45, %7) : $@convention(method) (MyInt, MyBool, _MyDependenceToken, @guaranteed MyArray<MyInt>) -> @out MyInt
+  strong_release %25 : $Builtin.BridgeObject
+  %52 = tuple ()
+  dealloc_stack %44 : $*MyInt
+  dealloc_stack %35 : $*MyInt
+  dealloc_stack %26 : $*MyInt
+  strong_release %25 : $Builtin.BridgeObject
+  return %52 : $()
+}
+
+// CHECK-LABEL: sil @propagate_with_get_element_returning_direct_result
+// CHECK:    struct $MyInt
+// CHECK:   [[V0:%.*]] = integer_literal $Builtin.Int64, 0
+// CHECK:   [[I0:%.*]] = struct $MyInt ([[V0]] : $Builtin.Int64)
+// CHECK:   [[V1:%.*]] = integer_literal $Builtin.Int64, 1
+// CHECK:   [[I1:%.*]] = struct $MyInt ([[V1]] : $Builtin.Int64)
+// CHECK:   [[V2:%.*]] = integer_literal $Builtin.Int64, 2
+// CHECK:   [[I2:%.*]] = struct $MyInt ([[V2]] : $Builtin.Int64)
+// CHECK:   [[S0:%.*]] = alloc_stack $MyInt
+// CHECK:   [[HFUN:%.*]] = function_ref @hoistableIsNativeTypeChecked
+// CHECK-NOT: apply [[HFUN]]
+// CHECK:   [[CFUN:%.*]] = function_ref @checkSubscript
+// CHECK-NOT: apply [[CFUN]]
+// CHECK:   [[GFUN:%.*]] = function_ref @getElement
+// CHECK-NOT: apply [[GFUN]]
+// CHECK-NOT: apply [[HFUN]]
+// CHECK-NOT: apply [[CFUN]]
+// CHECK-NOT: apply [[GFUN]]
+// CHECK:   store [[I0]] to [[S0]]
+// CHECK:   [[S1:%.*]] = alloc_stack $MyInt
+// CHECK:   store [[I1]] to [[S1]]
+// CHECK:   [[S2:%.*]] = alloc_stack $MyInt
+// CHECK:   store [[I2]] to [[S2]]
+// CHECK: return
+
+sil @propagate_with_get_element_returning_direct_result : $@convention(thin) () -> () {
+  %0 = function_ref @swift_bufferAllocate : $@convention(thin) () -> @owned AnyObject
+  %1 = integer_literal $Builtin.Int64, 3
+  %2 = struct $MyInt (%1 : $Builtin.Int64)
+  %3 = apply %0() : $@convention(thin) () -> @owned AnyObject
+  %4 = metatype $@thin MyArray<MyInt>.Type
+  %5 = function_ref @adoptStorage : $@convention(thin) (@owned AnyObject, MyInt, @thin MyArray<MyInt>.Type) -> @owned (MyArray<MyInt>, UnsafeMutablePointer<MyInt>)
+  %6 = apply %5(%3, %2, %4) : $@convention(thin) (@owned AnyObject, MyInt, @thin MyArray<MyInt>.Type) -> @owned (MyArray<MyInt>, UnsafeMutablePointer<MyInt>)
+  %7 = tuple_extract %6 : $(MyArray<MyInt>, UnsafeMutablePointer<MyInt>), 0
+  %8 = tuple_extract %6 : $(MyArray<MyInt>, UnsafeMutablePointer<MyInt>), 1
+  debug_value %7 : $MyArray<MyInt>
+  debug_value %8 : $UnsafeMutablePointer<MyInt>
+  %9 = struct_extract %8 : $UnsafeMutablePointer<MyInt>, #UnsafeMutablePointer._rawValue
+  %10 = pointer_to_address %9 : $Builtin.RawPointer to [strict] $*MyInt
+  %11 = integer_literal $Builtin.Int64, 0
+  %12 = struct $MyInt (%11 : $Builtin.Int64)
+  store %12 to %10 : $*MyInt
+  %13 = integer_literal $Builtin.Word, 1
+  %14 = index_addr %10 : $*MyInt, %13 : $Builtin.Word
+  %15 = integer_literal $Builtin.Int64, 1
+  %16 = struct $MyInt (%15 : $Builtin.Int64)
+  store %16 to %14 : $*MyInt
+  %17 = integer_literal $Builtin.Word, 2
+  %18 = index_addr %10 : $*MyInt, %17 : $Builtin.Word
+  %19 = integer_literal $Builtin.Int64, 2
+  %20 = struct $MyInt (%19 : $Builtin.Int64)
+  store %20 to %18 : $*MyInt
+  %23 = struct_extract %7 : $MyArray<MyInt>, #MyArray._buffer
+  %24 = struct_extract %23 : $_MyArrayBuffer<MyInt>, #_MyArrayBuffer._storage
+  %25 = struct_extract %24 : $_MyBridgeStorage, #_MyBridgeStorage.rawValue
+  %26 = alloc_stack $MyInt
+  debug_value %7 : $MyArray<MyInt>
+  %27 = function_ref @hoistableIsNativeTypeChecked : $@convention(method) (@guaranteed MyArray<MyInt>) -> MyBool
+  %28 = apply %27(%7) : $@convention(method) (@guaranteed MyArray<MyInt>) -> MyBool
+  debug_value %28 : $MyBool                        // id: %104
+  %29 = function_ref @checkSubscript : $@convention(method) (MyInt, MyBool, @guaranteed MyArray<MyInt>) -> _MyDependenceToken
+  %30 = apply %29(%12, %28, %7) : $@convention(method) (MyInt, MyBool, @guaranteed MyArray<MyInt>) -> _MyDependenceToken
+  debug_value %30 : $_MyDependenceToken
+  %31 = function_ref @getElement2 : $@convention(method) (MyInt, MyBool, _MyDependenceToken, @guaranteed MyArray<MyInt>) -> MyInt
+  %32 = apply %31(%12, %28, %30, %7) : $@convention(method) (MyInt, MyBool, _MyDependenceToken, @guaranteed MyArray<MyInt>) -> MyInt
+  store %32 to %26 : $*MyInt
+  %35 = alloc_stack $MyInt
+  debug_value %16 : $MyInt
+  debug_value %7 : $MyArray<MyInt>
+  debug_value %28 : $MyBool
+  strong_retain %25 : $Builtin.BridgeObject
+  %36 = apply %29(%16, %28, %7) : $@convention(method) (MyInt, MyBool, @guaranteed MyArray<MyInt>) -> _MyDependenceToken
+  debug_value %36 : $_MyDependenceToken
+  %37 = apply %31(%16, %28, %36, %7) : $@convention(method) (MyInt, MyBool, _MyDependenceToken, @guaranteed MyArray<MyInt>) -> MyInt
+  store %37 to %35 : $*MyInt
+  strong_release %25 : $Builtin.BridgeObject
+  %44 = alloc_stack $MyInt
+  debug_value %7 : $MyArray<MyInt>
+  debug_value %28 : $MyBool
+  strong_retain %25 : $Builtin.BridgeObject
+  %45 = apply %29(%20, %28, %7) : $@convention(method) (MyInt, MyBool, @guaranteed MyArray<MyInt>) -> _MyDependenceToken
+  debug_value %45 : $_MyDependenceToken
+  %46 = apply %31(%20, %28, %45, %7) : $@convention(method) (MyInt, MyBool, _MyDependenceToken, @guaranteed MyArray<MyInt>) -> MyInt
+  store %46 to %44 : $*MyInt
+  strong_release %25 : $Builtin.BridgeObject
+  %52 = tuple ()
+  dealloc_stack %44 : $*MyInt
+  dealloc_stack %35 : $*MyInt
+  dealloc_stack %26 : $*MyInt
+  strong_release %25 : $Builtin.BridgeObject
+  return %52 : $()
+}
+
+// CHECK-LABEL: sil @repeated_initialization
+// CHECK:   [[GFUN:%.*]] = function_ref @getElement
+// CHECK:   apply [[GFUN]]
+// CHECK:   apply [[GFUN]]
+// CHECK: return
+
+sil @repeated_initialization : $@convention(thin) () -> () {
+  %0 = function_ref @swift_bufferAllocate : $@convention(thin) () -> @owned AnyObject
+  %1 = integer_literal $Builtin.Int64, 2
+  %2 = struct $MyInt (%1 : $Builtin.Int64)
+  %3 = apply %0() : $@convention(thin) () -> @owned AnyObject
+  %4 = metatype $@thin MyArray<MyInt>.Type
+  %5 = function_ref @adoptStorage : $@convention(thin) (@owned AnyObject, MyInt, @thin MyArray<MyInt>.Type) -> @owned (MyArray<MyInt>, UnsafeMutablePointer<MyInt>)
+  %6 = apply %5(%3, %2, %4) : $@convention(thin) (@owned AnyObject, MyInt, @thin MyArray<MyInt>.Type) -> @owned (MyArray<MyInt>, UnsafeMutablePointer<MyInt>)
+  %7 = tuple_extract %6 : $(MyArray<MyInt>, UnsafeMutablePointer<MyInt>), 0
+  %8 = tuple_extract %6 : $(MyArray<MyInt>, UnsafeMutablePointer<MyInt>), 1
+  %9 = struct_extract %8 : $UnsafeMutablePointer<MyInt>, #UnsafeMutablePointer._rawValue
+  %10 = pointer_to_address %9 : $Builtin.RawPointer to [strict] $*MyInt
+  %11 = integer_literal $Builtin.Int64, 0
+  %12 = struct $MyInt (%11 : $Builtin.Int64)
+  store %12 to %10 : $*MyInt
+  %13 = integer_literal $Builtin.Word, 0
+  %14 = index_addr %10 : $*MyInt, %13 : $Builtin.Word
+  %15 = integer_literal $Builtin.Int64, 1
+  %16 = struct $MyInt (%15 : $Builtin.Int64)
+  store %16 to %14 : $*MyInt
+  %23 = struct_extract %7 : $MyArray<MyInt>, #MyArray._buffer
+  %24 = struct_extract %23 : $_MyArrayBuffer<MyInt>, #_MyArrayBuffer._storage
+  %25 = struct_extract %24 : $_MyBridgeStorage, #_MyBridgeStorage.rawValue
+  %26 = alloc_stack $MyInt
+  %27 = function_ref @hoistableIsNativeTypeChecked : $@convention(method) (@guaranteed MyArray<MyInt>) -> MyBool
+  %28 = apply %27(%7) : $@convention(method) (@guaranteed MyArray<MyInt>) -> MyBool
+  %29 = function_ref @checkSubscript : $@convention(method) (MyInt, MyBool, @guaranteed MyArray<MyInt>) -> _MyDependenceToken
+  %30 = apply %29(%12, %28, %7) : $@convention(method) (MyInt, MyBool, @guaranteed MyArray<MyInt>) -> _MyDependenceToken
+  %31 = function_ref @getElement : $@convention(method) (MyInt, MyBool, _MyDependenceToken, @guaranteed MyArray<MyInt>) -> @out MyInt
+  %32 = apply %31(%26, %12, %28, %30, %7) : $@convention(method) (MyInt, MyBool, _MyDependenceToken, @guaranteed MyArray<MyInt>) -> @out MyInt
+  %35 = alloc_stack $MyInt
+  strong_retain %25 : $Builtin.BridgeObject
+  %36 = apply %29(%16, %28, %7) : $@convention(method) (MyInt, MyBool, @guaranteed MyArray<MyInt>) -> _MyDependenceToken
+  %37 = apply %31(%35, %16, %28, %36, %7) : $@convention(method) (MyInt, MyBool, _MyDependenceToken, @guaranteed MyArray<MyInt>) -> @out MyInt
+  strong_release %25 : $Builtin.BridgeObject
+  %52 = tuple ()
+  dealloc_stack %35 : $*MyInt
+  dealloc_stack %26 : $*MyInt
+  strong_release %25 : $Builtin.BridgeObject
+  return %52 : $()
+}
+
+// CHECK-LABEL: sil @unknown_use
+// CHECK:   [[GFUN:%.*]] = function_ref @getElement
+// CHECK:   apply [[GFUN]]
+// CHECK: return
+
+sil @unknown_use : $@convention(thin) () -> () {
+  %0 = function_ref @swift_bufferAllocate : $@convention(thin) () -> @owned AnyObject
+  %1 = integer_literal $Builtin.Int64, 2
+  %2 = struct $MyInt (%1 : $Builtin.Int64)
+  %3 = apply %0() : $@convention(thin) () -> @owned AnyObject
+  %4 = metatype $@thin MyArray<MyInt>.Type
+  %5 = function_ref @adoptStorage : $@convention(thin) (@owned AnyObject, MyInt, @thin MyArray<MyInt>.Type) -> @owned (MyArray<MyInt>, UnsafeMutablePointer<MyInt>)
+  %6 = apply %5(%3, %2, %4) : $@convention(thin) (@owned AnyObject, MyInt, @thin MyArray<MyInt>.Type) -> @owned (MyArray<MyInt>, UnsafeMutablePointer<MyInt>)
+  %7 = tuple_extract %6 : $(MyArray<MyInt>, UnsafeMutablePointer<MyInt>), 0
+  %8 = tuple_extract %6 : $(MyArray<MyInt>, UnsafeMutablePointer<MyInt>), 1
+  %9 = struct_extract %8 : $UnsafeMutablePointer<MyInt>, #UnsafeMutablePointer._rawValue
+  %10 = pointer_to_address %9 : $Builtin.RawPointer to [strict] $*MyInt
+  %11 = integer_literal $Builtin.Int64, 0
+  %12 = struct $MyInt (%11 : $Builtin.Int64)
+  store %12 to %10 : $*MyInt
+  %23 = struct_extract %7 : $MyArray<MyInt>, #MyArray._buffer
+  %24 = struct_extract %23 : $_MyArrayBuffer<MyInt>, #_MyArrayBuffer._storage
+  %25 = struct_extract %24 : $_MyBridgeStorage, #_MyBridgeStorage.rawValue
+  %26 = alloc_stack $MyInt
+  %27 = function_ref @hoistableIsNativeTypeChecked : $@convention(method) (@guaranteed MyArray<MyInt>) -> MyBool
+  %28 = apply %27(%7) : $@convention(method) (@guaranteed MyArray<MyInt>) -> MyBool
+  %29 = function_ref @checkSubscript : $@convention(method) (MyInt, MyBool, @guaranteed MyArray<MyInt>) -> _MyDependenceToken
+  %30 = apply %29(%12, %28, %7) : $@convention(method) (MyInt, MyBool, @guaranteed MyArray<MyInt>) -> _MyDependenceToken
+  %31 = function_ref @getElement : $@convention(method) (MyInt, MyBool, _MyDependenceToken, @guaranteed MyArray<MyInt>) -> @out MyInt
+  %32 = apply %31(%26, %12, %28, %30, %7) : $@convention(method) (MyInt, MyBool, _MyDependenceToken, @guaranteed MyArray<MyInt>) -> @out MyInt
+  %33 = function_ref @unknown_array_use : $@convention(method) (@guaranteed MyArray<MyInt>) -> MyBool
+  %34 = apply %33(%7) : $@convention(method) (@guaranteed MyArray<MyInt>) -> MyBool
+  %52 = tuple ()
+  dealloc_stack %26 : $*MyInt
+  strong_release %25 : $Builtin.BridgeObject
+  return %52 : $()
+}
+
+// CHECK-LABEL: sil @append_contentsOf_int
+// CHECK:      [[ASFUN:%.*]] = function_ref @arrayAdoptStorage
+// CHECK-NEXT: [[ARR:%.*]] = apply [[ASFUN]]
+// CHECK-NEXT: [[OWNER:%.*]] = tuple_extract [[ARR]]{{.*}}, 0
+// CHECK-NOT:    apply [[ACFUN]]
+// CHECK:      [[AEFUN:%.*]] = function_ref @$SSa6appendyyxF
+// CHECK-NEXT: [[STACK:%.*]] = alloc_stack $MyInt
+// CHECK-NEXT: store %{{[0-9]+}} to [[STACK]]
+// CHECK-NEXT: apply [[AEFUN]]<MyInt>([[STACK]]
+// CHECK-NEXT: dealloc_stack [[STACK]]
+// CHECK-NEXT: release_value [[OWNER]]
+// CHECK:      return
+sil @append_contentsOf_int : $@convention(thin) () -> () {
+  %0 = function_ref @swift_bufferAllocate : $@convention(thin) () -> @owned AnyObject
+  %1 = integer_literal $Builtin.Int64, 1
+  %2 = struct $MyInt (%1 : $Builtin.Int64)
+  %3 = apply %0() : $@convention(thin) () -> @owned AnyObject
+  %4 = metatype $@thin Array<MyInt>.Type
+  %5 = function_ref @arrayAdoptStorage : $@convention(thin) (@owned AnyObject, MyInt, @thin Array<MyInt>.Type) -> @owned (Array<MyInt>, UnsafeMutablePointer<MyInt>)
+  %6 = apply %5(%3, %2, %4) : $@convention(thin) (@owned AnyObject, MyInt, @thin Array<MyInt>.Type) -> @owned (Array<MyInt>, UnsafeMutablePointer<MyInt>)
+  %7 = tuple_extract %6 : $(Array<MyInt>, UnsafeMutablePointer<MyInt>), 0
+  %8 = tuple_extract %6 : $(Array<MyInt>, UnsafeMutablePointer<MyInt>), 1
+  %9 = struct_extract %8 : $UnsafeMutablePointer<MyInt>, #UnsafeMutablePointer._rawValue
+  %10 = pointer_to_address %9 : $Builtin.RawPointer to [strict] $*MyInt
+  %11 = integer_literal $Builtin.Int64, 27
+  %12 = struct $MyInt (%11 : $Builtin.Int64)
+  store %12 to %10 : $*MyInt
+  %13 = alloc_stack $Array<MyInt>
+  %14 = metatype $@thin Array<MyInt>.Type
+  %15 = function_ref @arrayInit : $@convention(method) (@thin Array<MyInt>.Type) -> @owned Array<MyInt>
+  %16 = apply %15(%14) : $@convention(method) (@thin Array<MyInt>.Type) -> @owned Array<MyInt>
+  store %16 to %13 : $*Array<MyInt>
+  %17 = function_ref @arrayAppendContentsOf : $@convention(method) (@owned Array<MyInt>, @inout Array<MyInt>) -> ()
+  %18 = apply %17(%7, %13) : $@convention(method) (@owned Array<MyInt>, @inout Array<MyInt>) -> ()
+  dealloc_stack %13 : $*Array<MyInt>
+  %19 = tuple ()
+  return %19 : $()
+}
+
+class Hello {
+}
+
+sil [_semantics "array.uninitialized"] @adoptStorageHello : $@convention(method) (@owned _ContiguousArrayStorage<Hello>, MyInt, @thin Array<Hello>.Type) -> (@owned Array<Hello>, UnsafeMutablePointer<Hello>)
+sil [_semantics "array.append_contentsOf"] @arrayAppendContentsOfHello : $@convention(method) (@owned Array<Hello>, @inout Array<Hello>) -> ()
+
+// CHECK-LABEL: sil @append_contentsOf_class
+// CHECK:      [[ASFUN:%.*]] = function_ref @adoptStorageHello
+// CHECK-NEXT: [[ARR:%.*]] = apply [[ASFUN]]
+// CHECK-NEXT: [[OWNER:%.*]] = tuple_extract [[ARR]]{{.*}}, 0
+// CHECK:      strong_retain %1 : $Hello
+// CHECK-NEXT: store %1 to %{{[0-9]+}} : $*Hello
+// CHECK-NOT:     apply
+// CHECK:      [[AEFUN:%.*]] = function_ref @$SSa6appendyyxF
+// CHECK-NEXT: strong_retain %1 : $Hello
+// CHECK-NEXT: [[STACK:%.*]] = alloc_stack $Hello
+// CHECK-NEXT: store %1 to [[STACK]]
+// CHECK-NEXT: apply [[AEFUN]]<Hello>([[STACK]], %0)
+// CHECK-NEXT: dealloc_stack [[STACK]]
+// CHECK-NEXT: strong_release %1
+// CHECK-NEXT: release_value [[OWNER]]
+// CHECK-NEXT: return
+sil @append_contentsOf_class : $@convention(thin) (@inout Array<Hello>, @owned Hello) -> @owned Hello {
+bb0(%0 : $*Array<Hello>, %1 : $Hello):
+  %4 = integer_literal $Builtin.Word, 1
+  %5 = integer_literal $Builtin.Int64, 1
+  %6 = struct $MyInt (%5 : $Builtin.Int64)
+  %7 = alloc_ref [tail_elems $Hello * %4 : $Builtin.Word] $_ContiguousArrayStorage<Hello>
+  %8 = metatype $@thin Array<Hello>.Type
+  %9 = function_ref @adoptStorageHello : $@convention(method) (@owned _ContiguousArrayStorage<Hello>, MyInt, @thin Array<Hello>.Type) -> (@owned Array<Hello>, UnsafeMutablePointer<Hello>)
+  %10 = apply %9(%7, %6, %8) : $@convention(method) (@owned _ContiguousArrayStorage<Hello>, MyInt, @thin Array<Hello>.Type) -> (@owned Array<Hello>, UnsafeMutablePointer<Hello>)
+  %11 = tuple_extract %10 : $(Array<Hello>, UnsafeMutablePointer<Hello>), 0
+  %12 = tuple_extract %10 : $(Array<Hello>, UnsafeMutablePointer<Hello>), 1
+  %13 = struct_extract %12 : $UnsafeMutablePointer<Hello>, #UnsafeMutablePointer._rawValue
+  %22 = pointer_to_address %13 : $Builtin.RawPointer to [strict] $*Hello
+  strong_retain %1 : $Hello
+  store %1 to %22 : $*Hello
+  %25 = function_ref @arrayAppendContentsOfHello : $@convention(method) (@owned Array<Hello>, @inout Array<Hello>) -> ()
+  %26 = apply %25(%11, %0) : $@convention(method) (@owned Array<Hello>, @inout Array<Hello>) -> ()
+  return %1 : $Hello
+}
diff --git a/test/SILOptimizer/plus_zero_bridged_casts_folding.swift b/test/SILOptimizer/plus_zero_bridged_casts_folding.swift
new file mode 100644
index 0000000..5ef60d6
--- /dev/null
+++ b/test/SILOptimizer/plus_zero_bridged_casts_folding.swift
@@ -0,0 +1,949 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -O -emit-sil %s | %FileCheck %s
+
+// REQUIRES: objc_interop
+
+// Check that casts between bridged types are replaced by more 
+// efficient code sequences.
+// 
+// In particular, checked_cast_* and unconditional_checked_* instructions,
+// which are pretty expensive at run-time (e.g. because they use
+// runtime _dynamicCast calls and check conformances at run-time),
+// should be replaced by invocations of specialized bridging functions,
+// which make use of statically known compile-time conformances and 
+// do not perform any conformance checks at run-time.
+
+import Foundation
+
+public func forcedCast<NS, T>(_ ns: NS) -> T {
+  return ns as! T
+}
+
+public func condCast<NS, T>(_ ns: NS) -> T? {
+  return ns as? T
+}
+
+// Check optimizations of casts from NSString to String
+
+var nsString: NSString = "string"
+
+// CHECK-LABEL: sil [noinline] @$S21bridged_casts_folding29testForcedCastNStoSwiftStringSSyF
+// CHECK-NOT: unconditional_checked
+// CHECK: function_ref @$SSS10FoundationE26_forceBridgeFromObjectiveC_6resultySo8NSStringC_SSSgztFZ : $@convention(method) (@guaranteed NSString, @inout Optional<String>, @thin String.Type) -> ()
+// CHECK: return
+@inline(never)
+public func testForcedCastNStoSwiftString() -> String {
+  var o: String = forcedCast(nsString)
+  return o
+}
+
+// CHECK-LABEL: sil [noinline] @$S21bridged_casts_folding27testCondCastNStoSwiftStringSSSgyF
+// CHECK-NOT: checked_cast
+// CHECK: function_ref @$SSS10FoundationE34_conditionallyBridgeFromObjectiveC_6resultSbSo8NSStringC_SSSgztFZ : $@convention(method) (@guaranteed NSString, @inout Optional<String>, @thin String.Type) -> Bool
+// CHECK: return
+@inline(never)
+public func testCondCastNStoSwiftString() -> String? {
+  var o: String? = condCast(nsString)
+  return o
+}
+
+
+// Check optimizations of casts from NSNumber to Int
+
+var nsIntNumber = NSNumber(value: 1)
+
+// CHECK-LABEL: sil [noinline] @$S21bridged_casts_folding32testForcedCastNSNumberToSwiftIntSiyF
+// CHECK-NOT: unconditional_checked
+// CHECK: function_ref @$SSi10FoundationE26_forceBridgeFromObjectiveC_6resultySo8NSNumberC_SiSgztFZ : $@convention(method) (@guaranteed NSNumber, @inout Optional<Int>, @thin Int.Type) -> ()
+// CHECK: return
+@inline(never)
+public func testForcedCastNSNumberToSwiftInt() -> Int {
+  var o: Int = forcedCast(nsIntNumber)
+  return o
+}
+
+// CHECK-LABEL: sil [noinline] @$S21bridged_casts_folding30testCondCastNSNumberToSwiftIntSiSgyF
+// CHECK-NOT: checked_cast
+// CHECK: function_ref @$SSi10FoundationE34_conditionallyBridgeFromObjectiveC_6resultSbSo8NSNumberC_SiSgztFZ : $@convention(method) (@guaranteed NSNumber, @inout Optional<Int>, @thin Int.Type) -> Bool
+// CHECK: return
+@inline(never)
+public func testCondCastNSNumberToSwiftInt() -> Int? {
+  var o: Int? = condCast(nsIntNumber)
+  return o
+}
+
+// Check optimizations of casts from NSNumber to Double
+
+var nsDoubleNumber = NSNumber(value: 1.234)
+
+// CHECK-LABEL: sil [noinline] @$S21bridged_casts_folding35testForcedCastNSNumberToSwiftDoubleSdyF
+// CHECK-NOT: unconditional_checked
+// CHECK: function_ref @$SSd10FoundationE26_forceBridgeFromObjectiveC_6resultySo8NSNumberC_SdSgztFZ : $@convention(method) (@guaranteed NSNumber, @inout Optional<Double>, @thin Double.Type) -> ()
+// CHECK: return
+@inline(never)
+public func testForcedCastNSNumberToSwiftDouble() -> Double {
+  var o: Double = forcedCast(nsDoubleNumber)
+  return o
+}
+
+// CHECK-LABEL: sil [noinline] @$S21bridged_casts_folding33testCondCastNSNumberToSwiftDoubleSdSgyF
+// CHECK-NOT: checked_cast
+// CHECK: function_ref @$SSd10FoundationE34_conditionallyBridgeFromObjectiveC_6resultSbSo8NSNumberC_SdSgztFZ : $@convention(method) (@guaranteed NSNumber, @inout Optional<Double>, @thin Double.Type) -> Bool
+// CHECK: return
+@inline(never)
+public func testCondCastNSNumberToSwiftDouble() -> Double? {
+  var o: Double? = condCast(nsDoubleNumber)
+  return o
+}
+
+// CHECK-LABEL: sil [noinline] @$S21bridged_casts_folding38testForcedCastNSIntNumberToSwiftDoubleSdyF
+// CHECK-NOT: unconditional_checked
+// CHECK: function_ref @$SSd10FoundationE26_forceBridgeFromObjectiveC_6resultySo8NSNumberC_SdSgztFZ : $@convention(method) (@guaranteed NSNumber, @inout Optional<Double>, @thin Double.Type) -> ()
+// CHECK: return
+@inline(never)
+public func testForcedCastNSIntNumberToSwiftDouble() -> Double {
+  var o: Double = forcedCast(nsIntNumber)
+  return o
+}
+
+// CHECK-LABEL: sil [noinline] @$S21bridged_casts_folding36testCondCastNSIntNumberToSwiftDoubleSdSgyF
+// CHECK-NOT: checked_cast
+// CHECK: function_ref @$SSd10FoundationE34_conditionallyBridgeFromObjectiveC_6resultSbSo8NSNumberC_SdSgztFZ : $@convention(method) (@guaranteed NSNumber, @inout Optional<Double>, @thin Double.Type) -> Bool
+// CHECK: return
+@inline(never)
+public func testCondCastNSIntNumberToSwiftDouble() -> Double? {
+  var o: Double? = condCast(nsIntNumber)
+  return o
+}
+
+
+
+// Check optimization of casts from NSArray to Swift Array
+
+var nsArrInt: NSArray = [1, 2, 3, 4]
+var nsArrDouble: NSArray = [1.1, 2.2, 3.3, 4.4]
+var nsArrString: NSArray = ["One", "Two", "Three", "Four"]
+
+// CHECK-LABEL: sil [noinline] @$S21bridged_casts_folding31testForcedCastNStoSwiftArrayIntSaySiGyF
+// CHECK-NOT: unconditional_checked
+// CHECK: function_ref @$SSa10FoundationE26_forceBridgeFromObjectiveC_6resultySo7NSArrayC_SayxGSgztFZ : $@convention(method) <τ_0_0> (@guaranteed NSArray, @inout Optional<Array<τ_0_0>>, @thin Array<τ_0_0>.Type) -> ()
+// CHECK: return
+@inline(never)
+public func testForcedCastNStoSwiftArrayInt() -> [Int] {
+  var arr: [Int] = forcedCast(nsArrInt)
+  return arr
+}
+
+// CHECK-LABEL: sil [noinline] @$S21bridged_casts_folding29testCondCastNStoSwiftArrayIntSaySiGSgyF
+// CHECK-NOT: checked_cast
+// CHECK: function_ref @$SSa10FoundationE34_conditionallyBridgeFromObjectiveC_6resultSbSo7NSArrayC_SayxGSgztFZ : $@convention(method) <τ_0_0> (@guaranteed NSArray, @inout Optional<Array<τ_0_0>>, @thin Array<τ_0_0>.Type) -> Bool
+// CHECK: return
+@inline(never)
+public func testCondCastNStoSwiftArrayInt() -> [Int]? {
+  var arrOpt: [Int]? = condCast(nsArrInt)
+  return arrOpt
+}
+
+// CHECK-LABEL: sil [noinline] @$S21bridged_casts_folding34testForcedCastNStoSwiftArrayDoubleSaySdGyF
+// CHECK-NOT: unconditional_checked
+// CHECK: function_ref @$SSa10FoundationE26_forceBridgeFromObjectiveC_6resultySo7NSArrayC_SayxGSgztFZ : $@convention(method) <τ_0_0> (@guaranteed NSArray, @inout Optional<Array<τ_0_0>>, @thin Array<τ_0_0>.Type) -> ()
+// CHECK: return
+@inline(never)
+public func testForcedCastNStoSwiftArrayDouble() -> [Double] {
+  var arr: [Double] = forcedCast(nsArrDouble)
+  return arr
+}
+
+// CHECK-LABEL: sil [noinline] @$S21bridged_casts_folding32testCondCastNStoSwiftArrayDoubleSaySdGSgyF
+// CHECK-NOT: checked_cast
+// CHECK: function_ref @$SSa10FoundationE34_conditionallyBridgeFromObjectiveC_6resultSbSo7NSArrayC_SayxGSgztFZ : $@convention(method) <τ_0_0> (@guaranteed NSArray, @inout Optional<Array<τ_0_0>>, @thin Array<τ_0_0>.Type) -> Bool
+// CHECK: return
+@inline(never)
+public func testCondCastNStoSwiftArrayDouble() -> [Double]? {
+  var arrOpt: [Double]? = condCast(nsArrDouble)
+  return arrOpt
+}
+
+
+// CHECK-LABEL: sil [noinline] @$S21bridged_casts_folding34testForcedCastNStoSwiftArrayStringSaySSGyF
+// CHECK-NOT: unconditional_checked
+// CHECK: function_ref @$SSa10FoundationE26_forceBridgeFromObjectiveC_6resultySo7NSArrayC_SayxGSgztFZ : $@convention(method) <τ_0_0> (@guaranteed NSArray, @inout Optional<Array<τ_0_0>>, @thin Array<τ_0_0>.Type) -> ()
+// CHECK: return
+@inline(never)
+public func testForcedCastNStoSwiftArrayString() -> [String] {
+  var arr: [String] = forcedCast(nsArrString)
+  return arr
+}
+
+// CHECK-LABEL: sil [noinline] @$S21bridged_casts_folding32testCondCastNStoSwiftArrayStringSaySSGSgyF
+// CHECK-NOT: checked_cast
+// CHECK: function_ref @$SSa10FoundationE34_conditionallyBridgeFromObjectiveC_6resultSbSo7NSArrayC_SayxGSgztFZ : $@convention(method) <τ_0_0> (@guaranteed NSArray, @inout Optional<Array<τ_0_0>>, @thin Array<τ_0_0>.Type) -> Bool
+// CHECK: return
+@inline(never)
+public func testCondCastNStoSwiftArrayString() -> [String]? {
+  var arrOpt: [String]? = condCast(nsArrString)
+  return arrOpt
+}
+
+
+
+// Check optimization of casts from NSDictionary to Swift Dictionary
+
+var nsDictInt: NSDictionary = [1:1, 2:2, 3:3, 4:4]
+var nsDictDouble: NSDictionary = [1.1 : 1.1, 2.2 : 2.2, 3.3 : 3.3, 4.4 : 4.4]
+var nsDictString: NSDictionary = ["One":"One", "Two":"Two", "Three":"Three", "Four":"Four"]
+
+// CHECK-LABEL: sil [noinline] @$S21bridged_casts_folding30testForcedCastNStoSwiftDictInts10DictionaryVyS2iGyF
+// CHECK-NOT: unconditional_checked
+// CHECK: function_ref @$Ss10DictionaryV10FoundationE26_forceBridgeFromObjectiveC_6resultySo12NSDictionaryC_AByxq_GSgztFZ : $@convention(method) <τ_0_0, τ_0_1 where τ_0_0 : Hashable> (@guaranteed NSDictionary, @inout Optional<Dictionary<τ_0_0, τ_0_1>>, @thin Dictionary<τ_0_0, τ_0_1>.Type) -> ()
+// CHECK: return
+@inline(never)
+public func testForcedCastNStoSwiftDictInt() -> [Int: Int] {
+  var dict: [Int: Int] = forcedCast(nsDictInt)
+  return dict
+}
+
+// CHECK-LABEL: sil [noinline] @$S21bridged_casts_folding28testCondCastNStoSwiftDictInts10DictionaryVyS2iGSgyF
+// CHECK-NOT: checked_cast
+// CHECK: function_ref @$Ss10DictionaryV10FoundationE34_conditionallyBridgeFromObjectiveC_6resultSbSo12NSDictionaryC_AByxq_GSgztFZ : $@convention(method) <τ_0_0, τ_0_1 where τ_0_0 : Hashable> (@guaranteed NSDictionary, @inout Optional<Dictionary<τ_0_0, τ_0_1>>, @thin Dictionary<τ_0_0, τ_0_1>.Type) -> Bool
+// CHECK: return
+@inline(never)
+public func testCondCastNStoSwiftDictInt() -> [Int: Int]? {
+  var dictOpt: [Int: Int]? = condCast(nsDictInt)
+  return dictOpt
+}
+
+// CHECK-LABEL: sil [noinline] @$S21bridged_casts_folding33testForcedCastNStoSwiftDictDoubles10DictionaryVyS2dGyF
+// CHECK-NOT: unconditional_checked
+// CHECK: function_ref @$Ss10DictionaryV10FoundationE26_forceBridgeFromObjectiveC_6resultySo12NSDictionaryC_AByxq_GSgztFZ : $@convention(method) <τ_0_0, τ_0_1 where τ_0_0 : Hashable> (@guaranteed NSDictionary, @inout Optional<Dictionary<τ_0_0, τ_0_1>>, @thin Dictionary<τ_0_0, τ_0_1>.Type) -> ()
+// CHECK: return
+@inline(never)
+public func testForcedCastNStoSwiftDictDouble() -> [Double: Double] {
+  var dict: [Double: Double] = forcedCast(nsDictDouble)
+  return dict
+}
+
+// CHECK-LABEL: sil [noinline] @$S21bridged_casts_folding31testCondCastNStoSwiftDictDoubles10DictionaryVyS2dGSgyF
+// CHECK-NOT: checked_cast
+// CHECK: function_ref @$Ss10DictionaryV10FoundationE34_conditionallyBridgeFromObjectiveC_6resultSbSo12NSDictionaryC_AByxq_GSgztFZ : $@convention(method) <τ_0_0, τ_0_1 where τ_0_0 : Hashable> (@guaranteed NSDictionary, @inout Optional<Dictionary<τ_0_0, τ_0_1>>, @thin Dictionary<τ_0_0, τ_0_1>.Type) -> Bool
+// CHECK: return
+@inline(never)
+public func testCondCastNStoSwiftDictDouble() -> [Double: Double]? {
+  var dictOpt: [Double: Double]? = condCast(nsDictDouble)
+  return dictOpt
+}
+
+
+// CHECK-LABEL: sil [noinline] @$S21bridged_casts_folding33testForcedCastNStoSwiftDictStrings10DictionaryVyS2SGyF
+// CHECK-NOT: unconditional_checked
+// CHECK: function_ref @$Ss10DictionaryV10FoundationE26_forceBridgeFromObjectiveC_6resultySo12NSDictionaryC_AByxq_GSgztFZ : $@convention(method) <τ_0_0, τ_0_1 where τ_0_0 : Hashable> (@guaranteed NSDictionary, @inout Optional<Dictionary<τ_0_0, τ_0_1>>, @thin Dictionary<τ_0_0, τ_0_1>.Type) -> ()
+// CHECK: return
+@inline(never)
+public func testForcedCastNStoSwiftDictString() -> [String: String] {
+  var dict: [String: String] = forcedCast(nsDictString)
+  return dict
+}
+
+// CHECK-LABEL: sil [noinline] @$S21bridged_casts_folding31testCondCastNStoSwiftDictStrings10DictionaryVyS2SGSgyF
+// CHECK-NOT: checked_cast
+// CHECK: function_ref @$Ss10DictionaryV10FoundationE34_conditionallyBridgeFromObjectiveC_6resultSbSo12NSDictionaryC_AByxq_GSgztFZ : $@convention(method) <τ_0_0, τ_0_1 where τ_0_0 : Hashable> (@guaranteed NSDictionary, @inout Optional<Dictionary<τ_0_0, τ_0_1>>, @thin Dictionary<τ_0_0, τ_0_1>.Type) -> Bool
+// CHECK: return
+@inline(never)
+public func testCondCastNStoSwiftDictString() -> [String: String]? {
+  var dictOpt: [String: String]? = condCast(nsDictString)
+  return dictOpt
+}
+
+// CHECK-LABEL: sil [noinline] @$S21bridged_casts_folding40testForcedCastNSDictStringtoSwiftDictInts10DictionaryVyS2iGyF
+// CHECK-NOT: unconditional_checked
+// CHECK: function_ref @$Ss10DictionaryV10FoundationE26_forceBridgeFromObjectiveC_6resultySo12NSDictionaryC_AByxq_GSgztFZ : $@convention(method) <τ_0_0, τ_0_1 where τ_0_0 : Hashable> (@guaranteed NSDictionary, @inout Optional<Dictionary<τ_0_0, τ_0_1>>, @thin Dictionary<τ_0_0, τ_0_1>.Type) -> ()
+// CHECK: return
+@inline(never)
+public func testForcedCastNSDictStringtoSwiftDictInt() -> [Int: Int] {
+  var dictOpt: [Int: Int] = forcedCast(nsDictString)
+  return dictOpt
+}
+
+
+// CHECK-LABEL: sil [noinline] @$S21bridged_casts_folding38testCondCastNSDictStringtoSwiftDictInts10DictionaryVyS2iGSgyF
+// CHECK-NOT: checked_cast
+// CHECK: function_ref @$Ss10DictionaryV10FoundationE34_conditionallyBridgeFromObjectiveC_6resultSbSo12NSDictionaryC_AByxq_GSgztFZ : $@convention(method) <τ_0_0, τ_0_1 where τ_0_0 : Hashable> (@guaranteed NSDictionary, @inout Optional<Dictionary<τ_0_0, τ_0_1>>, @thin Dictionary<τ_0_0, τ_0_1>.Type) -> Bool
+// CHECK: return
+@inline(never)
+public func testCondCastNSDictStringtoSwiftDictInt() -> [Int: Int]? {
+  var dictOpt: [Int: Int]? = condCast(nsDictString)
+  return dictOpt
+}
+
+
+// Check optimization of casts from NSSet to Swift Set
+
+var nsSetInt: NSSet = [1, 2, 3, 4]
+var nsSetDouble: NSSet = [1.1, 2.2, 3.3, 4.4]
+var nsSetString: NSSet = ["One", "Two", "Three", "Four"]
+
+// CHECK-LABEL: sil [noinline] @$S21bridged_casts_folding29testForcedCastNStoSwiftSetInts0I0VySiGyF
+// CHECK-NOT: unconditional_checked
+// CHECK: function_ref @$Ss3SetV10FoundationE26_forceBridgeFromObjectiveC_6resultySo5NSSetC_AByxGSgztFZ : $@convention(method) <τ_0_0 where τ_0_0 : Hashable> (@guaranteed NSSet, @inout Optional<Set<τ_0_0>>, @thin Set<τ_0_0>.Type) -> ()
+// CHECK: return
+@inline(never)
+public func testForcedCastNStoSwiftSetInt() -> Set<Int> {
+  var set: Set<Int> = forcedCast(nsSetInt)
+  return set
+}
+
+// CHECK-LABEL: sil [noinline] @$S21bridged_casts_folding27testCondCastNStoSwiftSetInts0I0VySiGSgyF
+// CHECK-NOT: checked_cast
+// CHECK: function_ref @$Ss3SetV10FoundationE34_conditionallyBridgeFromObjectiveC_6resultSbSo5NSSetC_AByxGSgztFZ : $@convention(method) <τ_0_0 where τ_0_0 : Hashable> (@guaranteed NSSet, @inout Optional<Set<τ_0_0>>, @thin Set<τ_0_0>.Type) -> Bool
+// CHECK: return
+@inline(never)
+public func testCondCastNStoSwiftSetInt() -> Set<Int>? {
+  var setOpt: Set<Int>? = condCast(nsSetInt)
+  return setOpt
+}
+
+// CHECK-LABEL: sil [noinline] @$S21bridged_casts_folding32testForcedCastNStoSwiftSetDoubles0I0VySdGyF
+// CHECK-NOT: unconditional_checked
+// CHECK: function_ref @$Ss3SetV10FoundationE26_forceBridgeFromObjectiveC_6resultySo5NSSetC_AByxGSgztFZ : $@convention(method) <τ_0_0 where τ_0_0 : Hashable> (@guaranteed NSSet, @inout Optional<Set<τ_0_0>>, @thin Set<τ_0_0>.Type) -> ()
+// CHECK: return
+@inline(never)
+public func testForcedCastNStoSwiftSetDouble() -> Set<Double> {
+  var set: Set<Double> = forcedCast(nsSetDouble)
+  return set
+}
+
+// CHECK-LABEL: sil [noinline] @$S21bridged_casts_folding30testCondCastNStoSwiftSetDoubles0I0VySdGSgyF
+// CHECK-NOT: checked_cast
+// CHECK: function_ref @$Ss3SetV10FoundationE34_conditionallyBridgeFromObjectiveC_6resultSbSo5NSSetC_AByxGSgztFZ : $@convention(method) <τ_0_0 where τ_0_0 : Hashable> (@guaranteed NSSet, @inout Optional<Set<τ_0_0>>, @thin Set<τ_0_0>.Type) -> Bool
+// CHECK: return
+@inline(never)
+public func testCondCastNStoSwiftSetDouble() -> Set<Double>? {
+  var setOpt: Set<Double>? = condCast(nsSetDouble)
+  return setOpt
+}
+
+
+// CHECK-LABEL: sil [noinline] @$S21bridged_casts_folding32testForcedCastNStoSwiftSetStrings0I0VySSGyF
+// CHECK-NOT: unconditional_checked
+// CHECK: function_ref @$Ss3SetV10FoundationE26_forceBridgeFromObjectiveC_6resultySo5NSSetC_AByxGSgztFZ : $@convention(method) <τ_0_0 where τ_0_0 : Hashable> (@guaranteed NSSet, @inout Optional<Set<τ_0_0>>, @thin Set<τ_0_0>.Type) -> ()
+// CHECK: return
+@inline(never)
+public func testForcedCastNStoSwiftSetString() -> Set<String> {
+  var set: Set<String> = forcedCast(nsSetString)
+  return set
+}
+
+// CHECK-LABEL: sil [noinline] @$S21bridged_casts_folding30testCondCastNStoSwiftSetStrings0I0VySSGSgyF
+// CHECK-NOT: checked_cast
+// CHECK: function_ref @$Ss3SetV10FoundationE34_conditionallyBridgeFromObjectiveC_6resultSbSo5NSSetC_AByxGSgztFZ : $@convention(method) <τ_0_0 where τ_0_0 : Hashable> (@guaranteed NSSet, @inout Optional<Set<τ_0_0>>, @thin Set<τ_0_0>.Type) -> Bool
+// CHECK: return
+@inline(never)
+public func testCondCastNStoSwiftSetString() -> Set<String>? {
+  var setOpt: Set<String>? = condCast(nsSetString)
+  return setOpt
+}
+
+
+// Check optimizations of casts from String to NSString
+
+var swiftString: String = "string"
+
+// CHECK-LABEL: sil [noinline] @$S21bridged_casts_folding29testForcedCastSwiftToNSStringSo0I0CyF
+// CHECK-NOT: unconditional_checked
+// CHECK: function_ref @{{.*}}_bridgeToObjectiveC
+// CHECK: return
+@inline(never)
+public func testForcedCastSwiftToNSString() -> NSString {
+  var o: NSString = forcedCast(swiftString)
+  return o
+}
+
+// CHECK-LABEL: sil [noinline] @$S21bridged_casts_folding27testCondCastSwiftToNSStringSo0I0CSgyF
+// CHECK-NOT: unconditional_checked
+// CHECK: function_ref @{{.*}}_bridgeToObjectiveC
+// CHECK: return
+@inline(never)
+public func testCondCastSwiftToNSString() -> NSString? {
+  var o: NSString? = condCast(swiftString)
+  return o
+}
+
+
+// Check optimizations of casts from Int to NSNumber
+
+var swiftIntNumber: Int = 1
+
+// CHECK-LABEL: sil [noinline] @$S21bridged_casts_folding32testForcedCastSwiftIntToNSNumberSo0J0CyF
+// CHECK-NOT: unconditional_checked
+// CHECK: function_ref @{{.*}}_bridgeToObjectiveC
+// CHECK: return
+@inline(never)
+public func testForcedCastSwiftIntToNSNumber() -> NSNumber {
+  var o: NSNumber = forcedCast(swiftIntNumber)
+  return o
+}
+
+// CHECK-LABEL: sil [noinline] @$S21bridged_casts_folding30testCondCastSwiftIntToNSNumberSo0J0CSgyF
+// CHECK-NOT: unconditional_checked
+// CHECK: function_ref @{{.*}}_bridgeToObjectiveC
+// CHECK: return
+@inline(never)
+public func testCondCastSwiftIntToNSNumber() -> NSNumber? {
+  var o: NSNumber? = condCast(swiftIntNumber)
+  return o
+}
+
+// Check optimizations of casts from Double to NSNumber
+
+var swiftDoubleNumber: Double = 1.234
+
+// CHECK-LABEL: sil [noinline] @$S21bridged_casts_folding35testForcedCastSwiftDoubleToNSNumberSo0J0CyF
+// CHECK-NOT: unconditional_checked
+// CHECK: function_ref @{{.*}}_bridgeToObjectiveC
+// CHECK: return
+@inline(never)
+public func testForcedCastSwiftDoubleToNSNumber() -> NSNumber {
+  var o: NSNumber = forcedCast(swiftDoubleNumber)
+  return o
+}
+
+// CHECK-LABEL: sil [noinline] @$S21bridged_casts_folding33testCondCastSwiftDoubleToNSNumberSo0J0CSgyF
+// CHECK-NOT: unconditional_checked
+// CHECK: function_ref @{{.*}}_bridgeToObjectiveC
+// CHECK: return
+@inline(never)
+public func testCondCastSwiftDoubleToNSNumber() -> NSNumber? {
+  var o: NSNumber? = condCast(swiftDoubleNumber)
+  return o
+}
+
+
+// Check optimization of casts from Swift Array to NSArray
+
+var arrInt: [Int] = [1, 2, 3, 4]
+var arrDouble: [Double] = [1.1, 2.2, 3.3, 4.4]
+var arrString: [String] = ["One", "Two", "Three", "Four"]
+
+// CHECK-LABEL: sil [noinline] @$S21bridged_casts_folding31testForcedCastSwiftToNSArrayIntSo0I0CyF
+// CHECK-NOT: unconditional_checked
+// CHECK: function_ref @{{.*}}_bridgeToObjectiveC
+// CHECK: return
+@inline(never)
+public func testForcedCastSwiftToNSArrayInt() -> NSArray {
+  var arr: NSArray = forcedCast(arrInt)
+  return arr
+}
+
+// CHECK-LABEL: sil [noinline] @$S21bridged_casts_folding29testCondCastSwiftToNSArrayIntSo0I0CSgyF
+// CHECK-NOT: unconditional_checked
+// CHECK: function_ref @{{.*}}_bridgeToObjectiveC
+// CHECK: return
+@inline(never)
+public func testCondCastSwiftToNSArrayInt() -> NSArray? {
+  var arrOpt: NSArray? = condCast(arrInt)
+  return arrOpt
+}
+
+// CHECK-LABEL: sil [noinline] @$S21bridged_casts_folding34testForcedCastSwiftToNSArrayDoubleSo0I0CyF
+// CHECK-NOT: unconditional_checked
+// CHECK: function_ref @{{.*}}_bridgeToObjectiveC
+// CHECK: return
+@inline(never)
+public func testForcedCastSwiftToNSArrayDouble() -> NSArray {
+  var arr: NSArray = forcedCast(arrDouble)
+  return arr
+}
+
+// CHECK-LABEL: sil [noinline] @$S21bridged_casts_folding32testCondCastSwiftToNSArrayDoubleSo0I0CSgyF
+// CHECK-NOT: unconditional_checked
+// CHECK: function_ref @{{.*}}_bridgeToObjectiveC
+// CHECK: return
+@inline(never)
+public func testCondCastSwiftToNSArrayDouble() -> NSArray? {
+  var arrOpt: NSArray? = condCast(arrDouble)
+  return arrOpt
+}
+
+
+// CHECK-LABEL: sil [noinline] @$S21bridged_casts_folding34testForcedCastSwiftToNSArrayStringSo0I0CyF
+// CHECK-NOT: unconditional_checked
+// CHECK: function_ref @{{.*}}_bridgeToObjectiveC
+// CHECK: return
+@inline(never)
+public func testForcedCastSwiftToNSArrayString() -> NSArray {
+  var arr: NSArray = forcedCast(arrString)
+  return arr
+}
+
+// CHECK-LABEL: sil [noinline] @$S21bridged_casts_folding32testCondCastSwiftToNSArrayStringSo0I0CSgyF
+// CHECK-NOT: unconditional_checked
+// CHECK: function_ref @{{.*}}_bridgeToObjectiveC
+// CHECK: return
+@inline(never)
+public func testCondCastSwiftToNSArrayString() -> NSArray? {
+  var arrOpt: NSArray? = condCast(arrString)
+  return arrOpt
+}
+
+
+// Check optimization of casts from Swift Dict to NSDict
+
+var dictInt: [Int: Int] = [1:1, 2:2, 3:3, 4:4]
+var dictDouble: [Double: Double] = [1.1 : 1.1, 2.2 : 2.2, 3.3 : 3.3, 4.4 : 4.4]
+var dictString: [String: String] = ["One":"One", "Two":"Two", "Three":"Three", "Four":"Four"]
+
+// CHECK-LABEL: sil [noinline] @$S21bridged_casts_folding30testForcedCastSwiftToNSDictIntSo12NSDictionaryCyF
+// CHECK-NOT: unconditional_checked
+// CHECK: function_ref @{{.*}}_bridgeToObjectiveC
+// CHECK: return
+@inline(never)
+public func testForcedCastSwiftToNSDictInt() -> NSDictionary {
+  var dict: NSDictionary = forcedCast(dictInt)
+  return dict
+}
+
+// CHECK-LABEL: sil [noinline] @$S21bridged_casts_folding28testCondCastSwiftToNSDictIntSo12NSDictionaryCSgyF
+// CHECK-NOT: unconditional_checked
+// CHECK: function_ref @{{.*}}_bridgeToObjectiveC
+// CHECK: return
+@inline(never)
+public func testCondCastSwiftToNSDictInt() -> NSDictionary? {
+  var dictOpt: NSDictionary? = condCast(dictInt)
+  return dictOpt
+}
+
+// CHECK-LABEL: sil [noinline] @$S21bridged_casts_folding33testForcedCastSwiftToNSDictDoubleSo12NSDictionaryCyF
+// CHECK-NOT: unconditional_checked
+// CHECK: function_ref @{{.*}}_bridgeToObjectiveC
+// CHECK: return
+@inline(never)
+public func testForcedCastSwiftToNSDictDouble() -> NSDictionary {
+  var dict: NSDictionary = forcedCast(dictDouble)
+  return dict
+}
+
+// CHECK-LABEL: sil [noinline] @$S21bridged_casts_folding31testCondCastSwiftToNSDictDoubleSo12NSDictionaryCSgyF
+// CHECK-NOT: unconditional_checked
+// CHECK: function_ref @{{.*}}_bridgeToObjectiveC
+// CHECK: return
+@inline(never)
+public func testCondCastSwiftToNSDictDouble() -> NSDictionary? {
+  var dictOpt: NSDictionary? = condCast(dictDouble)
+  return dictOpt
+}
+
+
+// CHECK-LABEL: sil [noinline] @$S21bridged_casts_folding33testForcedCastSwiftToNSDictStringSo12NSDictionaryCyF
+// CHECK-NOT: unconditional_checked
+// CHECK: function_ref @{{.*}}_bridgeToObjectiveC
+// CHECK: return
+@inline(never)
+public func testForcedCastSwiftToNSDictString() -> NSDictionary {
+  var dict: NSDictionary = forcedCast(dictString)
+  return dict
+}
+
+// CHECK-LABEL: sil [noinline] @$S21bridged_casts_folding31testCondCastSwiftToNSDictStringSo12NSDictionaryCSgyF
+// CHECK-NOT: unconditional_checked
+// CHECK: function_ref @{{.*}}_bridgeToObjectiveC
+// CHECK: return
+@inline(never)
+public func testCondCastSwiftToNSDictString() -> NSDictionary? {
+  var dictOpt: NSDictionary? = condCast(dictString)
+  return dictOpt
+}
+
+
+// Check optimization of casts from Swift Set to NSSet
+
+var setInt: Set<Int> = [1, 2, 3, 4]
+var setDouble: Set<Double> = [1.1, 2.2, 3.3, 4.4]
+var setString: Set<String> = ["One", "Two", "Three", "Four"]
+
+// CHECK-LABEL: sil [noinline] @$S21bridged_casts_folding29testForcedCastSwiftToNSSetIntSo0I0CyF
+// CHECK-NOT: unconditional_checked
+// CHECK: function_ref @{{.*}}_bridgeToObjectiveC
+// CHECK: return
+@inline(never)
+public func testForcedCastSwiftToNSSetInt() -> NSSet {
+  var set: NSSet = forcedCast(setInt)
+  return set
+}
+
+// CHECK-LABEL: sil [noinline] @$S21bridged_casts_folding27testCondCastSwiftToNSSetIntSo0I0CSgyF
+// CHECK-NOT: unconditional_checked
+// CHECK: function_ref @{{.*}}_bridgeToObjectiveC
+// CHECK: return
+@inline(never)
+public func testCondCastSwiftToNSSetInt() -> NSSet? {
+  var setOpt: NSSet? = condCast(setInt)
+  return setOpt
+}
+
+// CHECK-LABEL: sil [noinline] @$S21bridged_casts_folding32testForcedCastSwiftToNSSetDoubleSo0I0CyF
+// CHECK-NOT: unconditional_checked
+// CHECK: function_ref @{{.*}}_bridgeToObjectiveC
+// CHECK: return
+@inline(never)
+public func testForcedCastSwiftToNSSetDouble() -> NSSet {
+  var set: NSSet = forcedCast(setDouble)
+  return set
+}
+
+// CHECK-LABEL: sil [noinline] @$S21bridged_casts_folding30testCondCastSwiftToNSSetDoubleSo0I0CSgyF
+// CHECK-NOT: unconditional_checked
+// CHECK: function_ref @{{.*}}_bridgeToObjectiveC
+// CHECK: return
+@inline(never)
+public func testCondCastSwiftToNSSetDouble() -> NSSet? {
+  var setOpt: NSSet? = condCast(setDouble)
+  return setOpt
+}
+
+
+// CHECK-LABEL: sil [noinline] @$S21bridged_casts_folding32testForcedCastSwiftToNSSetStringSo0I0CyF
+// CHECK-NOT: unconditional_checked
+// CHECK: function_ref @{{.*}}_bridgeToObjectiveC
+// CHECK: return
+@inline(never)
+public func testForcedCastSwiftToNSSetString() -> NSSet {
+  var set: NSSet = forcedCast(setString)
+  return set
+}
+
+// CHECK-LABEL: sil [noinline] @$S21bridged_casts_folding30testCondCastSwiftToNSSetStringSo0I0CSgyF
+// CHECK-NOT: unconditional_checked
+// CHECK: function_ref @{{.*}}_bridgeToObjectiveC
+// CHECK: return
+@inline(never)
+public func testCondCastSwiftToNSSetString() -> NSSet? {
+  var setOpt: NSSet? = condCast(setString)
+  return setOpt
+}
+
+// Casts involving generics cannot be optimized.
+
+// CHECK-LABEL: sil [noinline] @$S21bridged_casts_folding25testForcedCastFromGeneric{{[_0-9a-zA-Z]*}}F
+// CHECK: unconditional_checked
+// CHECK: return
+@inline(never)
+public func testForcedCastFromGeneric<T>(_ x: T) -> NSString {
+  var set: NSString = x as! NSString
+  return set
+}
+
+// CHECK-LABEL: sil [noinline] @$S21bridged_casts_folding23testForcedCastToGeneric{{[_0-9a-zA-Z]*}}F
+// CHECK: unconditional_checked
+// CHECK: return
+@inline(never)
+public func testForcedCastToGeneric<T>(_ x: T) -> T {
+  var set: T = nsString as! T
+  return set
+}
+
+// CHECK-LABEL: sil [noinline] @$S21bridged_casts_folding23testCondCastFromGeneric{{[_0-9a-zA-Z]*}}F
+// CHECK: checked_cast_addr_br
+// CHECK: return
+@inline(never)
+public func testCondCastFromGeneric<T>(_ x: T) -> NSString? {
+  var setOpt: NSString? = x as? NSString
+  return setOpt
+}
+
+// CHECK-LABEL: sil [noinline] @$S21bridged_casts_folding21testCondCastToGeneric{{[_0-9a-zA-Z]*}}F
+// CHECK: checked_cast_addr_br
+// CHECK: return
+@inline(never)
+public func testCondCastToGeneric<T>(_ x: T) -> T? {
+  var setOpt: T? = nsString as? T
+  return setOpt
+}
+
+
+// Run-time tests
+
+//// ObjC -> Swift
+
+// Arrays
+print("NS to Swift arrays: Start")
+print(testForcedCastNStoSwiftArrayInt())
+print(testCondCastNStoSwiftArrayInt())
+
+print(testForcedCastNStoSwiftArrayDouble())
+print(testCondCastNStoSwiftArrayDouble())
+
+print(testForcedCastNStoSwiftArrayString())
+print(testCondCastNStoSwiftArrayString())
+print("NS to Swift arrays: End")
+
+// Dicts
+print("NS to Swift dictionaries: Start")
+print(testForcedCastNStoSwiftDictInt())
+print(testCondCastNStoSwiftDictInt())
+
+print(testForcedCastNStoSwiftDictDouble())
+print(testCondCastNStoSwiftDictDouble())
+
+print(testForcedCastNStoSwiftDictString())
+print(testCondCastNStoSwiftDictString())
+print(testCondCastNSDictStringtoSwiftDictInt())
+// This line should crash at run-time
+//print(testForcedCastNSDictStringtoSwiftDictInt())
+print("NS to Swift dictionaries: End")
+
+// Sets
+print("NS to Swift sets: Start")
+print(testForcedCastNStoSwiftSetInt())
+print(testCondCastNStoSwiftSetInt())
+
+print(testForcedCastNStoSwiftSetDouble())
+print(testCondCastNStoSwiftSetDouble())
+
+print(testForcedCastNStoSwiftSetString())
+print(testCondCastNStoSwiftSetString())
+print("NS to Swift sets: End")
+
+
+// Basic types
+
+print("NS to Swift basic types: Start")
+print(testForcedCastNSNumberToSwiftInt())
+print(testCondCastNSNumberToSwiftInt())
+
+print(testForcedCastNSNumberToSwiftDouble())
+print(testCondCastNSNumberToSwiftDouble())
+
+print(testForcedCastNSIntNumberToSwiftDouble())
+print(testCondCastNSIntNumberToSwiftDouble())
+
+print(testForcedCastNStoSwiftString())
+print(testCondCastNStoSwiftString())
+print("NS to Swift basic types: End")
+
+//// Swift -> ObjC
+
+// Basic types
+
+print("Swift to NS basic types: Start")
+print(testForcedCastSwiftIntToNSNumber())
+print(testCondCastSwiftIntToNSNumber())
+
+print(testForcedCastSwiftDoubleToNSNumber())
+print(testCondCastSwiftDoubleToNSNumber())
+
+print(testForcedCastSwiftToNSString())
+print(testCondCastSwiftToNSString())
+print("Swift to NS basic types: End")
+
+// Arrays
+print("Swift to NS arrays: Start")
+
+print(testForcedCastSwiftToNSArrayInt())
+print(testCondCastSwiftToNSArrayInt())
+
+print(testForcedCastSwiftToNSArrayDouble())
+print(testCondCastSwiftToNSArrayDouble())
+
+print(testForcedCastSwiftToNSArrayString())
+print(testCondCastSwiftToNSArrayString())
+
+print("Swift to NS arrays: End")
+
+
+// Dicts
+print("Swift to NS dictionaries: Start")
+
+print(testForcedCastSwiftToNSDictInt())
+print(testCondCastSwiftToNSDictInt())
+
+print(testForcedCastSwiftToNSDictDouble())
+print(testCondCastSwiftToNSDictDouble())
+
+print(testForcedCastSwiftToNSDictString())
+print(testCondCastSwiftToNSDictString())
+
+print("Swift to NS dictionaries: End")
+
+// Sets
+print("Swift to NS sets: Start")
+
+print(testForcedCastSwiftToNSSetInt())
+print(testCondCastSwiftToNSSetInt())
+
+print(testForcedCastSwiftToNSSetDouble())
+print(testCondCastSwiftToNSSetDouble())
+
+print(testForcedCastSwiftToNSSetString())
+print(testCondCastSwiftToNSSetString())
+
+print("Swift to NS sets: End")
+
+// Check optimizations of casts from String to CFString
+
+// CHECK-LABEL: sil [noinline] @$S21bridged_casts_folding29testForcedCastSwiftToCFStringSo0I3RefayF
+// CHECK-NOT: unconditional_checked
+// CHECK: function_ref @{{.*}}_bridgeToObjectiveC
+// CHECK: unchecked_ref_cast{{.*}}: $NSString to $CFString
+// CHECK: end{{.*}}$S21bridged_casts_folding29testForcedCastSwiftToCFStringSo0I3RefayF
+@inline(never)
+public func testForcedCastSwiftToCFString() -> CFString {
+  let o: CFString = forcedCast(swiftString)
+  return o
+}
+
+// CHECK-LABEL: sil [noinline] @$S21bridged_casts_folding27testCondCastSwiftToCFStringSo0I3RefaSgyF
+// CHECK-NOT: unconditional_checked
+// CHECK: function_ref @{{.*}}_bridgeToObjectiveC
+// CHECK: unchecked_ref_cast{{.*}}: $NSString to $CFString
+// CHECK: end{{.*}}$S21bridged_casts_folding27testCondCastSwiftToCFStringSo0I3RefaSgyF
+@inline(never)
+public func testCondCastSwiftToCFString() -> CFString? {
+  let o: CFString? = condCast(swiftString)
+  return o
+}
+
+// Check optimizations of casts from Int to CFNumber
+
+// CHECK-LABEL: sil [noinline] @$S21bridged_casts_folding32testForcedCastSwiftIntToCFNumberSo0J3RefayF
+// CHECK-NOT: unconditional_checked
+// CHECK: function_ref @{{.*}}_bridgeToObjectiveC
+// CHECK: unchecked_ref_cast{{.*}}: $NSNumber to $CFNumber
+// CHECK: end{{.*}}$S21bridged_casts_folding32testForcedCastSwiftIntToCFNumberSo0J3RefayF
+@inline(never)
+public func testForcedCastSwiftIntToCFNumber() -> CFNumber {
+  let o: CFNumber = forcedCast(swiftIntNumber)
+  return o
+}
+
+// CHECK-LABEL: sil [noinline] @$S21bridged_casts_folding30testCondCastSwiftIntToCFNumberSo0J3RefaSgyF
+// CHECK-NOT: unconditional_checked
+// CHECK: function_ref @{{.*}}_bridgeToObjectiveC
+// CHECK: unchecked_ref_cast{{.*}}: $NSNumber to $CFNumber
+// CHECK: end{{.*}}$S21bridged_casts_folding30testCondCastSwiftIntToCFNumberSo0J3RefaSgyF
+@inline(never)
+public func testCondCastSwiftIntToCFNumber() -> CFNumber? {
+  let o: CFNumber? = condCast(swiftIntNumber)
+  return o
+}
+
+// Check optimization of casts from Swift Array to CFArray
+
+// CHECK-LABEL: sil [noinline] @$S21bridged_casts_folding31testForcedCastSwiftToCFArrayIntSo0I3RefayF
+// CHECK-NOT: unconditional_checked
+// CHECK: function_ref @{{.*}}_bridgeToObjectiveC
+// CHECK: unchecked_ref_cast{{.*}}: $NSArray to $CFArray
+// CHECK: end{{.*}}$S21bridged_casts_folding31testForcedCastSwiftToCFArrayIntSo0I3RefayF
+@inline(never)
+public func testForcedCastSwiftToCFArrayInt() -> CFArray {
+  let arr: CFArray = forcedCast(arrInt)
+  return arr
+}
+
+// CHECK-LABEL: sil [noinline] @$S21bridged_casts_folding29testCondCastSwiftToCFArrayIntSo0I3RefaSgyF
+// CHECK-NOT: unconditional_checked
+// CHECK: function_ref @{{.*}}_bridgeToObjectiveC
+// CHECK: unchecked_ref_cast{{.*}}: $NSArray to $CFArray
+// CHECK: end{{.*}}$S21bridged_casts_folding29testCondCastSwiftToCFArrayIntSo0I3RefaSgyF
+@inline(never)
+public func testCondCastSwiftToCFArrayInt() -> CFArray? {
+  let arrOpt: CFArray? = condCast(arrInt)
+  return arrOpt
+}
+
+// Check optimization of casts from Swift Dict to CFDictionary
+
+// CHECK-LABEL: sil [noinline] @$S21bridged_casts_folding30testForcedCastSwiftToCFDictIntSo15CFDictionaryRefayF
+// CHECK-NOT: unconditional_checked
+// CHECK: function_ref @{{.*}}_bridgeToObjectiveC
+// CHECK: unchecked_ref_cast{{.*}}: $NSDictionary to $CFDictionary
+// CHECK: end{{.*}}$S21bridged_casts_folding30testForcedCastSwiftToCFDictIntSo15CFDictionaryRefayF
+@inline(never)
+public func testForcedCastSwiftToCFDictInt() -> CFDictionary {
+  let dict: CFDictionary = forcedCast(dictInt)
+  return dict
+}
+
+// CHECK-LABEL: sil [noinline] @$S21bridged_casts_folding28testCondCastSwiftToCFDictIntSo15CFDictionaryRefaSgyF
+// CHECK-NOT: unconditional_checked
+// CHECK: function_ref @{{.*}}_bridgeToObjectiveC
+// CHECK: unchecked_ref_cast{{.*}}: $NSDictionary to $CFDictionary
+// CHECK: end{{.*}}$S21bridged_casts_folding28testCondCastSwiftToCFDictIntSo15CFDictionaryRefaSgyF
+@inline(never)
+public func testCondCastSwiftToCFDictInt() -> CFDictionary? {
+  let dictOpt: CFDictionary? = condCast(dictInt)
+  return dictOpt
+}
+
+// Check optimization of casts from Swift Set to CFSet
+
+// CHECK-LABEL: sil [noinline] @$S21bridged_casts_folding29testForcedCastSwiftToCFSetIntSo0I3RefayF
+// CHECK-NOT: unconditional_checked
+// CHECK: function_ref @{{.*}}_bridgeToObjectiveC
+// CHECK: unchecked_ref_cast{{.*}}: $NSSet to $CFSet
+// CHECK: end{{.*}}$S21bridged_casts_folding29testForcedCastSwiftToCFSetIntSo0I3RefayF
+@inline(never)
+public func testForcedCastSwiftToCFSetInt() -> CFSet {
+  let set: CFSet = forcedCast(setInt)
+  return set
+}
+
+// CHECK-LABEL: sil [noinline] @$S21bridged_casts_folding27testCondCastSwiftToCFSetIntSo0I3RefaSgyF
+// CHECK-NOT: unconditional_checked
+// CHECK: function_ref @{{.*}}_bridgeToObjectiveC
+// CHECK: unchecked_ref_cast{{.*}}: $NSSet to $CFSet
+// CHECK: end{{.*}}$S21bridged_casts_folding27testCondCastSwiftToCFSetIntSo0I3RefaSgyF
+@inline(never)
+public func testCondCastSwiftToCFSetInt() -> CFSet? {
+  let setOpt: CFSet? = condCast(setInt)
+  return setOpt
+}
+
+public class NSObjectSubclass : NSObject { }
+
+var anyHashable: AnyHashable = 0
+
+// CHECK-LABEL: $S21bridged_casts_folding29testUncondCastSwiftToSubclassAA08NSObjectI0CyF
+// CHECK: [[GLOBAL:%[0-9]+]] = global_addr @$S21bridged_casts_folding11anyHashables03AnyE0Vv
+// CHECK: [[FUNC:%.*]] = function_ref @$Ss11AnyHashableV10FoundationE19_bridgeToObjectiveCSo8NSObjectCyF
+// CHECK-NEXT: apply [[FUNC]]([[GLOBAL]])
+// CHECK-NEXT: unconditional_checked_cast {{%.*}} : $NSObject to $NSObjectSubclass
+// CHECK: } // end sil function '$S21bridged_casts_folding29testUncondCastSwiftToSubclassAA08NSObjectI0CyF'
+@inline(never)
+public func testUncondCastSwiftToSubclass() -> NSObjectSubclass {
+  return anyHashable as! NSObjectSubclass
+}
+
+class MyThing: Hashable {
+    let name: String
+    
+    init(name: String) {
+        self.name = name
+    }
+    
+    deinit {
+        Swift.print("Deinit \(name)")
+    }
+    
+    var hashValue: Int {
+        return 0
+    }
+    
+    static func ==(lhs: MyThing, rhs: MyThing) -> Bool {
+        return false
+    }
+}
+
+// CHECK-LABEL: sil hidden [noinline] @$S21bridged_casts_folding26doSomethingWithAnyHashableyys0gH0VF : $@convention(thin) (@in_guaranteed AnyHashable) -> () {
+// CHECK: %2 = alloc_stack $AnyHashable
+// CHECK: copy_addr %0 to [initialization] %2 : $*AnyHashable
+// CHECK: checked_cast_addr_br take_always AnyHashable in %2 : $*AnyHashable to MyThing
+@inline(never)
+func doSomethingWithAnyHashable(_ item: AnyHashable) {
+  _ = item as? MyThing
+}
+
+@inline(never)
+public func testMyThing() {
+  let x = MyThing(name: "B")
+  doSomethingWithAnyHashable(x)
+}
diff --git a/test/SILOptimizer/plus_zero_capture_promotion_generic_context.sil b/test/SILOptimizer/plus_zero_capture_promotion_generic_context.sil
new file mode 100644
index 0000000..8f08930
--- /dev/null
+++ b/test/SILOptimizer/plus_zero_capture_promotion_generic_context.sil
@@ -0,0 +1,124 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -assume-parsing-unqualified-ownership-sil -emit-sil -O -Xllvm -sil-fso-enable-generics=false %s | %FileCheck %s
+
+sil_stage raw
+
+import Builtin
+
+typealias Int = Builtin.Int32
+
+// rdar://problem/28945854: When a nongeneric closure was formed inside a
+// generic function, the capture promotion pass would erroneously try to
+// apply the generic caller's substitutions to the nongeneric callee, violating
+// invariants.
+
+// CHECK-LABEL: sil @$S14promotable_boxTf2i_n : $@convention(thin) (Builtin.Int32) -> Builtin.Int32
+
+sil @promotable_box : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Int>) -> Int {
+entry(%b : $<τ_0_0> { var τ_0_0 } <Int>):
+  %a = project_box %b : $<τ_0_0> { var τ_0_0 } <Int>, 0
+  %v = load %a : $*Int
+  return %v : $Int
+}
+
+// CHECK-LABEL: sil {{.*}}@call_promotable_box_from_generic
+// CHECK:         [[F:%.*]] = function_ref @$S14promotable_boxTf2i_n
+// CHECK:         partial_apply [callee_guaranteed] [[F]](
+
+sil @call_promotable_box_from_generic : $@convention(thin) <T> (@in T, Int) -> @owned @callee_guaranteed () -> Int {
+entry(%0 : $*T, %1 : $Int):
+  destroy_addr %0 : $*T
+  %f = function_ref @promotable_box : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Int>) -> Int
+  %b = alloc_box $<τ_0_0> { var τ_0_0 } <Int>
+  %a = project_box %b : $<τ_0_0> { var τ_0_0 } <Int>, 0
+  store %1 to %a : $*Int
+  %k = partial_apply [callee_guaranteed] %f(%b) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Int>) -> Int
+  return %k : $@callee_guaranteed () -> Int
+}
+
+protocol P {}
+
+// CHECK-LABEL: sil @$S22generic_promotable_boxTf2ni_n : $@convention(thin) <T> (@in T, Builtin.Int32) -> Builtin.Int32
+// CHECK:       bb0(%0 : $*T, %1 : $Builtin.Int32):
+// CHECK-NEXT:    return %1 : $Builtin.Int32
+
+sil @generic_promotable_box : $@convention(thin) <T> (@in T, <τ_0_0> { var τ_0_0 } <Int>) -> Int {
+entry(%0 : $*T, %b : $<τ_0_0> { var τ_0_0 } <Int>):
+  %a = project_box %b : $<τ_0_0> { var τ_0_0 } <Int>, 0
+  %v = load %a : $*Int
+  return %v : $Int
+}
+
+// CHECK-LABEL: sil @call_generic_promotable_box_from_different_generic
+// CHECK:       bb0(%0 : $*T, %1 : $*U, %2 : $Builtin.Int32):
+// CHECK-NEXT:    destroy_addr %0 : $*T
+// CHECK-NEXT:    destroy_addr %1 : $*U
+// CHECK:         [[F:%.*]] = function_ref @$S22generic_promotable_boxTf2ni_n : $@convention(thin) <τ_0_0> (@in τ_0_0, Builtin.Int32) -> Builtin.Int32
+// CHECK-NEXT:    [[CLOSURE:%.*]] = partial_apply [callee_guaranteed] [[F]]<U>(%2)
+// CHECK-NEXT:    return [[CLOSURE]]
+
+sil @call_generic_promotable_box_from_different_generic : $@convention(thin) <T, U: P> (@in T, @in U, Int) -> @owned @callee_guaranteed (@in U) -> Int {
+entry(%0 : $*T, %1 : $*U, %2 : $Int):
+  destroy_addr %0 : $*T
+  destroy_addr %1 : $*U
+  %f = function_ref @generic_promotable_box : $@convention(thin) <V> (@in V, <τ_0_0> { var τ_0_0 } <Int>) -> Int
+  %b = alloc_box $<τ_0_0> { var τ_0_0 } <Int>
+  %a = project_box %b : $<τ_0_0> { var τ_0_0 } <Int>, 0
+  store %2 to %a : $*Int
+  %k = partial_apply [callee_guaranteed] %f<U>(%b) : $@convention(thin) <V> (@in V, <τ_0_0> { var τ_0_0 } <Int>) -> Int
+  return %k : $@callee_guaranteed (@in U) -> Int
+}
+
+enum E<X> {
+  case None
+  case Some(X)
+}
+
+struct R<T> {
+}
+
+// Check that the capture promotion took place and the function now
+// take argument of a type E<(R<T>) -> Builtin.Int32>, which used
+// to be a slot inside a box.
+// CHECK-LABEL: sil @$S23generic_promotable_box2Tf2nni_n : $@convention(thin) <T> (@in R<T>, @in Builtin.Int32, @owned E<(R<T>) -> Builtin.Int32>) -> () 
+// CHECK:       bb0(%0 : $*R<T>, %1 : $*Builtin.Int32, %2 : $E<(R<T>) -> Builtin.Int32>):
+// CHECK-NOT:     project_box
+// CHECK:         switch_enum %2 : $E<(R<T>) -> Builtin.Int32>
+// CHECK-NOT:     project_box
+// CHECK:       } // end sil function '$S23generic_promotable_box2Tf2nni_n'
+sil @generic_promotable_box2 : $@convention(thin) <T> (@in R<T>, @in Int, <τ_0_0> { var E<(R<τ_0_0>) -> Int> } <T>) -> () {
+entry(%0: $*R<T>, %1 : $*Int, %b : $<τ_0_0> { var E< (R<τ_0_0>)->Int > } <T>):
+  %a = project_box %b : $<τ_0_0> { var E<(R<τ_0_0>)->Int> } <T>, 0
+  %e = load %a : $*E<(R<T>)->Int>
+  switch_enum %e : $E<(R<T>)->Int>, case #E.Some!enumelt.1 : bb1, default bb2
+
+bb1(%f : $@callee_guaranteed (@in_guaranteed R<T>) -> @out Int):
+  %t = tuple ()
+  apply %f(%1, %0) : $@callee_guaranteed (@in_guaranteed R<T>) -> @out Int
+  br exit
+bb2:
+  br exit
+exit:
+  %r = tuple ()
+  return %r : $()
+}
+
+// Check that alloc_box was eliminated and a specialized version of the
+// closure is invoked.
+// CHECK-LABEL: sil @call_generic_promotable_box_from_different_generic2
+// CHECK:       bb0(%0 : $*R<T>, %1 : $*E<(R<U>) -> Builtin.Int32>, %2 : $*Builtin.Int32):
+// CHECK:         %3 = load %1 : $*E<(R<U>) -> Builtin.Int32>
+// CHECK:         [[F:%.*]] = function_ref @$S23generic_promotable_box2Tf2nni_n : $@convention(thin) <τ_0_0> (@in R<τ_0_0>, @in Builtin.Int32, @owned E<(R<τ_0_0>) -> Builtin.Int32>) -> ()
+// CHECK-NEXT:    [[CLOSURE:%.*]] = partial_apply [callee_guaranteed] [[F]]<U>(%2, %3)
+// CHECK-NEXT:    return [[CLOSURE]]
+
+sil @call_generic_promotable_box_from_different_generic2 : $@convention(thin) <T, U: P> (@in R<T>, @in E<(R<U>)->Int>, @in Int) -> @owned @callee_guaranteed (@in R<U>) -> () {
+entry(%0 : $*R<T>, %1 : $*E<(R<U>)->Int>, %2 : $*Int):
+  destroy_addr %0 : $*R<T>
+  %f = function_ref @generic_promotable_box2 : $@convention(thin) <V> (@in R<V>, @in Int, <τ_0_0> { var E<(R<τ_0_0>)->Int> } <V>) -> ()
+  %b = alloc_box $<τ_0_0> { var E<(R<τ_0_0>)->Int> } <U>
+  %a = project_box %b : $<τ_0_0> { var E<(R<τ_0_0>)->Int> } <U>, 0
+  copy_addr [take] %1 to [initialization] %a : $*E<(R<U>)->Int>
+  %k = partial_apply [callee_guaranteed] %f<U>(%2, %b) : $@convention(thin) <V> (@in R<V>, @in Int, <τ_0_0> { var E<(R<τ_0_0>)->Int> } <V>) -> ()
+  return %k : $@callee_guaranteed (@in R<U>) -> ()
+}
diff --git a/test/SILOptimizer/plus_zero_capture_promotion_generic_context_ownership.sil b/test/SILOptimizer/plus_zero_capture_promotion_generic_context_ownership.sil
new file mode 100644
index 0000000..77ac818
--- /dev/null
+++ b/test/SILOptimizer/plus_zero_capture_promotion_generic_context_ownership.sil
@@ -0,0 +1,131 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -enable-sil-ownership -emit-sil -O -Xllvm -sil-fso-enable-generics=false %s | %FileCheck %s
+
+sil_stage raw
+
+import Builtin
+
+typealias Int = Builtin.Int32
+
+// rdar://problem/28945854: When a nongeneric closure was formed inside a
+// generic function, the capture promotion pass would erroneously try to
+// apply the generic caller's substitutions to the nongeneric callee, violating
+// invariants.
+
+// CHECK-LABEL: sil @$S14promotable_boxTf2i_n : $@convention(thin) (Builtin.Int32) -> Builtin.Int32
+sil @promotable_box : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } <Int>) -> Int {
+entry(%b : @owned $<τ_0_0> { var τ_0_0 } <Int>):
+  %a = project_box %b : $<τ_0_0> { var τ_0_0 } <Int>, 0
+  %v = load [trivial] %a : $*Int
+  destroy_value %b : $<τ_0_0> { var τ_0_0 } <Int>
+  return %v : $Int
+}
+
+// CHECK-LABEL: sil {{.*}}@call_promotable_box_from_generic
+// CHECK:         [[F:%.*]] = function_ref @$S14promotable_boxTf2i_n
+// CHECK:         partial_apply [callee_guaranteed] [[F]](
+
+sil @call_promotable_box_from_generic : $@convention(thin) <T> (@in T, Int) -> @owned @callee_guaranteed () -> Int {
+entry(%0 : @trivial $*T, %1 : @trivial $Int):
+  destroy_addr %0 : $*T
+  %f = function_ref @promotable_box : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } <Int>) -> Int
+  %b = alloc_box $<τ_0_0> { var τ_0_0 } <Int>
+  %a = project_box %b : $<τ_0_0> { var τ_0_0 } <Int>, 0
+  store %1 to [trivial] %a : $*Int
+  %k = partial_apply [callee_guaranteed] %f(%b) : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } <Int>) -> Int
+  return %k : $@callee_guaranteed () -> Int
+}
+
+protocol P {}
+
+// CHECK-LABEL: sil @$S22generic_promotable_boxTf2ni_n : $@convention(thin) <T> (@in T, Builtin.Int32) -> Builtin.Int32
+// CHECK:       bb0([[ARG0:%.*]] : $*T, [[ARG1:%.*]] : $Builtin.Int32):
+// CHECK-NEXT:    return [[ARG1]] : $Builtin.Int32
+
+sil @generic_promotable_box : $@convention(thin) <T> (@in T, @owned <τ_0_0> { var τ_0_0 } <Int>) -> Int {
+entry(%0 : @trivial $*T, %b : @owned $<τ_0_0> { var τ_0_0 } <Int>):
+  %a = project_box %b : $<τ_0_0> { var τ_0_0 } <Int>, 0
+  %v = load [trivial] %a : $*Int
+  destroy_value %b : $<τ_0_0> { var τ_0_0 } <Int>
+  return %v : $Int
+}
+
+// CHECK-LABEL: sil @call_generic_promotable_box_from_different_generic
+// CHECK:       bb0([[ARG0:%.*]] : $*T, [[ARG1:%.*]] : $*U, [[ARG2:%.*]] : $Builtin.Int32):
+// CHECK-NEXT:    destroy_addr [[ARG0]] : $*T
+// CHECK-NEXT:    destroy_addr [[ARG1]] : $*U
+// CHECK:         [[F:%.*]] = function_ref @$S22generic_promotable_boxTf2ni_n : $@convention(thin) <τ_0_0> (@in τ_0_0, Builtin.Int32) -> Builtin.Int32
+// CHECK-NEXT:    [[CLOSURE:%.*]] = partial_apply [callee_guaranteed] [[F]]<U>([[ARG2]])
+// CHECK-NEXT:    return [[CLOSURE]]
+
+sil @call_generic_promotable_box_from_different_generic : $@convention(thin) <T, U: P> (@in T, @in U, Int) -> @owned @callee_guaranteed (@in U) -> Int {
+entry(%0 : @trivial $*T, %1 : @trivial $*U, %2 : @trivial $Int):
+  destroy_addr %0 : $*T
+  destroy_addr %1 : $*U
+  %f = function_ref @generic_promotable_box : $@convention(thin) <V> (@in V, @owned <τ_0_0> { var τ_0_0 } <Int>) -> Int
+  %b = alloc_box $<τ_0_0> { var τ_0_0 } <Int>
+  %a = project_box %b : $<τ_0_0> { var τ_0_0 } <Int>, 0
+  store %2 to [trivial] %a : $*Int
+  %k = partial_apply [callee_guaranteed] %f<U>(%b) : $@convention(thin) <V> (@in V, @owned <τ_0_0> { var τ_0_0 } <Int>) -> Int
+  return %k : $@callee_guaranteed (@in U) -> Int
+}
+
+enum E<X> {
+  case None
+  case Some(X)
+}
+
+struct R<T> {
+}
+
+// Check that the capture promotion took place and the function now
+// take argument of a type E<(R<T>) -> Builtin.Int32>, which used
+// to be a slot inside a box.
+// CHECK-LABEL: sil @$S23generic_promotable_box2Tf2nni_n : $@convention(thin) <T> (@in R<T>, @in Builtin.Int32, @owned E<(R<T>) -> Builtin.Int32>) -> () 
+// CHECK:       bb0([[ARG0:%.*]] : $*R<T>, [[ARG1:%.*]] : $*Builtin.Int32, [[ARG2:%.*]] : $E<(R<T>) -> Builtin.Int32>):
+// CHECK-NOT:     project_box
+// CHECK:         switch_enum [[ARG2]] : $E<(R<T>) -> Builtin.Int32>
+// CHECK-NOT:     project_box
+// CHECK:       } // end sil function '$S23generic_promotable_box2Tf2nni_n'
+sil @generic_promotable_box2 : $@convention(thin) <T> (@in R<T>, @in Int, @owned <τ_0_0> { var E<(R<τ_0_0>) -> Int> } <T>) -> () {
+entry(%0 : @trivial $*R<T>, %1 : @trivial $*Int, %b : @owned $<τ_0_0> { var E<(R<τ_0_0>)->Int> } <T>):
+  %a = project_box %b : $<τ_0_0> { var E<(R<τ_0_0>)->Int> } <T>, 0
+  %e = load [copy] %a : $*E<(R<T>)->Int>
+  switch_enum %e : $E<(R<T>)->Int>, case #E.Some!enumelt.1 : bb1, default bb2
+
+bb1(%f : @owned $@callee_guaranteed (@in_guaranteed R<T>) -> @out Int):
+  %bf = begin_borrow %f : $@callee_guaranteed (@in_guaranteed R<T>) -> @out Int
+  apply %bf(%1, %0) : $@callee_guaranteed (@in_guaranteed R<T>) -> @out Int
+  end_borrow %bf from %f : $@callee_guaranteed (@in_guaranteed R<T>) -> @out Int , $@callee_guaranteed (@in_guaranteed R<T>) -> @out Int
+  destroy_value %f : $@callee_guaranteed (@in_guaranteed R<T>) -> @out Int
+  br exit
+
+bb2(%original : @owned $E<(R<T>)->Int>):
+  destroy_value %original : $E<(R<T>)->Int>
+  br exit
+
+exit:
+  destroy_value %b : $<τ_0_0> { var E<(R<τ_0_0>)->Int> } <T>
+  %r = tuple ()
+  return %r : $()
+}
+
+// Check that alloc_box was eliminated and a specialized version of the
+// closure is invoked.
+// CHECK-LABEL: sil @call_generic_promotable_box_from_different_generic2
+// CHECK:       bb0([[ARG0:%.*]] : $*R<T>, [[ARG1:%.*]] : $*E<(R<U>) -> Builtin.Int32>, [[ARG2:%.*]] : $*Builtin.Int32):
+// CHECK:         %3 = load [[ARG1]] : $*E<(R<U>) -> Builtin.Int32>
+// CHECK:         [[F:%.*]] = function_ref @$S23generic_promotable_box2Tf2nni_n : $@convention(thin) <τ_0_0> (@in R<τ_0_0>, @in Builtin.Int32, @owned E<(R<τ_0_0>) -> Builtin.Int32>) -> ()
+// CHECK-NEXT:    [[CLOSURE:%.*]] = partial_apply [callee_guaranteed] [[F]]<U>(%2, %3)
+// CHECK-NEXT:    return [[CLOSURE]]
+
+sil @call_generic_promotable_box_from_different_generic2 : $@convention(thin) <T, U: P> (@in R<T>, @in E<(R<U>)->Int>, @in Int) -> @owned @callee_guaranteed (@in R<U>) -> () {
+entry(%0 : @trivial $*R<T>, %1 : @trivial $*E<(R<U>)->Int>, %2 : @trivial $*Int):
+  destroy_addr %0 : $*R<T>
+  %f = function_ref @generic_promotable_box2 : $@convention(thin) <V> (@in R<V>, @in Int, @owned <τ_0_0> { var E<(R<τ_0_0>)->Int> } <V>) -> ()
+  %b = alloc_box $<τ_0_0> { var E<(R<τ_0_0>)->Int> } <U>
+  %a = project_box %b : $<τ_0_0> { var E<(R<τ_0_0>)->Int> } <U>, 0
+  copy_addr [take] %1 to [initialization] %a : $*E<(R<U>)->Int>
+  %k = partial_apply [callee_guaranteed] %f<U>(%2, %b) : $@convention(thin) <V> (@in R<V>, @in Int, @owned <τ_0_0> { var E<(R<τ_0_0>)->Int> } <V>) -> ()
+  return %k : $@callee_guaranteed (@in R<U>) -> ()
+}
diff --git a/test/SILOptimizer/plus_zero_cast_folding_no_bridging.sil b/test/SILOptimizer/plus_zero_cast_folding_no_bridging.sil
new file mode 100644
index 0000000..4b4c661
--- /dev/null
+++ b/test/SILOptimizer/plus_zero_cast_folding_no_bridging.sil
@@ -0,0 +1,103 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -assume-parsing-unqualified-ownership-sil -O -emit-sil %s | %FileCheck %s
+// REQUIRES: objc_interop
+
+// We want to check that casts between two types which are both Swift types or
+// both are ObjC types are not optimized by the cast optimizer into casts
+// to/from ObjC.
+
+sil_stage raw
+
+import Builtin
+import Swift
+import SwiftShims
+import Foundation
+
+
+// CHECK-LABEL: sil @testSwiftToSwift : $@convention(thin) (@in Set<Int>, @guaranteed Set<Int>)
+// CHECK: bb0
+// CHECK-NOT: checked_cast_addr_br
+// CHECK-NOT: _bridgeToObjectiveC
+// CHECK-NOT: _conditionallyBridgeFromObjectiveC_bridgeable
+// CHECK: return
+sil @testSwiftToSwift : $@convention(thin) (@in Set<Int>, @guaranteed Set<Int>) -> @owned Set<Int> {
+bb0(%0 : $*Set<Int>, %1 : $Set<Int>):
+  %3 = alloc_stack $Set<Int>
+  copy_addr %0 to [initialization] %3 : $*Set<Int>
+  %5 = alloc_stack $Set<Int>
+  checked_cast_addr_br take_always Set<Int> in %3 : $*Set<Int> to Set<Int> in %5 : $*Set<Int>, bb1, bb3
+
+bb1:
+  destroy_addr %0 : $*Set<Int>
+  %8 = load %5 : $*Set<Int>
+  br bb2(%8 : $Set<Int>)
+
+bb2(%14 : $Set<Int>):
+  dealloc_stack %5 : $*Set<Int>
+  dealloc_stack %3 : $*Set<Int>
+  return %14 : $Set<Int>
+
+bb3:
+  br bb2(%1 : $Set<Int>)
+}
+
+// CHECK-LABEL: sil @testObjCToObjC : $@convention(thin) (NSSet, NSSet)
+// CHECK: bb0
+// CHECK-NOT: checked_cast_br
+// CHECK-NOT: BridgeFromObjectiveC
+// CHECK-NOT: bridgeToObjectiveC
+// CHECK: return
+sil @testObjCToObjC : $@convention(thin) (NSSet, NSSet) -> @owned NSSet {
+bb0(%0 : $NSSet, %1 : $NSSet):
+  checked_cast_br %0 : $NSSet to $NSSet, bb1, bb3
+
+bb1(%2 : $NSSet):
+  br bb2(%2 : $NSSet)
+
+bb2(%14 : $NSSet):
+  return %14 : $NSSet
+
+bb3:
+  br bb2(%1 : $NSSet)
+}
+
+sil @fail : $@convention(thin) () -> Never
+
+// CHECK-LABEL: sil @testCFToObjC
+// CHECK: bb0(
+// CHECK-NEXT: [[T0:%.*]] = load %1 : $*CFString
+// CHECK-NEXT: [[T1:%.*]] = unchecked_ref_cast [[T0]] : $CFString to $NSString
+// CHECK-NEXT: store [[T1]] to %0 : $*NSString
+sil @testCFToObjC : $@convention(thin) (@in CFString) -> @out NSString {
+bb0(%0 : $*NSString, %1 : $*CFString):
+  checked_cast_addr_br take_always CFString in %1 : $*CFString to NSString in %0 : $*NSString, bb1, bb2
+
+bb1:
+  %ret = tuple ()
+  return %ret : $()
+
+bb2:
+  %fn = function_ref @fail : $@convention(thin) () -> Never
+  apply %fn() : $@convention(thin) () -> Never
+  unreachable
+}
+
+// CHECK-LABEL: sil @testCFToSwift
+// CHECK: bb0(
+// CHECK-NEXT: [[T0:%.*]] = load %1 : $*CFString
+// CHECK-NEXT: [[T1:%.*]] = unchecked_ref_cast [[T0]] : $CFString to $NSString
+// CHECK:      [[FN:%.*]] = function_ref @$SSS10FoundationE34_conditionallyBridgeFromObjectiveC_6resultSbSo8NSStringC_SSSgztFZ : $@convention(method) (@guaranteed NSString, @inout Optional<String>, @thin String.Type) -> Bool
+// CHECK: apply [[FN]]([[T1]], {{.*}}, {{.*}})
+sil @testCFToSwift : $@convention(thin) (@in CFString) -> @out String {
+bb0(%0 : $*String, %1 : $*CFString):
+  checked_cast_addr_br take_always CFString in %1 : $*CFString to String in %0 : $*String, bb1, bb2
+
+bb1:
+  %ret = tuple ()
+  return %ret : $()
+
+bb2:
+  %fn = function_ref @fail : $@convention(thin) () -> Never
+  apply %fn() : $@convention(thin) () -> Never
+  unreachable
+}
diff --git a/test/SILOptimizer/plus_zero_cast_folding_objc_generics.swift b/test/SILOptimizer/plus_zero_cast_folding_objc_generics.swift
new file mode 100644
index 0000000..effe201
--- /dev/null
+++ b/test/SILOptimizer/plus_zero_cast_folding_objc_generics.swift
@@ -0,0 +1,29 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -O -emit-sil %s | %FileCheck %s
+// REQUIRES: objc_interop
+
+import objc_generics
+
+// CHECK-LABEL: sil shared [noinline] @$S26cast_folding_objc_generics26testObjCGenericParamChangeySo12GenericClassCySo8NSStringCGADySo15NSMutableStringCGFTf4n_g : $@convention(thin) (@guaranteed GenericClass<NSMutableString>) -> GenericClass<NSString> {
+// CHECK:         upcast
+// CHECK-NOT:     int_trap
+@inline(never)
+public func testObjCGenericParamChange(_ a: GenericClass<NSMutableString>) -> GenericClass<NSString> {
+  return a as! GenericClass<NSString>
+}
+
+// CHECK-LABEL: sil shared [noinline] @$S26cast_folding_objc_generics34testObjCGenericParamChangeSubclassySo07GenericJ0CySo8NSStringCGSo0K5ClassCySo15NSMutableStringCGFTf4n_g : $@convention(thin) (@guaranteed GenericClass<NSMutableString>) -> GenericSubclass<NSString> {
+// CHECK:         unconditional_checked_cast
+// CHECK-NOT:     int_trap
+@inline(never)
+public func testObjCGenericParamChangeSubclass(_ a: GenericClass<NSMutableString>) -> GenericSubclass<NSString> {
+  return a as! GenericSubclass<NSString>
+}
+
+// CHECK-LABEL: sil shared [noinline] @$S26cast_folding_objc_generics36testObjCGenericParamChangeSuperclassySo12GenericClassCySo8NSStringCGSo0K8SubclassCySo15NSMutableStringCGFTf4n_g : $@convention(thin) (@guaranteed GenericSubclass<NSMutableString>) -> GenericClass<NSString> {
+// CHECK:         upcast
+// CHECK-NOT:     int_trap
+@inline(never)
+public func testObjCGenericParamChangeSuperclass(_ a: GenericSubclass<NSMutableString>) -> GenericClass<NSString> {
+  return a as! GenericClass<NSString>
+}
diff --git a/test/SILOptimizer/plus_zero_cast_folding_objc_no_foundation.swift b/test/SILOptimizer/plus_zero_cast_folding_objc_no_foundation.swift
new file mode 100644
index 0000000..5648147
--- /dev/null
+++ b/test/SILOptimizer/plus_zero_cast_folding_objc_no_foundation.swift
@@ -0,0 +1,67 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -O -emit-sil %s | %FileCheck %s
+// REQUIRES: objc_interop
+
+// TODO: Update optimizer for id-as-Any changes.
+
+// Note: no 'import Foundation'
+
+struct PlainStruct {}
+
+// CHECK-LABEL: sil hidden [noinline] @$S31cast_folding_objc_no_foundation23testAnyObjectToArrayIntySbyXlF : $@convention(thin) (@guaranteed AnyObject) -> Bool {
+// CHECK: bb0(%0 : $AnyObject):
+// CHECK: [[SOURCE:%.*]] = alloc_stack $AnyObject
+// CHECK: [[TARGET:%.*]] = alloc_stack $Array<Int>
+// CHECK: checked_cast_addr_br take_always AnyObject in [[SOURCE]] : $*AnyObject to Array<Int> in [[TARGET]] : $*Array<Int>, bb1, bb2
+@inline(never)
+func testAnyObjectToArrayInt(_ a: AnyObject) -> Bool {
+  return a is [Int]
+}
+
+// CHECK-LABEL: sil hidden [noinline] @$S31cast_folding_objc_no_foundation26testAnyObjectToArrayStringySbyXlF : $@convention(thin) (@guaranteed AnyObject) -> Bool {
+// CHECK: bb0(%0 : $AnyObject):
+// CHECK: [[SOURCE:%.*]] = alloc_stack $AnyObject
+// CHECK: [[TARGET:%.*]] = alloc_stack $Array<String>
+// CHECK: checked_cast_addr_br take_always AnyObject in [[SOURCE]] : $*AnyObject to Array<String> in [[TARGET]] : $*Array<String>, bb1, bb2
+@inline(never)
+func testAnyObjectToArrayString(_ a: AnyObject) -> Bool {
+  return a is [String]
+}
+
+// CHECK-LABEL: sil hidden [noinline] @$S31cast_folding_objc_no_foundation30testAnyObjectToArrayNotBridgedySbyXlF : $@convention(thin) (@guaranteed AnyObject) -> Bool {
+// CHECK: bb0(%0 : $AnyObject):
+// CHECK: [[SOURCE:%.*]] = alloc_stack $AnyObject
+// CHECK: [[TARGET:%.*]] = alloc_stack $Array<PlainStruct>
+// CHECK: checked_cast_addr_br take_always AnyObject in [[SOURCE]] : $*AnyObject to Array<PlainStruct> in [[TARGET]] : $*Array<PlainStruct>, bb1, bb2
+@inline(never)
+func testAnyObjectToArrayNotBridged(_ a: AnyObject) -> Bool {
+  return a is [PlainStruct]
+}
+
+// CHECK-LABEL: sil hidden [noinline] @$S31cast_folding_objc_no_foundation25testAnyObjectToDictionaryySbyXlF : $@convention(thin) (@guaranteed AnyObject) -> Bool {
+// CHECK: bb0(%0 : $AnyObject):
+// CHECK: [[SOURCE:%.*]] = alloc_stack $AnyObject
+// CHECK: [[TARGET:%.*]] = alloc_stack $Dictionary<Int, String>
+// CHECK: checked_cast_addr_br take_always AnyObject in [[SOURCE]] : $*AnyObject to Dictionary<Int, String> in [[TARGET]] : $*Dictionary<Int, String>, bb1, bb2
+@inline(never)
+func testAnyObjectToDictionary(_ a: AnyObject) -> Bool {
+  return a is [Int: String]
+}
+
+// CHECK-LABEL: sil hidden [noinline] @$S31cast_folding_objc_no_foundation21testAnyObjectToStringySbyXlF : $@convention(thin) (@guaranteed AnyObject) -> Bool {
+// CHECK: bb0(%0 : $AnyObject):
+// CHECK: [[SOURCE:%.*]] = alloc_stack $AnyObject
+// CHECK: [[TARGET:%.*]] = alloc_stack $String
+// CHECK: checked_cast_addr_br take_always AnyObject in [[SOURCE]] : $*AnyObject to String in [[TARGET]] : $*String, bb1, bb2
+@inline(never)
+func testAnyObjectToString(_ a: AnyObject) -> Bool {
+  return a is String
+}
+
+class SomeObject {}
+
+print(testAnyObjectToArrayInt(SomeObject()))
+print(testAnyObjectToArrayString(SomeObject()))
+print(testAnyObjectToArrayNotBridged(SomeObject()))
+print(testAnyObjectToDictionary(SomeObject()))
+print(testAnyObjectToString(SomeObject()))
diff --git a/test/SILOptimizer/plus_zero_devirt_covariant_return.swift b/test/SILOptimizer/plus_zero_devirt_covariant_return.swift
new file mode 100644
index 0000000..8c12f8d
--- /dev/null
+++ b/test/SILOptimizer/plus_zero_devirt_covariant_return.swift
@@ -0,0 +1,351 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -Xllvm -sil-full-demangle -O -Xllvm -disable-sil-cm-rr-cm=0   -Xllvm -sil-inline-generics=false -primary-file %s -emit-sil -sil-inline-threshold 1000 -Xllvm -sil-disable-pass=ObjectOutliner -sil-verify-all | %FileCheck %s
+
+// Make sure that we can dig all the way through the class hierarchy and
+// protocol conformances with covariant return types correctly. The verifier
+// should trip if we do not handle things correctly.
+//
+// TODO: this is not working right now: rdar://problem/33461095
+// As a side-test it also checks if all allocs can be promoted to the stack.
+
+// CHECK-LABEL: sil hidden @$S23devirt_covariant_return6driveryyF : $@convention(thin) () -> () {
+// CHECK: bb0
+// CHECK: alloc_ref
+// CHECK: alloc_ref
+// CHECK: function_ref @unknown1a : $@convention(thin) () -> ()
+// CHECK: apply
+// CHECK: function_ref @defenestrate : $@convention(thin) () -> ()
+// CHECK: apply
+// CHECK: function_ref @unknown2a : $@convention(thin) () -> ()
+// CHECK: apply
+// CHECK: apply
+// CHECK: function_ref @unknown3a : $@convention(thin) () -> ()
+// CHECK: apply
+// CHECK: apply
+// CHECK: tuple
+// CHECK: return
+
+@_silgen_name("unknown1a")
+func unknown1a() -> ()
+@_silgen_name("unknown1b")
+func unknown1b() -> ()
+@_silgen_name("unknown2a")
+func unknown2a() -> ()
+@_silgen_name("unknown2b")
+func unknown2b() -> ()
+@_silgen_name("unknown3a")
+func unknown3a() -> ()
+@_silgen_name("unknown3b")
+func unknown3b() -> ()
+@_silgen_name("defenestrate")
+func defenestrate() -> ()
+
+class B<T> {
+  // We do not specialize typealias's correctly now.
+  //typealias X = B
+  func doSomething() -> B<T> {
+    unknown1a()
+    return self
+  }
+
+  // See comment in protocol P
+  //class func doSomethingMeta() {
+  //  unknown1b()
+  //}
+
+  func doSomethingElse() {
+    defenestrate()
+  }
+}
+
+class B2<T> : B<T> {
+  // When we have covariance in protocols, change this to B2.
+  // We do not specialize typealias correctly now.
+  //typealias X = B
+  override func doSomething() -> B2<T> {
+    unknown2a()
+    return self
+  }
+
+  // See comment in protocol P
+  //override class func doSomethingMeta() {
+  //  unknown2b()
+  //}
+}
+
+class B3<T> : B2<T> {
+  override func doSomething() -> B3<T> {
+    unknown3a()
+    return self
+  }
+}
+
+func WhatShouldIDo<T>(_ b : B<T>) -> B<T> {
+  b.doSomething().doSomethingElse()
+  return b
+}
+
+func doSomethingWithB<T>(_ b : B<T>) {
+  
+}
+
+struct S {}
+
+func driver() -> () {
+  let b = B<S>()
+  let b2 = B2<S>()
+  let b3 = B3<S>()
+
+  WhatShouldIDo(b)
+  WhatShouldIDo(b2)
+  WhatShouldIDo(b3)
+}
+
+driver()
+
+public class Bear {
+  public init?(fail: Bool) {
+    if fail { return nil }
+  }
+
+  // Check that devirtualizer can handle convenience initializers, which have covariant optional
+  // return types.
+  // CHECK-LABEL: sil @$S23devirt_covariant_return4BearC{{[_0-9a-zA-Z]*}}fc
+  // CHECK: checked_cast_br [exact] %{{.*}} : $Bear to $PolarBear
+  // CHECK: upcast %{{.*}} : $Optional<PolarBear> to $Optional<Bear>
+  // CHECK: }
+  public convenience init?(delegateFailure: Bool, failAfter: Bool) {
+    self.init(fail: delegateFailure)
+    if failAfter { return nil }
+  }
+}
+
+final class PolarBear: Bear {
+
+  override init?(fail: Bool) {
+    super.init(fail: fail)
+  }
+
+  init?(chainFailure: Bool, failAfter: Bool) {
+    super.init(fail: chainFailure)
+    if failAfter { return nil }
+  }
+}
+
+
+
+
+class Payload {
+  let value: Int32
+  init(_ n: Int32) {
+    value = n
+  }
+
+  func getValue() -> Int32 {
+    return value
+  }
+}
+
+final class Payload1: Payload {
+  override init(_ n: Int32) {
+    super.init(n)
+  }
+}
+
+class C {
+   func doSomething() -> Payload? {
+      return Payload(1)
+   }
+}
+
+
+final class C1:C {
+   // Override base method, but return a non-optional result
+   override func doSomething() -> Payload {
+      return Payload(2)
+   }
+}
+
+final class C2:C {
+   // Override base method, but return a non-optional result of a type,
+   // which is derived from the expected type.
+   override func doSomething() -> Payload1 {
+      return Payload1(2)
+   }
+}
+
+// Check that the Optional return value from doSomething
+// gets properly unwrapped into a Payload object and then further
+// devirtualized.
+// CHECK-LABEL: sil hidden [noinline] @$S23devirt_covariant_return7driver1ys5Int32VAA2C1CF
+// CHECK: integer_literal $Builtin.Int32, 2
+// CHECK: struct $Int32 (%{{.*}} : $Builtin.Int32)
+// CHECK-NOT: class_method
+// CHECK-NOT: function_ref
+// CHECK: return
+@inline(never)
+func driver1(_ c: C1) -> Int32 {
+  return c.doSomething().getValue()
+}
+
+// Check that the Optional return value from doSomething
+// gets properly unwrapped into a Payload object and then further
+// devirtualized.
+// CHECK-LABEL: sil hidden [noinline] @$S23devirt_covariant_return7driver3ys5Int32VAA1CCF
+// CHECK: bb{{[0-9]+}}(%{{[0-9]+}} : $C2):
+// CHECK-NOT: bb{{.*}}:
+// check that for C2, we convert the non-optional result into an optional and then cast.
+// CHECK: enum $Optional
+// CHECK-NEXT: upcast
+// CHECK: return
+@inline(never)
+func driver3(_ c: C) -> Int32 {
+  return c.doSomething()!.getValue()
+}
+
+public class D {
+  let v: Int32
+  init(_ n: Int32) {
+    v = n
+  }
+}
+
+public class D1 : D {
+
+  public func foo() -> D? {
+    return nil
+  }
+
+  public func boo() -> Int32 {
+    return foo()!.v
+  }
+}
+
+let sD = D(0)
+
+public class D2: D1 {
+   // Override base method, but return a non-optional result
+   override public func foo() -> D {
+     return sD
+   }
+}
+
+// Check that the boo call gets properly devirtualized and that
+// that D2.foo() is inlined thanks to this.
+// CHECK-LABEL: sil hidden [noinline] @$S23devirt_covariant_return7driver2ys5Int32VAA2D2CF
+// CHECK-NOT: class_method
+// CHECK: checked_cast_br [exact] %{{.*}} : $D1 to $D2
+// CHECK: bb2
+// CHECK: global_addr
+// CHECK: load
+// CHECK: ref_element_addr
+// CHECK: bb3
+// CHECK: class_method
+// CHECK: }
+@inline(never)
+func driver2(_ d: D2) -> Int32 {
+  return d.boo()
+}
+
+class AA {
+}
+
+class BB : AA {
+}
+
+class CCC {
+  @inline(never)
+  func foo(_ b: BB) -> (AA, AA) {
+    return (b, b)
+  }
+}
+
+class DDD : CCC {
+  @inline(never)
+  override func foo(_ b: BB) -> (BB, BB) {
+    return (b, b)
+  }
+}
+
+
+class EEE : CCC {
+  @inline(never)
+  override func foo(_ b: BB) -> (AA, AA) {
+    return (b, b)
+  }
+}
+
+// Check that c.foo() is devirtualized, because the optimizer can handle the casting the return type
+// correctly, i.e. it can cast (BBB, BBB) into (AAA, AAA)
+// CHECK-LABEL: sil hidden [noinline] @$S23devirt_covariant_return37testDevirtOfMethodReturningTupleTypes_1bAA2AAC_AEtAA3CCCC_AA2BBCtF
+// CHECK: checked_cast_br [exact] %{{.*}} : $CCC to $CCC
+// CHECK: checked_cast_br [exact] %{{.*}} : $CCC to $DDD
+// CHECK: checked_cast_br [exact] %{{.*}} : $CCC to $EEE
+// CHECK: class_method
+// CHECK: }
+@inline(never)
+func testDevirtOfMethodReturningTupleTypes(_ c: CCC, b: BB) -> (AA, AA) {
+  return c.foo(b)
+}
+
+
+class AAAA {
+}
+
+class BBBB : AAAA {
+}
+
+class CCCC {
+  let a: BBBB
+  var foo : (AAAA, AAAA) {
+    @inline(never)
+    get {
+      return (a, a)
+    }
+  }
+  init(x: BBBB) { a = x }
+}
+
+class DDDD : CCCC {
+  override var foo : (BBBB, BBBB) {
+    @inline(never)
+    get {
+      return (a, a)
+    }
+  }
+}
+
+// Check devirtualization of methods with optional results, where
+// optional results need to be casted.
+// CHECK-LABEL: sil [noinline] @{{.*}}testOverridingMethodWithOptionalResult
+// CHECK: checked_cast_br [exact] %{{.*}} : $F to $F
+// CHECK: checked_cast_br [exact] %{{.*}} : $F to $G
+// CHECK: switch_enum
+// CHECK: checked_cast_br [exact] %{{.*}} : $F to $H
+// CHECK: switch_enum
+@inline(never)
+public func testOverridingMethodWithOptionalResult(_ f: F) -> (F?, Int)? {
+  return f.foo()
+}
+
+
+public class F {
+  @inline(never)
+  public func foo() -> (F?, Int)? {
+    return (F(), 1)
+  }
+}
+
+public class G: F {
+  @inline(never)
+  override public func foo() -> (G?, Int)? {
+    return (G(), 2)
+  }
+}
+
+public class H: F {
+  @inline(never)
+  override public func foo() -> (H?, Int)? {
+    return nil
+  }
+}
diff --git a/test/SILOptimizer/plus_zero_devirt_default_case.swift b/test/SILOptimizer/plus_zero_devirt_default_case.swift
new file mode 100644
index 0000000..c6eeaa8
--- /dev/null
+++ b/test/SILOptimizer/plus_zero_devirt_default_case.swift
@@ -0,0 +1,276 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -O -module-name devirt_default_case -emit-sil %s | %FileCheck -check-prefix=CHECK -check-prefix=CHECK-NORMAL %s
+// RUN: %target-swift-frontend -O -module-name devirt_default_case -emit-sil -enable-testing %s | %FileCheck -check-prefix=CHECK -check-prefix=CHECK-TESTABLE %s
+
+@_silgen_name("action")
+func action(_ n:Int) -> ()
+
+// public class
+open class Base1 {
+  @inline(never) func inner() { action(1)}
+  func middle() { inner() }
+// Check that call to Base1.middle cannot be devirtualized
+//
+// CHECK-LABEL: sil @$S19devirt_default_case5Base1C5outer{{[_0-9a-zA-Z]*}}F
+// CHECK: class_method 
+// CHECK: } // end sil function '$S19devirt_default_case5Base1C5outer{{[_0-9a-zA-Z]*}}F'
+  public func outer() { 
+    middle() 
+  }
+}
+
+// public class
+open class Derived1 : Base1 {
+  override func inner() { action(2) }
+  @inline(never) final override func middle() { inner() }
+}
+
+// private class
+private class Base2 {
+  @inline(never) func inner() { action(3)}
+  func middle() { inner() }
+  func outer() { middle() }
+}
+
+// private class
+private class Derived2 : Base2 {
+  override func inner() { action(4) }
+  @inline(never) final override func middle() { inner() }
+}
+
+
+// Check that call to Base2.middle can be devirtualized
+//
+// CHECK-LABEL: sil @$S19devirt_default_case9callOuteryS2iF
+// CHECK: function_ref @$S19devirt_default_case5Base233_{{.*}}5inner
+// CHECK: function_ref @$S19devirt_default_case8Derived233_{{.*}}6middle
+// CHECK-NOT: class_method
+// CHECK: } // end sil function '$S19devirt_default_case9callOuteryS2iF'
+public func callOuter(_ x: Int) -> Int {
+
+  var o:Base2
+  
+  if x == 1 {
+    o = Base2()
+  } else {
+    o = Derived2()
+  }
+  
+  o.outer()
+  return x
+}
+
+// internl class
+class Base3 {
+  @inline(never) func inner() { action(5)}
+  @inline(never) func middle() { inner() }
+// Check that call to Base3.middle can be devirtualized when not compiling
+// for testing.
+//
+// CHECK-LABEL: sil{{( hidden)?}} [noinline] @$S19devirt_default_case5Base3C5outeryyF : $@convention(method) (@guaranteed Base3) -> () {
+// CHECK: function_ref @$S19devirt_default_case5Base3C6middleyyF
+// CHECK: function_ref @$S19devirt_default_case8Derived333_{{.*}}6middle
+// CHECK-NORMAL-NOT: class_method
+// CHECK-TESTABLE: class_method %0 : $Base3, #Base3.middle!1
+// CHECK: } // end sil function '$S19devirt_default_case5Base3C5outeryyF'
+  @inline(never) func outer() {
+    middle()
+  }
+}
+
+// private class
+private class Derived3 : Base3 {
+  override func inner() { action(6) }
+  @inline(never) final override func middle() { inner() }
+  override func outer() {
+  }
+}
+
+class A2 { @inline(never) func f() -> Int { return 0 } }
+class B2 : A2 {}
+class C2 : A2 {}
+class D2: B2 {}
+class E2 :C2 {}
+
+class A3 { @inline(never) func f() -> Int { return 0 } }
+class B3 : A3 { @inline(never) override func f() -> Int { return 1 }}
+class C3 : A3 {}
+class D3: C3 {}
+class E3 :C3 {}
+
+// CHECK-TESTABLE: sil{{( hidden)?}} [noinline] @$S19devirt_default_case3fooySiAA2A3CF
+
+public func testfoo1() -> Int {
+  return foo(E2())
+}
+
+
+public func testfoo3() -> Int {
+  return foo(E3())
+}
+
+// Check that call to A3.f() can be devirtualized.
+//
+// CHECK-NORMAL: sil hidden [noinline] @$S19devirt_default_case3fooySiAA2A3CF
+// CHECK-NORMAL: function_ref @$S19devirt_default_case2B3C1fSiyFTf4d_n
+// CHECK-NORMAL: function_ref @$S19devirt_default_case2A3C1fSiyFTf4d_n
+// CHECK-NORMAL-NOT: class_method
+// CHECK: } // end sil function '$S19devirt_default_case3fooySiAA2A3CF'
+
+class Base4 {
+  @inline(never)
+  func test() { 
+// Check that call to foo() can be devirtualized
+//
+// CHECK-LABEL: sil{{( hidden)?}} [noinline] @$S19devirt_default_case5Base4C4testyyF
+// CHECK: function_ref @$S19devirt_default_case5Base4C3fooyyFTf4d_n
+// CHECK: function_ref @$S19devirt_default_case8Derived4C3fooyyFTf4d_n
+// CHECK-NORMAL-NOT: class_method
+// CHECK-TESTABLE: class_method %0 : $Base4, #Base4.foo!1
+// CHECK: } // end sil function '$S19devirt_default_case5Base4C4testyyF'
+    foo() 
+  }
+  
+  @inline(never) func foo() { }
+}
+
+
+// A, C,D,E all use the same implementation. 
+// B has its own implementation.
+@inline(never)
+func foo(_ a: A3) -> Int {
+  return a.f()
+}
+
+class Derived4 : Base4 {
+  @inline(never) override func foo() { }
+}
+
+open class Base5 {
+  @inline(never)
+  open func test() { 
+    foo() 
+  }
+  
+  @inline(never) public final func foo() { }
+}
+
+class Derived5 : Base5 {
+}
+
+open class C6 { 
+  func bar() -> Int { return 1 } 
+}
+
+class D6 : C6 { 
+  override func bar() -> Int { return 2 } 
+}
+
+@inline(never)
+func check_static_class_devirt(_ c: C6) -> Int { 
+// Check that C.bar() and D.bar() are devirtualized.
+//
+// CHECK-LABEL: sil{{( hidden)?}} [noinline] @$S19devirt_default_case019check_static_class_A0ySiAA2C6CF
+// CHECK: checked_cast_br [exact] %0 : $C6 to $C6
+// CHECK: checked_cast_br [exact] %0 : $C6 to $D6
+// CHECK: class_method
+// CHECK: } // end sil function '$S19devirt_default_case019check_static_class_A0ySiAA2C6CF'
+  return c.bar() 
+}
+
+public func test_check_static_class_devirt() -> Int {
+  return check_static_class_devirt(D6())
+}
+
+
+class A7 { @inline(never) func foo() -> Bool { return false } }
+class B7 : A7 { @inline(never) override func foo() -> Bool { return true } }
+
+public func test_check_call_on_downcasted_instance() -> Bool {
+  return check_call_on_downcasted_instance(B7())
+}
+
+@inline(never)
+func callIt(_ b3: Base3, _ b4: Base4, _ b5: Base5) {
+  b3.outer()
+  b4.test()
+  b5.test()
+}
+
+public func externalEntryPoint() {
+  callIt(Base3(), Base4(), Base5())
+}
+
+open class M {
+  func foo() -> Int32 {
+    return 0
+  }
+}
+
+
+open class M1: M {
+  @inline(never)
+  override func foo() -> Int32 {
+    return 1
+  }
+}
+
+internal class M2: M1 {
+  @inline(never)
+  override func foo() -> Int32 {
+    return 2
+  }
+}
+
+internal class M3: M1 {
+  @inline(never)
+  override func foo() -> Int32 {
+    return 3
+  }
+}
+
+internal class M22: M2 {
+  @inline(never)
+  override func foo() -> Int32 {
+    return 22
+  }
+}
+
+internal class M222: M22 {
+  @inline(never)
+  override func foo() -> Int32 {
+    return 222
+  }
+}
+
+internal class M33: M3 {
+  @inline(never)
+  override func foo() -> Int32 {
+    return 33
+  }
+}
+
+
+// Check that speculative devirtualization tries to devirtualize the first N
+// alternatives, if it has too many.
+// The alternatives should be taken in a breadth-first order, starting with
+// the static type of the instance.
+
+@inline(never)
+public func testSpeculativeDevirtualizationWithTooManyAlternatives(_ c:M1) -> Int32{
+  return c.foo()
+}
+
+
+@inline(never)
+func foo(_ a: A2) -> Int {
+  return a.f()
+}
+
+@inline(never)
+func check_call_on_downcasted_instance(_ a: A7) -> Bool {
+  if a is B7 {
+    return (a as! B7).foo()
+  }
+  return a.foo()
+}
diff --git a/test/SILOptimizer/plus_zero_devirt_nested_class.swift b/test/SILOptimizer/plus_zero_devirt_nested_class.swift
new file mode 100644
index 0000000..936d6d9
--- /dev/null
+++ b/test/SILOptimizer/plus_zero_devirt_nested_class.swift
@@ -0,0 +1,31 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -emit-sil -O %s | %FileCheck %s
+
+fileprivate class Outer<T> {
+  class Inner<U> : Base<T, U> {
+    @_optimize(none)
+    override func method<V>(v: V) {}
+  }
+}
+
+fileprivate class Base<T, U> {
+  @_optimize(none)
+  func method<V>(v: V) {}
+}
+
+fileprivate class Derived<T, U> : Outer<T>.Inner<U> {}
+
+@_transparent
+fileprivate func bar<T, U, V>(b: Base<T, U>, v: V) {
+  b.method(v: v)
+}
+
+fileprivate func foo<T, U, V>(d: Outer<T>.Inner<U>, v: V) {
+  bar(b: d, v: v)
+}
+
+foo(d: Outer<Int>.Inner<Int>(), v: 0)
+
+// CHECK-LABEL: sil @main : $@convention(c) (Int32, UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>) -> Int32
+// CHECK: function_ref @$S19devirt_nested_class5Outer{{.*}}LC5InnerC6method1vyqd0___tlF : $@convention(method) <τ_0_0><τ_1_0><τ_2_0> (@in_guaranteed τ_2_0, @guaranteed Outer<τ_0_0>.Inner<τ_1_0>) -> ()
+// CHECK: return
diff --git a/test/SILOptimizer/plus_zero_devirt_protocol_method_invocations.swift b/test/SILOptimizer/plus_zero_devirt_protocol_method_invocations.swift
new file mode 100644
index 0000000..2b1a325
--- /dev/null
+++ b/test/SILOptimizer/plus_zero_devirt_protocol_method_invocations.swift
@@ -0,0 +1,266 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -O -emit-sil %s | %FileCheck %s
+
+protocol PPP {
+    func f()
+}
+
+protocol QQQ : PPP {
+}
+
+protocol RRR : QQQ {
+}
+
+struct S : RRR {}
+
+extension QQQ {
+    @_optimize(none)
+    func f() {}
+}
+
+// Test that all witness_method instructions are devirtualized.
+// This test used to crash the compiler because it uses inherited conformances.
+// CHECK-LABEL: sil @$S34devirt_protocol_method_invocations24testInheritedConformanceyyF : $@convention(thin) () -> ()
+// CHECK-NOT: witness_method
+// CHECK-NOT: class_method
+// CHECK: apply
+// CHECK: // end sil function '$S34devirt_protocol_method_invocations24testInheritedConformanceyyF'
+public func testInheritedConformance() {
+    (S() as QQQ).f()
+}
+
+// Test that a witness_method instruction using an indirectly-inherited conformance
+// is devirtualized.
+//
+// This test used to crash the compiler because it uses inherited conformances.
+// CHECK-LABEL: sil @$S34devirt_protocol_method_invocations34testIndirectlyInheritedConformanceyyF : $@convention(thin) () -> ()
+// CHECK-NOT: witness_method
+// CHECK: apply
+// CHECK: // end sil function '$S34devirt_protocol_method_invocations34testIndirectlyInheritedConformanceyyF'
+public func testIndirectlyInheritedConformance() {
+  (S() as RRR).f()
+}
+
+
+public protocol Foo { 
+  func foo(_ x:Int) -> Int
+}
+
+public extension Foo {
+  func boo(_ x:Int) -> Int32 {
+    return 2222 + Int32(x)
+  }
+
+  func getSelf() -> Self {
+    return self
+  }
+}
+
+var gg = 1111
+
+open class C : Foo {
+  @inline(never)
+  open func foo(_ x:Int) -> Int {
+    gg += 1
+    return gg + x
+  }
+}
+
+@_transparent
+func callfoo(_ f: Foo) -> Int {
+  return f.foo(2) + f.foo(2)
+}
+
+@_transparent
+func callboo(_ f: Foo) -> Int32 {
+  return f.boo(2) + f.boo(2)
+}
+
+@_transparent
+func callGetSelf(_ f: Foo) -> Foo {
+  return f.getSelf()
+}
+
+// Check that methods returning Self are not devirtualized and do not crash the compiler.
+// CHECK-LABEL: sil [noinline] @$S34devirt_protocol_method_invocations05test_a1_b11_extension_C33_invocation_with_self_return_typeyAA3Foo_pAA1CCF
+// CHECK: init_existential_addr
+// CHECK: open_existential_addr
+// CHECK: return
+@inline(never)
+public func test_devirt_protocol_extension_method_invocation_with_self_return_type(_ c: C) -> Foo {
+  return callGetSelf(c)
+}
+
+// Check that calls to f.foo() get devirtualized and are not invoked
+// via the expensive witness_method instruction.
+// To achieve that the information about a concrete type C should
+// be propagated from init_existential_addr into witness_method and 
+// apply instructions.
+
+// CHECK-LABEL: sil [noinline] @$S34devirt_protocol_method_invocations05test_a1_b1_C11_invocationySiAA1CCF
+// CHECK-NOT: witness_method
+// CHECK: checked_cast
+// CHECK-NOT: checked_cast
+// CHECK: bb1(
+// CHECK-NOT: checked_cast
+// CHECK: return
+// CHECK: bb2(
+// CHECK-NOT: checked_cast
+// CHECK: function_ref
+// CHECK: apply
+// CHECK: apply
+// CHECK: br bb1(
+// CHECK: bb3
+// CHECK-NOT: checked_cast
+// CHECK: apply
+// CHECK: apply
+// CHECK: br bb1(
+
+// Check that calls of a method boo() from the protocol extension
+// get devirtualized and are not invoked via the expensive witness_method instruction
+// or by passing an existential as a parameter.
+// To achieve that the information about a concrete type C should
+// be propagated from init_existential_addr into apply instructions.
+// In fact, the call is expected to be inlined and then constant-folded
+// into a single integer constant.
+
+// CHECK-LABEL: sil [noinline] @$S34devirt_protocol_method_invocations05test_a1_b11_extension_C11_invocationys5Int32VAA1CCF
+// CHECK-NOT: checked_cast
+// CHECK-NOT: open_existential
+// CHECK-NOT: witness_method
+// CHECK-NOT: apply
+// CHECK: integer_literal
+// CHECK: return
+
+// CHECK: sil @$S34devirt_protocol_method_invocations12test24114020SiyF
+// CHECK:   [[T0:%.*]] = integer_literal $Builtin.Int{{.*}}, 1
+// CHECK:   [[T1:%.*]] = struct $Int ([[T0]] : $Builtin.Int{{.*}})
+// CHECK:   return [[T1]]
+
+// CHECK: sil @$S34devirt_protocol_method_invocations14testExMetatypeSiyF
+// CHECK:   [[T0:%.*]] = builtin "sizeof"<Int>
+// CHECK:   [[T1:%.*]] = builtin {{.*}}([[T0]]
+// CHECK:   [[T2:%.*]] = struct $Int ([[T1]] : {{.*}})
+// CHECK:   return [[T2]] : $Int
+
+@inline(never)
+public func test_devirt_protocol_method_invocation(_ c: C) -> Int {
+  return callfoo(c)
+}
+
+@inline(never)
+public func test_devirt_protocol_extension_method_invocation(_ c: C) -> Int32 {
+  return callboo(c)
+}
+
+
+// Make sure that we are not crashing with an assertion due to specialization
+// of methods with the Self return type as an argument.
+// rdar://20868966
+protocol Proto {
+  func f() -> Self
+}
+
+class CC : Proto {
+  func f() -> Self { return self }
+}
+
+func callDynamicSelfExistential(_ p: Proto) {
+  p.f()
+}
+
+public func testSelfReturnType() {
+  callDynamicSelfExistential(CC())
+}
+
+
+// Make sure that we are not crashing with an assertion due to specialization
+// of methods with the Self return type.
+// rdar://20955745.
+protocol CP : class { func f() -> Self }
+func callDynamicSelfClassExistential(_ cp: CP) { cp.f() }
+class PP : CP {
+  func f() -> Self { return self }
+}
+
+callDynamicSelfClassExistential(PP())
+
+// Make sure we handle indirect conformances.
+// rdar://24114020
+protocol Base {
+  var x: Int { get }
+}
+protocol Derived : Base {
+}
+struct SimpleBase : Derived {
+  var x: Int
+}
+public func test24114020() -> Int {
+  let base: Derived = SimpleBase(x: 1)
+  return base.x
+}
+
+protocol StaticP {
+  static var size: Int { get }
+}
+struct HasStatic<T> : StaticP {
+  static var size: Int { return MemoryLayout<T>.size }
+}
+public func testExMetatype() -> Int {
+  let type: StaticP.Type = HasStatic<Int>.self
+  return type.size
+}
+
+// rdar://32288618
+public func testExMetatypeVar() -> Int {
+  var type: StaticP.Type = HasStatic<Int>.self
+  return type.size
+}
+
+// IRGen used to crash on the testPropagationOfConcreteTypeIntoExistential method.
+// rdar://26286278
+
+protocol MathP {
+  var sum: Int32 { get nonmutating set }
+  func done()
+}
+
+extension MathP {
+  @inline(never)
+  func plus() -> Self {
+    sum += 1
+    return self
+  }
+
+  @inline(never)
+  func minus() {
+    sum -= 1
+    if sum == 0 {
+      done()
+    }
+  }
+}
+
+protocol MathA : MathP {}
+
+public final class V {
+  var a: MathA
+
+  init(a: MathA) {
+    self.a = a
+  }
+}
+
+// Check that all witness_method invocations are devirtualized.
+// CHECK-LABEL: sil [noinline] @$S34devirt_protocol_method_invocations44testPropagationOfConcreteTypeIntoExistential1v1xyAA1VC_s5Int32VtF
+// CHECK-NOT: witness_method
+// CHECK-NOT: class_method
+// CHECK: return
+@inline(never)
+public func testPropagationOfConcreteTypeIntoExistential(v: V, x: Int32) {
+  let y = v.a.plus()
+  defer {
+    y.minus()
+  }
+}
+
diff --git a/test/SILOptimizer/plus_zero_devirt_speculative_nested.swift b/test/SILOptimizer/plus_zero_devirt_speculative_nested.swift
new file mode 100644
index 0000000..bc6a9e8
--- /dev/null
+++ b/test/SILOptimizer/plus_zero_devirt_speculative_nested.swift
@@ -0,0 +1,32 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend %s -parse-as-library -O -emit-sil | %FileCheck %s
+// RUN: %target-swift-frontend %s -parse-as-library -Osize -emit-sil
+//
+// Test speculative devirtualization.
+
+public class Outer<T> {
+  final class Inner : Base {
+    @inline(never) override func update() {
+    }
+  }
+}
+
+public class Base {
+  @inline(never) func update() { }
+}
+
+// FIXME: We don't speculate to the override Outer<T>.Inner.update() here,
+// because we cannot express the cast -- the cast "returns" a new archetype
+// T, much like an opened existential.
+//
+// But at least, we shouldn't crash.
+
+// CHECK-LABEL: sil @$S25devirt_speculative_nested3foo1xyAA4BaseC_tF : $@convention(thin) (@guaranteed Base) -> ()
+// CHECK: checked_cast_br [exact] %0 : $Base to $Base
+// CHECK: function_ref @$S25devirt_speculative_nested4BaseC6updateyyF
+// CHECK: class_method %0 : $Base, #Base.update!1
+// CHECK: return
+
+public func foo(x: Base) {
+  x.update()
+}
diff --git a/test/SILOptimizer/plus_zero_devirt_value_metatypes.swift b/test/SILOptimizer/plus_zero_devirt_value_metatypes.swift
new file mode 100644
index 0000000..b324eab
--- /dev/null
+++ b/test/SILOptimizer/plus_zero_devirt_value_metatypes.swift
@@ -0,0 +1,63 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -emit-sil -O %s | %FileCheck %s
+
+open class A {
+  @inline(never)
+  class func foo() {
+  }
+}
+
+
+class B: A {
+  @inline(never)
+  override class func foo() {}
+}
+
+// CHECK-LABEL: sil @$S22devirt_value_metatypes17testValueMetatypeyyAA1ACF
+// CHECK: value_metatype $@thick A.Type
+// CHECK: checked_cast_br
+// CHECK: checked_cast_br
+// CHECK: class_method
+// CHECK: }
+public func testValueMetatype(_ x:A) {
+    type(of: x).foo()
+}
+
+open class C {
+  @inline(never)
+  class func foo() -> Int { return 0 }
+}
+
+open class D : C {
+  @inline(never)
+  override class func foo() -> Int { return 1 }
+}
+
+// CHECK-LABEL: sil @$S22devirt_value_metatypes5testDySiAA1DCF
+// CHECK-NOT: value_metatype %
+// D.foo is an internal method, D has no subclasses and it is a wmo compilation,
+// therefore D.foo method invocation can be devirtualized.
+// CHECK: function_ref @$S22devirt_value_metatypes1DC3fooSiyFZTf4d_n
+// CHECK-NOT: value_metatype %
+// CHECK-NOT: checked_cast_br
+// CHECK-NOT: class_method
+// CHECK: }
+public func testD(_ x: D) -> Int {
+  return (type(of: x) as C.Type).foo()
+}
+
+
+public final class E : C {
+  @inline(never)
+  override class func foo() -> Int { return 1 }
+}
+
+// CHECK-LABEL: sil @$S22devirt_value_metatypes5testEySiAA1ECF
+// CHECK-NOT: value_metatype $@thick E.Type
+// CHECK_NOT: checked_cast_br
+// CHECK: function_ref
+// CHECK: apply
+// CHECK: return
+public func testE(_ x: E) -> Int {
+  return (type(of: x) as C.Type).foo()
+}
diff --git a/test/SILOptimizer/plus_zero_devirt_witness_method_conformance.swift b/test/SILOptimizer/plus_zero_devirt_witness_method_conformance.swift
new file mode 100644
index 0000000..f3da042
--- /dev/null
+++ b/test/SILOptimizer/plus_zero_devirt_witness_method_conformance.swift
@@ -0,0 +1,20 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -O -emit-ir  -primary-file %s | %FileCheck %s
+// This is a swift file because the crash doesn't reproduce with SIL.
+@inline(never)
+func callFoo<T: X>(_ x: T) {
+  x.foo()
+}
+public func a(y: Sub) {
+  callFoo(y)
+  // specialization of callFoo for Sub:
+// CHECK-LABEL: define linkonce_odr hidden swiftcc void @"$S33devirt_witness_method_conformance7callFooyyxAA1XRzlFAA3SubC_Tg5"({{.*}}) local_unnamed_addr
+}
+protocol X {
+  func foo()
+}
+extension X {
+  func foo() {}
+}
+public class Base: X {}
+public class Sub: Base {}
diff --git a/test/SILOptimizer/plus_zero_let_properties_opts.swift b/test/SILOptimizer/plus_zero_let_properties_opts.swift
new file mode 100644
index 0000000..12be391
--- /dev/null
+++ b/test/SILOptimizer/plus_zero_let_properties_opts.swift
@@ -0,0 +1,356 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend %s -O -emit-sil | %FileCheck -check-prefix=CHECK-WMO %s
+// RUN: %target-swift-frontend -primary-file %s -O -emit-sil | %FileCheck %s
+
+// Test propagation of non-static let properties with compile-time constant values.
+
+// TODO: Once this optimization can remove the propagated fileprivate/internal let properties or
+// mark them as ones without a storage, new tests should be added here to check for this
+// functionality.
+
+// FIXME: This test is written in Swift instead of SIL, because there are some problems
+// with SIL deserialization (rdar://22636911)
+
+// Check that initializers do not contain a code to initialize fileprivate or
+// internal (if used with WMO) properties, because their values are propagated into
+// their uses and they cannot be accessed from other modules. Therefore the
+// initialization code could be removed.
+// Specifically, the initialization code for Prop1, Prop2 and Prop3 can be removed.
+
+// CHECK-WMO-LABEL: sil @$S19let_properties_opts3FooC{{[_0-9a-zA-Z]*}}fc : $@convention(method) (Int32, @owned Foo) -> @owned Foo
+// CHECK-WMO-NOT: ref_element_addr %{{[0-9]+}} : $Foo, #Foo.Prop1
+// CHECK-WMO-NOT: ref_element_addr %{{[0-9]+}} : $Foo, #Foo.Prop2
+// CHECK-WMO-NOT: ref_element_addr %{{[0-9]+}} : $Foo, #Foo.Prop3
+// CHECK-WMO: ref_element_addr %{{[0-9]+}} : $Foo, #Foo.Prop0
+// CHECK-WMO: ref_element_addr %{{[0-9]+}} : $Foo, #Foo.Prop1
+// CHECK-WMO: ref_element_addr %{{[0-9]+}} : $Foo, #Foo.Prop2
+// CHECK-WMO: ref_element_addr %{{[0-9]+}} : $Foo, #Foo.Prop3
+// CHECK-WMO: return
+
+// CHECK-WMO-LABEL: sil @$S19let_properties_opts3FooC{{[_0-9a-zA-Z]*}}fc : $@convention(method) (Int64, @owned Foo) -> @owned Foo
+// CHECK-WMO-NOT: ref_element_addr %{{[0-9]+}} : $Foo, #Foo.Prop1
+// CHECK-WMO-NOT: ref_element_addr %{{[0-9]+}} : $Foo, #Foo.Prop2
+// CHECK-WMO-NOT: ref_element_addr %{{[0-9]+}} : $Foo, #Foo.Prop3
+// CHECK-WMO: ref_element_addr %{{[0-9]+}} : $Foo, #Foo.Prop0
+// CHECK-WMO: ref_element_addr %{{[0-9]+}} : $Foo, #Foo.Prop1
+// CHECK-WMO: ref_element_addr %{{[0-9]+}} : $Foo, #Foo.Prop2
+// CHECK-WMO: ref_element_addr %{{[0-9]+}} : $Foo, #Foo.Prop3
+// CHECK-WMO: return
+
+// Check that initializers do not contain a code to initialize fileprivate properties, 
+// because their values are propagated into their uses and they cannot be accessed
+// from other modules. Therefore the initialization code could be removed.
+// Specifically, the initialization code for Prop2 can be removed.
+
+// CHECK-LABEL: sil @$S19let_properties_opts3FooC{{[_0-9a-zA-Z]*}}fc : $@convention(method) (Int32, @owned Foo) -> @owned Foo
+// CHECK: ref_element_addr %{{[0-9]+}} : $Foo, #Foo.Prop0
+// CHECK: ref_element_addr %{{[0-9]+}} : $Foo, #Foo.Prop1
+// CHECK: ref_element_addr %{{[0-9]+}} : $Foo, #Foo.Prop2
+// CHECK: ref_element_addr %{{[0-9]+}} : $Foo, #Foo.Prop3
+// CHECK: return
+
+// CHECK-LABEL: sil @$S19let_properties_opts3FooC{{[_0-9a-zA-Z]*}}fc : $@convention(method) (Int64, @owned Foo) -> @owned Foo
+// CHECK: ref_element_addr %{{[0-9]+}} : $Foo, #Foo.Prop0
+// CHECK: ref_element_addr %{{[0-9]+}} : $Foo, #Foo.Prop1
+// CHECK: ref_element_addr %{{[0-9]+}} : $Foo, #Foo.Prop2
+// CHECK: ref_element_addr %{{[0-9]+}} : $Foo, #Foo.Prop3
+// CHECK: return
+
+public class Foo {
+  public let Prop0: Int32 = 1
+  let Prop1: Int32 = 1 + 4/2 + 8
+  fileprivate let Prop2: Int32 = 3*7
+  internal let Prop3: Int32  = 4*8
+  public init(i:Int32) {}  
+  public init(i:Int64) {}
+}
+
+public class Foo1 {
+  let Prop1: Int32
+  fileprivate let Prop2: Int32 = 3*7
+  internal let Prop3: Int32 = 4*8
+  public init(i:Int32) {
+    Prop1  = 11
+  }
+
+  public init(i:Int64) {
+    Prop1  = 1111
+  }
+}
+
+public struct Boo {
+  public let Prop0: Int32 = 1
+  let Prop1: Int32 = 1 + 4/2 + 8  
+  fileprivate let Prop2: Int32 = 3*7
+  internal let Prop3: Int32 = 4*8
+  public init(i:Int32) {}
+  public init(i:Int64) {}
+}
+
+public class Foo2 {
+  internal let x: Int32
+  @inline(never)
+  init(count: Int32) {
+    if count < 2 {
+      x = 5
+    } else {
+      x = 10
+    }
+  }
+}
+
+public class C {}
+
+struct Boo3 {
+  //public 
+  let Prop0: Int32
+  let Prop1: Int32
+  fileprivate let Prop2: Int32
+  internal let Prop3: Int32
+
+  @inline(__always)
+  init(_ f1: C, _ f2: C) {
+    self.Prop0 = 0
+    self.Prop1 = 1
+    self.Prop2 = 2
+    self.Prop3 = 3
+  }
+
+  init(_ v: C) {
+    self.Prop0 = 10
+    self.Prop1 = 11
+    self.Prop2 = 12
+    self.Prop3 = 13
+  }
+}
+
+// The initializer of this struct can be defined elsewhere,
+// e.g. in an extension of this struct in a different module.
+public struct StructWithOnlyPublicLetProperties {
+  public let Prop0: Int32
+  public let Prop1: Int32
+
+  init(_ v: Int32, _ u: Int32) {
+    Prop0 = 10
+    Prop1 = 11
+  }
+}
+
+// The initializer of this struct cannot be defined outside
+// of the current module, because it contains an internal stored
+// property, which is impossible to initialize outside of this module.
+public struct StructWithPublicAndInternalLetProperties {
+  public let Prop0: Int32
+  internal let Prop1: Int32
+
+  init(_ v: Int32, _ u: Int32) {
+    Prop0 = 10
+    Prop1 = 11
+  }
+}
+
+// The initializer of this struct cannot be defined elsewhere,
+// because it contains a fileprivate stored property, which is
+// impossible to initialize outside of this file.
+public struct StructWithPublicAndInternalAndPrivateLetProperties {
+  public let Prop0: Int32
+  internal let Prop1: Int32
+  fileprivate let Prop2: Int32
+
+  init(_ v: Int32, _ u: Int32) {
+    Prop0 = 10
+    Prop1 = 11
+    Prop2 = 12
+  }
+}
+
+
+// Check that Foo1.Prop1 is not constant-folded, because its value is unknown, since it is initialized differently
+// by Foo1 initializers.
+
+// CHECK-LABEL: sil @$S19let_properties_opts13testClassLet1ys5Int32VAA4Foo1CF : $@convention(thin) (@guaranteed Foo1) -> Int32
+// bb0
+// CHECK: ref_element_addr %{{[0-9]+}} : $Foo1, #Foo1.Prop1 
+// CHECK-NOT: ref_element_addr %{{[0-9]+}} : $Foo1, #Foo1.Prop2
+// CHECK-NOT: ref_element_addr %{{[0-9]+}} : $Foo1, #Foo1.Prop3
+// CHECK: return
+public func testClassLet1(_ f: Foo1) -> Int32 {
+  return f.Prop1 + f.Prop2 + f.Prop3
+}
+
+// Check that Foo1.Prop1 is not constant-folded, because its value is unknown, since it is initialized differently
+// by Foo1 initializers.
+
+// CHECK-LABEL: sil @$S19let_properties_opts13testClassLet1ys5Int32VAA4Foo1CzF : $@convention(thin) (@inout Foo1) -> Int32
+// bb0
+// CHECK: ref_element_addr %{{[0-9]+}} : $Foo1, #Foo1.Prop1 
+// CHECK-NOT: ref_element_addr %{{[0-9]+}} : $Foo1, #Foo1.Prop2
+// CHECK-NOT: ref_element_addr %{{[0-9]+}} : $Foo1, #Foo1.Prop3
+// CHECK: return
+public func testClassLet1(_ f: inout Foo1) -> Int32 {
+  return f.Prop1 + f.Prop2 + f.Prop3
+}
+
+// Check that return expressions in all subsequent functions can be constant folded, because the values of let properties
+// are known to be constants of simple types.
+
+// CHECK: sil @$S19let_properties_opts12testClassLetys5Int32VAA3FooCF : $@convention(thin) (@guaranteed Foo) -> Int32
+// CHECK: bb0
+// CHECK: integer_literal $Builtin.Int32, 75
+// CHECK-NEXT: struct $Int32
+// CHECK-NEXT: return
+public func testClassLet(_ f: Foo) -> Int32 {
+  return f.Prop1 + f.Prop1 + f.Prop2 + f.Prop3
+}
+
+// CHECK-LABEL: sil @$S19let_properties_opts12testClassLetys5Int32VAA3FooCzF : $@convention(thin) (@inout Foo) -> Int32
+// CHECK: bb0
+// CHECK: integer_literal $Builtin.Int32, 75
+// CHECK-NEXT: struct $Int32
+// CHECK-NEXT: return
+public func testClassLet(_ f: inout Foo) -> Int32 {
+  return f.Prop1 + f.Prop1 + f.Prop2 + f.Prop3
+}
+
+// CHECK-LABEL: sil @$S19let_properties_opts18testClassPublicLetys5Int32VAA3FooCF : $@convention(thin) (@guaranteed Foo) -> Int32
+// CHECK: bb0
+// CHECK: integer_literal $Builtin.Int32, 1
+// CHECK-NEXT: struct $Int32
+// CHECK-NEXT: return
+public func testClassPublicLet(_ f: Foo) -> Int32 {
+  return f.Prop0
+}
+
+// CHECK-LABEL: sil @$S19let_properties_opts13testStructLetys5Int32VAA3BooVF : $@convention(thin) (Boo) -> Int32
+// CHECK: bb0
+// CHECK: integer_literal $Builtin.Int32, 75
+// CHECK-NEXT: struct $Int32
+// CHECK-NEXT: return
+public func testStructLet(_ b: Boo) -> Int32 {
+  return b.Prop1 + b.Prop1 + b.Prop2 + b.Prop3
+}
+
+// CHECK-LABEL: sil @$S19let_properties_opts13testStructLetys5Int32VAA3BooVzF : $@convention(thin) (@inout Boo) -> Int32
+// CHECK: bb0
+// CHECK: integer_literal $Builtin.Int32, 75
+// CHECK-NEXT: struct $Int32
+// CHECK-NEXT: return
+public func testStructLet(_ b: inout Boo) -> Int32 {
+  return b.Prop1 + b.Prop1 + b.Prop2 + b.Prop3
+}
+
+// CHECK-LABEL: sil @$S19let_properties_opts19testStructPublicLetys5Int32VAA3BooVF : $@convention(thin) (Boo) -> Int32
+// CHECK: bb0
+// CHECK: integer_literal $Builtin.Int32, 1
+// CHECK-NEXT: struct $Int32
+// CHECK-NEXT: return
+public func testStructPublicLet(_ b: Boo) -> Int32 {
+  return b.Prop0
+}
+
+// Check that f.x is not constant folded, because the initializer of Foo2 has multiple
+// assignments to the property x with different values.
+// CHECK-LABEL: sil @$S19let_properties_opts13testClassLet2ys5Int32VAA4Foo2CF : $@convention(thin) (@guaranteed Foo2) -> Int32
+// bb0
+// CHECK: ref_element_addr %{{[0-9]+}} : $Foo2, #Foo2.x
+// CHECK-NOT: ref_element_addr %{{[0-9]+}} : $Foo2, #Foo2.x
+// CHECK-NOT: ref_element_addr %{{[0-9]+}} : $Foo2, #Foo2.x
+// CHECK: return
+public func testClassLet2(_ f: Foo2) -> Int32 {
+  return f.x + f.x
+}
+
+// Check that the sum of properties is not folded into a constant.
+// CHECK-WMO-LABEL: sil hidden [noinline] @$S19let_properties_opts27testStructWithMultipleInitsys5Int32VAA4Boo3V_AFtF : $@convention(thin) (Boo3, Boo3) -> Int32
+// CHECK-WMO: bb0
+// No constant folding should have been performed.
+// CHECK-WMO-NOT: integer_literal $Builtin.Int32, 92
+// CHECK-WMO: struct_extract
+// CHECK-WMO: }
+@inline(never)
+func testStructWithMultipleInits( _ boos1: Boo3, _ boos2: Boo3) -> Int32 {
+  let count1 =  boos1.Prop0 + boos1.Prop1 + boos1.Prop2 + boos1.Prop3
+  let count2 =  boos2.Prop0 + boos2.Prop1 + boos2.Prop2 + boos2.Prop3
+  return count1 + count2
+}
+
+public func testStructWithMultipleInitsAndInlinedInitializer() {
+  let things = [C()]
+  // This line results in inlining of the initializer Boo3(C, C) and later
+  // removal of this initializer by the dead function elimination pass.
+  // As a result, only one initializer, Boo3(C) is seen by the Let Properties Propagation
+  // pass. This pass may think that there is only one initializer and take the
+  // values of let properties assigned there as constants and try to propagate
+  // those values into uses. But this is wrong! The pass should be clever enough
+  // to detect all stores to the let properties, including those outside of
+  // initializers, e.g. inside inlined initializers. And if it detects all such
+  // stores it should understand that values of let properties in Boo3 are not
+  // statically known constant initializers with the same value and thus
+  // cannot be propagated.
+  let boos1 = things.map { Boo3($0, C()) }
+  let boos2 = things.map(Boo3.init)
+  print(testStructWithMultipleInits(boos1[0], boos2[0]))
+}
+
+// Since all properties are public, they can be initialized in a
+// different module.
+// Their values are not known and cannot be propagated.
+
+// CHECK-LABEL: sil @$S19let_properties_opts31testStructPropertyAccessibilityys5Int32VAA0E27WithOnlyPublicLetPropertiesVF
+// CHECK: struct_extract %0 : $StructWithOnlyPublicLetProperties, #StructWithOnlyPublicLetProperties.Prop0
+// CHECK: return
+
+// CHECK-WMO-LABEL: sil @$S19let_properties_opts31testStructPropertyAccessibilityys5Int32VAA0E27WithOnlyPublicLetPropertiesVF
+// CHECK-WMO: struct_extract %0 : $StructWithOnlyPublicLetProperties, #StructWithOnlyPublicLetProperties.Prop0
+// CHECK-WMO: return
+public func testStructPropertyAccessibility(_ b: StructWithOnlyPublicLetProperties) -> Int32 {
+  return b.Prop0 + b.Prop1
+}
+
+// Properties can be initialized in a different file in the same module.
+// Their values are not known and cannot be propagated,
+// unless it is a WMO compilation.
+
+// CHECK-LABEL: sil @$S19let_properties_opts31testStructPropertyAccessibilityys5Int32VAA0E34WithPublicAndInternalLetPropertiesVF
+// CHECK: struct_extract %0 : $StructWithPublicAndInternalLetProperties, #StructWithPublicAndInternalLetProperties.Prop0
+// CHECK-NOT: integer_literal $Builtin.Int32, 21
+// CHECK: return
+
+// CHECK-WMO-LABEL: sil @$S19let_properties_opts31testStructPropertyAccessibilityys5Int32VAA0E34WithPublicAndInternalLetPropertiesVF
+// CHECK-WMO: integer_literal $Builtin.Int32, 21
+// CHECK-WMO-NEXT: struct $Int32
+// CHECK-WMO-NEXT: return
+public func testStructPropertyAccessibility(_ b: StructWithPublicAndInternalLetProperties) -> Int32 {
+  return b.Prop0 + b.Prop1
+}
+
+// Properties can be initialized only in this file, because one of the
+// properties is fileprivate.
+// Therefore their values are known and can be propagated.
+
+// CHECK: sil @$S19let_properties_opts31testStructPropertyAccessibilityys5Int32VAA0e21WithPublicAndInternalK20PrivateLetPropertiesVF
+// CHECK: integer_literal $Builtin.Int32, 33
+// CHECK-NEXT: struct $Int32
+// CHECK-NEXT: return
+
+// CHECK-WMO-LABEL: sil @$S19let_properties_opts31testStructPropertyAccessibilityys5Int32VAA0e21WithPublicAndInternalK20PrivateLetPropertiesVF
+// CHECK-WMO: integer_literal $Builtin.Int32, 33
+// CHECK-WMO-NEXT: struct $Int32
+// CHECK-WMO-NEXT: return
+public func testStructPropertyAccessibility(_ b: StructWithPublicAndInternalAndPrivateLetProperties) -> Int32 {
+  return b.Prop0 + b.Prop1 + b.Prop2
+}
+
+// Force use of initializers, otherwise they got removed by the dead-function-elimination pass
+// and the values of let properties cannot be determined.
+public func useInitializers() -> StructWithOnlyPublicLetProperties {
+  return StructWithOnlyPublicLetProperties(1, 1)
+}
+
+public func useInitializers() -> StructWithPublicAndInternalLetProperties {
+  return StructWithPublicAndInternalLetProperties(1, 1)
+}
+
+public func useInitializers() -> StructWithPublicAndInternalAndPrivateLetProperties {
+  return StructWithPublicAndInternalAndPrivateLetProperties(1, 1)
+}
diff --git a/test/SILOptimizer/plus_zero_mandatory_inlining.swift b/test/SILOptimizer/plus_zero_mandatory_inlining.swift
new file mode 100644
index 0000000..3dec6cb
--- /dev/null
+++ b/test/SILOptimizer/plus_zero_mandatory_inlining.swift
@@ -0,0 +1,177 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -enable-sil-ownership -sil-verify-all -primary-file %s -emit-sil -o - -verify | %FileCheck %s
+
+// These tests are deliberately shallow, because I do not want to depend on the
+// specifics of SIL generation, which might change for reasons unrelated to this
+// pass
+
+func foo(_ x: Float) -> Float {
+  return bar(x);
+}
+
+// CHECK-LABEL: sil hidden @$S18mandatory_inlining3foo{{[_0-9a-zA-Z]*}}F
+// CHECK: bb0(%0 : $Float):
+// CHECK-NEXT: debug_value %0 : $Float, let, name "x"
+// CHECK-NEXT: return %0
+
+@_transparent func bar(_ x: Float) -> Float {
+  return baz(x)
+}
+
+// CHECK-LABEL: sil hidden [transparent] @$S18mandatory_inlining3bar{{[_0-9a-zA-Z]*}}F
+  // CHECK-NOT: function_ref
+  // CHECK-NOT: apply
+  // CHECK: return
+
+@_transparent func baz(_ x: Float) -> Float {
+  return x
+}
+
+// CHECK-LABEL: sil hidden [transparent] @$S18mandatory_inlining3baz{{[_0-9a-zA-Z]*}}F
+// CHECK: return
+
+func spam(_ x: Int) -> Int {
+  return x
+}
+
+// CHECK-LABEL: sil hidden @$S18mandatory_inlining4spam{{[_0-9a-zA-Z]*}}F
+
+@_transparent func ham(_ x: Int) -> Int {
+  return spam(x)
+}
+
+// CHECK-LABEL: sil hidden [transparent] @$S18mandatory_inlining3ham{{[_0-9a-zA-Z]*}}F
+  // CHECK: function_ref @$S18mandatory_inlining4spam{{[_0-9a-zA-Z]*}}F
+  // CHECK: apply
+  // CHECK: return
+
+func eggs(_ x: Int) -> Int {
+  return ham(x)
+}
+
+// CHECK-LABEL: sil hidden @$S18mandatory_inlining4eggs{{[_0-9a-zA-Z]*}}F
+  // CHECK: function_ref @$S18mandatory_inlining4spam{{[_0-9a-zA-Z]*}}F
+  // CHECK: apply
+  // CHECK: return
+
+@_transparent func call_auto_closure(_ x: @autoclosure () -> Bool) -> Bool {
+  return x()
+}
+
+func test_auto_closure_with_capture(_ x: Bool) -> Bool {
+  return call_auto_closure(x)
+}
+
+// This should be fully inlined and simply return x; however, there's a lot of
+// non-SSA cruft that I don't want this test to depend on, so I'm just going
+// to verify that it doesn't have any function applications left
+
+// CHECK-LABEL: sil hidden @{{.*}}test_auto_closure_with_capture
+  // CHECK-NOT: = apply
+  // CHECK: return
+
+func test_auto_closure_without_capture() -> Bool {
+  return call_auto_closure(false)
+}
+
+// This should be fully inlined and simply return false, which is easier to check for
+
+// CHECK-LABEL: sil hidden @$S18mandatory_inlining33test_auto_closure_without_captureSbyF
+  // CHECK: [[FV:%.*]] = integer_literal $Builtin.Int1, 0
+  // CHECK: [[FALSE:%.*]] = struct $Bool ([[FV:%.*]] : $Builtin.Int1)
+  // CHECK: return [[FALSE]]
+
+infix operator &&& : LogicalConjunctionPrecedence
+infix operator ||| : LogicalDisjunctionPrecedence
+
+@_transparent func &&& (lhs: Bool, rhs: @autoclosure () -> Bool) -> Bool {
+  if lhs {
+    return rhs()
+  }
+
+  return false
+}
+
+@_transparent func ||| (lhs: Bool, rhs: @autoclosure () -> Bool) -> Bool {
+  if lhs {
+    return true
+  }
+
+  return rhs()
+}
+
+func test_chained_short_circuit(_ x: Bool, y: Bool, z: Bool) -> Bool {
+  return x &&& (y ||| z)
+}
+
+// The test below just makes sure there are no uninlined [transparent] calls
+// left (i.e. the autoclosure and the short-circuiting boolean operators are
+// recursively inlined properly)
+
+// CHECK-LABEL: sil hidden @$S18mandatory_inlining26test_chained_short_circuit{{[_0-9a-zA-Z]*}}F
+  // CHECK-NOT: = apply [transparent]
+  // CHECK: return
+
+
+// Union element constructors should be inlined automatically.
+enum X {
+  case onetransp
+  case twotransp
+}
+
+func testInlineUnionElement() -> X {
+  return X.onetransp
+  // CHECK-LABEL: sil hidden @$S18mandatory_inlining22testInlineUnionElementAA1XOyF
+  // CHECK: enum $X, #X.onetransp!enumelt
+  // CHECK-NOT: = apply
+  // CHECK: return
+}
+
+
+
+@_transparent
+func call_let_auto_closure(_ x: @autoclosure () -> Bool) -> Bool {
+  return x()
+}
+
+// CHECK-LABEL: sil hidden @{{.*}}test_let_auto_closure_with_value_capture
+// CHECK: bb0(%0 : $Bool):
+// CHECK-NEXT: debug_value %0 : $Bool
+// CHECK-NEXT: return %0 : $Bool
+// CHECK-LABEL: // end sil function '{{.*}}test_let_auto_closure_with_value_capture
+func test_let_auto_closure_with_value_capture(_ x: Bool) -> Bool {
+  return call_let_auto_closure(x)
+}
+
+
+class C {}
+
+// CHECK-LABEL: sil hidden [transparent] @$S18mandatory_inlining25class_constrained_generic{{[_0-9a-zA-Z]*}}F
+@_transparent
+func class_constrained_generic<T : C>(_ o: T) -> AnyClass? {
+  // CHECK: return
+  return T.self
+}
+
+// CHECK-LABEL: sil hidden @$S18mandatory_inlining6invokeyyAA1CCF : $@convention(thin) (@guaranteed C) -> () {
+func invoke(_ c: C) {
+  // CHECK-NOT: function_ref @$S18mandatory_inlining25class_constrained_generic{{[_0-9a-zA-Z]*}}F
+  // CHECK-NOT: apply
+  // CHECK: init_existential_metatype
+  _ = class_constrained_generic(c)
+  // CHECK: return
+}
+
+// Make sure we don't crash.
+@_transparent
+public func mydo(_ what: @autoclosure () -> ()) {
+  what()
+}
+public class A {
+  public func bar() {}
+  public func foo(_ act: (@escaping () ->()) -> ()) {
+    act { [unowned self] in
+      mydo( self.bar() )
+    }
+  }
+}
diff --git a/test/SILOptimizer/plus_zero_performance_inliner.sil b/test/SILOptimizer/plus_zero_performance_inliner.sil
new file mode 100644
index 0000000..e19b0c9
--- /dev/null
+++ b/test/SILOptimizer/plus_zero_performance_inliner.sil
@@ -0,0 +1,972 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil -enable-sil-verify-all %s -inline -sil-combine | %FileCheck %s
+
+sil_stage canonical
+
+import Builtin
+import Swift
+
+/////////////////////
+// Inlining Tests //
+/////////////////////
+
+// *NOTE* These tests currently validate whether or not we
+// visit nodes in the correct order since we do not explore inlined
+// code for more apply inst to inline. After that point, we will
+// probably need to do one of the following:
+//
+// 1. Introduce a flag to turn off the exploration behavior.
+// 2. Introduce some sort of debug output that displays the callgraph
+//    traversal order.
+
+// Node -> Node
+
+sil @test1_multiply_leaf : $@convention(thin) (Builtin.Int64) -> Builtin.Int64 {
+bb0(%0 : $Builtin.Int64):
+  %2 = integer_literal $Builtin.Int1, 0
+  %3 = builtin "umul_with_overflow_Int64"(%0 : $Builtin.Int64, %0 : $Builtin.Int64, %2 : $Builtin.Int1) : $(Builtin.Int64, Builtin.Int1)
+  %4 = tuple_extract %3 : $(Builtin.Int64, Builtin.Int1), 0
+  return %4: $Builtin.Int64
+}
+
+// CHECK-LABEL: sil @test1
+// CHECK: bb0([[INPUT:%[0-9]+]] : $Builtin.Int64)
+// CHECK: integer_literal $Builtin.Int1, 0
+// CHECK: [[MUL_TUPLE_RESULT:%[0-9]+]] = builtin "umul_with_overflow_Int64"([[INPUT]] : {{.*}}, [[INPUT]]
+// CHECK: [[MUL_RESULT:%[0-9]+]] = tuple_extract [[MUL_TUPLE_RESULT]]
+// CHECK: return [[MUL_RESULT]]
+sil @test1 : $@convention(thin) (Builtin.Int64) -> Builtin.Int64 {
+bb0(%0 : $Builtin.Int64):
+  %1 = function_ref @test1_multiply_leaf : $@convention(thin) (Builtin.Int64) -> (Builtin.Int64)
+  %2 = apply %1 (%0) : $@convention(thin) (Builtin.Int64) -> (Builtin.Int64)
+  return %2 : $Builtin.Int64
+}
+
+//      Node
+//     /    \
+//    v      v
+//  Node -> Node
+
+// CHECK-LABEL: sil @test2_add_leaf
+
+sil @test2_add_leaf : $@convention(thin) (Builtin.Int64) -> Builtin.Int64 {
+bb0(%0 : $Builtin.Int64):
+  %2 = integer_literal $Builtin.Int1, 0
+  %3 = builtin "uadd_with_overflow_Int64"(%0 : $Builtin.Int64, %0 : $Builtin.Int64, %2 : $Builtin.Int1) : $(Builtin.Int64, Builtin.Int1)
+  %4 = tuple_extract %3 : $(Builtin.Int64, Builtin.Int1), 0
+  return %4: $Builtin.Int64
+}
+
+sil @test2_multiply_leaf : $@convention(thin) (Builtin.Int64) -> Builtin.Int64 {
+bb0(%0 : $Builtin.Int64):
+  %2 = integer_literal $Builtin.Int1, 0
+  %3 = builtin "umul_with_overflow_Int64"(%0 : $Builtin.Int64, %0 : $Builtin.Int64, %2 : $Builtin.Int1) : $(Builtin.Int64, Builtin.Int1)
+  %4 = tuple_extract %3 : $(Builtin.Int64, Builtin.Int1), 0
+  return %4: $Builtin.Int64
+}
+
+sil @test2_add_then_multiply : $@convention(thin) (Builtin.Int64) -> Builtin.Int64 {
+bb0(%0 : $Builtin.Int64):
+  %1 = function_ref @test2_add_leaf : $@convention(thin) (Builtin.Int64) -> Builtin.Int64
+  %2 = apply %1(%0) : $@convention(thin) (Builtin.Int64) -> Builtin.Int64
+  %3 = function_ref @test2_multiply_leaf : $@convention(thin) (Builtin.Int64) -> Builtin.Int64
+  %4 = apply %3(%2) : $@convention(thin) (Builtin.Int64) -> Builtin.Int64
+  return %4 : $Builtin.Int64
+}
+
+// CHECK-LABEL: sil @test2 : $@convention(thin) (Builtin.Int64) -> Builtin.Int64 {
+// bb0([[INPUT:%[0-9]+]] : $Builtin.Int64):
+// CHECK: [[UADD_RESULT_TUPLE:%[0-9]+]] = builtin "uadd_with_overflow_Int64"([[INPUT]] : {{.*}}, [[INPUT]]
+// CHECK: [[UADD_RESULT:%[0-9]+]] = tuple_extract [[UADD_RESULT_TUPLE]] : $(Builtin.Int64, Builtin.Int1), 0
+// CHECK: [[UADD_RESULT_TUPLE2:%[0-9]+]] = builtin "uadd_with_overflow_Int64"([[UADD_RESULT]] : {{.*}}, [[UADD_RESULT]]
+// CHECK: [[UADD_RESULT2:%[0-9]+]] = tuple_extract [[UADD_RESULT_TUPLE2]]
+// CHECK: [[UMUL_RESULT_TUPLE:%[0-9]+]] = builtin "umul_with_overflow_Int64"([[UADD_RESULT2]] : {{.*}}, [[UADD_RESULT2]]
+// CHECK: [[UMUL_RESULT:%[0-9]+]] = tuple_extract [[UMUL_RESULT_TUPLE]]
+// CHECK: return [[UMUL_RESULT]] : $Builtin.Int64
+sil @test2 : $@convention(thin) (Builtin.Int64) -> Builtin.Int64 {
+bb0(%0 : $Builtin.Int64):
+  %1 = function_ref @test2_add_leaf: $@convention(thin) (Builtin.Int64) -> (Builtin.Int64)
+  %2 = apply %1 (%0) : $@convention(thin) (Builtin.Int64) -> (Builtin.Int64)
+  %3 = function_ref @test2_add_then_multiply : $@convention(thin) (Builtin.Int64) -> (Builtin.Int64)
+  %4 = apply %3 (%2) : $@convention(thin) (Builtin.Int64) -> (Builtin.Int64)
+  return %4 : $Builtin.Int64
+}
+
+//      Node
+//     /    \
+//    v      v
+//  Node    Node
+//    \      /
+//     v    v
+//      Node
+
+// CHECK-LABEL: sil @test3_add_leaf
+
+sil @test3_add_leaf : $@convention(thin) (Builtin.Int64) -> Builtin.Int64 {
+bb0(%0 : $Builtin.Int64):
+  %2 = integer_literal $Builtin.Int1, 0
+  %3 = builtin "uadd_with_overflow_Int64"(%0 : $Builtin.Int64, %0 : $Builtin.Int64, %2 : $Builtin.Int1) : $(Builtin.Int64, Builtin.Int1)
+  %4 = tuple_extract %3 : $(Builtin.Int64, Builtin.Int1), 0
+  return %4: $Builtin.Int64
+}
+
+sil @test3_sub_leaf : $@convention(thin) (Builtin.Int64) -> Builtin.Int64 {
+bb0(%0 : $Builtin.Int64):
+  %1 = integer_literal $Builtin.Int64, 1
+  %2 = integer_literal $Builtin.Int1, 0
+  %3 = builtin "usub_with_overflow_Int64"(%0 : $Builtin.Int64, %1 : $Builtin.Int64, %2 : $Builtin.Int1) : $(Builtin.Int64, Builtin.Int1)
+  %4 = tuple_extract %3 : $(Builtin.Int64, Builtin.Int1), 0
+  return %4: $Builtin.Int64
+}
+
+sil @test3_multiply_leaf : $@convention(thin) (Builtin.Int64) -> Builtin.Int64 {
+bb0(%0 : $Builtin.Int64):
+  %2 = integer_literal $Builtin.Int1, 0
+  %3 = builtin "umul_with_overflow_Int64"(%0 : $Builtin.Int64, %0 : $Builtin.Int64, %2 : $Builtin.Int1) : $(Builtin.Int64, Builtin.Int1)
+  %4 = tuple_extract %3 : $(Builtin.Int64, Builtin.Int1), 0
+  return %4: $Builtin.Int64
+}
+
+sil @test3_add_then_multiply : $@convention(thin) (Builtin.Int64) -> Builtin.Int64 {
+bb0(%0 : $Builtin.Int64):
+  %1 = function_ref @test3_add_leaf : $@convention(thin) (Builtin.Int64) -> Builtin.Int64
+  %2 = apply %1(%0) : $@convention(thin) (Builtin.Int64) -> Builtin.Int64
+  %3 = function_ref @test3_multiply_leaf : $@convention(thin) (Builtin.Int64) -> Builtin.Int64
+  %4 = apply %3(%2) : $@convention(thin) (Builtin.Int64) -> Builtin.Int64
+  return %4 : $Builtin.Int64
+}
+
+sil @test3_sub_then_multiply : $@convention(thin) (Builtin.Int64) -> Builtin.Int64 {
+bb0(%0 : $Builtin.Int64):
+  %1 = function_ref @test3_sub_leaf : $@convention(thin) (Builtin.Int64) -> Builtin.Int64
+  %2 = apply %1(%0) : $@convention(thin) (Builtin.Int64) -> Builtin.Int64
+  %3 = function_ref @test3_multiply_leaf : $@convention(thin) (Builtin.Int64) -> Builtin.Int64
+  %4 = apply %3(%2) : $@convention(thin) (Builtin.Int64) -> Builtin.Int64
+  return %4 : $Builtin.Int64
+}
+
+// CHECK-LABEL: sil @test3 : $@convention(thin) (Builtin.Int64) -> Builtin.Int64
+// CHECK: bb0([[INPUT:%[0-9]+]] : $Builtin.Int64):
+// CHECK: [[LITERAL1:%[0-9]+]] = integer_literal {{.*}}, 1
+// CHECK: [[USUB_RESULT_TUPLE:%[0-9]+]] = builtin "usub_with_overflow_Int64"([[INPUT]] : {{.*}}, [[LITERAL1]] : {{.*}}
+// CHECK: [[USUB_RESULT:%[0-9]+]] = tuple_extract [[USUB_RESULT_TUPLE]]
+// CHECK: [[UMUL_RESULT_TUPLE:%[0-9]+]] = builtin "umul_with_overflow_Int64"([[USUB_RESULT]] : {{.*}}, [[USUB_RESULT]]
+// CHECK: [[UMUL_RESULT:%[0-9]+]] = tuple_extract [[UMUL_RESULT_TUPLE]]
+// CHECK: [[UADD_RESULT_TUPLE:%[0-9]+]] = builtin "uadd_with_overflow_Int64"([[UMUL_RESULT]] : {{.*}}, [[UMUL_RESULT]]
+// CHECK: [[UADD_RESULT:%[0-9]+]] = tuple_extract [[UADD_RESULT_TUPLE]]
+// CHECK: [[UMUL_RESULT_TUPLE2:%[0-9]+]] = builtin "umul_with_overflow_Int64"([[UADD_RESULT]] : {{.*}}, [[UADD_RESULT]]
+// CHECK: [[UMUL_RESULT:%[0-9]+]] = tuple_extract [[UMUL_RESULT_TUPLE2]]
+// CHECK: return [[UMUL_RESULT]]
+sil @test3 : $@convention(thin) (Builtin.Int64) -> Builtin.Int64 {
+bb0(%0 : $Builtin.Int64):
+  %1 = function_ref @test3_sub_then_multiply : $@convention(thin) (Builtin.Int64) -> (Builtin.Int64)
+  %2 = apply %1 (%0) : $@convention(thin) (Builtin.Int64) -> (Builtin.Int64)
+  %3 = function_ref @test3_add_then_multiply : $@convention(thin) (Builtin.Int64) -> (Builtin.Int64)
+  %4 = apply %3 (%2) : $@convention(thin) (Builtin.Int64) -> (Builtin.Int64)
+  return %4 : $Builtin.Int64
+}
+
+//      Node
+//     /    \
+//    v      v
+//  Node -> Node
+//    \      /
+//     v    v
+//       Node
+
+// CHECK-LABEL: sil @test4_add_leaf
+
+sil @test4_add_leaf : $@convention(thin) (Builtin.Int64) -> Builtin.Int64 {
+bb0(%0 : $Builtin.Int64):
+  %2 = integer_literal $Builtin.Int1, 0
+  %3 = builtin "uadd_with_overflow_Int64"(%0 : $Builtin.Int64, %0 : $Builtin.Int64, %2 : $Builtin.Int1) : $(Builtin.Int64, Builtin.Int1)
+  %4 = tuple_extract %3 : $(Builtin.Int64, Builtin.Int1), 0
+  return %4: $Builtin.Int64
+}
+
+sil @test4_sub_leaf : $@convention(thin) (Builtin.Int64) -> Builtin.Int64 {
+bb0(%0 : $Builtin.Int64):
+  %2 = integer_literal $Builtin.Int1, 0
+  %3 = builtin "usub_with_overflow_Int64"(%0 : $Builtin.Int64, %0 : $Builtin.Int64, %2 : $Builtin.Int1) : $(Builtin.Int64, Builtin.Int1)
+  %4 = tuple_extract %3 : $(Builtin.Int64, Builtin.Int1), 0
+  return %4: $Builtin.Int64
+}
+
+sil @test4_multiply_leaf : $@convention(thin) (Builtin.Int64) -> Builtin.Int64 {
+bb0(%0 : $Builtin.Int64):
+  %2 = integer_literal $Builtin.Int1, 0
+  %3 = builtin "umul_with_overflow_Int64"(%0 : $Builtin.Int64, %0 : $Builtin.Int64, %2 : $Builtin.Int1) : $(Builtin.Int64, Builtin.Int1)
+  %4 = tuple_extract %3 : $(Builtin.Int64, Builtin.Int1), 0
+  return %4: $Builtin.Int64
+}
+
+sil @test4_add_then_multiply : $@convention(thin) (Builtin.Int64) -> Builtin.Int64 {
+bb0(%0 : $Builtin.Int64):
+  %1 = function_ref @test4_add_leaf : $@convention(thin) (Builtin.Int64) -> Builtin.Int64
+  %2 = apply %1(%0) : $@convention(thin) (Builtin.Int64) -> Builtin.Int64
+  %3 = function_ref @test4_multiply_leaf : $@convention(thin) (Builtin.Int64) -> Builtin.Int64
+  %4 = apply %3(%2) : $@convention(thin) (Builtin.Int64) -> Builtin.Int64
+  return %4 : $Builtin.Int64
+}
+
+sil @test4_add_then_multiply_then_multiply : $@convention(thin) (Builtin.Int64) -> Builtin.Int64 {
+bb0(%0 : $Builtin.Int64):
+  %1 = function_ref @test4_add_then_multiply : $@convention(thin) (Builtin.Int64) -> Builtin.Int64
+  %2 = apply %1(%0) : $@convention(thin) (Builtin.Int64) -> Builtin.Int64
+  %3 = function_ref @test4_multiply_leaf : $@convention(thin) (Builtin.Int64) -> Builtin.Int64
+  %4 = apply %3(%2) : $@convention(thin) (Builtin.Int64) -> Builtin.Int64
+  return %4 : $Builtin.Int64
+}
+
+// CHECK-LABEL: sil @test4 : $@convention(thin) (Builtin.Int64) -> Builtin.Int64
+// CHECK: bb0([[INPUT:%[0-9]+]] : $Builtin.Int64):
+// CHECK: [[UADD_RESULT_TUPLE:%[0-9]+]] = builtin "uadd_with_overflow_Int64"([[INPUT]] : {{.*}}, [[INPUT]]
+// CHECK: [[UADD_RESULT:%[0-9]+]] = tuple_extract [[UADD_RESULT_TUPLE]]
+// CHECK: [[UMUL_RESULT_TUPLE:%[0-9]+]] = builtin "umul_with_overflow_Int64"([[UADD_RESULT]] : {{.*}}, [[UADD_RESULT]]
+// CHECK: [[UMUL_RESULT:%[0-9]+]] = tuple_extract [[UMUL_RESULT_TUPLE]]
+
+// CHECK: [[UADD_RESULT_TUPLE2:%[0-9]+]] = builtin "uadd_with_overflow_Int64"([[UMUL_RESULT]] : {{.*}}, [[UMUL_RESULT]]
+// CHECK: [[UADD_RESULT2:%[0-9]+]] = tuple_extract [[UADD_RESULT_TUPLE2]]
+// CHECK: [[UMUL_RESULT_TUPLE2:%[0-9]+]] = builtin "umul_with_overflow_Int64"([[UADD_RESULT2]] : {{.*}}, [[UADD_RESULT2]]
+// CHECK: [[UMUL_RESULT2:%[0-9]+]] = tuple_extract [[UMUL_RESULT_TUPLE2]]
+
+// CHECK: [[UMUL_RESULT_TUPLE3:%[0-9]+]] = builtin "umul_with_overflow_Int64"([[UMUL_RESULT2]] : {{.*}}, [[UMUL_RESULT2]]
+// CHECK: [[UMUL_RESULT3:%[0-9]+]] = tuple_extract [[UMUL_RESULT_TUPLE3]]
+// CHECK: return [[UMUL_RESULT3]] : $Builtin.Int64
+sil @test4 : $@convention(thin) (Builtin.Int64) -> Builtin.Int64 {
+bb0(%0 : $Builtin.Int64):
+  %1 = function_ref @test4_add_then_multiply : $@convention(thin) (Builtin.Int64) -> (Builtin.Int64)
+  %2 = apply %1 (%0) : $@convention(thin) (Builtin.Int64) -> (Builtin.Int64)
+  %3 = function_ref @test4_add_then_multiply_then_multiply : $@convention(thin) (Builtin.Int64) -> (Builtin.Int64)
+  %4 = apply %3 (%2) : $@convention(thin) (Builtin.Int64) -> (Builtin.Int64)
+  return %4 : $Builtin.Int64
+}
+
+// Circular Inline.
+
+// CHECK-LABEL: sil @test5
+// CHECK: bb0([[INPUT:%[0-9]+]] : $Builtin.Int64):
+// CHECK: [[FUN:%[0-9]+]] = function_ref @test5 : $@convention(thin) (Builtin.Int64) -> Builtin.Int64
+// CHECK: [[FUN_RESULT:%[0-9]+]] = apply [[FUN]]([[INPUT]]) : $@convention(thin) (Builtin.Int64) -> Builtin.Int64
+// CHECK: return [[FUN_RESULT]] : $Builtin.Int64
+sil @test5 : $@convention(thin) (Builtin.Int64) -> Builtin.Int64 {
+bb0(%0 : $Builtin.Int64):
+  %1 = function_ref @test5 : $@convention(thin) (Builtin.Int64) -> Builtin.Int64
+  %2 = apply %1(%0) : $@convention(thin) (Builtin.Int64) -> Builtin.Int64
+  return %2 : $Builtin.Int64
+}
+
+//////////////////////
+// Apply Type Tests //
+//////////////////////
+
+// CHECK-LABEL: sil @generic_function
+sil @generic_function : $@convention(thin) <T> (@in T, @in T) -> Builtin.Int8 {
+bb0(%0 : $*T, %1 : $*T):
+  %2 = integer_literal $Builtin.Int8, 2
+  return %2 : $Builtin.Int8
+}
+
+// IGNORE-THIS-CHECK-LABEL: sil @ignore_applies_with_substitutions
+
+// We can't deserialize apply_inst with subst lists. When radar://14443304
+// is fixed then we should uncomment this test.
+
+// sil @ignore_applies_with_substitutions : $@convention(thin) (Builtin.Int64) -> Builtin.Int8 {
+// bb0(%0 : $Builtin.Int64):
+//   %1 = function_ref @generic_function : $@convention(thin) <T> (@in T, @in T) -> Builtin.Int8
+//   %2 = apply %1<T = Builtin.Int64>(%0, %0) : $@convention(thin) <T> (@in T, @in T) -> Builtin.Int8
+//   return %2 : $Builtin.Int8
+// }
+
+// CHECK-LABEL: sil @trivial_fun
+
+sil @trivial_fun : $@convention(thin) () -> (Builtin.Int64) {
+  %0 = integer_literal $Builtin.Int64, 32
+  return %0 : $Builtin.Int64
+}
+
+protocol P {}
+extension Int64: P {}
+
+// We can inline function_refs with witness_method calling convention.
+sil @trivial_witness_method : $@convention(witness_method: P) (@inout Int64) -> Int64 {
+bb0(%0 : $*Int64):
+  %1 = load %0 : $*Int64
+  return %1 : $Int64
+}
+
+// CHECK-LABEL: sil @trivial_witness_method_caller : $@convention(thin) () -> ()
+// CHECK-NOT: apply .*@convention(witness_method
+// CHECK: return
+sil @trivial_witness_method_caller : $@convention(thin) () -> () {
+  %0 = alloc_box ${ var Int64 }, var, name "x"
+  %1 = project_box %0 : ${ var Int64 }, 0
+  %2 = function_ref @$Ss5Int64V22_builtinIntegerLiteralABBi2048__tcfC : $@convention(method) (Builtin.Int2048, @thin Int64.Type) -> Int64 // user: %5
+  %3 = metatype $@thin Int64.Type
+  %4 = integer_literal $Builtin.Int2048, 0
+  %5 = apply %2(%4, %3) : $@convention(method) (Builtin.Int2048, @thin Int64.Type) -> Int64
+  store %5 to %1 : $*Int64
+  %6 = function_ref @trivial_witness_method : $@convention(witness_method: P) (@inout Int64) -> Int64
+  %7 = apply %6 (%1) : $@convention(witness_method: P) (@inout Int64) -> Int64
+  %8 = tuple()
+  return %8 : $()
+}
+
+// Int64.init(_builtinIntegerLiteral:)
+sil [transparent] [serialized] @$Ss5Int64V22_builtinIntegerLiteralABBi2048__tcfC : $@convention(method) (Builtin.Int2048, @thin Int64.Type) -> Int64
+
+
+// We can inline function_refs with c calling convention.
+sil @trivial_c : $@convention(c) (@inout Builtin.Int64) -> Builtin.Int64 {
+bb0(%0 : $*Builtin.Int64):
+  %1 = load %0 : $*Builtin.Int64
+  return %1 : $Builtin.Int64
+}
+
+// CHECK-LABEL: sil @trivial_c_caller : $@convention(thin) () -> ()
+// CHECK-NOT: apply
+// CHECK: return
+sil @trivial_c_caller : $@convention(thin) () -> () {
+  %0 = alloc_stack $Builtin.Int64
+  %1 = integer_literal $Builtin.Int64, 0
+  store %1 to %0 : $*Builtin.Int64
+  %2 = function_ref @trivial_c : $@convention(c) (@inout Builtin.Int64) -> Builtin.Int64
+  apply %2 (%0) : $@convention(c) (@inout Builtin.Int64) -> Builtin.Int64
+  dealloc_stack %0 : $*Builtin.Int64
+  %3 = tuple()
+  return %3 : $()
+}
+
+// We can inline function_refs with objc_method calling convention.
+//
+// ObjC calls are unable to be devirtualized since at runtime the call
+// could change. But there is no reason in principal why we could not
+// (if there existed something like sealed classes in objc perhaps?),
+// inline a function_ref to such a call.
+sil @trivial_objc : $@convention(objc_method) (@inout Builtin.Int64) -> Builtin.Int64 {
+bb0(%0 : $*Builtin.Int64):
+  %1 = load %0 : $*Builtin.Int64
+  return %1 : $Builtin.Int64
+}
+
+// CHECK-LABEL: sil @trivial_objc_caller : $@convention(thin) () -> ()
+// CHECK-NOT: apply
+// CHECK: return
+sil @trivial_objc_caller : $@convention(thin) () -> () {
+  %0 = alloc_stack $Builtin.Int64
+  %1 = integer_literal $Builtin.Int64, 0
+  store %1 to %0 : $*Builtin.Int64
+  %2 = function_ref @trivial_objc : $@convention(objc_method) (@inout Builtin.Int64) -> Builtin.Int64
+  apply %2 (%0) : $@convention(objc_method) (@inout Builtin.Int64) -> Builtin.Int64
+  dealloc_stack %0 : $*Builtin.Int64
+  %3 = tuple()
+  return %3 : $()
+}
+
+//////////
+// Misc //
+//////////
+
+// Make sure SILCloner does not get into an infinite loop here.
+sil @_TFsoi1xFT3lhsVs5UWord3rhsS__S_ : $@convention(thin) (UInt32, UInt32) -> UInt32 {
+bb0(%0 : $UInt32, %1 : $UInt32):
+  %3 = struct_extract %0 : $UInt32, #UInt32._value   // user: %5
+  %4 = struct_extract %1 : $UInt32, #UInt32._value   // user: %5
+  %5 = builtin "xor_Int32"(%3 : $Builtin.Int32, %4 : $Builtin.Int32) : $Builtin.Int32 // user: %6
+  %6 = struct $UInt32 (%5 : $Builtin.Int32)         // user: %7
+  return %6 : $UInt32                               // id: %7
+}
+
+sil @_TFsop1tFT1aVs5UWord_S_ : $@convention(thin) (UInt32) -> UInt32 {
+bb0(%0 : $UInt32):
+  // function_ref Swift.^ [infix] (lhs : Swift.UInt32, rhs : Swift.UInt32) -> Swift.UInt32
+  %1 = function_ref @_TFsoi1xFT3lhsVs5UWord3rhsS__S_ : $@convention(thin) (UInt32, UInt32) -> UInt32 // user: %6
+  // function_ref Swift.~ [prefix] (a : Swift.UInt32) -> Swift.UInt32
+  %2 = function_ref @_TFsop1tFT1aVs5UWord_S_ : $@convention(thin) (UInt32) -> UInt32 // user: %5
+  %3 = integer_literal $Builtin.Int32, 0            // user: %4
+  %4 = struct $UInt32 (%3 : $Builtin.Int32)         // user: %5
+  %5 = apply %2(%4) : $@convention(thin) (UInt32) -> UInt32     // user: %6
+  %6 = apply %1(%0, %5) : $@convention(thin) (UInt32, UInt32) -> UInt32 // user: %7
+  return %6 : $UInt32                               // id: %7
+}
+
+// Transparent function may inline private functions.
+//
+sil private @private_ret_undef : $@convention(thin) () -> () {
+entry:
+  return undef : $()
+}
+
+sil @uses_private : $@convention(thin) () -> () {
+entry:
+  %f = function_ref @private_ret_undef : $@convention(thin) () -> ()
+  %z = apply %f() : $@convention(thin) () -> ()
+  return %z : $()
+}
+
+// CHECK-LABEL: sil [transparent] @transparent_uses_uses_private : $@convention(thin) () -> () {
+// CHECK-NOT: function_ref @uses_private
+// CHECK: return
+sil [transparent] @transparent_uses_uses_private : $@convention(thin) () -> () {
+entry:
+  %f = function_ref @uses_private : $@convention(thin) () -> ()
+  %z = apply %f() : $@convention(thin) () -> ()
+  return %z : $()
+}
+
+// Test fragile-resilient inlining rules:
+// Everything is allowed except inlining of a resilient function into a fragile function.
+
+sil @resilient_function : $@convention(thin) () -> () {
+entry:
+  return undef : $()
+}
+
+sil [serialized] @fragile_function : $@convention(thin) () -> () {
+entry:
+  return undef : $()
+}
+
+// CHECK-LABEL: sil [serialized] @fragile_calls_resilient : $@convention(thin) () -> () {
+// CHECK: function_ref @resilient_function
+// CHECK: return
+sil [serialized] @fragile_calls_resilient : $@convention(thin) () -> () {
+entry:
+  %f = function_ref @resilient_function : $@convention(thin) () -> ()
+  %z = apply %f() : $@convention(thin) () -> ()
+  return %z : $()
+}
+
+// CHECK-LABEL: sil [serialized] @fragile_calls_fragile : $@convention(thin) () -> () {
+// CHECK-NOT: function_ref @resilient_function
+// CHECK: return
+sil [serialized] @fragile_calls_fragile : $@convention(thin) () -> () {
+entry:
+  %f = function_ref @fragile_function : $@convention(thin) () -> ()
+  %z = apply %f() : $@convention(thin) () -> ()
+  return %z : $()
+}
+
+// CHECK-LABEL: sil @resilient_calls_fragile : $@convention(thin) () -> () {
+// CHECK-NOT: function_ref @resilient_function
+// CHECK: return
+sil @resilient_calls_fragile : $@convention(thin) () -> () {
+entry:
+  %f = function_ref @fragile_function : $@convention(thin) () -> ()
+  %z = apply %f() : $@convention(thin) () -> ()
+  return %z : $()
+}
+
+// CHECK-LABEL: sil @resilient_calls_resilient : $@convention(thin) () -> () {
+// CHECK-NOT: function_ref @resilient_function
+// CHECK: return
+sil @resilient_calls_resilient : $@convention(thin) () -> () {
+entry:
+  %f = function_ref @resilient_function : $@convention(thin) () -> ()
+  %z = apply %f() : $@convention(thin) () -> ()
+  return %z : $()
+}
+
+// CHECK-LABEL: sil @calls_self
+// CHECK-NEXT: bb0:
+// CHECK: function_ref @calls_self
+// CHECK-NEXT: apply
+// CHECK-NEXT: return
+sil @calls_self : $@convention(thin) () -> () {
+entry:
+  %f = function_ref @calls_self : $@convention(thin) () -> ()
+  %z = apply %f() : $@convention(thin) () -> ()
+  return %z : $()
+}
+
+// Visibility Tests
+// These tests stem from a time where visibility had an influence
+// on the inlining. This is no longer the case so we just check
+// if everything can be inlined, regardless of visibility.
+
+sil_global private @private_global : $Builtin.Word
+sil private @private_function : $@convention(thin) () -> () {
+  %0 = integer_literal $Builtin.Int32, 0
+  %1 = tuple()
+  return %1 : $()
+}
+sil @references_private_global : $@convention(thin) () -> () {
+  %0 = global_addr @private_global : $*Builtin.Word
+  %1 = tuple()
+  return %1 : $()
+}
+sil @references_private_function : $@convention(thin) () -> () {
+  %0 = function_ref @private_function : $@convention(thin) () -> ()
+  %1 = tuple()
+  return %1 : $()
+}
+
+sil_global shared @shared_global : $Builtin.Word
+sil shared @shared_function : $@convention(thin) () -> () {
+  %0 = integer_literal $Builtin.Int32, 1
+  %1 = tuple()
+  return %1 : $()
+}
+sil @references_shared_global : $@convention(thin) () -> () {
+  %0 = global_addr @shared_global : $*Builtin.Word
+  %1 = tuple()
+  return %1 : $()
+}
+sil @references_shared_function : $@convention(thin) () -> () {
+  %0 = function_ref @shared_function : $@convention(thin) () -> ()
+  %1 = tuple()
+  return %1 : $()
+}
+
+sil_global hidden @hidden_global : $Builtin.Word
+sil hidden @hidden_function : $@convention(thin) () -> () {
+  %0 = integer_literal $Builtin.Int32, 2
+  %1 = tuple()
+  return %1 : $()
+}
+sil @references_hidden_global : $@convention(thin) () -> () {
+  %0 = global_addr @hidden_global : $*Builtin.Word
+  %1 = tuple()
+  return %1 : $()
+}
+sil @references_hidden_function : $@convention(thin) () -> () {
+  %0 = function_ref @hidden_function : $@convention(thin) () -> ()
+  %1 = tuple()
+  return %1 : $()
+}
+
+sil_global @public_global : $Builtin.Word
+sil @public_function : $@convention(thin) () -> () {
+  %0 = integer_literal $Builtin.Int32, 4
+  %1 = tuple()
+  return %1 : $()
+}
+
+sil @references_public_global : $@convention(thin) () -> () {
+  %0 = global_addr @public_global : $*Builtin.Word
+  %1 = tuple()
+  return %1 : $()
+}
+sil @references_public_function : $@convention(thin) () -> () {
+  %0 = function_ref @public_function : $@convention(thin) () -> ()
+  %1 = tuple()
+  return %1 : $()
+}
+
+// CHECK-LABEL: sil private @private_function_test : $@convention(thin) () -> () {
+// CHECK-NOT: function_ref
+// CHECK: return
+sil private @private_function_test : $@convention(thin) () -> () {
+  %0 = function_ref @references_public_function : $@convention(thin) () -> ()
+  %1 = function_ref @references_shared_function : $@convention(thin) () -> ()
+  %2 = function_ref @references_hidden_function : $@convention(thin) () -> ()
+  %3 = function_ref @references_private_function : $@convention(thin) () -> ()
+  %4 = function_ref @references_public_global : $@convention(thin) () -> ()
+  %5 = function_ref @references_shared_global : $@convention(thin) () -> ()
+  %6 = function_ref @references_hidden_global : $@convention(thin) () -> ()
+  %7 = function_ref @references_private_global : $@convention(thin) () -> ()
+  apply %0() : $@convention(thin) () -> ()
+  apply %1() : $@convention(thin) () -> ()
+  apply %2() : $@convention(thin) () -> ()
+  apply %3() : $@convention(thin) () -> ()
+  apply %4() : $@convention(thin) () -> ()
+  apply %5() : $@convention(thin) () -> ()
+  apply %6() : $@convention(thin) () -> ()
+  apply %7() : $@convention(thin) () -> ()
+  %8 = tuple()
+  return %8 : $()
+}
+
+// CHECK-LABEL: sil shared @shared_function_test : $@convention(thin) () -> () {
+// CHECK-NOT: function_ref
+// CHECK: return
+sil shared @shared_function_test : $@convention(thin) () -> () {
+  %0 = function_ref @references_public_function : $@convention(thin) () -> ()
+  %1 = function_ref @references_shared_function : $@convention(thin) () -> ()
+  %2 = function_ref @references_hidden_function : $@convention(thin) () -> ()
+  %3 = function_ref @references_private_function : $@convention(thin) () -> ()
+  %4 = function_ref @references_public_global : $@convention(thin) () -> ()
+  %5 = function_ref @references_shared_global : $@convention(thin) () -> ()
+  %6 = function_ref @references_hidden_global : $@convention(thin) () -> ()
+  %7 = function_ref @references_private_global : $@convention(thin) () -> ()
+  apply %0() : $@convention(thin) () -> ()
+  apply %1() : $@convention(thin) () -> ()
+  apply %2() : $@convention(thin) () -> ()
+  apply %3() : $@convention(thin) () -> ()
+  apply %4() : $@convention(thin) () -> ()
+  apply %5() : $@convention(thin) () -> ()
+  apply %6() : $@convention(thin) () -> ()
+  apply %7() : $@convention(thin) () -> ()
+  %8 = tuple()
+  return %8 : $()
+}
+
+// CHECK-LABEL: sil hidden @hidden_function_test : $@convention(thin) () -> () {
+// CHECK-NOT: function_ref
+// CHECK: return
+sil hidden @hidden_function_test : $@convention(thin) () -> () {
+  %0 = function_ref @references_public_function : $@convention(thin) () -> ()
+  %1 = function_ref @references_shared_function : $@convention(thin) () -> ()
+  %2 = function_ref @references_hidden_function : $@convention(thin) () -> ()
+  %3 = function_ref @references_private_function : $@convention(thin) () -> ()
+  %4 = function_ref @references_public_global : $@convention(thin) () -> ()
+  %5 = function_ref @references_shared_global : $@convention(thin) () -> ()
+  %6 = function_ref @references_hidden_global : $@convention(thin) () -> ()
+  %7 = function_ref @references_private_global : $@convention(thin) () -> ()
+  apply %0() : $@convention(thin) () -> ()
+  apply %1() : $@convention(thin) () -> ()
+  apply %2() : $@convention(thin) () -> ()
+  apply %3() : $@convention(thin) () -> ()
+  apply %4() : $@convention(thin) () -> ()
+  apply %5() : $@convention(thin) () -> ()
+  apply %6() : $@convention(thin) () -> ()
+  apply %7() : $@convention(thin) () -> ()
+  %8 = tuple()
+  return %8 : $()
+}
+
+// CHECK-LABEL: sil @public_function_test : $@convention(thin) () -> () {
+// CHECK-NOT: function_ref
+// CHECK: return
+sil @public_function_test : $@convention(thin) () -> () {
+  %0 = function_ref @references_public_function : $@convention(thin) () -> ()
+  %1 = function_ref @references_shared_function : $@convention(thin) () -> ()
+  %2 = function_ref @references_hidden_function : $@convention(thin) () -> ()
+  %3 = function_ref @references_private_function : $@convention(thin) () -> ()
+  %4 = function_ref @references_public_global : $@convention(thin) () -> ()
+  %5 = function_ref @references_shared_global : $@convention(thin) () -> ()
+  %6 = function_ref @references_hidden_global : $@convention(thin) () -> ()
+  %7 = function_ref @references_private_global : $@convention(thin) () -> ()
+  apply %0() : $@convention(thin) () -> ()
+  apply %1() : $@convention(thin) () -> ()
+  apply %2() : $@convention(thin) () -> ()
+  apply %3() : $@convention(thin) () -> ()
+  apply %4() : $@convention(thin) () -> ()
+  apply %5() : $@convention(thin) () -> ()
+  apply %6() : $@convention(thin) () -> ()
+  apply %7() : $@convention(thin) () -> ()
+  %8 = tuple()
+  return %8 : $()
+}
+
+// CHECK-LABEL: sil hidden_external @hidden_external_function_test : $@convention(thin) () -> () {
+// CHECK-NOT: function_ref
+// CHECK: return
+sil hidden_external @hidden_external_function_test : $@convention(thin) () -> () {
+  %0 = function_ref @references_public_function : $@convention(thin) () -> ()
+  %1 = function_ref @references_shared_function : $@convention(thin) () -> ()
+  %2 = function_ref @references_hidden_function : $@convention(thin) () -> ()
+  %3 = function_ref @references_private_function : $@convention(thin) () -> ()
+  %4 = function_ref @references_public_global : $@convention(thin) () -> ()
+  %5 = function_ref @references_shared_global : $@convention(thin) () -> ()
+  %6 = function_ref @references_hidden_global : $@convention(thin) () -> ()
+  %7 = function_ref @references_private_global : $@convention(thin) () -> ()
+  apply %0() : $@convention(thin) () -> ()
+  apply %1() : $@convention(thin) () -> ()
+  apply %2() : $@convention(thin) () -> ()
+  apply %3() : $@convention(thin) () -> ()
+  apply %4() : $@convention(thin) () -> ()
+  apply %5() : $@convention(thin) () -> ()
+  apply %6() : $@convention(thin) () -> ()
+  apply %7() : $@convention(thin) () -> ()
+  %8 = tuple()
+  return %8 : $()
+}
+
+// CHECK-LABEL: sil public_external @public_external_function_test : $@convention(thin) () -> () {
+// CHECK-NOT: function_ref
+// CHECK: return
+sil public_external @public_external_function_test : $@convention(thin) () -> () {
+  %0 = function_ref @references_public_function : $@convention(thin) () -> ()
+  %1 = function_ref @references_shared_function : $@convention(thin) () -> ()
+  %2 = function_ref @references_hidden_function : $@convention(thin) () -> ()
+  %3 = function_ref @references_private_function : $@convention(thin) () -> ()
+  %4 = function_ref @references_public_global : $@convention(thin) () -> ()
+  %5 = function_ref @references_shared_global : $@convention(thin) () -> ()
+  %6 = function_ref @references_hidden_global : $@convention(thin) () -> ()
+  %7 = function_ref @references_private_global : $@convention(thin) () -> ()
+  apply %0() : $@convention(thin) () -> ()
+  apply %1() : $@convention(thin) () -> ()
+  apply %2() : $@convention(thin) () -> ()
+  apply %3() : $@convention(thin) () -> ()
+  apply %4() : $@convention(thin) () -> ()
+  apply %5() : $@convention(thin) () -> ()
+  apply %6() : $@convention(thin) () -> ()
+  apply %7() : $@convention(thin) () -> ()
+  %8 = tuple()
+  return %8 : $()
+}
+
+// CHECK-LABEL: @caller_of_noinline
+sil @caller_of_noinline : $@convention(thin) () -> () {
+bb0:
+  // CHECK: function_ref @noinline_callee
+  // CHECK: apply
+  %0 = function_ref @noinline_callee : $@convention(thin) () -> Int
+  %1 = apply %0() : $@convention(thin) () -> Int
+  %2 = tuple ()
+  return %2 : $()
+}
+// CHECK-LABEL: [noinline] @noinline_callee
+sil [noinline] @noinline_callee : $@convention(thin) () -> Int {
+bb0:
+  %0 = function_ref @_TFSi33_convertFromBuiltinIntegerLiteralfMSiFBi2048_Si : $@convention(thin) (Builtin.Int2048, @thin Int.Type) -> Int
+  %1 = metatype $@thin Int.Type
+  %2 = integer_literal $Builtin.Int2048, 0
+  %3 = apply %0(%2, %1) : $@convention(thin) (Builtin.Int2048, @thin Int.Type) -> Int
+  return %3 : $Int
+}
+sil [transparent] @_TFSi33_convertFromBuiltinIntegerLiteralfMSiFBi2048_Si : $@convention(thin) (Builtin.Int2048, @thin Int.Type) -> Int
+
+sil @unknown_function : $@convention(thin) () -> ()
+
+sil @coldcall : $@convention(thin) () -> () {
+bb0:
+  // make it a non-trivial function
+  %f = function_ref @unknown_function : $@convention(thin) () -> ()
+  %a1 = apply %f() : $@convention(thin) () -> ()
+  %a2 = apply %f() : $@convention(thin) () -> ()
+  %a3 = apply %f() : $@convention(thin) () -> ()
+  %a4 = apply %f() : $@convention(thin) () -> ()
+  %a5 = apply %f() : $@convention(thin) () -> ()
+  %a6 = apply %f() : $@convention(thin) () -> ()
+  %a7 = apply %f() : $@convention(thin) () -> ()
+  %a8 = apply %f() : $@convention(thin) () -> ()
+  %a9 = apply %f() : $@convention(thin) () -> ()
+  %a10 = apply %f() : $@convention(thin) () -> ()
+  %a11 = apply %f() : $@convention(thin) () -> ()
+  %a12 = apply %f() : $@convention(thin) () -> ()
+  %a13 = apply %f() : $@convention(thin) () -> ()
+  %a14 = apply %f() : $@convention(thin) () -> ()
+  %a15 = apply %f() : $@convention(thin) () -> ()
+  %a16 = apply %f() : $@convention(thin) () -> ()
+  %a17 = apply %f() : $@convention(thin) () -> ()
+  %a18 = apply %f() : $@convention(thin) () -> ()
+  %a19 = apply %f() : $@convention(thin) () -> ()
+  %a20 = apply %f() : $@convention(thin) () -> ()
+  %a21 = apply %f() : $@convention(thin) () -> ()
+  %a22 = apply %f() : $@convention(thin) () -> ()
+  %0 = tuple ()                                   // user: %1
+  return %0 : $()                                 // id: %1
+}
+
+// Generic call to "branchHint" for use in specialized @slowPath
+sil public_external [transparent] [_semantics "branchhint"] @_TFs11_branchHintUs7Boolean__FTQ_Sb_Sb : $@convention(thin)(Bool, Bool) -> Bool {
+bb0(%0 : $Bool, %1 : $Bool):
+  return %0 : $Bool
+}
+
+// Specialized call to "slowPath" for use in @coldcall_caller
+sil shared [noinline] [transparent] [_semantics "slowpath"] @_TTSgSbSbs7Boolean___TFs9_slowPathUs7Boolean__FQ_Sb : $@convention(thin) (Bool) -> Bool {
+bb0(%0 : $Bool):
+  %3 = integer_literal $Builtin.Int1, 0
+  %4 = struct $Bool (%3 : $Builtin.Int1)
+  %5 = function_ref @_TFs11_branchHintUs7Boolean__FTQ_Sb_Sb : $@convention(thin) (Bool, Bool) -> Bool
+  %6 = apply %5(%0, %4) : $@convention(thin) (Bool, Bool) -> Bool
+  return %6 : $Bool
+}
+
+// CHECK-LABEL:  @coldcall_caller
+// CHECK: slowPath
+// CHECK-LABEL: bb1:
+// CHECK: function_ref @coldcall
+// CHECK: apply
+// CHECK-LABEL: bb2:
+sil @coldcall_caller : $@convention(thin) (Int32) -> () {
+bb0(%0 : $Int32):
+  %1 = alloc_stack $Bool                          // users: %7, %9, %11
+  %2 = integer_literal $Builtin.Int32, 0          // user: %5
+  %4 = struct_extract %0 : $Int32, #Int32._value   // user: %5
+  %5 = builtin "cmp_eq_Word"(%4 : $Builtin.Int32, %2 : $Builtin.Int32) : $Builtin.Int1 // user: %6
+  %6 = struct $Bool (%5 : $Builtin.Int1)          // user: %7
+  store %6 to %1 : $*Bool                       // id: %7
+  %8 = function_ref @_TTSgSbSbs7Boolean___TFs9_slowPathUs7Boolean__FQ_Sb : $@convention(thin) (Bool) -> Bool // user: %9
+  %9 = apply %8(%6) : $@convention(thin) (Bool) -> Bool // user: %10
+  %10 = struct_extract %9 : $Bool, #Bool._value    // user: %12
+  dealloc_stack %1 : $*Bool      // id: %11
+  cond_br %10, bb1, bb2                           // id: %12
+
+bb1:                                              // Preds: bb0
+  %13 = function_ref @coldcall : $@convention(thin) () -> () // user: %14
+  %14 = apply %13() : $@convention(thin) () -> ()
+  br bb2                                          // id: %15
+
+bb2:                                              // Preds: bb0 bb1
+  %16 = tuple ()                                  // user: %17
+  return %16 : $()                                // id: %17
+}
+
+sil @slowHelper : $@convention(thin) () -> () {
+bb0:
+  // make it a non-trivial function
+  %f = function_ref @unknown_function : $@convention(thin) () -> ()
+  %a1 = apply %f() : $@convention(thin) () -> ()
+  %a2 = apply %f() : $@convention(thin) () -> ()
+  %a3 = apply %f() : $@convention(thin) () -> ()
+  %a4 = apply %f() : $@convention(thin) () -> ()
+  %a5 = apply %f() : $@convention(thin) () -> ()
+  %a6 = apply %f() : $@convention(thin) () -> ()
+  %a7 = apply %f() : $@convention(thin) () -> ()
+  %a8 = apply %f() : $@convention(thin) () -> ()
+  %a9 = apply %f() : $@convention(thin) () -> ()
+  %a10 = apply %f() : $@convention(thin) () -> ()
+  %a11 = apply %f() : $@convention(thin) () -> ()
+  %a12 = apply %f() : $@convention(thin) () -> ()
+  %a13 = apply %f() : $@convention(thin) () -> ()
+  %a14 = apply %f() : $@convention(thin) () -> ()
+  %a15 = apply %f() : $@convention(thin) () -> ()
+  %a16 = apply %f() : $@convention(thin) () -> ()
+  %a17 = apply %f() : $@convention(thin) () -> ()
+  %a18 = apply %f() : $@convention(thin) () -> ()
+  %a19 = apply %f() : $@convention(thin) () -> ()
+  %a20 = apply %f() : $@convention(thin) () -> ()
+  %a21 = apply %f() : $@convention(thin) () -> ()
+  %a22 = apply %f() : $@convention(thin) () -> ()
+  %t = tuple ()
+  return %t : $()
+}
+
+sil [transparent] [_semantics "fastpath"] @fastPathHelper : $@convention(thin) (Bool) -> Bool
+
+// fastpath.closedTest0 () -> ()
+// From <rdar://problem/17611447> _fastPath kills optimizer
+// First test that the inliner is not inlining the slow call.
+// Then test that same calls is not inlined when transparent.
+// CHECK-LABEL:  @testNoInlineSlow
+// CHECK-LABEL: bb0:
+// CHECK: function_ref @fastPathHelper
+// CHECK-LABEL: bb1:
+// CHECK: function_ref @slowHelper
+// CHECK-LABEL: bb2:
+sil @testNoInlineSlow : $@convention(thin) () -> () {
+bb0:
+  %f1 = function_ref @fastPathHelper : $@convention(thin) (Bool) -> Bool
+  %v9 = alloc_stack $Bool
+  %v12 = integer_literal $Builtin.Int1, 0
+  %v16 = struct $Bool (%v12 : $Builtin.Int1)
+  store %v16 to %v9 : $*Bool                      // id: %17
+  %v18 = apply %f1(%v16) : $@convention(thin) (Bool) -> Bool
+  %v19 = struct_extract %v18 : $Bool, #Bool._value
+  dealloc_stack %v9 : $*Bool      // id: %20
+  cond_br %v19, bb2, bb1                           // id: %21
+
+bb1:
+  %f2 = function_ref @slowHelper : $@convention(thin) () -> ()
+  %r2 = apply %f2() : $@convention(thin) () -> ()
+  br bb2
+
+bb2:
+  %t3 = tuple ()
+  return %t3 : $()
+}
+
+// CHECK-LABEL:  @testInlineSlowTransparent
+// CHECK-LABEL: bb0:
+// CHECK: function_ref @fastPathHelper
+// CHECK-LABEL: bb1:
+// CHECK: function_ref @slowHelper
+// CHECK-LABEL: bb2:
+sil @testInlineSlowTransparent : $@convention(thin) () -> () {
+bb0:
+  %f1 = function_ref @fastPathHelper : $@convention(thin) (Bool) -> Bool
+  %v9 = alloc_stack $Bool
+  %v12 = integer_literal $Builtin.Int1, 0
+  %v16 = struct $Bool (%v12 : $Builtin.Int1)
+  store %v16 to %v9 : $*Bool                      // id: %17
+  %v18 = apply %f1(%v16) : $@convention(thin) (Bool) -> Bool
+  %v19 = struct_extract %v18 : $Bool, #Bool._value
+  dealloc_stack %v9 : $*Bool      // id: %20
+  cond_br %v19, bb2, bb1                           // id: %21
+
+bb1:
+  %f2 = function_ref @slowHelper : $@convention(thin) () -> ()
+  %r2 = apply %f2() : $@convention(thin) () -> ()
+  br bb2
+
+bb2:
+  %t3 = tuple ()
+  return %t3 : $()
+}
+
+// Attempt to ensure that calling the devirtualizer on a try_apply
+// from the performance inliner doesn't result in an assert/crash.
+
+class C {
+  @inline(never) func callThrowing<T>(other: T, closure: @escaping () throws -> T) -> T
+}
+
+// CHECK-LABEL: sil [noinline] @callThrowing
+sil [noinline] @callThrowing : $@convention(method) <T> (@in_guaranteed T, @guaranteed @callee_owned () -> (@out T, @error Error), @guaranteed C) -> @out T {
+bb0(%0 : $*T, %1 : $*T, %2 : $@callee_owned () -> (@out T, @error Error), %3 : $C):
+  strong_retain %2 : $@callee_owned () -> (@out T, @error Error)
+  try_apply %2(%0) : $@callee_owned () -> (@out T, @error Error), normal bb1, error bb4
+
+bb1(%6 : $()):
+  br bb2
+
+bb2:
+  strong_release %2 : $@callee_owned () -> (@out T, @error Error)
+  destroy_addr %1 : $*T
+  %10 = tuple ()
+  return %10 : $()
+
+bb3:
+  copy_addr %1 to [initialization] %0 : $*T
+  strong_release %15 : $Error
+  br bb2
+
+bb4(%15 : $Error):
+  br bb3
+}
+
+
+// CHECK-LABEL: sil @callNonThrowing
+sil @callNonThrowing : $@convention(thin) (@owned C) -> Int32 {
+bb0(%0 : $C):
+  %1 = integer_literal $Builtin.Int32, 1
+  %2 = struct $Int32 (%1 : $Builtin.Int32)
+  %3 = alloc_stack $Int32
+  store %2 to %3 : $*Int32
+  %5 = function_ref @theClosure : $@convention(thin) () -> (Int32, @error Error)
+  %6 = thin_to_thick_function %5 : $@convention(thin) () -> (Int32, @error Error) to $@callee_owned () -> (Int32, @error Error)
+  %7 = function_ref @reabstractionThunk : $@convention(thin) (@owned @callee_owned () -> (Int32, @error Error)) -> (@out Int32, @error Error)
+  %8 = partial_apply %7(%6) : $@convention(thin) (@owned @callee_owned () -> (Int32, @error Error)) -> (@out Int32, @error Error)
+  %9 = alloc_stack $Int32
+  %10 = function_ref @callThrowing : $@convention(method) <τ_0_0> (@in_guaranteed τ_0_0, @guaranteed @callee_owned () -> (@out τ_0_0, @error Error), @guaranteed C) -> @out τ_0_0
+  %11 = apply %10<Int32>(%9, %3, %8, %0) : $@convention(method) <τ_0_0> (@in_guaranteed τ_0_0, @guaranteed @callee_owned () -> (@out τ_0_0, @error Error), @guaranteed C) -> @out τ_0_0
+  %12 = load %9 : $*Int32
+  dealloc_stack %9 : $*Int32
+  dealloc_stack %3 : $*Int32
+  strong_release %0 : $C
+// CHECK: return
+  return %12 : $Int32
+}
+
+
+// CHECK-LABEL: sil @theClosure
+sil @theClosure : $@convention(thin) () -> (Int32, @error Error) {
+bb0:
+  %0 = integer_literal $Builtin.Int32, 0
+  %1 = struct $Int32 (%0 : $Builtin.Int32)
+  return %1 : $Int32
+}
+
+// CHECK-LABEL: sil [transparent] [reabstraction_thunk] @reabstractionThunk
+sil [transparent] [reabstraction_thunk] @reabstractionThunk : $@convention(thin) (@owned @callee_owned () -> (Int32, @error Error)) -> (@out Int32, @error Error) {
+bb0(%0 : $*Int32, %1 : $@callee_owned () -> (Int32, @error Error)):
+  try_apply %1() : $@callee_owned () -> (Int32, @error Error), normal bb1, error bb2
+
+bb1(%3 : $Int32):
+  store %3 to %0 : $*Int32
+  %5 = tuple ()
+  return %5 : $()
+
+bb2(%7 : $Error):
+  %8 = builtin "willThrow"(%7 : $Error) : $()
+  throw %7 : $Error
+}
+
+sil_vtable C {
+  #C.callThrowing!1: @callThrowing
+}
diff --git a/test/SILOptimizer/plus_zero_spec_archetype_method.swift b/test/SILOptimizer/plus_zero_spec_archetype_method.swift
new file mode 100644
index 0000000..f76cf39
--- /dev/null
+++ b/test/SILOptimizer/plus_zero_spec_archetype_method.swift
@@ -0,0 +1,45 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -O -Xllvm -sil-disable-pass=FunctionSignatureOpts -disable-arc-opts -emit-sil -primary-file %s | %FileCheck %s
+
+// We can't deserialize apply_inst with subst lists. When radar://14443304
+// is fixed then we should convert this test to a SIL test.
+
+protocol pingable {
+  func ping()
+}
+
+class ABC : pingable {
+  @inline(never)
+  func ping() {}
+}
+
+@inline(never)
+func generic_call<T : pingable>(x x: T) {
+  x.ping()
+}
+
+struct A<B> : pingable {
+  @inline(never)
+  func ping() {}
+}
+
+@inline(never)
+func useFoo<T>(x x: T) {
+  let a = A<T>()
+  generic_call(x: a)
+}
+
+//CHECK-LABEL: sil @$S21spec_archetype_method21interesting_code_hereyyF
+//CHECK: function_ref @$S21spec_archetype_method12generic_call{{[_0-9a-zA-Z]*}}FAA3ABCC_Tg5
+//CHECK-NEXT: apply
+//CHECK:  function_ref @$S21spec_archetype_method6useFoo{{[_0-9a-zA-Z]*}}FAA3ABCC_Tg5 : $@convention(thin) (@in_guaranteed ABC) -> ()
+//CHECK-NEXT: apply
+//CHECK: return
+public
+func interesting_code_here() {
+  let x = ABC()
+  // Make sure that we can specialize the function generic_call that has a
+  // generic call to x.ping().
+  generic_call(x: x)
+  useFoo(x: x)
+}
diff --git a/test/SILOptimizer/plus_zero_specialize_anyobject.swift b/test/SILOptimizer/plus_zero_specialize_anyobject.swift
new file mode 100644
index 0000000..5d5326c
--- /dev/null
+++ b/test/SILOptimizer/plus_zero_specialize_anyobject.swift
@@ -0,0 +1,23 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend  -O -sil-inline-threshold 0 -emit-sil -primary-file %s | %FileCheck %s
+
+// rdar://problem/20338028
+protocol PA: class { }
+protocol PB { associatedtype B: PA }
+
+class CA: PA { }
+class CB: PB { typealias B = CA }
+
+struct S<A: PB> {
+  @_transparent
+  func crash() -> Bool {
+    let a: A.B? = nil
+    return a === a
+  }
+}
+
+// CHECK-LABEL: sil hidden @$S20specialize_anyobject6callit{{[_0-9a-zA-Z]*}}F
+func callit(s: S<CB>) {
+  // CHECK: function_ref @$Ss3eeeoiySbyXlSg_ABtF : $@convention(thin) (@guaranteed Optional<AnyObject>, @guaranteed Optional<AnyObject>) -> Bool
+  s.crash()
+}
diff --git a/test/SILOptimizer/plus_zero_specialize_cg_update_crash.sil b/test/SILOptimizer/plus_zero_specialize_cg_update_crash.sil
new file mode 100644
index 0000000..01b0190
--- /dev/null
+++ b/test/SILOptimizer/plus_zero_specialize_cg_update_crash.sil
@@ -0,0 +1,33 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %empty-directory(%t)
+// RUN: %target-swift-frontend -parse-stdlib -parse-as-library  -module-name TestMod %S/Inputs/TestMod.sil -emit-module-path %t/TestMod.swiftmodule
+// RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil -enable-sil-verify-all -inline -I %t %s | %FileCheck %s
+
+// Test if the CG is updated correctly during specialization and
+// there is no crash because of a missing CG node for a deserialized function.
+
+sil_stage canonical
+
+import Builtin
+import TestMod
+
+struct MyStruct {
+}
+
+sil @_TF7TestMod10genlibfuncurFq_q_ : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> @out τ_0_0
+sil @_TF7TestMod11genlibfunc2urFq_q_ : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> @out τ_0_0
+
+// CHECK-LABEL: sil @testit
+sil @testit : $@convention(thin) () -> MyStruct {
+bb0:
+  %x0 = function_ref @_TF7TestMod10genlibfuncurFq_q_ : $@convention(thin) <X> (@in_guaranteed X) -> @out X
+  %13 = function_ref @_TF7TestMod11genlibfunc2urFq_q_ : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> @out τ_0_0
+  %14 = alloc_stack $MyStruct
+  %16 = alloc_stack $MyStruct
+  %17 = apply %13<MyStruct>(%16, %14) : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> @out τ_0_0
+  %18 = struct $MyStruct ()
+  dealloc_stack %16 : $*MyStruct
+  dealloc_stack %14 : $*MyStruct
+  return %18 : $MyStruct
+}
+
diff --git a/test/SILOptimizer/plus_zero_specialize_checked_cast_branch.swift b/test/SILOptimizer/plus_zero_specialize_checked_cast_branch.swift
new file mode 100644
index 0000000..4f6073d
--- /dev/null
+++ b/test/SILOptimizer/plus_zero_specialize_checked_cast_branch.swift
@@ -0,0 +1,338 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend  -emit-sil -O -sil-inline-threshold 0 %s -o - | %FileCheck %s
+
+class C {}
+class D : C {}
+class E {}
+
+struct NotUInt8 { var value: UInt8 }
+struct NotUInt64 { var value: UInt64 }
+
+var b = NotUInt8(value: 0)
+var c = C()
+var d = D()
+var e = E()
+var f = NotUInt64(value: 0)
+var o : AnyObject = c
+
+////////////////////////
+// Arch to Arch Casts //
+////////////////////////
+public func ArchetypeToArchetypeCast<T1, T2>(t1 : T1, t2 : T2) -> T2 {
+  if let x = t1 as? T2 {
+    return x
+  }
+  _preconditionFailure("??? Profit?")
+}
+
+// x -> y where x and y are unrelated.
+// CHECK-LABEL: sil shared @$S30specialize_checked_cast_branch011ArchetypeToE4Cast2t12t2q_x_q_tr0_lFAA1CC_AA1ECTg5 : $@convention(thin) (@in_guaranteed C, @in_guaranteed E) -> @owned E {
+// CHECK: bb0
+// CHECK-NOT: bb1
+// CHECK: %2 = integer_literal $Builtin.Int1, -1
+// CHECK: cond_fail %2 : $Builtin.Int1
+// CHECK: unreachable
+
+// CHECK-LABEL: sil shared @$S30specialize_checked_cast_branch28ArchetypeToConcreteCastUInt81tAA03NotI0Vx_tlFAE_Tg5 : $@convention(thin) (NotUInt8) -> NotUInt8 {
+// CHECK: bb0
+// CHECK: return %0 : $NotUInt8
+
+// CHECK-LABEL: sil shared [thunk] [always_inline] @$S30specialize_checked_cast_branch24ArchetypeToConcreteCastC1tAA1CCx_tlFAE_Tg5 : $@convention(thin) (@in_guaranteed C) -> @owned C {
+// CHECK: bb0
+// CHECK:  [[REF:%.*]] = function_ref @$S30specialize_checked_cast_branch24ArchetypeToConcreteCastC1tAA1CCx_tlFAE_Tg5Tf4n_g : $@convention(thin) (@in_guaranteed C) -> C
+// CHECK:  [[RET:%.*]] = apply [[REF]](%0) : $@convention(thin) (@in_guaranteed C) -> C
+// CHECK:  strong_retain [[RET]]
+// CHECK: return [[RET]] : $C
+
+// CHECK-LABEL: sil shared [thunk] [always_inline] @$S30specialize_checked_cast_branch24ArchetypeToConcreteCastC1tAA1CCx_tlFAA1DC_Tg5 : $@convention(thin) (@in_guaranteed D) -> @owned C {
+// CHECK: bb0
+// CHECK:  [[REF:%.*]] = function_ref @$S30specialize_checked_cast_branch24ArchetypeToConcreteCastC1tAA1CCx_tlFAA1DC_Tg5Tf4n_g : $@convention(thin) (@in_guaranteed D) -> C
+// CHECK:  [[RET:%.*]] = apply [[REF]](%0) : $@convention(thin) (@in_guaranteed D) -> C
+// CHECK:  strong_retain [[RET]]
+// CHECK: return [[RET]] : $C
+
+// CHECK-LABEL: sil shared @$S30specialize_checked_cast_branch24ArchetypeToConcreteCastE1tAA1ECx_tlFAA1CC_Tg5 : $@convention(thin) (@in_guaranteed C) -> @owned E {
+// CHECK: bb0
+// CHECK: [[TRUE:%.*]] = integer_literal $Builtin.Int1, -1
+// CHECK: cond_fail [[TRUE]]
+// CHECK: unreachable
+
+// x -> x where x is not a class.
+// CHECK-LABEL: sil shared @$S30specialize_checked_cast_branch011ArchetypeToE4Cast2t12t2q_x_q_tr0_lFAA8NotUInt8V_AFTg5Tf4nd_n : $@convention(thin) (NotUInt8) -> NotUInt8 {
+// CHECK: bb0
+// CHECK-NOT: bb1
+// CHECK: return %0 : $NotUInt8
+
+// x -> y where x,y are not classes and x is a different type from y.
+// CHECK-LABEL: sil shared @$S30specialize_checked_cast_branch011ArchetypeToE4Cast2t12t2q_x_q_tr0_lFAA8NotUInt8V_AA0J6UInt64VTg5Tf4dd_n : $@convention(thin) () -> NotUInt64 {
+// CHECK: bb0
+// CHECK-NOT: bb1
+// CHECK: %0 = integer_literal $Builtin.Int1, -1
+// CHECK: cond_fail %0 : $Builtin.Int1
+// CHECK: unreachable
+
+// x -> y where x is not a class but y is.
+// CHECK-LABEL: sil shared @$S30specialize_checked_cast_branch011ArchetypeToE4Cast2t12t2q_x_q_tr0_lFAA8NotUInt8V_AA1CCTg5Tf4dn_n : $@convention(thin) (@in_guaranteed C) -> @owned C {
+// CHECK: bb0
+// CHECK-NOT: bb1
+// CHECK: %1 = integer_literal $Builtin.Int1, -1
+// CHECK: cond_fail %1 : $Builtin.Int1
+// CHECK: unreachable
+
+// y -> x where x is a class but y is not.
+// CHECK-LABEL: sil shared @$S30specialize_checked_cast_branch011ArchetypeToE4Cast2t12t2q_x_q_tr0_lFAA1CC_AA8NotUInt8VTg5Tf4nd_n : $@convention(thin) (@in_guaranteed C) -> NotUInt8 {
+// CHECK: bb0
+// CHECK-NOT: bb1
+// CHECK: %1 = integer_literal $Builtin.Int1, -1
+// CHECK: cond_fail %1 : $Builtin.Int1
+// CHECK: unreachable
+
+// y -> x where x is a super class of y.
+// CHECK-LABEL: sil shared @$S30specialize_checked_cast_branch011ArchetypeToE4Cast2t12t2q_x_q_tr0_lFAA1DC_AA1CCTg5Tf4nn_g : $@convention(thin) (@in_guaranteed D, @in_guaranteed C) -> C {
+// CHECK: [[T0:%.*]] = load %0 : $*D
+// CHECK: [[T1:%.*]] = upcast [[T0]] : $D to $C
+// CHECK: return [[T1]] : $C
+
+
+_ = ArchetypeToArchetypeCast(t1: c, t2: d)
+_ = ArchetypeToArchetypeCast(t1: c, t2: c)
+_ = ArchetypeToArchetypeCast(t1: b, t2: b)
+_ = ArchetypeToArchetypeCast(t1: b, t2: f)
+_ = ArchetypeToArchetypeCast(t1: b, t2: c)
+_ = ArchetypeToArchetypeCast(t1: c, t2: b)
+_ = ArchetypeToArchetypeCast(t1: d, t2: c)
+_ = ArchetypeToArchetypeCast(t1: c, t2: e)
+
+///////////////////////////
+// Archetype To Concrete //
+///////////////////////////
+
+func ArchetypeToConcreteCastUInt8<T>(t : T) -> NotUInt8 {
+  if let x = t as? NotUInt8 {
+    return x
+  }
+  _preconditionFailure("??? Profit?")
+}
+
+func ArchetypeToConcreteCastC<T>(t : T) -> C {
+  if let x = t as? C {
+    return x
+  }
+  _preconditionFailure("??? Profit?")
+}
+
+func ArchetypeToConcreteCastD<T>(t : T) -> D {
+  if let x = t as? D {
+    return x
+  }
+  _preconditionFailure("??? Profit?")
+}
+
+func ArchetypeToConcreteCastE<T>(t : T) -> E {
+  if let x = t as? E {
+    return x
+  }
+  _preconditionFailure("??? Profit?")
+}
+
+_ = ArchetypeToConcreteCastUInt8(t: b)
+
+
+// CHECK-LABEL: sil shared @$S30specialize_checked_cast_branch28ArchetypeToConcreteCastUInt81tAA03NotI0Vx_tlFAA0J6UInt64V_Tg5Tf4d_n : $@convention(thin) () -> NotUInt8 {
+// CHECK: bb0
+// CHECK-NOT: checked_cast_br
+// CHECK: [[TRUE:%.*]] = integer_literal $Builtin.Int1, -1
+// CHECK: cond_fail [[TRUE]]
+// CHECK: unreachable
+
+// CHECK-LABEL: sil shared @$S30specialize_checked_cast_branch24ArchetypeToConcreteCastC1tAA1CCx_tlFAA8NotUInt8V_Tg5Tf4d_n : $@convention(thin) () -> @owned C {
+// CHECK: bb0
+// CHECK-NOT: checked_cast_br
+// CHECK: [[TRUE:%.*]] = integer_literal $Builtin.Int1, -1
+// CHECK: cond_fail [[TRUE]]
+// CHECK: unreachable
+
+// CHECK-LABEL: sil shared @$S30specialize_checked_cast_branch24ArchetypeToConcreteCastC1tAA1CCx_tlFAA1DC_Tg5Tf4n_g : $@convention(thin) (@in_guaranteed D) -> C {
+// CHECK: bb0
+// CHECK:  [[LOAD:%.*]] = load %0 : $*D
+// CHECK:  [[CAST:%.*]] = upcast [[LOAD]] : $D to $C
+// CHECK: return [[CAST]]
+
+// x -> y where x is a super class of y.
+// CHECK-LABEL: sil shared @$S30specialize_checked_cast_branch24ArchetypeToConcreteCastD1tAA1DCx_tlFAA1CC_Tg5Tf4n_g : $@convention(thin) (@in_guaranteed C) -> D {
+// CHECK:  [[LOAD:%.*]] = load %0 : $*C
+// CHECK: checked_cast_br [[LOAD]] : $C to $D,
+// CHECK: bb1([[T0:%.*]] : $D):
+// CHECK: return [[T0]] : $D
+// CHECK: bb2:
+// CHECK: integer_literal $Builtin.Int1, -1
+// CHECK: cond_fail
+// CHECK: unreachable
+
+_ = ArchetypeToConcreteCastUInt8(t: c)
+_ = ArchetypeToConcreteCastUInt8(t: f)
+_ = ArchetypeToConcreteCastC(t: c)
+_ = ArchetypeToConcreteCastC(t: b)
+_ = ArchetypeToConcreteCastC(t: d)
+_ = ArchetypeToConcreteCastC(t: e)
+_ = ArchetypeToConcreteCastD(t: c)
+_ = ArchetypeToConcreteCastE(t: c)
+
+///////////////////////////
+// Concrete To Archetype //
+///////////////////////////
+
+func ConcreteToArchetypeCastUInt8<T>(t: NotUInt8, t2: T) -> T {
+  if let x = t as? T {
+    return x
+  }
+  _preconditionFailure("??? Profit?")
+}
+func ConcreteToArchetypeCastC<T>(t: C, t2: T) -> T {
+  if let x = t as? T {
+    return x
+  }
+  _preconditionFailure("??? Profit?")
+}
+func ConcreteToArchetypeCastD<T>(t: D, t2: T) -> T {
+  if let x = t as? T {
+    return x
+  }
+  _preconditionFailure("??? Profit?")
+}
+
+// CHECK-LABEL: sil shared @$S30specialize_checked_cast_branch28ConcreteToArchetypeCastUInt81t2t2xAA03NotI0V_xtlFAF_Tg5Tf4nd_n : $@convention(thin) (NotUInt8) -> NotUInt8
+// CHECK: bb0
+// CHECK: return %0
+
+// CHECK-LABEL: sil shared @$S30specialize_checked_cast_branch28ConcreteToArchetypeCastUInt81t2t2xAA03NotI0V_xtlFAA1CC_Tg5Tf4dn_n : $@convention(thin) (@in_guaranteed C) -> @owned C {
+// CHECK: bb0
+// CHECK: [[TRUE:%.*]] = integer_literal $Builtin.Int1, -1
+// CHECK: cond_fail [[TRUE]]
+// CHECK: unreachable
+
+// CHECK-LABEL: sil shared @$S30specialize_checked_cast_branch28ConcreteToArchetypeCastUInt81t2t2xAA03NotI0V_xtlFAA0K6UInt64V_Tg5Tf4dd_n : $@convention(thin) () -> NotUInt64
+// CHECK: bb0
+// CHECK: [[TRUE:%.*]] = integer_literal $Builtin.Int1, -1
+// CHECK: cond_fail [[TRUE]]
+// CHECK: unreachable
+
+// CHECK-LABEL: sil shared @$S30specialize_checked_cast_branch24ConcreteToArchetypeCastC1t2t2xAA1CC_xtlFAF_Tg5Tf4nn_g : $@convention(thin) (@guaranteed C, @in_guaranteed C) -> C {
+// CHECK: bb0
+// CHECK: return %0
+
+// CHECK-LABEL: sil shared @$S30specialize_checked_cast_branch24ConcreteToArchetypeCastC1t2t2xAA1CC_xtlFAA8NotUInt8V_Tg5Tf4dd_n : $@convention(thin) () -> NotUInt8
+// CHECK: bb0
+// CHECK: [[TRUE:%.*]] = integer_literal $Builtin.Int1, -1
+// CHECK: cond_fail [[TRUE]]
+// CHECK: unreachable
+
+// CHECK-LABEL: sil shared @$S30specialize_checked_cast_branch24ConcreteToArchetypeCastC1t2t2xAA1CC_xtlFAA1DC_Tg5Tf4nn_g : $@convention(thin) (@guaranteed C, @in_guaranteed D) -> D {
+// CHECK: bb0
+// CHECK:  checked_cast_br %0 : $C to $D
+// CHECK: bb1
+
+// CHECK-LABEL: sil shared @$S30specialize_checked_cast_branch24ConcreteToArchetypeCastC1t2t2xAA1CC_xtlFAA1EC_Tg5Tf4dn_n : $@convention(thin) (@in_guaranteed E) -> @owned E {
+// CHECK: bb0
+// CHECK: [[TRUE:%.*]] = integer_literal $Builtin.Int1, -1
+// CHECK: cond_fail [[TRUE]]
+// CHECK: unreachable
+
+// CHECK-LABEL: sil shared @$S30specialize_checked_cast_branch24ConcreteToArchetypeCastD1t2t2xAA1DC_xtlFAA1CC_Tg5Tf4nn_g : $@convention(thin) (@guaranteed D, @in_guaranteed C) -> C {
+// CHECK: bb0
+// CHECK:  [[T0:%.*]] = upcast %0 : $D to $C
+// CHECK:  return [[T0]]
+
+// CHECK-LABEL: sil shared @$S30specialize_checked_cast_branch21SuperToArchetypeCastC1c1txAA1CC_xtlFAF_Tg5Tf4nn_g : $@convention(thin) (@guaranteed C, @in_guaranteed C) -> C {
+// CHECK: bb0
+// CHECK-NOT: bb1
+// CHECK: return %0 : $C
+
+// CHECK-LABEL: sil shared @$S30specialize_checked_cast_branch21SuperToArchetypeCastC1c1txAA1CC_xtlFAA1DC_Tg5Tf4nn_g : $@convention(thin) (@guaranteed C, @in_guaranteed D) -> D {
+// CHECK: bb0
+// CHECK:  checked_cast_br %0 : $C to $D, bb1, bb2
+// CHECK: bb1(
+// CHECK:   return
+// CHECK: bb2
+// CHECK:   integer_literal $Builtin.Int1, -1
+// CHECK:   cond_fail
+// CHECK:   unreachable
+
+_ = ConcreteToArchetypeCastUInt8(t: b, t2: b)
+_ = ConcreteToArchetypeCastUInt8(t: b, t2: c)
+_ = ConcreteToArchetypeCastUInt8(t: b, t2: f)
+_ = ConcreteToArchetypeCastC(t: c, t2: c)
+_ = ConcreteToArchetypeCastC(t: c, t2: b)
+_ = ConcreteToArchetypeCastC(t: c, t2: d)
+_ = ConcreteToArchetypeCastC(t: c, t2: e)
+_ = ConcreteToArchetypeCastD(t: d, t2: c)
+
+////////////////////////
+// Super To Archetype //
+////////////////////////
+
+func SuperToArchetypeCastC<T>(c : C, t : T) -> T {
+  if let x = c as? T {
+    return x
+  }
+  _preconditionFailure("??? Profit?")
+}
+
+func SuperToArchetypeCastD<T>(d : D, t : T) -> T {
+  if let x = d as? T {
+    return x
+  }
+  _preconditionFailure("??? Profit?")
+}
+
+// CHECK-LABEL: sil shared @$S30specialize_checked_cast_branch21SuperToArchetypeCastC1c1txAA1CC_xtlFAA8NotUInt8V_Tg5Tf4dd_n : $@convention(thin) () -> NotUInt8 {
+// CHECK: bb0
+// CHECK: [[TRUE:%.*]] = integer_literal $Builtin.Int1, -1
+// CHECK: cond_fail [[TRUE]]
+// CHECK: unreachable
+
+// CHECK-LABEL: sil shared @$S30specialize_checked_cast_branch21SuperToArchetypeCastD1d1txAA1DC_xtlFAA1CC_Tg5Tf4nn_g : $@convention(thin) (@guaranteed D, @in_guaranteed C) -> C {
+// CHECK: bb0
+// CHECK:  [[T0:%.*]] = upcast %0 : $D to $C
+// CHECK:  return [[T0]]
+
+// CHECK-LABEL: sil shared @$S30specialize_checked_cast_branch21SuperToArchetypeCastD1d1txAA1DC_xtlFAF_Tg5Tf4nn_g : $@convention(thin) (@guaranteed D, @in_guaranteed D) -> D {
+// CHECK: bb0
+// CHECK: return %0 : $D
+
+_ = SuperToArchetypeCastC(c: c, t: c)
+_ = SuperToArchetypeCastC(c: c, t: d)
+_ = SuperToArchetypeCastC(c: c, t: b)
+_ = SuperToArchetypeCastD(d: d, t: c)
+_ = SuperToArchetypeCastD(d: d, t: d)
+
+//////////////////////////////
+// Existential To Archetype //
+//////////////////////////////
+
+func ExistentialToArchetypeCast<T>(o : AnyObject, t : T) -> T {
+  if let x = o as? T {
+    return x
+  }
+  _preconditionFailure("??? Profit?")
+}
+
+// CHECK-LABEL: sil shared @$S30specialize_checked_cast_branch26ExistentialToArchetypeCast1o1txyXl_xtlFAA1CC_Tg5Tf4nn_g : $@convention(thin) (@guaranteed AnyObject, @in_guaranteed C) -> C {
+// CHECK: bb0
+// CHECK:  checked_cast_br %0 : $AnyObject to $C
+// CHECK: bb1
+
+// CHECK-LABEL: sil shared @$S30specialize_checked_cast_branch26ExistentialToArchetypeCast1o1txyXl_xtlFAA8NotUInt8V_Tg5Tf4nd_n : $@convention(thin) (@guaranteed AnyObject) -> NotUInt8 {
+// CHECK: bb0
+// CHECK:  checked_cast_addr_br take_always AnyObject in {{%.*}} : $*AnyObject to NotUInt8 in {{%.*}} : $*NotUInt8,
+// CHECK: bb1
+
+// CHECK-LABEL: sil shared @$S30specialize_checked_cast_branch26ExistentialToArchetypeCast1o1txyXl_xtlFyXl_Tg5Tf4nn_g : $@convention(thin) (@guaranteed AnyObject, @in_guaranteed AnyObject) -> AnyObject
+// CHECK: bb0
+// CHECK-NOT: checked_cast_br %
+// CHECK: return %0 : $AnyObject
+// CHECK-NOT: checked_cast_br %
+
+_ = ExistentialToArchetypeCast(o: o, t: c)
+_ = ExistentialToArchetypeCast(o: o, t: b)
+_ = ExistentialToArchetypeCast(o: o, t: o)
diff --git a/test/SILOptimizer/plus_zero_specialize_dynamic_self.swift b/test/SILOptimizer/plus_zero_specialize_dynamic_self.swift
new file mode 100644
index 0000000..4348be6
--- /dev/null
+++ b/test/SILOptimizer/plus_zero_specialize_dynamic_self.swift
@@ -0,0 +1,30 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -Xllvm -sil-inline-generics -emit-sil -O -primary-file %s | %FileCheck %s
+
+protocol P {}
+
+extension P {
+  @_optimize(none) func method1() {}
+
+  @inline(__always) func method2() { method1() }
+}
+
+class C<T> : P {
+  // CHECK-LABEL: sil shared [always_inline] @$S23specialize_dynamic_self1CC11returnsSelfACyxGXDyFSi_Tg5 : $@convention(method) (@guaranteed C<Int>) -> @owned C<Int>
+  // CHECK: [[RESULT:%.*]] = alloc_stack $C<Int>
+  // CHECK: [[FN:%.*]] = function_ref @$S23specialize_dynamic_self1PPAAE7method1yyF : $@convention(method) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> ()
+  // CHECK: apply [[FN]]<@dynamic_self C<Int>>([[RESULT]]) : $@convention(method) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> ()
+  // CHECK: return %0 : $C<Int>
+  @inline(__always)
+  final func returnsSelf() -> Self {
+    method2()
+    return self
+  }
+}
+
+// CHECK-LABEL: sil hidden @$S23specialize_dynamic_self8usesCInt1cyAA1CCySiG_tF : $@convention(thin) (@guaranteed C<Int>) -> () {
+// CHECK: function_ref @$S23specialize_dynamic_self1CC11returnsSelfACyxGXDyFSi_Tg5 : $@convention(method) (@guaranteed C<Int>) -> @owned C<Int>
+// CHECK: return
+func usesCInt(c: C<Int>) {
+  _ = c.returnsSelf()
+}
diff --git a/test/SILOptimizer/plus_zero_specialize_inherited_multifile.swift b/test/SILOptimizer/plus_zero_specialize_inherited_multifile.swift
new file mode 100644
index 0000000..387094d
--- /dev/null
+++ b/test/SILOptimizer/plus_zero_specialize_inherited_multifile.swift
@@ -0,0 +1,19 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -primary-file %s %S/Inputs/specialize_inherited_multifile.swift -O -emit-sil -sil-verify-all | %FileCheck %s
+
+@_optimize(none) func takesBase<T : Base>(t: T) {}
+
+@inline(never) func takesHasAssocType<T : HasAssocType>(t: T) {
+  takesBase(t: t.value)
+}
+
+// Make sure the ConcreteDerived : Base conformance is available here.
+
+// CHECK-LABEL: sil shared [noinline] @$S30specialize_inherited_multifile17takesHasAssocType1tyx_tAA0efG0RzlFAA08ConcreteefG0C_Tg5 : $@convention(thin) (@in_guaranteed ConcreteHasAssocType) -> ()
+// CHECK: [[FN:%.*]] = function_ref @$S30specialize_inherited_multifile9takesBase1tyx_tAA0E0RzlF
+// CHECK: apply [[FN]]<ConcreteDerived>({{%.*}})
+// CHECK: return
+
+public func takesConcreteHasAssocType(c: ConcreteHasAssocType) {
+  takesHasAssocType(t: c)
+}
diff --git a/test/SILOptimizer/plus_zero_specialize_partial_apply.swift b/test/SILOptimizer/plus_zero_specialize_partial_apply.swift
new file mode 100644
index 0000000..9297335
--- /dev/null
+++ b/test/SILOptimizer/plus_zero_specialize_partial_apply.swift
@@ -0,0 +1,245 @@
+// REQUIRES: plus_zero_runtime
+// First check the SIL.
+// RUN: %target-swift-frontend -O -Xllvm -sil-disable-pass=FunctionSignatureOpts -module-name=test -emit-sil -primary-file %s | %FileCheck %s
+
+// Also do an end-to-end test to check all components, including IRGen.
+// RUN: %empty-directory(%t) 
+// RUN: %target-build-swift -O -Xllvm -sil-disable-pass=FunctionSignatureOpts -module-name=test %s -o %t/a.out
+// RUN: %target-run %t/a.out | %FileCheck %s -check-prefix=CHECK-OUTPUT
+// REQUIRES: executable_test
+
+struct MyError : Error {
+	let _code : Int
+	init(_ xx: Int) {
+		_code = xx
+	}
+}
+
+// We need a reabstraction thunk to convert from direct args/result to indirect
+// args/result, which is expected in the returned closure.
+
+// CHECK-LABEL: sil shared [noinline] @$S4test16generic_get_funcyxxcx_SbtlFSi_Tg5 : $@convention(thin) (Int, Bool) -> @owned @callee_guaranteed (@in_guaranteed Int) -> @out Int {
+// CHECK: [[F:%[0-9]+]] = function_ref @$S4test16generic_get_funcyxxcx_SbtlF0B0L_yxxlFSi_TG5 : $@convention(thin) (@in_guaranteed Int, Bool, @guaranteed <τ_0_0> { var τ_0_0 } <Int>) -> @out Int
+// CHECK: [[PA:%[0-9]+]] = partial_apply [callee_guaranteed] [[F]](%1, %{{[0-9]+}}) : $@convention(thin) (@in_guaranteed Int, Bool, @guaranteed <τ_0_0> { var τ_0_0 } <Int>) -> @out Int
+// CHECK: return [[PA]] : $@callee_guaranteed (@in_guaranteed Int) -> @out Int
+@inline(never)
+func generic_get_func<T>(_ t1: T, _ b: Bool) -> (T) -> T {
+
+	@inline(never)
+	func generic(_ t2: T) -> T {
+		return b ? t1 : t2
+	}
+
+	return generic
+}
+
+// CHECK-LABEL: sil hidden [noinline] @$S4test7testit1yS2icSbF : $@convention(thin) (Bool) -> @owned @callee_guaranteed (Int) -> Int {
+// CHECK: [[F:%[0-9]+]] = function_ref @$S4test16generic_get_funcyxxcx_SbtlFSi_Tg5 : $@convention(thin) (Int, Bool) -> @owned @callee_guaranteed (@in_guaranteed Int) -> @out Int
+// CHECK: [[CL:%[0-9]+]] = apply [[F]](%{{[0-9]+}}, %0) : $@convention(thin) (Int, Bool) -> @owned @callee_guaranteed (@in_guaranteed Int) -> @out Int
+// CHECK: [[TH:%[0-9]+]] = function_ref @$SS2iIegnr_S2iIegyd_TR : $@convention(thin) (Int, @guaranteed @callee_guaranteed (@in_guaranteed Int) -> @out Int) -> Int
+// CHECK: [[RET:%[0-9]+]] = partial_apply [callee_guaranteed] [[TH]]([[CL]])
+// CHECK: return [[RET]] : $@callee_guaranteed (Int) -> Int
+@inline(never)
+func testit1(_ b: Bool) -> (Int) -> Int {
+	return generic_get_func(27, b)
+}
+
+
+@inline(never)
+func generic2<T>(_ t1: T, t2: T, b: Bool) -> T {
+	return b ? t1 : t2
+}
+
+// No reabstraction thunk is needed because the returned closure expects direct
+// args/result anyway.
+
+// CHECK-LABEL: sil hidden [noinline] @$S4test17concrete_get_funcS2i_SiSbtcyF : $@convention(thin) () -> @owned @callee_guaranteed (Int, Int, Bool) -> Int {
+// CHECK: [[F:%[0-9]+]] = function_ref @$S4test8generic2_2t21bxx_xSbtlFSi_Tg5 : $@convention(thin) (Int, Int, Bool) -> Int
+// CHECK: [[RET:%[0-9]+]] = thin_to_thick_function [[F]] : $@convention(thin) (Int, Int, Bool) -> Int to $@callee_guaranteed (Int, Int, Bool) -> Int
+// CHECK: return [[RET]] : $@callee_guaranteed (Int, Int, Bool) -> Int
+@inline(never)
+func concrete_get_func() -> (Int, Int, Bool) -> Int {
+	return generic2
+}
+
+@inline(never)
+func testit2() -> (Int, Int, Bool) -> Int {
+	return concrete_get_func()
+}
+
+
+@inline(never)
+func generic3<T>(_ t1: T, _ t2: T, _ b: Bool) -> T {
+	return b ? t1 : t2
+}
+
+// No reabstraction thunk is needed because we directly apply the returned closure.
+
+// CHECK-LABEL: sil hidden [noinline] @$S4test7testit3ySiSbF : $@convention(thin) (Bool) -> Int {
+// CHECK: [[F:%[0-9]+]] = function_ref @$S4test8generic3yxx_xSbtlFSi_Tg5 : $@convention(thin) (Int, Int, Bool) -> Int
+// CHECK: [[RET:%[0-9]+]] = apply [[F]]({{.*}}) : $@convention(thin) (Int, Int, Bool) -> Int
+// CHECK: return [[RET]] : $Int
+@inline(never)
+func testit3(_ b: Bool) -> Int {
+	return generic3(270, 28, b)
+}
+
+// The same three test cases again, but with throwing functions.
+
+// We need a reabstraction thunk to convert from direct args/result to indirect
+// args/result, which is expected in the returned closure.
+
+// CHECK-LABEL: sil shared [noinline] @$S4test25generic_get_func_throwingyxxKcSblFSi_Tg5 : $@convention(thin) (Bool) -> @owned @callee_guaranteed (@in_guaranteed Int) -> (@out Int, @error Error) {
+// CHECK: [[F:%[0-9]+]] = function_ref @$S4test25generic_get_func_throwingyxxKcSblF0B0L_yxxKlFSi_TG5 : $@convention(thin) (@in_guaranteed Int, Bool) -> (@out Int, @error Error)
+// CHECK: [[PA:%[0-9]+]] = partial_apply [callee_guaranteed] [[F]](%0) : $@convention(thin) (@in_guaranteed Int, Bool) -> (@out Int, @error Error)
+// CHECK: return [[PA]] : $@callee_guaranteed (@in_guaranteed Int) -> (@out Int, @error Error)
+@inline(never)
+func generic_get_func_throwing<T>(_ b: Bool) -> (T) throws -> T {
+
+	@inline(never)
+	func generic(_ t2: T) throws -> T {
+		if b {
+			throw MyError(123)
+		}
+		return t2
+	}
+
+	return generic
+}
+
+// CHECK-LABEL: sil hidden [noinline] @$S4test16testit1_throwingyS2iKcSbF : $@convention(thin) (Bool) -> @owned @callee_guaranteed (Int) -> (Int, @error Error) {
+// CHECK: [[F:%[0-9]+]] = function_ref @$S4test25generic_get_func_throwingyxxKcSblFSi_Tg5 : $@convention(thin) (Bool) -> @owned @callee_guaranteed (@in_guaranteed Int) -> (@out Int, @error Error)
+// CHECK: [[CL:%[0-9]+]] = apply [[F]](%0) : $@convention(thin) (Bool) -> @owned @callee_guaranteed (@in_guaranteed Int) -> (@out Int, @error Error)
+// CHECK: [[TH:%[0-9]+]] = function_ref @$SS2is5Error_pIegnrzo_S2isAA_pIegydzo_TR : $@convention(thin) (Int, @guaranteed @callee_guaranteed (@in_guaranteed Int) -> (@out Int, @error Error)) -> (Int, @error Error)
+// CHECK: [[RET:%[0-9]+]] = partial_apply [callee_guaranteed] [[TH]]([[CL]])
+// CHECK: return [[RET]] : $@callee_guaranteed (Int) -> (Int, @error Error)
+@inline(never)
+func testit1_throwing(_ b: Bool) -> (Int) throws -> Int {
+	return generic_get_func_throwing(b)
+}
+
+
+@inline(never)
+func generic2_throwing<T>(_ t1: T, b: Bool) throws -> T {
+	if b {
+		throw MyError(124)
+	}
+	return t1
+}
+
+// No reabstraction thunk is needed because the returned closure expects direct
+// args/result anyway.
+
+// CHECK-LABEL: sil hidden [noinline] @$S4test26concrete_get_func_throwingS2i_SbtKcyF : $@convention(thin) () -> @owned @callee_guaranteed (Int, Bool) -> (Int, @error Error) {
+// CHECK: [[F:%[0-9]+]] = function_ref @$S4test17generic2_throwing_1bxx_SbtKlFSi_Tg5 : $@convention(thin) (Int, Bool) -> (Int, @error Error)
+// CHECK: [[RET:%[0-9]+]] = thin_to_thick_function [[F]] : $@convention(thin) (Int, Bool) -> (Int, @error Error) to $@callee_guaranteed (Int, Bool) -> (Int, @error Error)
+// CHECK: return [[RET]] : $@callee_guaranteed (Int, Bool) -> (Int, @error Error)
+@inline(never)
+func concrete_get_func_throwing() -> (Int, Bool) throws -> Int {
+	return generic2_throwing
+}
+
+@inline(never)
+func testit2_throwing() -> (Int, Bool) throws -> Int {
+	return concrete_get_func_throwing()
+}
+
+
+
+@inline(never)
+func generic3_throwing<T>(_ t1: T, _ b: Bool) throws -> T {
+	if b {
+		throw MyError(125)
+	}
+	return t1
+}
+
+// No reabstraction thunk is needed because we directly apply the returned closure.
+
+// CHECK-LABEL: sil hidden [noinline] @$S4test16testit3_throwingySiSbF : $@convention(thin) (Bool) -> Int {
+// CHECK: [[F:%[0-9]+]] = function_ref @$S4test17generic3_throwingyxx_SbtKlFSi_Tg5 : $@convention(thin) (Int, Bool) -> (Int, @error Error)
+// CHECK: try_apply [[F]](%{{[0-9]+}}, %0) : $@convention(thin) (Int, Bool) -> (Int, @error Error), normal bb{{[0-9]+}}, error bb{{[0-9]+}}
+// CHECK: }
+@inline(never)
+func testit3_throwing(_ b: Bool) -> Int {
+	do {
+		return try generic3_throwing(271, b)
+	} catch {
+		return error._code
+	}
+}
+
+// CHECK-LABEL: sil shared [transparent] [thunk] @$S4test16generic_get_funcyxxcx_SbtlF0B0L_yxxlFSi_TG5 : $@convention(thin) (@in_guaranteed Int, Bool, @guaranteed <τ_0_0> { var τ_0_0 } <Int>) -> @out Int {
+// CHECK: bb0(%0 : $*Int, %1 : $*Int, %2 : $Bool, %3 : $<τ_0_0> { var τ_0_0 } <Int>):
+// CHECK: [[LD:%[0-9]+]] = load %1 : $*Int
+// CHECK: [[F:%[0-9]+]] = function_ref @$S4test16generic_get_funcyxxcx_SbtlF0B0L_yxxlFSi_Tg5 : $@convention(thin) (Int, Bool, @guaranteed <τ_0_0> { var τ_0_0 } <Int>) -> Int
+// CHECK: [[RET:%[0-9]+]] = apply [[F]]([[LD]], %2, %3)
+// CHECK: store [[RET]] to %0 : $*Int
+// CHECK: return %{{[0-9]*}} : $()
+
+// CHECK-LABEL: sil shared [transparent] [thunk] @$S4test25generic_get_func_throwingyxxKcSblF0B0L_yxxKlFSi_TG5 : $@convention(thin) (@in_guaranteed Int, Bool) -> (@out Int, @error Error) {
+// CHECK: bb0(%0 : $*Int, %1 : $*Int, %2 : $Bool):
+// CHECK: [[LD:%[0-9]+]] = load %1 : $*Int
+// CHECK: [[F:%[0-9]+]] = function_ref @$S4test25generic_get_func_throwingyxxKcSblF0B0L_yxxKlFSi_Tg5 : $@convention(thin) (Int, Bool) -> (Int, @error Error)
+// CHECK: try_apply [[F]]([[LD]], %2) : $@convention(thin) (Int, Bool) -> (Int, @error Error), normal bb1, error bb2
+// CHECK: bb1([[NORMAL:%[0-9]+]] : $Int):
+// CHECK: store [[NORMAL]] to %0 : $*Int
+// CHECK: return %{{[0-9]*}} : $()
+// CHECK: bb2([[ERROR:%[0-9]+]] : $Error):
+// CHECK: throw [[ERROR]] : $Error
+
+
+// The main program.
+// Check if the generated executable produces the correct output.
+
+// CHECK-OUTPUT: 18
+print(testit1(false)(18))
+// CHECK-OUTPUT: 27
+print(testit1(true)(18))
+
+// CHECK-OUTPUT: 4
+print(testit2()(3, 4, false))
+// CHECK-OUTPUT: 3
+print(testit2()(3, 4, true))
+
+// CHECK-OUTPUT: 28
+print(testit3(false))
+// CHECK-OUTPUT: 270
+print(testit3(true))
+
+var x: Int
+do {
+	x = try testit1_throwing(false)(19)
+} catch {
+	x = error._code
+}
+// CHECK-OUTPUT: 19
+print(x)
+do {
+	x = try testit1_throwing(true)(19)
+} catch {
+	x = error._code
+}
+// CHECK-OUTPUT: 123
+print(x)
+
+do {
+	x = try testit2_throwing()(20, false)
+} catch {
+	x = error._code
+}
+// CHECK-OUTPUT: 20
+print(x)
+do {
+	x = try testit2_throwing()(20, true)
+} catch {
+	x = error._code
+}
+// CHECK-OUTPUT: 124
+print(x)
+
+// CHECK-OUTPUT: 271
+print(testit3_throwing(false))
+// CHECK-OUTPUT: 125
+print(testit3_throwing(true))
+
diff --git a/test/SILOptimizer/plus_zero_specialize_same_type_constraint.swift b/test/SILOptimizer/plus_zero_specialize_same_type_constraint.swift
new file mode 100644
index 0000000..f8db643
--- /dev/null
+++ b/test/SILOptimizer/plus_zero_specialize_same_type_constraint.swift
@@ -0,0 +1,54 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend  -O -emit-sil -primary-file %s | %FileCheck %s
+
+protocol FirstChild {}
+
+protocol FirstParent {
+  associatedtype Child : FirstChild
+
+  var firstChild: Child { get }
+}
+
+protocol SecondChild {}
+
+protocol SecondParent {
+  associatedtype Child : SecondChild
+
+  var secondChild: Child { get }
+}
+
+@_optimize(none)
+func takesFirstChild<T : FirstChild>(t: T) {}
+
+@_optimize(none)
+func takesSecondChild<T : SecondChild>(t: T) {}
+
+@inline(never)
+func doStuff<First : FirstParent, Second : SecondParent>(f: First, s: Second)
+    where First.Child == Second.Child {
+  takesFirstChild(t: f.firstChild)
+  takesSecondChild(t: f.firstChild)
+
+  takesFirstChild(t: s.secondChild)
+  takesSecondChild(t: s.secondChild)
+}
+
+struct ConcreteChild : FirstChild, SecondChild {}
+
+struct ConcreteFirstParent<T> : FirstParent {
+  var firstChild: ConcreteChild { return ConcreteChild() }
+}
+
+struct ConcreteSecondParent<T> : SecondParent {
+  var secondChild: ConcreteChild { return ConcreteChild() }
+}
+
+doStuff(f: ConcreteFirstParent<ConcreteChild>(),
+        s: ConcreteSecondParent<ConcreteChild>())
+
+// CHECK-LABEL: sil shared [noinline] @$S31specialize_same_type_constraint7doStuff1f1syx_q_tAA11FirstParentRzAA06SecondH0R_5ChildQy_AGRtzr0_lFAA08ConcretegH0VyAA0kJ0VG_AA0kiH0VyAMGTg5Tf4dd_n : $@convention(thin) () -> () {
+// CHECK: [[FIRST:%.*]] = function_ref @$S31specialize_same_type_constraint15takesFirstChild1tyx_tAA0fG0RzlF
+// CHECK: apply [[FIRST]]<ConcreteChild>({{.*}}) : $@convention(thin) <τ_0_0 where τ_0_0 : FirstChild> (@in_guaranteed τ_0_0) -> ()
+// CHECK: [[SECOND:%.*]] = function_ref @$S31specialize_same_type_constraint16takesSecondChild1tyx_tAA0fG0RzlF
+// CHECK: apply [[SECOND]]<ConcreteChild>({{.*}}) : $@convention(thin) <τ_0_0 where τ_0_0 : SecondChild> (@in_guaranteed τ_0_0) -> ()
+// CHECK: return
diff --git a/test/SILOptimizer/plus_zero_specialize_self.swift b/test/SILOptimizer/plus_zero_specialize_self.swift
new file mode 100644
index 0000000..b181e3e
--- /dev/null
+++ b/test/SILOptimizer/plus_zero_specialize_self.swift
@@ -0,0 +1,20 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -Xllvm -sil-full-demangle  -O -sil-inline-threshold 0 -emit-sil -primary-file %s | %FileCheck %s
+
+// CHECK-NOT: generic specialization <Swift.AnyObject, Self> of specialize_self.cast <A, B>(A) -> Swift.Optional<B>
+
+// CHECK-LABEL: specialize_self.cast<A, B>(A) -> Swift.Optional<B>
+// CHECK-NEXT: sil hidden @$S15specialize_self4cast{{[_0-9a-zA-Z]*}}F : $@convention(thin) <T, R> (@in_guaranteed T) -> @out Optional<R>
+func cast<T,R>(_ x: T) -> R? {
+  return x as? R
+}
+
+// CHECK-LABEL: static specialize_self.Base.returnIfSelf(Swift.AnyObject) -> Swift.Optional<Self>
+// CHECK-NEXT: sil hidden @$S15specialize_self4BaseC12returnIfSelf{{[_0-9a-zA-Z]*}}FZ : $@convention(method) (@guaranteed AnyObject, @thick Base.Type) -> @owned Optional<Base>
+// CHECK: [[CAST:%[0-9]+]] = function_ref @$S15specialize_self4cast{{[_0-9a-zA-Z]*}}F
+// CHECK: apply [[CAST]]<AnyObject, @dynamic_self Base>
+class Base {
+  class func returnIfSelf(_ x: AnyObject) -> Self? {
+    return cast(x)
+  }
+}
diff --git a/test/SILOptimizer/plus_zero_specialize_self_conforming.swift b/test/SILOptimizer/plus_zero_specialize_self_conforming.swift
new file mode 100644
index 0000000..1c01bc2
--- /dev/null
+++ b/test/SILOptimizer/plus_zero_specialize_self_conforming.swift
@@ -0,0 +1,25 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -emit-sil -O -primary-file %s | %FileCheck %s
+
+// REQUIRES: objc_interop
+
+import Foundation
+
+@objc protocol P {}
+
+@_optimize(none)
+func takesP<T : P>(_: T) {}
+
+@inline(__always)
+func callsTakesP<T : P>(_ t: T) {
+  takesP(t)
+}
+
+// CHECK-LABEL: sil hidden @$S26specialize_self_conforming16callsTakesPWithPyyAA1P_pF : $@convention(thin) (@guaranteed P) -> () {
+// CHECK: [[FN:%.*]] = function_ref @$S26specialize_self_conforming6takesPyyxAA1PRzlF : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@guaranteed τ_0_0) -> ()
+// CHECK: apply [[FN]]<P>(%0) : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@guaranteed τ_0_0) -> ()
+// CHECK: return
+
+func callsTakesPWithP(_ p: P) {
+  callsTakesP(p)
+}
diff --git a/test/SILOptimizer/plus_zero_specialize_unconditional_checked_cast.swift b/test/SILOptimizer/plus_zero_specialize_unconditional_checked_cast.swift
new file mode 100644
index 0000000..6f6977d
--- /dev/null
+++ b/test/SILOptimizer/plus_zero_specialize_unconditional_checked_cast.swift
@@ -0,0 +1,381 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend  -Xllvm -sil-disable-pass=FunctionSignatureOpts -emit-sil -o - -O %s | %FileCheck %s
+
+//////////////////
+// Declarations //
+//////////////////
+
+public class C {}
+public class D : C {}
+public class E {}
+
+public struct NotUInt8 { var value: UInt8 }
+public struct NotUInt64 { var value: UInt64 }
+
+var b = NotUInt8(value: 0)
+var c = C()
+var d = D()
+var e = E()
+var f = NotUInt64(value: 0)
+var o : AnyObject = c
+
+////////////////////////////
+// Archetype To Archetype //
+////////////////////////////
+
+@inline(never)
+public func ArchetypeToArchetype<T1, T2>(t t: T1, t2: T2) -> T2 {
+  return t as! T2
+}
+
+ArchetypeToArchetype(t: b, t2: b)
+ArchetypeToArchetype(t: c, t2: c)
+ArchetypeToArchetype(t: b, t2: c)
+ArchetypeToArchetype(t: c, t2: b)
+ArchetypeToArchetype(t: c, t2: d)
+ArchetypeToArchetype(t: d, t2: c)
+ArchetypeToArchetype(t: c, t2: e)
+ArchetypeToArchetype(t: b, t2: f)
+
+// x -> x where x is not a class.
+// CHECK-LABEL: sil shared [noinline] @$S37specialize_unconditional_checked_cast011ArchetypeToE0{{[_0-9a-zA-Z]*}}FAA8NotUInt8V{{.*}}Tg5 : $@convention(thin) (NotUInt8, NotUInt8) -> NotUInt8 {
+// CHECK-NOT: unconditional_checked_cast archetype_to_archetype
+
+// x -> x where x is a class.
+// CHECK-LABEL: sil shared [noinline] @$S37specialize_unconditional_checked_cast011ArchetypeToE0{{[_0-9a-zA-Z]*}}FAA1CC{{.*}}Tg5 : $@convention(thin) (@in_guaranteed C, @in_guaranteed C) -> @owned C {
+// CHECK-NOT: unconditional_checked_cast archetype_to_archetype
+
+// x -> y where x is not a class but y is.
+// CHECK-LABEL: sil shared [noinline] @$S37specialize_unconditional_checked_cast011ArchetypeToE0{{[_0-9a-zA-Z]*}}FAA8NotUInt8V_AA1CCTg5 : $@convention(thin) (NotUInt8, @in_guaranteed C) -> @owned C {
+// CHECK-NOT: unconditional_checked_cast_addr
+// CHECK-NOT: unconditional_checked_cast_addr
+// CHECK:     builtin "int_trap"
+// CHECK-NOT: unconditional_checked_cast_addr
+
+// y -> x where x is not a class but y is.
+// CHECK-LABEL: sil shared [noinline] @$S37specialize_unconditional_checked_cast011ArchetypeToE0{{[_0-9a-zA-Z]*}}FAA1CC_AA8NotUInt8VTg5 : $@convention(thin) (@in_guaranteed C, NotUInt8) -> NotUInt8 {
+// CHECK-NOT: unconditional_checked_cast archetype_to_archetype
+// CHECK: builtin "int_trap"
+// CHECK-NOT: unconditional_checked_cast archetype_to_archetype
+
+// x -> y where x is a super class of y.
+// CHECK-LABEL: sil shared [noinline] @$S37specialize_unconditional_checked_cast011ArchetypeToE0{{[_0-9a-zA-Z]*}}FAA1CC_AA1DCTg5 : $@convention(thin) (@in_guaranteed C, @in_guaranteed D) -> @owned D {
+// CHECK: [[STACK:%[0-9]+]] = alloc_stack $C
+// TODO: This should be optimized to an unconditional_checked_cast without the need of alloc_stack: rdar://problem/24775038
+// CHECK: unconditional_checked_cast_addr C in [[STACK]] : $*C to D in
+
+// y -> x where x is a super class of y.
+// CHECK-LABEL: sil shared [noinline] @$S37specialize_unconditional_checked_cast011ArchetypeToE0{{[_0-9a-zA-Z]*}}FAA1DC_AA1CCTg5 : $@convention(thin) (@in_guaranteed D, @in_guaranteed C) -> @owned C {
+// CHECK-NOT: unconditional_checked_cast archetype_to_archetype
+// CHECK: upcast {{%[0-9]+}} : $D to $C
+// CHECK-NOT: unconditional_checked_cast archetype_to_archetype
+
+// x -> y where x and y are unrelated classes.
+// CHECK-LABEL: sil shared [noinline] @$S37specialize_unconditional_checked_cast011ArchetypeToE0{{[_0-9a-zA-Z]*}}FAA1CC_AA1ECTg5 : $@convention(thin) (@in_guaranteed C, @in_guaranteed E) -> @owned E {
+// CHECK-NOT: unconditional_checked_cast archetype_to_archetype
+// CHECK: builtin "int_trap"
+// CHECK-NOT: unconditional_checked_cast archetype_to_archetype
+
+// x -> y where x and y are unrelated non classes.
+// CHECK-LABEL: sil shared [noinline] @$S37specialize_unconditional_checked_cast011ArchetypeToE0{{[_0-9a-zA-Z]*}}FAA8NotUInt8V_AA0H6UInt64VTg5 : $@convention(thin) (NotUInt8, NotUInt64) -> NotUInt64 {
+// CHECK-NOT: unconditional_checked_cast archetype_to_archetype
+// CHECK-NOT: unconditional_checked_cast archetype_to_archetype
+// CHECK:      builtin "int_trap"
+// CHECK-NOT: unconditional_checked_cast archetype_to_archetype
+
+
+///////////////////////////
+// Archetype To Concrete //
+///////////////////////////
+
+@inline(never)
+public func ArchetypeToConcreteConvertUInt8<T>(t t: T) -> NotUInt8 {
+  return t as! NotUInt8
+}
+ArchetypeToConcreteConvertUInt8(t: b)
+ArchetypeToConcreteConvertUInt8(t: c)
+ArchetypeToConcreteConvertUInt8(t: f)
+
+// x -> x where x is not a class.
+// CHECK-LABEL: sil shared [noinline] @$S37specialize_unconditional_checked_cast31ArchetypeToConcreteConvertUInt8{{[_0-9a-zA-Z]*}}3Not{{.*}}Tg5 : $@convention(thin) (NotUInt8) -> NotUInt8 {
+// CHECK: bb0
+// CHECK-NEXT: debug_value %0
+// CHECK-NEXT: return %0
+
+// x -> y where y is a class but x is not.
+// CHECK-LABEL: sil shared [noinline] @$S37specialize_unconditional_checked_cast31ArchetypeToConcreteConvertUInt8{{[_0-9a-zA-Z]*}}FAA1CC_Tg5
+// CHECK: bb0
+// CHECK: builtin "int_trap"
+// CHECK: unreachable
+// CHECK-NEXT: }
+
+// x -> y where x,y are not classes and x is a different type from y.
+// CHECK-LABEL: sil shared [noinline] @$S37specialize_unconditional_checked_cast31ArchetypeToConcreteConvertUInt8{{[_0-9a-zA-Z]*}}3Not{{.*}}Tg5
+// CHECK: bb0
+// CHECK: builtin "int_trap"
+// CHECK: unreachable
+// CHECK-NEXT: }
+
+// x -> x where x is a class.
+// CHECK-LABEL: sil shared [noinline] @$S37specialize_unconditional_checked_cast27ArchetypeToConcreteConvertC{{[_0-9a-zA-Z]*}}Tg5 : $@convention(thin) (@in_guaranteed C) -> @owned C {
+// CHECK: bb0
+// CHECK-NEXT: debug_value_addr %0
+// CHECK-NEXT: %2 = load %0 : $*C
+// CHECK: return %2
+
+// x -> y where x is a class but y is not.
+// CHECK-LABEL: sil shared [noinline] @$S37specialize_unconditional_checked_cast27ArchetypeToConcreteConvertC{{[_0-9a-zA-Z]*}}FAA8NotUInt8V_Tg5
+// CHECK: bb0
+// CHECK: builtin "int_trap"
+// CHECK: unreachable
+// CHECK-NEXT: }
+
+// x -> y where x,y are classes and x is a super class of y.
+// CHECK-LABEL: sil shared [noinline] @$S37specialize_unconditional_checked_cast27ArchetypeToConcreteConvertC{{[_0-9a-zA-Z]*}}FAA1DC_Tg5 : $@convention(thin) (@in_guaranteed D) -> @owned C {
+// CHECK: bb0
+// CHECK-NEXT: debug_value_addr %0
+// CHECK-NEXT: %2 = load %0 : $*D
+// CHECK: [[UC:%[0-9]+]] = upcast %2
+// CHECK: return [[UC]]
+
+// x -> y where x,y are classes, but x is unrelated to y.
+// CHECK-LABEL: sil shared [noinline] @$S37specialize_unconditional_checked_cast27ArchetypeToConcreteConvertC{{[_0-9a-zA-Z]*}}FAA1EC_Tg5
+// CHECK: bb0
+// CHECK: builtin "int_trap"
+// CHECK: unreachable
+// CHECK-NEXT: }
+
+@inline(never)
+public func ArchetypeToConcreteConvertC<T>(t t: T) -> C {
+  return t as! C
+}
+
+ArchetypeToConcreteConvertC(t: c)
+ArchetypeToConcreteConvertC(t: b)
+ArchetypeToConcreteConvertC(t: d)
+ArchetypeToConcreteConvertC(t: e)
+
+@inline(never)
+public func ArchetypeToConcreteConvertD<T>(t t: T) -> D {
+  return t as! D
+}
+
+ArchetypeToConcreteConvertD(t: c)
+
+// x -> y where x,y are classes and x is a sub class of y.
+// CHECK-LABEL: sil shared [noinline] @$S37specialize_unconditional_checked_cast27ArchetypeToConcreteConvertD{{[_0-9a-zA-Z]*}}FAA1CC_Tg5 : $@convention(thin) (@in_guaranteed C) -> @owned D {
+// CHECK: bb0(%0 : $*C):
+// CHECK-DAG: [[STACK_C:%[0-9]+]] = alloc_stack $C
+// CHECK-DAG: store {{.*}} to [[STACK_C]]
+// CHECK-DAG: [[STACK_D:%[0-9]+]] = alloc_stack $D
+// TODO: This should be optimized to an unconditional_checked_cast without the need of alloc_stack: rdar://problem/24775038
+// CHECK-DAG: unconditional_checked_cast_addr C in [[STACK_C]] : $*C to D in [[STACK_D]] : $*D
+// CHECK-DAG: [[LOAD:%[0-9]+]] = load [[STACK_D]]
+// CHECK: return [[LOAD]]
+
+@inline(never)
+public func ArchetypeToConcreteConvertE<T>(t t: T) -> E {
+  return t as! E
+}
+
+ArchetypeToConcreteConvertE(t: c)
+
+// x -> y where x,y are classes, but y is unrelated to x. The idea is
+// to make sure that the fact that y is concrete does not affect the
+// result.
+// CHECK-LABEL: sil shared [noinline] @$S37specialize_unconditional_checked_cast27ArchetypeToConcreteConvertE{{[_0-9a-zA-Z]*}}FAA1CC_Tg5
+// CHECK: bb0
+// CHECK: builtin "int_trap"
+// CHECK: unreachable
+// CHECK-NEXT: }
+
+
+///////////////////////////
+// Concrete to Archetype //
+///////////////////////////
+
+@inline(never)
+public func ConcreteToArchetypeConvertUInt8<T>(t t: NotUInt8, t2: T) -> T {
+  return t as! T
+}
+
+ConcreteToArchetypeConvertUInt8(t: b, t2: b)
+ConcreteToArchetypeConvertUInt8(t: b, t2: c)
+ConcreteToArchetypeConvertUInt8(t: b, t2: f)
+
+// x -> x where x is not a class.
+// CHECK-LABEL: sil shared [noinline] @$S37specialize_unconditional_checked_cast31ConcreteToArchetypeConvertUInt8{{[_0-9a-zA-Z]*}}3Not{{.*}}Tg5 : $@convention(thin) (NotUInt8, NotUInt8) -> NotUInt8 {
+// CHECK: bb0(%0 : $NotUInt8, %1 : $NotUInt8):
+// CHECK-NEXT: debug_value %0
+// CHECK-NEXT: return %0
+
+// x -> y where x is not a class but y is a class.
+// CHECK-LABEL: sil shared [noinline] @$S37specialize_unconditional_checked_cast31ConcreteToArchetypeConvertUInt8{{[_0-9a-zA-Z]*}}FAA1CC_Tg5 : $@convention(thin) (NotUInt8, @in_guaranteed C) -> @owned C {
+// CHECK: bb0
+// CHECK: builtin "int_trap"
+// CHECK: unreachable
+// CHECK-NEXT: }
+
+// x -> y where x,y are different non class types.
+// CHECK-LABEL: sil shared [noinline] @$S37specialize_unconditional_checked_cast31ConcreteToArchetypeConvertUInt8{{[_0-9a-zA-Z]*}}Not{{.*}}Tg5 : $@convention(thin) (NotUInt8, NotUInt64) -> NotUInt64 {
+// CHECK: bb0
+// CHECK: builtin "int_trap"
+// CHECK: unreachable
+// CHECK-NEXT: }
+
+@inline(never)
+public func ConcreteToArchetypeConvertC<T>(t t: C, t2: T) -> T {
+  return t as! T
+}
+
+ConcreteToArchetypeConvertC(t: c, t2: c)
+ConcreteToArchetypeConvertC(t: c, t2: b)
+ConcreteToArchetypeConvertC(t: c, t2: d)
+ConcreteToArchetypeConvertC(t: c, t2: e)
+
+
+// x -> x where x is a class.
+// CHECK-LABEL: sil shared [noinline] @$S37specialize_unconditional_checked_cast27ConcreteToArchetypeConvertC{{[_0-9a-zA-Z]*}}Tg5 : $@convention(thin) (@guaranteed C, @in_guaranteed C) -> @owned C {
+// CHECK: bb0(%0 : $C, %1 : $*C):
+// CHECK: return %0
+
+// x -> y where x is a class but y is not.
+// CHECK-LABEL: sil shared [noinline] @$S37specialize_unconditional_checked_cast27ConcreteToArchetypeConvertC{{[_0-9a-zA-Z]*}}Not{{.*}}Tg5 : $@convention(thin) (@guaranteed C, NotUInt8) -> NotUInt8 {
+// CHECK: bb0
+// CHECK: builtin "int_trap"
+// CHECK: unreachable
+// CHECK-NEXT: }
+
+// x -> y where x is a super class of y.
+// CHECK-LABEL: sil shared [noinline] @$S37specialize_unconditional_checked_cast27ConcreteToArchetypeConvertC{{[_0-9a-zA-Z]*}}FAA1DC_Tg5 : $@convention(thin) (@guaranteed C, @in_guaranteed D) -> @owned D {
+// CHECK: bb0(%0 : $C, %1 : $*D):
+// CHECK-DAG: [[STACK_C:%[0-9]+]] = alloc_stack $C
+// CHECK-DAG: store %0 to [[STACK_C]]
+// CHECK-DAG: [[STACK_D:%[0-9]+]] = alloc_stack $D
+// TODO: This should be optimized to an unconditional_checked_cast without the need of alloc_stack: rdar://problem/24775038
+// CHECK-DAG: unconditional_checked_cast_addr C in [[STACK_C]] : $*C to D in [[STACK_D]] : $*D
+// CHECK-DAG: [[LOAD:%[0-9]+]] = load [[STACK_D]]
+// CHECK: return [[LOAD]]
+
+// x -> y where x and y are unrelated classes.
+// CHECK-LABEL: sil shared [noinline] @$S37specialize_unconditional_checked_cast27ConcreteToArchetypeConvertC{{[_0-9a-zA-Z]*}}FAA1EC_Tg5 : $@convention(thin) (@guaranteed C, @in_guaranteed E) -> @owned E {
+// CHECK: bb0(%0 : $C, %1 : $*E):
+// CHECK-NEXT: builtin "int_trap"
+// CHECK-NEXT: unreachable
+// CHECK-NEXT: }
+
+@inline(never)
+public func ConcreteToArchetypeConvertD<T>(t t: D, t2: T) -> T {
+  return t as! T
+}
+
+ConcreteToArchetypeConvertD(t: d, t2: c)
+
+// x -> y where x is a subclass of y.
+// CHECK-LABEL: sil shared [noinline] @$S37specialize_unconditional_checked_cast27ConcreteToArchetypeConvertD{{[_0-9a-zA-Z]*}}FAA1CC_Tg5 : $@convention(thin) (@guaranteed D, @in_guaranteed C) -> @owned C {
+// CHECK: bb0(%0 : $D, %1 : $*C):
+// CHECK-DAG: [[UC:%[0-9]+]] = upcast %0
+// CHECK: return [[UC]]
+
+
+////////////////////////
+// Super To Archetype //
+////////////////////////
+
+@inline(never)
+public func SuperToArchetypeC<T>(c c : C, t : T) -> T {
+  return c as! T
+}
+
+SuperToArchetypeC(c: c, t: c)
+SuperToArchetypeC(c: c, t: d)
+SuperToArchetypeC(c: c, t: b)
+
+
+// x -> x where x is a class.
+// CHECK-LABEL: sil shared [noinline] @$S37specialize_unconditional_checked_cast17SuperToArchetypeC{{[_0-9a-zA-Z]*}}Tg5 : $@convention(thin) (@guaranteed C, @in_guaranteed C) -> @owned C {
+// CHECK: bb0(%0 : $C, %1 : $*C):
+// CHECK: return %0
+
+// x -> y where x is a super class of y.
+// CHECK-LABEL: sil shared [noinline] @$S37specialize_unconditional_checked_cast17SuperToArchetypeC{{[_0-9a-zA-Z]*}}FAA1DC_Tg5 : $@convention(thin) (@guaranteed C, @in_guaranteed D) -> @owned D {
+// CHECK: bb0
+// CHECK: unconditional_checked_cast_addr C in
+
+// x -> y where x is a class and y is not.
+// CHECK-LABEL: sil shared [noinline] @$S37specialize_unconditional_checked_cast17SuperToArchetypeC{{[_0-9a-zA-Z]*}}FAA8NotUInt8V_Tg5 : $@convention(thin) (@guaranteed C, NotUInt8) -> NotUInt8 {
+// CHECK: bb0
+// CHECK: builtin "int_trap"
+// CHECK: unreachable
+// CHECK-NEXT: }
+
+@inline(never)
+public func SuperToArchetypeD<T>(d d : D, t : T) -> T {
+  return d as! T
+}
+
+SuperToArchetypeD(d: d, t: c)
+SuperToArchetypeD(d: d, t: d)
+
+// *NOTE* The frontend is smart enough to turn this into an upcast. When this
+// test is converted to SIL, this should be fixed appropriately.
+// CHECK-LABEL: sil shared [noinline] @$S37specialize_unconditional_checked_cast17SuperToArchetypeD{{[_0-9a-zA-Z]*}}FAA1CC_Tg5 : $@convention(thin) (@guaranteed D, @in_guaranteed C) -> @owned C {
+// CHECK-NOT: unconditional_checked_cast super_to_archetype
+// CHECK: upcast
+// CHECK-NOT: unconditional_checked_cast super_to_archetype
+
+// CHECK-LABEL: sil shared [noinline] @$S37specialize_unconditional_checked_cast17SuperToArchetypeD{{[_0-9a-zA-Z]*}}Tg5 : $@convention(thin) (@guaranteed D, @in_guaranteed D) -> @owned D {
+// CHECK: bb0(%0 : $D, %1 : $*D):
+// CHECK: return %0
+
+//////////////////////////////
+// Existential To Archetype //
+//////////////////////////////
+
+@inline(never)
+public func ExistentialToArchetype<T>(o o : AnyObject, t : T) -> T {
+  return o as! T
+}
+
+// AnyObject -> Class.
+// CHECK-LABEL: sil shared [noinline] @$S37specialize_unconditional_checked_cast22ExistentialToArchetype{{[_0-9a-zA-Z]*}}FAA1CC_Tg5 : $@convention(thin) (@guaranteed AnyObject, @in_guaranteed C) -> @owned C {
+// CHECK: unconditional_checked_cast_addr AnyObject in {{%.*}} : $*AnyObject to C
+
+// AnyObject -> Non Class (should always fail)
+// CHECK-LABEL: sil shared [noinline] @$S37specialize_unconditional_checked_cast22ExistentialToArchetype{{[_0-9a-zA-Z]*}}FAA8NotUInt8V_Tg5 : $@convention(thin) (@guaranteed AnyObject, NotUInt8) -> NotUInt8 {
+// CHECK-NOT: builtin "int_trap"()
+// CHECK-NOT: unreachable
+// CHECK: return
+
+// AnyObject -> AnyObject
+// CHECK-LABEL: sil shared [noinline] @$S37specialize_unconditional_checked_cast22ExistentialToArchetype{{[_0-9a-zA-Z]*}}yXl{{.*}}Tg5 : $@convention(thin) (@guaranteed AnyObject, @in_guaranteed AnyObject) -> @owned AnyObject {
+// CHECK: bb0(%0 : $AnyObject, %1 : $*AnyObject):
+// CHECK: return %0
+
+ExistentialToArchetype(o: o, t: c)
+ExistentialToArchetype(o: o, t: b)
+ExistentialToArchetype(o: o, t: o)
+
+// Ensure that a downcast from an Optional source is not promoted to a
+// value cast. We could do the promotion, but the optimizer would need
+// to insert the Optional unwrapping logic before the cast.
+//
+// CHECK-LABEL: sil shared [noinline] @$S37specialize_unconditional_checked_cast15genericDownCastyq_x_q_mtr0_lFAA1CCSg_AA1DCTg5 : $@convention(thin) (@in_guaranteed Optional<C>, @thick D.Type) -> @owned D {
+// CHECK: bb0(%0 : $*Optional<C>, %1 : $@thick D.Type):
+// CHECK-DAG: [[STACK_D:%[0-9]+]] = alloc_stack $D
+// CHECK-DAG: [[STACK_C:%[0-9]+]] = alloc_stack $Optional<C>
+// CHECK-DAG: %5 = load %0 : $*Optional<C>
+// CHECK-DAG: store %5 to [[STACK_C]]
+// TODO: This should be optimized to an unconditional_checked_cast without the need of alloc_stack: rdar://problem/24775038
+// CHECK-DAG: unconditional_checked_cast_addr Optional<C> in [[STACK_C]] : $*Optional<C> to D in [[STACK_D]] : $*D
+// CHECK-DAG: [[LOAD:%[0-9]+]] = load [[STACK_D]]
+// CHECK: return [[LOAD]]
+@inline(never)
+public func genericDownCast<T, U>(_ a: T, _ : U.Type) -> U {
+  return a as! U
+}
+
+public func callGenericDownCast(_ c: C?) -> D {
+  return genericDownCast(c, D.self)
+}
+
diff --git a/test/SILOptimizer/plus_zero_specialized_anyobject_conformance.swift b/test/SILOptimizer/plus_zero_specialized_anyobject_conformance.swift
new file mode 100644
index 0000000..5cc511e
--- /dev/null
+++ b/test/SILOptimizer/plus_zero_specialized_anyobject_conformance.swift
@@ -0,0 +1,24 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend  -O -sil-inline-threshold 0 -emit-sil -primary-file %s | %FileCheck %s
+
+// rdar://problem/31910351
+
+// Check that swift compiler does not crash on this input.
+
+public protocol P {
+  func use<T:AnyObject>(_ t: T)
+}
+
+public class C<T> {
+}
+
+public func callee(_ t: C<Int32>?, _ p: P) {
+  // This call results in a creation of a specialized conformance of C<Int32> to AnyObject.
+  p.use(t!)
+}
+
+// CHECK-LABEL: sil @$S33specialized_anyobject_conformance7caller11pyAA1P_p_tF : $@convention(thin) (@in_guaranteed P) -> () {
+public func caller1(p: P) {
+  callee(C<Int32>(), p)
+}
+
diff --git a/test/SILOptimizer/spec_archetype_method.swift b/test/SILOptimizer/spec_archetype_method.swift
index b206b7a..c1bdc18 100644
--- a/test/SILOptimizer/spec_archetype_method.swift
+++ b/test/SILOptimizer/spec_archetype_method.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -O -Xllvm -sil-disable-pass=FunctionSignatureOpts -disable-arc-opts -emit-sil -primary-file %s | %FileCheck %s
 
 // We can't deserialize apply_inst with subst lists. When radar://14443304
diff --git a/test/SILOptimizer/specialize_anyobject.swift b/test/SILOptimizer/specialize_anyobject.swift
index 4b6b8f7..3549297 100644
--- a/test/SILOptimizer/specialize_anyobject.swift
+++ b/test/SILOptimizer/specialize_anyobject.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend  -O -sil-inline-threshold 0 -emit-sil -primary-file %s | %FileCheck %s
 
 // rdar://problem/20338028
diff --git a/test/SILOptimizer/specialize_cg_update_crash.sil b/test/SILOptimizer/specialize_cg_update_crash.sil
index 4267d5e..317bdce 100644
--- a/test/SILOptimizer/specialize_cg_update_crash.sil
+++ b/test/SILOptimizer/specialize_cg_update_crash.sil
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %empty-directory(%t)
 // RUN: %target-swift-frontend -parse-stdlib -parse-as-library  -module-name TestMod %S/Inputs/TestMod.sil -emit-module-path %t/TestMod.swiftmodule
 // RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil -enable-sil-verify-all -inline -I %t %s | %FileCheck %s
diff --git a/test/SILOptimizer/specialize_checked_cast_branch.swift b/test/SILOptimizer/specialize_checked_cast_branch.swift
index a61de44..87f8234 100644
--- a/test/SILOptimizer/specialize_checked_cast_branch.swift
+++ b/test/SILOptimizer/specialize_checked_cast_branch.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend  -emit-sil -O -sil-inline-threshold 0 %s -o - | %FileCheck %s
 
 class C {}
diff --git a/test/SILOptimizer/specialize_dynamic_self.swift b/test/SILOptimizer/specialize_dynamic_self.swift
index c801480..835abec 100644
--- a/test/SILOptimizer/specialize_dynamic_self.swift
+++ b/test/SILOptimizer/specialize_dynamic_self.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -Xllvm -sil-inline-generics -emit-sil -O -primary-file %s | %FileCheck %s
 
 protocol P {}
diff --git a/test/SILOptimizer/specialize_inherited_multifile.swift b/test/SILOptimizer/specialize_inherited_multifile.swift
index 96da56e..f6921c0 100644
--- a/test/SILOptimizer/specialize_inherited_multifile.swift
+++ b/test/SILOptimizer/specialize_inherited_multifile.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -primary-file %s %S/Inputs/specialize_inherited_multifile.swift -O -emit-sil -sil-verify-all | %FileCheck %s
 
 @_optimize(none) func takesBase<T : Base>(t: T) {}
diff --git a/test/SILOptimizer/specialize_partial_apply.swift b/test/SILOptimizer/specialize_partial_apply.swift
index fafb263..db5172e 100644
--- a/test/SILOptimizer/specialize_partial_apply.swift
+++ b/test/SILOptimizer/specialize_partial_apply.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // First check the SIL.
 // RUN: %target-swift-frontend -O -Xllvm -sil-disable-pass=FunctionSignatureOpts -module-name=test -emit-sil -primary-file %s | %FileCheck %s
 
diff --git a/test/SILOptimizer/specialize_same_type_constraint.swift b/test/SILOptimizer/specialize_same_type_constraint.swift
index fe11b5b..e80cda3 100644
--- a/test/SILOptimizer/specialize_same_type_constraint.swift
+++ b/test/SILOptimizer/specialize_same_type_constraint.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend  -O -emit-sil -primary-file %s | %FileCheck %s
 
 protocol FirstChild {}
diff --git a/test/SILOptimizer/specialize_self.swift b/test/SILOptimizer/specialize_self.swift
index 4bc585d..4384da9 100644
--- a/test/SILOptimizer/specialize_self.swift
+++ b/test/SILOptimizer/specialize_self.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -Xllvm -sil-full-demangle  -O -sil-inline-threshold 0 -emit-sil -primary-file %s | %FileCheck %s
 
 // CHECK-NOT: generic specialization <Swift.AnyObject, Self> of specialize_self.cast <A, B>(A) -> Swift.Optional<B>
diff --git a/test/SILOptimizer/specialize_self_conforming.swift b/test/SILOptimizer/specialize_self_conforming.swift
index c182da3..847fa94e 100644
--- a/test/SILOptimizer/specialize_self_conforming.swift
+++ b/test/SILOptimizer/specialize_self_conforming.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -emit-sil -O -primary-file %s | %FileCheck %s
 
 // REQUIRES: objc_interop
diff --git a/test/SILOptimizer/specialize_unconditional_checked_cast.swift b/test/SILOptimizer/specialize_unconditional_checked_cast.swift
index d4cbb5a..31ab14a 100644
--- a/test/SILOptimizer/specialize_unconditional_checked_cast.swift
+++ b/test/SILOptimizer/specialize_unconditional_checked_cast.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend  -Xllvm -sil-disable-pass=FunctionSignatureOpts -emit-sil -o - -O %s | %FileCheck %s
 
 //////////////////
diff --git a/test/SILOptimizer/specialized_anyobject_conformance.swift b/test/SILOptimizer/specialized_anyobject_conformance.swift
index 89f63f7..d127df0 100644
--- a/test/SILOptimizer/specialized_anyobject_conformance.swift
+++ b/test/SILOptimizer/specialized_anyobject_conformance.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend  -O -sil-inline-threshold 0 -emit-sil -primary-file %s | %FileCheck %s
 
 // rdar://problem/31910351
diff --git a/test/Sanitizers/tsan.swift b/test/Sanitizers/tsan.swift
index 214274a..3b793f5 100644
--- a/test/Sanitizers/tsan.swift
+++ b/test/Sanitizers/tsan.swift
@@ -3,7 +3,11 @@
 // REQUIRES: executable_test
 // REQUIRES: tsan_runtime
 // UNSUPPORTED: OS=tvos
-#if os(OSX) || os(iOS)
+
+// https://bugs.swift.org/browse/SR-6622
+// XFAIL: linux
+
+#if os(macOS) || os(iOS)
 import Darwin
 #elseif os(Linux) || os(FreeBSD) || os(PS4) || os(Android) || os(Cygwin)
 import Glibc
@@ -34,7 +38,7 @@
 var racey_x: Int;
 
 for _ in 1...5 {
-#if os(OSX) || os(iOS)
+#if os(macOS) || os(iOS)
   var t : pthread_t?
 #else
   var t : pthread_t = 0
@@ -45,7 +49,7 @@
 
     return nil
   }, nil)
-#if os(OSX) || os(iOS)
+#if os(macOS) || os(iOS)
   threads.append(t!)
 #else
   threads.append(t)
diff --git a/test/Sanitizers/witness_table_lookup.swift b/test/Sanitizers/witness_table_lookup.swift
index f0120ac..202880e 100644
--- a/test/Sanitizers/witness_table_lookup.swift
+++ b/test/Sanitizers/witness_table_lookup.swift
@@ -3,6 +3,9 @@
 // REQUIRES: executable_test
 // REQUIRES: tsan_runtime
 
+// https://bugs.swift.org/browse/SR-6622
+// XFAIL: linux
+
 // Check that TSan does not report spurious races in witness table lookup.
 
 func consume(_ x: Any) {}
diff --git a/test/Sema/fixed_ambiguities/plus_zero_rdar27198177.swift b/test/Sema/fixed_ambiguities/plus_zero_rdar27198177.swift
new file mode 100644
index 0000000..39fbc60
--- /dev/null
+++ b/test/Sema/fixed_ambiguities/plus_zero_rdar27198177.swift
@@ -0,0 +1,7 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -emit-sil -verify %s -swift-version 4 | %FileCheck %s
+
+let arr = ["A", "B", "C"]
+let lazy: LazyMapCollection = arr.lazy.map { $0 }
+// CHECK: function_ref @$Ss22LazyCollectionProtocolPsE6filterys0a6FilterB0Vy8ElementsQzGSb7ElementQzcF : $@convention(method) <τ_0_0 where τ_0_0 : LazyCollectionProtocol> (@guaranteed @callee_guaranteed (@in_guaranteed τ_0_0.Element) -> Bool, @in_guaranteed τ_0_0) -> @out LazyFilterCollection<τ_0_0.Elements>
+_ = lazy.filter { $0 > "A" }.count
diff --git a/test/Sema/fixed_ambiguities/plus_zero_rdar33142386.swift b/test/Sema/fixed_ambiguities/plus_zero_rdar33142386.swift
new file mode 100644
index 0000000..ea617e2
--- /dev/null
+++ b/test/Sema/fixed_ambiguities/plus_zero_rdar33142386.swift
@@ -0,0 +1,6 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -emit-sil -verify %s -swift-version 4 | %FileCheck %s
+
+let x: String = "ultimate question"
+// CHECK: function_ref @$Ss26RangeReplaceableCollectionPsE6filteryxSb7ElementQzKXEKF : $@convention(method) <τ_0_0 where τ_0_0 : RangeReplaceableCollection> (@noescape @callee_guaranteed (@in_guaranteed τ_0_0.Element) -> (Bool, @error Error), @in_guaranteed τ_0_0) -> (@out τ_0_0, @error Error)
+_ = x.filter({ $0 == " " }).count < 3
diff --git a/test/Sema/fixed_ambiguities/plus_zero_rdar35623181.swift b/test/Sema/fixed_ambiguities/plus_zero_rdar35623181.swift
new file mode 100644
index 0000000..43e9c26
--- /dev/null
+++ b/test/Sema/fixed_ambiguities/plus_zero_rdar35623181.swift
@@ -0,0 +1,9 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -emit-sil -verify %s | %FileCheck %s
+
+extension Sequence where Element == String {
+  func record() -> String {
+    // CHECK: function_ref @$Ss20LazySequenceProtocolPsE3mapys0a3MapB0Vy8ElementsQzqd__Gqd__7ElementQzclF : $@convention(method) <τ_0_0 where τ_0_0 : LazySequenceProtocol><τ_1_0> (@guaranteed @callee_guaranteed (@in_guaranteed τ_0_0.Element) -> @out τ_1_0, @in_guaranteed τ_0_0) -> @out LazyMapSequence<τ_0_0.Elements, τ_1_0
+    return lazy.map({ $0 }).joined(separator: ",")
+  }
+}
diff --git a/test/Sema/fixed_ambiguities/plus_zero_rdar36333688.swift b/test/Sema/fixed_ambiguities/plus_zero_rdar36333688.swift
new file mode 100644
index 0000000..81b8f77
--- /dev/null
+++ b/test/Sema/fixed_ambiguities/plus_zero_rdar36333688.swift
@@ -0,0 +1,31 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %target-swift-frontend -emit-sil -verify %s | %FileCheck %s
+
+infix operator +=+ : AdditionPrecedence
+extension RangeReplaceableCollection {
+   public static func +=+ <
+     Other : Sequence
+   >(lhs: Self, rhs: Other) -> Self
+    where Element == Other.Element {
+     fatalError()
+   }
+
+   public static func +=+ <
+     Other : Sequence
+   >(lhs: Other, rhs: Self) -> Self
+    where Element == Other.Element {
+     fatalError()
+   }
+
+   public static func +=+ <
+    Other : RangeReplaceableCollection
+   >(lhs: Self, rhs: Other) -> Self
+    where Element == Other.Element {
+     fatalError()
+   }
+}
+
+func rdar36333688(_ first: Int, _ rest: Int...) {
+  // CHECK: function_ref @{{.*}} : $@convention(method) <τ_0_0 where τ_0_0 : RangeReplaceableCollection><τ_1_0 where τ_1_0 : RangeReplaceableCollection, τ_0_0.Element == τ_1_0.Element> (@in_guaranteed τ_0_0, @in_guaranteed τ_1_0, @thick τ_0_0.Type) -> @out τ_0_0
+  let _ = [first] +=+ rest
+}
diff --git a/test/Sema/fixed_ambiguities/rdar27198177.swift b/test/Sema/fixed_ambiguities/rdar27198177.swift
index 0cfad49..bd240b3 100644
--- a/test/Sema/fixed_ambiguities/rdar27198177.swift
+++ b/test/Sema/fixed_ambiguities/rdar27198177.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -emit-sil -verify %s -swift-version 4 | %FileCheck %s
 
 let arr = ["A", "B", "C"]
diff --git a/test/Sema/fixed_ambiguities/rdar33142386.swift b/test/Sema/fixed_ambiguities/rdar33142386.swift
index 798fc6b..e6fd493 100644
--- a/test/Sema/fixed_ambiguities/rdar33142386.swift
+++ b/test/Sema/fixed_ambiguities/rdar33142386.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -emit-sil -verify %s -swift-version 4 | %FileCheck %s
 
 let x: String = "ultimate question"
diff --git a/test/Sema/fixed_ambiguities/rdar35623181.swift b/test/Sema/fixed_ambiguities/rdar35623181.swift
index d72f4b6..d3278c8 100644
--- a/test/Sema/fixed_ambiguities/rdar35623181.swift
+++ b/test/Sema/fixed_ambiguities/rdar35623181.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -emit-sil -verify %s | %FileCheck %s
 
 extension Sequence where Element == String {
diff --git a/test/Sema/fixed_ambiguities/rdar36333688.swift b/test/Sema/fixed_ambiguities/rdar36333688.swift
index b7827cc..3417b6a 100644
--- a/test/Sema/fixed_ambiguities/rdar36333688.swift
+++ b/test/Sema/fixed_ambiguities/rdar36333688.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %target-swift-frontend -emit-sil -verify %s | %FileCheck %s
 
 infix operator +=+ : AdditionPrecedence
diff --git a/test/Serialization/function.swift b/test/Serialization/function.swift
index 6e9074a..93e74be 100644
--- a/test/Serialization/function.swift
+++ b/test/Serialization/function.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %empty-directory(%t)
 // RUN: %target-swift-frontend -emit-module -o %t %S/Inputs/def_func.swift
 // RUN: llvm-bcanalyzer %t/def_func.swiftmodule | %FileCheck %s
diff --git a/test/Serialization/objc.swift b/test/Serialization/objc.swift
index 90bf773..d2ba2bf 100644
--- a/test/Serialization/objc.swift
+++ b/test/Serialization/objc.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %empty-directory(%t)
 // RUN: %target-swift-frontend -emit-module -o %t %S/Inputs/def_objc.swift -disable-objc-attr-requires-foundation-module
 // RUN: llvm-bcanalyzer %t/def_objc.swiftmodule | %FileCheck %s
diff --git a/test/Serialization/plus_zero_function.swift b/test/Serialization/plus_zero_function.swift
new file mode 100644
index 0000000..0332f22
--- /dev/null
+++ b/test/Serialization/plus_zero_function.swift
@@ -0,0 +1,120 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %empty-directory(%t)
+// RUN: %target-swift-frontend -emit-module -o %t %S/Inputs/def_func.swift
+// RUN: llvm-bcanalyzer %t/def_func.swiftmodule | %FileCheck %s
+// RUN: %target-swift-frontend -emit-silgen -I %t %s | %FileCheck %s -check-prefix=SIL
+
+// CHECK-NOT: FALL_BACK_TO_TRANSLATION_UNIT
+// CHECK-NOT: UnknownCode
+
+import def_func
+
+func useEq<T: EqualOperator>(_ x: T, y: T) -> Bool {
+  return x == y
+}
+
+// SIL: sil @main
+// SIL:   [[RAW:%.+]] = global_addr @$S8function3rawSivp : $*Int
+// SIL:   [[ZERO:%.+]] = function_ref @$S8def_func7getZeroSiyF : $@convention(thin) () -> Int
+// SIL:   [[RESULT:%.+]] = apply [[ZERO]]() : $@convention(thin) () -> Int
+// SIL:   store [[RESULT]] to [trivial] [[RAW]] : $*Int
+var raw = getZero()
+
+// Check that 'raw' is an Int
+var cooked : Int = raw
+
+
+// SIL:   [[GET_INPUT:%.+]] = function_ref @$S8def_func8getInput1xS2i_tF : $@convention(thin) (Int) -> Int
+// SIL:   {{%.+}} = apply [[GET_INPUT]]({{%.+}}) : $@convention(thin) (Int) -> Int
+var raw2 = getInput(x: raw)
+
+// SIL:   [[GET_SECOND:%.+]] = function_ref @$S8def_func9getSecond_1yS2i_SitF : $@convention(thin) (Int, Int) -> Int
+// SIL:   {{%.+}} = apply [[GET_SECOND]]({{%.+}}, {{%.+}}) : $@convention(thin) (Int, Int) -> Int
+var raw3 = getSecond(raw, y: raw2)
+
+// SIL:   [[USE_NESTED:%.+]] = function_ref @$S8def_func9useNested_1nySi1x_Si1yt_SitF : $@convention(thin) (Int, Int, Int) -> ()
+// SIL:   {{%.+}} = apply [[USE_NESTED]]({{%.+}}, {{%.+}}, {{%.+}}) : $@convention(thin) (Int, Int, Int) -> ()
+useNested((raw, raw2), n: raw3)
+
+// SIL:   [[VA_SIZE:%.+]] = integer_literal $Builtin.Word, 2
+// SIL:   {{%.+}} = apply {{%.*}}<Int>([[VA_SIZE]])
+// SIL:   [[VARIADIC:%.+]] = function_ref @$S8def_func8variadic1x_ySd_SidtF : $@convention(thin) (Double, @guaranteed Array<Int>) -> ()
+// SIL:   {{%.+}} = apply [[VARIADIC]]({{%.+}}, {{%.+}}) : $@convention(thin) (Double, @guaranteed Array<Int>) -> ()
+variadic(x: 2.5, 4, 5)
+
+// SIL:   [[VARIADIC:%.+]] = function_ref @$S8def_func9variadic2_1xySid_SdtF : $@convention(thin) (@guaranteed Array<Int>, Double) -> ()
+variadic2(1, 2, 3, x: 5.0)
+
+// SIL:   [[SLICE_SIZE:%.+]] = integer_literal $Builtin.Word, 3
+// SIL:   {{%.+}} = apply {{%.*}}<Int>([[SLICE_SIZE]])
+// SIL:   [[SLICE:%.+]] = function_ref @$S8def_func5slice1xySaySiG_tF : $@convention(thin) (@guaranteed Array<Int>) -> ()
+// SIL:   {{%.+}} = apply [[SLICE]]({{%.+}}) : $@convention(thin) (@guaranteed Array<Int>) -> ()
+slice(x: [2, 4, 5])
+
+optional(x: .some(23))
+optional(x: .none)
+
+
+// SIL:   [[MAKE_PAIR:%.+]] = function_ref @$S8def_func8makePair{{[_0-9a-zA-Z]*}}F : $@convention(thin) <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0, @in_guaranteed τ_0_1) -> (@out τ_0_0, @out τ_0_1)
+// SIL:   {{%.+}} = apply [[MAKE_PAIR]]<Int, Double>({{%.+}}, {{%.+}})
+
+var pair : (Int, Double) = makePair(a: 1, b: 2.5)
+
+// SIL:   [[DIFFERENT_A:%.+]] = function_ref @$S8def_func9different{{[_0-9a-zA-Z]*}}F : $@convention(thin) <τ_0_0 where τ_0_0 : Equatable> (@in_guaranteed τ_0_0, @in_guaranteed τ_0_0) -> Bool
+// SIL:   [[DIFFERENT_B:%.+]] = function_ref @$S8def_func9different{{[_0-9a-zA-Z]*}}F : $@convention(thin) <τ_0_0 where τ_0_0 : Equatable> (@in_guaranteed τ_0_0, @in_guaranteed τ_0_0) -> Bool
+
+_ = different(a: 1, b: 2)
+_ = different(a: false, b: false)
+
+// SIL:   [[DIFFERENT2_A:%.+]] = function_ref @$S8def_func10different2{{[_0-9a-zA-Z]*}}F : $@convention(thin) <τ_0_0 where τ_0_0 : Equatable> (@in_guaranteed τ_0_0, @in_guaranteed τ_0_0) -> Bool
+// SIL:   [[DIFFERENT2_B:%.+]] = function_ref @$S8def_func10different2{{[_0-9a-zA-Z]*}}F : $@convention(thin) <τ_0_0 where τ_0_0 : Equatable> (@in_guaranteed τ_0_0, @in_guaranteed τ_0_0) -> Bool
+_ = different2(a: 1, b: 2)
+_ = different2(a: false, b: false)
+
+
+struct IntWrapper1 : Wrapped {
+  typealias Value = Int
+  func getValue() -> Int { return 1 }
+}
+struct IntWrapper2 : Wrapped {
+  typealias Value = Int
+  func getValue() -> Int { return 2 }
+}
+
+// SIL:   [[DIFFERENT_WRAPPED:%.+]] = function_ref @$S8def_func16differentWrapped1a1bSbx_q_tAA0D0RzAaER_5ValueQy_AFRtzr0_lF : $@convention(thin) <τ_0_0, τ_0_1 where τ_0_0 : Wrapped, τ_0_1 : Wrapped, τ_0_0.Value == τ_0_1.Value> (@in_guaranteed τ_0_0, @in_guaranteed τ_0_1) -> Bool
+
+
+_ = differentWrapped(a: IntWrapper1(), b: IntWrapper2())
+
+
+// SIL:   {{%.+}} = function_ref @$S8def_func10overloaded1xySi_tF : $@convention(thin) (Int) -> ()
+// SIL:   {{%.+}} = function_ref @$S8def_func10overloaded1xySb_tF : $@convention(thin) (Bool) -> ()
+
+overloaded(x: 1)
+overloaded(x: false)
+
+
+// SIL:   {{%.+}} = function_ref @primitive : $@convention(thin) () -> ()
+primitive()
+
+
+if raw == 5 {
+  testNoReturnAttr()
+  testNoReturnAttrPoly(x: 5)
+}
+// SIL: {{%.+}} = function_ref @$S8def_func16testNoReturnAttrs5NeverOyF : $@convention(thin) () -> Never
+// SIL: {{%.+}} = function_ref @$S8def_func20testNoReturnAttrPoly{{[_0-9a-zA-Z]*}}F : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> Never
+
+
+// SIL: sil @$S8def_func16testNoReturnAttrs5NeverOyF : $@convention(thin) () -> Never
+// SIL: sil @$S8def_func20testNoReturnAttrPoly{{[_0-9a-zA-Z]*}}F : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> Never
+
+do {
+  try throws1()
+  _ = try throws2(1)
+} catch _ {}
+// SIL: sil @$S8def_func7throws1yyKF : $@convention(thin) () -> @error Error
+// SIL: sil @$S8def_func7throws2{{[_0-9a-zA-Z]*}}F : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> (@out τ_0_0, @error Error)
+
+// LLVM: }
+
diff --git a/test/Serialization/plus_zero_objc.swift b/test/Serialization/plus_zero_objc.swift
new file mode 100644
index 0000000..787e961
--- /dev/null
+++ b/test/Serialization/plus_zero_objc.swift
@@ -0,0 +1,39 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %empty-directory(%t)
+// RUN: %target-swift-frontend -emit-module -o %t %S/Inputs/def_objc.swift -disable-objc-attr-requires-foundation-module
+// RUN: llvm-bcanalyzer %t/def_objc.swiftmodule | %FileCheck %s
+// RUN: %target-swift-frontend -emit-silgen -I %t %s -o - | %FileCheck %s -check-prefix=SIL
+
+// CHECK-NOT: UnknownCode
+
+import def_objc
+
+// SIL: sil hidden @$S4objc9testProto3objy04def_A09ObjCProto_p_tF : $@convention(thin) (@guaranteed ObjCProto) -> () {
+func testProto(obj obj: ObjCProto) {
+  // SIL: = objc_method {{%.*}} : $@opened({{.*}}) ObjCProto, #ObjCProto.doSomething!1.foreign
+  obj.doSomething()
+}
+
+// SIL: sil hidden @$S4objc9testClass3objy04def_A09ObjCClassC_tF : $@convention(thin) (@guaranteed ObjCClass) -> () {
+func testClass(obj obj: ObjCClass) {
+  // SIL: = objc_method %{{.+}} : $ObjCClass, #ObjCClass.implicitlyObjC!1.foreign
+  obj.implicitlyObjC()
+
+  // SIL: = objc_method %{{.+}} : $@objc_metatype ObjCClass.Type, #ObjCClass.classMethod!1.foreign
+  ObjCClass.classMethod()
+}
+
+// SIL: sil hidden @$S4objc15testNativeClass3objy04def_A012NonObjCClassC_tF : $@convention(thin) (@guaranteed NonObjCClass) -> () {
+func testNativeClass(obj obj: NonObjCClass) {
+  // SIL: = objc_method %{{.+}} : $NonObjCClass, #NonObjCClass.doSomething!1.foreign
+  // SIL: = objc_method %{{.+}} : $NonObjCClass, #NonObjCClass.objcMethod!1.foreign
+  obj.doSomething()
+  obj.objcMethod()
+
+  // SIL: objc_method [[OBJ:%[0-9]+]] : $NonObjCClass, #NonObjCClass.objcProp!getter.1.foreign
+  var x = obj.objcProp
+  
+  // SIL: objc_method [[OBJ:%[0-9]+]] : $NonObjCClass, #NonObjCClass.subscript!getter.1.foreign
+  _ = obj[42]
+}
+
diff --git a/test/Serialization/plus_zero_serialize_attr.swift b/test/Serialization/plus_zero_serialize_attr.swift
new file mode 100644
index 0000000..ea32612
--- /dev/null
+++ b/test/Serialization/plus_zero_serialize_attr.swift
@@ -0,0 +1,84 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %empty-directory(%t)
+// RUN: %target-swift-frontend -emit-module -parse-as-library -o %t %s
+// RUN: llvm-bcanalyzer %t/serialize_attr.swiftmodule | %FileCheck %s -check-prefix=BCANALYZER
+// RUN: %target-sil-opt -enable-sil-verify-all -disable-sil-linking %t/serialize_attr.swiftmodule | %FileCheck %s
+
+// BCANALYZER-NOT: UnknownCode
+
+// @_semantics
+// -----------------------------------------------------------------------------
+
+//CHECK-DAG: @_semantics("crazy") func foo()
+@_inlineable
+@_versioned
+@_semantics("crazy") func foo() -> Int  { return 5}
+
+// @_optimize
+// -----------------------------------------------------------------------------
+
+//CHECK-DAG: @_optimize(none) func test_onone()
+@_inlineable
+@_versioned
+@_optimize(none)
+func test_onone() -> Int  { return 5}
+
+//CHECK-DAG: @_optimize(speed) func test_ospeed()
+@_inlineable
+@_versioned
+@_optimize(speed)
+func test_ospeed() -> Int  { return 5}
+ 
+//CHECK-DAG: @_optimize(size) func test_osize()
+@_inlineable
+@_versioned
+@_optimize(size)
+func test_osize() -> Int  { return 5}
+
+// @_specialize
+// -----------------------------------------------------------------------------
+
+// These lines should be contiguous.
+// CHECK-DAG: @_specialize(exported: false, kind: full, where T == Int, U == Float)
+// CHECK-DAG: func specializeThis<T, U>(_ t: T, u: U)
+@_inlineable
+@_versioned
+@_specialize(where T == Int, U == Float)
+func specializeThis<T, U>(_ t: T, u: U) {}
+
+public protocol PP {
+  associatedtype PElt
+}
+public protocol QQ {
+  associatedtype QElt
+}
+
+public struct RR : PP {
+  public typealias PElt = Float
+}
+public struct SS : QQ {
+  public typealias QElt = Int
+}
+
+public struct GG<T : PP> {}
+
+// These three lines should be contiguous, however, there is no way to
+// sequence FileCheck directives while using CHECK-DAG as the outer
+// label, and the declaration order is unpredictable.
+//
+// CHECK-DAG: class CC<T> where T : PP {
+// CHECK-DAG: @_specialize(exported: false, kind: full, where T == RR, U == SS)
+// CHECK-DAG: @inline(never) func foo<U>(_ u: U, g: GG<T>) -> (U, GG<T>) where U : QQ
+public class CC<T : PP> {
+  @_inlineable
+  @_versioned
+  @inline(never)
+  @_specialize(where T==RR, U==SS)
+  func foo<U : QQ>(_ u: U, g: GG<T>) -> (U, GG<T>) {
+    return (u, g)
+  }
+}
+
+// CHECK-DAG: sil [serialized] [_specialize exported: false, kind: full, where T == Int, U == Float] [canonical] @$S14serialize_attr14specializeThis_1uyx_q_tr0_lF : $@convention(thin) <T, U> (@in_guaranteed T, @in_guaranteed U) -> () {
+
+// CHECK-DAG: sil [serialized] [noinline] [_specialize exported: false, kind: full, where T == RR, U == SS] [canonical] @$S14serialize_attr2CCC3foo_1gqd___AA2GGVyxGtqd___AHtAA2QQRd__lF : $@convention(method) <T where T : PP><U where U : QQ> (@in_guaranteed U, GG<T>, @guaranteed CC<T>) -> (@out U, GG<T>) {
diff --git a/test/Serialization/plus_zero_transparent-std.swift b/test/Serialization/plus_zero_transparent-std.swift
new file mode 100644
index 0000000..0a92f03
--- /dev/null
+++ b/test/Serialization/plus_zero_transparent-std.swift
@@ -0,0 +1,58 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %empty-directory(%t)
+// RUN: %target-swift-frontend -emit-module -parse-stdlib -o %t %S/Inputs/def_transparent_std.swift
+// RUN: llvm-bcanalyzer %t/def_transparent_std.swiftmodule | %FileCheck %s
+// RUN: %target-swift-frontend -assume-parsing-unqualified-ownership-sil -emit-sil -sil-debug-serialization -parse-stdlib -I %t %s | %FileCheck %s -check-prefix=SIL
+
+// CHECK-NOT: UnknownCode
+
+import def_transparent_std
+
+// SIL-LABEL: sil public_external [transparent] [serialized] [canonical] @$S19def_transparent_std3foo1x1yBi1_Bi1__Bi1_tF : $@convention(thin) (Builtin.Int1, Builtin.Int1) -> Builtin.Int1 {
+// SIL: = builtin "cmp_eq_Int1"(%0 : $Builtin.Int1, %1 : $Builtin.Int1) : $Builtin.Int1
+func test_foo(x: Builtin.Int1, y: Builtin.Int1) -> Builtin.Int1 {
+  var a = foo(x: x, y: y)
+  return a
+}
+
+// SIL-LABEL: sil public_external [transparent] [serialized] [canonical] @$S19def_transparent_std12assign_tuple1x1yyBi64__Bot_BptF : $@convention(thin) (Builtin.Int64, @guaranteed Builtin.NativeObject, Builtin.RawPointer) -> () {
+// SIL: = tuple (%0 : $Builtin.Int64, %1 : $Builtin.NativeObject)
+// SIL: retain_value
+// SIL: = tuple_extract
+// SIL: = tuple_extract
+// SIL: = pointer_to_address
+// SIL: = tuple
+// SIL: = load
+func test_tuple(x: (Builtin.Int64, Builtin.NativeObject),
+                y: Builtin.RawPointer) {
+  assign_tuple(x: x, y: y)
+}
+
+func test_conversion(c: C, t32: Builtin.Int32) {
+// SIL-LABEL: sil public_external [transparent] [serialized] [canonical] @$S19def_transparent_std22class_to_native_object1cBoAA1CC_tF : $@convention(thin) (@guaranteed C) -> @owned Builtin.NativeObject {
+// SIL: bb0(%0 : $C):
+// SIL: unchecked_ref_cast %0 : $C to $Builtin.NativeObject
+// SIL-NEXT: strong_retain
+// SIL-NEXT: return
+  var b = class_to_native_object(c: c)
+
+// SIL-LABEL: sil public_external [transparent] [serialized] [canonical] @$S19def_transparent_std24class_from_native_object1pAA1CCBo_tF : $@convention(thin) (@guaranteed Builtin.NativeObject) -> @owned C {
+// SIL: unchecked_ref_cast %0 : $Builtin.NativeObject to $C
+  var c = class_from_native_object(p: b)
+
+// SIL-LABEL: sil public_external [transparent] [serialized] [canonical] @$S19def_transparent_std20class_to_raw_pointer1cBpAA1CC_tF : $@convention(thin) (@guaranteed C) -> Builtin.RawPointer {
+// SIL: ref_to_raw_pointer %0 : $C to $Builtin.RawPointer
+  var d = class_to_raw_pointer(c: c)
+
+// SIL-LABEL: sil public_external [transparent] [serialized] [canonical] @$S19def_transparent_std22class_from_raw_pointer1pAA1CCBp_tF : $@convention(thin) (Builtin.RawPointer) -> @owned C {
+// SIL: raw_pointer_to_ref %0 : $Builtin.RawPointer to $C
+  var e = class_from_raw_pointer(p: d)
+
+// SIL-LABEL: sil public_external [transparent] [serialized] [canonical] @$S19def_transparent_std5gep321p1iBpBp_Bi32_tF : $@convention(thin) (Builtin.RawPointer, Builtin.Int32) -> Builtin.RawPointer {
+// SIL: index_raw_pointer %0 : $Builtin.RawPointer, %1 : $Builtin.Int32
+  var f = gep32(p: d, i: t32)
+
+// SIL-LABEL: sil public_external [transparent] [serialized] [canonical] @$S19def_transparent_std11destroy_obj1xyBp_tF : $@convention(thin) (Builtin.RawPointer) -> () {
+// SIL: pointer_to_address %0 : $Builtin.RawPointer to [strict] $*Builtin.NativeObject
+  destroy_obj(x: d)
+}
diff --git a/test/Serialization/plus_zero_transparent.swift b/test/Serialization/plus_zero_transparent.swift
new file mode 100644
index 0000000..3fd2497
--- /dev/null
+++ b/test/Serialization/plus_zero_transparent.swift
@@ -0,0 +1,73 @@
+// REQUIRES: plus_zero_runtime
+// RUN: %empty-directory(%t)
+// RUN: %target-swift-frontend -emit-module -o %t %S/Inputs/def_transparent.swift
+// RUN: llvm-bcanalyzer %t/def_transparent.swiftmodule | %FileCheck %s
+// RUN: %target-swift-frontend -emit-silgen -sil-link-all -I %t %s | %FileCheck %s -check-prefix=SIL
+
+// CHECK-NOT: UnknownCode
+
+import def_transparent
+
+// SIL-LABEL: sil @main : $@convention(c) (Int32, UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>) -> Int32 {
+// SIL: [[RAW:%.+]] = global_addr @$S11transparent3rawSbvp : $*Bool
+// SIL: [[FUNC:%.+]] = function_ref @$S15def_transparent15testTransparent1xS2b_tF : $@convention(thin) (Bool) -> Bool
+// SIL: [[RESULT:%.+]] = apply [[FUNC]]({{%.+}}) : $@convention(thin) (Bool) -> Bool
+// SIL: store [[RESULT]] to [trivial] [[RAW]] : $*Bool
+var raw = testTransparent(x: false)
+
+// SIL: [[TMP:%.+]] = global_addr @$S11transparent3tmps5Int32Vvp : $*Int32
+// SIL: [[FUNC2:%.+]] = function_ref @$S15def_transparent11testBuiltins5Int32VyF : $@convention(thin) () -> Int32
+// SIL: [[RESULT2:%.+]] = apply [[FUNC2]]() : $@convention(thin) () -> Int32
+// SIL: store [[RESULT2]] to [trivial] [[TMP]] : $*Int32
+var tmp = testBuiltin()
+
+// SIL-LABEL: sil public_external [transparent] [serialized] [canonical] @$S15def_transparent15testTransparent1xS2b_tF : $@convention(thin) (Bool) -> Bool {
+// SIL: bb0(%0 : $Bool):
+// SIL: return %0 : $Bool
+
+// SIL-LABEL: sil public_external [transparent] [serialized] [canonical] @$S15def_transparent11testBuiltins5Int32VyF : $@convention(thin) () -> Int32 {
+// SIL: bb0:
+// SIL: integer_literal $Builtin.Int32, 300
+// SIL: string_literal utf8 "foo"
+// SIL: return %{{.*}} : $Int32
+
+// SIL-LABEL: sil public_external [transparent] [serialized] [canonical] @$S15def_transparent7test_bryyF : $@convention(thin) () -> () {
+// SIL: bb{{.*}}:
+// SIL: cond_br %{{.*}}, bb{{.*}}, bb{{.*}}
+// SIL: bb{{.*}}:
+// SIL: br bb{{.*}}
+func wrap_br() {
+  test_br()
+}
+
+// SIL-LABEL: sil public_external [serialized] [canonical] @$S15def_transparent9do_switch1uyAA9MaybePairO_tF : $@convention(thin) (@guaranteed MaybePair) -> () {
+// SIL: bb0(%0 : $MaybePair):
+// SIL: retain_value %0 : $MaybePair
+// SIL: switch_enum %0 : $MaybePair, case #MaybePair.Neither!enumelt: bb[[CASE1:[0-9]+]], case #MaybePair.Left!enumelt.1: bb[[CASE2:[0-9]+]], case #MaybePair.Right!enumelt.1: bb[[CASE3:[0-9]+]], case #MaybePair.Both!enumelt.1: bb[[CASE4:[0-9]+]]
+// SIL: bb[[CASE4]](%{{.*}} : $(Int32, String)):
+// SIL: bb[[CASE3]](%{{.*}} : $String):
+// SIL: bb[[CASE2]](%{{.*}} : $Int32):
+// SIL: bb[[CASE1]]:
+func test_switch(u: MaybePair) {
+  do_switch(u: u)
+}
+
+// SIL-LABEL: sil public_external [transparent] [serialized] [canonical] @$S15def_transparent7WrapperV3ValACs5Int32V_tcfC : $@convention(method) (Int32, @thin Wrapper.Type) -> Wrapper {
+// SIL-LABEL: sil public_external [transparent] [serialized] [canonical] @$S15def_transparent7WrapperV8getValue{{[_0-9a-zA-Z]*}}F : $@convention(method) (Wrapper) -> Int32 {
+// SIL-LABEL: sil public_external [transparent] [serialized] [canonical] @$S15def_transparent7WrapperV10valueAgains5Int32Vvg : $@convention(method) (Wrapper) -> Int32 {
+// SIL-LABEL: sil public_external [transparent] [serialized] [canonical] @$S15def_transparent7WrapperV13getValueAgain{{[_0-9a-zA-Z]*}}F : $@convention(method) (Wrapper) -> Int32 {
+func test_wrapper() {
+  var w = Wrapper(Val: 42)
+  
+  print(w.value, terminator: "")
+  print(w.getValue(), terminator: "")
+  print(w.valueAgain, terminator: "")
+  print(w.getValueAgain(), terminator: "")
+}
+
+// SIL-LABEL: sil public_external [transparent] [serialized] [canonical] @$S15def_transparent17open_existentials1p2cpyAA1P_p_AA2CP_ptF
+func test_open_existentials(p: P, cp: CP) {
+  // SIL: open_existential_addr immutable_access [[EXIST:%[0-9]+]] : $*P to $*@opened([[N:".*"]]) P
+  // SIL: open_existential_ref [[EXIST:%[0-9]+]] : $CP to $@opened([[M:".*"]]) CP
+  open_existentials(p: p, cp: cp)
+}
diff --git a/test/Serialization/serialize_attr.swift b/test/Serialization/serialize_attr.swift
index 8456016..501abe1 100644
--- a/test/Serialization/serialize_attr.swift
+++ b/test/Serialization/serialize_attr.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %empty-directory(%t)
 // RUN: %target-swift-frontend -emit-module -parse-as-library -o %t %s
 // RUN: llvm-bcanalyzer %t/serialize_attr.swiftmodule | %FileCheck %s -check-prefix=BCANALYZER
diff --git a/test/Serialization/transparent-std.swift b/test/Serialization/transparent-std.swift
index 76f887d..1e51fae 100644
--- a/test/Serialization/transparent-std.swift
+++ b/test/Serialization/transparent-std.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %empty-directory(%t)
 // RUN: %target-swift-frontend -emit-module -parse-stdlib -o %t %S/Inputs/def_transparent_std.swift
 // RUN: llvm-bcanalyzer %t/def_transparent_std.swiftmodule | %FileCheck %s
diff --git a/test/Serialization/transparent.swift b/test/Serialization/transparent.swift
index 72a46a3..89f29dd 100644
--- a/test/Serialization/transparent.swift
+++ b/test/Serialization/transparent.swift
@@ -1,3 +1,4 @@
+// REQUIRES: plus_one_runtime
 // RUN: %empty-directory(%t)
 // RUN: %target-swift-frontend -emit-module -o %t %S/Inputs/def_transparent.swift
 // RUN: llvm-bcanalyzer %t/def_transparent.swiftmodule | %FileCheck %s
diff --git a/test/lit.site.cfg.in b/test/lit.site.cfg.in
index 0b5957b..c8c7a39 100644
--- a/test/lit.site.cfg.in
+++ b/test/lit.site.cfg.in
@@ -36,6 +36,8 @@
 config.coverage_mode = "@SWIFT_ANALYZE_CODE_COVERAGE@"
 config.lldb_build_root = "@LLDB_BUILD_DIR@"
 
+# Please remember to handle empty strings and/or unset variables correctly.
+
 if "@SWIFT_ASAN_BUILD@" == "TRUE":
     config.available_features.add("asan")
 else:
@@ -89,10 +91,10 @@
 if "@SWIFT_ENABLE_SOURCEKIT_TESTS@" == "TRUE":
     config.available_features.add('sourcekit')
 
-if "@SWIFT_ENABLE_GUARANTEED_NORMAL_ARGUMENTS@" == "FALSE":
-   config.available_features.add('plus_one_runtime')
-else:
+if "@SWIFT_ENABLE_GUARANTEED_NORMAL_ARGUMENTS@" == "TRUE":
    config.available_features.add('plus_zero_runtime')
+else:
+   config.available_features.add('plus_one_runtime')
 
 # Let the main config do the real work.
 if config.test_exec_root is None:
diff --git a/test/stdlib/CodableTests.swift b/test/stdlib/CodableTests.swift
index 8498145..566398c 100644
--- a/test/stdlib/CodableTests.swift
+++ b/test/stdlib/CodableTests.swift
@@ -117,7 +117,7 @@
 // MARK: - Tests
 class TestCodable : TestCodableSuper {
     // MARK: - AffineTransform
-#if os(OSX)
+#if os(macOS)
     lazy var affineTransformValues: [Int : AffineTransform] = [
         #line : AffineTransform.identity,
         #line : AffineTransform(),
@@ -776,7 +776,7 @@
     "test_UUID_Plist" : TestCodable.test_UUID_Plist,
 ]
 
-#if os(OSX)
+#if os(macOS)
     tests["test_AffineTransform_JSON"] = TestCodable.test_AffineTransform_JSON
     tests["test_AffineTransform_Plist"] = TestCodable.test_AffineTransform_Plist
 #endif
diff --git a/test/stdlib/ErrorHandling.swift b/test/stdlib/ErrorHandling.swift
index b733542..ea5d427 100644
--- a/test/stdlib/ErrorHandling.swift
+++ b/test/stdlib/ErrorHandling.swift
@@ -1,9 +1,6 @@
 // RUN: %target-run-simple-swift
 // REQUIRES: executable_test
 
-// FIXME: <https://bugs.swift.org/browse/SR-7146> 2 tests are failing on linux in optimized mode
-// UNSUPPORTED: OS=linux-gnu
-
 //
 // Tests for error handling in standard library APIs.
 //
diff --git a/test/stdlib/FloatConstants.swift b/test/stdlib/FloatConstants.swift
index e3847f4..5d40927 100644
--- a/test/stdlib/FloatConstants.swift
+++ b/test/stdlib/FloatConstants.swift
@@ -1,6 +1,6 @@
 // RUN: %target-typecheck-verify-swift
 
-#if os(OSX) || os(iOS) || os(watchOS) || os(tvOS)
+#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS)
 import Darwin
 #elseif os(Linux) || os(FreeBSD) || os(PS4) || os(Android)
 import Glibc
diff --git a/test/stdlib/FloatingPoint.swift.gyb b/test/stdlib/FloatingPoint.swift.gyb
index 24cd535..6df78cb 100644
--- a/test/stdlib/FloatingPoint.swift.gyb
+++ b/test/stdlib/FloatingPoint.swift.gyb
@@ -577,8 +577,8 @@
 %for Self in ['Float', 'Double']:
 FloatingPoint.test("${Self}.nextUp, .nextDown/nan") {
   let x = ${Self}.nan
-  expectBitwiseEqual(x, x.nextUp)
-  expectBitwiseEqual(x, x.nextDown)
+  expectTrue(x.nextUp.isNaN)
+  expectTrue(x.nextDown.isNaN)
   expectTrue((-x).nextDown.isNaN)
   expectTrue((-x).nextUp.isNaN)
 }
diff --git a/test/stdlib/MathConstants.swift b/test/stdlib/MathConstants.swift
index fd3c3a0..2ecc54d 100644
--- a/test/stdlib/MathConstants.swift
+++ b/test/stdlib/MathConstants.swift
@@ -1,6 +1,6 @@
 // RUN: %target-typecheck-verify-swift
 
-#if os(OSX) || os(iOS) || os(watchOS) || os(tvOS)
+#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS)
 import Darwin
 #elseif os(Linux) || os(FreeBSD) || os(PS4) || os(Android)
 import Glibc
diff --git a/test/stdlib/Metal.swift b/test/stdlib/Metal.swift
index cb6d50e..682df24 100644
--- a/test/stdlib/Metal.swift
+++ b/test/stdlib/Metal.swift
@@ -72,7 +72,7 @@
       /* Setup */
 
       let device = MTLCreateSystemDefaultDevice()!
-      #if os(OSX)
+      #if os(macOS)
         let options = MTLResourceOptions.storageModeManaged
       #else
         let options = MTLResourceOptions.storageModePrivate
@@ -81,7 +81,7 @@
 
       /* Call APIs */
 
-      #if os(OSX)
+      #if os(macOS)
         buf.didModifyRange(0..<4)
       #endif
       buf.addDebugMarker("test marker", range: 0..<4)
@@ -97,7 +97,7 @@
       let queue = device.makeCommandQueue()!
       let cmdBuf = queue.makeCommandBuffer()!
 
-      #if os(OSX)
+      #if os(macOS)
         let options = MTLResourceOptions.storageModeManaged
       #else
         let options = MTLResourceOptions.storageModePrivate
@@ -162,7 +162,7 @@
       let queue = device.makeCommandQueue()!
       let cmdBuf = queue.makeCommandBuffer()!
 
-      #if os(OSX)
+      #if os(macOS)
         let options = MTLResourceOptions.storageModeManaged
       #else
         let options = MTLResourceOptions.storageModePrivate
@@ -182,7 +182,7 @@
       let encoder = cmdBuf.makeRenderCommandEncoder(descriptor: rpDesc)!
       encoder.useResources([buf], usage: MTLResourceUsage.read)
       encoder.useHeaps([heap])
-      #if os(OSX)
+      #if os(macOS)
         encoder.setViewports([MTLViewport()])
         encoder.setScissorRects([MTLScissorRect(x:0, y:0, width:1, height:1)])
       #endif
diff --git a/test/stdlib/NSStringAPI.swift b/test/stdlib/NSStringAPI.swift
index ac7bd20..cf9afb9 100644
--- a/test/stdlib/NSStringAPI.swift
+++ b/test/stdlib/NSStringAPI.swift
@@ -1329,7 +1329,7 @@
 }
 
 func getHomeDir() -> String {
-#if os(OSX)
+#if os(macOS)
   return String(cString: getpwuid(getuid()).pointee.pw_dir)
 #elseif os(iOS) || os(tvOS) || os(watchOS)
   // getpwuid() returns null in sandboxed apps under iOS simulator.
diff --git a/test/stdlib/NSValueBridging.swift.gyb b/test/stdlib/NSValueBridging.swift.gyb
index 685aadf..5b322b8 100644
--- a/test/stdlib/NSValueBridging.swift.gyb
+++ b/test/stdlib/NSValueBridging.swift.gyb
@@ -59,7 +59,7 @@
 // For historic reasons, macOS has different NSValue methods for the
 // CoreGraphics types from other Apple platforms.
 
-#if os(OSX)
+#if os(macOS)
 
 ${ testCase("CGRect",            "CGRect(x: 17, y: 38, width: 6, height: 79)", "rect",  "(==)") }
 ${ testCase("CGPoint",           "CGPoint(x: 17, y: 38)",                      "point", "(==)") }
diff --git a/test/stdlib/Reflection_objc.swift b/test/stdlib/Reflection_objc.swift
index 28286f7..414221c 100644
--- a/test/stdlib/Reflection_objc.swift
+++ b/test/stdlib/Reflection_objc.swift
@@ -15,7 +15,7 @@
 import Swift
 import Foundation
 
-#if os(OSX)
+#if os(macOS)
 import AppKit
 
 typealias OSImage = NSImage
diff --git a/test/stdlib/Runtime.swift.gyb b/test/stdlib/Runtime.swift.gyb
index e386aac..67ee2bf 100644
--- a/test/stdlib/Runtime.swift.gyb
+++ b/test/stdlib/Runtime.swift.gyb
@@ -9,7 +9,7 @@
 import StdlibUnittest
 import SwiftShims
 
-#if os(OSX) || os(iOS) || os(watchOS) || os(tvOS)
+#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS)
 import Darwin
 #elseif os(Linux) || os(FreeBSD) || os(PS4) || os(Android)
 import Glibc
@@ -553,7 +553,7 @@
 }
 
 Runtime.test("SwiftError layout constants for LLDB") {
-#if os(OSX) || os(iOS) || os(watchOS) || os(tvOS)
+#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS)
   let RTLD_DEFAULT = UnsafeMutableRawPointer(bitPattern: -2)
 #elseif os(Linux)
   let RTLD_DEFAULT = UnsafeMutableRawPointer(bitPattern: 0)
@@ -565,7 +565,7 @@
     dlsym(RTLD_DEFAULT, "_swift_lldb_offsetof_SwiftError_typeMetadata")!
   let sizeof_SwiftError =
     dlsym(RTLD_DEFAULT, "_swift_lldb_sizeof_SwiftError")!
-#if os(OSX) || os(iOS) || os(watchOS) || os(tvOS)
+#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS)
 #if arch(i386) || arch(arm)
   expectEqual(20, offsetof_SwiftError_typeMetadata.load(as: UInt.self))
   expectEqual(36, sizeof_SwiftError.load(as: UInt.self))
@@ -1671,7 +1671,7 @@
 
 // _stdlib_isOSVersionAtLeast is broken for
 // watchOS. rdar://problem/20234735
-#if os(OSX) || os(iOS) || os(tvOS) || os(watchOS)
+#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
   // This test assumes that no version component on an OS we test upon
   // will ever be greater than 1066 and that every major version will always
   // be greater than 1.
diff --git a/test/stdlib/TestAffineTransform.swift b/test/stdlib/TestAffineTransform.swift
index ad2b07a..a0b384a 100644
--- a/test/stdlib/TestAffineTransform.swift
+++ b/test/stdlib/TestAffineTransform.swift
@@ -12,7 +12,7 @@
 
 import Foundation
 
-#if os(OSX)
+#if os(macOS)
 
 #if FOUNDATION_XCTEST
 import XCTest
diff --git a/test/stdlib/TestURL.swift b/test/stdlib/TestURL.swift
index 637e043..8c0128c 100644
--- a/test/stdlib/TestURL.swift
+++ b/test/stdlib/TestURL.swift
@@ -67,7 +67,7 @@
         }
     }
     
-#if os(OSX)
+#if os(macOS)
     func testQuarantineProperties() {
         // Test the quarantine stuff; it has special logic
         if #available(OSX 10.11, iOS 9.0, *) {
@@ -383,7 +383,7 @@
 URLTests.test("testBasics") { TestURL().testBasics() }
 URLTests.test("testProperties") { TestURL().testProperties() }
 URLTests.test("testSetProperties") { TestURL().testSetProperties() }
-#if os(OSX)
+#if os(macOS)
 URLTests.test("testQuarantineProperties") { TestURL().testQuarantineProperties() }
 #endif
 URLTests.test("testMoreSetProperties") { TestURL().testMoreSetProperties() }
diff --git a/tools/SourceKit/cmake/modules/AddSwiftSourceKit.cmake b/tools/SourceKit/cmake/modules/AddSwiftSourceKit.cmake
index 441c019..6b8b3f3 100644
--- a/tools/SourceKit/cmake/modules/AddSwiftSourceKit.cmake
+++ b/tools/SourceKit/cmake/modules/AddSwiftSourceKit.cmake
@@ -238,9 +238,9 @@
     add_dependencies(${name} ${LLVM_COMMON_DEPENDS})
   endif()
 
-  target_link_libraries(${name} ${SOURCEKITEXE_LINK_LIBS})
+  target_link_libraries(${name} PRIVATE ${SOURCEKITEXE_LINK_LIBS})
   swift_common_llvm_config(${name} ${SOURCEKITEXE_LLVM_COMPONENT_DEPENDS})
-  target_link_libraries(${name} ${LLVM_COMMON_LIBS})
+  target_link_libraries(${name} PRIVATE ${LLVM_COMMON_LIBS})
 
   set_target_properties(${name} PROPERTIES FOLDER "SourceKit executables")
   if (NOT SWIFT_ASAN_BUILD)
@@ -422,9 +422,9 @@
     add_dependencies(${name} ${LLVM_COMMON_DEPENDS})
   endif(LLVM_COMMON_DEPENDS)
 
-  target_link_libraries(${name} ${SOURCEKITXPC_LINK_LIBS})
+  target_link_libraries(${name} PRIVATE ${SOURCEKITXPC_LINK_LIBS})
   swift_common_llvm_config(${name} ${SOURCEKITXPC_LLVM_COMPONENT_DEPENDS})
-  target_link_libraries(${name} ${LLVM_COMMON_LIBS})
+  target_link_libraries(${name} PRIVATE ${LLVM_COMMON_LIBS})
 
   add_dependencies(${framework_target} ${name})
 
diff --git a/tools/SourceKit/lib/Support/ImmutableTextBuffer.cpp b/tools/SourceKit/lib/Support/ImmutableTextBuffer.cpp
index b42a3ed..5a12804 100644
--- a/tools/SourceKit/lib/Support/ImmutableTextBuffer.cpp
+++ b/tools/SourceKit/lib/Support/ImmutableTextBuffer.cpp
@@ -177,7 +177,8 @@
     Length += I.piece().size();
   }
 
-  auto MemBuf = llvm::MemoryBuffer::getNewUninitMemBuffer(Length, Filename);
+  auto MemBuf =
+    llvm::WritableMemoryBuffer::getNewUninitMemBuffer(Length, Filename);
   char *Ptr = (char*)MemBuf->getBufferStart();
   for (RewriteRope::iterator I = Rope.begin(), E = Rope.end(); I != E;
        I.MoveToNextPiece()) {
@@ -186,7 +187,7 @@
     Ptr += Text.size();
   }
 
-  return MemBuf;
+  return std::move(MemBuf);
 }
 
 ImmutableTextBufferRef EditableTextBuffer::getBufferForSnapshot(
diff --git a/tools/SourceKit/lib/SwiftLang/SwiftCompletion.cpp b/tools/SourceKit/lib/SwiftLang/SwiftCompletion.cpp
index c756578..7804d6c 100644
--- a/tools/SourceKit/lib/SwiftLang/SwiftCompletion.cpp
+++ b/tools/SourceKit/lib/SwiftLang/SwiftCompletion.cpp
@@ -156,10 +156,11 @@
   }
 
   const char *Position = InputFile->getBufferStart() + CodeCompletionOffset;
-  std::unique_ptr<llvm::MemoryBuffer> NewBuffer =
-      llvm::MemoryBuffer::getNewUninitMemBuffer(InputFile->getBufferSize() + 1,
+  std::unique_ptr<llvm::WritableMemoryBuffer> NewBuffer =
+      llvm::WritableMemoryBuffer::getNewUninitMemBuffer(
+                                              InputFile->getBufferSize() + 1,
                                               InputFile->getBufferIdentifier());
-  char *NewBuf = const_cast<char*>(NewBuffer->getBufferStart());
+  char *NewBuf = NewBuffer->getBufferStart();
   char *NewPos = std::copy(InputFile->getBufferStart(), Position, NewBuf);
   *NewPos = '\0';
   std::copy(Position, InputFile->getBufferEnd(), NewPos+1);
diff --git a/tools/SourceKit/tools/sourcekitd/lib/API/CompactArray.cpp b/tools/SourceKit/tools/sourcekitd/lib/API/CompactArray.cpp
index 8f9f978..914a4a3 100644
--- a/tools/SourceKit/tools/sourcekitd/lib/API/CompactArray.cpp
+++ b/tools/SourceKit/tools/sourcekitd/lib/API/CompactArray.cpp
@@ -71,10 +71,10 @@
 
 std::unique_ptr<llvm::MemoryBuffer>
 CompactArrayBuilderImpl::createBuffer() const {
-  std::unique_ptr<llvm::MemoryBuffer> Buf;
-  Buf = llvm::MemoryBuffer::getNewUninitMemBuffer(sizeInBytes());
-  copyInto(const_cast<char *>(Buf->getBufferStart()), Buf->getBufferSize());
-  return Buf;
+  std::unique_ptr<llvm::WritableMemoryBuffer> Buf;
+  Buf = llvm::WritableMemoryBuffer::getNewUninitMemBuffer(sizeInBytes());
+  copyInto(Buf->getBufferStart(), Buf->getBufferSize());
+  return std::move(Buf);
 }
 
 void CompactArrayBuilderImpl::appendTo(SmallVectorImpl<char> &Buf) const {
diff --git a/tools/SourceKit/tools/sourcekitd/lib/API/DocStructureArray.cpp b/tools/SourceKit/tools/sourcekitd/lib/API/DocStructureArray.cpp
index c03f0d8..c71cb00 100644
--- a/tools/SourceKit/tools/sourcekitd/lib/API/DocStructureArray.cpp
+++ b/tools/SourceKit/tools/sourcekitd/lib/API/DocStructureArray.cpp
@@ -249,11 +249,11 @@
   // * offset of top structure array (relative to structure array section) (1)
   size_t headerSize = sizeof(uint64_t) * 6;
 
-  auto result = llvm::MemoryBuffer::getNewUninitMemBuffer(
+  auto result = llvm::WritableMemoryBuffer::getNewUninitMemBuffer(
       inheritedTypesBufferSize + attrsBufferSize + elementsBufferSize +
       structureArrayBufferSize + structureBufferSize + headerSize);
 
-  char *start = const_cast<char *>(result->getBufferStart());
+  char *start = result->getBufferStart();
   char *headerPtr = start;
   char *ptr = start + headerSize;
 
@@ -277,7 +277,7 @@
   assert(headerPtr == start + (headerSize - sizeof(topOffset)));
   memcpy(headerPtr, &topOffset, sizeof(topOffset));
 
-  return result;
+  return std::move(result);
 }
 
 namespace {
diff --git a/tools/SourceKit/tools/sourcekitd/lib/API/sourcekitdAPI-XPC.cpp b/tools/SourceKit/tools/sourcekitd/lib/API/sourcekitdAPI-XPC.cpp
index 4dedc75..60dffda 100644
--- a/tools/SourceKit/tools/sourcekitd/lib/API/sourcekitdAPI-XPC.cpp
+++ b/tools/SourceKit/tools/sourcekitd/lib/API/sourcekitdAPI-XPC.cpp
@@ -245,7 +245,7 @@
       CustomBufferKind Kind, std::unique_ptr<llvm::MemoryBuffer> MemBuf) {
 
   std::unique_ptr<llvm::MemoryBuffer> CustomBuf;
-  CustomBuf = llvm::MemoryBuffer::getNewUninitMemBuffer(
+  CustomBuf = llvm::WritableMemoryBuffer::getNewUninitMemBuffer(
       sizeof(uint64_t) + MemBuf->getBufferSize());
   char *BufPtr = (char*)CustomBuf->getBufferStart();
   *reinterpret_cast<uint64_t*>(BufPtr) = (uint64_t)Kind;
diff --git a/tools/SwiftSyntax/SyntaxNodes.swift.gyb b/tools/SwiftSyntax/SyntaxNodes.swift.gyb
index 7df2872..2d57718 100644
--- a/tools/SwiftSyntax/SyntaxNodes.swift.gyb
+++ b/tools/SwiftSyntax/SyntaxNodes.swift.gyb
@@ -196,7 +196,7 @@
 % end
 
 % for trait in TRAITS:
-public protocol ${trait.trait_name}Syntax {
+public protocol ${trait.trait_name}Syntax: Syntax {
 % for child in trait.children:
 %   ret_type = child.type_name
 %   if child.is_optional:
diff --git a/tools/driver/CMakeLists.txt b/tools/driver/CMakeLists.txt
index cd9f779..766d3d4 100644
--- a/tools/driver/CMakeLists.txt
+++ b/tools/driver/CMakeLists.txt
@@ -13,7 +13,7 @@
 )
 
 if(HAVE_UNICODE_LIBEDIT)
-  target_link_libraries(swift edit)
+  target_link_libraries(swift PRIVATE edit)
 endif()
 
 swift_create_post_build_symlink(swift
diff --git a/tools/sil-opt/SILOpt.cpp b/tools/sil-opt/SILOpt.cpp
index 1467da4..57a9951 100644
--- a/tools/sil-opt/SILOpt.cpp
+++ b/tools/sil-opt/SILOpt.cpp
@@ -326,7 +326,7 @@
   SILOpts.EnableSILOwnership = EnableSILOwnershipOpt;
   SILOpts.AssumeUnqualifiedOwnershipWhenParsing =
     AssumeUnqualifiedOwnershipWhenParsing;
-  SILOpts.EnableGuaranteedNormalArguments =
+  SILOpts.EnableGuaranteedNormalArguments |=
     EnableGuaranteedNormalArguments;
 
   SILOpts.VerifyExclusivity = VerifyExclusivity;
diff --git a/tools/swift-api-digester/swift-api-digester.cpp b/tools/swift-api-digester/swift-api-digester.cpp
index fbf14b9..8a41b3e 100644
--- a/tools/swift-api-digester/swift-api-digester.cpp
+++ b/tools/swift-api-digester/swift-api-digester.cpp
@@ -939,7 +939,7 @@
   SDKNodeInitInfo Info(Ctx);
   NodeVector Children;
 
-  for (auto Pair : *Node) {
+  for (auto &Pair : *Node) {
     switch(parseKeyKind(GetScalarString(Pair.getKey()))) {
     case KeyKind::KK_kind:
       Kind = parseSDKNodeKind(GetScalarString(Pair.getValue()));
diff --git a/tools/swift-ide-test/CMakeLists.txt b/tools/swift-ide-test/CMakeLists.txt
index e260cab..a3afd93 100644
--- a/tools/swift-ide-test/CMakeLists.txt
+++ b/tools/swift-ide-test/CMakeLists.txt
@@ -14,7 +14,7 @@
 # If libxml2 is available, make it available for swift-ide-test.
 if(SWIFT_HAVE_LIBXML)
   include_directories(SYSTEM ${LIBXML2_INCLUDE_DIR})
-  target_link_libraries(swift-ide-test ${LIBXML2_LIBRARIES})
+  target_link_libraries(swift-ide-test PRIVATE ${LIBXML2_LIBRARIES})
   add_definitions(-DSWIFT_HAVE_LIBXML="1")
 endif()
 
@@ -23,4 +23,4 @@
   SOURCE "${SWIFT_SOURCE_DIR}/utils/swift-api-dump.py"
   DESTINATION "${SWIFT_RUNTIME_OUTPUT_INTDIR}/swift-api-dump.py"
   COMMENT "Creating development symlink for swift-api-dump.py.")
-  
\ No newline at end of file
+
diff --git a/tools/swift-llvm-opt/LLVMOpt.cpp b/tools/swift-llvm-opt/LLVMOpt.cpp
index a744f42..2a7de50 100644
--- a/tools/swift-llvm-opt/LLVMOpt.cpp
+++ b/tools/swift-llvm-opt/LLVMOpt.cpp
@@ -37,7 +37,7 @@
 #include "llvm/Analysis/TargetLibraryInfo.h"
 #include "llvm/Analysis/TargetTransformInfo.h"
 #include "llvm/Bitcode/BitcodeWriterPass.h"
-#include "llvm/CodeGen/CommandFlags.h"
+#include "llvm/CodeGen/CommandFlags.def"
 #include "llvm/CodeGen/TargetPassConfig.h"
 #include "llvm/IR/DataLayout.h"
 #include "llvm/IR/DebugInfo.h"
@@ -136,7 +136,7 @@
 
   return TheTarget->createTargetMachine(
       TheTriple.getTriple(), CPUStr, FeaturesStr, Options,
-      Optional<Reloc::Model>(RelocModel), CMModel, GetCodeGenOptLevel());
+      Optional<Reloc::Model>(RelocModel), getCodeModel(), GetCodeGenOptLevel());
 }
 
 static void dumpOutput(llvm::Module &M, llvm::raw_ostream &os) {
@@ -271,14 +271,14 @@
     M->setTargetTriple(llvm::Triple::normalize(TargetTriple));
 
   // Figure out what stream we are supposed to write to...
-  std::unique_ptr<llvm::tool_output_file> Out;
+  std::unique_ptr<llvm::ToolOutputFile> Out;
   // Default to standard output.
   if (OutputFilename.empty())
     OutputFilename = "-";
 
   std::error_code EC;
   Out.reset(
-      new llvm::tool_output_file(OutputFilename, EC, llvm::sys::fs::F_None));
+      new llvm::ToolOutputFile(OutputFilename, EC, llvm::sys::fs::F_None));
   if (EC) {
     errs() << EC.message() << '\n';
     return 1;
diff --git a/tools/swift-remoteast-test/CMakeLists.txt b/tools/swift-remoteast-test/CMakeLists.txt
index 9ae0bb0..73f5ac4 100644
--- a/tools/swift-remoteast-test/CMakeLists.txt
+++ b/tools/swift-remoteast-test/CMakeLists.txt
@@ -8,7 +8,7 @@
 
 set_target_properties(swift-remoteast-test PROPERTIES ENABLE_EXPORTS 1)
 if(HAVE_UNICODE_LIBEDIT)
-  target_link_libraries(swift-remoteast-test edit)
+  target_link_libraries(swift-remoteast-test PRIVATE edit)
 endif()
 
 # If building as part of clang, make sure the headers are installed.
diff --git a/tools/swift-stdlib-tool/CMakeLists.txt b/tools/swift-stdlib-tool/CMakeLists.txt
index 0de9578..a585b1b 100644
--- a/tools/swift-stdlib-tool/CMakeLists.txt
+++ b/tools/swift-stdlib-tool/CMakeLists.txt
@@ -2,7 +2,7 @@
   swift-stdlib-tool.mm)
 
 find_library(FOUNDATION NAMES Foundation)
-target_link_libraries(swift-stdlib-tool ${FOUNDATION})
+target_link_libraries(swift-stdlib-tool PRIVATE ${FOUNDATION})
 
 swift_install_in_component(compiler
     TARGETS swift-stdlib-tool
diff --git a/unittests/AST/CMakeLists.txt b/unittests/AST/CMakeLists.txt
index 5c58c84..12f912d 100644
--- a/unittests/AST/CMakeLists.txt
+++ b/unittests/AST/CMakeLists.txt
@@ -7,6 +7,7 @@
 )
 
 target_link_libraries(SwiftASTTests
+   PRIVATE
    swiftAST
    # FIXME: Circular dependencies.
    swiftParse
diff --git a/unittests/Basic/CMakeLists.txt b/unittests/Basic/CMakeLists.txt
index 74613f7..4152a70 100644
--- a/unittests/Basic/CMakeLists.txt
+++ b/unittests/Basic/CMakeLists.txt
@@ -35,6 +35,7 @@
 add_dependencies(SwiftBasicTests "${gyb_dependency_targets}")
 
 target_link_libraries(SwiftBasicTests
+  PRIVATE
   swiftBasic
   clangBasic
   )
diff --git a/unittests/Driver/CMakeLists.txt b/unittests/Driver/CMakeLists.txt
index d96dd4a..d85fc16 100644
--- a/unittests/Driver/CMakeLists.txt
+++ b/unittests/Driver/CMakeLists.txt
@@ -3,5 +3,6 @@
 )
 
 target_link_libraries(SwiftDriverTests
+   PRIVATE
    swiftDriver
 )
diff --git a/unittests/IDE/CMakeLists.txt b/unittests/IDE/CMakeLists.txt
index ce0e38f..f55846d 100644
--- a/unittests/IDE/CMakeLists.txt
+++ b/unittests/IDE/CMakeLists.txt
@@ -3,5 +3,6 @@
   Placeholders.cpp
   )
 target_link_libraries(SwiftIDETests
+  PRIVATE
   swiftIDE
 )
diff --git a/unittests/Parse/CMakeLists.txt b/unittests/Parse/CMakeLists.txt
index b7c2f38..1eb943d 100644
--- a/unittests/Parse/CMakeLists.txt
+++ b/unittests/Parse/CMakeLists.txt
@@ -6,6 +6,7 @@
 )
 
 target_link_libraries(SwiftParseTests
+    PRIVATE
     swiftSIL
     swiftClangImporter
     swiftParse
diff --git a/unittests/Reflection/CMakeLists.txt b/unittests/Reflection/CMakeLists.txt
index 91ce58d..0354f0c 100644
--- a/unittests/Reflection/CMakeLists.txt
+++ b/unittests/Reflection/CMakeLists.txt
@@ -4,6 +4,7 @@
     add_swift_unittest(SwiftReflectionTests
       TypeRef.cpp)
     target_link_libraries(SwiftReflectionTests
+      PRIVATE
       swiftReflection${SWIFT_PRIMARY_VARIANT_SUFFIX})
   endif()
 endif()
diff --git a/unittests/SourceKit/Support/CMakeLists.txt b/unittests/SourceKit/Support/CMakeLists.txt
index 5f0e79d..da17a05 100644
--- a/unittests/SourceKit/Support/CMakeLists.txt
+++ b/unittests/SourceKit/Support/CMakeLists.txt
@@ -4,5 +4,6 @@
   )
 
 target_link_libraries(SourceKitSupportTests
+  PRIVATE
   SourceKitSupport
   )
diff --git a/unittests/SourceKit/SwiftLang/CMakeLists.txt b/unittests/SourceKit/SwiftLang/CMakeLists.txt
index fc89375..ca018cc 100644
--- a/unittests/SourceKit/SwiftLang/CMakeLists.txt
+++ b/unittests/SourceKit/SwiftLang/CMakeLists.txt
@@ -6,6 +6,7 @@
     )
 
   target_link_libraries(SourceKitSwiftLangTests
+    PRIVATE
     SourceKitSwiftLang
     )
 
diff --git a/unittests/SwiftDemangle/CMakeLists.txt b/unittests/SwiftDemangle/CMakeLists.txt
index f080917..9ba1aeb 100644
--- a/unittests/SwiftDemangle/CMakeLists.txt
+++ b/unittests/SwiftDemangle/CMakeLists.txt
@@ -7,6 +7,7 @@
   )
   
   target_link_libraries(SwiftDemangleTests
+    PRIVATE
     swiftDemangle
   )
 endif()
diff --git a/unittests/Syntax/CMakeLists.txt b/unittests/Syntax/CMakeLists.txt
index 1b9f0cf..20dc5d4 100644
--- a/unittests/Syntax/CMakeLists.txt
+++ b/unittests/Syntax/CMakeLists.txt
@@ -12,4 +12,5 @@
   )
 
 target_link_libraries(SwiftSyntaxTests
+  PRIVATE
   swiftSyntax)
diff --git a/unittests/runtime/CMakeLists.txt b/unittests/runtime/CMakeLists.txt
index 5d1c174..e504de1 100644
--- a/unittests/runtime/CMakeLists.txt
+++ b/unittests/runtime/CMakeLists.txt
@@ -56,6 +56,7 @@
 
   # FIXME: cross-compile for all variants.
   target_link_libraries(SwiftRuntimeTests
+    PRIVATE
     swiftCore${SWIFT_PRIMARY_VARIANT_SUFFIX}
     ${PLATFORM_TARGET_LINK_LIBRARIES}
     ${swift_runtime_test_extra_libraries}
diff --git a/unittests/runtime/LongTests/CMakeLists.txt b/unittests/runtime/LongTests/CMakeLists.txt
index 665cf5e..7b77ddb 100644
--- a/unittests/runtime/LongTests/CMakeLists.txt
+++ b/unittests/runtime/LongTests/CMakeLists.txt
@@ -48,6 +48,7 @@
 
   # FIXME: cross-compile for all variants.
   target_link_libraries(SwiftRuntimeLongTests
+    PRIVATE
     swiftCore${SWIFT_PRIMARY_VARIANT_SUFFIX}
     ${PLATFORM_TARGET_LINK_LIBRARIES}
     ${swift_runtime_test_extra_libraries}
diff --git a/utils/build-script-impl b/utils/build-script-impl
index 1f885b3..b7e70e3 100755
--- a/utils/build-script-impl
+++ b/utils/build-script-impl
@@ -70,7 +70,7 @@
     llvm-num-parallel-lto-link-jobs ""           "The number of parallel link jobs to use when compiling llvm"
     swift-stdlib-build-type     "Debug"          "the CMake build variant for Swift"
     swift-stdlib-enable-assertions "1"           "enable assertions in Swift"
-    swift-stdlib-enable-resilience "0"           "build the Swift stdlib and overlays with resilience enabled"
+    swift-stdlib-enable-resilience "1"           "build the Swift stdlib and overlays with resilience enabled"
     swift-stdlib-use-nonatomic-rc "0"            "build the Swift stdlib and overlays with nonatomic reference count operations enabled"
     lldb-build-type             "Debug"          "the CMake build variant for LLDB"
     lldb-build-with-xcode       "1"              "Use xcodebuild to build LLDB, instead of CMake"
@@ -2346,6 +2346,15 @@
                         fi
                         ;;
                 esac
+                if [[ "${BUILD_TOOLCHAIN_ONLY}" ]]; then
+                    cmake_options+=(
+                        -DLLDB_INCLUDE_TESTS=NO
+                        )
+                else
+                    cmake_options+=(
+                        -DLLDB_INCLUDE_TESTS=YES
+                    )
+                fi
                 ;;
             llbuild)
                 cmake_options=(
@@ -2823,16 +2832,17 @@
                 fi
                 call mkdir -p "${results_dir}"
                 with_pushd "${results_dir}" \
-                           call env SWIFTCC="$(build_directory $LOCAL_HOST swift)/bin/swiftc" \
-                           SWIFTLIBS="${swift_build_dir}/lib/swift" \
-                           "${LLDB_SOURCE_DIR}"/test/dotest.py \
-                           --executable "${lldb_executable}" \
-                           ${LLDB_TEST_DEBUG_SERVER} \
-                           ${LLDB_TEST_SUBDIR_CLAUSE} \
-                           ${LLDB_TEST_CATEGORIES} \
-                           ${LLDB_DOTEST_CC_OPTS} \
-                           ${LLDB_FORMATTER_OPTS} \
-                           -E "${DOTEST_EXTRA}"
+                    call env SWIFTCC="$(build_directory $LOCAL_HOST swift)/bin/swiftc" \
+                    SWIFTLIBS="${swift_build_dir}/lib/swift" \
+                    "${LLDB_SOURCE_DIR}"/test/dotest.py \
+                    --executable "${lldb_executable}" \
+                    ${LLDB_TEST_DEBUG_SERVER} \
+                    ${LLDB_TEST_SUBDIR_CLAUSE} \
+                    ${LLDB_TEST_CATEGORIES} \
+                    ${LLDB_DOTEST_CC_OPTS} \
+                    ${LLDB_FORMATTER_OPTS} \
+                    --build-dir "${lldb_build_dir}/lldb-test-build.noindex" \
+                    -E "${DOTEST_EXTRA}"
                 continue
                 ;;
             llbuild)
diff --git a/validation-test/stdlib/FixedPoint.swift.gyb b/validation-test/stdlib/FixedPoint.swift.gyb
index 6cecc0c..f405b05 100644
--- a/validation-test/stdlib/FixedPoint.swift.gyb
+++ b/validation-test/stdlib/FixedPoint.swift.gyb
@@ -51,15 +51,6 @@
     if dst <= ((1 << (dst_bits - 1)) - 1):
         return dst
     return dst - mask - 1
-
-def get_fixed_point_hash(bit_pattern, src_bits, word_bits):
-    if src_bits <= word_bits:
-        bit_pattern = prepare_bit_pattern(bit_pattern, src_bits, True)
-        return prepare_bit_pattern(bit_pattern, word_bits, True)
-    if src_bits == word_bits * 2:
-        return prepare_bit_pattern(
-            bit_pattern ^ (bit_pattern >> 32), word_bits, True)
-
 }%
 
 //===----------------------------------------------------------------------===//
@@ -250,8 +241,15 @@
 %     input = prepare_bit_pattern(bit_pattern, self_ty.bits, self_ty.is_signed)
     let input = get${Self}(${input})
     let output = getInt(input.hashValue)
-    let expected = getInt(${get_fixed_point_hash(input, self_ty.bits, word_bits)})
-    expectEqual(expected, output)
+
+    var hasher = _SipHash13(key: _Hasher._secretKey)
+%     if prepare_bit_pattern(input, word_bits, self_ty.is_signed) == input:
+    hasher.append(${input} as ${"" if self_ty.is_signed else "U"}Int)
+%     else:
+    hasher.append(input)
+%     end
+    let expected = getInt(Int(truncatingIfNeeded: hasher.finalize()))
+    expectEqual(expected, output, "input: \(input)")
   }
 
 %   end
@@ -269,7 +267,6 @@
   ${gyb.execute_template(
       hash_value_test_template,
       prepare_bit_pattern=prepare_bit_pattern,
-      get_fixed_point_hash=get_fixed_point_hash,
       test_bit_patterns=test_bit_patterns,
       word_bits=32)}
 
@@ -278,7 +275,6 @@
   ${gyb.execute_template(
       hash_value_test_template,
       prepare_bit_pattern=prepare_bit_pattern,
-      get_fixed_point_hash=get_fixed_point_hash,
       test_bit_patterns=test_bit_patterns,
       word_bits=64)}
 
diff --git a/validation-test/stdlib/Hashing.swift b/validation-test/stdlib/Hashing.swift
index 0018c42..a88498d 100644
--- a/validation-test/stdlib/Hashing.swift
+++ b/validation-test/stdlib/Hashing.swift
@@ -8,109 +8,65 @@
 
 var HashingTestSuite = TestSuite("Hashing")
 
-HashingTestSuite.test("_mixUInt32/GoldenValues") {
-  expectEqual(0x11b882c9, _mixUInt32(0x0))
-  expectEqual(0x60d0aafb, _mixUInt32(0x1))
-  expectEqual(0x636847b5, _mixUInt32(0xffff))
-  expectEqual(0x203f5350, _mixUInt32(0xffff_ffff))
-
-  expectEqual(0xb8747ef6, _mixUInt32(0xa62301f9))
-  expectEqual(0xef4eeeb2, _mixUInt32(0xfe1b46c6))
-  expectEqual(0xd44c9cf1, _mixUInt32(0xe4daf7ca))
-  expectEqual(0xfc1eb1de, _mixUInt32(0x33ff6f5c))
-  expectEqual(0x5605f0c0, _mixUInt32(0x13c2a2b8))
-  expectEqual(0xd9c48026, _mixUInt32(0xf3ad1745))
-  expectEqual(0x471ab8d0, _mixUInt32(0x656eff5a))
-  expectEqual(0xfe265934, _mixUInt32(0xfd2268c9))
+func checkHash(
+  for value: UInt64,
+  withKey key: (UInt64, UInt64),
+  expected: UInt64,
+  file: String = #file, line: UInt = #line
+) {
+  var hasher = _Hasher(key: key)
+  hasher.append(bits: value)
+  let hash = hasher.finalize()
+  expectEqual(
+    hash, Int(truncatingIfNeeded: expected),
+    file: file, line: line)
 }
 
-HashingTestSuite.test("_mixInt32/GoldenValues") {
-  expectEqual(Int32(bitPattern: 0x11b882c9 as UInt32), _mixInt32(0x0))
+HashingTestSuite.test("_Hasher/CustomKeys") {
+  // This assumes _Hasher implements SipHash-1-3.
+  checkHash(for: 0, withKey: (0, 0), expected: 0xbd60acb658c79e45)
+  checkHash(for: 0, withKey: (0, 1), expected: 0x1ce32b0b44e61175)
+  checkHash(for: 0, withKey: (1, 0), expected: 0x9c44b7c8df2ca74b)
+  checkHash(for: 0, withKey: (1, 1), expected: 0x9653ca0a3b455506)
+  checkHash(for: 0, withKey: (.max, .max), expected: 0x3ab336a4895e4d36)
+
+  checkHash(for: 1, withKey: (0, 0), expected: 0x1e9f734161d62dd9)
+  checkHash(for: 1, withKey: (0, 1), expected: 0xb6fcf32d09f76cba)
+  checkHash(for: 1, withKey: (1, 0), expected: 0xacb556b13007504a)
+  checkHash(for: 1, withKey: (1, 1), expected: 0x7defec680db51d24)
+  checkHash(for: 1, withKey: (.max, .max), expected: 0x212798441870ef6b)
+
+  checkHash(for: .max, withKey: (0, 0), expected: 0x2f205be2fec8e38d)
+  checkHash(for: .max, withKey: (0, 1), expected: 0x3ff7fa33381ecf7b)
+  checkHash(for: .max, withKey: (1, 0), expected: 0x404afd8eb2c4b22a)
+  checkHash(for: .max, withKey: (1, 1), expected: 0x855642d657c1bd46)
+  checkHash(for: .max, withKey: (.max, .max), expected: 0x5b16b7a8181980c2)
 }
 
-HashingTestSuite.test("_mixUInt64/GoldenValues") {
-  expectEqual(0xb2b2_4f68_8dc4_164d, _mixUInt64(0x0))
-  expectEqual(0x792e_33eb_0685_57de, _mixUInt64(0x1))
-  expectEqual(0x9ec4_3423_1b42_3dab, _mixUInt64(0xffff))
-  expectEqual(0x4cec_e9c9_01fa_9a84, _mixUInt64(0xffff_ffff))
-  expectEqual(0xcba5_b650_bed5_b87c, _mixUInt64(0xffff_ffff_ffff))
-  expectEqual(0xe583_5646_3fb8_ac99, _mixUInt64(0xffff_ffff_ffff_ffff))
+HashingTestSuite.test("_Hasher/DefaultKey") {
+  let value: UInt64 = 0x0102030405060708
 
-  expectEqual(0xf5d0079f828d43a5, _mixUInt64(0x94ce7d9319f8d233))
-  expectEqual(0x61900a6be9db9c3f, _mixUInt64(0x2728821e8c5b1f7))
-  expectEqual(0xf2fd34b1b7d4b46e, _mixUInt64(0xe7f67ec98c64f482))
-  expectEqual(0x216199ed628c821, _mixUInt64(0xd7c277b5438873ac))
-  expectEqual(0xb1b486ff5f2e0e53, _mixUInt64(0x8399f1d563c42f82))
-  expectEqual(0x61acc92bd91c030, _mixUInt64(0x488cefd48a2c4bfd))
-  expectEqual(0xa7a52d6e4a8e3ddf, _mixUInt64(0x270a15116c351f95))
-  expectEqual(0x98ceedc363c4e56a, _mixUInt64(0xe5fb9b5f6c426a84))
+  let defaultHash = _hashValue(for: value)
+
+  var defaultHasher = _Hasher()
+  defaultHasher.append(bits: value)
+  expectEqual(defaultHasher.finalize(), defaultHash)
+
+  var customHasher = _Hasher(key: _Hasher._secretKey)
+  customHasher.append(bits: value)
+  expectEqual(customHasher.finalize(), defaultHash)
 }
 
-HashingTestSuite.test("_mixUInt64/GoldenValues") {
-  expectEqual(Int64(bitPattern: 0xb2b2_4f68_8dc4_164d as UInt64), _mixInt64(0x0))
-}
+HashingTestSuite.test("_Hasher/keyOverride") {
+  let value: UInt64 = 0x0102030405060708
+  let expected = Int(truncatingIfNeeded: 0x661dac5d71c78013 as UInt64)
 
-HashingTestSuite.test("_mixUInt/GoldenValues") {
-#if arch(i386) || arch(arm)
-  expectEqual(0x11b8_82c9, _mixUInt(0x0))
-#elseif arch(x86_64) || arch(arm64) || arch(powerpc64) || arch(powerpc64le) || arch(s390x)
-  expectEqual(0xb2b2_4f68_8dc4_164d, _mixUInt(0x0))
-#else
-  fatalError("unimplemented")
-#endif
-}
+  let originalKey = _Hasher._secretKey
+  _Hasher._secretKey = (1, 2)
+  let hash = _hashValue(for: value)
+  _Hasher._secretKey = originalKey
 
-HashingTestSuite.test("_mixInt/GoldenValues") {
-#if arch(i386) || arch(arm)
-  expectEqual(Int(bitPattern: 0x11b8_82c9 as UInt), _mixInt(0x0))
-#elseif arch(x86_64) || arch(arm64) || arch(powerpc64) || arch(powerpc64le) || arch(s390x)
-  expectEqual(Int(bitPattern: 0xb2b2_4f68_8dc4_164d as UInt), _mixInt(0x0))
-#else
-  fatalError("unimplemented")
-#endif
-}
-
-HashingTestSuite.test("_squeezeHashValue/Int") {
-  // Check that the function can return values that cover the whole range.
-  func checkRange(_ r: Int) {
-    var results = Set<Int>()
-    for _ in 0..<(14 * r) {
-      let v = _squeezeHashValue(randInt(), r)
-      expectTrue(v < r)
-      results.insert(v)
-    }
-    expectEqual(r, results.count)
-  }
-  checkRange(1)
-  checkRange(2)
-  checkRange(4)
-  checkRange(8)
-  checkRange(16)
-}
-
-HashingTestSuite.test("String/hashValue/topBitsSet") {
-#if _runtime(_ObjC)
-#if arch(x86_64) || arch(arm64)
-  // Make sure that we don't accidentally throw away bits by storing the result
-  // of NSString.hash into an int in the runtime.
-
-  // This is the bit pattern that we xor to NSString's hash value.
-  let hashOffset = UInt(bitPattern: 0x429b_1266_0000_0000 as Int)
-  let hash = "efghijkl".hashValue
-  // When we are not equal to the top bit of the xor'ed hashOffset pattern
-  // there where some bits set.
-  let topHashBits = UInt(bitPattern: hash) & 0xffff_ffff_0000_0000
-  expectTrue(hash > 0)
-  expectTrue(topHashBits != hashOffset)
-#endif
-#endif
-}
-
-HashingTestSuite.test("overridePerExecutionHashSeed/overflow") {
-  // Test that we don't use checked arithmetic on the seed.
-  _HashingDetail.fixedSeedOverride = UInt64.max
-  expectEqual(0x4344_dc3a_239c_3e81, _mixUInt64(0xffff_ffff_ffff_ffff))
-  _HashingDetail.fixedSeedOverride = 0
+  expectEqual(hash, expected)
 }
 
 runAllTests()
diff --git a/validation-test/stdlib/HashingAvalanche.swift b/validation-test/stdlib/HashingAvalanche.swift
index 51b89da..09b3365 100644
--- a/validation-test/stdlib/HashingAvalanche.swift
+++ b/validation-test/stdlib/HashingAvalanche.swift
@@ -47,12 +47,12 @@
 
 // White-box testing: assume that the other N-bit to N-bit mixing functions
 // just dispatch to these.  (Avalanche test is relatively expensive.)
-HashingTestSuite.test("_mixUInt64/avalanche") {
-  avalancheTest(64, _mixUInt64, 0.02)
+HashingTestSuite.test("_Hasher.append(UInt64)/avalanche") {
+  avalancheTest(64, { UInt64(truncatingIfNeeded: _hashValue(for: $0)) }, 0.02)
 }
 
-HashingTestSuite.test("_mixUInt32/avalanche") {
-  avalancheTest(32, { UInt64(_mixUInt32(UInt32($0 & 0xffff_ffff))) }, 0.02)
+HashingTestSuite.test("_Hasher.append(UInt32)/avalanche") {
+  avalancheTest(32, { UInt64(truncatingIfNeeded: _hashValue(for: $0)) }, 0.02)
 }
 
 runAllTests()
diff --git a/validation-test/stdlib/SipHash.swift b/validation-test/stdlib/SipHash.swift
index cbf5edb..7bda072 100644
--- a/validation-test/stdlib/SipHash.swift
+++ b/validation-test/stdlib/SipHash.swift
@@ -243,12 +243,61 @@
 #endif
 }
 
+func loadPartialUnalignedUInt64LE(
+  from p: UnsafeRawPointer,
+  byteCount: Int
+) -> UInt64 {
+  _sanityCheck((0..<8).contains(byteCount))
+  var result: UInt64 = 0
+  if byteCount >= 1 { result |= UInt64(p.load(fromByteOffset: 0, as: UInt8.self)) }
+  if byteCount >= 2 { result |= UInt64(p.load(fromByteOffset: 1, as: UInt8.self)) &<< (8 as UInt64) }
+  if byteCount >= 3 { result |= UInt64(p.load(fromByteOffset: 2, as: UInt8.self)) &<< (16 as UInt64) }
+  if byteCount >= 4 { result |= UInt64(p.load(fromByteOffset: 3, as: UInt8.self)) &<< (24 as UInt64) }
+  if byteCount >= 5 { result |= UInt64(p.load(fromByteOffset: 4, as: UInt8.self)) &<< (32 as UInt64) }
+  if byteCount >= 6 { result |= UInt64(p.load(fromByteOffset: 5, as: UInt8.self)) &<< (40 as UInt64) }
+  if byteCount >= 7 { result |= UInt64(p.load(fromByteOffset: 6, as: UInt8.self)) &<< (48 as UInt64) }
+  return result
+}
+
+func loadPartialUnalignedUInt32LE(
+  from p: UnsafeRawPointer,
+  byteCount: Int
+) -> UInt32 {
+  _sanityCheck((0..<4).contains(byteCount))
+  var result: UInt32 = 0
+  if byteCount >= 1 { result |= UInt32(p.load(fromByteOffset: 0, as: UInt8.self)) }
+  if byteCount >= 2 { result |= UInt32(p.load(fromByteOffset: 1, as: UInt8.self)) &<< (8 as UInt32) }
+  if byteCount >= 3 { result |= UInt32(p.load(fromByteOffset: 2, as: UInt8.self)) &<< (16 as UInt32) }
+  return result
+}
+
+func loadPartialUnalignedUIntLE(
+  from p: UnsafeRawPointer,
+  byteCount: Int
+) -> UInt {
+#if arch(i386) || arch(arm)
+  return UInt(loadPartialUnalignedUInt32LE(from: p, byteCount: byteCount))
+#elseif arch(x86_64) || arch(arm64) || arch(powerpc64) || arch(powerpc64le) || arch(s390x)
+  return UInt(loadPartialUnalignedUInt64LE(from: p, byteCount: byteCount))
+#endif
+}
+
 % for data_type in ['Int', 'Int64', 'Int32']:
 func loadUnaligned${data_type}LE(
   from p: UnsafeRawPointer
 ) -> ${data_type} {
   return ${data_type}(bitPattern: loadUnalignedU${data_type}LE(from: p))
 }
+
+func loadPartialUnaligned${data_type}LE(
+  from p: UnsafeRawPointer,
+  byteCount: Int
+) -> ${data_type} {
+  return ${data_type}(
+    bitPattern: loadPartialUnalignedU${data_type}LE(
+      from: p,
+      byteCount: byteCount))
+}
 % end
 
 % for data_type in ['UInt', 'Int', 'UInt64', 'Int64', 'UInt32', 'Int32']:
@@ -257,85 +306,45 @@
 ) -> ${data_type} {
   return ${data_type}(littleEndian: loadUnaligned${data_type}LE(from: p))
 }
+func loadPartialUnaligned${data_type}(
+  from p: UnsafeRawPointer,
+  byteCount: Int
+) -> ${data_type} {
+  return ${data_type}(littleEndian:
+    loadPartialUnaligned${data_type}LE(from: p, byteCount: byteCount))
+}
 % end
 
 % for (Self, tests) in [
-%   ('_SipHash13Context', 'sipHash13Tests'),
-%   ('_SipHash24Context', 'sipHash24Tests')
+%   ('_SipHash13', 'sipHash13Tests'),
+%   ('_SipHash24', 'sipHash24Tests')
 % ]:
-SipHashTests.test("${Self}/Oneshot").forEach(in: ${tests}) {
-  test in
-
-  expectEqual(
-    test.output,
-    ${Self}.hash(
-      data: test.input,
-      dataByteCount: test.input.count,
-      key: test.key))
-}
-
-SipHashTests.test("${Self}.append(UnsafeRawPointer)")
-  .forEach(in: cartesianProduct(${tests}, incrementalPatterns)) {
-  test_ in
-  let (test, pattern) = test_
-
-  var context = ${Self}(key: test.key)
-  var startIndex = 0
-  var chunkSizeIndex = 0
-  while startIndex != test.input.endIndex {
-    let chunkSize = min(
-      pattern[chunkSizeIndex],
-      test.input.endIndex - startIndex)
-    context.append(
-      Array(test.input[startIndex..<(startIndex+chunkSize)]),
-      byteCount: chunkSize)
-    startIndex += chunkSize
-    chunkSizeIndex += 1
-    chunkSizeIndex %= pattern.count
-  }
-  expectEqual(
-    test.output,
-    context.finalizeAndReturnHash())
-
-  // Check that we can query the hash value more than once.
-  expectEqual(
-    test.output,
-    context.finalizeAndReturnHash())
-}
-
 % for data_type in ['UInt', 'Int', 'UInt64', 'Int64', 'UInt32', 'Int32']:
 SipHashTests.test("${Self}.append(${data_type})").forEach(in: ${tests}) {
   test in
 
-  var context = ${Self}(key: test.key)
+  var hasher = ${Self}(key: test.key)
 
   let chunkSize = MemoryLayout<${data_type}>.size
 
   var startIndex = 0
   let endIndex = test.input.count - (test.input.count % chunkSize)
   while startIndex != endIndex {
-    context.append(
+    hasher.append(
       loadUnaligned${data_type}(
         from: Array(
           test.input[startIndex..<(startIndex+chunkSize)])))
     startIndex += chunkSize
   }
-  context.append(
-    Array(test.input.suffix(from: endIndex)),
-    byteCount: test.input.count - endIndex)
-
-  expectEqual(
-    test.output,
-    context.finalizeAndReturnHash())
+  let tailCount = test.input.count - endIndex
+  let hash = hasher.finalize(
+    tailBytes: loadPartialUnalignedUInt64(
+      from: Array(test.input.suffix(from: endIndex)),
+      byteCount: tailCount),
+    tailByteCount: tailCount)
+  expectEqual(test.output, hash)
 }
 % end
-
-SipHashTests.test("${Self}/AppendAfterFinalizing") {
-  var context = ${Self}(key: (0, 0))
-  _ = context.finalizeAndReturnHash()
-  expectCrashLater()
-  context.append([], byteCount: 0)
-}
 % end
 
 runAllTests()