Merge pull request #14893 from jckarter/keypath-resilience-silgen-refactor

SILGen: Refactor key path component lowering.
diff --git a/CHANGELOG.md b/CHANGELOG.md
index ab7572c..59149f7 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -42,6 +42,8 @@
 	conditionally conforms to `P`, will succeed when the conditional
 	requirements are met.
 
+**Add new entries to the top of this file, not here!**
+
 Swift 4.1
 ---------
 
@@ -167,8 +169,6 @@
 
   If you wish to provide your own implementation of `==`/`hashValue`, you still can; a custom implementation will replace the one synthesized by the compiler.
 
-  **Add new entries to the top of this file, not here!**
-
 Swift 4.0
 ---------
 
@@ -6875,3 +6875,9 @@
 [SE-0191]: <https://github.com/apple/swift-evolution/blob/master/proposals/0191-eliminate-indexdistance.md>
 [SE-0192]: <https://github.com/apple/swift-evolution/blob/master/proposals/0192-non-exhaustive-enums.md>
 [SE-0193]: <https://github.com/apple/swift-evolution/blob/master/proposals/0193-cross-module-inlining-and-specialization.md>
+[SE-0194]: <https://github.com/apple/swift-evolution/blob/master/proposals/0194-derived-collection-of-enum-cases.md>
+[SE-0195]: <https://github.com/apple/swift-evolution/blob/master/proposals/0195-dynamic-member-lookup.md>
+[SE-0196]: <https://github.com/apple/swift-evolution/blob/master/proposals/0196-diagnostic-directives.md>
+[SE-0197]: <https://github.com/apple/swift-evolution/blob/master/proposals/0197-remove-where.md>
+[SE-0198]: <https://github.com/apple/swift-evolution/blob/master/proposals/0198-playground-quicklook-api-revamp.md>
+[SE-0199]: <https://github.com/apple/swift-evolution/blob/master/proposals/0199-bool-toggle.md>
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 717f920..e9281bf 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -194,14 +194,16 @@
 #
 
 foreach(sdk ANDROID;FREEBSD;LINUX;WINDOWS;HAIKU)
-  set(SWIFT_${sdk}_ICU_UC "" CACHE STRING
-      "Path to a directory containing the icuuc library for ${sdk}")
-  set(SWIFT_${sdk}_ICU_UC_INCLUDE "" CACHE STRING
-      "Path to a directory containing headers for icuuc for ${sdk}")
-  set(SWIFT_${sdk}_ICU_I18N "" CACHE STRING
-      "Path to a directory containing the icui18n library for ${sdk}")
-  set(SWIFT_${sdk}_ICU_I18N_INCLUDE "" CACHE STRING
-      "Path to a directory containing headers icui18n for ${sdk}")
+  foreach(arch aarch64;armv6;armv7;i686;powerpc64;powerpc64le;s390x;x86_64)
+    set(SWIFT_${sdk}_${arch}_ICU_UC "" CACHE STRING
+        "Path to a directory containing the icuuc library for ${sdk}")
+    set(SWIFT_${sdk}_${arch}_ICU_UC_INCLUDE "" CACHE STRING
+        "Path to a directory containing headers for icuuc for ${sdk}")
+    set(SWIFT_${sdk}_${arch}_ICU_I18N "" CACHE STRING
+        "Path to a directory containing the icui18n library for ${sdk}")
+    set(SWIFT_${sdk}_${arch}_ICU_I18N_INCLUDE "" CACHE STRING
+        "Path to a directory containing headers icui18n for ${sdk}")
+  endforeach()
 endforeach()
 
 #
diff --git a/cmake/modules/AddSwift.cmake b/cmake/modules/AddSwift.cmake
index 19bf777..f489be3 100644
--- a/cmake/modules/AddSwift.cmake
+++ b/cmake/modules/AddSwift.cmake
@@ -396,11 +396,11 @@
       endif()
   endif()
 
-  if(NOT "${SWIFT_${LFLAGS_SDK}_ICU_UC}" STREQUAL "")
-    list(APPEND library_search_directories "${SWIFT_${sdk}_ICU_UC}")
+  if(NOT "${SWIFT_${LFLAGS_SDK}_${LFLAGS_ARCH}_ICU_UC}" STREQUAL "")
+    list(APPEND library_search_directories "${SWIFT_${sdk}_${arch}_ICU_UC}")
   endif()
-  if(NOT "${SWIFT_${LFLAGS_SDK}_ICU_I18N}" STREQUAL "")
-    list(APPEND library_search_directories "${SWIFT_${sdk}_ICU_I18N}")
+  if(NOT "${SWIFT_${LFLAGS_SDK}_${LFLAGS_ARCH}_ICU_I18N}" STREQUAL "")
+    list(APPEND library_search_directories "${SWIFT_${sdk}_${arch}_ICU_I18N}")
   endif()
 
   if(NOT SWIFT_COMPILER_IS_MSVC_LIKE)
@@ -852,17 +852,17 @@
   _set_target_prefix_and_suffix("${target}" "${libkind}" "${SWIFTLIB_SINGLE_SDK}")
 
   if(SWIFTLIB_SINGLE_TARGET_LIBRARY)
-    if(NOT "${SWIFT_${SWIFTLIB_SINGLE_SDK}_ICU_UC_INCLUDE}" STREQUAL "" AND
-       NOT "${SWIFT_${SWIFTLIB_SINGLE_SDK}_ICU_UC_INCLUDE}" STREQUAL "/usr/include" AND
-       NOT "${SWIFT_${SWIFTLIB_SINGLE_SDK}_ICU_UC_INCLUDE}" STREQUAL "/usr/${SWIFT_SDK_${SWIFTLIB_SINGLE_SDK}_ARCH_${SWIFTLIB_SINGLE_ARCHITECTURE}_TRIPLE}/include" AND
-       NOT "${SWIFT_${SWIFTLIB_SINGLE_SDK}_ICU_UC_INCLUDE}" STREQUAL "/usr/${SWIFT_SDK_${SWIFT_HOST_VARIANT_SDK}_ARCH_${SWIFT_HOST_VARIANT_ARCH}_TRIPLE}/include")
-      target_include_directories("${target}" SYSTEM PRIVATE "${SWIFT_${SWIFTLIB_SINGLE_SDK}_ICU_UC_INCLUDE}")
+    if(NOT "${SWIFT_${SWIFTLIB_SINGLE_SDK}_${SWIFTLIB_SINGLE_ARCHITECTURE}_ICU_UC_INCLUDE}" STREQUAL "" AND
+       NOT "${SWIFT_${SWIFTLIB_SINGLE_SDK}_${SWIFTLIB_SINGLE_ARCHITECTURE}_ICU_UC_INCLUDE}" STREQUAL "/usr/include" AND
+       NOT "${SWIFT_${SWIFTLIB_SINGLE_SDK}_${SWIFTLIB_SINGLE_ARCHITECTURE}_ICU_UC_INCLUDE}" STREQUAL "/usr/${SWIFT_SDK_${SWIFTLIB_SINGLE_SDK}_ARCH_${SWIFTLIB_SINGLE_ARCHITECTURE}_TRIPLE}/include" AND
+       NOT "${SWIFT_${SWIFTLIB_SINGLE_SDK}_${SWIFTLIB_SINGLE_ARCHITECTURE}_ICU_UC_INCLUDE}" STREQUAL "/usr/${SWIFT_SDK_${SWIFT_HOST_VARIANT_SDK}_ARCH_${SWIFT_HOST_VARIANT_ARCH}_TRIPLE}/include")
+     target_include_directories("${target}" SYSTEM PRIVATE "${SWIFT_${SWIFTLIB_SINGLE_SDK}_${SWIFTLIB_SINGLE_ARCHITECTURE}_ICU_UC_INCLUDE}")
     endif()
-    if(NOT "${SWIFT_${SWIFTLIB_SINGLE_SDK}_ICU_I18N_INCLUDE}" STREQUAL "" AND
-       NOT "${SWIFT_${SWIFTLIB_SINGLE_SDK}_ICU_I18N_INCLUDE}" STREQUAL "/usr/include" AND
-       NOT "${SWIFT_${SWIFTLIB_SINGLE_SDK}_ICU_I18N_INCLUDE}" STREQUAL "/usr/${SWIFT_SDK_${SWIFTLIB_SINGLE_SDK}_ARCH_${SWIFTLIB_SINGLE_ARCHITECTURE}_TRIPLE}/include" AND
-       NOT "${SWIFT_${SWIFTLIB_SINGLE_SDK}_ICU_I18N_INCLUDE}" STREQUAL "/usr/${SWIFT_SDK_${SWIFT_HOST_VARIANT_SDK}_ARCH_${SWIFT_HOST_VARIANT_ARCH}_TRIPLE}/include")
-      target_include_directories("${target}" SYSTEM PRIVATE "${SWIFT_${SWIFTLIB_SINGLE_SDK}_ICU_I18N_INCLUDE}")
+    if(NOT "${SWIFT_${SWIFTLIB_SINGLE_SDK}_${SWIFTLIB_SINGLE_ARCHITECTURE}_ICU_I18N_INCLUDE}" STREQUAL "" AND
+       NOT "${SWIFT_${SWIFTLIB_SINGLE_SDK}_${SWIFTLIB_SINGLE_ARCHITECTURE}_ICU_I18N_INCLUDE}" STREQUAL "/usr/include" AND
+       NOT "${SWIFT_${SWIFTLIB_SINGLE_SDK}_${SWIFTLIB_SINGLE_ARCHITECTURE}_ICU_I18N_INCLUDE}" STREQUAL "/usr/${SWIFT_SDK_${SWIFTLIB_SINGLE_SDK}_ARCH_${SWIFTLIB_SINGLE_ARCHITECTURE}_TRIPLE}/include" AND
+       NOT "${SWIFT_${SWIFTLIB_SINGLE_SDK}_${SWIFTLIB_SINGLE_ARCHITECTURE}_ICU_I18N_INCLUDE}" STREQUAL "/usr/${SWIFT_SDK_${SWIFT_HOST_VARIANT_SDK}_ARCH_${SWIFT_HOST_VARIANT_ARCH}_TRIPLE}/include")
+     target_include_directories("${target}" SYSTEM PRIVATE "${SWIFT_${SWIFTLIB_SINGLE_SDK}_${SWIFTLIB_SINGLE_ARCHITECTURE}_ICU_I18N_INCLUDE}")
     endif()
   endif()
 
@@ -1539,7 +1539,7 @@
         foreach(lib ${SWIFTLIB_PRIVATE_LINK_LIBRARIES})
           if("${lib}" STREQUAL "ICU_UC")
             list(APPEND swiftlib_private_link_libraries_targets
-                 "${SWIFT_${sdk}_ICU_UC}")
+                 "${SWIFT_${sdk}_${arch}_ICU_UC}")
             # temporary fix for atomic needing to be
             # after object files for libswiftCore.so
             if("${sdk}" STREQUAL "ANDROID")
@@ -1553,7 +1553,7 @@
             endif()
           elseif("${lib}" STREQUAL "ICU_I18N")
             list(APPEND swiftlib_private_link_libraries_targets
-                 "${SWIFT_${sdk}_ICU_I18N}")
+                 "${SWIFT_${sdk}_${arch}_ICU_I18N}")
           elseif(TARGET "${lib}${VARIANT_SUFFIX}")
             list(APPEND swiftlib_private_link_libraries_targets
                 "${lib}${VARIANT_SUFFIX}")
diff --git a/cmake/modules/FindICU.cmake b/cmake/modules/FindICU.cmake
index 4f380c8..e40a128 100644
--- a/cmake/modules/FindICU.cmake
+++ b/cmake/modules/FindICU.cmake
@@ -34,11 +34,11 @@
 foreach(sdk ANDROID;FREEBSD;LINUX;WINDOWS;HAIKU)
   foreach(MODULE ${ICU_FIND_COMPONENTS})
     string(TOUPPER "${MODULE}" MODULE)
-    if("${SWIFT_${sdk}_ICU_${MODULE}_INCLUDE}" STREQUAL "")
-      set(SWIFT_${sdk}_ICU_${MODULE}_INCLUDE ${ICU_${MODULE}_INCLUDE_DIRS})
+    if("${SWIFT_${sdk}_${SWIFT_HOST_VARIANT_ARCH}_ICU_${MODULE}_INCLUDE}" STREQUAL "")
+      set(SWIFT_${sdk}_${SWIFT_HOST_VARIANT_ARCH}_ICU_${MODULE}_INCLUDE ${ICU_${MODULE}_INCLUDE_DIRS} CACHE STRING "" FORCE)
     endif()
-    if("${SWIFT_${sdk}_ICU_${MODULE}}" STREQUAL "")
-      set(SWIFT_${sdk}_ICU_${MODULE} ${ICU_${MODULE}_LIBRARY})
+    if("${SWIFT_${sdk}_${SWIFT_HOST_VARIANT_ARCH}_ICU_${MODULE}}" STREQUAL "")
+      set(SWIFT_${sdk}_${SWIFT_HOST_VARIANT_ARCH}_ICU_${MODULE} ${ICU_${MODULE}_LIBRARY} CACHE STRING "" FORCE)
     endif()
   endforeach()
 endforeach()
diff --git a/include/swift/ABI/MetadataValues.h b/include/swift/ABI/MetadataValues.h
index 271f0bc..aed6000 100644
--- a/include/swift/ABI/MetadataValues.h
+++ b/include/swift/ABI/MetadataValues.h
@@ -21,6 +21,7 @@
 
 #include "swift/AST/Ownership.h"
 #include "swift/Basic/LLVM.h"
+#include "swift/Basic/FlagSet.h"
 #include "swift/Runtime/Unreachable.h"
 
 #include <stdlib.h>
@@ -981,19 +982,67 @@
 
 /// Flags for nominal type context descriptors. These values are used as the
 /// kindSpecificFlags of the ContextDescriptorFlags for the type.
-enum class TypeContextDescriptorFlags: uint16_t {
-  /// Set if the context descriptor is includes metadata for dynamically
-  /// constructing a class's vtables at metadata instantiation time.
-  HasVTable = 0x8000u,
-  
-  /// Set if the context descriptor is for a class with resilient ancestry.
-  HasResilientSuperclass = 0x4000u,
-  
-  /// Set if the type represents an imported C tag type.
-  IsCTag = 0x2000u,
-  
-  /// Set if the type represents an imported C typedef type.
-  IsCTypedef = 0x1000u,
+class TypeContextDescriptorFlags : public FlagSet<uint16_t> {
+  enum {
+    // All of these values are bit offsets or widths.
+    // Generic flags build upwards from 0.
+    // Type-specific flags build downwards from 15.
+
+    /// Set if the type represents an imported C tag type.
+    ///
+    /// Meaningful for all type-descriptor kinds.
+    IsCTag = 0,
+
+    /// Set if the type represents an imported C typedef type.
+    ///
+    /// Meaningful for all type-descriptor kinds.
+    IsCTypedef = 1,
+
+    /// Set if the type supports reflection.  C and Objective-C enums
+    /// currently don't.
+    ///
+    /// Meaningful for all type-descriptor kinds.
+    IsReflectable = 2,
+
+    /// Set if the context descriptor is includes metadata for dynamically
+    /// constructing a class's vtables at metadata instantiation time.
+    ///
+    /// Only meaningful for class descriptors.
+    Class_HasVTable = 15,
+
+    /// Set if the context descriptor is for a class with resilient ancestry.
+    ///
+    /// Only meaningful for class descriptors.
+    Class_HasResilientSuperclass = 14,
+
+    /// The kind of reference that this class makes to its superclass
+    /// descriptor.  A TypeMetadataRecordKind.
+    ///
+    /// Only meaningful for class descriptors.
+    Class_SuperclassReferenceKind = 12,
+    Class_SuperclassReferenceKind_width = 2,
+  };
+
+public:
+  explicit TypeContextDescriptorFlags(uint16_t bits) : FlagSet(bits) {}
+  constexpr TypeContextDescriptorFlags() {}
+
+  FLAGSET_DEFINE_FLAG_ACCESSORS(IsCTag, isCTag, setIsCTag)
+  FLAGSET_DEFINE_FLAG_ACCESSORS(IsCTypedef, isCTypedef, setIsCTypedef)
+  FLAGSET_DEFINE_FLAG_ACCESSORS(IsReflectable, isReflectable, setIsReflectable)
+
+  FLAGSET_DEFINE_FLAG_ACCESSORS(Class_HasVTable,
+                                class_hasVTable,
+                                class_setHasVTable)
+  FLAGSET_DEFINE_FLAG_ACCESSORS(Class_HasResilientSuperclass,
+                                class_hasResilientSuperclass,
+                                class_setHasResilientSuperclass)
+
+  FLAGSET_DEFINE_FIELD_ACCESSORS(Class_SuperclassReferenceKind,
+                                 Class_SuperclassReferenceKind_width,
+                                 TypeMetadataRecordKind,
+                                 class_getSuperclassReferenceKind,
+                                 class_setSuperclassReferenceKind)
 };
 
 enum class GenericParamKind : uint8_t {
diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h
index 7f6bafc..2d43a1f 100644
--- a/include/swift/AST/Decl.h
+++ b/include/swift/AST/Decl.h
@@ -1712,7 +1712,9 @@
     return D->getKind() == DeclKind::Extension;
   }
   static bool classof(const DeclContext *C) {
-    return C->getContextKind() == DeclContextKind::ExtensionDecl;
+    if (auto D = C->getAsDeclOrDeclExtensionContext())
+      return classof(D);
+    return false;
   }
   static bool classof(const IterableDeclContext *C) {
     return C->getIterableContextKind() 
@@ -2003,7 +2005,9 @@
     return D->getKind() == DeclKind::TopLevelCode;
   }
   static bool classof(const DeclContext *C) {
-    return C->getContextKind() == DeclContextKind::TopLevelCodeDecl;
+    if (auto D = C->getAsDeclOrDeclExtensionContext())
+      return classof(D);
+    return false;
   }
   
   using DeclContext::operator new;
@@ -2465,7 +2469,9 @@
   using TypeDecl::getDeclaredInterfaceType;
 
   static bool classof(const DeclContext *C) {
-    return C->getContextKind() == DeclContextKind::GenericTypeDecl;
+    if (auto D = C->getAsDeclOrDeclExtensionContext())
+      return classof(D);
+    return false;
   }
   static bool classof(const Decl *D) {
     return D->getKind() >= DeclKind::First_GenericTypeDecl &&
@@ -2533,8 +2539,9 @@
     return D->getKind() == DeclKind::TypeAlias;
   }
   static bool classof(const DeclContext *C) {
-    auto GTD = dyn_cast<GenericTypeDecl>(C);
-    return GTD && classof(GTD);
+    if (auto D = C->getAsDeclOrDeclExtensionContext())
+      return classof(D);
+    return false;
   }
 };
 
@@ -3038,8 +3045,9 @@
   }
 
   static bool classof(const DeclContext *C) {
-    auto GTD = dyn_cast<GenericTypeDecl>(C);
-    return GTD && classof(GTD);
+    if (auto D = C->getAsDeclOrDeclExtensionContext())
+      return classof(D);
+    return false;
   }
   static bool classof(const IterableDeclContext *C) {
     return C->getIterableContextKind()
@@ -3183,8 +3191,9 @@
     return D->getKind() == DeclKind::Enum;
   }
   static bool classof(const DeclContext *C) {
-    auto GTD = dyn_cast<GenericTypeDecl>(C);
-    return GTD && classof(static_cast<const Decl*>(GTD));
+    if (auto D = C->getAsDeclOrDeclExtensionContext())
+      return classof(D);
+    return false;
   }
   static bool classof(const IterableDeclContext *C) {
     auto NTD = dyn_cast<NominalTypeDecl>(C);
@@ -3252,8 +3261,9 @@
     return D->getKind() == DeclKind::Struct;
   }
   static bool classof(const DeclContext *C) {
-    auto GTD = dyn_cast<GenericTypeDecl>(C);
-    return GTD && classof(static_cast<const Decl*>(GTD));
+    if (auto D = C->getAsDeclOrDeclExtensionContext())
+      return classof(D);
+    return false;
   }
   static bool classof(const IterableDeclContext *C) {
     auto NTD = dyn_cast<NominalTypeDecl>(C);
@@ -3509,8 +3519,9 @@
     return D->getKind() == DeclKind::Class;
   }
   static bool classof(const DeclContext *C) {
-    auto GTD = dyn_cast<GenericTypeDecl>(C);
-    return GTD && classof(static_cast<const Decl*>(GTD));
+    if (auto D = C->getAsDeclOrDeclExtensionContext())
+      return classof(D);
+    return false;
   }
   static bool classof(const IterableDeclContext *C) {
     auto NTD = dyn_cast<NominalTypeDecl>(C);
@@ -3827,8 +3838,9 @@
     return D->getKind() == DeclKind::Protocol;
   }
   static bool classof(const DeclContext *C) {
-    auto GTD = dyn_cast<GenericTypeDecl>(C);
-    return GTD && classof(static_cast<const Decl*>(GTD));
+    if (auto D = C->getAsDeclOrDeclExtensionContext())
+      return classof(D);
+    return false;
   }
   static bool classof(const IterableDeclContext *C) {
     auto NTD = dyn_cast<NominalTypeDecl>(C);
@@ -4333,13 +4345,13 @@
 
   /// Given that this is an Objective-C property or subscript declaration,
   /// produce its getter selector.
-  ObjCSelector getObjCGetterSelector(LazyResolver *resolver = nullptr,
-                                Identifier preferredName = Identifier()) const;
+  ObjCSelector
+  getObjCGetterSelector(Identifier preferredName = Identifier()) const;
 
   /// Given that this is an Objective-C property or subscript declaration,
   /// produce its setter selector.
-  ObjCSelector getObjCSetterSelector(LazyResolver *resolver = nullptr,
-                                Identifier preferredName = Identifier()) const;
+  ObjCSelector
+  getObjCSetterSelector(Identifier preferredName = Identifier()) const;
 
   AbstractStorageDecl *getOverriddenDecl() const {
     return OverriddenDecl;
@@ -4835,7 +4847,7 @@
 
   /// Determine the kind of Objective-C subscripting this declaration
   /// implies.
-  ObjCSubscriptKind getObjCSubscriptKind(LazyResolver *resolver) const;
+  ObjCSubscriptKind getObjCSubscriptKind() const;
 
   SubscriptDecl *getOverriddenDecl() const {
     return cast_or_null<SubscriptDecl>(
@@ -4847,7 +4859,9 @@
   }
   
   static bool classof(const DeclContext *DC) {
-    return DC->getContextKind() == DeclContextKind::SubscriptDecl;
+    if (auto D = DC->getAsDeclOrDeclExtensionContext())
+      return classof(D);
+    return false;
   }
 
   using DeclContext::operator new;
@@ -5121,8 +5135,7 @@
   const CaptureInfo &getCaptureInfo() const { return Captures; }
 
   /// Retrieve the Objective-C selector that names this method.
-  ObjCSelector getObjCSelector(LazyResolver *resolver = nullptr,
-                               DeclName preferredName = DeclName()) const;
+  ObjCSelector getObjCSelector(DeclName preferredName = DeclName()) const;
 
   /// Determine whether the given method would produce an Objective-C
   /// instance method.
@@ -5230,7 +5243,9 @@
   }
 
   static bool classof(const DeclContext *DC) {
-    return DC->getContextKind() == DeclContextKind::AbstractFunctionDecl;
+    if (auto D = DC->getAsDeclOrDeclExtensionContext())
+      return classof(D);
+    return false;
   }
   
   /// True if the declaration is forced to be statically dispatched.
@@ -5496,8 +5511,8 @@
     return classof(static_cast<const Decl*>(D));
   }
   static bool classof(const DeclContext *DC) {
-    if (auto fn = dyn_cast<AbstractFunctionDecl>(DC))
-      return classof(fn);
+    if (auto D = DC->getAsDeclOrDeclExtensionContext())
+      return classof(D);
     return false;
   }
 
@@ -5617,8 +5632,8 @@
     return classof(static_cast<const Decl*>(D));
   }
   static bool classof(const DeclContext *DC) {
-    if (auto fn = dyn_cast<AbstractFunctionDecl>(DC))
-      return classof(fn);
+    if (auto D = DC->getAsDeclOrDeclExtensionContext())
+      return classof(D);
     return false;
   }
 };
@@ -6036,8 +6051,8 @@
     return classof(static_cast<const Decl*>(D));
   }
   static bool classof(const DeclContext *DC) {
-    if (auto fn = dyn_cast<AbstractFunctionDecl>(DC))
-      return classof(fn);
+    if (auto D = DC->getAsDeclOrDeclExtensionContext())
+      return classof(D);
     return false;
   }
 };
@@ -6080,8 +6095,8 @@
     return classof(static_cast<const Decl*>(D));
   }
   static bool classof(const DeclContext *DC) {
-    if (auto fn = dyn_cast<AbstractFunctionDecl>(DC))
-      return classof(fn);
+    if (auto D = DC->getAsDeclOrDeclExtensionContext())
+      return classof(D);
     return false;
   }
 };
@@ -6584,6 +6599,12 @@
   }
 }
 
+inline bool DeclContext::isExtensionContext() const {
+  if (auto D = getAsDeclOrDeclExtensionContext())
+    return ExtensionDecl::classof(D);
+  return false;
+}
+
 inline bool DeclContext::classof(const Decl *D) {
   switch (D->getKind()) { //
   default: return false;
diff --git a/include/swift/AST/DeclContext.h b/include/swift/AST/DeclContext.h
index d23d9ee..27e3bec 100644
--- a/include/swift/AST/DeclContext.h
+++ b/include/swift/AST/DeclContext.h
@@ -262,25 +262,18 @@
   }
   
   /// isModuleContext - Return true if this is a subclass of Module.
-  bool isModuleContext() const {
-    return getContextKind() == DeclContextKind::Module;
-  }
+  bool isModuleContext() const; // see swift/AST/Module.h
 
   /// \returns true if this is a context with module-wide scope, e.g. a module
   /// or a source file.
-  bool isModuleScopeContext() const {
-    return getContextKind() == DeclContextKind::Module ||
-           getContextKind() == DeclContextKind::FileUnit;
-  }
+  bool isModuleScopeContext() const; // see swift/AST/Module.h
 
   /// \returns true if this is a type context, e.g., a struct, a class, an
   /// enum, a protocol, or an extension.
   bool isTypeContext() const;
 
   /// \brief Determine whether this is an extension context.
-  bool isExtensionContext() const {
-    return getContextKind() == DeclContextKind::ExtensionDecl;
-  }
+  bool isExtensionContext() const; // see swift/AST/Decl.h
 
   /// If this DeclContext is a NominalType declaration or an
   /// extension thereof, return the NominalTypeDecl.
diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def
index f693f84..70531ab 100644
--- a/include/swift/AST/DiagnosticsSema.def
+++ b/include/swift/AST/DiagnosticsSema.def
@@ -1371,6 +1371,8 @@
       "generic parameters at runtime", ())
 NOTE(objc_generic_extension_using_type_parameter_here,none,
      "generic parameter used here", ())
+NOTE(objc_generic_extension_using_type_parameter_try_objc,none,
+     "add '@objc' to allow uses of 'self' within the function body", ())
 
 // Protocols
 ERROR(type_does_not_conform,none,
diff --git a/include/swift/AST/Module.h b/include/swift/AST/Module.h
index 83ce624..01a760d 100644
--- a/include/swift/AST/Module.h
+++ b/include/swift/AST/Module.h
@@ -492,7 +492,9 @@
   SourceRange getSourceRange() const { return SourceRange(); }
 
   static bool classof(const DeclContext *DC) {
-    return DC->getContextKind() == DeclContextKind::Module;
+    if (auto D = DC->getAsDeclOrDeclExtensionContext())
+      return classof(D);
+    return false;
   }
 
   static bool classof(const Decl *D) {
@@ -1219,6 +1221,18 @@
   explicit operator bool() const { return !Mod.isNull(); }
 };
 
+inline bool DeclContext::isModuleContext() const {
+  if (auto D = getAsDeclOrDeclExtensionContext())
+    return ModuleDecl::classof(D);
+  return false;
+}
+
+inline bool DeclContext::isModuleScopeContext() const {
+  if (ParentAndKind.getInt() == ASTHierarchy::FileUnit)
+    return true;
+  return isModuleContext();
+}
+
 } // end namespace swift
 
 namespace llvm {
diff --git a/include/swift/AST/Type.h b/include/swift/AST/Type.h
index f741f48..2619c78 100644
--- a/include/swift/AST/Type.h
+++ b/include/swift/AST/Type.h
@@ -368,15 +368,19 @@
   /// class D { }
   /// \endcode
   ///
-  /// The join of B and C is A, the join of A and B is A. However, there is no
-  /// join of D and A (or D and B, or D and C) because there is no common
-  /// superclass. One would have to jump to an existential (e.g., \c AnyObject)
-  /// to find a common type.
+  /// The join of B and C is A, the join of A and B is A.
+  ///
+  /// The Any type is considered the common supertype by default when no
+  /// closer common supertype exists.
+  ///
+  /// In unsupported cases where we cannot yet compute an accurate join,
+  /// we return None.
   ///
   /// \returns the join of the two types, if there is a concrete type
   /// that can express the join, or Any if the only join would be a
-  /// more-general existential type
-  static Type join(Type first, Type second);
+  /// more-general existential type, or None if we cannot yet compute a
+  /// correct join but one better than Any may exist.
+  static Optional<Type> join(Type first, Type second);
 
 private:
   // Direct comparison is disabled for types, because they may not be canonical.
diff --git a/include/swift/Basic/FlagSet.h b/include/swift/Basic/FlagSet.h
new file mode 100644
index 0000000..e58bf08
--- /dev/null
+++ b/include/swift/Basic/FlagSet.h
@@ -0,0 +1,111 @@
+//===--- FlagSet.h - Helper class for opaque flag types ---------*- C++ -*-===//
+//
+// This source file is part of the Swift.org open source project
+//
+// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
+// Licensed under Apache License v2.0 with Runtime Library Exception
+//
+// See https://swift.org/LICENSE.txt for license information
+// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the FlagSet template, a class which makes it easier to
+// define opaque flag types.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SWIFT_BASIC_FLAGSET_H
+#define SWIFT_BASIC_FLAGSET_H
+
+#include <type_traits>
+#include <assert.h>
+
+namespace swift {
+
+/// A template designed to simplify the task of defining a wrapper type
+/// for a flags bitfield.
+///
+/// Unfortunately, this doesn't currently support functional-style
+/// building patterns, which means this can't practically be used for
+/// types that need to be used in constant expressions.
+template <typename IntType>
+class FlagSet {
+  static_assert(std::is_integral<IntType>::value,
+                "storage type for FlagSet must be an integral type");
+  IntType Bits;
+
+protected:
+  template <unsigned BitWidth>
+  static constexpr IntType lowMaskFor() {
+    return IntType((1 << BitWidth) - 1);
+  }
+
+  template <unsigned FirstBit, unsigned BitWidth = 1>
+  static constexpr IntType maskFor() {
+    return lowMaskFor<BitWidth>() << FirstBit;
+  }
+
+  constexpr FlagSet(IntType bits = 0) : Bits(bits) {}
+
+  /// Read a single-bit flag.
+  template <unsigned Bit>
+  bool getFlag() const {
+    return Bits & maskFor<Bit>();
+  }
+
+  /// Set a single-bit flag.
+  template <unsigned Bit>
+  void setFlag(bool value) {
+    if (value) {
+      Bits |= maskFor<Bit>();
+    } else {
+      Bits |= ~maskFor<Bit>();
+    }
+  }
+
+  /// Read a multi-bit field.
+  template <unsigned FirstBit, unsigned BitWidth, typename FieldType = IntType>
+  FieldType getField() const {
+    return FieldType((Bits >> FirstBit) & lowMaskFor<BitWidth>());
+  }
+
+  /// Assign to a multi-bit field.
+  template <unsigned FirstBit, unsigned BitWidth, typename FieldType = IntType>
+  void setField(typename std::enable_if<true, FieldType>::type value) {
+    // Note that we suppress template argument deduction for FieldType.
+    assert(IntType(value) <= lowMaskFor<BitWidth>() && "value out of range");
+    Bits = (Bits & ~maskFor<FirstBit, BitWidth>())
+         | (IntType(value) << FirstBit);
+  }
+
+  // A convenient macro for defining a getter and setter for a flag.
+  // Intended to be used in the body of a subclass of FlagSet.
+#define FLAGSET_DEFINE_FLAG_ACCESSORS(BIT, GETTER, SETTER) \
+  bool GETTER() const {                                    \
+    return getFlag<BIT>();                                 \
+  }                                                        \
+  void SETTER(bool value) {                                \
+    setFlag<BIT>(value);                                   \
+  }
+
+  // A convenient macro for defining a getter and setter for a field.
+  // Intended to be used in the body of a subclass of FlagSet.
+#define FLAGSET_DEFINE_FIELD_ACCESSORS(BIT, WIDTH, TYPE, GETTER, SETTER) \
+  TYPE GETTER() const {                                                  \
+    return getField<BIT, WIDTH, TYPE>();                                 \
+  }                                                                      \
+  void SETTER(TYPE value) {                                              \
+    setField<BIT, WIDTH, TYPE>(value);                                   \
+  }
+
+public:
+  /// Get the bits as an opaque integer value.
+  IntType getOpaqueValue() const {
+    return Bits;
+  }
+};
+
+} // end namespace swift
+
+#endif
diff --git a/include/swift/Basic/LLVMInitialize.h b/include/swift/Basic/LLVMInitialize.h
index 4d44f5a..bba5e0e 100644
--- a/include/swift/Basic/LLVMInitialize.h
+++ b/include/swift/Basic/LLVMInitialize.h
@@ -10,34 +10,33 @@
 //
 //===----------------------------------------------------------------------===//
 //
-// A file that declares a macro for initializing all parts of LLVM that various
-// binaries in swift use. Please call the macro in the main routine of all
-// binaries.
+// A file that declares macros for initializing all parts of LLVM that various
+// binaries in swift use. Please call PROGRAM_START in the main routine of all
+// binaries, and INITIALIZE_LLVM in anything that uses Clang or LLVM IR.
 //
 //===----------------------------------------------------------------------===//
 
 #ifndef SWIFT_BASIC_LLVMINITIALIZE_H
 #define SWIFT_BASIC_LLVMINITIALIZE_H
 
-#include "llvm/Support/FileSystem.h"
-#include "llvm/Support/Host.h"
 #include "llvm/Support/ManagedStatic.h"
-#include "llvm/Support/Path.h"
 #include "llvm/Support/PrettyStackTrace.h"
-#include "llvm/Support/Process.h"
 #include "llvm/Support/Signals.h"
 #include "llvm/Support/TargetSelect.h"
-#include "llvm/Support/raw_ostream.h"
 
-#define INITIALIZE_LLVM(argc, argv) \
+#define PROGRAM_START(argc, argv) \
   llvm::sys::PrintStackTraceOnErrorSignal(argv[0]); \
   llvm::PrettyStackTraceProgram _INITIALIZE_LLVM_STACKTRACE(argc, argv); \
-  llvm::llvm_shutdown_obj _INITIALIZE_LLVM_SHUTDOWN_OBJ; \
-  llvm::InitializeAllTargets(); \
-  llvm::InitializeAllTargetMCs(); \
-  llvm::InitializeAllAsmPrinters(); \
-  llvm::InitializeAllAsmParsers(); \
-  llvm::InitializeAllDisassemblers(); \
-  llvm::InitializeAllTargetInfos();
+  llvm::llvm_shutdown_obj _INITIALIZE_LLVM_SHUTDOWN_OBJ
+
+#define INITIALIZE_LLVM() \
+  do { \
+    llvm::InitializeAllTargets(); \
+    llvm::InitializeAllTargetMCs(); \
+    llvm::InitializeAllAsmPrinters(); \
+    llvm::InitializeAllAsmParsers(); \
+    llvm::InitializeAllDisassemblers(); \
+    llvm::InitializeAllTargetInfos(); \
+  } while (0)
 
 #endif // SWIFT_BASIC_LLVMINITIALIZE_H
diff --git a/include/swift/Basic/PrimarySpecificPaths.h b/include/swift/Basic/PrimarySpecificPaths.h
index c950405..b645a49 100644
--- a/include/swift/Basic/PrimarySpecificPaths.h
+++ b/include/swift/Basic/PrimarySpecificPaths.h
@@ -15,26 +15,39 @@
 
 #include "swift/Basic/LLVM.h"
 #include "swift/Basic/SupplementaryOutputPaths.h"
+#include "llvm/ADT/StringRef.h"
 
 #include <string>
 
 namespace swift {
+
+/// Holds all of the output paths, and debugging-info path that are
+/// specific to which primary file is being compiled at the moment.
+
 class PrimarySpecificPaths {
 public:
+  /// The name of the main output file,
+  /// that is, the .o file for this input. If there is no such file, contains an
+  /// empty string. If the output is to be written to stdout, contains "-".
   std::string OutputFilename;
+
   SupplementaryOutputPaths SupplementaryOutputs;
 
   /// The name of the "main" input file, used by the debug info.
   std::string MainInputFilenameForDebugInfo;
 
-  PrimarySpecificPaths(
-      std::string OutputFilename = std::string(),
-      std::string MainInputFilenameForDebugInfo = std::string(),
-      SupplementaryOutputPaths SupplementaryOutputs =
-          SupplementaryOutputPaths())
+  PrimarySpecificPaths(StringRef OutputFilename = StringRef(),
+                       StringRef MainInputFilenameForDebugInfo = StringRef(),
+                       SupplementaryOutputPaths SupplementaryOutputs =
+                           SupplementaryOutputPaths())
       : OutputFilename(OutputFilename),
         SupplementaryOutputs(SupplementaryOutputs),
         MainInputFilenameForDebugInfo(MainInputFilenameForDebugInfo) {}
+
+  bool haveModuleOrModuleDocOutputPaths() const {
+    return !SupplementaryOutputs.ModuleOutputPath.empty() ||
+           !SupplementaryOutputs.ModuleDocOutputPath.empty();
+  }
 };
 } // namespace swift
 
diff --git a/include/swift/Basic/SupplementaryOutputPaths.h b/include/swift/Basic/SupplementaryOutputPaths.h
index 943ace0..95098da 100644
--- a/include/swift/Basic/SupplementaryOutputPaths.h
+++ b/include/swift/Basic/SupplementaryOutputPaths.h
@@ -21,18 +21,28 @@
 namespace swift {
 struct SupplementaryOutputPaths {
   /// The path to which we should emit an Objective-C header for the module.
+  /// Currently only makes sense when the compiler has whole module knowledge.
+  /// The modes for which it makes sense incuide both WMO and the "merge
+  /// modules" job that happens after the normal compilation jobs. That's where
+  /// the header is emitted in single-file mode, since it needs whole-module
+  /// information.
+
   std::string ObjCHeaderOutputPath;
 
   /// The path to which we should emit a serialized module.
+  /// It is valid whenever there are any inputs.
   std::string ModuleOutputPath;
 
   /// The path to which we should emit a module documentation file.
+  /// It is valid whenever there are any inputs.
   std::string ModuleDocOutputPath;
 
   /// The path to which we should output a Make-style dependencies file.
+  /// It is valid whenever there are any inputs.
   std::string DependenciesFilePath;
 
   /// The path to which we should output a Swift reference dependencies file.
+  /// It is valid whenever there are any inputs.
   std::string ReferenceDependenciesFilePath;
 
   /// Path to a file which should contain serialized diagnostics for this
@@ -40,9 +50,11 @@
   std::string SerializedDiagnosticsPath;
 
   /// 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;
 
   /// The path to which we should output a TBD file.
+  /// It is currently only used with WMO, but could be generalized.
   std::string TBDPath;
 
   SupplementaryOutputPaths() = default;
diff --git a/include/swift/Driver/Job.h b/include/swift/Driver/Job.h
index d2f32ee..f449f41 100644
--- a/include/swift/Driver/Job.h
+++ b/include/swift/Driver/Job.h
@@ -96,6 +96,13 @@
   /// derived from the BaseInput it is related to. Also used as a key into
   /// the DerivedOutputFileMap.
   StringRef Primary;
+
+  /// Construct a CommandInputPair from a Base Input and, optionally, a Primary;
+  /// if the Primary is empty, use the Base value for it.
+  explicit CommandInputPair(StringRef BaseInput, StringRef PrimaryInput)
+    : Base(BaseInput),
+      Primary(PrimaryInput.empty() ? BaseInput : PrimaryInput)
+    {}
 };
 
 class CommandOutput {
@@ -162,8 +169,14 @@
   StringRef getPrimaryOutputFilename() const;
 
   /// Return a all of the outputs of type \c getPrimaryOutputType() associated
-  /// with a primary input. Note that the returned \c StringRef vector may be
-  /// invalidated by subsequent mutations to the \c CommandOutput.
+  /// with a primary input. The return value will contain one \c StringRef per
+  /// primary input, _even if_ the primary output type is TY_Nothing, and the
+  /// primary output filenames are therefore all empty strings.
+  ///
+  /// FIXME: This is not really ideal behaviour -- it would be better to return
+  /// only nonempty strings in all cases, and have the callers differentiate
+  /// contexts with absent primary outputs another way -- but this is currently
+  /// assumed at several call sites.
   SmallVector<StringRef, 16> getPrimaryOutputFilenames() const;
 
   /// Assuming (and asserting) that there are one or more input pairs, associate
@@ -177,6 +190,17 @@
   /// first primary input.
   StringRef getAdditionalOutputForType(types::ID type) const;
 
+  /// Return a vector of additional (not primary) outputs of type \p type
+  /// associated with the primary inputs.
+  ///
+  /// In contrast to \c getPrimaryOutputFilenames, this method does _not_ return
+  /// any empty strings or ensure the return vector is matched in size with the
+  /// set of primary inputs; however it _does_ assert that the return vector's
+  /// length is _either_ zero, one, or equal to the size of the set of inputs,
+  /// as these are the only valid arity relationships between primary and
+  /// additional outputs.
+  SmallVector<StringRef, 16> getAdditionalOutputsForType(types::ID type) const;
+
   /// Assuming (and asserting) that there is only one input pair, return any
   /// output -- primary or additional -- of type \p type associated with that
   /// the sole primary input.
@@ -187,6 +211,10 @@
 
   void print(raw_ostream &Stream) const;
   void dump() const LLVM_ATTRIBUTE_USED;
+
+  /// For use in assertions: check the CommandOutput's state is consistent with
+  /// its invariants.
+  void checkInvariants() const;
 };
 
 class Job {
diff --git a/include/swift/Frontend/ArgsToFrontendOutputsConverter.h b/include/swift/Frontend/ArgsToFrontendOutputsConverter.h
index 0f62f70..1b2ecd0 100644
--- a/include/swift/Frontend/ArgsToFrontendOutputsConverter.h
+++ b/include/swift/Frontend/ArgsToFrontendOutputsConverter.h
@@ -43,7 +43,7 @@
         Diags(diags) {}
 
   bool convert(std::vector<std::string> &mainOutputs,
-               SupplementaryOutputPaths &supplementaryOutputs);
+               std::vector<SupplementaryOutputPaths> &supplementaryOutputs);
 
   /// Try to read an output file list file.
   /// \returns `None` if it could not open the filelist.
@@ -57,7 +57,7 @@
   const FrontendInputsAndOutputs &InputsAndOutputs;
   const std::vector<std::string> OutputFileArguments;
   const std::string OutputDirectoryArgument;
-  const StringRef FirstInput;
+  const std::string FirstInput;
   const FrontendOptions::ActionType RequestedAction;
   const llvm::opt::Arg *const ModuleNameArg;
   const StringRef Suffix;
diff --git a/include/swift/Frontend/Frontend.h b/include/swift/Frontend/Frontend.h
index e3ff790..46aef96 100644
--- a/include/swift/Frontend/Frontend.h
+++ b/include/swift/Frontend/Frontend.h
@@ -174,15 +174,6 @@
     return SearchPathOpts.SDKPath;
   }
 
-  void setSerializedDiagnosticsPath(StringRef Path) {
-    FrontendOpts.InputsAndOutputs.supplementaryOutputs()
-        .SerializedDiagnosticsPath = Path;
-  }
-  StringRef getSerializedDiagnosticsPath() const {
-    return FrontendOpts.InputsAndOutputs.supplementaryOutputs()
-        .SerializedDiagnosticsPath;
-  }
-
   LangOptions &getLangOptions() {
     return LangOpts;
   }
@@ -245,8 +236,7 @@
     return FrontendOpts.ModuleName;
   }
 
-
-  StringRef getOutputFilename() const {
+  std::string getOutputFilename() const {
     return FrontendOpts.InputsAndOutputs.getSingleOutputFilename();
   }
 
@@ -302,11 +292,25 @@
     return FrontendOpts.InputKind == InputFileKind::IFK_Swift_Library;
   }
 
-  PrimarySpecificPaths getPrimarySpecificPathsForAtMostOnePrimary() const;
-  PrimarySpecificPaths
+  const PrimarySpecificPaths &
+  getPrimarySpecificPathsForAtMostOnePrimary() const;
+  const PrimarySpecificPaths &
   getPrimarySpecificPathsForPrimary(StringRef filename) const;
-  PrimarySpecificPaths
+  const PrimarySpecificPaths &
   getPrimarySpecificPathsForSourceFile(const SourceFile &SF) const;
+
+  std::string getOutputFilenameForAtMostOnePrimary() const;
+  std::string getMainInputFilenameForDebugInfoForAtMostOnePrimary() const;
+  std::string getObjCHeaderOutputPathForAtMostOnePrimary() const;
+  std::string getModuleOutputPathForAtMostOnePrimary() const;
+  std::string
+  getReferenceDependenciesFilePathForPrimary(StringRef filename) const;
+  std::string getSerializedDiagnosticsPathForAtMostOnePrimary() const;
+
+  /// TBDPath only makes sense in whole module compilation mode,
+  /// so return the TBDPath when in that mode and fail an assert
+  /// if not in that mode.
+  std::string getTBDPathForWholeModule() const;
 };
 
 /// A class which manages the state and execution of the compiler.
@@ -584,12 +588,13 @@
   void finishTypeChecking(OptionSet<TypeCheckingFlags> TypeCheckOptions);
 
 public:
-  PrimarySpecificPaths
+  const PrimarySpecificPaths &
   getPrimarySpecificPathsForWholeModuleOptimizationMode() const;
-  PrimarySpecificPaths
+  const PrimarySpecificPaths &
   getPrimarySpecificPathsForPrimary(StringRef filename) const;
-  PrimarySpecificPaths getPrimarySpecificPathsForAtMostOnePrimary() const;
-  PrimarySpecificPaths
+  const PrimarySpecificPaths &
+  getPrimarySpecificPathsForAtMostOnePrimary() const;
+  const PrimarySpecificPaths &
   getPrimarySpecificPathsForSourceFile(const SourceFile &SF) const;
 };
 
diff --git a/include/swift/Frontend/FrontendInputsAndOutputs.h b/include/swift/Frontend/FrontendInputsAndOutputs.h
index 06ea15a..be87323 100644
--- a/include/swift/Frontend/FrontendInputsAndOutputs.h
+++ b/include/swift/Frontend/FrontendInputsAndOutputs.h
@@ -35,8 +35,8 @@
   friend class ArgsToFrontendInputsConverter;
 
   std::vector<InputFile> AllInputs;
-
-  llvm::StringMap<unsigned> PrimaryInputs;
+  llvm::StringMap<unsigned> PrimaryInputsByName;
+  std::vector<unsigned> PrimaryInputsInOrder;
 
   /// In Single-threaded WMO mode, all inputs are used
   /// both for importing and compiling.
@@ -45,25 +45,10 @@
   /// Punt where needed to enable batch mode experiments.
   bool AreBatchModeChecksBypassed = false;
 
-  SupplementaryOutputPaths SupplementaryOutputs;
-
 public:
   bool areBatchModeChecksBypassed() const { return AreBatchModeChecksBypassed; }
   void setBypassBatchModeChecks(bool bbc) { AreBatchModeChecksBypassed = bbc; }
 
-  const SupplementaryOutputPaths &supplementaryOutputs() const {
-    return SupplementaryOutputs;
-  }
-  SupplementaryOutputPaths &supplementaryOutputs() {
-    return SupplementaryOutputs;
-  }
-
-  /// When performing a compilation for zero or one primary input file,
-  /// this will hold the PrimarySpecificPaths.
-  /// In a future PR, each InputFile will hold its own PrimarySpecificPaths and
-  /// this will go away.
-  PrimarySpecificPaths PrimarySpecificPathsForAtMostOnePrimary;
-
   FrontendInputsAndOutputs() = default;
   FrontendInputsAndOutputs(const FrontendInputsAndOutputs &other);
   FrontendInputsAndOutputs &operator=(const FrontendInputsAndOutputs &other);
@@ -88,6 +73,9 @@
 
   std::vector<std::string> getInputFilenames() const;
 
+  /// \return nullptr if not a primary input file.
+  const InputFile *primaryInputNamed(StringRef name) const;
+
   unsigned inputCount() const { return AllInputs.size(); }
 
   bool hasInputs() const { return !AllInputs.empty(); }
@@ -99,21 +87,23 @@
 
   const InputFile &lastInput() const { return AllInputs.back(); }
 
-  StringRef getFilenameOfFirstInput() const;
+  const std::string &getFilenameOfFirstInput() const;
 
   bool isReadingFromStdin() const;
 
-  void forEachInput(llvm::function_ref<void(const InputFile &)> fn) const;
+  /// If \p fn returns true, exits early and returns true.
+  bool forEachInput(llvm::function_ref<bool(const InputFile &)> fn) const;
 
   // Primaries:
 
   const InputFile &firstPrimaryInput() const;
   const InputFile &lastPrimaryInput() const;
 
-  void
-  forEachPrimaryInput(llvm::function_ref<void(const InputFile &)> fn) const;
+  /// If \p fn returns true, exit early and return true.
+  bool
+  forEachPrimaryInput(llvm::function_ref<bool(const InputFile &)> fn) const;
 
-  unsigned primaryInputCount() const { return PrimaryInputs.size(); }
+  unsigned primaryInputCount() const { return PrimaryInputsInOrder.size(); }
 
   // Primary count readers:
 
@@ -143,11 +133,8 @@
 
   const InputFile &getRequiredUniquePrimaryInput() const;
 
-  /// \return the name of the unique primary input, or an empty StrinRef if
-  /// there isn't one.
-  StringRef getNameOfUniquePrimaryInputFile() const;
-
-  /// Combines all primaries for stats reporter
+  /// FIXME: Should combine all primaries for the result
+  /// instead of just answering "batch" if there is more than one primary.
   std::string getStatsFileMangledInputName() const;
 
   bool isInputPrimary(StringRef file) const;
@@ -181,9 +168,9 @@
 private:
   friend class ArgsToFrontendOptionsConverter;
 
-  void
-  setMainAndSupplementaryOutputs(ArrayRef<std::string> outputFiles,
-                                 SupplementaryOutputPaths supplementaryOutputs);
+  void setMainAndSupplementaryOutputs(
+      ArrayRef<std::string> outputFiles,
+      ArrayRef<SupplementaryOutputPaths> supplementaryOutputs);
 
 public:
   unsigned countOfInputsProducingMainOutputs() const;
@@ -198,17 +185,18 @@
   /// Under single-threaded WMO, we pretend that the first input
   /// generates the main output, even though it will include code
   /// generated from all of them.
-  void forEachInputProducingAMainOutputFile(
-      llvm::function_ref<void(const InputFile &)> fn) const;
+  ///
+  /// If \p fn returns true, return early and return true.
+  bool forEachInputProducingAMainOutputFile(
+      llvm::function_ref<bool(const InputFile &)> fn) const;
 
   std::vector<std::string> copyOutputFilenames() const;
 
-  void
-  forEachOutputFilename(llvm::function_ref<void(const std::string &)> fn) const;
+  void forEachOutputFilename(llvm::function_ref<void(StringRef)> fn) const;
 
   /// Gets the name of the specified output filename.
   /// If multiple files are specified, the last one is returned.
-  StringRef getSingleOutputFilename() const;
+  std::string getSingleOutputFilename() const;
 
   bool isOutputFilenameStdout() const;
   bool isOutputFileDirectory() const;
@@ -218,17 +206,22 @@
 
   unsigned countOfFilesProducingSupplementaryOutput() const;
 
-  void forEachInputProducingSupplementaryOutput(
-      llvm::function_ref<void(const InputFile &)> fn) const;
+  /// If \p fn returns true, exit early and return true.
+  bool forEachInputProducingSupplementaryOutput(
+      llvm::function_ref<bool(const InputFile &)> fn) const;
 
   /// Assumes there is not more than one primary input file, if any.
   /// Otherwise, you would need to call getPrimarySpecificPathsForPrimary
   /// to tell it which primary input you wanted the outputs for.
+  const PrimarySpecificPaths &
+  getPrimarySpecificPathsForAtMostOnePrimary() const;
 
-  PrimarySpecificPaths getPrimarySpecificPathsForAtMostOnePrimary() const;
+  const PrimarySpecificPaths &
+      getPrimarySpecificPathsForPrimary(StringRef) const;
 
-  PrimarySpecificPaths
-  getPrimarySpecificPathsForPrimary(StringRef filename) const;
+  bool hasSupplementaryOutputPath(
+      llvm::function_ref<const std::string &(const SupplementaryOutputPaths &)>
+          extractorFn) const;
 
   bool hasDependenciesPath() const;
   bool hasReferenceDependenciesPath() const;
diff --git a/include/swift/Frontend/FrontendOptions.h b/include/swift/Frontend/FrontendOptions.h
index 05552ae..0e8146d 100644
--- a/include/swift/Frontend/FrontendOptions.h
+++ b/include/swift/Frontend/FrontendOptions.h
@@ -39,7 +39,7 @@
   InputFileKind InputKind = InputFileKind::IFK_Swift;
 
   void forAllOutputPaths(const InputFile &input,
-                         std::function<void(const std::string &)> fn) const;
+                         std::function<void(StringRef)> fn) const;
 
   bool isOutputFileDirectory() const;
 
@@ -273,8 +273,6 @@
     return llvm::hash_value(0);
   }
 
-  StringRef originalPath() const;
-
   StringRef determineFallbackModuleName() const;
 
   bool isCompilingExactlyOneSwiftFile() const {
@@ -282,8 +280,10 @@
            InputsAndOutputs.hasSingleInput();
   }
 
-  PrimarySpecificPaths getPrimarySpecificPathsForAtMostOnePrimary() const;
-  PrimarySpecificPaths getPrimarySpecificPathsForPrimary(StringRef) const;
+  const PrimarySpecificPaths &
+  getPrimarySpecificPathsForAtMostOnePrimary() const;
+  const PrimarySpecificPaths &
+      getPrimarySpecificPathsForPrimary(StringRef) const;
 
 private:
   static bool canActionEmitDependencies(ActionType);
diff --git a/include/swift/Frontend/InputFile.h b/include/swift/Frontend/InputFile.h
index 309df35..484a08c 100644
--- a/include/swift/Frontend/InputFile.h
+++ b/include/swift/Frontend/InputFile.h
@@ -13,6 +13,8 @@
 #ifndef SWIFT_FRONTEND_INPUTFILE_H
 #define SWIFT_FRONTEND_INPUTFILE_H
 
+#include "swift/Basic/PrimarySpecificPaths.h"
+#include "swift/Basic/SupplementaryOutputPaths.h"
 #include "llvm/Support/MemoryBuffer.h"
 #include <string>
 #include <vector>
@@ -37,10 +39,12 @@
   /// none.
   llvm::MemoryBuffer *Buffer;
 
-  /// Contains the name of the main output file, that is, the .o file for this
-  /// input. If there is no such file, contains an empty string. If the output
-  /// is to be written to stdout, contains "-".
-  std::string OutputFilename;
+  /// If there are explicit primary inputs (i.e. designated with -primary-input
+  /// or -primary-filelist), the paths specific to those inputs (other than the
+  /// input file path itself) are kept here. If there are no explicit primary
+  /// inputs (for instance for whole module optimization), the corresponding
+  /// paths are kept in the first input file.
+  PrimarySpecificPaths PSPs;
 
 public:
   /// Does not take ownership of \p buffer. Does take ownership of (copy) a
@@ -50,13 +54,13 @@
             StringRef outputFilename = StringRef())
       : Filename(
             convertBufferNameFromLLVM_getFileOrSTDIN_toSwiftConventions(name)),
-        IsPrimary(isPrimary), Buffer(buffer), OutputFilename(outputFilename) {
+        IsPrimary(isPrimary), Buffer(buffer), PSPs(PrimarySpecificPaths()) {
     assert(!name.empty());
   }
 
   bool isPrimary() const { return IsPrimary; }
   llvm::MemoryBuffer *buffer() const { return Buffer; }
-  StringRef file() const {
+  const std::string &file() const {
     assert(!Filename.empty());
     return Filename;
   }
@@ -68,13 +72,26 @@
     return filename.equals("<stdin>") ? "-" : filename;
   }
 
-  const std::string &outputFilename() const { return OutputFilename; }
+  std::string outputFilename() const { return PSPs.OutputFilename; }
 
-  void setOutputFilename(StringRef outputFilename) {
-    OutputFilename = outputFilename;
+  const PrimarySpecificPaths &getPrimarySpecificPaths() const { return PSPs; }
+
+  void setPrimarySpecificPaths(const PrimarySpecificPaths &PSPs) {
+    this->PSPs = PSPs;
+  }
+
+  // The next set of functions provides access to those primary-specific paths
+  // accessed directly from an InputFile, as opposed to via
+  // FrontendInputsAndOutputs. They merely make the call sites
+  // a bit shorter. Add more forwarding methods as needed.
+
+  std::string dependenciesFilePath() const {
+    return getPrimarySpecificPaths().SupplementaryOutputs.DependenciesFilePath;
+  }
+  std::string loadedModuleTracePath() const {
+    return getPrimarySpecificPaths().SupplementaryOutputs.LoadedModuleTracePath;
   }
 };
-
 } // namespace swift
 
 #endif /* SWIFT_FRONTEND_INPUTFILE_H */
diff --git a/include/swift/Remote/MetadataReader.h b/include/swift/Remote/MetadataReader.h
index 029c36c..9e365cf 100644
--- a/include/swift/Remote/MetadataReader.h
+++ b/include/swift/Remote/MetadataReader.h
@@ -983,8 +983,8 @@
     case ContextDescriptorKind::Class:
       baseSize = sizeof(TargetClassDescriptor<Runtime>);
       genericHeaderSize = sizeof(TypeGenericContextDescriptorHeader);
-      hasVTable = flags.getKindSpecificFlags()
-                   & (uint16_t)TypeContextDescriptorFlags::HasVTable;
+      hasVTable = TypeContextDescriptorFlags(flags.getKindSpecificFlags())
+                    .class_hasVTable();
       break;
     case ContextDescriptorKind::Enum:
       baseSize = sizeof(TargetEnumDescriptor<Runtime>);
@@ -1082,21 +1082,25 @@
         return Reader->readString(RemoteAddress(nameAddress), nodeName);
       };
       
+      bool isTypeContext = false;
       switch (auto contextKind = parent->getKind()) {
       case ContextDescriptorKind::Class:
         if (!getTypeName())
           return nullptr;
         nodeKind = Demangle::Node::Kind::Class;
+        isTypeContext = true;
         break;
       case ContextDescriptorKind::Struct:
         if (!getTypeName())
           return nullptr;
         nodeKind = Demangle::Node::Kind::Structure;
+        isTypeContext = true;
         break;
       case ContextDescriptorKind::Enum:
         if (!getTypeName())
           return nullptr;
         nodeKind = Demangle::Node::Kind::Enum;
+        isTypeContext = true;
         break;
 
       case ContextDescriptorKind::Extension:
@@ -1125,11 +1129,15 @@
       }
 
       // Override the node kind if this was a Clang-imported type.
-      auto flags = parent->Flags.getKindSpecificFlags();
-      if (flags & (uint16_t)TypeContextDescriptorFlags::IsCTag)
-        nodeKind = Demangle::Node::Kind::Structure;
-      else if (flags & (uint16_t)TypeContextDescriptorFlags::IsCTypedef)
-        nodeKind = Demangle::Node::Kind::TypeAlias;
+      if (isTypeContext) {
+        auto typeFlags =
+          TypeContextDescriptorFlags(parent->Flags.getKindSpecificFlags());
+
+        if (typeFlags.isCTag())
+          nodeKind = Demangle::Node::Kind::Structure;
+        else if (typeFlags.isCTypedef())
+          nodeKind = Demangle::Node::Kind::TypeAlias;
+      }
 
       nameComponents.emplace_back(nodeKind, nodeName);
       
diff --git a/include/swift/Runtime/Metadata.h b/include/swift/Runtime/Metadata.h
index ebf9f3f..cb5b1eb 100644
--- a/include/swift/Runtime/Metadata.h
+++ b/include/swift/Runtime/Metadata.h
@@ -2303,7 +2303,7 @@
     switch (getTypeKind()) {
     case TypeMetadataRecordKind::IndirectObjCClass:
       break;
-        
+
     case TypeMetadataRecordKind::Reserved:
       return nullptr;
 
@@ -3004,6 +3004,10 @@
     return MetadataAccessFunction(AccessFunctionPtr.get());
   }
 
+  TypeContextDescriptorFlags getTypeContextDescriptorFlags() const {
+    return TypeContextDescriptorFlags(this->Flags.getKindSpecificFlags());
+  }
+
   const TargetTypeGenericContextDescriptorHeader<Runtime> &
     getFullGenericContextHeader() const;
 
@@ -3061,16 +3065,14 @@
   using TrailingGenericContextObjects::getGenericContextHeader;
   using TrailingGenericContextObjects::getFullGenericContextHeader;
 
-  /// This bit is set in the context descriptor header's kind-specific flags
-  /// if this is a class descriptor with a vtable descriptor for runtime
-  /// vtable instantiation.
-  static constexpr const uint16_t HasVTableFlag =
-    uint16_t(TypeContextDescriptorFlags::HasVTable);
-  /// This bit is set in the context descriptor header's kind-specific flags
-  /// if this is a class descriptor with a resilient superclass.
-  static constexpr const uint16_t HasResilientSuperclassFlag =
-    uint16_t(TypeContextDescriptorFlags::HasResilientSuperclass);
-  
+  /// The superclass of this class.  This pointer can be interpreted
+  /// using the superclass reference kind stored in the type context
+  /// descriptor flags.  It is null if the class has no formal superclass.
+  ///
+  /// Note that SwiftObject, the implicit superclass of all Swift root
+  /// classes when building with ObjC compatibility, does not appear here.
+  TargetRelativeDirectPointer<Runtime, const void, /*nullable*/true> SuperClass;
+
   /// The number of stored properties in the class, not including its
   /// superclasses. If there is a field offset vector, this is its length.
   uint32_t NumFields;
@@ -3103,12 +3105,6 @@
   }
 
 public:
-  /// Indicates if the type represented by this descriptor
-  /// supports reflection (C and Obj-C enums currently don't).
-  /// FIXME: This is temporarily left as 32-bit integer to avoid
-  ///        changing layout of context descriptor.
-  uint32_t IsReflectable;
-
   /// True if metadata records for this type have a field offset vector for
   /// its stored properties.
   bool hasFieldOffsetVector() const { return FieldOffsetVectorOffset != 0; }
@@ -3123,12 +3119,11 @@
   }
 
   bool hasVTable() const {
-    return (this->Flags.getKindSpecificFlags() & HasVTableFlag) != 0;
+    return this->getTypeContextDescriptorFlags().class_hasVTable();
   }
 
   bool hasResilientSuperclass() const {
-    return (this->Flags.getKindSpecificFlags() & HasResilientSuperclassFlag)
-      != 0;
+    return this->getTypeContextDescriptorFlags().class_hasResilientSuperclass();
   }
   
   const VTableDescriptorHeader *getVTableDescriptor() const {
@@ -3220,12 +3215,6 @@
   /// vector.
   uint32_t FieldOffsetVectorOffset;
   
-  /// Indicates if the type represented by this descriptor
-  /// supports reflection (C and Obj-C enums currently don't).
-  /// FIXME: This is temporarily left as 32-bit integer to avoid
-  ///        changing layout of context descriptor.
-  uint32_t IsReflectable;
-
   /// True if metadata records for this type have a field offset vector for
   /// its stored properties.
   bool hasFieldOffsetVector() const { return FieldOffsetVectorOffset != 0; }
@@ -3268,12 +3257,6 @@
   /// The number of empty cases in the enum.
   uint32_t NumEmptyCases;
 
-  /// Indicates if the type represented by this descriptor
-  /// supports reflection (C and Obj-C enums currently don't).
-  /// FIXME: This is temporarily left as 32-bit integer to avoid
-  ///        changing layout of context descriptor.
-  uint32_t IsReflectable;
-
   uint32_t getNumPayloadCases() const {
     return NumPayloadCasesAndPayloadSizeOffset & 0x00FFFFFFU;
   }
diff --git a/include/swift/SIL/SILArgumentConvention.h b/include/swift/SIL/SILArgumentConvention.h
index 51f594f..b3d5276 100644
--- a/include/swift/SIL/SILArgumentConvention.h
+++ b/include/swift/SIL/SILArgumentConvention.h
@@ -87,6 +87,24 @@
     return Value <= SILArgumentConvention::Indirect_Out;
   }
 
+  bool isOwnedConvention() const {
+    switch (Value) {
+    case SILArgumentConvention::Indirect_In:
+    case SILArgumentConvention::Direct_Owned:
+      return true;
+    case SILArgumentConvention::Indirect_In_Guaranteed:
+    case SILArgumentConvention::Direct_Guaranteed:
+    case SILArgumentConvention::Indirect_Inout:
+    case SILArgumentConvention::Indirect_In_Constant:
+    case SILArgumentConvention::Indirect_Out:
+    case SILArgumentConvention::Indirect_InoutAliasable:
+    case SILArgumentConvention::Direct_Unowned:
+    case SILArgumentConvention::Direct_Deallocating:
+      return false;
+    }
+    llvm_unreachable("covered switch isn't covered?!");
+  }
+
   bool isGuaranteedConvention() const {
     switch (Value) {
     case SILArgumentConvention::Indirect_In_Guaranteed:
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 84d9a8a..659a6ec 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -2515,7 +2515,7 @@
     // Note: This should be treated as a lookup for intra-module dependency
     // purposes, but a subclass already depends on its superclasses and any
     // extensions for many other reasons.
-    auto selector = method->getObjCSelector(nullptr);
+    auto selector = method->getObjCSelector();
     AbstractFunctionDecl *overriddenMethod
       = lookupObjCMethodInType(classDecl->getSuperclass(),
                                selector,
diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp
index 8e659c5..f01ad7c 100644
--- a/lib/AST/ASTPrinter.cpp
+++ b/lib/AST/ASTPrinter.cpp
@@ -1762,7 +1762,13 @@
   assert(Nominal && "extension of non-nominal type");
   if (auto nt = ExtendedType->getAs<NominalType>()) {
     if (auto ParentType = nt->getParent()) {
-      ParentType.print(Printer, Options);
+      if (auto *ParentNT = ParentType->getAs<NominalOrBoundGenericNominalType>()) {
+        // Avoid using the parent type directly because it can be bound
+        // generic type and sugared.
+        ParentNT->getDecl()->getDeclaredType().print(Printer, Options);
+      } else {
+        ParentType.print(Printer, Options);
+      }
       Printer << ".";
     }
   }
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index 62c0314..44c79c1 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -3908,8 +3908,8 @@
   return None;
 }
 
-ObjCSelector AbstractStorageDecl::getObjCGetterSelector(
-               LazyResolver *resolver, Identifier preferredName) const {
+ObjCSelector
+AbstractStorageDecl::getObjCGetterSelector(Identifier preferredName) const {
   // If the getter has an @objc attribute with a name, use that.
   if (auto getter = getGetter()) {
       if (auto name = getNameFromObjcAttribute(getter->getAttrs().
@@ -3920,7 +3920,7 @@
   // Subscripts use a specific selector.
   auto &ctx = getASTContext();
   if (auto *SD = dyn_cast<SubscriptDecl>(this)) {
-    switch (SD->getObjCSubscriptKind(resolver)) {
+    switch (SD->getObjCSubscriptKind()) {
     case ObjCSubscriptKind::None:
       llvm_unreachable("Not an Objective-C subscript");
     case ObjCSubscriptKind::Indexed:
@@ -3940,8 +3940,8 @@
   return VarDecl::getDefaultObjCGetterSelector(ctx, name);
 }
 
-ObjCSelector AbstractStorageDecl::getObjCSetterSelector(
-               LazyResolver *resolver, Identifier preferredName) const {
+ObjCSelector
+AbstractStorageDecl::getObjCSetterSelector(Identifier preferredName) const {
   // If the setter has an @objc attribute with a name, use that.
   auto setter = getSetter();
   auto objcAttr = setter ? setter->getAttrs().getAttribute<ObjCAttr>()
@@ -3953,7 +3953,7 @@
   // Subscripts use a specific selector.
   auto &ctx = getASTContext();
   if (auto *SD = dyn_cast<SubscriptDecl>(this)) {
-    switch (SD->getObjCSubscriptKind(resolver)) {
+    switch (SD->getObjCSubscriptKind()) {
     case ObjCSubscriptKind::None:
       llvm_unreachable("Not an Objective-C subscript");
 
@@ -4554,8 +4554,7 @@
   return elementTy->castTo<AnyFunctionType>()->getResult();
 }
 
-ObjCSubscriptKind SubscriptDecl::getObjCSubscriptKind(
-                    LazyResolver *resolver) const {
+ObjCSubscriptKind SubscriptDecl::getObjCSubscriptKind() const {
   auto indexTy = getIndicesInterfaceType();
 
   // Look through a named 1-tuple.
@@ -4741,8 +4740,8 @@
   return getNameLoc();
 }
 
-ObjCSelector AbstractFunctionDecl::getObjCSelector(
-               LazyResolver *resolver, DeclName preferredName) const {
+ObjCSelector
+AbstractFunctionDecl::getObjCSelector(DeclName preferredName) const {
   // If there is an @objc attribute with a name, use that name.
   auto *objc = getAttrs().getAttribute<ObjCAttr>();
   if (auto name = getNameFromObjcAttribute(objc, preferredName)) {
@@ -4780,9 +4779,9 @@
     // For a getter or setter, go through the variable or subscript decl.
     auto asd = accessor->getStorage();
     if (accessor->isGetter())
-      return asd->getObjCGetterSelector(resolver, baseName);
+      return asd->getObjCGetterSelector(baseName);
     if (accessor->isSetter())
-      return asd->getObjCSetterSelector(resolver, baseName);
+      return asd->getObjCSetterSelector(baseName);
   }
 
   // If this is a zero-parameter initializer with a long selector
diff --git a/lib/AST/SwiftNameTranslation.cpp b/lib/AST/SwiftNameTranslation.cpp
index 2d741c8..4996f2a 100644
--- a/lib/AST/SwiftNameTranslation.cpp
+++ b/lib/AST/SwiftNameTranslation.cpp
@@ -73,9 +73,8 @@
 std::pair<Identifier, ObjCSelector> swift::objc_translation::
 getObjCNameForSwiftDecl(const ValueDecl *VD, DeclName PreferredName){
   ASTContext &Ctx = VD->getASTContext();
-  LazyResolver *Resolver = Ctx.getLazyResolver();
   if (auto *FD = dyn_cast<AbstractFunctionDecl>(VD)) {
-    return {Identifier(), FD->getObjCSelector(Resolver, PreferredName)};
+    return {Identifier(), FD->getObjCSelector(PreferredName)};
   } else if (auto *VAD = dyn_cast<VarDecl>(VD)) {
     if (PreferredName)
       return {PreferredName.getBaseIdentifier(), ObjCSelector()};
diff --git a/lib/AST/TypeJoinMeet.cpp b/lib/AST/TypeJoinMeet.cpp
index f54597f..266c29c 100644
--- a/lib/AST/TypeJoinMeet.cpp
+++ b/lib/AST/TypeJoinMeet.cpp
@@ -19,36 +19,59 @@
 #include "swift/AST/Decl.h"
 #include "swift/AST/Type.h"
 #include "swift/AST/Types.h"
+#include "llvm/ADT/Optional.h"
 #include "llvm/ADT/SmallPtrSet.h"
 using namespace swift;
 
+namespace {
+
 // FIXME: This is currently woefully incomplete, and is only currently
 // used for optimizing away extra exploratory work in the constraint
 // solver. It should eventually encompass all of the subtyping rules
 // of the language.
 struct TypeJoin : CanTypeVisitor<TypeJoin, CanType> {
+  // The type we're joining with another type (the latter of which is
+  // passed as an argument in the visitor.
   CanType First;
 
-  TypeJoin(CanType First) : First(First) {
+  // Always null. Used as a marker for places where we can improve the
+  // implementation.
+  CanType Unimplemented;
+
+  // For convenience, TheAnyType from ASTContext;
+  CanType TheAnyType;
+
+  TypeJoin(CanType First) : First(First), Unimplemented(CanType()) {
     assert(First && "Unexpected null type!");
+    TheAnyType = First->getASTContext().TheAnyType;
   }
 
   static CanType getSuperclassJoin(CanType first, CanType second);
 
+  CanType visitErrorType(CanType second);
+  CanType visitTupleType(CanType second);
+  CanType visitEnumType(CanType second);
+  CanType visitStructType(CanType second);
   CanType visitClassType(CanType second);
+  CanType visitProtocolType(CanType second);
   CanType visitBoundGenericClassType(CanType second);
-  CanType visitArchetypeType(CanType second);
-  CanType visitDynamicSelfType(CanType second);
+  CanType visitBoundGenericEnumType(CanType second);
+  CanType visitBoundGenericStructType(CanType second);
   CanType visitMetatypeType(CanType second);
   CanType visitExistentialMetatypeType(CanType second);
-  CanType visitBoundGenericEnumType(CanType second);
-
-  CanType visitOptionalType(CanType second);
+  CanType visitModuleType(CanType second);
+  CanType visitDynamicSelfType(CanType second);
+  CanType visitArchetypeType(CanType second);
+  CanType visitGenericTypeParamType(CanType second);
+  CanType visitDependentMemberType(CanType second);
+  CanType visitFunctionType(CanType second);
+  CanType visitGenericFunctionType(CanType second);
+  CanType visitProtocolCompositionType(CanType second);
+  CanType visitLValueType(CanType second);
+  CanType visitInOutType(CanType second);
 
   CanType visitType(CanType second) {
-    // FIXME: Implement all the visitors.
-    //    llvm_unreachable("Unimplemented type visitor!");
-    return First->getASTContext().TheAnyType;
+    llvm_unreachable("Unimplemented type visitor!");
   }
 
 public:
@@ -65,18 +88,37 @@
     if (first == second)
       return first;
 
-    // Until we handle all the combinations of joins, we need to make
-    // sure we visit the optional side.
+    // Optionals broadly interact with all the other types since
+    //   T <: T? for any T (including Any)
+    // So we'll always attempt to dispatch Optional here rather than
+    // make every visitor check for it explicitly.
+    if (first->getOptionalObjectType())
+      return TypeJoin(second).visit(first);
+
     if (second->getOptionalObjectType())
       return TypeJoin(first).visit(second);
 
+    // Likewise, rather than making every visitor deal with Any, just
+    // handle it here.
+    // join with Any is always Any
+    if (first->isAny())
+      return first;
+
+    if (second->isAny())
+      return second;
+
+    // Otherwise the first type might be an optional (or not), so
+    // dispatch there.
     return TypeJoin(second).visit(first);
   }
 };
 
 CanType TypeJoin::getSuperclassJoin(CanType first, CanType second) {
+  assert(first != second);
+
+  // FIXME: Handle joins of classes and a single protocol?
   if (!first->mayHaveSuperclass() || !second->mayHaveSuperclass())
-    return first->getASTContext().TheAnyType;
+    return CanType();
 
   /// Walk the superclasses of `first` looking for `second`. Record them
   /// for our second step.
@@ -101,128 +143,222 @@
       return canSuper;
   }
 
-  // There is no common superclass; we're done.
-  return first->getASTContext().TheAnyType;
+  // FIXME: Unimplemented.
+  return CanType();
+}
+
+CanType TypeJoin::visitErrorType(CanType second) {
+  llvm_unreachable("join with ErrorType not supported");
+  return second;
+}
+
+CanType TypeJoin::visitTupleType(CanType second) {
+  assert(First != second);
+
+  return TheAnyType;
+}
+
+CanType TypeJoin::visitEnumType(CanType second) {
+  assert(First != second);
+
+  return Unimplemented;
+}
+
+CanType TypeJoin::visitStructType(CanType second) {
+  assert(First != second);
+
+  // Deal with inout cases in visitInOutType.
+  if (auto inoutTy = First->getAs<InOutType>())
+    return TypeJoin(second).visit(First);
+
+  // FIXME: When possible we should return a protocol or protocol
+  // composition.
+  return TheAnyType;
 }
 
 CanType TypeJoin::visitClassType(CanType second) {
   return getSuperclassJoin(First, second);
 }
 
+CanType TypeJoin::visitProtocolType(CanType second) {
+  assert(First != second);
+
+  // FIXME: We should compute a tighter bound and/or return nullptr if
+  // we cannot. We do this now because existing tests rely on
+  // producing Any for the join of protocols that have a common
+  // supertype.
+  return TheAnyType;
+}
+
 CanType TypeJoin::visitBoundGenericClassType(CanType second) {
   return getSuperclassJoin(First, second);
 }
 
+/// The subtype relationship of Optionals is as follows:
+///   S  <: S?
+///   S? <: T? if S <: T (covariant)
+static Optional<CanType> joinOptional(CanType first, CanType second) {
+  auto firstObject = first.getOptionalObjectType();
+  auto secondObject = second.getOptionalObjectType();
+
+  // If neither is any kind of Optional, we're done.
+  if (!firstObject && !secondObject)
+    return None;
+
+  first = (firstObject ? firstObject : first);
+  second = (secondObject ? secondObject : second);
+
+  auto join = TypeJoin::join(first, second);
+  if (!join)
+    return None;
+
+  return OptionalType::get(join)->getCanonicalType();
+}
+
+CanType TypeJoin::visitBoundGenericEnumType(CanType second) {
+  // Deal with either First or second (or both) being optionals.
+  if (auto joined = joinOptional(First, second))
+    return joined.getValue();
+
+  assert(First != second);
+
+  return Unimplemented;
+}
+
+CanType TypeJoin::visitBoundGenericStructType(CanType second) {
+  assert(First != second);
+
+  // Deal with inout cases in visitInOutType.
+  if (auto inoutTy = First->getAs<InOutType>())
+    return TypeJoin(second).visit(First);
+
+  return Unimplemented;
+}
+
+CanType TypeJoin::visitMetatypeType(CanType second) {
+  assert(First != second);
+
+  if (First->getKind() != second->getKind())
+    return TheAnyType;
+
+  auto firstInstance =
+      First->castTo<AnyMetatypeType>()->getInstanceType()->getCanonicalType();
+  auto secondInstance =
+      second->castTo<AnyMetatypeType>()->getInstanceType()->getCanonicalType();
+
+  auto joinInstance = join(firstInstance, secondInstance);
+  if (!joinInstance)
+    return CanType();
+
+  return MetatypeType::get(joinInstance)->getCanonicalType();
+}
+
+CanType TypeJoin::visitExistentialMetatypeType(CanType second) {
+  assert(First != second);
+
+  if (First->getKind() != second->getKind())
+    return TheAnyType;
+
+  auto firstInstance =
+      First->castTo<AnyMetatypeType>()->getInstanceType()->getCanonicalType();
+  auto secondInstance =
+      second->castTo<AnyMetatypeType>()->getInstanceType()->getCanonicalType();
+
+  auto joinInstance = join(firstInstance, secondInstance);
+  if (!joinInstance)
+    return CanType();
+
+  return ExistentialMetatypeType::get(joinInstance)->getCanonicalType();
+}
+
+CanType TypeJoin::visitModuleType(CanType second) {
+  assert(First != second);
+
+  return TheAnyType;
+}
+
+CanType TypeJoin::visitDynamicSelfType(CanType second) {
+  return getSuperclassJoin(First, second);
+}
+
 CanType TypeJoin::visitArchetypeType(CanType second) {
   return getSuperclassJoin(First, second);
 }
 
-CanType TypeJoin::visitDynamicSelfType(CanType second) {
-  return getSuperclassJoin(First, second);
+CanType TypeJoin::visitGenericTypeParamType(CanType second) {
+  llvm_unreachable("Saw GenericTypeParamType in TypeJoin::join");
 }
 
-CanType TypeJoin::visitMetatypeType(CanType second) {
+CanType TypeJoin::visitDependentMemberType(CanType second) {
+  assert(First != second);
+
   if (First->getKind() != second->getKind())
-    return First->getASTContext().TheAnyType;
+    return TheAnyType;
 
-  auto firstInstance =
-      First->castTo<AnyMetatypeType>()->getInstanceType()->getCanonicalType();
-  auto secondInstance =
-      second->castTo<AnyMetatypeType>()->getInstanceType()->getCanonicalType();
-
-  auto joinInstance = join(firstInstance, secondInstance);
-
-  if (!joinInstance)
-    return First->getASTContext().TheAnyType;
-
-  return MetatypeType::get(joinInstance)->getCanonicalType();
+  return Unimplemented;
 }
 
-CanType TypeJoin::visitExistentialMetatypeType(CanType second) {
+CanType TypeJoin::visitFunctionType(CanType second) {
+  assert(First != second);
+
   if (First->getKind() != second->getKind())
-    return First->getASTContext().TheAnyType;
+    return TheAnyType;
 
-  auto firstInstance =
-      First->castTo<AnyMetatypeType>()->getInstanceType()->getCanonicalType();
-  auto secondInstance =
-      second->castTo<AnyMetatypeType>()->getInstanceType()->getCanonicalType();
+  auto firstFnTy = First->castTo<FunctionType>();
+  auto secondFnTy = second->castTo<FunctionType>();
 
-  auto joinInstance = join(firstInstance, secondInstance);
+  // FIXME: Properly handle these attributes.
+  if (firstFnTy->getExtInfo() != secondFnTy->getExtInfo())
+    return Unimplemented;
 
-  if (!joinInstance)
-    return First->getASTContext().TheAnyType;
+  // FIXME: Properly compute parameter types from getParams().
+  if (firstFnTy->getInput()->getCanonicalType() !=
+      secondFnTy->getInput()->getCanonicalType())
+    return Unimplemented;
 
-  return ExistentialMetatypeType::get(joinInstance)->getCanonicalType();
+  auto firstResult = firstFnTy->getResult()->getCanonicalType();
+  auto secondResult = secondFnTy->getResult()->getCanonicalType();
+
+  auto result = join(firstResult, secondResult);
+  if (!result)
+    return Unimplemented;
+
+  return FunctionType::get(firstFnTy->getInput(), result,
+                           firstFnTy->getExtInfo())->getCanonicalType();
 }
 
-CanType TypeJoin::visitBoundGenericEnumType(CanType second) {
+CanType TypeJoin::visitGenericFunctionType(CanType second) {
+  assert(First != second);
+
   if (First->getKind() != second->getKind())
-    return First->getASTContext().TheAnyType;
+    return TheAnyType;
 
-  bool firstIsOptional, secondIsOptional;
-  auto firstObject = First->getOptionalObjectType(firstIsOptional);
-  auto secondObject = second->getOptionalObjectType(secondIsOptional);
-  if (firstIsOptional || secondIsOptional) {
-    CanType canFirst;
-    CanType canSecond;
-
-    if (firstObject)
-      canFirst = firstObject->getCanonicalType();
-    if (secondObject)
-      canSecond = secondObject->getCanonicalType();
-
-    // Compute the join of the unwrapped type. If there is none, we're done.
-    auto unwrappedJoin =
-        join(canFirst ? canFirst : First, canSecond ? canSecond : second);
-    // FIXME: More general joins of enums need to be handled.
-    if (!unwrappedJoin)
-      return First->getASTContext().TheAnyType;
-
-    return OptionalType::get(unwrappedJoin)->getCanonicalType();
-  }
-
-  // FIXME: More general joins of enums need to be handled.
-  return First->getASTContext().TheAnyType;
+  return Unimplemented;
 }
 
-Type Type::join(Type first, Type second) {
+CanType TypeJoin::visitProtocolCompositionType(CanType second) {
+  if (second->isAny())
+    return second;
+
+  return Unimplemented;
+}
+
+CanType TypeJoin::visitLValueType(CanType second) { return Unimplemented; }
+
+CanType TypeJoin::visitInOutType(CanType second) { return Unimplemented; }
+
+} // namespace
+
+Optional<Type> Type::join(Type first, Type second) {
   assert(first && second && "Unexpected null type!");
 
-  if (!first || !second) {
-    if (first)
-      return Type(ErrorType::get(first->getASTContext()));
+  if (!first || !second)
+    return None;
 
-    if (second)
-      return Type(ErrorType::get(second->getASTContext()));
+  auto join =
+      TypeJoin::join(first->getCanonicalType(), second->getCanonicalType());
+  if (!join)
+    return None;
 
-    return Type();
-  }
-
-  // FIXME: Remove this once all of the cases are implemented.
-  // If one or both of the types are optional types,
-  // look at the underlying object type.
-  bool isFirstOptional, isSecondOptional;
-  Type objectType1 = first->getOptionalObjectType(isFirstOptional);
-  Type objectType2 = second->getOptionalObjectType(isSecondOptional);
-
-  if (isFirstOptional || isSecondOptional) {
-    auto &ctx = first->getASTContext();
-    // Compute the join of the unwrapped type. If there is none, we're done.
-    Type unwrappedJoin = join(objectType1 ? objectType1 : first,
-                              objectType2 ? objectType2 : second);
-
-    auto isAnyType = [&](Type candidate) -> bool {
-      return candidate && candidate->isEqual(ctx.TheAnyType);
-    };
-
-    // If join produced 'Any' but neither type was itself 'Any',
-    // let's return empty type to indicate that there is no join.
-    if (!unwrappedJoin || (isAnyType(unwrappedJoin) &&
-                          !isAnyType(objectType1) && !isAnyType(objectType2)))
-        return nullptr;
-
-    return OptionalType::get(unwrappedJoin);
-  }
-
-  return TypeJoin::join(first->getCanonicalType(), second->getCanonicalType());
+  return join;
 }
diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp
index e23d936..9abdd59 100644
--- a/lib/Driver/Driver.cpp
+++ b/lib/Driver/Driver.cpp
@@ -1966,7 +1966,16 @@
   } else if (!outputPath.empty()) {
     output.setAdditionalOutputForType(outputType, outputPath);
   } else {
-    // Put the auxiliary output file next to the primary output file.
+    // Put the auxiliary output file next to "the" primary output file.
+    //
+    // FIXME: when we're in WMO and have multiple primary outputs, we derive the
+    // additional filename here from the _first_ primary output name, which
+    // means that in the derived OFM (in Job.cpp) the additional output will
+    // have a possibly-surprising name. But that's only half the problem: it
+    // also get associated with the first primary _input_, even when there are
+    // multiple primary inputs; really it should be associated with the build as
+    // a whole -- derived OFM input "" -- but that's a more general thing to
+    // fix.
     llvm::SmallString<128> path;
     if (output.getPrimaryOutputType() != types::TY_Nothing)
       path = output.getPrimaryOutputFilenames()[0];
@@ -1976,6 +1985,7 @@
       formFilenameFromBaseAndExt(OI.ModuleName, /*newExt=*/"", workingDirectory,
                                  path);
     }
+    assert(!path.empty());
 
     bool isTempFile = C.isTemporaryFile(path);
     llvm::sys::path::replace_extension(path,
@@ -2290,7 +2300,7 @@
       OutputFile = getOutputFilename(C, JA, OI, OMForInput, workingDirectory,
                                      TC.getTriple(), C.getArgs(), AtTopLevel,
                                      Base, Primary, Diags, Buf);
-      Output->addPrimaryOutput(CommandInputPair{Base, Primary},
+      Output->addPrimaryOutput(CommandInputPair(Base, Primary),
                                OutputFile);
     };
     // Add an output file for each input action.
@@ -2312,9 +2322,8 @@
     OutputFile = getOutputFilename(C, JA, OI, OutputMap, workingDirectory,
                                    TC.getTriple(), C.getArgs(), AtTopLevel,
                                    BaseInput, PrimaryInput, Diags, Buf);
-    Output->addPrimaryOutput(
-        CommandInputPair{BaseInput, PrimaryInput},
-        OutputFile);
+    Output->addPrimaryOutput(CommandInputPair(BaseInput, PrimaryInput),
+                             OutputFile);
   }
 }
 
@@ -2369,10 +2378,11 @@
       llvm::sys::path::replace_extension(Path, SERIALIZED_MODULE_EXTENSION);
       Output->setAdditionalOutputForType(types::TY_SwiftModuleFile, Path);
     }
-  } else {
+  } else if (Output->getPrimaryOutputType() != types::TY_Nothing) {
     // We're only generating the module as an intermediate, so put it next
     // to the primary output of the compile command.
     llvm::SmallString<128> Path(Output->getPrimaryOutputFilenames()[0]);
+    assert(!Path.empty());
     bool isTempFile = C.isTemporaryFile(Path);
     llvm::sys::path::replace_extension(Path, SERIALIZED_MODULE_EXTENSION);
     Output->setAdditionalOutputForType(types::ID::TY_SwiftModuleFile, Path);
@@ -2399,7 +2409,7 @@
     // Prefer a path from the OutputMap.
     Output->setAdditionalOutputForType(types::TY_SwiftModuleDocFile,
                                        OFMModuleDocOutputPath);
-  } else {
+  } else if (Output->getPrimaryOutputType() != types::TY_Nothing) {
     // Otherwise, put it next to the swiftmodule file.
     llvm::SmallString<128> Path(
         Output->getAnyOutputForType(types::TY_SwiftModuleFile));
diff --git a/lib/Driver/Job.cpp b/lib/Driver/Job.cpp
index c53f052..a2668b3 100644
--- a/lib/Driver/Job.cpp
+++ b/lib/Driver/Job.cpp
@@ -25,19 +25,39 @@
 
 StringRef CommandOutput::getOutputForInputAndType(StringRef PrimaryInputFile,
                                                   types::ID Type) const {
+  if (Type == types::TY_Nothing)
+    return StringRef();
   auto const *M = DerivedOutputMap.getOutputMapForInput(PrimaryInputFile);
   if (!M)
     return StringRef();
   auto const Out = M->find(Type);
   if (Out == M->end())
     return StringRef();
+  assert(!Out->second.empty());
   return StringRef(Out->second);
 }
 
+struct CommandOutputInvariantChecker {
+  CommandOutput const &Out;
+  CommandOutputInvariantChecker(CommandOutput const &CO) : Out(CO) {
+#ifndef NDEBUG
+    Out.checkInvariants();
+#endif
+  }
+  ~CommandOutputInvariantChecker() {
+#ifndef NDEBUG
+    Out.checkInvariants();
+#endif
+  }
+};
+
 void CommandOutput::ensureEntry(StringRef PrimaryInputFile,
                                 types::ID Type,
                                 StringRef OutputFile,
                                 bool Overwrite) {
+  assert(!PrimaryInputFile.empty());
+  assert(!OutputFile.empty());
+  assert(Type != types::TY_Nothing);
   auto &M = DerivedOutputMap.getOrCreateOutputMapForInput(PrimaryInputFile);
   if (Overwrite) {
     M[Type] = OutputFile;
@@ -52,6 +72,35 @@
   }
 }
 
+void CommandOutput::checkInvariants() const {
+  types::forAllTypes([&](types::ID Type) {
+      size_t numOutputsOfType = 0;
+      for (auto const &I : Inputs) {
+        // FIXME: At the moment, empty primary input names correspond to
+        // corner cases in the driver where it is doing TY_Nothing work
+        // and isn't even given a primary input; but at some point we
+        // ought to enable storing derived OFM entries under the empty
+        // name in general, for "whole build" additional outputs. They
+        // are presently (arbitrarily and wrongly) stored in entries
+        // associated with the first primary input of the CommandOutput
+        // that they were derived from.
+        assert(PrimaryOutputType == types::TY_Nothing || !I.Primary.empty());
+        auto const *M = DerivedOutputMap.getOutputMapForInput(I.Primary);
+        if (!M)
+          continue;
+        auto const Out = M->find(Type);
+        if (Out == M->end())
+          continue;
+        assert(!Out->second.empty());
+        ++numOutputsOfType;
+      }
+      assert(numOutputsOfType == 0 ||
+             numOutputsOfType == 1 ||
+             numOutputsOfType == Inputs.size());
+    });
+  assert(AdditionalOutputTypes.count(PrimaryOutputType) == 0);
+}
+
 bool CommandOutput::hasSameAdditionalOutputTypes(
     CommandOutput const &other) const {
   bool sameAdditionalOutputTypes = true;
@@ -65,6 +114,7 @@
 }
 
 void CommandOutput::addOutputs(CommandOutput const &other) {
+  CommandOutputInvariantChecker Check(*this);
   assert(PrimaryOutputType == other.PrimaryOutputType);
   assert(&DerivedOutputMap == &other.DerivedOutputMap);
   Inputs.append(other.Inputs.begin(),
@@ -80,7 +130,9 @@
 
 CommandOutput::CommandOutput(types::ID PrimaryOutputType,
                              OutputFileMap &Derived)
-    : PrimaryOutputType(PrimaryOutputType), DerivedOutputMap(Derived) {}
+    : PrimaryOutputType(PrimaryOutputType), DerivedOutputMap(Derived) {
+  CommandOutputInvariantChecker Check(*this);
+}
 
 types::ID CommandOutput::getPrimaryOutputType() const {
   return PrimaryOutputType;
@@ -88,23 +140,45 @@
 
 void CommandOutput::addPrimaryOutput(CommandInputPair Input,
                                      StringRef PrimaryOutputFile) {
-  Inputs.push_back(Input);
   PrettyStackTraceDriverCommandOutputAddition CrashInfo(
-      "primary", this, Input.Primary, PrimaryOutputType, PrimaryOutputFile);
+    "primary", this, Input.Primary, PrimaryOutputType, PrimaryOutputFile);
+  if (PrimaryOutputType == types::TY_Nothing) {
+    // For TY_Nothing, we accumulate the inputs but do not add any outputs.
+    // The invariant holds on either side of this action because all primary
+    // outputs for this command will be absent (so the length == 0 case in the
+    // invariant holds).
+    CommandOutputInvariantChecker Check(*this);
+    Inputs.push_back(Input);
+    return;
+  }
+  // The invariant holds in the non-TY_Nothing case before an input is added and
+  // _after the corresponding output is added_, but not inbetween. Don't try to
+  // merge these two cases, they're different.
+  CommandOutputInvariantChecker Check(*this);
+  Inputs.push_back(Input);
+  assert(!PrimaryOutputFile.empty());
+  assert(AdditionalOutputTypes.count(PrimaryOutputType) == 0);
   ensureEntry(Input.Primary, PrimaryOutputType, PrimaryOutputFile, false);
 }
 
 StringRef CommandOutput::getPrimaryOutputFilename() const {
+  // FIXME: ideally this shouldn't exist, or should at least assert size() == 1,
+  // and callers should handle cases with multiple primaries explicitly.
   assert(Inputs.size() >= 1);
   return getOutputForInputAndType(Inputs[0].Primary, PrimaryOutputType);
 }
 
 SmallVector<StringRef, 16> CommandOutput::getPrimaryOutputFilenames() const {
   SmallVector<StringRef, 16> V;
+  size_t NonEmpty = 0;
   for (auto const &I : Inputs) {
     auto Out = getOutputForInputAndType(I.Primary, PrimaryOutputType);
     V.push_back(Out);
+    if (!Out.empty())
+      ++NonEmpty;
+    assert(!Out.empty() || PrimaryOutputType == types::TY_Nothing);
   }
+  assert(NonEmpty == 0 || NonEmpty == Inputs.size());
   return V;
 }
 
@@ -112,25 +186,54 @@
                                                StringRef OutputFilename) {
   PrettyStackTraceDriverCommandOutputAddition CrashInfo(
       "additional", this, Inputs[0].Primary, Type, OutputFilename);
+  CommandOutputInvariantChecker Check(*this);
   assert(Inputs.size() >= 1);
+  assert(!OutputFilename.empty());
+  assert(Type != types::TY_Nothing);
 
   // If we're given an "additional" output with the same type as the primary,
   // and we've not yet had such an additional type added, we treat it as a
   // request to overwrite the primary choice (which happens early and is
   // sometimes just inferred) with a refined value (eg. -emit-module-path).
-  bool Overwrite = (Type == PrimaryOutputType &&
-                    AdditionalOutputTypes.count(Type) == 0);
+  bool Overwrite = Type == PrimaryOutputType;
+  if (Overwrite) {
+    assert(AdditionalOutputTypes.count(Type) == 0);
+  } else {
+    AdditionalOutputTypes.insert(Type);
+  }
   ensureEntry(Inputs[0].Primary, Type, OutputFilename, Overwrite);
-  AdditionalOutputTypes.insert(Type);
 }
 
 StringRef CommandOutput::getAdditionalOutputForType(types::ID Type) const {
   if (AdditionalOutputTypes.count(Type) == 0)
     return StringRef();
   assert(Inputs.size() >= 1);
+  // FIXME: ideally this shouldn't associate the additional output with the
+  // first primary, but with a specific primary (and/or possibly the primary "",
+  // for build-wide outputs) specified by the caller.
+  assert(Inputs.size() >= 1);
   return getOutputForInputAndType(Inputs[0].Primary, Type);
 }
 
+SmallVector<StringRef, 16>
+CommandOutput::getAdditionalOutputsForType(types::ID Type) const {
+  SmallVector<StringRef, 16> V;
+  if (AdditionalOutputTypes.count(Type) != 0) {
+    for (auto const &I : Inputs) {
+      auto Out = getOutputForInputAndType(I.Primary, Type);
+      // FIXME: In theory this should always be non-empty -- and V.size() would
+      // always be either 0 or N like with primary outputs -- but in practice
+      // WMO currently associates additional outputs with the _first primary_ in
+      // a multi-primary job, which means that the 2nd..Nth primaries will have
+      // an empty result from getOutputForInputAndType, and V.size() will be 1.
+      if (!Out.empty())
+        V.push_back(Out);
+    }
+  }
+  assert(V.empty() || V.size() == 1 || V.size() == Inputs.size());
+  return V;
+}
+
 StringRef CommandOutput::getAnyOutputForType(types::ID Type) const {
   if (PrimaryOutputType == Type)
     return getPrimaryOutputFilename();
diff --git a/lib/Driver/PrettyStackTrace.cpp b/lib/Driver/PrettyStackTrace.cpp
index a195dc6..b2c9226 100644
--- a/lib/Driver/PrettyStackTrace.cpp
+++ b/lib/Driver/PrettyStackTrace.cpp
@@ -48,6 +48,7 @@
   out << "While adding " << Description
       << " output named " << NewOutputName
       << " of type " << types::getTypeName(NewOutputType)
+      << " for input " << PrimaryInput
       << " to driver CommandOutput\n";
   TheCommandOutput->print(out);
   out << '\n';
diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp
index d251cc1..37d50c7 100644
--- a/lib/Driver/ToolChains.cpp
+++ b/lib/Driver/ToolChains.cpp
@@ -85,6 +85,23 @@
   }
 }
 
+static bool
+addOutputsOfType(ArgStringList &Arguments,
+                 CommandOutput const &Output,
+                 const llvm::opt::ArgList &Args,
+                 types::ID OutputType,
+                 const char *PrefixArgument = nullptr) {
+  bool Added = false;
+  for (auto Output : Output.getAdditionalOutputsForType(OutputType)) {
+    assert(!Output.empty());
+    if (PrefixArgument)
+      Arguments.push_back(PrefixArgument);
+    Arguments.push_back(Args.MakeArgString(Output));
+    Added = true;
+  }
+  return Added;
+}
+
 /// Handle arguments common to all invocations of the frontend (compilation,
 /// module-merging, LLDB's REPL, etc).
 static void addCommonFrontendArgs(const ToolChain &TC,
@@ -197,23 +214,16 @@
   inputArgs.AddAllArgs(arguments, options::OPT_Xllvm);
   inputArgs.AddAllArgs(arguments, options::OPT_Xcc);
 
-  auto moduleDocOutputPath =
-      output.getAdditionalOutputForType(types::TY_SwiftModuleDocFile);
-  if (!moduleDocOutputPath.empty()) {
-    arguments.push_back("-emit-module-doc-path");
-    arguments.push_back(inputArgs.MakeArgString(moduleDocOutputPath));
-  }
+  addOutputsOfType(arguments, output, inputArgs,
+                   types::TY_SwiftModuleDocFile,
+                   "-emit-module-doc-path");
 
   if (llvm::sys::Process::StandardErrHasColors())
     arguments.push_back("-color-diagnostics");
 
-  auto SerializedDiagnosticsPath =
-    output.getAdditionalOutputForType(types::TY_SerializedDiagnostics);
-  if (!SerializedDiagnosticsPath.empty()) {
-    arguments.push_back("-serialize-diagnostics-path");
-    arguments.push_back(
-        inputArgs.MakeArgString(SerializedDiagnosticsPath));
-  }
+  addOutputsOfType(arguments, output, inputArgs,
+                   types::TY_SerializedDiagnostics,
+                   "-serialize-diagnostics-path");
 }
 
 
@@ -443,72 +453,44 @@
   Arguments.push_back("-module-name");
   Arguments.push_back(context.Args.MakeArgString(context.OI.ModuleName));
 
-  auto ModuleOutputPath =
-    context.Output.getAdditionalOutputForType(types::ID::TY_SwiftModuleFile);
-  if (!ModuleOutputPath.empty()) {
-    Arguments.push_back("-emit-module-path");
-    Arguments.push_back(context.Args.MakeArgString(ModuleOutputPath));
+  addOutputsOfType(Arguments, context.Output, context.Args,
+                   types::ID::TY_SwiftModuleFile,
+                   "-emit-module-path");
+
+  if (addOutputsOfType(Arguments, context.Output, context.Args,
+                       types::ID::TY_ObjCHeader, "-emit-objc-header-path")) {
+      assert(context.OI.CompilerMode == OutputInfo::Mode::SingleCompile &&
+             "The Swift tool should only emit an Obj-C header in single compile"
+             "mode!");
   }
 
-  auto ObjCHeaderOutputPath =
-    context.Output.getAdditionalOutputForType(types::ID::TY_ObjCHeader);
-  if (!ObjCHeaderOutputPath.empty()) {
-    assert(context.OI.CompilerMode == OutputInfo::Mode::SingleCompile &&
-           "The Swift tool should only emit an Obj-C header in single compile"
-           "mode!");
+  addOutputsOfType(Arguments, context.Output, context.Args,
+                   types::TY_Dependencies,
+                   "-emit-dependencies-path");
 
-    Arguments.push_back("-emit-objc-header-path");
-    Arguments.push_back(
-        context.Args.MakeArgString(ObjCHeaderOutputPath));
-  }
+  addOutputsOfType(Arguments, context.Output, context.Args,
+                   types::TY_SwiftDeps,
+                   "-emit-reference-dependencies-path");
 
-  auto DependenciesPath =
-    context.Output.getAdditionalOutputForType(types::TY_Dependencies);
-  if (!DependenciesPath.empty()) {
-    Arguments.push_back("-emit-dependencies-path");
-    Arguments.push_back(context.Args.MakeArgString(DependenciesPath));
-  }
+  addOutputsOfType(Arguments, context.Output, context.Args,
+                   types::TY_ModuleTrace,
+                   "-emit-loaded-module-trace-path");
 
-  auto ReferenceDependenciesPath =
-    context.Output.getAdditionalOutputForType(types::TY_SwiftDeps);
-  if (!ReferenceDependenciesPath.empty()) {
-    Arguments.push_back("-emit-reference-dependencies-path");
-    Arguments.push_back(
-        context.Args.MakeArgString(ReferenceDependenciesPath));
-  }
+  addOutputsOfType(Arguments, context.Output, context.Args,
+                   types::TY_TBD,
+                   "-emit-tbd-path");
 
-  auto LoadedModuleTracePath =
-      context.Output.getAdditionalOutputForType(types::TY_ModuleTrace);
-  if (!LoadedModuleTracePath.empty()) {
-    Arguments.push_back("-emit-loaded-module-trace-path");
-    Arguments.push_back(
-        context.Args.MakeArgString(LoadedModuleTracePath));
-  }
-
-  auto TBDPath =
-      context.Output.getAdditionalOutputForType(types::TY_TBD);
-  if (!TBDPath.empty()) {
-    Arguments.push_back("-emit-tbd-path");
-    Arguments.push_back(context.Args.MakeArgString(TBDPath));
-  }
-
-  auto OptRecordPath =
-      context.Output.getAdditionalOutputForType(types::TY_OptRecord);
-  if (!OptRecordPath.empty()) {
-    Arguments.push_back("-save-optimization-record-path");
-    Arguments.push_back(context.Args.MakeArgString(OptRecordPath));
-  }
+  addOutputsOfType(Arguments, context.Output, context.Args,
+                   types::TY_OptRecord,
+                   "-save-optimization-record-path");
 
   if (context.Args.hasArg(options::OPT_migrate_keep_objc_visibility)) {
     Arguments.push_back("-migrate-keep-objc-visibility");
   }
 
-  auto FixitsPath =
-    context.Output.getAdditionalOutputForType(types::TY_Remapping);
-  if (!FixitsPath.empty()) {
-    Arguments.push_back("-emit-remap-file-path");
-    Arguments.push_back(context.Args.MakeArgString(FixitsPath));
-  }
+  addOutputsOfType(Arguments, context.Output, context.Args,
+                   types::TY_Remapping,
+                   "-emit-remap-file-path");
 
   if (context.OI.numThreads > 0) {
     Arguments.push_back("-num-threads");
@@ -743,8 +725,10 @@
     addInputsOfType(Arguments, context.Inputs, context.Args, types::TY_SwiftModuleFile);
     addInputsOfType(Arguments, context.InputActions, types::TY_SwiftModuleFile);
     assert(Arguments.size() - origLen >=
-           context.Inputs.size() + context.InputActions.size());
+           context.Inputs.size() + context.InputActions.size() ||
+           context.OI.CompilerOutputType == types::TY_Nothing);
     assert((Arguments.size() - origLen == context.Inputs.size() ||
+            context.OI.CompilerOutputType == types::TY_Nothing ||
             !context.InputActions.empty()) &&
            "every input to MergeModule must generate a swiftmodule");
   }
diff --git a/lib/Frontend/ArgsToFrontendOptionsConverter.cpp b/lib/Frontend/ArgsToFrontendOptionsConverter.cpp
index 2013a98..68c583a 100644
--- a/lib/Frontend/ArgsToFrontendOptionsConverter.cpp
+++ b/lib/Frontend/ArgsToFrontendOptionsConverter.cpp
@@ -427,12 +427,12 @@
       OutputFilesComputer::getOutputFilenamesFromCommandLineOrFilelist(Args,
                                                                        Diags);
 
-  auto nameToStem =
+  std::string nameToStem =
       outputFilenames && outputFilenames->size() == 1 &&
               outputFilenames->front() != "-" &&
               !llvm::sys::fs::is_directory(outputFilenames->front())
           ? outputFilenames->front()
-          : Opts.InputsAndOutputs.getFilenameOfFirstInput().str();
+          : Opts.InputsAndOutputs.getFilenameOfFirstInput();
 
   Opts.ModuleName = llvm::sys::path::stem(nameToStem);
   return false;
@@ -441,7 +441,7 @@
 bool ArgsToFrontendOptionsConverter::
     computeMainAndSupplementaryOutputFilenames() {
   std::vector<std::string> mainOutputs;
-  SupplementaryOutputPaths supplementaryOutputs;
+  std::vector<SupplementaryOutputPaths> supplementaryOutputs;
   const bool hadError = ArgsToFrontendOutputsConverter(
                             Args, Opts.ModuleName, Opts.InputsAndOutputs, Diags)
                             .convert(mainOutputs, supplementaryOutputs);
@@ -487,9 +487,7 @@
   using namespace options;
   if (const Arg *A = Args.getLastArgNoClaim(OPT_import_objc_header)) {
     Opts.ImplicitObjCHeaderPath = A->getValue();
-    Opts.SerializeBridgingHeader |=
-        !Opts.InputsAndOutputs.hasPrimaryInputs() &&
-        !Opts.InputsAndOutputs.supplementaryOutputs().ModuleOutputPath.empty();
+    Opts.SerializeBridgingHeader |= !Opts.InputsAndOutputs.hasPrimaryInputs();
   }
 }
 void ArgsToFrontendOptionsConverter::computeImplicitImportModuleNames() {
diff --git a/lib/Frontend/ArgsToFrontendOutputsConverter.cpp b/lib/Frontend/ArgsToFrontendOutputsConverter.cpp
index 20fec23..6fd74ee 100644
--- a/lib/Frontend/ArgsToFrontendOutputsConverter.cpp
+++ b/lib/Frontend/ArgsToFrontendOutputsConverter.cpp
@@ -33,7 +33,7 @@
 
 bool ArgsToFrontendOutputsConverter::convert(
     std::vector<std::string> &mainOutputs,
-    SupplementaryOutputPaths &supplementaryOutputs) {
+    std::vector<SupplementaryOutputPaths> &supplementaryOutputs) {
 
   Optional<OutputFilesComputer> ofc =
       OutputFilesComputer::create(Args, Diags, InputsAndOutputs);
@@ -51,10 +51,7 @@
     return true;
 
   mainOutputs = std::move(*mains);
-  assert(supplementaries->size() <= 1 &&
-         "Have not implemented multiple primaries yet");
-  if (!supplementaries->empty())
-    supplementaryOutputs = std::move(supplementaries->front());
+  supplementaryOutputs = std::move(*supplementaries);
   return false;
 }
 
@@ -103,9 +100,10 @@
   ArrayRef<std::string> outputFileArguments =
       outputDirectoryArgument.empty() ? ArrayRef<std::string>(*outputArguments)
                                       : ArrayRef<std::string>();
-  const StringRef firstInput = inputsAndOutputs.hasSingleInput()
-                                   ? inputsAndOutputs.getFilenameOfFirstInput()
-                                   : StringRef();
+  const StringRef firstInput =
+      inputsAndOutputs.hasSingleInput()
+          ? StringRef(inputsAndOutputs.getFilenameOfFirstInput())
+          : StringRef();
   const FrontendOptions::ActionType requestedAction =
       ArgsToFrontendOptionsConverter::determineRequestedAction(args);
 
@@ -143,21 +141,19 @@
 Optional<std::vector<std::string>>
 OutputFilesComputer::computeOutputFiles() const {
   std::vector<std::string> outputFiles;
-  bool hadError = false;
   unsigned i = 0;
-  InputsAndOutputs.forEachInputProducingAMainOutputFile(
-      [&](const InputFile &input) -> void {
+  bool hadError = InputsAndOutputs.forEachInputProducingAMainOutputFile(
+      [&](const InputFile &input) -> bool {
 
         StringRef outputArg = OutputFileArguments.empty()
                                   ? StringRef()
                                   : StringRef(OutputFileArguments[i++]);
 
         Optional<std::string> outputFile = computeOutputFile(outputArg, input);
-        if (!outputFile) {
-          hadError = true;
-          return;
-        }
+        if (!outputFile)
+          return true;
         outputFiles.push_back(*outputFile);
+        return false;
       });
   return hadError ? None : Optional<std::vector<std::string>>(outputFiles);
 }
@@ -208,7 +204,7 @@
 
 std::string
 OutputFilesComputer::determineBaseNameOfOutput(const InputFile &input) const {
-  StringRef nameToStem =
+  std::string nameToStem =
       input.isPrimary()
           ? input.file()
           : ModuleNameArg ? ModuleNameArg->getValue() : FirstInput;
@@ -256,15 +252,15 @@
 
   std::vector<SupplementaryOutputPaths> outputPaths;
   unsigned i = 0;
-  bool hadError = false;
-  InputsAndOutputs.forEachInputProducingSupplementaryOutput(
-      [&](const InputFile &input) -> void {
+  bool hadError = InputsAndOutputs.forEachInputProducingSupplementaryOutput(
+      [&](const InputFile &input) -> bool {
         if (auto suppPaths = computeOutputPathsForOneInput(
-                OutputFiles[i], (*pathsFromUser)[i], input))
+                OutputFiles[i], (*pathsFromUser)[i], input)) {
+          ++i;
           outputPaths.push_back(*suppPaths);
-        else
-          hadError = true;
-        ++i;
+          return false;
+        }
+        return true;
       });
   if (hadError)
     return None;
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index 005665a..f00ba48 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -675,12 +675,12 @@
   if (Args.hasArg(OPT_debug_on_sil)) {
     // Derive the name of the SIL file for debugging from
     // the regular outputfile.
-    StringRef BaseName = FEOpts.InputsAndOutputs.getSingleOutputFilename();
+    std::string BaseName = FEOpts.InputsAndOutputs.getSingleOutputFilename();
     // If there are no or multiple outputfiles, derive the name
     // from the module name.
     if (BaseName.empty())
       BaseName = FEOpts.ModuleName;
-    Opts.SILOutputFileNameForDebugging = BaseName.str();
+    Opts.SILOutputFileNameForDebugging = BaseName;
   }
 
   if (const Arg *A = Args.getLastArg(options::OPT_sanitize_EQ)) {
diff --git a/lib/Frontend/Frontend.cpp b/lib/Frontend/Frontend.cpp
index 483b501..5c29484 100644
--- a/lib/Frontend/Frontend.cpp
+++ b/lib/Frontend/Frontend.cpp
@@ -56,21 +56,58 @@
   return llvm::APInt(64, Code).toString(36, /*Signed=*/false);
 }
 
-PrimarySpecificPaths
+const PrimarySpecificPaths &
 CompilerInvocation::getPrimarySpecificPathsForAtMostOnePrimary() const {
   return getFrontendOptions().getPrimarySpecificPathsForAtMostOnePrimary();
 }
 
-PrimarySpecificPaths CompilerInvocation::getPrimarySpecificPathsForPrimary(
+const PrimarySpecificPaths &
+CompilerInvocation::getPrimarySpecificPathsForPrimary(
     StringRef filename) const {
   return getFrontendOptions().getPrimarySpecificPathsForPrimary(filename);
 }
 
-PrimarySpecificPaths CompilerInvocation::getPrimarySpecificPathsForSourceFile(
+const PrimarySpecificPaths &
+CompilerInvocation::getPrimarySpecificPathsForSourceFile(
     const SourceFile &SF) const {
   return getPrimarySpecificPathsForPrimary(SF.getFilename());
 }
 
+std::string CompilerInvocation::getOutputFilenameForAtMostOnePrimary() const {
+  return getPrimarySpecificPathsForAtMostOnePrimary().OutputFilename;
+}
+std::string
+CompilerInvocation::getMainInputFilenameForDebugInfoForAtMostOnePrimary()
+    const {
+  return getPrimarySpecificPathsForAtMostOnePrimary()
+      .MainInputFilenameForDebugInfo;
+}
+std::string
+CompilerInvocation::getObjCHeaderOutputPathForAtMostOnePrimary() const {
+  return getPrimarySpecificPathsForAtMostOnePrimary()
+      .SupplementaryOutputs.ObjCHeaderOutputPath;
+}
+std::string CompilerInvocation::getModuleOutputPathForAtMostOnePrimary() const {
+  return getPrimarySpecificPathsForAtMostOnePrimary()
+      .SupplementaryOutputs.ModuleOutputPath;
+}
+std::string CompilerInvocation::getReferenceDependenciesFilePathForPrimary(
+    StringRef filename) const {
+  return getPrimarySpecificPathsForPrimary(filename)
+      .SupplementaryOutputs.ReferenceDependenciesFilePath;
+}
+std::string
+CompilerInvocation::getSerializedDiagnosticsPathForAtMostOnePrimary() const {
+  return getPrimarySpecificPathsForAtMostOnePrimary()
+      .SupplementaryOutputs.SerializedDiagnosticsPath;
+}
+std::string CompilerInvocation::getTBDPathForWholeModule() const {
+  assert(getFrontendOptions().InputsAndOutputs.isWholeModule() &&
+         "TBDPath only makes sense in WMO mode");
+  return getPrimarySpecificPathsForAtMostOnePrimary()
+      .SupplementaryOutputs.TBDPath;
+}
+
 void CompilerInstance::createSILModule() {
   assert(MainModule && "main module not created yet");
   // Assume WMO if a -primary-file option was not provided.
@@ -103,9 +140,7 @@
 
   // If we are asked to emit a module documentation file, configure lexing and
   // parsing to remember comments.
-  if (!Invocation.getFrontendOptions()
-           .InputsAndOutputs.supplementaryOutputs()
-           .ModuleDocOutputPath.empty())
+  if (Invocation.getFrontendOptions().InputsAndOutputs.hasModuleDocOutputPath())
     Invocation.getLangOptions().AttachCommentsToDecls = true;
 
   // If we are doing index-while-building, configure lexing and parsing to
@@ -240,7 +275,6 @@
   }
 
   if (input.isPrimary()) {
-    assert(PrimaryBufferIDs.empty() && "re-setting PrimaryBufferID");
     recordPrimaryInputBuffer(*bufferID);
   }
   return false;
@@ -849,20 +883,21 @@
 
 void CompilerInstance::freeSILModule() { TheSILModule.reset(); }
 
-PrimarySpecificPaths
+const PrimarySpecificPaths &
 CompilerInstance::getPrimarySpecificPathsForWholeModuleOptimizationMode()
     const {
   return getPrimarySpecificPathsForAtMostOnePrimary();
 }
-PrimarySpecificPaths
+const PrimarySpecificPaths &
 CompilerInstance::getPrimarySpecificPathsForAtMostOnePrimary() const {
   return Invocation.getPrimarySpecificPathsForAtMostOnePrimary();
 }
-PrimarySpecificPaths
+const PrimarySpecificPaths &
 CompilerInstance::getPrimarySpecificPathsForPrimary(StringRef filename) const {
   return Invocation.getPrimarySpecificPathsForPrimary(filename);
 }
-PrimarySpecificPaths CompilerInstance::getPrimarySpecificPathsForSourceFile(
+const PrimarySpecificPaths &
+CompilerInstance::getPrimarySpecificPathsForSourceFile(
     const SourceFile &SF) const {
   return Invocation.getPrimarySpecificPathsForSourceFile(SF);
 }
diff --git a/lib/Frontend/FrontendInputsAndOutputs.cpp b/lib/Frontend/FrontendInputsAndOutputs.cpp
index 47c7be3..f37eec1 100644
--- a/lib/Frontend/FrontendInputsAndOutputs.cpp
+++ b/lib/Frontend/FrontendInputsAndOutputs.cpp
@@ -36,9 +36,6 @@
   for (InputFile input : other.AllInputs)
     addInput(input);
   IsSingleThreadedWMO = other.IsSingleThreadedWMO;
-  SupplementaryOutputs = other.SupplementaryOutputs;
-  PrimarySpecificPathsForAtMostOnePrimary =
-      other.PrimarySpecificPathsForAtMostOnePrimary;
 }
 
 FrontendInputsAndOutputs &FrontendInputsAndOutputs::
@@ -47,9 +44,6 @@
   for (InputFile input : other.AllInputs)
     addInput(input);
   IsSingleThreadedWMO = other.IsSingleThreadedWMO;
-  SupplementaryOutputs = other.SupplementaryOutputs;
-  PrimarySpecificPathsForAtMostOnePrimary =
-      other.PrimarySpecificPathsForAtMostOnePrimary;
   return *this;
 }
 
@@ -67,43 +61,40 @@
   return hasSingleInput() && getFilenameOfFirstInput() == "-";
 }
 
-StringRef FrontendInputsAndOutputs::getFilenameOfFirstInput() const {
+const std::string &FrontendInputsAndOutputs::getFilenameOfFirstInput() const {
   assert(hasInputs());
   const InputFile &inp = AllInputs[0];
-  StringRef f = inp.file();
+  const std::string &f = inp.file();
   assert(!f.empty());
   return f;
 }
 
-void FrontendInputsAndOutputs::forEachInput(
-    llvm::function_ref<void(const InputFile &)> fn) const {
+bool FrontendInputsAndOutputs::forEachInput(
+    llvm::function_ref<bool(const InputFile &)> fn) const {
   for (const InputFile &input : AllInputs)
-    fn(input);
+    if (fn(input))
+      return true;
+  return false;
 }
 
 // Primaries:
 
 const InputFile &FrontendInputsAndOutputs::firstPrimaryInput() const {
-  assert(!PrimaryInputs.empty());
-  for (const auto &f : AllInputs)
-    if (f.isPrimary())
-      return f;
-  llvm_unreachable("no first primary?!");
+  assert(!PrimaryInputsInOrder.empty());
+  return AllInputs[PrimaryInputsInOrder.front()];
 }
 
 const InputFile &FrontendInputsAndOutputs::lastPrimaryInput() const {
-  assert(!PrimaryInputs.empty());
-  for (const auto &f : reversed(AllInputs))
-    if (f.isPrimary())
-      return f;
-  llvm_unreachable("no last primary?!");
+  assert(!PrimaryInputsInOrder.empty());
+  return AllInputs[PrimaryInputsInOrder.back()];
 }
 
-void FrontendInputsAndOutputs::forEachPrimaryInput(
-    llvm::function_ref<void(const InputFile &)> fn) const {
-  for (auto &f : AllInputs)
-    if (f.isPrimary())
-      fn(f);
+bool FrontendInputsAndOutputs::forEachPrimaryInput(
+    llvm::function_ref<bool(const InputFile &)> fn) const {
+  for (unsigned i : PrimaryInputsInOrder)
+    if (fn(AllInputs[i]))
+      return true;
+  return false;
 }
 
 void FrontendInputsAndOutputs::assertMustNotBeMoreThanOnePrimaryInput() const {
@@ -120,8 +111,9 @@
 
 const InputFile *FrontendInputsAndOutputs::getUniquePrimaryInput() const {
   assertMustNotBeMoreThanOnePrimaryInput();
-  const auto b = PrimaryInputs.begin();
-  return b == PrimaryInputs.end() ? nullptr : &AllInputs[b->second];
+  return PrimaryInputsInOrder.empty()
+             ? nullptr
+             : &AllInputs[PrimaryInputsInOrder.front()];
 }
 
 const InputFile &
@@ -131,11 +123,6 @@
   llvm_unreachable("No primary when one is required");
 }
 
-StringRef FrontendInputsAndOutputs::getNameOfUniquePrimaryInputFile() const {
-  const auto *input = getUniquePrimaryInput();
-  return input == nullptr ? StringRef() : input->file();
-}
-
 std::string FrontendInputsAndOutputs::getStatsFileMangledInputName() const {
   // FIXME: "batch" should probably be some concatenation of all the primary
   // input names, in order to keep the stats file names unique. (Or perhaps just
@@ -146,25 +133,18 @@
 }
 
 bool FrontendInputsAndOutputs::isInputPrimary(StringRef file) const {
-  StringRef correctedFile =
-      InputFile::convertBufferNameFromLLVM_getFileOrSTDIN_toSwiftConventions(
-          file);
-  auto iterator = PrimaryInputs.find(correctedFile);
-  if (iterator == PrimaryInputs.end())
-    return false;
-  assert(AllInputs[iterator->second].isPrimary() &&
-         "PrimaryInputs should only hold primaries");
-  return true;
+  return primaryInputNamed(file) != nullptr;
 }
 
 unsigned FrontendInputsAndOutputs::numberOfPrimaryInputsEndingWith(
     const char *extension) const {
-  return count_if(
-      PrimaryInputs, [&](const llvm::StringMapEntry<unsigned> &elem) -> bool {
-        StringRef filename = AllInputs[elem.second].file();
-
-        return llvm::sys::path::extension(filename).endswith(extension);
-      });
+  unsigned n = 0;
+  (void)forEachPrimaryInput([&](const InputFile &input) -> bool {
+    if (llvm::sys::path::extension(input.file()).endswith(extension))
+      ++n;
+    return false;
+  });
+  return n;
 }
 
 // Input queries
@@ -182,7 +162,7 @@
   if (hasSingleInput()) {
     // If we have exactly one input filename, and its extension is "sil",
     // treat the input as SIL.
-    StringRef Input(getFilenameOfFirstInput());
+    const std::string &Input(getFilenameOfFirstInput());
     return llvm::sys::path::extension(Input).endswith(SIL_EXTENSION);
   }
   // If we have one primary input and it's a filename with extension "sil",
@@ -245,13 +225,17 @@
 
 void FrontendInputsAndOutputs::clearInputs() {
   AllInputs.clear();
-  PrimaryInputs.clear();
+  PrimaryInputsByName.clear();
+  PrimaryInputsInOrder.clear();
 }
 
 void FrontendInputsAndOutputs::addInput(const InputFile &input) {
-  if (!input.file().empty() && input.isPrimary())
-    PrimaryInputs.insert(std::make_pair(input.file(), AllInputs.size()));
+  const unsigned index = AllInputs.size();
   AllInputs.push_back(input);
+  if (input.isPrimary()) {
+    PrimaryInputsInOrder.push_back(index);
+    PrimaryInputsByName.insert(std::make_pair(AllInputs.back().file(), index));
+  }
 }
 
 void FrontendInputsAndOutputs::addInputFile(StringRef file,
@@ -284,62 +268,77 @@
              : hasPrimaryInputs() ? lastPrimaryInput() : lastInput();
 }
 
-void FrontendInputsAndOutputs::forEachInputProducingAMainOutputFile(
-    llvm::function_ref<void(const InputFile &)> fn) const {
-  isSingleThreadedWMO()
-      ? fn(firstInput())
-      : hasPrimaryInputs() ? forEachPrimaryInput(fn) : forEachInput(fn);
+bool FrontendInputsAndOutputs::forEachInputProducingAMainOutputFile(
+    llvm::function_ref<bool(const InputFile &)> fn) const {
+  return isSingleThreadedWMO()
+             ? fn(firstInput())
+             : hasPrimaryInputs() ? forEachPrimaryInput(fn) : forEachInput(fn);
 }
 
 void FrontendInputsAndOutputs::setMainAndSupplementaryOutputs(
     ArrayRef<std::string> outputFiles,
-    SupplementaryOutputPaths supplementaryOutputs) {
+    ArrayRef<SupplementaryOutputPaths> supplementaryOutputs) {
+  if (AllInputs.empty()) {
+    assert(outputFiles.empty() && "Cannot have outputs without inputs");
+    assert(supplementaryOutputs.empty() &&
+           "Cannot have supplementary outputs without inputs");
+    return;
+  }
   if (hasPrimaryInputs()) {
-    unsigned i = 0;
-    for (auto index : indices(AllInputs)) {
-      InputFile &f = AllInputs[index];
-      if (f.isPrimary())
-        f.setOutputFilename(outputFiles[i++]);
-    }
-  } else if (isSingleThreadedWMO()) {
-    AllInputs[0].setOutputFilename(outputFiles[0]);
-  } else {
-    for (auto i : indices(AllInputs))
-      AllInputs[i].setOutputFilename(outputFiles[i]);
-  }
-  SupplementaryOutputs = supplementaryOutputs;
+    const auto N = primaryInputCount();
+    assert(outputFiles.size() == N && "Must have one main output per primary");
+    assert(supplementaryOutputs.size() == N &&
+           "Must have one set of supplementary outputs per primary");
 
-  if (hasUniquePrimaryInput() || (hasInputs() && isWholeModule())) {
-    // When batch mode is fully implemented, each InputFile will own
-    // a PrimarySpecificPaths.
-    PrimarySpecificPathsForAtMostOnePrimary.OutputFilename =
-        getSingleOutputFilename();
-    PrimarySpecificPathsForAtMostOnePrimary.MainInputFilenameForDebugInfo =
-        hasInputsProducingMainOutputs() ? firstInputProducingOutput().file()
-                                        : StringRef();
-    PrimarySpecificPathsForAtMostOnePrimary.SupplementaryOutputs =
-        supplementaryOutputs;
+    unsigned i = 0;
+    for (auto &input : AllInputs) {
+      if (input.isPrimary()) {
+        input.setPrimarySpecificPaths(PrimarySpecificPaths(
+            outputFiles[i], input.file(), supplementaryOutputs[i]));
+        ++i;
+      }
+    }
+    return;
   }
+  assert(supplementaryOutputs.size() == 1 &&
+         "WMO only ever produces one set of supplementary outputs");
+  if (outputFiles.size() == 1) {
+    AllInputs.front().setPrimarySpecificPaths(PrimarySpecificPaths(
+        outputFiles.front(), firstInputProducingOutput().file(),
+        supplementaryOutputs.front()));
+    return;
+  }
+  assert(outputFiles.size() == AllInputs.size() &&
+         "Multi-threaded WMO requires one main output per input");
+  for (auto i : indices(AllInputs))
+    AllInputs[i].setPrimarySpecificPaths(PrimarySpecificPaths(
+        outputFiles[i], outputFiles[i],
+        i == 0 ? supplementaryOutputs.front() : SupplementaryOutputPaths()));
 }
 
 std::vector<std::string> FrontendInputsAndOutputs::copyOutputFilenames() const {
   std::vector<std::string> outputs;
-  forEachInputProducingAMainOutputFile([&](const InputFile &input) -> void {
-    outputs.push_back(input.outputFilename());
-  });
+  (void)forEachInputProducingAMainOutputFile(
+      [&](const InputFile &input) -> bool {
+        outputs.push_back(input.outputFilename());
+        return false;
+      });
   return outputs;
 }
 
 void FrontendInputsAndOutputs::forEachOutputFilename(
-    llvm::function_ref<void(const std::string &)> fn) const {
-  forEachInputProducingAMainOutputFile(
-      [&](const InputFile &input) -> void { fn(input.outputFilename()); });
+    llvm::function_ref<void(StringRef)> fn) const {
+  (void)forEachInputProducingAMainOutputFile(
+      [&](const InputFile &input) -> bool {
+        fn(input.outputFilename());
+        return false;
+      });
 }
 
-StringRef FrontendInputsAndOutputs::getSingleOutputFilename() const {
+std::string FrontendInputsAndOutputs::getSingleOutputFilename() const {
   assertMustNotBeMoreThanOnePrimaryInputUnlessBatchModeChecksHaveBeenBypassed();
-  return hasInputs() ? StringRef(lastInputProducingOutput().outputFilename())
-                     : StringRef();
+  return hasInputs() ? lastInputProducingOutput().outputFilename()
+                     : std::string();
 }
 
 bool FrontendInputsAndOutputs::isOutputFilenameStdout() const {
@@ -362,34 +361,63 @@
   return hasPrimaryInputs() ? primaryInputCount() : hasInputs() ? 1 : 0;
 }
 
-void FrontendInputsAndOutputs::forEachInputProducingSupplementaryOutput(
-    llvm::function_ref<void(const InputFile &)> fn) const {
-  if (hasPrimaryInputs())
-    forEachPrimaryInput(fn);
-  else if (hasInputs())
-    fn(firstInput());
+bool FrontendInputsAndOutputs::forEachInputProducingSupplementaryOutput(
+    llvm::function_ref<bool(const InputFile &)> fn) const {
+  return hasPrimaryInputs() ? forEachPrimaryInput(fn)
+                            : hasInputs() ? fn(firstInput()) : false;
+}
+
+bool FrontendInputsAndOutputs::hasSupplementaryOutputPath(
+    llvm::function_ref<const std::string &(const SupplementaryOutputPaths &)>
+        extractorFn) const {
+  return forEachInputProducingSupplementaryOutput([&](const InputFile &input)
+                                                      -> bool {
+    return !extractorFn(input.getPrimarySpecificPaths().SupplementaryOutputs)
+                .empty();
+  });
 }
 
 bool FrontendInputsAndOutputs::hasDependenciesPath() const {
-  return !supplementaryOutputs().DependenciesFilePath.empty();
+  return hasSupplementaryOutputPath(
+      [](const SupplementaryOutputPaths &outs) -> const std::string & {
+        return outs.DependenciesFilePath;
+      });
 }
 bool FrontendInputsAndOutputs::hasReferenceDependenciesPath() const {
-  return !supplementaryOutputs().ReferenceDependenciesFilePath.empty();
+  return hasSupplementaryOutputPath(
+      [](const SupplementaryOutputPaths &outs) -> const std::string & {
+        return outs.ReferenceDependenciesFilePath;
+      });
 }
 bool FrontendInputsAndOutputs::hasObjCHeaderOutputPath() const {
-  return !supplementaryOutputs().ObjCHeaderOutputPath.empty();
+  return hasSupplementaryOutputPath(
+      [](const SupplementaryOutputPaths &outs) -> const std::string & {
+        return outs.ObjCHeaderOutputPath;
+      });
 }
 bool FrontendInputsAndOutputs::hasLoadedModuleTracePath() const {
-  return !supplementaryOutputs().LoadedModuleTracePath.empty();
+  return hasSupplementaryOutputPath(
+      [](const SupplementaryOutputPaths &outs) -> const std::string & {
+        return outs.LoadedModuleTracePath;
+      });
 }
 bool FrontendInputsAndOutputs::hasModuleOutputPath() const {
-  return !supplementaryOutputs().ModuleOutputPath.empty();
+  return hasSupplementaryOutputPath(
+      [](const SupplementaryOutputPaths &outs) -> const std::string & {
+        return outs.ModuleOutputPath;
+      });
 }
 bool FrontendInputsAndOutputs::hasModuleDocOutputPath() const {
-  return !supplementaryOutputs().ModuleDocOutputPath.empty();
+  return hasSupplementaryOutputPath(
+      [](const SupplementaryOutputPaths &outs) -> const std::string & {
+        return outs.ModuleDocOutputPath;
+      });
 }
 bool FrontendInputsAndOutputs::hasTBDPath() const {
-  return !supplementaryOutputs().TBDPath.empty();
+  return hasSupplementaryOutputPath(
+      [](const SupplementaryOutputPaths &outs) -> const std::string & {
+        return outs.TBDPath;
+      });
 }
 
 bool FrontendInputsAndOutputs::hasDependencyTrackerPath() const {
@@ -397,13 +425,31 @@
          hasLoadedModuleTracePath();
 }
 
-PrimarySpecificPaths
+const PrimarySpecificPaths &
 FrontendInputsAndOutputs::getPrimarySpecificPathsForAtMostOnePrimary() const {
-  return PrimarySpecificPathsForAtMostOnePrimary;
+  assertMustNotBeMoreThanOnePrimaryInputUnlessBatchModeChecksHaveBeenBypassed();
+  static auto emptyPaths = PrimarySpecificPaths();
+  return hasInputs() ? firstInputProducingOutput().getPrimarySpecificPaths()
+                     : emptyPaths;
 }
 
-PrimarySpecificPaths
+const PrimarySpecificPaths &
 FrontendInputsAndOutputs::getPrimarySpecificPathsForPrimary(
     StringRef filename) const {
-  return getPrimarySpecificPathsForAtMostOnePrimary(); // just a stub for now
+  const InputFile *f = primaryInputNamed(filename);
+  return f->getPrimarySpecificPaths();
+}
+
+const InputFile *
+FrontendInputsAndOutputs::primaryInputNamed(StringRef name) const {
+  assert(!name.empty() && "input files have names");
+  StringRef correctedFile =
+      InputFile::convertBufferNameFromLLVM_getFileOrSTDIN_toSwiftConventions(
+          name);
+  auto iterator = PrimaryInputsByName.find(correctedFile);
+  if (iterator == PrimaryInputsByName.end())
+    return nullptr;
+  const InputFile *f = &AllInputs[iterator->second];
+  assert(f->isPrimary() && "PrimaryInputsByName should only include primries");
+  return f;
 }
diff --git a/lib/Frontend/FrontendOptions.cpp b/lib/Frontend/FrontendOptions.cpp
index e220d53..e801410 100644
--- a/lib/Frontend/FrontendOptions.cpp
+++ b/lib/Frontend/FrontendOptions.cpp
@@ -108,7 +108,7 @@
 }
 
 void FrontendOptions::forAllOutputPaths(
-    const InputFile &input, std::function<void(const std::string &)> fn) const {
+    const InputFile &input, std::function<void(StringRef)> fn) const {
   if (RequestedAction != FrontendOptions::ActionType::EmitModuleOnly &&
       RequestedAction != FrontendOptions::ActionType::MergeModules) {
     if (InputsAndOutputs.isWholeModule())
@@ -116,28 +116,19 @@
     else
       fn(input.outputFilename());
   }
-  const std::string *outputs[] = {
-      &InputsAndOutputs.supplementaryOutputs().ModuleOutputPath,
-      &InputsAndOutputs.supplementaryOutputs().ModuleDocOutputPath,
-      &InputsAndOutputs.supplementaryOutputs().ObjCHeaderOutputPath};
-  for (const std::string *next : outputs) {
-    if (!next->empty())
-      fn(*next);
-  }
-}
-
-
-StringRef FrontendOptions::originalPath() const {
-  if (InputsAndOutputs.hasNamedOutputFile())
-    // Put the serialized diagnostics file next to the output file.
-    return InputsAndOutputs.getSingleOutputFilename();
-
-  // If we have a primary input, so use that as the basis for the name of the
-  // serialized diagnostics file, otherwise fall back on the
-  // module name.
-  const auto input = InputsAndOutputs.getUniquePrimaryInput();
-  return input ? llvm::sys::path::filename(input->file())
-               : StringRef(ModuleName);
+  (void)InputsAndOutputs.forEachInputProducingSupplementaryOutput(
+      [&](const InputFile &inp) -> bool {
+        const SupplementaryOutputPaths &outs =
+            inp.getPrimarySpecificPaths().SupplementaryOutputs;
+        const std::string *outputs[] = {&outs.ModuleOutputPath,
+                                        &outs.ModuleDocOutputPath,
+                                        &outs.ObjCHeaderOutputPath};
+        for (const std::string *next : outputs) {
+          if (!next->empty())
+            fn(*next);
+        }
+        return false;
+      });
 }
 
 const char *
@@ -387,12 +378,12 @@
   }
 }
 
-PrimarySpecificPaths
+const PrimarySpecificPaths &
 FrontendOptions::getPrimarySpecificPathsForAtMostOnePrimary() const {
   return InputsAndOutputs.getPrimarySpecificPathsForAtMostOnePrimary();
 }
 
-PrimarySpecificPaths
+const PrimarySpecificPaths &
 FrontendOptions::getPrimarySpecificPathsForPrimary(StringRef filename) const {
   return InputsAndOutputs.getPrimarySpecificPathsForPrimary(filename);
 }
diff --git a/lib/FrontendTool/FrontendTool.cpp b/lib/FrontendTool/FrontendTool.cpp
index 08022fc..3bce5e8 100644
--- a/lib/FrontendTool/FrontendTool.cpp
+++ b/lib/FrontendTool/FrontendTool.cpp
@@ -40,6 +40,7 @@
 #include "swift/Basic/FileSystem.h"
 #include "swift/Basic/JSONSerialization.h"
 #include "swift/Basic/LLVMContext.h"
+#include "swift/Basic/LLVMInitialize.h"
 #include "swift/Basic/SourceManager.h"
 #include "swift/Basic/Statistic.h"
 #include "swift/Basic/Timer.h"
@@ -99,20 +100,20 @@
 }
 
 /// Emits a Make-style dependencies file.
-static bool emitMakeDependencies(DiagnosticEngine &diags,
-                                 DependencyTracker &depTracker,
-                                 const FrontendOptions &opts,
-                                 const InputFile &input) {
+static bool emitMakeDependenciesIfNeeded(DiagnosticEngine &diags,
+                                         DependencyTracker *depTracker,
+                                         const FrontendOptions &opts,
+                                         const InputFile &input) {
+  const std::string &dependenciesFilePath = input.dependenciesFilePath();
+  if (dependenciesFilePath.empty())
+    return false;
+
   std::error_code EC;
-  llvm::raw_fd_ostream out(
-      opts.InputsAndOutputs.supplementaryOutputs().DependenciesFilePath, EC,
-      llvm::sys::fs::F_None);
+  llvm::raw_fd_ostream out(dependenciesFilePath, EC, llvm::sys::fs::F_None);
 
   if (out.has_error() || EC) {
-    diags.diagnose(
-        SourceLoc(), diag::error_opening_output,
-        opts.InputsAndOutputs.supplementaryOutputs().DependenciesFilePath,
-        EC.message());
+    diags.diagnose(SourceLoc(), diag::error_opening_output,
+                   dependenciesFilePath, EC.message());
     out.clear_error();
     return true;
   }
@@ -139,7 +140,7 @@
 
   // FIXME: Xcode can't currently handle multiple targets in a single
   // dependency line.
-  opts.forAllOutputPaths(input, [&](StringRef targetName) {
+  opts.forAllOutputPaths(input, [&](const StringRef targetName) {
     out << escape(targetName) << " :";
     // First include all other files in the module. Make-style dependencies
     // need to be conservative!
@@ -148,7 +149,7 @@
       out << ' ' << escape(path);
     // Then print dependencies we've picked up during compilation.
     for (auto const &path :
-           reversePathSortedFilenames(depTracker.getDependencies()))
+           reversePathSortedFilenames(depTracker->getDependencies()))
       out << ' ' << escape(path);
     out << '\n';
   });
@@ -156,15 +157,13 @@
   return false;
 }
 
-static bool emitMakeDependencies(DiagnosticEngine &diags,
-                                 DependencyTracker &depTracker,
-                                 const FrontendOptions &opts) {
-  bool hadError = false;
-  opts.InputsAndOutputs.forEachInputProducingSupplementaryOutput(
-      [&](const InputFile &f) -> void {
-        hadError = emitMakeDependencies(diags, depTracker, opts, f) || hadError;
+static bool emitMakeDependenciesIfNeeded(DiagnosticEngine &diags,
+                                         DependencyTracker *depTracker,
+                                         const FrontendOptions &opts) {
+  return opts.InputsAndOutputs.forEachInputProducingSupplementaryOutput(
+      [&](const InputFile &f) -> bool {
+        return emitMakeDependenciesIfNeeded(diags, depTracker, opts, f);
       });
-  return hadError;
 }
 
 namespace {
@@ -189,20 +188,16 @@
 
 static bool emitLoadedModuleTraceIfNeeded(ASTContext &ctxt,
                                           DependencyTracker *depTracker,
-                                          const FrontendOptions &opts) {
-  if (opts.InputsAndOutputs.supplementaryOutputs()
-          .LoadedModuleTracePath.empty())
+                                          StringRef loadedModuleTracePath,
+                                          StringRef moduleName) {
+  if (loadedModuleTracePath.empty())
     return false;
   std::error_code EC;
-  llvm::raw_fd_ostream out(
-      opts.InputsAndOutputs.supplementaryOutputs().LoadedModuleTracePath, EC,
-      llvm::sys::fs::F_Append);
+  llvm::raw_fd_ostream out(loadedModuleTracePath, EC, llvm::sys::fs::F_Append);
 
   if (out.has_error() || EC) {
-    ctxt.Diags.diagnose(
-        SourceLoc(), diag::error_opening_output,
-        opts.InputsAndOutputs.supplementaryOutputs().LoadedModuleTracePath,
-        EC.message());
+    ctxt.Diags.diagnose(SourceLoc(), diag::error_opening_output,
+                        loadedModuleTracePath, EC.message());
     out.clear_error();
     return true;
   }
@@ -235,7 +230,7 @@
   }
 
   LoadedModuleTraceFormat trace = {
-      /*name=*/opts.ModuleName,
+      /*name=*/moduleName,
       /*arch=*/ctxt.LangOpts.Target.getArchName(),
       /*swiftmodules=*/reversePathSortedFilenames(swiftModules)};
 
@@ -255,6 +250,16 @@
   return true;
 }
 
+static bool
+emitLoadedModuleTraceForAllPrimariesIfNeeded(ASTContext &ctxt,
+                                             DependencyTracker *depTracker,
+                                             const FrontendOptions &opts) {
+  return opts.InputsAndOutputs.forEachInputProducingSupplementaryOutput(
+      [&](const InputFile &input) -> bool {
+        return emitLoadedModuleTraceIfNeeded(
+            ctxt, depTracker, input.loadedModuleTracePath(), opts.ModuleName);
+      });
+}
 
 /// Gets an output stream for the provided output filename, or diagnoses to the
 /// provided AST Context and returns null if there was an error getting the
@@ -306,7 +311,7 @@
                   PSPs.OutputFilename, opts.EmitSortedSIL);
 }
 
-static bool printAsObjCIfNeeded(const std::string &outputPath, ModuleDecl *M,
+static bool printAsObjCIfNeeded(StringRef outputPath, ModuleDecl *M,
                                 StringRef bridgingHeader, bool moduleIsPublic) {
   using namespace llvm::sys;
 
@@ -739,19 +744,18 @@
 static void emitReferenceDependenciesForAllPrimaryInputsIfNeeded(
     CompilerInvocation &Invocation, CompilerInstance &Instance) {
   if (Invocation.getFrontendOptions()
-          .InputsAndOutputs.supplementaryOutputs()
-          .ReferenceDependenciesFilePath.empty())
-    return;
-  if (Instance.getPrimarySourceFiles().empty()) {
+          .InputsAndOutputs.hasReferenceDependenciesPath() &&
+      Instance.getPrimarySourceFiles().empty()) {
     Instance.getASTContext().Diags.diagnose(
         SourceLoc(), diag::emit_reference_dependencies_without_primary_file);
     return;
   }
   for (auto *SF : Instance.getPrimarySourceFiles()) {
-    std::string referenceDependenciesFilePath =
-        Invocation.getPrimarySpecificPathsForSourceFile(*SF)
-            .SupplementaryOutputs.ReferenceDependenciesFilePath;
-    emitReferenceDependenciesIfNeeded(Instance.getASTContext().Diags, SF,
+    const std::string &referenceDependenciesFilePath =
+        Invocation.getReferenceDependenciesFilePathForPrimary(
+            SF->getFilename());
+    if (!referenceDependenciesFilePath.empty())
+      (void)emitReferenceDependencies(Instance.getASTContext().Diags, SF,
                                       *Instance.getDependencyTracker(),
                                       referenceDependenciesFilePath);
   }
@@ -759,11 +763,13 @@
 
 static bool writeTBDIfNeeded(CompilerInvocation &Invocation,
                              CompilerInstance &Instance) {
-  StringRef TBDPath = Invocation.getFrontendOptions()
-                          .InputsAndOutputs.supplementaryOutputs()
-                          .TBDPath;
-  if (TBDPath.empty())
+  if (!Invocation.getFrontendOptions().InputsAndOutputs.hasTBDPath())
     return false;
+
+  const std::string &TBDPath = Invocation.getTBDPathForWholeModule();
+  assert(!TBDPath.empty() &&
+         "If not WMO, getTBDPathForWholeModule should have failed");
+
   auto installName = Invocation.getFrontendOptions().TBDInstallName.empty()
                          ? "lib" + Invocation.getModuleName().str() + ".dylib"
                          : Invocation.getFrontendOptions().TBDInstallName;
@@ -805,24 +811,24 @@
   // If there are primary source files, build a separate SILModule for
   // each source file, and run the remaining SILOpt-Serialize-IRGen-LLVM
   // once for each such input.
-  if (auto *PrimaryFile = Instance.getPrimarySourceFile()) {
+  std::deque<PostSILGenInputs> PSGIs;
+  for (auto *PrimaryFile : Instance.getPrimarySourceFiles()) {
     auto SM = performSILGeneration(*PrimaryFile, SILOpts, None);
-    std::deque<PostSILGenInputs> PSGIs;
     const PrimarySpecificPaths PSPs =
         Instance.getPrimarySpecificPathsForSourceFile(*PrimaryFile);
     PSGIs.push_back(PostSILGenInputs{std::move(SM), true, PrimaryFile, PSPs});
-    return PSGIs;
   }
+  if (!PSGIs.empty())
+    return PSGIs;
   // If there are primary inputs but no primary _source files_, there might be
   // a primary serialized input.
-  std::deque<PostSILGenInputs> PSGIs;
   for (FileUnit *fileUnit : mod->getFiles()) {
     if (auto SASTF = dyn_cast<SerializedASTFile>(fileUnit))
       if (Invocation.getFrontendOptions().InputsAndOutputs.isInputPrimary(
               SASTF->getFilename())) {
         assert(PSGIs.empty() && "Can only handle one primary AST input");
         auto SM = performSILGeneration(*SASTF, SILOpts, None);
-        const PrimarySpecificPaths PSPs =
+        const PrimarySpecificPaths &PSPs =
             Instance.getPrimarySpecificPathsForPrimary(SASTF->getFilename());
         PSGIs.push_back(
             PostSILGenInputs{std::move(SM), !fileIsSIB(SASTF), mod, PSPs});
@@ -831,6 +837,18 @@
   return PSGIs;
 }
 
+/// Emits index data for all primary inputs, or the main module.
+static bool
+emitIndexData(CompilerInvocation &Invocation, CompilerInstance &Instance) {
+  bool hadEmitIndexDataError = false;
+  if (Instance.getPrimarySourceFiles().empty())
+    return emitIndexDataIfNeeded(nullptr, Invocation, Instance);
+  for (SourceFile *SF : Instance.getPrimarySourceFiles())
+    hadEmitIndexDataError = emitIndexDataIfNeeded(SF, Invocation, Instance) ||
+                            hadEmitIndexDataError;
+  return hadEmitIndexDataError;
+}
+
 static bool performCompileStepsPostSILGen(
     CompilerInstance &Instance, CompilerInvocation &Invocation,
     std::unique_ptr<SILModule> SM, bool astGuaranteedToCorrespondToSIL,
@@ -905,20 +923,17 @@
   if (opts.PrintClangStats && Context.getClangModuleLoader())
     Context.getClangModuleLoader()->printStatistics();
 
-  if (!opts.InputsAndOutputs.supplementaryOutputs()
-           .DependenciesFilePath.empty())
-    (void)emitMakeDependencies(Context.Diags, *Instance.getDependencyTracker(),
-                               opts);
+  (void)emitMakeDependenciesIfNeeded(Context.Diags,
+                                     Instance.getDependencyTracker(), opts);
 
   emitReferenceDependenciesForAllPrimaryInputsIfNeeded(Invocation, Instance);
 
-  (void)emitLoadedModuleTraceIfNeeded(Context, Instance.getDependencyTracker(),
-                                      opts);
+  (void)emitLoadedModuleTraceForAllPrimariesIfNeeded(
+      Context, Instance.getDependencyTracker(), opts);
 
   if (Context.hadError()) {
     //  Emit the index store data even if there were compiler errors.
-    (void)emitIndexDataIfNeeded(Instance.getPrimarySourceFile(), Invocation,
-                                Instance);
+    (void)emitIndexData(Invocation, Instance);
     return true;
   }
 
@@ -932,11 +947,11 @@
   // We've just been told to perform a typecheck, so we can return now.
   if (Action == FrontendOptions::ActionType::Typecheck) {
     const bool hadPrintAsObjCError = printAsObjCIfNeeded(
-        opts.InputsAndOutputs.supplementaryOutputs().ObjCHeaderOutputPath,
+        Invocation.getObjCHeaderOutputPathForAtMostOnePrimary(),
         Instance.getMainModule(), opts.ImplicitObjCHeaderPath, moduleIsPublic);
 
-    const bool hadEmitIndexDataError = emitIndexDataIfNeeded(
-        Instance.getPrimarySourceFile(), Invocation, Instance);
+    const bool hadEmitIndexDataError = emitIndexData(Invocation, Instance);
+
     return hadPrintAsObjCError || hadEmitIndexDataError || Context.hadError();
   }
 
@@ -1008,7 +1023,7 @@
   serializationOpts.OutputPath = outs.ModuleOutputPath.c_str();
   serializationOpts.DocOutputPath = outs.ModuleDocOutputPath.c_str();
   serializationOpts.GroupInfoPath = opts.GroupInfoPath.c_str();
-  if (opts.SerializeBridgingHeader)
+  if (opts.SerializeBridgingHeader && !outs.ModuleOutputPath.empty())
     serializationOpts.ImportedHeader = opts.ImplicitObjCHeaderPath;
   serializationOpts.ModuleLinkName = opts.ModuleLinkName;
   serializationOpts.ExtraClangOptions =
@@ -1144,7 +1159,7 @@
 }
 
 static bool generateCode(CompilerInvocation &Invocation,
-                         CompilerInstance &Instance, std::string OutputFilename,
+                         CompilerInstance &Instance, StringRef OutputFilename,
                          llvm::Module *IRModule,
                          llvm::GlobalVariable *HashGlobal,
                          UnifiedStatsReporter *Stats) {
@@ -1263,21 +1278,21 @@
   if (Action == FrontendOptions::ActionType::EmitSIB)
     return serializeSIB(SM.get(), PSPs, Instance.getASTContext(), MSF);
 
-  const bool haveModulePath =
-      !PSPs.SupplementaryOutputs.ModuleOutputPath.empty() ||
-      !PSPs.SupplementaryOutputs.ModuleDocOutputPath.empty();
-  if (haveModulePath && !SM->isSerialized())
-    SM->serialize();
+  {
+    const bool haveModulePath = PSPs.haveModuleOrModuleDocOutputPaths();
+    if (haveModulePath && !SM->isSerialized())
+      SM->serialize();
 
-  if (haveModulePath) {
-    if (Action == FrontendOptions::ActionType::MergeModules ||
-        Action == FrontendOptions::ActionType::EmitModuleOnly) {
-      // What if MSF is a module?
-      // emitIndexDataIfNeeded already handles that case;
-      // it'll index everything.
-      return emitIndexDataIfNeeded(MSF.dyn_cast<SourceFile *>(), Invocation,
-                                   Instance) ||
-             Context.hadError();
+    if (haveModulePath) {
+      if (Action == FrontendOptions::ActionType::MergeModules ||
+          Action == FrontendOptions::ActionType::EmitModuleOnly) {
+        // What if MSF is a module?
+        // emitIndexDataIfNeeded already handles that case;
+        // it'll index everything.
+        return emitIndexDataIfNeeded(MSF.dyn_cast<SourceFile *>(), Invocation,
+                                     Instance) ||
+               Context.hadError();
+      }
     }
   }
 
@@ -1360,15 +1375,18 @@
   }
 
   if (PrimarySourceFile) {
-    if (index::indexAndRecord(
-            PrimarySourceFile, opts.InputsAndOutputs.getSingleOutputFilename(),
-            opts.IndexStorePath, opts.IndexSystemModules, isDebugCompilation,
-            Invocation.getTargetTriple(), *Instance.getDependencyTracker())) {
+    const PrimarySpecificPaths &PSPs =
+        opts.InputsAndOutputs.getPrimarySpecificPathsForPrimary(
+            PrimarySourceFile->getFilename());
+    if (index::indexAndRecord(PrimarySourceFile, PSPs.OutputFilename,
+                              opts.IndexStorePath, opts.IndexSystemModules,
+                              isDebugCompilation, Invocation.getTargetTriple(),
+                              *Instance.getDependencyTracker())) {
       return true;
     }
   } else {
-    StringRef moduleToken =
-        opts.InputsAndOutputs.supplementaryOutputs().ModuleOutputPath;
+    std::string moduleToken =
+        Invocation.getModuleOutputPathForAtMostOnePrimary();
     if (moduleToken.empty())
       moduleToken = opts.InputsAndOutputs.getSingleOutputFilename();
 
@@ -1472,7 +1490,7 @@
   std::string InputName =
       FEOpts.InputsAndOutputs.getStatsFileMangledInputName();
   StringRef OptType = silOptModeArgStr(SILOpts.OptMode);
-  StringRef OutFile =
+  const std::string &OutFile =
       FEOpts.InputsAndOutputs.lastInputProducingOutput().outputFilename();
   StringRef OutputType = llvm::sys::path::extension(OutFile);
   std::string TripleName = LangOpts.Target.normalize();
@@ -1494,10 +1512,7 @@
 int swift::performFrontend(ArrayRef<const char *> Args,
                            const char *Argv0, void *MainAddr,
                            FrontendObserver *observer) {
-  llvm::InitializeAllTargets();
-  llvm::InitializeAllTargetMCs();
-  llvm::InitializeAllAsmPrinters();
-  llvm::InitializeAllAsmParsers();
+  INITIALIZE_LLVM();
 
   PrintingDiagnosticConsumer PDC;
 
@@ -1606,12 +1621,13 @@
   // arguments are generated by the driver, not directly by a user. The driver
   // is responsible for emitting diagnostics for its own errors. See SR-2683
   // for details.
+  //
+  // FIXME: Do we need one SerializedConsumer per primary? Owned by the
+  // SourceFile?
   std::unique_ptr<DiagnosticConsumer> SerializedConsumer;
   {
     const std::string &SerializedDiagnosticsPath =
-        Invocation.getFrontendOptions()
-            .InputsAndOutputs.supplementaryOutputs()
-            .SerializedDiagnosticsPath;
+        Invocation.getSerializedDiagnosticsPathForAtMostOnePrimary();
     if (!SerializedDiagnosticsPath.empty()) {
       SerializedConsumer.reset(
           serialized_diagnostics::createConsumer(SerializedDiagnosticsPath));
@@ -1646,17 +1662,13 @@
   }
 
   DependencyTracker depTracker;
-  if (!Invocation.getFrontendOptions()
-           .InputsAndOutputs.supplementaryOutputs()
-           .DependenciesFilePath.empty() ||
-      !Invocation.getFrontendOptions()
-           .InputsAndOutputs.supplementaryOutputs()
-           .ReferenceDependenciesFilePath.empty() ||
-      !Invocation.getFrontendOptions().IndexStorePath.empty() ||
-      !Invocation.getFrontendOptions()
-           .InputsAndOutputs.supplementaryOutputs()
-           .LoadedModuleTracePath.empty()) {
-    Instance->setDependencyTracker(&depTracker);
+  {
+    const FrontendInputsAndOutputs &io =
+        Invocation.getFrontendOptions().InputsAndOutputs;
+    if (io.hasDependencyTrackerPath() ||
+        !Invocation.getFrontendOptions().IndexStorePath.empty()) {
+      Instance->setDependencyTracker(&depTracker);
+    }
   }
 
   if (Instance->setup(Invocation)) {
diff --git a/lib/FrontendTool/ImportedModules.cpp b/lib/FrontendTool/ImportedModules.cpp
index 8fbed1d..4a6b8f7 100644
--- a/lib/FrontendTool/ImportedModules.cpp
+++ b/lib/FrontendTool/ImportedModules.cpp
@@ -46,7 +46,7 @@
 bool swift::emitImportedModules(ASTContext &Context, ModuleDecl *mainModule,
                                 const FrontendOptions &opts) {
 
-  auto path = opts.InputsAndOutputs.getSingleOutputFilename();
+  std::string path = opts.InputsAndOutputs.getSingleOutputFilename();
   std::error_code EC;
   llvm::raw_fd_ostream out(path, EC, llvm::sys::fs::F_None);
 
diff --git a/lib/FrontendTool/ReferenceDependencies.cpp b/lib/FrontendTool/ReferenceDependencies.cpp
index 9dfd95b..21a05f9 100644
--- a/lib/FrontendTool/ReferenceDependencies.cpp
+++ b/lib/FrontendTool/ReferenceDependencies.cpp
@@ -123,20 +123,11 @@
   return tmp;
 }
 
-bool swift::emitReferenceDependenciesIfNeeded(DiagnosticEngine &diags,
-                                              SourceFile *SF,
-                                              DependencyTracker &depTracker,
-                                              StringRef outputPath) {
+bool swift::emitReferenceDependencies(DiagnosticEngine &diags, SourceFile *SF,
+                                      DependencyTracker &depTracker,
+                                      StringRef outputPath) {
   assert(SF && "Cannot emit reference dependencies without a SourceFile");
-
-  const ReferencedNameTracker *const tracker = SF->getReferencedNameTracker();
-  if (!tracker) {
-    assert(outputPath.empty());
-    return false;
-  }
-
-  assert(!outputPath.empty());
-
+  
   // Before writing to the dependencies file path, preserve any previous file
   // that may have been there. No error handling -- this is just a nicety, it
   // doesn't matter if it fails.
@@ -342,6 +333,9 @@
     return pairs;
   };
 
+  const ReferencedNameTracker *const tracker = SF->getReferencedNameTracker();
+  assert(tracker && "Cannot emit reference dependencies without a tracker");
+
   out << "depends-top-level:\n";
   for (auto &entry : sortedByName(tracker->getTopLevelNames())) {
     assert(!entry.first.empty());
diff --git a/lib/FrontendTool/ReferenceDependencies.h b/lib/FrontendTool/ReferenceDependencies.h
index 5dd0f84..16c7c03 100644
--- a/lib/FrontendTool/ReferenceDependencies.h
+++ b/lib/FrontendTool/ReferenceDependencies.h
@@ -32,9 +32,9 @@
 reversePathSortedFilenames(const llvm::ArrayRef<std::string> paths);
 
 /// Emit a Swift-style dependencies file for \p SF.
-bool emitReferenceDependenciesIfNeeded(DiagnosticEngine &diags, SourceFile *SF,
-                                       DependencyTracker &depTracker,
-                                       StringRef outputPath);
+bool emitReferenceDependencies(DiagnosticEngine &diags, SourceFile *SF,
+                               DependencyTracker &depTracker,
+                               StringRef outputPath);
 } // end namespace swift
 
 #endif
diff --git a/lib/FrontendTool/TBD.h b/lib/FrontendTool/TBD.h
index 446618a..bda0922 100644
--- a/lib/FrontendTool/TBD.h
+++ b/lib/FrontendTool/TBD.h
@@ -24,8 +24,8 @@
 class FileUnit;
 class FrontendOptions;
 
-bool writeTBD(ModuleDecl *M, bool hasMultipleIGMs,
-              llvm::StringRef OutputFilename, llvm::StringRef installName);
+bool writeTBD(ModuleDecl *M, bool hasMultipleIGMs, StringRef OutputFilename,
+              llvm::StringRef installName);
 bool inputFileKindCanHaveTBDValidated(InputFileKind kind);
 bool validateTBD(ModuleDecl *M, llvm::Module &IRModule, bool hasMultipleIGMs,
                  bool diagnoseExtraSymbolsInTBD);
diff --git a/lib/IDE/Formatting.cpp b/lib/IDE/Formatting.cpp
index 18d7786..7ef1655 100644
--- a/lib/IDE/Formatting.cpp
+++ b/lib/IDE/Formatting.cpp
@@ -843,6 +843,9 @@
     auto AddIndentFunc = [&] () {
       auto Width = FmtOptions.UseTabs ? FmtOptions.TabWidth
                                       : FmtOptions.IndentWidth;
+      // We don't need to add additional indentation if Width is zero.
+      if (!Width)
+        return;
       // Increment indent.
       ExpandedIndent += Width;
       // Normalize indent to align on proper column indent width.
diff --git a/lib/IRGen/GenDecl.cpp b/lib/IRGen/GenDecl.cpp
index 73f4dad..d635dfb 100644
--- a/lib/IRGen/GenDecl.cpp
+++ b/lib/IRGen/GenDecl.cpp
@@ -2252,6 +2252,17 @@
 static llvm::GlobalVariable *createGOTEquivalent(IRGenModule &IGM,
                                                  llvm::Constant *global,
                                                  StringRef globalName) {
+  if (IGM.Triple.getObjectFormat() == llvm::Triple::COFF) {
+    if (cast<llvm::GlobalValue>(global)->hasDLLImportStorageClass()) {
+      llvm::GlobalVariable *GV =
+          new llvm::GlobalVariable(IGM.Module, global->getType(),
+                                   /*Constant=*/true,
+                                   llvm::GlobalValue::ExternalLinkage,
+                                   nullptr, llvm::Twine("__imp_") + globalName);
+      GV->setExternallyInitialized(true);
+      return GV;
+    }
+  }
 
   auto gotEquivalent = new llvm::GlobalVariable(IGM.Module,
                                       global->getType(),
@@ -2431,14 +2442,20 @@
                               Alignment alignment,
                               llvm::Type *defaultType,
                               ConstantReference::Directness forceIndirectness) {
+  // ObjC class references can always be directly referenced, even in
+  // the weird cases where we don't see a definition.
+  if (entity.isObjCClassRef()) {
+    auto value = getAddrOfObjCClassRef(
+      const_cast<ClassDecl *>(cast<ClassDecl>(entity.getDecl())));
+    return { cast<llvm::Constant>(value.getAddress()),
+             ConstantReference::Direct };
+  }
+
   // Ensure the variable is at least forward-declared.
   if (entity.isForeignTypeMetadataCandidate()) {
     auto foreignCandidate
       = getAddrOfForeignTypeMetadataCandidate(entity.getType());
     (void)foreignCandidate;
-  } else if (entity.isObjCClassRef()) {
-    (void)getAddrOfObjCClassRef(
-                  const_cast<ClassDecl *>(cast<ClassDecl>(entity.getDecl())));
   } else {
     getAddrOfLLVMVariable(entity, alignment, ConstantInit(),
                           defaultType, DebugTypeInfo());
@@ -2498,47 +2515,40 @@
   return {gotEquivalent, ConstantReference::Indirect};
 }
 
-namespace {
-struct TypeEntityInfo {
-  TypeMetadataRecordKind typeKind;
-  LinkEntity entity;
-  llvm::Type *defaultTy, *defaultPtrTy;
-
-  /// Adjust the flags once we know whether the reference to this entity
-  /// will be indirect.
-  void adjustForKnownRef(ConstantReference &ref) {
-    if (ref.isIndirect() &&
-        typeKind == TypeMetadataRecordKind::DirectNominalTypeDescriptor)
-      typeKind = TypeMetadataRecordKind::IndirectNominalTypeDescriptor;
-  }
-};
-} // end anonymous namespace
-
-static TypeEntityInfo
-getTypeEntityInfo(IRGenModule &IGM, NominalTypeDecl *nom) {
-  TypeMetadataRecordKind typeKind;
+TypeEntityReference
+IRGenModule::getTypeEntityReference(NominalTypeDecl *decl) {
+  TypeMetadataRecordKind kind;
   Optional<LinkEntity> entity;
-  llvm::Type *defaultTy, *defaultPtrTy;
+  llvm::Type *defaultTy;
 
-  auto clas = dyn_cast<ClassDecl>(nom);
-  if (clas && !clas->isForeign() && !hasKnownSwiftMetadata(IGM, clas)) {
+  auto clas = dyn_cast<ClassDecl>(decl);
+  if (clas && !clas->isForeign() && !hasKnownSwiftMetadata(*this, clas)) {
     // A reference to an Objective-C class object.
     assert(clas->isObjC() && "Must have an Objective-C class here");
 
-    typeKind = TypeMetadataRecordKind::IndirectObjCClass;
-    defaultTy = IGM.TypeMetadataPtrTy;
-    defaultPtrTy = IGM.TypeMetadataPtrTy;
+    kind = TypeMetadataRecordKind::IndirectObjCClass;
+    defaultTy = TypeMetadataPtrTy;
     entity = LinkEntity::forObjCClassRef(clas);
   } else {
-    // Conformances for generics and concrete subclasses of generics
-    // are represented by referencing the nominal type descriptor.
-    typeKind = TypeMetadataRecordKind::DirectNominalTypeDescriptor;
-    entity = LinkEntity::forNominalTypeDescriptor(nom);
-    defaultTy = IGM.TypeContextDescriptorTy;
-    defaultPtrTy = IGM.TypeContextDescriptorPtrTy;
+    // A reference to a concrete type.
+    // TODO: consider using a symbolic reference (i.e. a symbol string
+    // to be looked up dynamically) for types defined outside the module.
+    kind = TypeMetadataRecordKind::DirectNominalTypeDescriptor;
+    entity = LinkEntity::forNominalTypeDescriptor(decl);
+    defaultTy = TypeContextDescriptorTy;
   }
 
-  return {typeKind, *entity, defaultTy, defaultPtrTy};
+  auto ref = getAddrOfLLVMVariableOrGOTEquivalent(
+      *entity, getPointerAlignment(), defaultTy);
+
+  // Adjust the flags now that we know whether the reference to this
+  // entity will be indirect.
+  if (ref.isIndirect()) {
+    assert(kind == TypeMetadataRecordKind::DirectNominalTypeDescriptor);
+    kind = TypeMetadataRecordKind::IndirectNominalTypeDescriptor;
+  }
+
+  return TypeEntityReference(kind, ref.getValue());
 }
 
 /// Form an LLVM constant for the relative distance between a reference
@@ -2682,16 +2692,12 @@
     }
 
     void addConformingType() {
-      // Relative reference to the type entity info, with the type reference
-      // kind mangled in the lower bits.
-      auto typeEntity =
-        getTypeEntityInfo(IGM, Conformance->getType()->getAnyNominal());
-      auto typeRef =
-        IGM.getAddrOfLLVMVariableOrGOTEquivalent(
-          typeEntity.entity, IGM.getPointerAlignment(), typeEntity.defaultTy);
-      typeEntity.adjustForKnownRef(typeRef);
-      B.addRelativeAddress(typeRef.getValue());
-      Flags = Flags.withTypeReferenceKind(typeEntity.typeKind);
+      // Add a relative reference to the type, with the type reference
+      // kind stored in the flags.
+      auto ref =
+        IGM.getTypeEntityReference(Conformance->getType()->getAnyNominal());
+      B.addRelativeAddress(ref.getValue());
+      Flags = Flags.withTypeReferenceKind(ref.getKind());
     }
 
     void addWitnessTable() {
@@ -2879,16 +2885,13 @@
 
   SmallVector<llvm::Constant *, 8> elts;
   for (auto type : RuntimeResolvableTypes) {
-    auto typeEntity = getTypeEntityInfo(*this, type);
-    auto typeRef = getAddrOfLLVMVariableOrGOTEquivalent(
-            typeEntity.entity, getPointerAlignment(), typeEntity.defaultTy);
-    typeEntity.adjustForKnownRef(typeRef);
+    auto ref = getTypeEntityReference(type);
 
     // Form the relative address, with the type refernce kind in the low bits.
     unsigned arrayIdx = elts.size();
     llvm::Constant *relativeAddr =
-      emitDirectRelativeReference(typeRef.getValue(), var, { arrayIdx, 0 });
-    unsigned lowBits = static_cast<unsigned>(typeEntity.typeKind);
+      emitDirectRelativeReference(ref.getValue(), var, { arrayIdx, 0 });
+    unsigned lowBits = static_cast<unsigned>(ref.getKind());
     if (lowBits != 0) {
       relativeAddr = llvm::ConstantExpr::getAdd(relativeAddr,
                        llvm::ConstantInt::get(RelativeAddressTy, lowBits));
diff --git a/lib/IRGen/GenMeta.cpp b/lib/IRGen/GenMeta.cpp
index 67d4113..92a6b49 100644
--- a/lib/IRGen/GenMeta.cpp
+++ b/lib/IRGen/GenMeta.cpp
@@ -2058,6 +2058,10 @@
         return emitFromValueWitnessTable(IGF.IGM.Context.TheEmptyTupleType);
       }
       case MetatypeRepresentation::Thick:
+        if (isa<ExistentialMetatypeType>(type)) {
+          return emitFromTypeMetadata(type);
+        }
+        // Otherwise, this is a metatype that looks like a pointer.
       case MetatypeRepresentation::ObjC:
         // Thick metatypes look like pointers with spare bits.
         return emitFromValueWitnessTable(
@@ -2692,19 +2696,23 @@
     
     /// Flags to indicate Clang-imported declarations so we mangle them
     /// consistently at runtime.
-    uint16_t getClangImportedFlags() const {
+    void getClangImportedFlags(TypeContextDescriptorFlags &flags) const {
       auto clangDecl = Mangle::ASTMangler::getClangDeclForMangling(Type);
       if (!clangDecl)
-        return 0;
+        return;
       
-      if (isa<clang::TagDecl>(clangDecl))
-        return (uint16_t)TypeContextDescriptorFlags::IsCTag;
+      if (isa<clang::TagDecl>(clangDecl)) {
+        flags.setIsCTag(true);
+        return;
+      }
       
       if (isa<clang::TypedefNameDecl>(clangDecl)
-          || isa<clang::ObjCCompatibleAliasDecl>(clangDecl))
-        return (uint16_t)TypeContextDescriptorFlags::IsCTypedef;
+          || isa<clang::ObjCCompatibleAliasDecl>(clangDecl)) {
+        flags.setIsCTypedef(true);
+        return;
+      }
       
-      return 0;
+      return;
     }
 
     // Subclasses should provide:
@@ -2811,15 +2819,23 @@
     
     void addLayoutInfo() {
       auto properties = getType()->getStoredProperties();
+
+      // uint32_t NumFields;
       B.addInt32(std::distance(properties.begin(), properties.end()));
+
+      // uint32_t FieldOffsetVectorOffset;
       B.addInt32(FieldVectorOffset / IGM.getPointerSize());
-      B.addInt32(1); // struct always reflectable
 
       addFieldTypes(IGM, getType(), properties);
     }
     
     uint16_t getKindSpecificFlags() {
-      return getClangImportedFlags();
+      TypeContextDescriptorFlags flags;
+
+      flags.setIsReflectable(true); // struct always reflectable
+
+      getClangImportedFlags(flags);
+      return flags.getOpaqueValue();
     }
   };
   
@@ -2834,11 +2850,14 @@
     
     Size GenericParamsOffset;
     Size PayloadSizeOffset;
+    const EnumImplStrategy &Strategy;
     
   public:
     EnumContextDescriptorBuilder(IRGenModule &IGM, EnumDecl *Type,
                                  RequireMetadata_t requireMetadata)
-      : super(IGM, Type, requireMetadata)
+      : super(IGM, Type, requireMetadata),
+        Strategy(getEnumImplStrategy(IGM,
+                     getType()->getDeclaredTypeInContext()->getCanonicalType()))
     {
       auto &layout = IGM.getMetadataLayout(getType());
       GenericParamsOffset = layout.getStaticGenericRequirementsOffset();
@@ -2855,12 +2874,8 @@
     }
     
     void addLayoutInfo() {
-      auto &strategy = getEnumImplStrategy(IGM,
-                     getType()->getDeclaredTypeInContext()->getCanonicalType());
-      
-      
       // # payload cases in the low 24 bits, payload size offset in the high 8.
-      unsigned numPayloads = strategy.getElementsWithPayload().size();
+      unsigned numPayloads = Strategy.getElementsWithPayload().size();
       assert(numPayloads < (1<<24) && "too many payload elements for runtime");
       assert(PayloadSizeOffset % IGM.getPointerAlignment() == Size(0)
              && "payload size not word-aligned");
@@ -2868,16 +2883,23 @@
         = PayloadSizeOffset / IGM.getPointerSize();
       assert(PayloadSizeOffsetInWords < 0x100 &&
              "payload size offset too far from address point for runtime");
-      B.addInt32(numPayloads | (PayloadSizeOffsetInWords << 24));
-      // # empty cases
-      B.addInt32(strategy.getElementsWithNoPayload().size());
-      B.addInt32(strategy.isReflectable());
 
-      addFieldTypes(IGM, strategy.getElementsWithPayload());
+      // uint32_t NumPayloadCasesAndPayloadSizeOffset;
+      B.addInt32(numPayloads | (PayloadSizeOffsetInWords << 24));
+
+      // uint32_t NumEmptyCases;
+      B.addInt32(Strategy.getElementsWithNoPayload().size());
+
+      addFieldTypes(IGM, Strategy.getElementsWithPayload());
     }
     
     uint16_t getKindSpecificFlags() {
-      return getClangImportedFlags();
+      TypeContextDescriptorFlags flags;
+
+      flags.setIsReflectable(Strategy.isReflectable());
+
+      getClangImportedFlags(flags);
+      return flags.getOpaqueValue();
     }
   };
   
@@ -2891,6 +2913,8 @@
       return cast<ClassDecl>(Type);
     }
 
+    Optional<TypeEntityReference> SuperClassRef;
+
     // Offsets of key fields in the metadata records.
     Size FieldVectorOffset, GenericParamsOffset;
 
@@ -2910,6 +2934,10 @@
         return;
       }
 
+      if (auto superclassDecl = getType()->getSuperclassDecl()) {
+        SuperClassRef = IGM.getTypeEntityReference(superclassDecl);
+      }
+
       auto &layout = IGM.getClassMetadataLayout(getType());
 
       VTable = IGM.getSILModule().lookUpVTable(getType());
@@ -2936,19 +2964,26 @@
     }
     
     uint16_t getKindSpecificFlags() {
-      uint16_t flags = 0;
+      TypeContextDescriptorFlags flags;
+
+      flags.setIsReflectable(true); // class is always reflectable
+
       if (!getType()->isForeign()) {
         if (VTableSize != 0)
-          flags |= (uint16_t)TypeContextDescriptorFlags::HasVTable;
+          flags.class_setHasVTable(true);
 
         auto &layout = IGM.getClassMetadataLayout(getType());
         if (layout.hasResilientSuperclass())
-          flags |= (uint16_t)TypeContextDescriptorFlags::HasResilientSuperclass;
+          flags.class_setHasResilientSuperclass(true);
+      }
+
+      if (SuperClassRef) {
+        flags.class_setSuperclassReferenceKind(SuperClassRef->getKind());
       }
       
-      flags |= getClangImportedFlags();
+      getClangImportedFlags(flags);
       
-      return flags;
+      return flags.getOpaqueValue();
     }
     
     Size getGenericParamsOffset() {
@@ -3009,9 +3044,19 @@
     
     void addLayoutInfo() {
       auto properties = getType()->getStoredProperties();
+
+      // RelativeDirectPointer<const void, /*nullable*/ true> SuperClass;
+      if (SuperClassRef) {
+        B.addRelativeAddress(SuperClassRef->getValue());
+      } else {
+        B.addInt32(0);
+      }
+
+      // uint32_t NumFields;
       B.addInt32(std::distance(properties.begin(), properties.end()));
+
+      // uint32_t FieldOffsetVectorOffset;
       B.addInt32(FieldVectorOffset / IGM.getPointerSize());
-      B.addInt32(1); // class is always reflectable
 
       addFieldTypes(IGM, getType(), properties);
     }
diff --git a/lib/IRGen/IRGen.cpp b/lib/IRGen/IRGen.cpp
index 6090a40..353faeb 100644
--- a/lib/IRGen/IRGen.cpp
+++ b/lib/IRGen/IRGen.cpp
@@ -665,8 +665,7 @@
 }
 
 std::pair<IRGenerator *, IRGenModule *>
-swift::irgen::createIRGenModule(SILModule *SILMod,
-                                StringRef OutputFilename,
+swift::irgen::createIRGenModule(SILModule *SILMod, StringRef OutputFilename,
                                 StringRef MainInputFilenameForDebugInfo,
                                 llvm::LLVMContext &LLVMContext) {
 
diff --git a/lib/IRGen/IRGenModule.h b/lib/IRGen/IRGenModule.h
index 5d41c92..5b93a9a 100644
--- a/lib/IRGen/IRGenModule.h
+++ b/lib/IRGen/IRGenModule.h
@@ -97,6 +97,7 @@
   class SourceLoc;
   class SourceFile;
   class Type;
+  enum class TypeMetadataRecordKind : unsigned;
 
 namespace Lowering {
   class TypeConverter;
@@ -413,6 +414,18 @@
   }
 };
 
+/// A reference to a declared type entity.
+class TypeEntityReference {
+  TypeMetadataRecordKind Kind;
+  llvm::Constant *Value;
+public:
+  TypeEntityReference(TypeMetadataRecordKind kind, llvm::Constant *value)
+    : Kind(kind), Value(value) {}
+
+  TypeMetadataRecordKind getKind() const { return Kind; }
+  llvm::Constant *getValue() const { return Value; }
+};
+
 /// IRGenModule - Primary class for emitting IR for global declarations.
 /// 
 class IRGenModule {
@@ -1036,11 +1049,9 @@
   ///
   /// The \p SF is the source file for which the llvm module is generated when
   /// doing multi-threaded whole-module compilation. Otherwise it is null.
-  IRGenModule(IRGenerator &irgen,
-              std::unique_ptr<llvm::TargetMachine> &&target,
+  IRGenModule(IRGenerator &irgen, std::unique_ptr<llvm::TargetMachine> &&target,
               SourceFile *SF, llvm::LLVMContext &LLVMContext,
-              StringRef ModuleName,
-              StringRef OutputFilename,
+              StringRef ModuleName, StringRef OutputFilename,
               StringRef MainInputFilenameForDebugInfo);
   ~IRGenModule();
 
@@ -1112,6 +1123,8 @@
                                   ConstantInitFuture init,
                                   llvm::StringRef section = {});
 
+  TypeEntityReference getTypeEntityReference(NominalTypeDecl *D);
+
   llvm::Constant *getAddrOfTypeMetadata(CanType concreteType);
   ConstantReference getAddrOfTypeMetadata(CanType concreteType,
                                           SymbolReferenceKind kind);
diff --git a/lib/Immediate/REPL.cpp b/lib/Immediate/REPL.cpp
index 8abe70d..401baf5 100644
--- a/lib/Immediate/REPL.cpp
+++ b/lib/Immediate/REPL.cpp
@@ -897,10 +897,11 @@
     if (!ShouldRun)
       return true;
 
+    const PrimarySpecificPaths PSPs =
+        CI.getPrimarySpecificPathsForAtMostOnePrimary();
     // IRGen the current line(s).
     // FIXME: We shouldn't need to use the global context here, but
     // something is persisting across calls to performIRGeneration.
-    const auto PSPs = CI.getPrimarySpecificPathsForAtMostOnePrimary();
     auto LineModule = performIRGeneration(
         IRGenOpts, REPLInputFile, std::move(sil), "REPLLine", PSPs,
         getGlobalLLVMContext(), RC.CurIRGenElem);
diff --git a/lib/SIL/LoopInfo.cpp b/lib/SIL/LoopInfo.cpp
index 65271c9..6258d78 100644
--- a/lib/SIL/LoopInfo.cpp
+++ b/lib/SIL/LoopInfo.cpp
@@ -81,6 +81,9 @@
   if (isa<ThrowInst>(I))
     return false;
 
+  if (isa<BeginAccessInst>(I))
+    return false;
+
   assert(I->isTriviallyDuplicatable() &&
     "Code here must match isTriviallyDuplicatable in SILInstruction");
   return true;
diff --git a/lib/SIL/SILFunctionType.cpp b/lib/SIL/SILFunctionType.cpp
index 014cce8..c6cc8c2 100644
--- a/lib/SIL/SILFunctionType.cpp
+++ b/lib/SIL/SILFunctionType.cpp
@@ -1250,6 +1250,7 @@
   case SILFunctionType::Representation::WitnessMethod: {
     switch (constant ? constant->kind : SILDeclRef::Kind::Func) {
     case SILDeclRef::Kind::Initializer:
+    case SILDeclRef::Kind::EnumElement:
       return getSILFunctionType(M, origType, substInterfaceType, extInfo,
                                 DefaultInitializerConventions(), ForeignInfo(),
                                 constant, witnessMethodConformance);
@@ -1272,7 +1273,6 @@
     case SILDeclRef::Kind::StoredPropertyInitializer:
     case SILDeclRef::Kind::IVarInitializer:
     case SILDeclRef::Kind::IVarDestroyer:
-    case SILDeclRef::Kind::EnumElement:
       return getSILFunctionType(M, origType, substInterfaceType, extInfo,
                                 getNormalArgumentConvention(M), ForeignInfo(),
                                 constant, witnessMethodConformance);
diff --git a/lib/SIL/SILInstruction.cpp b/lib/SIL/SILInstruction.cpp
index e867b1e..8f52be8 100644
--- a/lib/SIL/SILInstruction.cpp
+++ b/lib/SIL/SILInstruction.cpp
@@ -1142,9 +1142,6 @@
 /// additional handling. It is important to know this information when
 /// you perform such optimizations like e.g. jump-threading.
 bool SILInstruction::isTriviallyDuplicatable() const {
-  if (isa<ThrowInst>(this))
-    return false;
-
   if (isa<AllocStackInst>(this) || isa<DeallocStackInst>(this)) {
     return false;
   }
@@ -1152,7 +1149,6 @@
     if (ARI->canAllocOnStack())
       return false;
   }
-
   if (isa<OpenExistentialAddrInst>(this) || isa<OpenExistentialRefInst>(this) ||
       isa<OpenExistentialMetatypeInst>(this) ||
       isa<OpenExistentialValueInst>(this) || isa<OpenExistentialBoxInst>(this) ||
@@ -1169,6 +1165,13 @@
     if (MI->getMember().isForeign)
       return false;
   }
+  if (isa<ThrowInst>(this))
+    return false;
+
+  // BeginAccess defines the access scope entry point. All associated EndAccess
+  // instructions must directly operate on the BeginAccess.
+  if (isa<BeginAccessInst>(this))
+    return false;
 
   return true;
 }
diff --git a/lib/SIL/SILVerifier.cpp b/lib/SIL/SILVerifier.cpp
index 5982941..6a5be4e 100644
--- a/lib/SIL/SILVerifier.cpp
+++ b/lib/SIL/SILVerifier.cpp
@@ -329,11 +329,6 @@
       delete Dominance;
   }
 
-  // Address-type block args must be prohibited whenever access markers are
-  // present. Access markers are always present in raw SIL to diagnose exclusive
-  // memory access. In canonical SIL, access markers are only present with
-  // EnforceExclusivityDynamic.
-  //
   // FIXME: For sanity, address-type block args should be prohibited at all SIL
   // stages. However, the optimizer currently breaks the invariant in three
   // places:
@@ -341,8 +336,8 @@
   //    (sneaky jump threading).
   // 2. Simplify CFG via Jump Threading.
   // 3. Loop Rotation.
-  // Once EnforceExclusivityDynamic is performant enough to be enabled by
-  // default at -O, address-type blocks args can be prohibited unconditionally.
+  //
+  //
   bool prohibitAddressBlockArgs() {
     // If this function was deserialized from canonical SIL, this invariant may
     // already have been violated regardless of this module's SIL stage or
@@ -352,12 +347,7 @@
       return false;
 
     SILModule &M = F.getModule();
-    if (M.getStage() == SILStage::Raw)
-      return true;
-
-    // If dynamic enforcement is enabled, markers are present at -O so we
-    // prohibit address block args.
-    return M.getOptions().EnforceExclusivityDynamic;
+    return M.getStage() == SILStage::Raw;
   }
 
   void visitSILArgument(SILArgument *arg) {
diff --git a/lib/SILGen/LValue.h b/lib/SILGen/LValue.h
index 8977c80..dd6e015 100644
--- a/lib/SILGen/LValue.h
+++ b/lib/SILGen/LValue.h
@@ -166,6 +166,13 @@
   virtual AccessKind getBaseAccessKind(SILGenFunction &SGF,
                                        AccessKind accessKind) const = 0;
 
+  /// Is loading a value from this component guaranteed to have no observable
+  /// side effects?
+  virtual bool isLoadingPure() const {
+    // By default, don't assume any component is pure; components must opt-in.
+    return false;
+  }
+
   virtual bool isRValue() const { return false; }
 
   /// Returns the logical type-as-rvalue of the value addressed by the
@@ -363,6 +370,16 @@
 
   bool isValid() const { return !Path.empty(); }
 
+  /// Is loading a value from this lvalue guaranteed to have no observable side
+  /// effects?
+  bool isLoadingPure() {
+    assert(isValid());
+    for (auto &component : Path)
+      if (!component->isLoadingPure())
+        return false;
+    return true;
+  }
+
   /// Is this lvalue purely physical?
   bool isPhysical() const {
     assert(isValid());
diff --git a/lib/SILGen/SILGenApply.cpp b/lib/SILGen/SILGenApply.cpp
index b832956..3f8a2f2 100644
--- a/lib/SILGen/SILGenApply.cpp
+++ b/lib/SILGen/SILGenApply.cpp
@@ -3788,6 +3788,10 @@
   auto subs = callee.getSubstitutions();
   auto upcastedSelf = uncurriedArgs.back();
 
+  // Make sure that upcasted self is at +1 since we are going to place it into a
+  // partial_apply.
+  upcastedSelf = upcastedSelf.ensurePlusOne(SGF, loc);
+
   auto constantInfo = SGF.getConstantInfo(callee.getMethodName());
   auto functionTy = constantInfo.getSILType();
   ManagedValue superMethod;
@@ -3813,11 +3817,9 @@
   if (constantInfo.SILFnType->isPolymorphic() && !subs.empty())
     partialApplyTy = partialApplyTy.substGenericArgs(module, subs);
 
-  SILValue partialApply =
-      SGF.B.createPartialApply(loc, superMethod.getValue(), partialApplyTy,
-                               subs, {upcastedSelf.forward(SGF)}, closureTy);
+  ManagedValue pa = SGF.B.createPartialApply(loc, superMethod, partialApplyTy,
+                                             subs, {upcastedSelf}, closureTy);
   assert(!closureTy.castTo<SILFunctionType>()->isNoEscape());
-  ManagedValue pa = SGF.emitManagedRValueWithCleanup(partialApply);
   firstLevelResult.value = RValue(SGF, loc, formalApplyType.getResult(), pa);
   return firstLevelResult;
 }
diff --git a/lib/SILGen/SILGenBridging.cpp b/lib/SILGen/SILGenBridging.cpp
index def5241..710efca 100644
--- a/lib/SILGen/SILGenBridging.cpp
+++ b/lib/SILGen/SILGenBridging.cpp
@@ -801,6 +801,7 @@
   assert(formalBlockParams.size() == blockTy->getNumParameters());
   assert(formalFuncParams.size() == funcTy->getNumParameters());
 
+  // Create the arguments for the call.
   for (unsigned i : indices(funcTy->getParameters())) {
     auto &param = funcTy->getParameters()[i];
     CanType formalBlockParamTy = formalBlockParams[i];
@@ -808,12 +809,23 @@
 
     auto paramTy = fnConv.getSILType(param);
     SILValue v = entry->createFunctionArgument(paramTy);
+
+    // First get the managed parameter for this function.
     auto mv = emitManagedParameter(SGF, loc, param, v);
 
     SILType loweredBlockArgTy = blockTy->getParameters()[i].getSILStorageType();
-    args.push_back(SGF.emitNativeToBridgedValue(loc, mv, formalFuncParamTy,
-                                                formalBlockParamTy,
-                                                loweredBlockArgTy));
+
+    // Then bridge the native value to its bridged variant.
+    mv = SGF.emitNativeToBridgedValue(loc, mv, formalFuncParamTy,
+                                      formalBlockParamTy, loweredBlockArgTy);
+
+    // Finally change ownership if we need to. We do not need to care about the
+    // case of a +1 parameter being passed to a +0 function since +1 parameters
+    // can be "instantaneously" borrowed at the call site.
+    if (blockTy->getParameters()[i].isConsumed()) {
+      mv = mv.ensurePlusOne(SGF, loc);
+    }
+    args.push_back(mv);
   }
 
   // Add the block argument.
@@ -1094,10 +1106,8 @@
     };
     auto conformances = getASTContext().AllocateCopy(conformanceArray);
 
-    SILValue nativeError =
-      B.createInitExistentialRef(loc, nativeErrorTy, bridgedErrorTy,
-                                 bridgedError.forward(*this), conformances);
-    return emitManagedRValueWithCleanup(nativeError);
+    return B.createInitExistentialRef(loc, nativeErrorTy, bridgedErrorTy,
+                                      bridgedError, conformances);
   }
 
   // Otherwise, we need to call a runtime function to potential substitute
diff --git a/lib/SILGen/SILGenConstructor.cpp b/lib/SILGen/SILGenConstructor.cpp
index d2aa8ad..946640b 100644
--- a/lib/SILGen/SILGenConstructor.cpp
+++ b/lib/SILGen/SILGenConstructor.cpp
@@ -57,20 +57,25 @@
     RValue tuple(type);
     for (auto fieldType : tupleTy.getElementTypes())
       tuple.addElement(emitImplicitValueConstructorArg(SGF, loc, fieldType, DC));
-
     return tuple;
-  } else {
-    auto &AC = SGF.getASTContext();
-    auto VD = new (AC) ParamDecl(VarDecl::Specifier::Owned, SourceLoc(), SourceLoc(),
-                                 AC.getIdentifier("$implicit_value"),
-                                 SourceLoc(),
-                                 AC.getIdentifier("$implicit_value"), Type(),
-                                 DC);
-    VD->setInterfaceType(interfaceType);
-    SILValue arg =
-        SGF.F.begin()->createFunctionArgument(SGF.getLoweredType(type), VD);
-    return RValue(SGF, loc, type, SGF.emitManagedRValueWithCleanup(arg));
   }
+
+  auto &AC = SGF.getASTContext();
+  auto VD = new (AC) ParamDecl(VarDecl::Specifier::Owned, SourceLoc(), SourceLoc(),
+                               AC.getIdentifier("$implicit_value"),
+                               SourceLoc(),
+                               AC.getIdentifier("$implicit_value"), Type(),
+                               DC);
+  VD->setInterfaceType(interfaceType);
+  SILFunctionArgument *arg =
+      SGF.F.begin()->createFunctionArgument(SGF.getLoweredType(type), VD);
+  ManagedValue mvArg;
+  if (arg->getArgumentConvention().isOwnedConvention()) {
+    mvArg = SGF.emitManagedRValueWithCleanup(arg);
+  } else {
+    mvArg = ManagedValue::forUnmanaged(arg);
+  }
+  return RValue(SGF, loc, type, mvArg);
 }
 
 static void emitImplicitValueConstructor(SILGenFunction &SGF,
diff --git a/lib/SILGen/SILGenConvert.cpp b/lib/SILGen/SILGenConvert.cpp
index 1dd9dfd..93f4be4 100644
--- a/lib/SILGen/SILGenConvert.cpp
+++ b/lib/SILGen/SILGenConvert.cpp
@@ -369,6 +369,9 @@
   auto isNotPresentBB = createBasicBlock();
   auto isPresentBB = createBasicBlock();
 
+  // All conversions happen at +1.
+  input = input.ensurePlusOne(*this, loc);
+
   SwitchEnumBuilder SEBuilder(B, loc, input);
   SILType noOptResultTy = resultTy.getOptionalObjectType();
   assert(noOptResultTy);
diff --git a/lib/SILGen/SILGenExpr.cpp b/lib/SILGen/SILGenExpr.cpp
index f6e935a..72d725b7 100644
--- a/lib/SILGen/SILGenExpr.cpp
+++ b/lib/SILGen/SILGenExpr.cpp
@@ -5371,6 +5371,8 @@
                                AccessKind kind) const override {
     return kind;
   }
+
+  virtual bool isLoadingPure() const override { return true; }
   
   void set(SILGenFunction &SGF, SILLocation loc,
            ArgumentSource &&value, ManagedValue base) && override {
@@ -5707,9 +5709,10 @@
     FormalEvaluationScope scope(*this);
     PostponedCleanup postpone(*this);
     LValue lv = emitLValue(LE->getSubExpr(), AccessKind::Read);
-    // If the lvalue is purely physical, then it won't have any side effects,
-    // and we don't need to drill into it.
-    if (lv.isPhysical())
+
+    // If loading from the lvalue is guaranteed to have no side effects, we
+    // don't need to drill into it.
+    if (lv.isLoadingPure())
       return;
 
     // If the last component is physical, then we just need to drill through
@@ -5725,6 +5728,39 @@
     return;
   }
 
+  auto findLoadThroughForceValueExprs = [](Expr *E,
+                                           SmallVectorImpl<ForceValueExpr *>
+                                             &forceValueExprs) -> LoadExpr * {
+    while (auto FVE = dyn_cast<ForceValueExpr>(E)) {
+      forceValueExprs.push_back(FVE);
+      E = FVE->getSubExpr();
+    }
+    return dyn_cast<LoadExpr>(E);
+  };
+
+  // Look through force unwrap(s) of an lvalue. If possible, we want to just to
+  // emit the precondition(s) without having to load the value.
+  SmallVector<ForceValueExpr *, 4> forceValueExprs;
+  if (auto *LE = findLoadThroughForceValueExprs(E, forceValueExprs)) {
+    FormalEvaluationScope scope(*this);
+    LValue lv = emitLValue(LE->getSubExpr(), AccessKind::Read);
+
+    ManagedValue value;
+    if (lv.isLastComponentPhysical()) {
+      value = emitAddressOfLValue(LE, std::move(lv), AccessKind::Read);
+    } else {
+      value = emitLoadOfLValue(LE, std::move(lv),
+          SGFContext::AllowImmediatePlusZero).getAsSingleValue(*this, LE);
+    }
+
+    for (auto &FVE : reversed(forceValueExprs)) {
+      const TypeLowering &optTL = getTypeLowering(FVE->getSubExpr()->getType());
+      value = emitCheckedGetOptionalValueFrom(
+          FVE, value, optTL, SGFContext::AllowImmediatePlusZero);
+    }
+    return;
+  }
+
   // Otherwise, emit the result (to get any side effects), but produce it at +0
   // if that allows simplification.
   emitRValue(E, SGFContext::AllowImmediatePlusZero);
diff --git a/lib/SILGen/SILGenLValue.cpp b/lib/SILGen/SILGenLValue.cpp
index 4afdfba..74ac49b 100644
--- a/lib/SILGen/SILGenLValue.cpp
+++ b/lib/SILGen/SILGenLValue.cpp
@@ -581,7 +581,9 @@
       : PhysicalPathComponent(typeData, RefElementKind),
         Field(field), SubstFieldType(substFieldType),
         IsNonAccessing(options.IsNonAccessing) {}
-    
+
+    virtual bool isLoadingPure() const override { return true; }
+
     ManagedValue offset(SILGenFunction &SGF, SILLocation loc, ManagedValue base,
                         AccessKind accessKind) && override {
       assert(base.getType().isObject() &&
@@ -616,7 +618,9 @@
     TupleElementComponent(unsigned elementIndex, LValueTypeData typeData)
       : PhysicalPathComponent(typeData, TupleElementKind),
         ElementIndex(elementIndex) {}
-    
+
+    virtual bool isLoadingPure() const override { return true; }
+
     ManagedValue offset(SILGenFunction &SGF, SILLocation loc, ManagedValue base,
                         AccessKind accessKind) && override {
       assert(base && "invalid value for element base");
@@ -640,7 +644,9 @@
                            LValueTypeData typeData)
       : PhysicalPathComponent(typeData, StructElementKind),
         Field(field), SubstFieldType(substFieldType) {}
-    
+
+    virtual bool isLoadingPure() const override { return true; }
+
     ManagedValue offset(SILGenFunction &SGF, SILLocation loc, ManagedValue base,
                         AccessKind accessKind) && override {
       assert(base && "invalid value for element base");
@@ -684,6 +690,8 @@
       assert(getSubstFormalType() == openedArchetype);
     }
 
+    virtual bool isLoadingPure() const override { return true; }
+
     ManagedValue offset(SILGenFunction &SGF, SILLocation loc, ManagedValue base,
                         AccessKind accessKind) && override {
       assert(base.getType().isExistentialType() &&
@@ -732,6 +740,8 @@
       : LogicalPathComponent(typeData, OpenNonOpaqueExistentialKind),
         OpenedArchetype(openedArchetype) {}
 
+    virtual bool isLoadingPure() const override { return true; }
+
     AccessKind getBaseAccessKind(SILGenFunction &SGF,
                                  AccessKind kind) const override {
       // Always use the same access kind for the base.
@@ -832,6 +842,8 @@
         assert(IsRValue || value.getType().isAddress());
     }
 
+    virtual bool isLoadingPure() const override { return true; }
+
     ManagedValue offset(SILGenFunction &SGF, SILLocation loc, ManagedValue base,
                         AccessKind accessKind) && override {
       assert(!base && "value component must be root of lvalue path");
@@ -1821,6 +1833,8 @@
         OrigType(origType)
     {}
 
+    virtual bool isLoadingPure() const override { return true; }
+
     RValue untranslate(SILGenFunction &SGF, SILLocation loc,
                        RValue &&rv, SGFContext c) && override {
       return SGF.emitSubstToOrigValue(loc, std::move(rv), OrigType,
@@ -1860,6 +1874,8 @@
                              SubstToOrigKind)
     {}
 
+    virtual bool isLoadingPure() const override { return true; }
+
     RValue untranslate(SILGenFunction &SGF, SILLocation loc,
                        RValue &&rv, SGFContext c) && override {
       return SGF.emitOrigToSubstValue(loc, std::move(rv), getOrigFormalType(),
@@ -1895,6 +1911,8 @@
       : LogicalPathComponent(typeData, OwnershipKind) {
     }
 
+    virtual bool isLoadingPure() const override { return true; }
+
     AccessKind getBaseAccessKind(SILGenFunction &SGF,
                                  AccessKind kind) const override {
       // Always use the same access kind for the base.
diff --git a/lib/Sema/CSBindings.cpp b/lib/Sema/CSBindings.cpp
index 5bcaf7a..23945be 100644
--- a/lib/Sema/CSBindings.cpp
+++ b/lib/Sema/CSBindings.cpp
@@ -134,19 +134,17 @@
       !binding.BindingType->hasTypeVariable() && !binding.DefaultedProtocol &&
       !binding.isDefaultableBinding() && allowJoinMeet) {
     if (lastSupertypeIndex) {
-      // Can we compute a join?
       auto &lastBinding = Bindings[*lastSupertypeIndex];
       auto lastType = lastBinding.BindingType->getWithoutSpecifierType();
       auto bindingType = binding.BindingType->getWithoutSpecifierType();
+
       auto join = Type::join(lastType, bindingType);
-      if (join) {
-        auto anyType = join->getASTContext().TheAnyType;
-        if (!join->isEqual(anyType) || lastType->isEqual(anyType) ||
-            bindingType->isEqual(anyType)) {
-          // Replace the last supertype binding with the join. We're done.
-          lastBinding.BindingType = join;
-          return;
-        }
+      if (join && !(*join)->isAny() &&
+          (!(*join)->getOptionalObjectType()
+           || !(*join)->getOptionalObjectType()->isAny())) {
+        // Replace the last supertype binding with the join. We're done.
+        lastBinding.BindingType = *join;
+        return;
       }
     }
 
diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp
index 999254c..4ed18d5 100644
--- a/lib/Sema/CSGen.cpp
+++ b/lib/Sema/CSGen.cpp
@@ -2998,15 +2998,10 @@
         auto join =
             Type::join(lhsMeta->getInstanceType(), rhsMeta->getInstanceType());
 
-        // We will hit this assert today due to implemenation details
-        // of Type::join, but the intent is to define join to always
-        // result in a type.
-        assert(join && "Unexpected null type returned from Type::join!");
-
         if (!join)
           return ErrorType::get(ctx);
 
-        return MetatypeType::get(join, ctx)->getCanonicalType();
+        return MetatypeType::get(*join, ctx)->getCanonicalType();
       }
 
       case TypeOperation::JoinInout: {
@@ -3020,15 +3015,10 @@
         auto join =
             Type::join(lhsInOut, rhsMeta->getInstanceType());
 
-        // We will hit this assert today due to implemenation details
-        // of Type::join, but the intent is to define join to always
-        // result in a type.
-        assert(join && "Unexpected null type returned from Type::join!");
-
         if (!join)
           return ErrorType::get(ctx);
 
-        return MetatypeType::get(join, ctx)->getCanonicalType();
+        return MetatypeType::get(*join, ctx)->getCanonicalType();
       }
 
       case TypeOperation::JoinMeta: {
@@ -3041,15 +3031,10 @@
 
         auto join = Type::join(lhsMeta, rhsMeta);
 
-        // We will hit this assert today due to implemenation details
-        // of Type::join, but the intent is to define join to always
-        // result in a type.
-        assert(join && "Unexpected null type returned from Type::join!");
-
         if (!join)
           return ErrorType::get(ctx);
 
-        return join;
+        return *join;
       }
       }
     }
diff --git a/lib/Sema/TypeCheckCaptures.cpp b/lib/Sema/TypeCheckCaptures.cpp
index bf25431..3a8bcef 100644
--- a/lib/Sema/TypeCheckCaptures.cpp
+++ b/lib/Sema/TypeCheckCaptures.cpp
@@ -19,6 +19,7 @@
 #include "swift/AST/ASTVisitor.h"
 #include "swift/AST/ASTWalker.h"
 #include "swift/AST/Decl.h"
+#include "swift/AST/ForeignErrorConvention.h"
 #include "swift/AST/ParameterList.h"
 #include "swift/AST/TypeWalker.h"
 #include "swift/Basic/Defer.h"
@@ -743,9 +744,20 @@
   // their context.
   if (AFD && GenericParamCaptureLoc.isValid()) {
     if (auto Clas = AFD->getParent()->getAsClassOrClassExtensionContext()) {
-      if (Clas->isGenericContext() && Clas->hasClangNode()) {
+      if (Clas->usesObjCGenericsModel()) {
         diagnose(AFD->getLoc(),
                  diag::objc_generic_extension_using_type_parameter);
+
+        // If it's possible, suggest adding @objc.
+        Optional<ForeignErrorConvention> errorConvention;
+        if (!AFD->isObjC() &&
+            isRepresentableInObjC(AFD, ObjCReason::MemberOfObjCMembersClass,
+                                  errorConvention)) {
+          diagnose(AFD->getLoc(),
+                   diag::objc_generic_extension_using_type_parameter_try_objc)
+            .fixItInsert(AFD->getAttributeInsertionLoc(false), "@objc ");
+        }
+
         diagnose(GenericParamCaptureLoc,
                  diag::objc_generic_extension_using_type_parameter_here);
       }
diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp
index a63493c..77b6384 100644
--- a/lib/Sema/TypeCheckDecl.cpp
+++ b/lib/Sema/TypeCheckDecl.cpp
@@ -2627,7 +2627,7 @@
       // Handle methods first.
       if (auto overriddenFunc = dyn_cast<AbstractFunctionDecl>(overridden)) {
         // Determine the selector of the overridden method.
-        ObjCSelector overriddenSelector = overriddenFunc->getObjCSelector(&tc);
+        ObjCSelector overriddenSelector = overriddenFunc->getObjCSelector();
 
         // Dig out the @objc attribute on the method, if it exists.
         auto attr = decl->getAttrs().getAttribute<ObjCAttr>();
@@ -2867,7 +2867,7 @@
             return None;
           }
         };
-        auto sel = method->getObjCSelector(&TC);
+        auto sel = method->getObjCSelector();
         if (auto diagID = isForbiddenSelector(sel)) {
           auto diagInfo = getObjCMethodDiagInfo(method);
           TC.diagnose(method, *diagID,
@@ -6066,14 +6066,13 @@
         bool objCMatch = false;
         if (parentDecl->isObjC() && decl->isObjC()) {
           if (method) {
-            if (method->getObjCSelector(&TC)
-                  == parentMethod->getObjCSelector(&TC))
+            if (method->getObjCSelector() == parentMethod->getObjCSelector())
               objCMatch = true;
           } else if (auto *parentSubscript =
                        dyn_cast<SubscriptDecl>(parentStorage)) {
             // If the subscript kinds don't match, it's not an override.
-            if (subscript->getObjCSubscriptKind(&TC)
-                  == parentSubscript->getObjCSubscriptKind(&TC))
+            if (subscript->getObjCSubscriptKind()
+                  == parentSubscript->getObjCSubscriptKind())
               objCMatch = true;
           }
 
@@ -6170,11 +6169,11 @@
         if (objCMatch) {
           if (method) {
             TC.diagnose(decl, diag::override_objc_type_mismatch_method,
-                        method->getObjCSelector(&TC), declTy);
+                        method->getObjCSelector(), declTy);
           } else {
             TC.diagnose(decl, diag::override_objc_type_mismatch_subscript,
                         static_cast<unsigned>(
-                          subscript->getObjCSubscriptKind(&TC)),
+                          subscript->getObjCSubscriptKind()),
                         declTy);
           }
           TC.diagnose(parentDecl, diag::overridden_here_with_type,
diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp
index 598e5b6..879d0e0 100644
--- a/lib/Sema/TypeCheckType.cpp
+++ b/lib/Sema/TypeCheckType.cpp
@@ -3835,7 +3835,7 @@
     return false;
 
   // Make sure we know how to map the selector appropriately.
-  if (Result && SD->getObjCSubscriptKind(this) == ObjCSubscriptKind::None) {
+  if (Result && SD->getObjCSubscriptKind() == ObjCSubscriptKind::None) {
     SourceRange IndexRange = SD->getIndices()->getSourceRange();
     diagnose(SD->getLoc(), diag::objc_invalid_subscript_key_type,
              getObjCDiagnosticAttrKind(Reason), IndicesType)
diff --git a/stdlib/public/SwiftShims/LibcShims.h b/stdlib/public/SwiftShims/LibcShims.h
index 398bde1..f964cd5 100644
--- a/stdlib/public/SwiftShims/LibcShims.h
+++ b/stdlib/public/SwiftShims/LibcShims.h
@@ -38,7 +38,7 @@
 #elif defined(_WIN32)
 #if defined(_M_ARM) || defined(_M_IX86)
 typedef           int __swift_ssize_t;
-#elif defined(_M_X64)
+#elif defined(_M_X64) || defined(_M_ARM64)
 typedef long long int __swift_ssize_t;
 #else
 #error unsupported machine type
diff --git a/stdlib/public/core/ManagedBuffer.swift b/stdlib/public/core/ManagedBuffer.swift
index e5a8283..4be4a71 100644
--- a/stdlib/public/core/ManagedBuffer.swift
+++ b/stdlib/public/core/ManagedBuffer.swift
@@ -118,9 +118,8 @@
   public final func withUnsafeMutablePointers<R>(
     _ body: (UnsafeMutablePointer<Header>, UnsafeMutablePointer<Element>) throws -> R
   ) rethrows -> R {
-    let r = try body(headerAddress, firstElementAddress)
-    _fixLifetime(self)
-    return r
+    defer { _fixLifetime(self) }
+    return try body(headerAddress, firstElementAddress)
   }
 
   /// The stored `Header` instance.
@@ -304,9 +303,8 @@
   public func withUnsafeMutablePointers<R>(
     _ body: (UnsafeMutablePointer<Header>, UnsafeMutablePointer<Element>) throws -> R
   ) rethrows -> R {
-    let r = try body(_headerPointer, _elementPointer)
-    _fixLifetime(_nativeBuffer)
-    return r
+    defer { _fixLifetime(_nativeBuffer) }
+    return try body(_headerPointer, _elementPointer)
   }
 
   /// Returns `true` iff `self` holds the only strong reference to its buffer.
diff --git a/stdlib/public/core/NormalizedCodeUnitIterator.swift b/stdlib/public/core/NormalizedCodeUnitIterator.swift
index cc61452..901ced1 100644
--- a/stdlib/public/core/NormalizedCodeUnitIterator.swift
+++ b/stdlib/public/core/NormalizedCodeUnitIterator.swift
@@ -128,8 +128,7 @@
         index += 1
         bufferIndex += 1
       } while unmanagedString.hasNormalizationBoundary(
-          after: index - 1, 
-          count: unmanagedString.count) == false
+          after: index - 1) == false
       
       return bufferIndex
     }
diff --git a/stdlib/public/core/StringComparison.swift b/stdlib/public/core/StringComparison.swift
index 95dbd1b..680130d 100644
--- a/stdlib/public/core/StringComparison.swift
+++ b/stdlib/public/core/StringComparison.swift
@@ -803,7 +803,7 @@
       if idx+1 == other.count {
         return _lexicographicalCompare(selfASCIIChar, otherCU)
       }
-      if _fastPath(other.hasNormalizationBoundary(after: idx, count: other.count)) {
+      if _fastPath(other.hasNormalizationBoundary(after: idx)) {
         return _lexicographicalCompare(selfASCIIChar, otherCU)
       }
     }
@@ -843,9 +843,9 @@
 }
 
 extension _UnmanagedString where CodeUnit == UInt16 {
-  func hasNormalizationBoundary(after index: Int, count: Int) -> Bool {
+  func hasNormalizationBoundary(after index: Int) -> Bool {
     let nextIndex = index + 1
-    if nextIndex >= count {
+    if nextIndex >= self.count {
       return true
     }
     
@@ -1115,8 +1115,8 @@
       &selfOutputBuffer, selfLength,
       &otherOutputBuffer, otherLength) 
     {
-      let selfSlice = self[selfSegmentEndIdx...]
-      let otherSlice = other[otherSegmentEndIdx...]
+      let selfSlice = self[selfSegmentStartIdx...]
+      let otherSlice = other[otherSegmentStartIdx...]
       return selfSlice._compareStringsPathological(other: otherSlice)
     }
 
diff --git a/stdlib/public/runtime/CMakeLists.txt b/stdlib/public/runtime/CMakeLists.txt
index 8424276..3522c09 100644
--- a/stdlib/public/runtime/CMakeLists.txt
+++ b/stdlib/public/runtime/CMakeLists.txt
@@ -102,6 +102,10 @@
   set_target_properties(swiftImageInspectionShared PROPERTIES
     ARCHIVE_OUTPUT_DIRECTORY "${SWIFTSTATICLIB_DIR}/${lowercase_sdk}")
 
+  swift_install_in_component(stdlib
+    TARGETS swiftImageInspectionShared
+    DESTINATION "lib/swift_static/${lowercase_sdk}")
+
   # Generate the static-executable-args.lnk file used for ELF systems (eg linux)
   set(linkfile "${lowercase_sdk}/static-executable-args.lnk")
   add_custom_command_target(swift_static_binary_${sdk}_args
diff --git a/stdlib/public/runtime/Demangle.cpp b/stdlib/public/runtime/Demangle.cpp
index 8130e69..0cf3b33 100644
--- a/stdlib/public/runtime/Demangle.cpp
+++ b/stdlib/public/runtime/Demangle.cpp
@@ -151,10 +151,10 @@
         
         // Override the node kind if this is a Clang-imported type so we give it
         // a stable mangling.
-        auto typeFlags = type->Flags.getKindSpecificFlags();
-        if (typeFlags & (uint16_t)TypeContextDescriptorFlags::IsCTag) {
+        auto typeFlags = type->getTypeContextDescriptorFlags();
+        if (typeFlags.isCTag()) {
           nodeKind = Node::Kind::Structure;
-        } else if (typeFlags & (uint16_t)TypeContextDescriptorFlags::IsCTypedef) {
+        } else if (typeFlags.isCTypedef()) {
           nodeKind = Node::Kind::TypeAlias;
         }
         
diff --git a/stdlib/public/runtime/ImageInspectionCOFF.cpp b/stdlib/public/runtime/ImageInspectionCOFF.cpp
index a14311d..2b60233 100644
--- a/stdlib/public/runtime/ImageInspectionCOFF.cpp
+++ b/stdlib/public/runtime/ImageInspectionCOFF.cpp
@@ -82,6 +82,20 @@
   }
 }
 
+void swift::initializeTypeFieldLookup() {
+  const swift::MetadataSections *sections = registered;
+  while (true) {
+    const swift::MetadataSections::Range &fields = sections->swift5_fieldmd;
+    if (fields.length)
+      addImageTypeFieldDescriptorBlockCallback(
+          reinterpret_cast<void *>(fields.start), fields.length);
+
+    if (sections->next == registered)
+      break;
+    sections = sections->next;
+  }
+}
+
 SWIFT_RUNTIME_EXPORT
 void swift_addNewDSOImage(const void *addr) {
   const swift::MetadataSections *sections =
diff --git a/stdlib/public/runtime/MetadataLookup.cpp b/stdlib/public/runtime/MetadataLookup.cpp
index f03716c..273877b 100644
--- a/stdlib/public/runtime/MetadataLookup.cpp
+++ b/stdlib/public/runtime/MetadataLookup.cpp
@@ -187,7 +187,6 @@
     
     default:
       if (auto type = llvm::dyn_cast<TypeContextDescriptor>(context)) {
-        auto flags = type->Flags.getKindSpecificFlags();
         switch (node->getKind()) {
         // If the mangled name doesn't indicate a type kind, accept anything.
         // Otherwise, try to match them up.
@@ -195,7 +194,7 @@
           break;
         case Demangle::Node::Kind::Structure:
           if (type->getKind() != ContextDescriptorKind::Struct
-              && !(flags & (uint16_t)TypeContextDescriptorFlags::IsCTag))
+              && !type->getTypeContextDescriptorFlags().isCTag())
             return false;
           break;
         case Demangle::Node::Kind::Class:
@@ -207,7 +206,7 @@
             return false;
           break;
         case Demangle::Node::Kind::TypeAlias:
-          if (!(flags & (uint16_t)TypeContextDescriptorFlags::IsCTypedef))
+          if (!type->getTypeContextDescriptorFlags().isCTypedef())
             return false;
           break;
 
diff --git a/stdlib/public/runtime/ReflectionMirror.mm b/stdlib/public/runtime/ReflectionMirror.mm
index 8910654..2781eb3 100644
--- a/stdlib/public/runtime/ReflectionMirror.mm
+++ b/stdlib/public/runtime/ReflectionMirror.mm
@@ -39,6 +39,44 @@
 #include <objc/runtime.h>
 #endif
 
+#if defined(_WIN32)
+#include <stdarg.h>
+
+namespace {
+int asprintf(char **strp, const char *fmt, ...) {
+  va_list argp0, argp1;
+
+  va_start(argp0, fmt);
+  va_copy(argp1, argp0);
+
+  int length = _vscprintf(fmt, argp0);
+
+  *strp = reinterpret_cast<char *>(malloc(length + 1));
+  if (*strp == nullptr)
+    return -1;
+
+  length = _vsnprintf(*strp, length, fmt, argp1);
+
+  va_end(argp0);
+  va_end(argp1);
+
+  return length;
+}
+
+char *strndup(const char *s, size_t n) {
+  size_t length = std::min(strlen(s), n);
+
+  char *buffer = reinterpret_cast<char *>(malloc(length + 1));
+  if (buffer == nullptr)
+    return buffer;
+
+  strncpy(buffer, s, length);
+  buffer[length] = '\0';
+  return buffer;
+}
+}
+#endif
+
 using namespace swift;
 
 #if SWIFT_OBJC_INTEROP
@@ -268,7 +306,7 @@
   bool isReflectable() {
     const auto *Enum = static_cast<const EnumMetadata *>(type);
     const auto &Description = Enum->getDescription();
-    return Description->IsReflectable;
+    return Description->getTypeContextDescriptorFlags().isReflectable();
   }
   
   const char *getInfo(unsigned *tagPtr = nullptr,
diff --git a/test/AutolinkExtract/import_archive.swift b/test/AutolinkExtract/import_archive.swift
index 16e7b57..e578bce 100644
--- a/test/AutolinkExtract/import_archive.swift
+++ b/test/AutolinkExtract/import_archive.swift
@@ -1,4 +1,3 @@
-// REQUIRES: rdar37605557
 // RUN: %empty-directory(%t)
 // RUN: %target-swiftc_driver -emit-library -emit-module -emit-module-path %t/empty.swiftmodule -module-name empty -module-link-name empty %S/empty.swift
 // RUN: %target-swiftc_driver -c %s -I %t -o %t/import_experimental.o
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index fefbe22..64800a1 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -236,8 +236,8 @@
               # These two directories may contain the same libraries,
               # but upload both to device just in case. Duplicates will be
               # overwritten, and uploading doesn't take very long anyway.
-              "${SWIFT_ANDROID_ICU_UC}"
-              "${SWIFT_ANDROID_ICU_I18N}")
+              "${SWIFT_ANDROID_${ARCH}_ICU_UC}"
+              "${SWIFT_ANDROID_${ARCH}_ICU_I18N}")
     endif()
     add_custom_target("upload-stdlib${VARIANT_SUFFIX}"
         ${command_upload_stdlib}
diff --git a/test/ClangImporter/objc_bridging_generics.swift b/test/ClangImporter/objc_bridging_generics.swift
index 6fee23f..8ac6c6c 100644
--- a/test/ClangImporter/objc_bridging_generics.swift
+++ b/test/ClangImporter/objc_bridging_generics.swift
@@ -123,7 +123,7 @@
     _ = T.self // expected-note{{used here}}
   }
   // expected-error@+1{{extension of a generic Objective-C class cannot access the class's generic parameters}}
-@objc   func usesGenericParamE(_ x: Int) {
+  @objc func usesGenericParamE(_ x: Int) {
     _ = x as? T // expected-note{{used here}}
   }
   // expected-error@+1{{extension of a generic Objective-C class cannot access the class's generic parameters}}
@@ -249,18 +249,22 @@
   }
 
 
+  // expected-note@+2{{add '@objc' to allow uses of 'self' within the function body}}{{3-3=@objc }}
   // expected-error@+1{{extension of a generic Objective-C class cannot access the class's generic parameters}}
   func usesGenericParamA(_ x: T) {
     _ = T(noise: x) // expected-note{{used here}}
   }
+  // expected-note@+2{{add '@objc' to allow uses of 'self' within the function body}}{{3-3=@objc }}
   // expected-error@+1{{extension of a generic Objective-C class cannot access the class's generic parameters}}
   func usesGenericParamB() {
     _ = T.create() // expected-note{{used here}}
   }
+  // expected-note@+2{{add '@objc' to allow uses of 'self' within the function body}}{{3-3=@objc }}
   // expected-error@+1{{extension of a generic Objective-C class cannot access the class's generic parameters}}
   func usesGenericParamC() {
     _ = T.apexPredator // expected-note{{used here}}
   }
+  // expected-note@+2{{add '@objc' to allow uses of 'self' within the function body}}{{3-3=@objc }}
   // expected-error@+1{{extension of a generic Objective-C class cannot access the class's generic parameters}}
   func usesGenericParamD(_ x: T) {
     T.apexPredator = x // expected-note{{used here}}
@@ -269,6 +273,7 @@
   // rdar://problem/27796375 -- allocating init entry points for ObjC
   // initializers are generated as true Swift generics, so reify type
   // parameters.
+  // expected-note@+2{{add '@objc' to allow uses of 'self' within the function body}}{{3-3=@objc }}
   // expected-error@+1{{extension of a generic Objective-C class cannot access the class's generic parameters}}
   func usesGenericParamE(_ x: T) {
     _ = GenericClass(thing: x) // expected-note{{used here}}
diff --git a/test/Frontend/batch-mode.swift b/test/Frontend/batch-mode.swift
new file mode 100644
index 0000000..8706761f
--- /dev/null
+++ b/test/Frontend/batch-mode.swift
@@ -0,0 +1,16 @@
+// RUN: %empty-directory(%t)
+// RUN: echo 'public func a() { }' >%t/a.swift
+// RUN: echo 'public func b() { }' >%t/b.swift
+// RUN: echo 'public func c() { }' >%t/c.swift
+// RUN: echo 'public func main() {a(); b(); c()}' >%t/main.swift
+// RUN: %target-swift-frontend -c -enable-batch-mode -bypass-batch-mode-checks -module-name foo -primary-file %t/a.swift -primary-file %t/b.swift -primary-file %t/c.swift -primary-file %t/main.swift -o %t/a.o -o %t/b.o -o %t/c.o -o %t/main.o
+//
+// RUN: llvm-objdump -t %t/a.o | swift-demangle | %FileCheck -check-prefix=CHECK-A %s
+// RUN: llvm-objdump -t %t/b.o | swift-demangle | %FileCheck -check-prefix=CHECK-B %s
+// RUN: llvm-objdump -t %t/c.o | swift-demangle | %FileCheck -check-prefix=CHECK-C %s
+// RUN: llvm-objdump -t %t/main.o | swift-demangle | %FileCheck -check-prefix=CHECK-MAIN %s
+//
+// CHECK-A: foo.a() -> ()
+// CHECK-B: foo.b() -> ()
+// CHECK-C: foo.c() -> ()
+// CHECK-MAIN: foo.main() -> ()
diff --git a/test/IRGen/cf.sil b/test/IRGen/cf.sil
index f9cd361..bb9a108 100644
--- a/test/IRGen/cf.sil
+++ b/test/IRGen/cf.sil
@@ -28,7 +28,7 @@
 
 // CHECK-64: @"$SSo24CCMutableRefrigeratorRefaMn" = linkonce_odr hidden constant
 // -- is imported C typedef, is class, is nonunique
-// CHECK-64-SAME: <i32 0x1000_0010>
+// CHECK-64-SAME: <i32 0x0006_0010>
 // CHECK-64-SAME: [[MUTABLE_REFRIGERATOR_NAME]]
 
 // CHECK-64: @"$SSo24CCMutableRefrigeratorRefaN" = linkonce_odr hidden global <{ {{.*}} }> <{
diff --git a/test/IRGen/class_metadata.swift b/test/IRGen/class_metadata.swift
new file mode 100644
index 0000000..3f927a3
--- /dev/null
+++ b/test/IRGen/class_metadata.swift
@@ -0,0 +1,115 @@
+// RUN: %target-swift-frontend -emit-ir %s | %FileCheck %s -check-prefix=CHECK -check-prefix=CHECK-%target-ptrsize
+
+class A {}
+
+// CHECK:      [[A_NAME:@.*]] = private constant [2 x i8] c"A\00"
+// CHECK-LABEL: @"$S14class_metadata1ACMn" =
+//   Flags. -2147221424 == 0x8004_0050 == HasVTable | Reflectable | Unique | Class
+// CHECK-SAME: i32 -2147221424,
+//   Parent.
+// CHECK-SAME: i32 {{.*}} @"$S14class_metadataMXM"
+//   Name.
+// CHECK-SAME: i32 {{.*}} [[A_NAME]]
+//   Metadata access function.
+// CHECK-SAME: i32 {{.*}} @"$S14class_metadata1ACMa"
+//   Superclass.
+// CHECK-SAME: i32 0,
+//   Field count.
+// CHECK-SAME: i32 0,
+//   Field offset vector offset.
+// CHECK-32-SAME: i32 14,
+// CHECK-64-SAME: i32 11,
+//   V-table offset.
+// CHECK-32-SAME: i32 13,
+// CHECK-64-SAME: i32 10,
+//   V-table length.
+// CHECK-SAME: i32 1,
+//   V-table entry #1: invocation function.
+// CHECK-SAME: @"$S14class_metadata1ACACycfc"
+//   V-table entry #1: flags.
+// CHECK-SAME: i32 1 } }>, section
+
+class B : A {}
+
+// CHECK:      [[B_NAME:@.*]] = private constant [2 x i8] c"B\00"
+// CHECK-LABEL: @"$S14class_metadata1BCMn" =
+//   Flags. 262224 == 0x0004_0050 == Reflectable | Unique | Class
+// CHECK-SAME: i32 262224,
+//   Parent.
+// CHECK-SAME: i32 {{.*}} @"$S14class_metadataMXM"
+//   Name.
+// CHECK-SAME: i32 {{.*}} [[B_NAME]]
+//   Metadata access function.
+// CHECK-SAME: i32 {{.*}} @"$S14class_metadata1BCMa"
+//   Superclass.
+// CHECK-SAME: i32 {{.*}} @"$S14class_metadata1ACMn"
+//   Field count.
+// CHECK-SAME: i32 0,
+//   Field offset vector offset.
+// CHECK-32-SAME: i32 14 }>, section
+// CHECK-64-SAME: i32 11 }>, section
+
+class C<T> : B {}
+
+// CHECK:      [[C_NAME:@.*]] = private constant [2 x i8] c"C\00"
+// CHECK-LABEL: @"$S14class_metadata1CCMn" =
+//   Flags. 262352 == 0x0004_00d0 == Reflectable | Generic | Unique | Class
+// CHECK-SAME: i32 262352,
+//   Parent.
+// CHECK-SAME: i32 {{.*}} @"$S14class_metadataMXM"
+//   Name.
+// CHECK-SAME: i32 {{.*}} [[C_NAME]]
+//   Metadata access function.
+// CHECK-SAME: i32 {{.*}} @"$S14class_metadata1CCMa"
+//   Superclass.
+// CHECK-SAME: i32 {{.*}} @"$S14class_metadata1BCMn"
+//   Field count.
+// CHECK-SAME: i32 0,
+//   Field offset vector offset.
+// CHECK-32-SAME: i32 15,
+// CHECK-64-SAME: i32 12,
+//   Argument offset.
+// CHECK-32-SAME: i32 14,
+// CHECK-64-SAME: i32 11,
+//   Instantiation function.
+// CHECK-SAME: i32 {{.*}} @"$S14class_metadata1CCMi"
+//   Instantiation cache.
+// CHECK-SAME: i32 {{.*}} @"$S14class_metadata1CCMI"
+//   Generic parameter count.
+// CHECK-SAME: i32 1,
+//   Generic requirement count.
+// CHECK-SAME: i32 0,
+//   Key generic arguments count.
+// CHECK-SAME: i32 1,
+//   Extra generic arguments count.
+// CHECK-SAME: i32 0,
+//   Generic parameter descriptor #1: flags. -128 == 0x80 == Key
+// CHECK-SAME: i8 -128,
+///  Padding.
+// CHECK-SAME: i8 0,
+// CHECK-SAME: i8 0,
+// CHECK-SAME: i8 0 }>, section
+
+// For stupid reasons, when we declare the superclass after the subclass,
+// we end up using an indirect reference to the nominal type descriptor.
+class D : E {}
+
+// CHECK:      [[D_NAME:@.*]] = private constant [2 x i8] c"D\00"
+// CHECK-LABEL: @"$S14class_metadata1DCMn" =
+//   Flags. 268697680 == 0x1004_0050 == Reflectable | IndirectSuperclass | Unique | Class
+// CHECK-SAME: i32 268697680,
+//   Parent.
+// CHECK-SAME: i32 {{.*}} @"$S14class_metadataMXM"
+//   Name.
+// CHECK-SAME: i32 {{.*}} [[D_NAME]]
+//   Metadata access function.
+// CHECK-SAME: i32 {{.*}} @"$S14class_metadata1DCMa"
+//   Superclass.
+// CHECK-SAME: i32 {{.*}} @"got.$S14class_metadata1ECMn
+//   Field count.
+// CHECK-SAME: i32 0,
+//   Field offset vector offset.
+// CHECK-32-SAME: i32 14 }>, section
+// CHECK-64-SAME: i32 11 }>, section
+
+class E {}
diff --git a/test/IRGen/class_resilience.swift b/test/IRGen/class_resilience.swift
index 776eac4..da4709b 100644
--- a/test/IRGen/class_resilience.swift
+++ b/test/IRGen/class_resilience.swift
@@ -29,8 +29,8 @@
 // CHECK: [[RESILIENTCHILD_NAME:@.*]] = private constant [15 x i8] c"ResilientChild\00"
 
 // CHECK: @"$S16class_resilience14ResilientChildCMn" = {{(protected )?}}constant <{{.*}}> <{
-// --       flags: class, unique, has vtable, has resilient superclass
-// CHECK-SAME:   <i32 0xC000_0050>
+// --       flags: class, unique, reflectable, has vtable, has resilient superclass
+// CHECK-SAME:   <i32 0xD004_0050>
 // --       name:
 // CHECK-SAME:   [15 x i8]* [[RESILIENTCHILD_NAME]]
 // --       num fields
diff --git a/test/IRGen/dllimport.swift b/test/IRGen/dllimport.swift
index c24285c..b46c279 100644
--- a/test/IRGen/dllimport.swift
+++ b/test/IRGen/dllimport.swift
@@ -52,7 +52,7 @@
 // CHECK-OPT-DAG: declare dllimport %swift.refcounted* @swift_retain(%swift.refcounted* returned) local_unnamed_addr
 // CHECK-OPT-DAG: @"$SBoWV" = external dllimport global i8*
 // CHECK-OPT-DAG: @"$S9dllexport1cCN" = external dllimport global %swift.type
-// CHECK-OPT-DAG: @"$S9dllexport1pMp" = external dllimport global %swift.protocol
+// CHECK-OPT-DAG: @"__imp_$S9dllexport1pMp" = external externally_initialized constant %swift.protocol*
 // CHECK-OPT-DAG: declare dllimport swiftcc i8* @"$S9dllexport2ciAA1cCvau"()
 // CHECK-OPT-DAG: declare dllimport %swift.type* @"$S9dllexport1cCMa"()
 // CHECK-OPT-DAG: declare dllimport void @swift_deallocClassInstance(%swift.refcounted*, i32, i32)
diff --git a/test/IRGen/generic_classes.sil b/test/IRGen/generic_classes.sil
index 2426a4c..3700dc5 100644
--- a/test/IRGen/generic_classes.sil
+++ b/test/IRGen/generic_classes.sil
@@ -15,8 +15,8 @@
 // CHECK: [[ROOTGENERIC_NAME:@.*]] = private constant [12 x i8] c"RootGeneric\00"
 
 // CHECK-LABEL: @"$S15generic_classes11RootGenericCMn" =
-// --       flags: class, generic, unique, has vtable
-// CHECK-SAME:   <i32 0x8000_00D0>
+// --       flags: class, generic, unique, reflectable, has vtable
+// CHECK-SAME:   <i32 0x8004_00D0>
 // --       name
 // CHECK-SAME:   [12 x i8]* [[ROOTGENERIC_NAME]]
 // --       num fields
@@ -54,8 +54,8 @@
 //    FIXME: Strings should be unnamed_addr. rdar://problem/22674524
 // CHECK: [[ROOTNONGENERIC_NAME:@.*]] = private constant [15 x i8] c"RootNonGeneric\00"
 // CHECK: @"$S15generic_classes14RootNonGenericCMn" = hidden constant <{ {{.*}} %swift.method_descriptor }> <{
-// --       flags: class, unique, has vtable
-// CHECK-SAME:   <i32 0x8000_0050>
+// --       flags: class, unique, has vtable, reflectable
+// CHECK-SAME:   <i32 0x8004_0050>
 // --       name
 // CHECK-SAME:   [15 x i8]* [[ROOTNONGENERIC_NAME]]
 // --       num fields
diff --git a/test/IRGen/generic_structs.sil b/test/IRGen/generic_structs.sil
index caf5d4f..7af64cd 100644
--- a/test/IRGen/generic_structs.sil
+++ b/test/IRGen/generic_structs.sil
@@ -21,8 +21,8 @@
 //    FIXME: Strings should be unnamed_addr. rdar://problem/22674524
 // CHECK: [[SINGLEDYNAMIC_NAME:@.*]] = private constant [14 x i8] c"SingleDynamic\00"
 // CHECK: @"$S15generic_structs13SingleDynamicVMn" = hidden constant 
-// --       flags: struct, unique, generic
-// CHECK-SAME:   <i32 0x0000_00D1>
+// --       flags: struct, unique, generic, reflectable
+// CHECK-SAME:   <i32 0x0004_00D1>
 // --       name
 // CHECK-SAME:   [14 x i8]* [[SINGLEDYNAMIC_NAME]]
 // --       field count
@@ -51,8 +51,8 @@
 //    FIXME: Strings should be unnamed_addr. rdar://problem/22674524
 // CHECK: [[DYNAMICWITHREQUIREMENTS_NAME:@.*]] = private constant [24 x i8] c"DynamicWithRequirements\00"
 // CHECK: @"$S15generic_structs23DynamicWithRequirementsVMn" = hidden constant <{ {{.*}} i32 }> <{
-// --       flags: struct, unique, generic
-// CHECK-SAME:   <i32 0x0000_00D1>
+// --       flags: struct, unique, generic, reflectable
+// CHECK-SAME:   <i32 0x0004_00D1>
 // --       name
 // CHECK-SAME: [24 x i8]* [[DYNAMICWITHREQUIREMENTS_NAME]]
 // --       field count
diff --git a/test/IRGen/generic_vtable.swift b/test/IRGen/generic_vtable.swift
index 1fb3376..dd5c8f0 100644
--- a/test/IRGen/generic_vtable.swift
+++ b/test/IRGen/generic_vtable.swift
@@ -23,8 +23,8 @@
 //// Nominal type descriptor for 'Base' does not have any method descriptors.
 
 // CHECK-LABEL: @"$S14generic_vtable4BaseCMn" = {{(protected )?}}constant
-// -- flags: has vtable, is class, is unique
-// CHECK-SAME: <i32 0x8000_0050>,
+// -- flags: has vtable, reflectable, is class, is unique
+// CHECK-SAME: <i32 0x8004_0050>,
 // -- vtable offset
 // CHECK-SAME: i32 10,
 // -- vtable size
@@ -48,8 +48,8 @@
 //// Nominal type descriptor for 'Derived' has method descriptors.
 
 // CHECK-LABEL: @"$S14generic_vtable7DerivedCMn" = {{(protected )?}}constant
-// -- flags: has vtable, is class, is unique, is generic
-// CHECK-SAME: <i32 0x8000_00D0>,
+// -- flags: has vtable, reflectable, is class, is unique, is generic
+// CHECK-SAME: <i32 0x8004_00D0>,
 // -- vtable offset
 // CHECK-SAME: i32 14,
 // -- vtable size
@@ -74,8 +74,8 @@
 //// Nominal type descriptor for 'Concrete' has method descriptors.
 
 // CHECK-LABEL: @"$S14generic_vtable8ConcreteCMn" = {{(protected )?}}constant
-// -- flags: has vtable, is class, is unique
-// CHECK-SAME: <i32 0x8000_0050>,
+// -- flags: has vtable, reflectable, is class, is unique
+// CHECK-SAME: <i32 0x8004_0050>,
 // -- vtable offset
 // CHECK-SAME: i32 15,
 // -- vtable size
diff --git a/test/IRGen/type_layout_reference_storage.swift b/test/IRGen/type_layout_reference_storage.swift
index 8c6f954..d7f905d 100644
--- a/test/IRGen/type_layout_reference_storage.swift
+++ b/test/IRGen/type_layout_reference_storage.swift
@@ -91,3 +91,20 @@
   // CHECK: store i8** getelementptr inbounds (i8*, i8** @"$S[[UNKNOWN]]SgXwWV", i32 9)
   weak            var uwi: Unknown!
 }
+
+
+public class Base {
+   var a: UInt32 = 0
+}
+// CHECK-LABEL: %swift.type* @{{.*}}7DerivedCMi"(%swift.type_descriptor*, i8**)
+// CHECK-NOT: store {{.*}}getelementptr{{.*}}SBomWV
+// CHECK: call %swift.type* @"$S29type_layout_reference_storage1P_pXmTMa"()
+// CHECK: store {{.*}}getelementptr{{.*}}SBoWV
+// CHECK: ret
+public class Derived<T> : Base {
+  var type : P.Type
+  var k = C()
+  init(_ t: P.Type) {
+    type = t
+  }
+}
diff --git a/test/Interpreter/metatype.swift b/test/Interpreter/metatype.swift
new file mode 100644
index 0000000..f8efb06
--- /dev/null
+++ b/test/Interpreter/metatype.swift
@@ -0,0 +1,29 @@
+// RUN: %target-run-simple-swift | %FileCheck %s
+// REQUIRES: executable_test
+
+protocol Bar : class {
+}
+
+public class Foo : Bar {
+}
+
+public class Base {
+   final fileprivate(set) var a: UInt32 = 0
+}
+
+public class Derived<T> : Base {
+  final var type : Bar.Type
+  final var k = Foo()
+
+  init(_ t: Bar.Type, _ kl: Foo ) {
+    type = t
+    k = kl
+  }
+}
+
+public func dontCrash() {
+  // CHECK: Derived<Swift.Int>
+  print(Derived<Int>(Foo.self, Foo()))
+}
+
+dontCrash()
diff --git a/test/SILGen/expressions.swift b/test/SILGen/expressions.swift
index b3c8da2..5f91200 100644
--- a/test/SILGen/expressions.swift
+++ b/test/SILGen/expressions.swift
@@ -555,7 +555,7 @@
 }
 
 
-func dynamicTypePlusZero(_ a : Super1) -> Super1.Type {
+func dynamicTypePlusZero(_ a: Super1) -> Super1.Type {
   return type(of: a)
 }
 // CHECK-LABEL: dynamicTypePlusZero
@@ -567,9 +567,15 @@
 // CHECK: end_borrow [[BORROWED_ARG]] from [[ARG]]
 // CHECK: destroy_value [[ARG]]
 
-struct NonTrivialStruct { var c : Super1 }
+struct NonTrivialStruct {
+  var c : Super1
+  var x: NonTrivialStruct? {
+    get { return nil }
+    set {}
+  }
+}
 
-func dontEmitIgnoredLoadExpr(_ a : NonTrivialStruct) -> NonTrivialStruct.Type {
+func dontEmitIgnoredLoadExpr(_ a: NonTrivialStruct) -> NonTrivialStruct.Type {
   return type(of: a)
 }
 // CHECK-LABEL: dontEmitIgnoredLoadExpr
@@ -581,6 +587,118 @@
 // CHECK-NEXT: destroy_value %0
 // CHECK-NEXT: return %4 : $@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 : @owned $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_BORROW:%[0-9]+]] = begin_borrow %1
+// CHECK-NEXT: [[KP_TEMP:%[0-9]+]] = copy_value [[KP_BORROW]]
+// 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: apply [[PROJECT_FN]]<NonTrivialStruct, Int>([[RESULT]], [[S_TEMP]], [[KP]])
+// CHECK-NEXT: end_access [[S_READ]]
+// CHECK-NEXT: dealloc_stack [[RESULT]]
+// CHECK-NEXT: end_borrow [[KP_BORROW]] from %1
+// CHECK-NEXT: dealloc_stack [[S_TEMP]]
+// CHECK-NEXT: [[METATYPE:%[0-9]+]] = metatype $@thin Int.Type
+// CHECK-NEXT: 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
diff --git a/test/Sema/type_join.swift b/test/Sema/type_join.swift
index 2a469b1..bf5df54 100644
--- a/test/Sema/type_join.swift
+++ b/test/Sema/type_join.swift
@@ -10,6 +10,32 @@
 expectEqualType(Builtin.type_join(Int.self, Int.self), Int.self)
 expectEqualType(Builtin.type_join_meta(D.self, C.self), C.self)
 
+expectEqualType(Builtin.type_join(Int?.self, Int?.self), Int?.self)
+expectEqualType(Builtin.type_join(Int.self, Int?.self), Int?.self)
+expectEqualType(Builtin.type_join(Int?.self, Int.self), Int?.self)
+expectEqualType(Builtin.type_join(Int.self, Int??.self), Int??.self)
+expectEqualType(Builtin.type_join(Int??.self, Int.self), Int??.self)
+expectEqualType(Builtin.type_join(Int?.self, Int??.self), Int??.self)
+expectEqualType(Builtin.type_join(Int??.self, Int?.self), Int??.self)
+expectEqualType(Builtin.type_join(D?.self, D?.self), D?.self)
+expectEqualType(Builtin.type_join(C?.self, D?.self), C?.self)
+expectEqualType(Builtin.type_join(D?.self, C?.self), C?.self)
+expectEqualType(Builtin.type_join(D.self, D?.self), D?.self)
+expectEqualType(Builtin.type_join(D?.self, D.self), D?.self)
+expectEqualType(Builtin.type_join(C.self, D?.self), C?.self)
+expectEqualType(Builtin.type_join(D?.self, C.self), C?.self)
+expectEqualType(Builtin.type_join(D.self, C?.self), C?.self)
+expectEqualType(Builtin.type_join(C?.self, D.self), C?.self)
+expectEqualType(Builtin.type_join(Any?.self, D.self), Any?.self)
+expectEqualType(Builtin.type_join(D.self, Any?.self), Any?.self)
+expectEqualType(Builtin.type_join(Any.self, D?.self), Any?.self)
+expectEqualType(Builtin.type_join(D?.self, Any.self), Any?.self)
+expectEqualType(Builtin.type_join(Any?.self, Any.self), Any?.self)
+expectEqualType(Builtin.type_join(Any.self, Any?.self), Any?.self)
+
 func rdar37241221(_ a: C?, _ b: D?) {
-  let _ = [a!, b] // Should be inferred as `[C?]`
+  let c: C? = C()
+  let array_c_opt = [c]
+  let inferred = [a!, b]
+  expectEqualType(type(of: array_c_opt).self, type(of: inferred).self)
 }
diff --git a/test/SourceKit/CodeFormat/indent-zero-width.swift b/test/SourceKit/CodeFormat/indent-zero-width.swift
new file mode 100644
index 0000000..371fd5d
--- /dev/null
+++ b/test/SourceKit/CodeFormat/indent-zero-width.swift
@@ -0,0 +1,22 @@
+class Foo {
+
+var test : Int
+
+	func foo() {
+		test = 1
+	}
+
+}
+func bar(a: Int,
+b: Int) {}
+
+// RUN: %sourcekitd-test -req=format -line=1 -length=1 -req-opts=usetabs=0 -req-opts=indentwidth=0 %s >%t.response
+// RUN: %sourcekitd-test -req=format -line=3 -length=1 -req-opts=usetabs=0 -req-opts=indentwidth=0 %s >>%t.response
+// RUN: %sourcekitd-test -req=format -line=6 -length=1 -req-opts=usetabs=0 -req-opts=indentwidth=0 %s >>%t.response
+// RUN: %sourcekitd-test -req=format -line=11 -length=1 -req-opts=usetabs=0 -req-opts=indentwidth=0 %s >>%t.response
+// RUN: %FileCheck --strict-whitespace %s <%t.response
+
+// CHECK: key.sourcetext: "class Foo {"
+// CHECK: key.sourcetext: "var test : Int"
+// CHECK: key.sourcetext: "    test = 1"
+// CHECK: key.sourcetext: "         b: Int) {}"
diff --git a/test/SourceKit/DocSupport/Inputs/cake1.swift b/test/SourceKit/DocSupport/Inputs/cake1.swift
index 0b53509..1895342 100644
--- a/test/SourceKit/DocSupport/Inputs/cake1.swift
+++ b/test/SourceKit/DocSupport/Inputs/cake1.swift
@@ -25,3 +25,7 @@
 public extension P2 where Self : P3 {
   func fooConstraint() {}
 }
+
+public extension Dictionary.Keys {
+  public func foo() {}
+}
diff --git a/test/SourceKit/DocSupport/doc_swift_module1.swift.response b/test/SourceKit/DocSupport/doc_swift_module1.swift.response
index 193fea0..9de4a19 100644
--- a/test/SourceKit/DocSupport/doc_swift_module1.swift.response
+++ b/test/SourceKit/DocSupport/doc_swift_module1.swift.response
@@ -41,6 +41,11 @@
     func p3Required()
 }
 
+extension Dictionary.Keys where Key : Hashable {
+
+    func foo()
+}
+
 
 [
   {
@@ -383,6 +388,52 @@
     key.kind: source.lang.swift.syntaxtype.identifier,
     key.offset: 439,
     key.length: 10
+  },
+  {
+    key.kind: source.lang.swift.syntaxtype.keyword,
+    key.offset: 455,
+    key.length: 9
+  },
+  {
+    key.kind: source.lang.swift.ref.struct,
+    key.name: "Dictionary",
+    key.usr: "s:s10DictionaryV",
+    key.offset: 465,
+    key.length: 10
+  },
+  {
+    key.kind: source.lang.swift.ref.struct,
+    key.name: "Keys",
+    key.usr: "s:s10DictionaryV4KeysV",
+    key.offset: 476,
+    key.length: 4
+  },
+  {
+    key.kind: source.lang.swift.syntaxtype.keyword,
+    key.offset: 481,
+    key.length: 5
+  },
+  {
+    key.kind: source.lang.swift.syntaxtype.typeidentifier,
+    key.offset: 487,
+    key.length: 3
+  },
+  {
+    key.kind: source.lang.swift.ref.protocol,
+    key.name: "Hashable",
+    key.usr: "s:s8HashableP",
+    key.offset: 493,
+    key.length: 8
+  },
+  {
+    key.kind: source.lang.swift.syntaxtype.keyword,
+    key.offset: 509,
+    key.length: 4
+  },
+  {
+    key.kind: source.lang.swift.syntaxtype.identifier,
+    key.offset: 514,
+    key.length: 3
   }
 ]
 [
@@ -610,5 +661,38 @@
         key.fully_annotated_decl: "<decl.function.method.instance><syntaxtype.keyword>func</syntaxtype.keyword> <decl.name>p3Required</decl.name>()</decl.function.method.instance>"
       }
     ]
+  },
+  {
+    key.kind: source.lang.swift.decl.extension.struct,
+    key.generic_params: [
+      {
+        key.name: "Key"
+      },
+      {
+        key.name: "Value"
+      }
+    ],
+    key.generic_requirements: [
+      {
+        key.description: "Key : Hashable"
+      }
+    ],
+    key.offset: 455,
+    key.length: 66,
+    key.extends: {
+      key.kind: source.lang.swift.ref.struct,
+      key.name: "Keys",
+      key.usr: "s:s10DictionaryV4KeysV"
+    },
+    key.entities: [
+      {
+        key.kind: source.lang.swift.decl.function.method.instance,
+        key.name: "foo()",
+        key.usr: "s:s10DictionaryV4KeysV5cake1E3fooyyF",
+        key.offset: 509,
+        key.length: 10,
+        key.fully_annotated_decl: "<decl.function.method.instance><syntaxtype.keyword>func</syntaxtype.keyword> <decl.name>foo</decl.name>()</decl.function.method.instance>"
+      }
+    ]
   }
 ]
diff --git a/tools/SourceKit/lib/SwiftLang/SwiftASTManager.cpp b/tools/SourceKit/lib/SwiftLang/SwiftASTManager.cpp
index d5379b0..5452a25 100644
--- a/tools/SourceKit/lib/SwiftLang/SwiftASTManager.cpp
+++ b/tools/SourceKit/lib/SwiftLang/SwiftASTManager.cpp
@@ -439,7 +439,6 @@
   ImporterOpts.DetailedPreprocessingRecord = true;
 
   assert(!Invocation.getModuleName().empty());
-  Invocation.setSerializedDiagnosticsPath(StringRef());
   Invocation.getLangOptions().AttachCommentsToDecls = true;
   Invocation.getLangOptions().DiagnosticsEditorMode = true;
   Invocation.getLangOptions().CollectParsedToken = true;
@@ -700,7 +699,7 @@
       Invok.Opts.Invok.getFrontendOptions().InputsAndOutputs.inputCount());
   for (const auto &input :
        Invok.Opts.Invok.getFrontendOptions().InputsAndOutputs.getAllInputs()) {
-    StringRef File = input.file();
+    const std::string &File = input.file();
     bool FoundSnapshot = false;
     for (auto &Snap : Snapshots) {
       if (Snap->getFilename() == File) {
@@ -887,7 +886,7 @@
   const InvocationOptions &Opts = InvokRef->Impl.Opts;
   for (const auto &input :
        Opts.Invok.getFrontendOptions().InputsAndOutputs.getAllInputs()) {
-    StringRef File = input.file();
+    const std::string &File = input.file();
     bool IsPrimary = input.isPrimary();
     bool FoundSnapshot = false;
     for (auto &Snap : Snapshots) {
diff --git a/tools/SourceKit/tools/swift-lang/SourceKitdClient.swift b/tools/SourceKit/tools/swift-lang/SourceKitdClient.swift
index 52c4c1e..2b53977 100644
--- a/tools/SourceKit/tools/swift-lang/SourceKitdClient.swift
+++ b/tools/SourceKit/tools/swift-lang/SourceKitdClient.swift
@@ -23,7 +23,22 @@
   deinit {
     sourcekitd_shutdown()
   }
+
+  /// Send a request synchronously with a handler for its response.
+  /// - Parameter request: The request to send.
+  /// - Returns: The response from the sourcekitd service.
   public func sendSyn(request: SourceKitdRequest) -> SourceKitdResponse {
     return SourceKitdResponse(resp: sourcekitd_send_request_sync(request.rawRequest))
   }
+
+  /// Send a request asynchronously with a handler for its response.
+  /// - Parameter request: The request to send.
+  /// - Parameter handler: The handler for the response in the future.
+  public func send(request: SourceKitdRequest,
+                   handler: @escaping (SourceKitdResponse) -> ())  {
+    sourcekitd_send_request(request.rawRequest, nil) { response in
+      guard let response = response else { return }
+      handler(SourceKitdResponse(resp: response))
+    }
+  }
 }
diff --git a/tools/driver/driver.cpp b/tools/driver/driver.cpp
index 74421b7..341c880 100644
--- a/tools/driver/driver.cpp
+++ b/tools/driver/driver.cpp
@@ -110,7 +110,7 @@
 extern int apinotes_main(ArrayRef<const char *> Args);
 
 int main(int argc_, const char **argv_) {
-  INITIALIZE_LLVM(argc_, argv_);
+  PROGRAM_START(argc_, argv_);
 
   SmallVector<const char *, 256> argv;
   llvm::SpecificBumpPtrAllocator<char> ArgAllocator;
diff --git a/tools/driver/modulewrap_main.cpp b/tools/driver/modulewrap_main.cpp
index 846a4e7..579e1c0 100644
--- a/tools/driver/modulewrap_main.cpp
+++ b/tools/driver/modulewrap_main.cpp
@@ -18,6 +18,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "swift/AST/DiagnosticsFrontend.h"
+#include "swift/Basic/LLVMInitialize.h"
 #include "swift/Frontend/Frontend.h"
 #include "swift/Frontend/PrintingDiagnosticConsumer.h"
 #include "swift/Option/Options.h"
@@ -113,10 +114,7 @@
 
 int modulewrap_main(ArrayRef<const char *> Args, const char *Argv0,
                     void *MainAddr) {
-  llvm::InitializeAllTargets();
-  llvm::InitializeAllTargetMCs();
-  llvm::InitializeAllAsmPrinters();
-  llvm::InitializeAllAsmParsers();
+  INITIALIZE_LLVM();
 
   CompilerInstance Instance;
   PrintingDiagnosticConsumer PDC;
diff --git a/tools/lldb-moduleimport-test/lldb-moduleimport-test.cpp b/tools/lldb-moduleimport-test/lldb-moduleimport-test.cpp
index 38a097d..4b5b3f0 100644
--- a/tools/lldb-moduleimport-test/lldb-moduleimport-test.cpp
+++ b/tools/lldb-moduleimport-test/lldb-moduleimport-test.cpp
@@ -62,7 +62,8 @@
 }
 
 int main(int argc, char **argv) {
-  INITIALIZE_LLVM(argc, argv);
+  PROGRAM_START(argc, argv);
+  INITIALIZE_LLVM();
 
   // Command line handling.
   llvm::cl::list<std::string> InputNames(
diff --git a/tools/sil-func-extractor/SILFunctionExtractor.cpp b/tools/sil-func-extractor/SILFunctionExtractor.cpp
index 138013c..a764a08 100644
--- a/tools/sil-func-extractor/SILFunctionExtractor.cpp
+++ b/tools/sil-func-extractor/SILFunctionExtractor.cpp
@@ -225,7 +225,8 @@
 }
 
 int main(int argc, char **argv) {
-  INITIALIZE_LLVM(argc, argv);
+  PROGRAM_START(argc, argv);
+  INITIALIZE_LLVM();
 
   llvm::cl::ParseCommandLineOptions(argc, argv, "Swift SIL Extractor\n");
 
diff --git a/tools/sil-llvm-gen/SILLLVMGen.cpp b/tools/sil-llvm-gen/SILLLVMGen.cpp
index c16de4c..b450a81 100644
--- a/tools/sil-llvm-gen/SILLLVMGen.cpp
+++ b/tools/sil-llvm-gen/SILLLVMGen.cpp
@@ -113,7 +113,8 @@
 void anchorForGetMainExecutable() {}
 
 int main(int argc, char **argv) {
-  INITIALIZE_LLVM(argc, argv);
+  PROGRAM_START(argc, argv);
+  INITIALIZE_LLVM();
 
   llvm::cl::ParseCommandLineOptions(argc, argv, "Swift LLVM IR Generator\n");
 
diff --git a/tools/sil-nm/SILNM.cpp b/tools/sil-nm/SILNM.cpp
index 6e9d6ce..d914f0c 100644
--- a/tools/sil-nm/SILNM.cpp
+++ b/tools/sil-nm/SILNM.cpp
@@ -139,7 +139,8 @@
 }
 
 int main(int argc, char **argv) {
-  INITIALIZE_LLVM(argc, argv);
+  PROGRAM_START(argc, argv);
+  INITIALIZE_LLVM();
 
   llvm::cl::ParseCommandLineOptions(argc, argv, "SIL NM\n");
 
diff --git a/tools/sil-opt/SILOpt.cpp b/tools/sil-opt/SILOpt.cpp
index ab500c1..1467da4 100644
--- a/tools/sil-opt/SILOpt.cpp
+++ b/tools/sil-opt/SILOpt.cpp
@@ -264,7 +264,8 @@
 void anchorForGetMainExecutable() {}
 
 int main(int argc, char **argv) {
-  INITIALIZE_LLVM(argc, argv);
+  PROGRAM_START(argc, argv);
+  INITIALIZE_LLVM();
 
   llvm::cl::ParseCommandLineOptions(argc, argv, "Swift SIL optimizer\n");
 
@@ -427,9 +428,9 @@
   } else {
     auto *SILMod = CI.getSILModule();
     {
-      const auto PSPs = CI.getPrimarySpecificPathsForAtMostOnePrimary();
       auto T = irgen::createIRGenModule(
-          SILMod, PSPs.OutputFilename, PSPs.MainInputFilenameForDebugInfo,
+          SILMod, Invocation.getOutputFilenameForAtMostOnePrimary(),
+          Invocation.getMainInputFilenameForDebugInfoForAtMostOnePrimary(),
           getGlobalLLVMContext());
       runCommandLineSelectedPasses(SILMod, T.second);
       irgen::deleteIRGenModule(T);
diff --git a/tools/sil-passpipeline-dumper/SILPassPipelineDumper.cpp b/tools/sil-passpipeline-dumper/SILPassPipelineDumper.cpp
index ee0332f..6ad3313 100644
--- a/tools/sil-passpipeline-dumper/SILPassPipelineDumper.cpp
+++ b/tools/sil-passpipeline-dumper/SILPassPipelineDumper.cpp
@@ -44,7 +44,8 @@
 } // namespace llvm
 
 int main(int argc, char **argv) {
-  INITIALIZE_LLVM(argc, argv);
+  PROGRAM_START(argc, argv);
+  INITIALIZE_LLVM();
 
   llvm::cl::ParseCommandLineOptions(argc, argv,
                                     "Swift SIL Pass Pipeline Dumper\n");
diff --git a/tools/swift-api-digester/swift-api-digester.cpp b/tools/swift-api-digester/swift-api-digester.cpp
index c1ab72f..bb6927d 100644
--- a/tools/swift-api-digester/swift-api-digester.cpp
+++ b/tools/swift-api-digester/swift-api-digester.cpp
@@ -3610,7 +3610,8 @@
 }
 
 int main(int argc, char *argv[]) {
-  INITIALIZE_LLVM(argc, argv);
+  PROGRAM_START(argc, argv);
+  INITIALIZE_LLVM();
 
   llvm::cl::ParseCommandLineOptions(argc, argv, "Swift SDK Digester\n");
   CompilerInvocation InitInvok;
diff --git a/tools/swift-ide-test/swift-ide-test.cpp b/tools/swift-ide-test/swift-ide-test.cpp
index b84602d..4f37ef7 100644
--- a/tools/swift-ide-test/swift-ide-test.cpp
+++ b/tools/swift-ide-test/swift-ide-test.cpp
@@ -2928,7 +2928,8 @@
 void anchorForGetMainExecutable() {}
 
 int main(int argc, char *argv[]) {
-  INITIALIZE_LLVM(argc, argv);
+  PROGRAM_START(argc, argv);
+  INITIALIZE_LLVM();
 
   if (argc > 1) {
     // Handle integrated test tools which do not use
diff --git a/tools/swift-llvm-opt/LLVMOpt.cpp b/tools/swift-llvm-opt/LLVMOpt.cpp
index cba627f..a744f42 100644
--- a/tools/swift-llvm-opt/LLVMOpt.cpp
+++ b/tools/swift-llvm-opt/LLVMOpt.cpp
@@ -212,7 +212,8 @@
 //===----------------------------------------------------------------------===//
 
 int main(int argc, char **argv) {
-  INITIALIZE_LLVM(argc, argv);
+  PROGRAM_START(argc, argv);
+  INITIALIZE_LLVM();
 
   // Initialize passes
   PassRegistry &Registry = *PassRegistry::getPassRegistry();
diff --git a/tools/swift-refactor/swift-refactor.cpp b/tools/swift-refactor/swift-refactor.cpp
index 71ebf2f..02a6bb7 100644
--- a/tools/swift-refactor/swift-refactor.cpp
+++ b/tools/swift-refactor/swift-refactor.cpp
@@ -10,12 +10,13 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "llvm/Support/CommandLine.h"
 #include "swift/Basic/LLVMInitialize.h"
 #include "swift/Frontend/Frontend.h"
 #include "swift/Frontend/PrintingDiagnosticConsumer.h"
 #include "swift/IDE/Refactoring.h"
 #include "swift/IDE/Utils.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/FileSystem.h"
 
 #include <regex>
 
@@ -218,7 +219,8 @@
 void anchorForGetMainExecutable() {}
 
 int main(int argc, char *argv[]) {
-  INITIALIZE_LLVM(argc, argv);
+  PROGRAM_START(argc, argv);
+  INITIALIZE_LLVM();
   llvm::cl::ParseCommandLineOptions(argc, argv, "Swift refactor\n");
   if (options::SourceFilename.empty()) {
     llvm::errs() << "cannot find source filename\n";
diff --git a/tools/swift-reflection-dump/swift-reflection-dump.cpp b/tools/swift-reflection-dump/swift-reflection-dump.cpp
index 53e3e4a..e80b8fe 100644
--- a/tools/swift-reflection-dump/swift-reflection-dump.cpp
+++ b/tools/swift-reflection-dump/swift-reflection-dump.cpp
@@ -293,6 +293,7 @@
 }
 
 int main(int argc, char *argv[]) {
+  PROGRAM_START(argc, argv);
   llvm::cl::ParseCommandLineOptions(argc, argv, "Swift Reflection Dump\n");
   return doDumpReflectionSections(options::BinaryFilename,
                                   options::Architecture,
diff --git a/tools/swift-remoteast-test/swift-remoteast-test.cpp b/tools/swift-remoteast-test/swift-remoteast-test.cpp
index 0096dab..25f9473 100644
--- a/tools/swift-remoteast-test/swift-remoteast-test.cpp
+++ b/tools/swift-remoteast-test/swift-remoteast-test.cpp
@@ -19,6 +19,7 @@
 #include "swift/Frontend/Frontend.h"
 #include "swift/FrontendTool/FrontendTool.h"
 #include "swift/Basic/LLVM.h"
+#include "swift/Basic/LLVMInitialize.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/Support/raw_ostream.h"
 #include <cassert>
@@ -143,6 +144,8 @@
 } // end anonymous namespace
 
 int main(int argc, const char *argv[]) {
+  PROGRAM_START(argc, argv);
+
   unsigned numForwardedArgs = argc
       - 1  // we drop argv[0]
       + 1; // -interpret
diff --git a/tools/swift-syntax-test/swift-syntax-test.cpp b/tools/swift-syntax-test/swift-syntax-test.cpp
index b075dc6..f4d00a9 100644
--- a/tools/swift-syntax-test/swift-syntax-test.cpp
+++ b/tools/swift-syntax-test/swift-syntax-test.cpp
@@ -21,6 +21,7 @@
 #include "swift/AST/DiagnosticEngine.h"
 #include "swift/AST/DiagnosticsFrontend.h"
 #include "swift/Basic/LangOptions.h"
+#include "swift/Basic/LLVMInitialize.h"
 #include "swift/Basic/SourceManager.h"
 #include "swift/Frontend/Frontend.h"
 #include "swift/Frontend/PrintingDiagnosticConsumer.h"
@@ -281,6 +282,7 @@
 }// end of anonymous namespace
 
 int main(int argc, char *argv[]) {
+  PROGRAM_START(argc, argv);
   llvm::cl::ParseCommandLineOptions(argc, argv, "Swift Syntax Test\n");
 
   int ExitCode = EXIT_SUCCESS;
diff --git a/utils/build-script-impl b/utils/build-script-impl
index d9ba30d..9d1fb48 100755
--- a/utils/build-script-impl
+++ b/utils/build-script-impl
@@ -2011,10 +2011,10 @@
                         -DSWIFT_ANDROID_NDK_PATH:STRING="${ANDROID_NDK}"
                         -DSWIFT_ANDROID_NDK_GCC_VERSION:STRING="${ANDROID_NDK_GCC_VERSION}"
                         -DSWIFT_ANDROID_SDK_PATH:STRING="${ANDROID_NDK}/platforms/android-${ANDROID_API_LEVEL}/arch-arm"
-                        -DSWIFT_ANDROID_ICU_UC:STRING="${ANDROID_ICU_UC}"
-                        -DSWIFT_ANDROID_ICU_UC_INCLUDE:STRING="${ANDROID_ICU_UC_INCLUDE}"
-                        -DSWIFT_ANDROID_ICU_I18N:STRING="${ANDROID_ICU_I18N}"
-                        -DSWIFT_ANDROID_ICU_I18N_INCLUDE:STRING="${ANDROID_ICU_I18N_INCLUDE}"
+                        -DSWIFT_ANDROID_${HOST}_ICU_UC:STRING="${ANDROID_ICU_UC}"
+                        -DSWIFT_ANDROID_${HOST}_ICU_UC_INCLUDE:STRING="${ANDROID_ICU_UC_INCLUDE}"
+                        -DSWIFT_ANDROID_${HOST}_ICU_I18N:STRING="${ANDROID_ICU_I18N}"
+                        -DSWIFT_ANDROID_${HOST}_ICU_I18N_INCLUDE:STRING="${ANDROID_ICU_I18N_INCLUDE}"
                         -DSWIFT_ANDROID_DEPLOY_DEVICE_PATH:STRING="${ANDROID_DEPLOY_DEVICE_PATH}"
                     )
                 fi
@@ -2557,9 +2557,9 @@
                 export PKG_CONFIG_PATH="${ICU_TMPLIBDIR}/pkgconfig"
                 swift_cmake_options=(
                     "${swift_cmake_options[@]}"
-                    -DSWIFT_${SWIFT_HOST_VARIANT_SDK}_ICU_UC_INCLUDE:STRING="${ICU_TMPINSTALL}/include"
-                    -DSWIFT_${SWIFT_HOST_VARIANT_SDK}_ICU_I18N_INCLUDE:STRING="${ICU_TMPINSTALL}/include"
-                    -DSWIFT_${SWIFT_HOST_VARIANT_SDK}_ICU_STATICLIB:BOOL=TRUE
+                    -DSWIFT_${SWIFT_HOST_VARIANT_SDK}_${SWIFT_HOST_VARIANT_ARCH}_ICU_UC_INCLUDE:STRING="${ICU_TMPINSTALL}/include"
+                    -DSWIFT_${SWIFT_HOST_VARIANT_SDK}_${SWIFT_HOST_VARIANT_ARCH}_ICU_I18N_INCLUDE:STRING="${ICU_TMPINSTALL}/include"
+                    -DSWIFT_${SWIFT_HOST_VARIANT_SDK}_${SWIFT_HOST_VARIANT_ARCH}_ICU_STATICLIB:BOOL=TRUE
                 )
                 # libicu builds itself and doesn't use cmake
                 continue
diff --git a/validation-test/stdlib/String.swift b/validation-test/stdlib/String.swift
index 7d8885e..2047e64 100644
--- a/validation-test/stdlib/String.swift
+++ b/validation-test/stdlib/String.swift
@@ -2011,6 +2011,7 @@
     "a\u{fa1}\u{fb7}\u{fa1}\u{fb7}a\u{fa1}\u{fb7}\u{fa1}\u{fb7}\u{fa1}\u{fb7}\u{fa1}\u{fb7}\u{fa1}\u{fb7}\u{fa1}\u{fb7}"
     ], .equal),
 
+  ComparisonTestCase(["a\u{301}\u{0301}", "\u{e1}"], .greater),
   ComparisonTestCase(["😀", "😀"], .equal),
   ComparisonTestCase(["\u{2f9df}", "\u{8f38}"], .equal),
   ComparisonTestCase([