Merge pull request #11465 from KingOfBrian/bugfix/SR-964

Warn if the getter is used, but the setter argument is not used
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 22fb3fb..cf1242a 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -66,7 +66,11 @@
 endif()
 
 option(SWIFT_BUILD_PERF_TESTSUITE
-    "Create targets for swift performance benchmarks."
+    "Create in-tree targets for building swift performance benchmarks."
+    FALSE)
+
+option(SWIFT_BUILD_EXTERNAL_PERF_TESTSUITE
+    "Create out-of-tree targets for building swift performance benchmarks."
     FALSE)
 
 option(SWIFT_INCLUDE_TESTS "Create targets for building/running tests." TRUE)
@@ -869,22 +873,54 @@
 endif()
 
 # Add all of the subdirectories, where we actually do work.
+
+###############
+# PLEASE READ #
+###############
+#
+# We have to include stdlib/ before tools/.
+# Do not move add_subdirectory(stdlib) after add_subdirectory(tools)!                                             
+#
+# We must include stdlib/ before tools/ because stdlib/CMakeLists.txt
+# declares the swift-stdlib-* set of targets. These targets will then
+# implicitly depend on any targets declared with IS_STDLIB or
+# TARGET_LIBRARY.
+#
+# One such library that declares IS_STDLIB is SwiftSyntax, living in
+# tools/SwiftSyntax. If we include stdlib/ after tools/,
+# the swift-stdlib-* set of targets will not have been generated yet,
+# causing the implicit dependency for SwiftSyntax to silently not be
+# created. This then will cause SwiftSyntax to fail to build.
+#
+# https://bugs.swift.org/browse/SR-5975
+add_subdirectory(stdlib)
+
 if(SWIFT_INCLUDE_TOOLS)
   add_subdirectory(include)
   add_subdirectory(lib)
+  
+  # Always include this after including stdlib/!
+  # Refer to the large comment above the add_subdirectory(stdlib) call.
+  # https://bugs.swift.org/browse/SR-5975
   add_subdirectory(tools)
 endif()
 
 add_subdirectory(utils)
-add_subdirectory(stdlib)
 
 if(SWIFT_BUILD_DYNAMIC_STDLIB AND SWIFT_INCLUDE_TESTS)
   add_subdirectory(tools/swift-reflection-test)
 endif()
 
-if(SWIFT_BUILD_PERF_TESTSUITE AND "${CMAKE_SYSTEM_NAME}" STREQUAL "Darwin")
-  add_subdirectory(benchmark)
+if ("${CMAKE_SYSTEM_NAME}" STREQUAL "Darwin")
+  if(SWIFT_BUILD_PERF_TESTSUITE)
+    add_subdirectory(benchmark)
+  endif()
+  if(SWIFT_BUILD_EXTERNAL_PERF_TESTSUITE)
+    include(SwiftExternalBenchmarkBuild)
+    add_external_benchmark_suite()
+  endif()
 endif()
+
 if(SWIFT_INCLUDE_TESTS)
   add_subdirectory(test)
   add_subdirectory(unittests)
diff --git a/benchmark/CMakeLists.txt b/benchmark/CMakeLists.txt
index 8012413..fe92ab2 100644
--- a/benchmark/CMakeLists.txt
+++ b/benchmark/CMakeLists.txt
@@ -125,9 +125,16 @@
     single-source/XorLoop
 )
 
-set(SWIFT_MULTISOURCE_BENCHES
+set(SWIFT_MULTISOURCE_SWIFT3_BENCHES
+  multi-source/PrimsSplit
 )
 
+set(PrimsSplit_sources
+    multi-source/PrimsSplit/Prims.swift
+    multi-source/PrimsSplit/main.swift)
+
+set(SWIFT_MULTISOURCE_SWIFT4_BENCHES
+)
 
 set(BENCH_DRIVER_LIBRARY_FLAGS)
 if (SWIFT_RUNTIME_ENABLE_LEAK_CHECKER)
@@ -231,6 +238,7 @@
 
 message("--")
 message("-- Swift Benchmark Suite:")
+message("--   SWIFT_BENCHMARK_BUILT_STANDALONE = ${SWIFT_BENCHMARK_BUILT_STANDALONE}")
 message("--   SWIFT_EXEC = ${SWIFT_EXEC}")
 message("--   SWIFT_LIBRARY_PATH = ${SWIFT_LIBRARY_PATH}")
 message("--   CLANG_EXEC = ${CLANG_EXEC}")
diff --git a/benchmark/cmake/modules/AddSwiftBenchmarkSuite.cmake b/benchmark/cmake/modules/AddSwiftBenchmarkSuite.cmake
index 3a0c547..e56b583 100644
--- a/benchmark/cmake/modules/AddSwiftBenchmarkSuite.cmake
+++ b/benchmark/cmake/modules/AddSwiftBenchmarkSuite.cmake
@@ -1,5 +1,6 @@
 
 include(CMakeParseArguments)
+include(SwiftBenchmarkUtils)
 
 # Run a shell command and assign output to a variable or fail with an error.
 # Example usage:
@@ -20,7 +21,7 @@
 endfunction(runcmd)
 
 function (add_swift_benchmark_library objfile_out sibfile_out)
-  cmake_parse_arguments(BENCHLIB "" "MODULE_PATH;SOURCE_DIR;OBJECT_DIR" "SOURCES;LIBRARY_FLAGS" ${ARGN})
+  cmake_parse_arguments(BENCHLIB "" "MODULE_PATH;SOURCE_DIR;OBJECT_DIR" "SOURCES;LIBRARY_FLAGS;DEPENDS" ${ARGN})
 
   precondition(BENCHLIB_MODULE_PATH)
   precondition(BENCHLIB_SOURCE_DIR)
@@ -39,7 +40,7 @@
   precondition(objfile_out)
   add_custom_command(
     OUTPUT "${objfile}"
-    DEPENDS ${stdlib_dependencies} ${sources}
+    DEPENDS ${stdlib_dependencies} ${sources} ${BENCHLIB_DEPENDS}
     COMMAND "${SWIFT_EXEC}"
       ${BENCHLIB_LIBRARY_FLAGS}
       "-force-single-frontend-invocation"
@@ -58,7 +59,7 @@
     add_custom_command(
       OUTPUT "${sibfile}"
       DEPENDS
-      ${stdlib_dependencies} ${sources}
+      ${stdlib_dependencies} ${sources} ${BENCHLIB_DEPENDS}
       COMMAND "${SWIFT_EXEC}"
         ${BENCHLIB_LIBRARY_FLAGS}
         "-force-single-frontend-invocation"
@@ -72,6 +73,104 @@
   endif()
 endfunction()
 
+function(_construct_sources_for_multibench sources_out objfile_out)
+  cmake_parse_arguments(SOURCEJSONLIST "" "" "SOURCES" ${ARGN})
+
+  set(sources)
+  set(objfiles)
+
+  foreach(source ${SOURCEJSONLIST_SOURCES})
+    list(APPEND sources "${srcdir}/${source}")
+
+    get_filename_component(basename "${source}" NAME_WE)
+    set(objfile "${objdir}/${module_name}/${basename}.o")
+
+    string(CONCAT json "${json}"
+      "  \"${srcdir}/${source}\": { \"object\": \"${objfile}\" },\n")
+
+    list(APPEND objfiles "${objfile}")
+  endforeach()
+  string(CONCAT json "${json}" "}")
+  file(WRITE "${objdir}/${module_name}/outputmap.json" ${json})
+  set(${sources_out} ${sources} PARENT_SCOPE)
+  set(${objfile_out} ${objfiles} PARENT_SCOPE)
+endfunction()
+
+# Regular whole-module-compilation: only a single object file is
+# generated.
+function (add_swift_multisource_wmo_benchmark_library objfile_out)
+  cmake_parse_arguments(BENCHLIB "" "MODULE_PATH;SOURCE_DIR;OBJECT_DIR" "SOURCES;LIBRARY_FLAGS;DEPENDS" ${ARGN})
+
+  precondition(BENCHLIB_MODULE_PATH)
+  precondition(BENCHLIB_SOURCE_DIR)
+  precondition(BENCHLIB_OBJECT_DIR)
+  precondition(BENCHLIB_SOURCES)
+
+  set(module_name_path "${BENCHLIB_MODULE_PATH}")
+  get_filename_component(module_name "${module_name_path}" NAME)
+  set(srcdir "${BENCHLIB_SOURCE_DIR}")
+  set(objdir "${BENCHLIB_OBJECT_DIR}")
+
+  set(objfile "${objdir}/${module_name}.o")
+
+  set(sources)
+  foreach(source ${BENCHLIB_SOURCES})
+    list(APPEND sources "${srcdir}/${source}")
+  endforeach()
+
+  add_custom_command(
+    OUTPUT "${objfile}"
+    DEPENDS
+      ${sources} ${BENCHLIB_DEPENDS}
+    COMMAND "${SWIFT_EXEC}"
+      ${BENCHLIB_LIBRARY_FLAGS}
+      "-parse-as-library"
+      "-emit-module" "-module-name" "${module_name}"
+      "-I" "${objdir}"
+      "-o" "${objfile}"
+      ${sources})
+
+  set(${objfile_out} "${objfile}" PARENT_SCOPE)
+endfunction()
+
+function(add_swift_multisource_nonwmo_benchmark_library objfiles_out)
+  cmake_parse_arguments(BENCHLIB "" "MODULE_PATH;SOURCE_DIR;OBJECT_DIR" "SOURCES;LIBRARY_FLAGS;DEPENDS" ${ARGN})
+
+  precondition(BENCHLIB_MODULE_PATH)
+  precondition(BENCHLIB_SOURCE_DIR)
+  precondition(BENCHLIB_OBJECT_DIR)
+  precondition(BENCHLIB_SOURCES)
+
+  set(module_name_path "${BENCHLIB_MODULE_PATH}")
+  get_filename_component(module_name "${module_name_path}" NAME)
+  set(srcdir "${BENCHLIB_SOURCE_DIR}")
+  set(objdir "${BENCHLIB_OBJECT_DIR}")
+
+  set(objfile "${objdir}/${module_name}.o")
+
+  # No whole-module-compilation or multi-threaded compilation.
+  # There is an output object file for each input file. We have to write
+  # an output-map-file to specify the output object file names.
+  set(sources)
+  set(objfiles)
+  _construct_sources_for_multibench(sources objfiles
+    SOURCES ${BENCHLIB_SOURCES})
+
+  add_custom_command(
+    OUTPUT ${objfiles}
+    DEPENDS ${sources} ${BENCHLIB_DEPENDS}
+    COMMAND "${SWIFT_EXEC}"
+      ${BENCHLIB_LIBRARY_FLAGS}
+      "-parse-as-library"
+      "-emit-module-path" "${objdir}/${module_name}.swiftmodule"
+      "-module-name" "${module_name}"
+      "-I" "${objdir}"
+      "-output-file-map" "${objdir}/${module_name}/outputmap.json"
+      ${sources})
+
+  set(${objfiles_out} ${objfiles} PARENT_SCOPE)
+endfunction()
+
 function (swift_benchmark_compile_archopts)
   cmake_parse_arguments(BENCH_COMPILE_ARCHOPTS "" "PLATFORM;ARCH;OPT" "" ${ARGN})
   set(sdk ${${BENCH_COMPILE_ARCHOPTS_PLATFORM}_sdk})
@@ -94,7 +193,6 @@
   set(bench_flags "${${benchvar}}")
 
   set(common_options
-      "-swift-version" "3" # FIXME: Force Swift 3 version compatibility.
       "-c"
       "-sdk" "${sdk}"
       "-target" "${target}"
@@ -102,6 +200,8 @@
       "-${BENCH_COMPILE_ARCHOPTS_OPT}"
       "-no-link-objc-runtime"
       "-I" "${srcdir}/utils/ObjectiveCTests")
+  set(common_swift3_options ${common_options} "-swift-version" "3")
+  set(common_swift4_options ${common_options} "-swift-version" "4")
 
   # Always optimize the driver modules.
   # Note that we compile the driver for Ounchecked also with -Ounchecked
@@ -120,89 +220,47 @@
   set(bench_library_sibfiles)
   # Build libraries used by the driver and benchmarks.
   foreach(module_name_path ${BENCH_LIBRARY_MODULES})
-    get_filename_component(module_name "${module_name_path}" NAME)
+    set(sources "${srcdir}/${module_name_path}.swift")
 
-    set(objfile "${objdir}/${module_name}.o")
-    set(swiftmodule "${objdir}/${module_name}.swiftmodule")
-    set(source "${srcdir}/${module_name_path}.swift")
-    list(APPEND bench_library_objects "${objfile}")
-    add_custom_command(
-        OUTPUT "${objfile}"
-        DEPENDS
-          ${stdlib_dependencies} "${source}" ${extra_sources}
-        COMMAND "${SWIFT_EXEC}"
-        ${common_options}
-        "-force-single-frontend-invocation"
-        "-parse-as-library"
-        "-module-name" "${module_name}"
-        "-emit-module" "-emit-module-path" "${swiftmodule}"
-        "-o" "${objfile}"
-        "${source}" ${extra_sources})
+    add_swift_benchmark_library(objfile_out sibfile_out
+      MODULE_PATH "${module_name_path}"
+      SOURCE_DIR "${srcdir}"
+      OBJECT_DIR "${objdir}"
+      SOURCES ${sources}
+      LIBRARY_FLAGS ${common_swift3_options})
+    precondition(objfile_out)
+    list(APPEND bench_library_objects "${objfile_out}")
     if (SWIFT_BENCHMARK_EMIT_SIB)
-      set(sibfile "${objdir}/${module_name}.sib")
-      list(APPEND bench_library_sibfiles "${sibfile}")
-      add_custom_command(
-          OUTPUT "${sibfile}"
-          DEPENDS
-            ${stdlib_dependencies} "${srcdir}/${module_name_path}.swift"
-            ${extra_sources}
-          COMMAND "${SWIFT_EXEC}"
-          ${common_options}
-          "-force-single-frontend-invocation"
-          "-parse-as-library"
-          "-module-name" "${module_name}"
-          "-emit-sib"
-          "-o" "${sibfile}"
-          "${source}" ${extra_sources})
+      precondition(sibfile_out)
+      list(APPEND bench_library_sibfiles "${sibfile_out}")
     endif()
   endforeach()
+  precondition(bench_library_objects)
 
   set(bench_driver_objects)
   set(bench_driver_sibfiles)
   foreach(module_name_path ${BENCH_DRIVER_LIBRARY_MODULES})
-    get_filename_component(module_name "${module_name_path}" NAME)
+    set(sources "${srcdir}/${module_name_path}.swift")
 
+    get_filename_component(module_name "${module_name_path}" NAME)
     if("${module_name}" STREQUAL "DriverUtils")
-      set(extra_sources "${srcdir}/utils/ArgParse.swift")
+      list(APPEND sources "${srcdir}/utils/ArgParse.swift")
     endif()
 
-    set(objfile "${objdir}/${module_name}.o")
-    set(swiftmodule "${objdir}/${module_name}.swiftmodule")
-    list(APPEND bench_driver_objects "${objfile}")
-    set(source "${srcdir}/${module_name_path}.swift")
-    add_custom_command(
-        OUTPUT "${objfile}"
-        DEPENDS
-          ${stdlib_dependencies} ${bench_library_objects} ${source}
-          ${extra_sources}
-        COMMAND "${SWIFT_EXEC}"
-        ${common_options_driver}
-        ${BENCH_DRIVER_LIBRARY_FLAGS}
-        "-force-single-frontend-invocation"
-        "-parse-as-library"
-        "-module-name" "${module_name}"
-        "-emit-module" "-emit-module-path" "${swiftmodule}"
-        "-I" "${objdir}"
-        "-o" "${objfile}"
-        "${source}" ${extra_sources})
-    if(SWIFT_BENCHMARK_EMIT_SIB)
-      set(sibfile "${objdir}/${module_name}.sib")
-      list(APPEND bench_driver_sibfiles "${sibfile}")
-      add_custom_command(
-          OUTPUT "${sibfile}"
-          DEPENDS
-            ${stdlib_dependencies} ${bench_library_objects} ${source}
-            ${extra_sources}
-          COMMAND "${SWIFT_EXEC}"
-          ${common_options_driver}
-          ${BENCH_DRIVER_LIBRARY_FLAGS}
-          "-force-single-frontend-invocation"
-          "-parse-as-library"
-          "-module-name" "${module_name}"
-          "-emit-sib"
-          "-I" "${objdir}"
-          "-o" "${sibfile}"
-          "${source}" ${extra_sources})
+    set(objfile_out)
+    set(sibfile_out)
+    add_swift_benchmark_library(objfile_out sibfile_out
+      MODULE_PATH "${module_name_path}"
+      SOURCE_DIR "${srcdir}"
+      OBJECT_DIR "${objdir}"
+      SOURCES ${sources}
+      LIBRARY_FLAGS ${common_options_driver} ${BENCH_DRIVER_LIBRARY_FLAGS}
+      DEPENDS ${bench_library_objects})
+    precondition(objfile_out)
+    list(APPEND bench_driver_objects "${objfile_out}")
+    if (SWIFT_BENCHMARK_EMIT_SIB)
+      precondition(sibfile_out)
+      list(APPEND bench_driver_sibfiles "${sibfile_out}")
     endif()
   endforeach()
 
@@ -238,7 +296,7 @@
             ${stdlib_dependencies} ${bench_library_objects}
             "${srcdir}/${module_name_path}.swift"
           COMMAND "${SWIFT_EXEC}"
-          ${common_options}
+          ${common_swift3_options}
           ${extra_options}
           "-parse-as-library"
           ${bench_flags}
@@ -256,7 +314,7 @@
               ${stdlib_dependencies} ${bench_library_sibfiles}
               "${srcdir}/${module_name_path}.swift"
             COMMAND "${SWIFT_EXEC}"
-            ${common_options}
+            ${common_swift3_options}
             "-parse-as-library"
             ${bench_flags}
             "-module-name" "${module_name}"
@@ -268,67 +326,61 @@
     endif()
   endforeach()
 
-  foreach(module_name_path ${SWIFT_MULTISOURCE_BENCHES})
+  foreach(module_name_path ${SWIFT_MULTISOURCE_SWIFT3_BENCHES})
     get_filename_component(module_name "${module_name_path}" NAME)
 
     if ("${bench_flags}" MATCHES "-whole-module.*" AND
         NOT "${bench_flags}" MATCHES "-num-threads.*")
-      # Regular whole-module-compilation: only a single object file is
-      # generated.
-      set(objfile "${objdir}/${module_name}.o")
-      list(APPEND SWIFT_BENCH_OBJFILES "${objfile}")
-      set(sources)
-      foreach(source ${${module_name}_sources})
-        list(APPEND sources "${srcdir}/${source}")
-      endforeach()
-      add_custom_command(
-          OUTPUT "${objfile}"
-          DEPENDS
-            ${stdlib_dependencies} ${bench_library_objects} ${sources}
-          COMMAND "${SWIFT_EXEC}"
-          ${common_options}
-          ${bench_flags}
-          "-parse-as-library"
-          "-emit-module" "-module-name" "${module_name}"
-          "-I" "${objdir}"
-          "-o" "${objfile}"
-          ${sources})
+      set(objfile_out)
+      add_swift_multisource_wmo_benchmark_library(objfile_out
+        MODULE_PATH "${module_name_path}"
+        SOURCE_DIR "${srcdir}"
+        OBJECT_DIR "${objdir}"
+        SOURCES ${${module_name}_sources}
+        LIBRARY_FLAGS ${common_swift3_options} ${bench_flags}
+        DEPENDS ${bench_library_objects} ${stdlib_dependencies})
+      precondition(objfile_out)
+      list(APPEND SWIFT_BENCH_OBJFILES "${objfile_out}")
     else()
+      set(objfiles_out)
+      add_swift_multisource_nonwmo_benchmark_library(objfiles_out
+        MODULE_PATH "${module_name_path}"
+        SOURCE_DIR "${srcdir}"
+        OBJECT_DIR "${objdir}"
+        SOURCES ${${module_name}_sources}
+        LIBRARY_FLAGS ${common_swift3_options} ${bench_flags}
+        DEPENDS ${bench_library_objects} ${stdlib_dependencies})
+      precondition(objfiles_out)
+      list(APPEND SWIFT_BENCH_OBJFILES ${objfiles_out})
+    endif()
+  endforeach()
 
-      # No whole-module-compilation or multi-threaded compilation.
-      # There is an output object file for each input file. We have to write
-      # an output-map-file to specify the output object file names.
-      set(sources)
-      set(objfiles)
-      set(json "{\n")
-      foreach(source ${${module_name}_sources})
-          list(APPEND sources "${srcdir}/${source}")
+  foreach(module_name_path ${SWIFT_MULTISOURCE_SWIFT4_BENCHES})
+    get_filename_component(module_name "${module_name_path}" NAME)
 
-          get_filename_component(basename "${source}" NAME_WE)
-          set(objfile "${objdir}/${module_name}/${basename}.o")
-
-              string(CONCAT json "${json}"
-    "  \"${srcdir}/${source}\": { \"object\": \"${objfile}\" },\n")
-
-          list(APPEND objfiles "${objfile}")
-          list(APPEND SWIFT_BENCH_OBJFILES "${objfile}")
-      endforeach()
-      string(CONCAT json "${json}" "}")
-      file(WRITE "${objdir}/${module_name}/outputmap.json" ${json})
-
-      add_custom_command(
-          OUTPUT ${objfiles}
-          DEPENDS
-            ${stdlib_dependencies} ${bench_library_objects} ${sources}
-          COMMAND "${SWIFT_EXEC}"
-          ${common_options}
-          ${bench_flags}
-          "-parse-as-library"
-          "-emit-module-path" "${objdir}/${module_name}.swiftmodule"
-          "-module-name" "${module_name}"
-          "-I" "${objdir}"
-          "-output-file-map" "${objdir}/${module_name}/outputmap.json"
-          ${sources})
+    if ("${bench_flags}" MATCHES "-whole-module.*" AND
+        NOT "${bench_flags}" MATCHES "-num-threads.*")
+      set(objfile_out)
+      add_swift_multisource_wmo_benchmark_library(objfile_out
+        MODULE_PATH "${module_name_path}"
+        SOURCE_DIR "${srcdir}"
+        OBJECT_DIR "${objdir}"
+        SOURCES ${${module_name}_sources}
+        LIBRARY_FLAGS ${common_swift4_options} ${bench_flags}
+        DEPENDS ${bench_library_objects} ${stdlib_dependencies})
+      precondition(objfile_out)
+      list(APPEND SWIFT_BENCH_OBJFILES "${objfile_out}")
+    else()
+      set(objfiles_out)
+      add_swift_multisource_nonwmo_benchmark_library(objfiles_out
+        MODULE_PATH "${module_name_path}"
+        SOURCE_DIR "${srcdir}"
+        OBJECT_DIR "${objdir}"
+        SOURCES ${${module_name}_sources}
+        LIBRARY_FLAGS ${common_swift4_options} ${bench_flags}
+        DEPENDS ${bench_library_objects} ${stdlib_dependencies})
+      precondition(objfiles_out)
+      list(APPEND SWIFT_BENCH_OBJFILES ${objfiles_out})
     endif()
   endforeach()
 
@@ -342,7 +394,7 @@
         ${bench_library_sibfiles} ${bench_driver_sibfiles}
         ${SWIFT_BENCH_SIBFILES} "${source}"
       COMMAND "${SWIFT_EXEC}"
-      ${common_options}
+      ${common_swift3_options}
       "-force-single-frontend-invocation"
       "-emit-module" "-module-name" "${module_name}"
       "-I" "${objdir}"
@@ -436,7 +488,16 @@
       list(APPEND platform_executables ${new_output_exec})
     endforeach()
 
-    set(executable_target "swift-benchmark-${SWIFT_BENCHMARK_COMPILE_PLATFORM}-${arch}")
+    # If we are building standalone, we add the -external suffix to all of our
+    # cmake target names. This enables the main swift build to simple create
+    # -external targets and forward them via AddExternalProject to the
+    # standalone benchmark project. The reason why this is necessary is that we
+    # want to be able to support in-tree and out-of-tree benchmark builds at the
+    # same time implying that we need some sort of way to distinguish the
+    # in-tree (which don't have the suffix) from the out of tree target (which
+    # do).
+    translate_flag(SWIFT_BENCHMARK_BUILT_STANDALONE "-external" external)
+    set(executable_target "swift-benchmark-${SWIFT_BENCHMARK_COMPILE_PLATFORM}-${arch}${external}")
 
     add_custom_target("${executable_target}"
         DEPENDS ${platform_executables})
diff --git a/benchmark/cmake/modules/SwiftBenchmarkUtils.cmake b/benchmark/cmake/modules/SwiftBenchmarkUtils.cmake
new file mode 100644
index 0000000..9c5e6a0
--- /dev/null
+++ b/benchmark/cmake/modules/SwiftBenchmarkUtils.cmake
@@ -0,0 +1,45 @@
+
+include(CMakeParseArguments)
+
+function(precondition var)
+  cmake_parse_arguments(
+    PRECONDITION # prefix
+    "NEGATE" # options
+    "MESSAGE" # single-value args
+    "" # multi-value args
+    ${ARGN})
+
+  if (PRECONDITION_NEGATE)
+    if (${var})
+      if (PRECONDITION_MESSAGE)
+        message(FATAL_ERROR "Error! ${PRECONDITION_MESSAGE}")
+      else()
+        message(FATAL_ERROR "Error! Variable ${var} is true or not empty. The value of ${var} is ${${var}}.")
+      endif()
+    endif()
+  else()
+    if (NOT ${var})
+      if (PRECONDITION_MESSAGE)
+        message(FATAL_ERROR "Error! ${PRECONDITION_MESSAGE}")
+      else()
+        message(FATAL_ERROR "Error! Variable ${var} is false, empty or not set.")
+      endif()
+    endif()
+  endif()
+endfunction()
+
+# Translate a yes/no variable to the presence of a given string in a
+# variable.
+#
+# Usage:
+#   translate_flag(is_set flag_name var_name)
+#
+# If is_set is true, sets ${var_name} to ${flag_name}. Otherwise,
+# unsets ${var_name}.
+function(translate_flag is_set flag_name var_name)
+  if(${is_set})
+    set("${var_name}" "${flag_name}" PARENT_SCOPE)
+  else()
+    set("${var_name}" "" PARENT_SCOPE)
+  endif()
+endfunction()
diff --git a/benchmark/multi-source/PrimsSplit/Prims.swift b/benchmark/multi-source/PrimsSplit/Prims.swift
new file mode 100644
index 0000000..57d1f6d
--- /dev/null
+++ b/benchmark/multi-source/PrimsSplit/Prims.swift
@@ -0,0 +1,214 @@
+//===--- Prims.swift ------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// The test implements Prim's algorithm for minimum spanning tree building.
+// http://en.wikipedia.org/wiki/Prim%27s_algorithm
+
+// This class implements array-based heap (priority queue).
+// It is used to store edges from nodes in spanning tree to nodes outside of it.
+// We are interested only in the edges with the smallest costs, so if there are
+// several edges pointing to the same node, we keep only one from them. Thus,
+// it is enough to record this node instead.
+// We maintain a map (node index in graph)->(node index in heap) to be able to
+// update the heap fast when we add a new node to the tree.
+import TestsUtils
+
+class PriorityQueue {
+  final var heap: Array<EdgeCost>
+  final var graphIndexToHeapIndexMap: Array<Int?>
+
+  // Create heap for graph with NUM nodes.
+  init(Num: Int) {
+    heap = Array<EdgeCost>()
+    graphIndexToHeapIndexMap = Array<Int?>(repeating:nil, count: Num)
+  }
+
+  func isEmpty() -> Bool {
+    return heap.isEmpty
+  }
+
+  // Insert element N to heap, maintaining the heap property.
+  func insert(_ n: EdgeCost) {
+    let ind: Int = heap.count
+    heap.append(n)
+    graphIndexToHeapIndexMap[n.to] = heap.count - 1
+    bubbleUp(ind)
+  }
+
+  // Insert element N if in's not in the heap, or update its cost if the new
+  // value is less than the existing one.
+  func insertOrUpdate(_ n: EdgeCost) {
+    let id = n.to
+    let c  = n.cost
+    if let ind = graphIndexToHeapIndexMap[id] {
+      if heap[ind].cost <= c {
+        // We don't need an edge with a bigger cost
+        return
+      }
+      heap[ind].cost = c
+      heap[ind].from = n.from
+      bubbleUp(ind)
+    } else {
+      insert(n)
+    }
+  }
+
+  // Restore heap property by moving element at index IND up.
+  // This is needed after insertion, and after decreasing an element's cost.
+  func bubbleUp(_ ind: Int) {
+    var ind = ind
+    let c = heap[ind].cost
+    while (ind != 0) {
+      let p = getParentIndex(ind)
+      if heap[p].cost > c {
+        Swap(p, with: ind)
+        ind = p
+      } else {
+        break
+      }
+    }
+  }
+
+  // Pop minimum element from heap and restore the heap property after that.
+  func pop() -> EdgeCost? {
+    if (heap.isEmpty) {
+      return nil
+    }
+    Swap(0, with:heap.count-1)
+    let r = heap.removeLast()
+    graphIndexToHeapIndexMap[r.to] = nil
+    bubbleDown(0)
+    return r
+  }
+
+  // Restore heap property by moving element at index IND down.
+  // This is needed after removing an element, and after increasing an
+  // element's cost.
+  func bubbleDown(_ ind: Int) {
+    var ind = ind
+    let n = heap.count
+    while (ind < n) {
+      let l = getLeftChildIndex(ind)
+      let r = getRightChildIndex(ind)
+      if (l >= n) {
+        break
+      }
+      var min: Int
+      if (r < n && heap[r].cost < heap[l].cost) {
+        min = r
+      } else {
+        min = l
+      }
+      if (heap[ind].cost <= heap[min].cost) {
+        break
+      }
+      Swap(ind, with: min)
+      ind = min
+    }
+  }
+
+  // Swaps elements I and J in the heap and correspondingly updates
+  // graphIndexToHeapIndexMap.
+  func Swap(_ i: Int, with j : Int) {
+    if (i == j) {
+      return
+    }
+    (heap[i], heap[j]) = (heap[j], heap[i])
+    let (I, J) = (heap[i].to, heap[j].to)
+    (graphIndexToHeapIndexMap[I], graphIndexToHeapIndexMap[J]) =
+    (graphIndexToHeapIndexMap[J], graphIndexToHeapIndexMap[I])
+  }
+
+  // Dumps the heap.
+  func dump() {
+    print("QUEUE")
+    for nodeCost in heap {
+      let to: Int = nodeCost.to
+      let from: Int = nodeCost.from
+      let cost: Double = nodeCost.cost
+      print("(\(from)->\(to), \(cost))")
+    }
+  }
+
+  func getLeftChildIndex(_ index : Int) -> Int {
+    return index*2 + 1
+  }
+  func getRightChildIndex(_ index : Int) -> Int {
+    return (index + 1)*2
+  }
+  func getParentIndex(_ childIndex : Int) -> Int {
+    return (childIndex - 1)/2
+  }
+}
+
+struct GraphNode {
+  var id: Int
+  var adjList: Array<Int>
+
+  init(i : Int) {
+    id = i
+    adjList = Array<Int>()
+  }
+}
+
+struct EdgeCost {
+  var to: Int
+  var cost: Double
+  var from: Int
+}
+
+struct Edge : Equatable {
+  var start: Int
+  var end: Int
+}
+
+func ==(lhs: Edge, rhs: Edge) -> Bool {
+  return lhs.start == rhs.start && lhs.end == rhs.end
+}
+
+extension Edge : Hashable {
+  var hashValue: Int {
+    get {
+      return start.hashValue ^ end.hashValue
+    }
+  }
+}
+
+func Prims(_ graph : Array<GraphNode>, _ fun : (Int, Int) -> Double) -> Array<Int?> {
+  var treeEdges = Array<Int?>(repeating:nil, count:graph.count)
+
+  let queue = PriorityQueue(Num:graph.count)
+  // Make the minimum spanning tree root its own parent for simplicity.
+  queue.insert(EdgeCost(to: 0, cost: 0.0, from: 0))
+
+  // Take an element with the smallest cost from the queue and add its
+  // neighbors to the queue if their cost was updated
+  while !queue.isEmpty() {
+    // Add an edge with minimum cost to the spanning tree
+    let e = queue.pop()!
+    let newnode = e.to
+    // Add record about the edge newnode->e.from to treeEdges
+    treeEdges[newnode] = e.from
+
+    // Check all adjacent nodes and add edges, ending outside the tree, to the
+    // queue. If the queue already contains an edge to an adjacent node, we
+    // replace existing one with the new one in case the new one costs less.
+    for adjNodeIndex in graph[newnode].adjList {
+      if treeEdges[adjNodeIndex] != nil {
+        continue
+      }
+      let newcost = fun(newnode, graph[adjNodeIndex].id)
+      queue.insertOrUpdate(EdgeCost(to: adjNodeIndex, cost: newcost, from: newnode))
+    }
+  }
+  return treeEdges
+}
diff --git a/benchmark/multi-source/PrimsSplit/README.md b/benchmark/multi-source/PrimsSplit/README.md
new file mode 100644
index 0000000..9987e9c
--- /dev/null
+++ b/benchmark/multi-source/PrimsSplit/README.md
@@ -0,0 +1,4 @@
+
+This test is just a split version of Prims.swift. The reason why this is here is
+to provide at least 1 multi-source benchmark for the purpose of validating that
+the multi-source benchmarks can build successfully.
diff --git a/benchmark/multi-source/PrimsSplit/main.swift b/benchmark/multi-source/PrimsSplit/main.swift
new file mode 100644
index 0000000..0609e92
--- /dev/null
+++ b/benchmark/multi-source/PrimsSplit/main.swift
@@ -0,0 +1,555 @@
+//===--- main.swift -------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+import TestsUtils
+
+@inline(never)
+public func run_PrimsSplit(_ N: Int) {
+  for _ in 1...5*N {
+    let nodes : [Int] = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
+      13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28,
+      29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
+      45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60,
+      61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76,
+      77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92,
+      93, 94, 95, 96, 97, 98, 99 ]
+
+    // Prim's algorithm is designed for undirected graphs.
+    // Due to that, in our set all the edges are paired, i.e. for any
+    // edge (start, end, C) there is also an edge (end, start, C).
+    let edges : [(Int, Int, Double)] = [
+      (26, 47, 921),
+      (20, 25, 971),
+      (92, 59, 250),
+      (33, 55, 1391),
+      (78, 39, 313),
+      (7, 25, 637),
+      (18, 19, 1817),
+      (33, 41, 993),
+      (64, 41, 926),
+      (88, 86, 574),
+      (93, 15, 1462),
+      (86, 33, 1649),
+      (37, 35, 841),
+      (98, 51, 1160),
+      (15, 30, 1125),
+      (65, 78, 1052),
+      (58, 12, 1273),
+      (12, 17, 285),
+      (45, 61, 1608),
+      (75, 53, 545),
+      (99, 48, 410),
+      (97, 0, 1303),
+      (48, 17, 1807),
+      (1, 54, 1491),
+      (15, 34, 807),
+      (94, 98, 646),
+      (12, 69, 136),
+      (65, 11, 983),
+      (63, 83, 1604),
+      (78, 89, 1828),
+      (61, 63, 845),
+      (18, 36, 1626),
+      (68, 52, 1324),
+      (14, 50, 690),
+      (3, 11, 943),
+      (21, 68, 914),
+      (19, 44, 1762),
+      (85, 80, 270),
+      (59, 92, 250),
+      (86, 84, 1431),
+      (19, 18, 1817),
+      (52, 68, 1324),
+      (16, 29, 1108),
+      (36, 80, 395),
+      (67, 18, 803),
+      (63, 88, 1717),
+      (68, 21, 914),
+      (75, 82, 306),
+      (49, 82, 1292),
+      (73, 45, 1876),
+      (89, 82, 409),
+      (45, 47, 272),
+      (22, 83, 597),
+      (61, 12, 1791),
+      (44, 68, 1229),
+      (50, 51, 917),
+      (14, 53, 355),
+      (77, 41, 138),
+      (54, 21, 1870),
+      (93, 70, 1582),
+      (76, 2, 1658),
+      (83, 73, 1162),
+      (6, 1, 482),
+      (11, 65, 983),
+      (81, 90, 1024),
+      (19, 1, 970),
+      (8, 58, 1131),
+      (60, 42, 477),
+      (86, 29, 258),
+      (69, 59, 903),
+      (34, 15, 807),
+      (37, 2, 1451),
+      (7, 73, 754),
+      (47, 86, 184),
+      (67, 17, 449),
+      (18, 67, 803),
+      (25, 4, 595),
+      (3, 31, 1337),
+      (64, 31, 1928),
+      (9, 43, 237),
+      (83, 63, 1604),
+      (47, 45, 272),
+      (86, 88, 574),
+      (87, 74, 934),
+      (98, 94, 646),
+      (20, 1, 642),
+      (26, 92, 1344),
+      (18, 17, 565),
+      (47, 11, 595),
+      (10, 59, 1558),
+      (2, 76, 1658),
+      (77, 74, 1277),
+      (42, 60, 477),
+      (80, 36, 395),
+      (35, 23, 589),
+      (50, 37, 203),
+      (6, 96, 481),
+      (78, 65, 1052),
+      (1, 52, 127),
+      (65, 23, 1932),
+      (46, 51, 213),
+      (59, 89, 89),
+      (15, 93, 1462),
+      (69, 3, 1305),
+      (17, 37, 1177),
+      (30, 3, 193),
+      (9, 15, 818),
+      (75, 95, 977),
+      (86, 47, 184),
+      (10, 12, 1736),
+      (80, 27, 1010),
+      (12, 10, 1736),
+      (86, 1, 1958),
+      (60, 12, 1240),
+      (43, 71, 683),
+      (91, 65, 1519),
+      (33, 86, 1649),
+      (62, 26, 1773),
+      (1, 13, 1187),
+      (2, 10, 1018),
+      (91, 29, 351),
+      (69, 12, 136),
+      (43, 9, 237),
+      (29, 86, 258),
+      (17, 48, 1807),
+      (31, 64, 1928),
+      (68, 61, 1936),
+      (76, 38, 1724),
+      (1, 6, 482),
+      (53, 14, 355),
+      (51, 50, 917),
+      (54, 13, 815),
+      (19, 29, 883),
+      (35, 87, 974),
+      (70, 96, 511),
+      (23, 35, 589),
+      (39, 69, 1588),
+      (93, 73, 1093),
+      (13, 73, 435),
+      (5, 60, 1619),
+      (42, 41, 1523),
+      (66, 58, 1596),
+      (1, 67, 431),
+      (17, 67, 449),
+      (30, 95, 906),
+      (71, 43, 683),
+      (5, 87, 190),
+      (12, 78, 891),
+      (30, 97, 402),
+      (28, 17, 1131),
+      (7, 97, 1356),
+      (58, 66, 1596),
+      (20, 37, 1294),
+      (73, 76, 514),
+      (54, 8, 613),
+      (68, 35, 1252),
+      (92, 32, 701),
+      (3, 90, 652),
+      (99, 46, 1576),
+      (13, 54, 815),
+      (20, 87, 1390),
+      (36, 18, 1626),
+      (51, 26, 1146),
+      (2, 23, 581),
+      (29, 7, 1558),
+      (88, 59, 173),
+      (17, 1, 1071),
+      (37, 49, 1011),
+      (18, 6, 696),
+      (88, 33, 225),
+      (58, 38, 802),
+      (87, 50, 1744),
+      (29, 91, 351),
+      (6, 71, 1053),
+      (45, 24, 1720),
+      (65, 91, 1519),
+      (37, 50, 203),
+      (11, 3, 943),
+      (72, 65, 1330),
+      (45, 50, 339),
+      (25, 20, 971),
+      (15, 9, 818),
+      (14, 54, 1353),
+      (69, 95, 393),
+      (8, 66, 1213),
+      (52, 2, 1608),
+      (50, 14, 690),
+      (50, 45, 339),
+      (1, 37, 1273),
+      (45, 93, 1650),
+      (39, 78, 313),
+      (1, 86, 1958),
+      (17, 28, 1131),
+      (35, 33, 1667),
+      (23, 2, 581),
+      (51, 66, 245),
+      (17, 54, 924),
+      (41, 49, 1629),
+      (60, 5, 1619),
+      (56, 93, 1110),
+      (96, 13, 461),
+      (25, 7, 637),
+      (11, 69, 370),
+      (90, 3, 652),
+      (39, 71, 1485),
+      (65, 51, 1529),
+      (20, 6, 1414),
+      (80, 85, 270),
+      (73, 83, 1162),
+      (0, 97, 1303),
+      (13, 33, 826),
+      (29, 71, 1788),
+      (33, 12, 461),
+      (12, 58, 1273),
+      (69, 39, 1588),
+      (67, 75, 1504),
+      (87, 20, 1390),
+      (88, 97, 526),
+      (33, 88, 225),
+      (95, 69, 393),
+      (2, 52, 1608),
+      (5, 25, 719),
+      (34, 78, 510),
+      (53, 99, 1074),
+      (33, 35, 1667),
+      (57, 30, 361),
+      (87, 58, 1574),
+      (13, 90, 1030),
+      (79, 74, 91),
+      (4, 86, 1107),
+      (64, 94, 1609),
+      (11, 12, 167),
+      (30, 45, 272),
+      (47, 91, 561),
+      (37, 17, 1177),
+      (77, 49, 883),
+      (88, 23, 1747),
+      (70, 80, 995),
+      (62, 77, 907),
+      (18, 4, 371),
+      (73, 93, 1093),
+      (11, 47, 595),
+      (44, 23, 1990),
+      (20, 0, 512),
+      (3, 69, 1305),
+      (82, 3, 1815),
+      (20, 88, 368),
+      (44, 45, 364),
+      (26, 51, 1146),
+      (7, 65, 349),
+      (71, 39, 1485),
+      (56, 88, 1954),
+      (94, 69, 1397),
+      (12, 28, 544),
+      (95, 75, 977),
+      (32, 90, 789),
+      (53, 1, 772),
+      (54, 14, 1353),
+      (49, 77, 883),
+      (92, 26, 1344),
+      (17, 18, 565),
+      (97, 88, 526),
+      (48, 80, 1203),
+      (90, 32, 789),
+      (71, 6, 1053),
+      (87, 35, 974),
+      (55, 90, 1808),
+      (12, 61, 1791),
+      (1, 96, 328),
+      (63, 10, 1681),
+      (76, 34, 871),
+      (41, 64, 926),
+      (42, 97, 482),
+      (25, 5, 719),
+      (23, 65, 1932),
+      (54, 1, 1491),
+      (28, 12, 544),
+      (89, 10, 108),
+      (27, 33, 143),
+      (67, 1, 431),
+      (32, 45, 52),
+      (79, 33, 1871),
+      (6, 55, 717),
+      (10, 58, 459),
+      (67, 39, 393),
+      (10, 4, 1808),
+      (96, 6, 481),
+      (1, 19, 970),
+      (97, 7, 1356),
+      (29, 16, 1108),
+      (1, 53, 772),
+      (30, 15, 1125),
+      (4, 6, 634),
+      (6, 20, 1414),
+      (88, 56, 1954),
+      (87, 64, 1950),
+      (34, 76, 871),
+      (17, 12, 285),
+      (55, 59, 321),
+      (61, 68, 1936),
+      (50, 87, 1744),
+      (84, 44, 952),
+      (41, 33, 993),
+      (59, 18, 1352),
+      (33, 27, 143),
+      (38, 32, 1210),
+      (55, 70, 1264),
+      (38, 58, 802),
+      (1, 20, 642),
+      (73, 13, 435),
+      (80, 48, 1203),
+      (94, 64, 1609),
+      (38, 28, 414),
+      (73, 23, 1113),
+      (78, 12, 891),
+      (26, 62, 1773),
+      (87, 43, 579),
+      (53, 6, 95),
+      (59, 95, 285),
+      (88, 63, 1717),
+      (17, 5, 633),
+      (66, 8, 1213),
+      (41, 42, 1523),
+      (83, 22, 597),
+      (95, 30, 906),
+      (51, 65, 1529),
+      (17, 49, 1727),
+      (64, 87, 1950),
+      (86, 4, 1107),
+      (37, 98, 1102),
+      (32, 92, 701),
+      (60, 94, 198),
+      (73, 98, 1749),
+      (4, 18, 371),
+      (96, 70, 511),
+      (7, 29, 1558),
+      (35, 37, 841),
+      (27, 64, 384),
+      (12, 33, 461),
+      (36, 38, 529),
+      (69, 16, 1183),
+      (91, 47, 561),
+      (85, 29, 1676),
+      (3, 82, 1815),
+      (69, 58, 1579),
+      (93, 45, 1650),
+      (97, 42, 482),
+      (37, 1, 1273),
+      (61, 4, 543),
+      (96, 1, 328),
+      (26, 0, 1993),
+      (70, 64, 878),
+      (3, 30, 193),
+      (58, 69, 1579),
+      (4, 25, 595),
+      (31, 3, 1337),
+      (55, 6, 717),
+      (39, 67, 393),
+      (78, 34, 510),
+      (75, 67, 1504),
+      (6, 53, 95),
+      (51, 79, 175),
+      (28, 91, 1040),
+      (89, 78, 1828),
+      (74, 93, 1587),
+      (45, 32, 52),
+      (10, 2, 1018),
+      (49, 37, 1011),
+      (63, 61, 845),
+      (0, 20, 512),
+      (1, 17, 1071),
+      (99, 53, 1074),
+      (37, 20, 1294),
+      (10, 89, 108),
+      (33, 92, 946),
+      (23, 73, 1113),
+      (23, 88, 1747),
+      (49, 17, 1727),
+      (88, 20, 368),
+      (21, 54, 1870),
+      (70, 93, 1582),
+      (59, 88, 173),
+      (32, 38, 1210),
+      (89, 59, 89),
+      (23, 44, 1990),
+      (38, 76, 1724),
+      (30, 57, 361),
+      (94, 60, 198),
+      (59, 10, 1558),
+      (55, 64, 1996),
+      (12, 11, 167),
+      (36, 24, 1801),
+      (97, 30, 402),
+      (52, 1, 127),
+      (58, 87, 1574),
+      (54, 17, 924),
+      (93, 74, 1587),
+      (24, 36, 1801),
+      (2, 37, 1451),
+      (91, 28, 1040),
+      (59, 55, 321),
+      (69, 11, 370),
+      (8, 54, 613),
+      (29, 85, 1676),
+      (44, 19, 1762),
+      (74, 79, 91),
+      (93, 56, 1110),
+      (58, 10, 459),
+      (41, 50, 1559),
+      (66, 51, 245),
+      (80, 19, 1838),
+      (33, 79, 1871),
+      (76, 73, 514),
+      (98, 37, 1102),
+      (45, 44, 364),
+      (16, 69, 1183),
+      (49, 41, 1629),
+      (19, 80, 1838),
+      (71, 57, 500),
+      (6, 4, 634),
+      (64, 27, 384),
+      (84, 86, 1431),
+      (5, 17, 633),
+      (96, 88, 334),
+      (87, 5, 190),
+      (70, 21, 1619),
+      (55, 33, 1391),
+      (10, 63, 1681),
+      (11, 62, 1339),
+      (33, 13, 826),
+      (64, 70, 878),
+      (65, 72, 1330),
+      (70, 55, 1264),
+      (64, 55, 1996),
+      (50, 41, 1559),
+      (46, 99, 1576),
+      (88, 96, 334),
+      (51, 20, 868),
+      (73, 7, 754),
+      (80, 70, 995),
+      (44, 84, 952),
+      (29, 19, 883),
+      (59, 69, 903),
+      (57, 53, 1575),
+      (90, 13, 1030),
+      (28, 38, 414),
+      (12, 60, 1240),
+      (85, 58, 573),
+      (90, 55, 1808),
+      (4, 10, 1808),
+      (68, 44, 1229),
+      (92, 33, 946),
+      (90, 81, 1024),
+      (53, 75, 545),
+      (45, 30, 272),
+      (41, 77, 138),
+      (21, 70, 1619),
+      (45, 73, 1876),
+      (35, 68, 1252),
+      (13, 96, 461),
+      (53, 57, 1575),
+      (82, 89, 409),
+      (28, 61, 449),
+      (58, 61, 78),
+      (27, 80, 1010),
+      (61, 58, 78),
+      (38, 36, 529),
+      (80, 30, 397),
+      (18, 59, 1352),
+      (62, 11, 1339),
+      (95, 59, 285),
+      (51, 98, 1160),
+      (6, 18, 696),
+      (30, 80, 397),
+      (69, 94, 1397),
+      (58, 85, 573),
+      (48, 99, 410),
+      (51, 46, 213),
+      (57, 71, 500),
+      (91, 30, 104),
+      (65, 7, 349),
+      (79, 51, 175),
+      (47, 26, 921),
+      (4, 61, 543),
+      (98, 73, 1749),
+      (74, 77, 1277),
+      (61, 28, 449),
+      (58, 8, 1131),
+      (61, 45, 1608),
+      (74, 87, 934),
+      (71, 29, 1788),
+      (30, 91, 104),
+      (13, 1, 1187),
+      (0, 26, 1993),
+      (82, 49, 1292),
+      (43, 87, 579),
+      (24, 45, 1720),
+      (20, 51, 868),
+      (77, 62, 907),
+      (82, 75, 306),
+    ]
+
+    // Prepare graph and edge->cost map
+    var graph = Array<GraphNode>()
+    for n in nodes {
+      graph.append(GraphNode(i: n))
+    }
+    var map = Dictionary<Edge, Double>()
+    for tup in edges {
+      map[Edge(start: tup.0, end: tup.1)] = tup.2
+      graph[tup.0].adjList.append(tup.1)
+    }
+
+    // Find spanning tree
+    let treeEdges = Prims(graph, { (start: Int, end: Int) in
+        return map[Edge(start: start, end: end)]!
+    })
+
+    // Compute its cost in order to check results
+    var cost = 0.0
+    for i in 1..<treeEdges.count {
+      if let n = treeEdges[i] { cost += map[Edge(start: n, end: i)]! }
+    }
+    CheckResults(Int(cost) == 49324)
+  }
+}
diff --git a/benchmark/utils/DriverUtils.swift b/benchmark/utils/DriverUtils.swift
index 103529b..f0eba2d 100644
--- a/benchmark/utils/DriverUtils.swift
+++ b/benchmark/utils/DriverUtils.swift
@@ -26,7 +26,9 @@
   var mean: UInt64 = 0
   var sd: UInt64 = 0
   var median: UInt64 = 0
+
   init() {}
+
   init(delim: String, sampleCount: UInt64, min: UInt64, max: UInt64, mean: UInt64, sd: UInt64, median: UInt64) {
     self.delim = delim
     self.sampleCount = sampleCount
@@ -56,21 +58,21 @@
   let index: Int
   let f: (Int) -> ()
   let run: Bool
-  let tags: [BenchmarkCategories]
+  let tags: [BenchmarkCategory]
 }
 
 // Legacy test dictionaries.
-public var precommitTests: [String : ((Int) -> (), [BenchmarkCategories])] = [:]
-public var otherTests: [String : ((Int) -> (), [BenchmarkCategories])] = [:]
-public var stringTests: [String : ((Int) -> (), [BenchmarkCategories])] = [:]
+public var precommitTests: [String : ((Int) -> (), [BenchmarkCategory])] = [:]
+public var otherTests: [String : ((Int) -> (), [BenchmarkCategory])] = [:]
+public var stringTests: [String : ((Int) -> (), [BenchmarkCategory])] = [:]
 
 // We should migrate to a collection of BenchmarkInfo.
 public var registeredBenchmarks = [TestsUtils.BenchmarkInfo]()
 
 enum TestAction {
-  case Run
-  case ListTests
-  case Fail(String)
+  case run
+  case listTests
+  case fail(String)
 }
 
 struct TestConfig {
@@ -81,7 +83,7 @@
   var filters = [String]()
 
   /// The tag that we want to run
-  var tags = Set<BenchmarkCategories>()
+  var tags = Set<BenchmarkCategory>()
 
   /// The scalar multiple of the amount of times a test should be run. This
   /// enables one to cause tests to run for N iterations longer than they
@@ -123,24 +125,24 @@
     ]
     let maybeBenchArgs: Arguments? = parseArgs(validOptions)
     if maybeBenchArgs == nil {
-      return .Fail("Failed to parse arguments")
+      return .fail("Failed to parse arguments")
     }
     let benchArgs = maybeBenchArgs!
 
     filters = benchArgs.positionalArgs
 
     if let x = benchArgs.optionalArgsMap["--iter-scale"] {
-      if x.isEmpty { return .Fail("--iter-scale requires a value") }
+      if x.isEmpty { return .fail("--iter-scale requires a value") }
       iterationScale = Int(x)!
     }
 
     if let x = benchArgs.optionalArgsMap["--num-iters"] {
-      if x.isEmpty { return .Fail("--num-iters requires a value") }
+      if x.isEmpty { return .fail("--num-iters requires a value") }
       fixedNumIters = numericCast(Int(x)!)
     }
 
     if let x = benchArgs.optionalArgsMap["--num-samples"] {
-      if x.isEmpty { return .Fail("--num-samples requires a value") }
+      if x.isEmpty { return .fail("--num-samples requires a value") }
       numSamples = Int(x)!
     }
 
@@ -150,75 +152,16 @@
     }
 
     if let x = benchArgs.optionalArgsMap["--delim"] {
-      if x.isEmpty { return .Fail("--delim requires a value") }
+      if x.isEmpty { return .fail("--delim requires a value") }
       delim = x
     }
 
     if let x = benchArgs.optionalArgsMap["--tags"] {
-      if x.isEmpty { return .Fail("--tags requires a value") }
-      if x.contains("cpubench") {
-        tags.insert(BenchmarkCategories.cpubench)
+      if x.isEmpty { return .fail("--tags requires a value") }
+      guard let cat = BenchmarkCategory(rawValue: x) else {
+        return .fail("Unknown benchmark category: '\(x)'")
       }
-      if x.contains("unstable") {
-        tags.insert(BenchmarkCategories.unstable)
-      }
-      if x.contains("validation") {
-        tags.insert(BenchmarkCategories.validation)
-      }
-      if x.contains("api") {
-        tags.insert(BenchmarkCategories.api)
-      }
-      if x.contains("Array") {
-        tags.insert(BenchmarkCategories.Array)
-      }
-      if x.contains("String") {
-        tags.insert(BenchmarkCategories.String)
-      }
-      if x.contains("Dictionary") {
-        tags.insert(BenchmarkCategories.Dictionary)
-      }
-      if x.contains("Codable") {
-        tags.insert(BenchmarkCategories.Codable)
-      }
-      if x.contains("Set") {
-        tags.insert(BenchmarkCategories.Set)
-      }
-      if x.contains("sdk") {
-        tags.insert(BenchmarkCategories.sdk)
-      }
-      if x.contains("runtime") {
-        tags.insert(BenchmarkCategories.runtime)
-      }
-      if x.contains("refcount") {
-        tags.insert(BenchmarkCategories.refcount)
-      }
-      if x.contains("metadata") {
-        tags.insert(BenchmarkCategories.metadata)
-      }
-      if x.contains("abstraction") {
-        tags.insert(BenchmarkCategories.abstraction)
-      }
-      if x.contains("safetychecks") {
-        tags.insert(BenchmarkCategories.safetychecks)
-      }
-      if x.contains("exceptions") {
-        tags.insert(BenchmarkCategories.exceptions)
-      }
-      if x.contains("bridging") {
-        tags.insert(BenchmarkCategories.bridging)
-      }
-      if x.contains("concurrency") {
-        tags.insert(BenchmarkCategories.concurrency)
-      }
-      if x.contains("algorithm") {
-        tags.insert(BenchmarkCategories.algorithm)
-      }
-      if x.contains("miniapplication") {
-        tags.insert(BenchmarkCategories.miniapplication)
-      }
-      if x.contains("regression") {
-        tags.insert(BenchmarkCategories.regression)
-      }
+      tags.insert(cat)
     }
 
     if let _ = benchArgs.optionalArgsMap["--run-all"] {
@@ -227,32 +170,32 @@
 
     if let x = benchArgs.optionalArgsMap["--sleep"] {
       if x.isEmpty {
-        return .Fail("--sleep requires a non-empty integer value")
+        return .fail("--sleep requires a non-empty integer value")
       }
       let v: Int? = Int(x)
       if v == nil {
-        return .Fail("--sleep requires a non-empty integer value")
+        return .fail("--sleep requires a non-empty integer value")
       }
       afterRunSleep = v!
     }
 
     if let _ = benchArgs.optionalArgsMap["--list"] {
-      return .ListTests
+      return .listTests
     }
 
     if let _ = benchArgs.optionalArgsMap["--registered"] {
       onlyRegistered = true
     }
 
-    return .Run
+    return .run
   }
 
   mutating func findTestsToRun() {
-    var allTests: [(key: String, value: ((Int) -> (), [BenchmarkCategories]))]
+    var allTests: [(key: String, value: ((Int) -> (), [BenchmarkCategory]))]
 
     if onlyRegistered {
       allTests = registeredBenchmarks.map {
-        bench -> (key: String, value: ((Int) -> (), [BenchmarkCategories])) in
+        bench -> (key: String, value: ((Int) -> (), [BenchmarkCategory])) in
         (bench.name, (bench.runFunction, bench.tags))
       }
       // FIXME: for now unstable/extra benchmarks are not registered at all, but
@@ -261,7 +204,7 @@
     }
     else {
       allTests = [precommitTests, otherTests, stringTests]
-        .map { dictionary -> [(key: String, value: ((Int) -> (), [BenchmarkCategories]))] in
+        .map { dictionary -> [(key: String, value: ((Int) -> (), [BenchmarkCategory]))] in
           Array(dictionary).sorted { $0.key < $1.key } } // by name
         .flatMap { $0 }
     }
@@ -466,48 +409,48 @@
 func runBenchmarks(_ c: TestConfig) {
   let units = "us"
   print("#\(c.delim)TEST\(c.delim)SAMPLES\(c.delim)MIN(\(units))\(c.delim)MAX(\(units))\(c.delim)MEAN(\(units))\(c.delim)SD(\(units))\(c.delim)MEDIAN(\(units))")
-  var SumBenchResults = BenchResults()
-  SumBenchResults.sampleCount = 0
+  var sumBenchResults = BenchResults()
+  sumBenchResults.sampleCount = 0
 
   for t in c.tests {
     if !t.run {
       continue
     }
-    let BenchIndex = t.index
-    let BenchName = t.name
-    let BenchFunc = t.f
-    let results = runBench(BenchName, BenchFunc, c)
-    print("\(BenchIndex)\(c.delim)\(BenchName)\(c.delim)\(results.description)")
+    let benchIndex = t.index
+    let benchName = t.name
+    let benchFunc = t.f
+    let results = runBench(benchName, benchFunc, c)
+    print("\(benchIndex)\(c.delim)\(benchName)\(c.delim)\(results.description)")
     fflush(stdout)
 
-    SumBenchResults.min += results.min
-    SumBenchResults.max += results.max
-    SumBenchResults.mean += results.mean
-    SumBenchResults.sampleCount += 1
+    sumBenchResults.min += results.min
+    sumBenchResults.max += results.max
+    sumBenchResults.mean += results.mean
+    sumBenchResults.sampleCount += 1
     // Don't accumulate SD and Median, as simple sum isn't valid for them.
     // TODO: Compute SD and Median for total results as well.
-    // SumBenchResults.sd += results.sd
-    // SumBenchResults.median += results.median
+    // sumBenchResults.sd += results.sd
+    // sumBenchResults.median += results.median
   }
 
   print("")
-  print("Totals\(c.delim)\(SumBenchResults.description)")
+  print("Totals\(c.delim)\(sumBenchResults.description)")
 }
 
 public func main() {
   var config = TestConfig()
 
   switch (config.processArguments()) {
-    case let .Fail(msg):
+    case let .fail(msg):
       // We do this since we need an autoclosure...
       fatalError("\(msg)")
-    case .ListTests:
+    case .listTests:
       config.findTestsToRun()
       print("Enabled Tests\(config.delim)Tags")
       for t in config.tests where t.run == true {
         print("\(t.name)\(config.delim)\(t.tags)")
       }
-    case .Run:
+    case .run:
       config.findTestsToRun()
       printRunInfo(config)
       runBenchmarks(config)
diff --git a/benchmark/utils/TestsUtils.swift b/benchmark/utils/TestsUtils.swift
index fd9ab99..107260e 100644
--- a/benchmark/utils/TestsUtils.swift
+++ b/benchmark/utils/TestsUtils.swift
@@ -16,7 +16,7 @@
 import Darwin
 #endif
 
-public enum BenchmarkCategories : CustomStringConvertible {
+public enum BenchmarkCategory : String {
   // Validation "micro" benchmarks test a specific operation or critical path that
   // we know is important to measure.
   case validation
@@ -65,40 +65,21 @@
   // reimplementing or call into code paths that have known opportunities for
   // significant optimization.
   case cpubench
-
-  public var description : String {
-    switch self {
-    case .cpubench: return "cpubench"
-    case .unstable: return "unstable"
-    case .validation: return "validation"
-    case .api: return "api"
-    case .Array: return "Array"
-    case .String: return "String"
-    case .Dictionary: return "Dictionary"
-    case .Codable: return "Codable"
-    case .Set: return "Set"
-    case .sdk: return "sdk"
-    case .runtime: return "runtime"
-    case .refcount: return "refcount"
-    case .metadata: return "metadata"
-    case .abstraction: return "abstraction"
-    case .safetychecks: return "safetychecks"
-    case .exceptions: return "exceptions"
-    case .bridging: return "bridging"
-    case .concurrency: return "concurrency"
-    case .algorithm: return "algorithm"
-    case .miniapplication: return "miniapplication"
-    case .regression: return "regression"
-    }
-  }
 }
 
 public struct BenchmarkInfo {
+  /// The name of the benchmark that should be displayed by the harness.
   public var name: String
-  public var runFunction: (Int) -> ()
-  public var tags: [BenchmarkCategories]
 
-  public init(name: String, runFunction: @escaping (Int) -> (), tags: [BenchmarkCategories]) {
+  /// A function that invokes the specific benchmark routine.
+  public var runFunction: (Int) -> ()
+
+  /// A set of category tags that describe this benchmark. This is used by the
+  /// harness to allow for easy slicing of the set of benchmarks along tag
+  /// boundaries, e.x.: run all string benchmarks or ref count benchmarks, etc.
+  public var tags: [BenchmarkCategory]
+
+  public init(name: String, runFunction: @escaping (Int) -> (), tags: [BenchmarkCategory]) {
     self.name = name
     self.runFunction = runFunction
     self.tags = tags
diff --git a/benchmark/utils/main.swift b/benchmark/utils/main.swift
index 88b7326..2c6287e 100644
--- a/benchmark/utils/main.swift
+++ b/benchmark/utils/main.swift
@@ -90,6 +90,7 @@
 import Prefix
 import PrefixWhile
 import Prims
+import PrimsSplit
 import ProtocolDispatch
 import ProtocolDispatch2
 import RC4
@@ -141,10 +142,10 @@
 
 @inline(__always)
 private func addTo(
-  _ testSuite: inout [String : ((Int) -> (), [BenchmarkCategories])],
+  _ testSuite: inout [String : ((Int) -> (), [BenchmarkCategory])],
   _ name: String,
   _ function: @escaping (Int) -> (),
-  _ tags: [BenchmarkCategories] = []
+  _ tags: [BenchmarkCategory] = []
   ) {
   testSuite[name] = (function, tags)
 }
@@ -402,6 +403,7 @@
 addTo(&precommitTests, "PrefixWhileSequence", run_PrefixWhileSequence, [.validation, .api, .abstraction])
 addTo(&precommitTests, "PrefixWhileSequenceLazy", run_PrefixWhileSequenceLazy, [.validation, .api, .abstraction])
 addTo(&precommitTests, "Prims", run_Prims, [.validation, .algorithm])
+addTo(&precommitTests, "PrimsSplit", run_PrimsSplit, [.validation, .algorithm])
 addTo(&precommitTests, "ProtocolDispatch", run_ProtocolDispatch, [.validation, .abstraction])
 addTo(&precommitTests, "ProtocolDispatch2", run_ProtocolDispatch2, [.validation, .abstraction])
 addTo(&precommitTests, "RC4", run_RC4, [.validation, .algorithm])
diff --git a/cmake/modules/AddSwift.cmake b/cmake/modules/AddSwift.cmake
index 9741821..5145017 100644
--- a/cmake/modules/AddSwift.cmake
+++ b/cmake/modules/AddSwift.cmake
@@ -1,5 +1,6 @@
 include(SwiftList)
 include(SwiftXcodeSupport)
+include(SwiftWindowsSupport)
 
 # SWIFTLIB_DIR is the directory in the build tree where Swift resource files
 # should be placed.  Note that $CMAKE_CFG_INTDIR expands to "." for
@@ -240,6 +241,9 @@
     list(APPEND result "-D_CRT_USE_BUILTIN_OFFSETOF")
     # TODO(compnerd) permit building for different families
     list(APPEND result "-D_CRT_USE_WINAPI_FAMILY_DESKTOP_APP")
+    if("${CFLAGS_ARCH}" MATCHES arm)
+      list(APPEND result "-D_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE")
+    endif()
     # TODO(compnerd) handle /MT
     list(APPEND result "-D_DLL")
     # NOTE: We assume that we are using VS 2015 U2+
@@ -354,6 +358,8 @@
       # options. This causes conflicts.
       list(APPEND result "-nostdlib")
     endif()
+    swift_windows_lib_for_arch(${LFLAGS_ARCH} ${LFLAGS_ARCH}_LIB)
+    list(APPEND library_search_directories ${${LFLAGS_ARCH}_LIB})
   elseif("${LFLAGS_SDK}" STREQUAL "HAIKU")
     list(APPEND result "-lbsd" "-latomic" "-Wl,-Bsymbolic")
   elseif("${LFLAGS_SDK}" STREQUAL "ANDROID")
@@ -723,6 +729,13 @@
   endif()
 
   if("${SWIFTLIB_SINGLE_SDK}" STREQUAL "WINDOWS")
+    swift_windows_include_for_arch(${SWIFTLIB_SINGLE_ARCHITECTURE} SWIFTLIB_INCLUDE)
+    foreach(directory ${SWIFTLIB_INCLUDE})
+      list(APPEND SWIFTLIB_SINGLE_SWIFT_COMPILE_FLAGS -Xfrontend;-I${directory})
+    endforeach()
+    if("${SWIFTLIB_SINGLE_ARCHITECTURE}" MATCHES arm)
+      list(APPEND SWIFTLIB_SINGLE_SWIFT_COMPILE_FLAGS -Xcc;-D_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE)
+    endif()
     list(APPEND SWIFTLIB_SINGLE_SWIFT_COMPILE_FLAGS -Xfrontend;-autolink-library;-Xfrontend;oldnames)
     # TODO(compnerd) handle /MT and /MTd
     if("${CMAKE_BUILD_TYPE}" STREQUAL "RELEASE")
@@ -833,6 +846,11 @@
     endif()
   endif()
 
+  if("${SWIFTLIB_SINGLE_SDK}" STREQUAL "WINDOWS")
+    swift_windows_include_for_arch(${SWIFTLIB_SINGLE_ARCHITECTURE} SWIFTLIB_INCLUDE)
+    target_include_directories("${target}" SYSTEM PRIVATE ${SWIFTLIB_INCLUDE})
+  endif()
+
   if("${SWIFTLIB_SINGLE_SDK}" STREQUAL "WINDOWS" AND NOT "${CMAKE_SYSTEM_NAME}" STREQUAL "Windows")
     if("${libkind}" STREQUAL "SHARED")
       # Each dll has an associated .lib (import library); since we may be
diff --git a/cmake/modules/SwiftConfigureSDK.cmake b/cmake/modules/SwiftConfigureSDK.cmake
index 12ccac7..a69c8e7 100644
--- a/cmake/modules/SwiftConfigureSDK.cmake
+++ b/cmake/modules/SwiftConfigureSDK.cmake
@@ -5,12 +5,22 @@
 # built for each variant.
 set(SWIFT_CONFIGURED_SDKS)
 
+include(SwiftWindowsSupport)
+
 # Report the given SDK to the user.
 function(_report_sdk prefix)
   message(STATUS "${SWIFT_SDK_${prefix}_NAME} SDK:")
   if("${prefix}" STREQUAL "WINDOWS")
-    message(STATUS "  INCLUDE: $ENV{INCLUDE}")
-    message(STATUS "  LIB: $ENV{LIB}")
+    message(STATUS "  UCRT Version: $ENV{UCRTVersion}")
+    message(STATUS "  UCRT SDK Dir: $ENV{UniversalCRTSdkDir}")
+    message(STATUS "  VC Dir: $ENV{VCToolsInstallDir}")
+
+    foreach(arch ${SWIFT_SDK_${prefix}_ARCHITECTURES})
+      swift_windows_include_for_arch(${arch} ${arch}_INCLUDE)
+      swift_windows_lib_for_arch(${arch} ${arch}_LIB)
+      message(STATUS "  ${arch} INCLUDE: ${${arch}_INCLUDE}")
+      message(STATUS "  ${arch} LIB: ${${arch}_LIB}")
+    endforeach()
   else()
     message(STATUS "  Path: ${SWIFT_SDK_${prefix}_PATH}")
   endif()
diff --git a/cmake/modules/SwiftExternalBenchmarkBuild.cmake b/cmake/modules/SwiftExternalBenchmarkBuild.cmake
new file mode 100644
index 0000000..64db306
--- /dev/null
+++ b/cmake/modules/SwiftExternalBenchmarkBuild.cmake
@@ -0,0 +1,89 @@
+
+include(CMakeParseArguments)
+include(LLVMExternalProjectUtils)
+include(SwiftUtils)
+
+# This is the name of the target on the parent cmake side that is associated
+# with an external project target.
+#
+# If LLVMExternalProjectUtils refactors its external target code, so we can
+# easily add individual forwarded targets with different dependencies, this can
+# be removed.
+function(compute_external_target_name target_name_out target)
+  string(REPLACE ":" ";" target_list ${target})
+  list(GET target_list 0 target)
+  list(LENGTH target_list target_list_len)
+  if(${target_list_len} GREATER 1)
+    list(GET target_list 1 target_name)
+  else()
+    set(target_name "${target}")
+  endif()
+
+  set(${target_name_out} "${target_name}" PARENT_SCOPE)
+endfunction()
+
+function(compute_stdlib_dependencies stdlib_dependencies_out platform)
+  foreach(stdlib_dependency ${UNIVERSAL_LIBRARY_NAMES_${platform}})
+    string(FIND "${stdlib_dependency}" "Unittest" find_output)
+    if("${find_output}" STREQUAL "-1")
+      list(APPEND stdlib_dependencies "${stdlib_dependency}")
+    endif()
+  endforeach()
+  set(${stdlib_dependencies_out} "${stdlib_dependencies}" PARENT_SCOPE)
+endfunction()
+
+set(ONLY_PLATFORMS "macosx" "iphoneos" "appletvos" "watchos")
+
+function (get_platform_from_target target_platform_out target)
+  foreach (platform ${ONLY_PLATFORMS})
+    string(FIND "${target}" "${platform}" FOUND_TARGET_PLATFORM)
+    if (NOT FOUND_TARGET_PLATFORM)
+      continue()
+    endif()
+
+    set(${target_platform_out} "${platform}" PARENT_SCOPE)
+    break()
+  endforeach()
+endfunction()
+
+function (compute_target_stdlib_dependencies dependencies_out target)
+  get_platform_from_target(target_platform ${target})
+  precondition(target_platform
+    MESSAGE "Failed to find a platform for ${target_platform}")
+  compute_stdlib_dependencies(stdlib_dependencies ${target_platform})
+  set(${dependencies_out} ${stdlib_dependencies} PARENT_SCOPE)
+endfunction()
+
+function (add_external_benchmark_suite)
+  set(name swift-benchmark)
+  set(src_dir ${SWIFT_SOURCE_DIR}/benchmark)
+  set(bin_dir ${SWIFT_BINARY_DIR}/external-benchmark/binary)
+  set(stamp_dir ${SWIFT_BINARY_DIR}/external-benchmark/stamps)
+  set(prefix_dir ${SWIFT_BINARY_DIR}/external-benchmark/prefix)
+
+  set(bench_targets Benchmark_O Benchmark_Onone Benchmark_Ounchecked)
+  set(library_targets swift-benchmark-macosx-x86_64-external)
+
+  set(all_stdlib_dependencies)
+  foreach (target ${library_targets})
+    compute_target_stdlib_dependencies(stdlib_dependencies ${target})
+    precondition(stdlib_dependencies)
+    # Add dependencies from all of our stdlib dependencies to
+    # swift-bench-configure. This will ensure the stdlib is ready to be poked at
+    # in the configure script if we ever want to do so.
+    list(APPEND all_stdlib_dependencies ${stdlib_dependencies})
+  endforeach()
+
+  llvm_ExternalProject_add(swift-bench ${src_dir}
+    SOURCE_DIR ${src_dir}
+    EXCLUDE_FROM_ALL
+    DEPENDS swift ${all_stdlib_dependencies}
+    EXTRA_TARGETS ${bench_targets} ${library_targets}
+    CMAKE_ARGS
+      -DSWIFT_EXEC=${SWIFT_BINARY_DIR}/bin/swiftc
+      -DSWIFT_LIBRARY_PATH=${SWIFT_BINARY_DIR}/lib/swift
+      -DCMAKE_C_COMPILER=${PATH_TO_CLANG_BUILD}/bin/clang
+      -DCMAKE_CXX_COMPILER=${PATH_TO_CLANG_BUILD}/bin/clang++
+    PASSTHROUGH_PREFIXES SWIFT_BENCHMARK
+    )
+endfunction()
diff --git a/cmake/modules/SwiftWindowsSupport.cmake b/cmake/modules/SwiftWindowsSupport.cmake
new file mode 100644
index 0000000..8fd49b4
--- /dev/null
+++ b/cmake/modules/SwiftWindowsSupport.cmake
@@ -0,0 +1,60 @@
+
+include(SwiftUtils)
+
+function(swift_windows_arch_spelling arch var)
+  if(${arch} STREQUAL i686)
+    set(${var} x86 PARENT_SCOPE)
+  elseif(${arch} STREQUAL x86_64)
+    set(${var} x64 PARENT_SCOPE)
+  elseif(${arch} STREQUAL armv7)
+    set(${var} arm PARENT_SCOPE)
+  elseif(${arch} STREQUAL aarch64)
+    set(${var} arm64 PARENT_SCOPE)
+  else()
+    message(FATAL_ERROR "do not know MSVC spelling for ARCH: `${arch}`")
+  endif()
+endfunction()
+
+function(swift_verify_windows_environment_variables)
+  set(VCToolsInstallDir $ENV{VCToolsInstallDir})
+  set(UniversalCRTSdkDir $ENV{UniversalCRTSdkDir})
+  set(UCRTVersion $ENV{UCRTVersion})
+
+  precondition(VCToolsInstallDir
+               MESSAGE
+                 "VCToolsInstallDir environment variable must be set")
+  precondition(UniversalCRTSdkDir
+               MESSAGE
+                 "UniversalCRTSdkDir environment variable must be set")
+  precondition(UCRTVersion
+               MESSAGE
+                 "UCRTVersion environment variable must be set")
+endfunction()
+
+function(swift_windows_include_for_arch arch var)
+  swift_verify_windows_environment_variables()
+
+  set(paths
+        "$ENV{VCToolsInstallDir}/include"
+        "$ENV{UniversalCRTSdkDir}/Include/$ENV{UCRTVersion}/ucrt"
+        "$ENV{UniversalCRTSdkDir}/Include/$ENV{UCRTVersion}/um"
+        "$ENV{UniversalCRTSdkDir}/Include/$ENV{UCRTVersion}/shared")
+  set(${var} ${paths} PARENT_SCOPE)
+endfunction()
+
+function(swift_windows_lib_for_arch arch var)
+  swift_verify_windows_environment_variables()
+  swift_windows_arch_spelling(${arch} ARCH)
+
+  set(paths)
+  if(${ARCH} STREQUAL x86)
+    list(APPEND paths "$ENV{VCToolsInstallDir}/Lib")
+  else()
+    list(APPEND paths "$ENV{VCToolsInstallDir}/Lib/${ARCH}")
+  endif()
+  list(APPEND paths
+          "$ENV{UniversalCRTSdkDir}/Lib/$ENV{UCRTVersion}/ucrt/${ARCH}"
+          "$ENV{UniversalCRTSdkDir}/Lib/$ENV{UCRTVersion}/um/${ARCH}")
+  set(${var} ${paths} PARENT_SCOPE)
+endfunction()
+
diff --git a/docs/SIL.rst b/docs/SIL.rst
index 7d71939..3cd82a8 100644
--- a/docs/SIL.rst
+++ b/docs/SIL.rst
@@ -167,7 +167,7 @@
     %2 = struct_extract %0 : $Point, #Point.x
     %3 = struct_extract %0 : $Point, #Point.y
     %4 = apply %1(%2, %3) : $(Double, Double) -> Double
-    %5 = return %4 : Double
+    return %4 : Double
   }
 
   // Define a SIL vtable. This matches dynamically-dispatched method
@@ -4625,7 +4625,7 @@
                        sil-type 'in' sil-operand 'to'
                        sil-type 'in' sil-operand
 
-  %1 = unconditional_checked_cast_addr $A in %0 : $*@thick A to $B in $*@thick B
+  unconditional_checked_cast_addr $A in %0 : $*@thick A to $B in $*@thick B
   // $A and $B must be both addresses
   // %1 will be of type $*B
   // $A is destroyed during the conversion. There is no implicit copy.
diff --git a/docs/Windows.md b/docs/Windows.md
index 8b65abf..387dc71 100644
--- a/docs/Windows.md
+++ b/docs/Windows.md
@@ -11,18 +11,18 @@
 Windows 10 SDK at revision 10.10.586.
 
 ```
-export WINKIT_ROOT=".../Windows Kits/10"
-export VC_ROOT=".../Microsoft Visual Studio 14.0/VC"
-export INCLUDE='${VC_ROOT}/include;${WINKIT_ROOT}/Include/10.0.10586.0/ucrt;${WINKIT_ROOT}/Include/10.0.10586.0/um;${WINKIT_ROOT}/Include/10.0.10586.0/shared'
-export LIB='${VC_ROOT}/lib;${WINKIT_ROOT}/Lib/10.0.10586.0/ucrt/x86;${WINKIT_ROOT}/Lib/10.0.10586.0/um/x86'
+# Visual Studio 2015 does not have VCToolsInstallDir, use VCINSTALLDIR's value
+export UCRTVersion=10.0.10586.0
+export UniversalCRTSdkDir=".../Windows Kits/10"
+export VCToolsInstallDir=".../Microsoft Visual Studio/2017/Community"
 ```
 
 ### 2. Setup `visualc` and `ucrt` modules
 The `visualc.modulemap` located at
 `swift/stdlib/public/Platform/visualc.modulemap` needs to be copied into
-`${VC_ROOT}/include`. The `ucrt.modulemap` located at
+`${VCToolsInstallDir}/include`. The `ucrt.modulemap` located at
 `swift/stdlib/public/Platform/ucrt.modulemap` needs to be copied into
-`${WINKIT_ROOT}/Include/10.0.10586.0/ucrt`.
+`${UniversalCRTSdkDir}/Include/${UCRTVersion}/ucrt`.
 
 ### 3. Configure the runtime to be built with the just built clang
 Ensure that we use the tools from the just built LLVM and clang tools to build
diff --git a/include/swift/ABI/MetadataValues.h b/include/swift/ABI/MetadataValues.h
index 1d53b34..0259ba7 100644
--- a/include/swift/ABI/MetadataValues.h
+++ b/include/swift/ABI/MetadataValues.h
@@ -305,11 +305,9 @@
 
 /// Flags in a generic nominal type descriptor.
 class GenericParameterDescriptorFlags {
-  typedef uint32_t int_type;
+  typedef uint16_t int_type;
   enum : int_type {
-    HasParent        = 0x01,
-    HasGenericParent = 0x02,
-    HasVTable        = 0x04,
+    HasVTable        = 0x0004,
   };
   int_type Data;
   
@@ -317,38 +315,11 @@
 public:
   constexpr GenericParameterDescriptorFlags() : Data(0) {}
 
-  constexpr GenericParameterDescriptorFlags withHasParent(bool b) const {
-    return GenericParameterDescriptorFlags(b ? (Data | HasParent)
-                                             : (Data & ~HasParent));
-  }
-
-  constexpr GenericParameterDescriptorFlags withHasGenericParent(bool b) const {
-    return GenericParameterDescriptorFlags(b ? (Data | HasGenericParent)
-                                             : (Data & ~HasGenericParent));
-  }
-
   constexpr GenericParameterDescriptorFlags withHasVTable(bool b) const {
     return GenericParameterDescriptorFlags(b ? (Data | HasVTable)
                                              : (Data & ~HasVTable));
   }
 
-  /// Does this type have a lexical parent type?
-  ///
-  /// For class metadata, if this is true, the storage for the parent type
-  /// appears immediately prior to the first generic argument.  Other
-  /// metadata always have a slot for their parent type.
-  bool hasParent() const {
-    return Data & HasParent;
-  }
-
-  /// Given that this type has a parent type, is that type generic?  If so,
-  /// it forms part of the key distinguishing this metadata from other
-  /// metadata, and the parent metadata will be the first argument to
-  /// the generic metadata access function.
-  bool hasGenericParent() const {
-    return Data & HasGenericParent;
-  }
-
   /// If this type is a class, does it have a vtable?  If so, the number
   /// of vtable entries immediately follows the generic requirement
   /// descriptor.
diff --git a/include/swift/AST/Attr.def b/include/swift/AST/Attr.def
index 359a7bd..19937a3 100644
--- a/include/swift/AST/Attr.def
+++ b/include/swift/AST/Attr.def
@@ -259,8 +259,8 @@
 // FIXME: Replace with improved @available attribute.
 SIMPLE_DECL_ATTR(_versioned, Versioned,
                  OnFunc | OnVar | OnSubscript | OnConstructor |
-                 OnStruct | OnEnum | OnClass | OnProtocol |
-                 LongAttribute | UserInaccessible,
+                 OnDestructor | OnStruct | OnEnum | OnClass |
+                 OnProtocol | LongAttribute | UserInaccessible,
                  64)
 
 SIMPLE_DECL_ATTR(discardableResult, DiscardableResult,
diff --git a/include/swift/AST/DiagnosticsCommon.def b/include/swift/AST/DiagnosticsCommon.def
index fb17f8c..70fd091 100644
--- a/include/swift/AST/DiagnosticsCommon.def
+++ b/include/swift/AST/DiagnosticsCommon.def
@@ -82,6 +82,9 @@
 NOTE(note_typo_candidate,none,
      "did you mean '%0'?", (StringRef))
 
+NOTE(profile_read_error,none,
+     "failed to load profile data '%0': '%1'", (StringRef, StringRef))
+
 #ifndef DIAG_NO_UNDEF
 # if defined(DIAG)
 #  undef DIAG
diff --git a/include/swift/AST/DiagnosticsDriver.def b/include/swift/AST/DiagnosticsDriver.def
index 8fea22f..a589010 100644
--- a/include/swift/AST/DiagnosticsDriver.def
+++ b/include/swift/AST/DiagnosticsDriver.def
@@ -133,6 +133,9 @@
 WARNING(verify_debug_info_requires_debug_option,none,
         "ignoring '-verify-debug-info'; no debug info is being generated", ())
 
+ERROR(error_profile_missing,none,
+      "no profdata file exists at '%0'", (StringRef))
+
 #ifndef DIAG_NO_UNDEF
 # if defined(DIAG)
 #  undef DIAG
diff --git a/include/swift/AST/DiagnosticsParse.def b/include/swift/AST/DiagnosticsParse.def
index b6260cf..aab6948 100644
--- a/include/swift/AST/DiagnosticsParse.def
+++ b/include/swift/AST/DiagnosticsParse.def
@@ -511,6 +511,8 @@
       "SIL instructions must be at the start of a line", ())
 ERROR(expected_equal_in_sil_instr,none,
       "expected '=' in SIL instruction", ())
+ERROR(wrong_result_count_in_sil_instr,none,
+      "wrong number of results for SIL instruction, expected %0", (unsigned))
 ERROR(expected_sil_instr_opcode,none,
       "expected SIL instruction opcode", ())
 ERROR(expected_tok_in_sil_instr,none,
diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def
index 736c72f..c8af8d0 100644
--- a/include/swift/AST/DiagnosticsSema.def
+++ b/include/swift/AST/DiagnosticsSema.def
@@ -333,7 +333,7 @@
 ERROR(cannot_convert_default_arg_value_protocol,none,
       "default argument value of type %0 does not conform to %1", (Type,Type))
 ERROR(cannot_convert_default_arg_value_nil,none,
-      "nil default argument value of cannot be converted to type %0", (Type))
+      "nil default argument value cannot be converted to type %0", (Type))
 
 ERROR(cannot_convert_argument_value,none,
       "cannot convert value of type %0 to expected argument type %1",
diff --git a/include/swift/AST/GenericSignatureBuilder.h b/include/swift/AST/GenericSignatureBuilder.h
index ddf8ebe..94dafa3 100644
--- a/include/swift/AST/GenericSignatureBuilder.h
+++ b/include/swift/AST/GenericSignatureBuilder.h
@@ -769,16 +769,6 @@
     /// \c TypeRepr.
     Inferred,
 
-    /// A requirement inferred from part of the signature of a declaration
-    /// but for which we don't want to produce warnings, e.g., the result
-    /// type of a generic function:
-    ///
-    /// func f<T>() -> Set<T> { ... } // infers T: Hashable, but don't warn
-    ///
-    /// This is a root requirement source, which can be described by a
-    /// \c TypeRepr.
-    QuietlyInferred,
-
     /// A requirement for the creation of the requirement signature of a
     /// protocol.
     ///
@@ -889,7 +879,6 @@
 
     case Explicit:
     case Inferred:
-    case QuietlyInferred:
     case NestedTypeNameMatch:
     case ConcreteTypeBinding:
     case Superclass:
@@ -930,7 +919,6 @@
     switch (kind) {
     case Explicit:
     case Inferred:
-    case QuietlyInferred:
     case RequirementSignatureSelf:
     case NestedTypeNameMatch:
     case ConcreteTypeBinding:
@@ -1052,8 +1040,7 @@
   /// inferred from some part of a generic declaration's signature, e.g., the
   /// parameter or result type of a generic function.
   static const RequirementSource *forInferred(PotentialArchetype *root,
-                                              const TypeRepr *typeRepr,
-                                              bool quietly);
+                                              const TypeRepr *typeRepr);
 
   /// Retrieve a requirement source representing the requirement signature
   /// computation for a protocol.
@@ -1150,7 +1137,7 @@
 
   /// Whether the requirement is inferred or derived from an inferred
   /// requirement.
-  bool isInferredRequirement(bool includeQuietInferred) const;
+  bool isInferredRequirement() const;
 
   /// Classify the kind of this source for diagnostic purposes.
   unsigned classifyDiagKind() const;
@@ -1272,8 +1259,6 @@
     Explicit,
     /// An inferred requirement source lacking a root.
     Inferred,
-    /// A quietly inferred requirement source lacking a root.
-    QuietlyInferred,
     /// A requirement source augmented by an abstract protocol requirement
     AbstractProtocol,
     /// A requirement source for a nested-type-name match introduced by
@@ -1319,9 +1304,8 @@
     return { Explicit, requirementRepr };
   }
 
-  static FloatingRequirementSource forInferred(const TypeRepr *typeRepr,
-                                               bool quietly) {
-    return { quietly? QuietlyInferred : Inferred, typeRepr };
+  static FloatingRequirementSource forInferred(const TypeRepr *typeRepr) {
+    return { Inferred, typeRepr };
   }
 
   static FloatingRequirementSource viaProtocolRequirement(
diff --git a/include/swift/AST/IRGenOptions.h b/include/swift/AST/IRGenOptions.h
index 4c9c6b1..a72fbc5 100644
--- a/include/swift/AST/IRGenOptions.h
+++ b/include/swift/AST/IRGenOptions.h
@@ -139,9 +139,6 @@
   /// Frameworks that we should not autolink against.
   SmallVector<std::string, 1> DisableAutolinkFrameworks;
 
-  /// Instrument code to generate profiling information.
-  unsigned GenerateProfile : 1;
-
   /// Print the LLVM inline tree at the end of the LLVM pass pipeline.
   unsigned PrintInlineTree : 1;
 
@@ -168,6 +165,12 @@
   /// Enable use of the swiftcall calling convention.
   unsigned UseSwiftCall : 1;
 
+  /// Instrument code to generate profiling information.
+  unsigned GenerateProfile : 1;
+
+  /// Path to the profdata file to be used for PGO, or the empty string.
+  std::string UseProfile = "";
+
   /// List of backend command-line options for -embed-bitcode.
   std::vector<uint8_t> CmdArgs;
 
@@ -181,11 +184,11 @@
         DebugInfoKind(IRGenDebugInfoKind::None), UseJIT(false),
         DisableLLVMOptzns(false), DisableLLVMARCOpts(false),
         DisableLLVMSLPVectorizer(false), DisableFPElim(true), Playground(false),
-        EmitStackPromotionChecks(false), GenerateProfile(false),
-        PrintInlineTree(false), EmbedMode(IRGenEmbedMode::None),
-        HasValueNamesSetting(false), ValueNames(false),
-        EnableReflectionMetadata(true), EnableReflectionNames(true),
-        UseIncrementalLLVMCodeGen(true), UseSwiftCall(false), CmdArgs(),
+        EmitStackPromotionChecks(false), PrintInlineTree(false),
+        EmbedMode(IRGenEmbedMode::None), HasValueNamesSetting(false),
+        ValueNames(false), EnableReflectionMetadata(true),
+        EnableReflectionNames(true), UseIncrementalLLVMCodeGen(true),
+        UseSwiftCall(false), GenerateProfile(false), CmdArgs(),
         SanitizeCoverage(llvm::SanitizerCoverageOptions()) {}
 
   /// Gets the name of the specified output filename.
diff --git a/include/swift/AST/SILOptions.h b/include/swift/AST/SILOptions.h
index 3dd247c..1b6eb44 100644
--- a/include/swift/AST/SILOptions.h
+++ b/include/swift/AST/SILOptions.h
@@ -107,6 +107,9 @@
   /// Instrument code to generate profiling information.
   bool GenerateProfile = false;
 
+  /// Path to the profdata file to be used for PGO, or the empty string.
+  std::string UseProfile = "";
+
   /// Emit a mapping of profile counters for use in coverage.
   bool EmitProfileCoverageMapping = false;
 
diff --git a/include/swift/AST/Type.h b/include/swift/AST/Type.h
index 453fab4..f0408a7 100644
--- a/include/swift/AST/Type.h
+++ b/include/swift/AST/Type.h
@@ -356,11 +356,11 @@
   /// 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.
-  /// 
-  /// \returns the join of the two types, if there is a concrete type that can
-  /// express the join, or a null type if the only join would be a more-general
-  /// existential type (e.g., \c Any).
-  static Type join(Type type1, Type type2);
+  ///
+  /// \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);
 
 private:
   // Direct comparison is disabled for types, because they may not be canonical.
diff --git a/include/swift/Basic/ArrayRefView.h b/include/swift/Basic/ArrayRefView.h
index ad27232..89edd8d 100644
--- a/include/swift/Basic/ArrayRefView.h
+++ b/include/swift/Basic/ArrayRefView.h
@@ -29,6 +29,7 @@
 class ArrayRefView {
   llvm::ArrayRef<Orig> Array;
 public:
+  ArrayRefView() {}
   ArrayRefView(llvm::ArrayRef<Orig> array) : Array(array) {}
 
   class iterator {
@@ -111,6 +112,41 @@
                   "original array access not enabled for this view");
     return Array;
   }
+
+  friend bool operator==(ArrayRefView lhs, ArrayRefView rhs) {
+    if (lhs.size() != rhs.size())
+      return false;
+    for (auto i : indices(lhs))
+      if (lhs[i] != rhs[i])
+        return false;
+    return true;
+  }
+  friend bool operator==(llvm::ArrayRef<Projected> lhs, ArrayRefView rhs) {
+    if (lhs.size() != rhs.size())
+      return false;
+    for (auto i : indices(lhs))
+      if (lhs[i] != rhs[i])
+        return false;
+    return true;
+  }
+  friend bool operator==(ArrayRefView lhs, llvm::ArrayRef<Projected> rhs) {
+    if (lhs.size() != rhs.size())
+      return false;
+    for (auto i : indices(lhs))
+      if (lhs[i] != rhs[i])
+        return false;
+    return true;
+  }
+
+  friend bool operator!=(ArrayRefView lhs, ArrayRefView rhs) {
+    return !(lhs == rhs);
+  }
+  friend bool operator!=(llvm::ArrayRef<Projected> lhs, ArrayRefView rhs) {
+    return !(lhs == rhs);
+  }
+  friend bool operator!=(ArrayRefView lhs, llvm::ArrayRef<Projected> rhs) {
+    return !(lhs == rhs);
+  }
 };
 
 } // end namespace swift
diff --git a/include/swift/Basic/ProfileCounter.h b/include/swift/Basic/ProfileCounter.h
new file mode 100644
index 0000000..b01c274
--- /dev/null
+++ b/include/swift/Basic/ProfileCounter.h
@@ -0,0 +1,46 @@
+//===------------ ProfileCounter.h - PGO Propfile counter -------*- 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
+//
+//===----------------------------------------------------------------------===//
+//
+/// \file Declares ProfileCounter, a convenient type for PGO
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SWIFT_BASIC_PROFILECOUNTER_H
+#define SWIFT_BASIC_PROFILECOUNTER_H
+
+#include <cassert>
+#include <cstdint>
+
+namespace swift {
+/// A class designed to be smaller than using Optional<uint64_t> for PGO
+class ProfileCounter {
+private:
+  uint64_t count;
+
+public:
+  explicit ProfileCounter() : count(UINT64_MAX) {}
+  ProfileCounter(uint64_t Count) : count(Count) {
+    if (Count == UINT64_MAX) {
+      count = UINT64_MAX - 1;
+    }
+  }
+
+  bool hasValue() const { return count != UINT64_MAX; }
+  uint64_t getValue() const {
+    assert(hasValue());
+    return count;
+  }
+  explicit operator bool() const { return hasValue(); }
+};
+} // end namespace swift
+
+#endif // SWIFT_BASIC_PROFILECOUNTER_H
diff --git a/include/swift/Basic/Range.h b/include/swift/Basic/Range.h
index d9b6a7f..3e23aea 100644
--- a/include/swift/Basic/Range.h
+++ b/include/swift/Basic/Range.h
@@ -63,11 +63,47 @@
     return result;
   }
 
-/// A range of integers.  This type behaves roughly like an ArrayRef.
-template <class T=unsigned> class IntRange {
-  static_assert(std::is_integral<T>::value, "T must be an integer type");
+template <class T, bool IsEnum = std::is_enum<T>::value>
+struct IntRangeTraits;
+
+template <class T>
+struct IntRangeTraits<T, /*is enum*/ false> {
+  static_assert(std::is_integral<T>::value,
+                "argument type of IntRange is either an integer nor an enum");
+  using int_type = T;
+  using difference_type = typename std::make_signed<int_type>::type;
+
+  static T addOffset(T value, difference_type quantity) {
+    return T(difference_type(value) + quantity);
+  }
+  static difference_type distance(T begin, T end) {
+    return difference_type(end) - difference_type(begin);
+  }
+};
+
+template <class T>
+struct IntRangeTraits<T, /*is enum*/ true> {
+  using int_type = typename std::underlying_type<T>::type;
+  using difference_type = typename std::make_signed<int_type>::type;
+
+  static T addOffset(T value, difference_type quantity) {
+    return T(difference_type(value) + quantity);
+  }
+  static difference_type distance(T begin, T end) {
+    return difference_type(end) - difference_type(begin);
+  }
+};
+
+/// A range of integers or enum values.  This type behaves roughly
+/// like an ArrayRef.
+template <class T = unsigned, class Traits = IntRangeTraits<T>>
+class IntRange {
   T Begin;
   T End;
+
+  using int_type = typename Traits::int_type;
+  using difference_type = typename Traits::difference_type;
+
 public:
   IntRange() : Begin(0), End(0) {}
   IntRange(T end) : Begin(0), End(end) {}
@@ -87,37 +123,48 @@
     typedef std::random_access_iterator_tag iterator_category;
 
     T operator*() const { return Value; }
-    iterator &operator++() { Value++; return *this; }
-    iterator operator++(int) { return iterator(Value++); }
-    iterator &operator--() {
-      Value--;
-      return *this;
+    iterator &operator++() {
+      return *this += 1;
     }
-    iterator operator--(int) { return iterator(Value--); }
+    iterator operator++(int) {
+      auto copy = *this;
+      *this += 1;
+      return copy;
+    }
+    iterator &operator--() {
+      return *this -= 1;
+    }
+    iterator operator--(int) {
+      auto copy = *this;
+      *this -= 1;
+      return copy;
+    }
     bool operator==(iterator rhs) { return Value == rhs.Value; }
     bool operator!=(iterator rhs) { return Value != rhs.Value; }
 
     iterator &operator+=(difference_type i) {
-      Value += T(i);
+      Value = Traits::addOffset(Value, i);
       return *this;
     }
     iterator operator+(difference_type i) const {
-      return iterator(Value + T(i));
+      return iterator(Traits::adddOfset(Value, i));
     }
     friend iterator operator+(difference_type i, iterator base) {
-      return iterator(base.Value + T(i));
+      return iterator(Traits::addOffset(base.Value, i));
     }
     iterator &operator-=(difference_type i) {
-      Value -= T(i);
+      Value = Traits::addOffset(Value, -i);
       return *this;
     }
     iterator operator-(difference_type i) const {
-      return iterator(Value - T(i));
+      return iterator(Traits::addOffset(Value, -i));
     }
     difference_type operator-(iterator rhs) const {
-      return difference_type(Value - rhs.Value);
+      return Traits::distance(rhs.Value, Value);
     }
-    T operator[](difference_type i) const { return Value + T(i);       }
+    T operator[](difference_type i) const {
+      return Traits::addOffset(Value, i);
+    }
     bool operator<(iterator rhs) const {    return Value <  rhs.Value; }
     bool operator<=(iterator rhs) const {   return Value <= rhs.Value; }
     bool operator>(iterator rhs) const {    return Value >  rhs.Value; }
@@ -134,26 +181,27 @@
   }
 
   bool empty() const { return Begin == End; }
-  size_t size() const { return End - Begin; }
+  size_t size() const { return size_t(Traits::distance(Begin, End)); }
   T operator[](size_t i) const {
     assert(i < size());
-    return Begin + i;
+    return Traits::addOffset(Begin, i);
   }
   T front() const { assert(!empty()); return Begin; }
-  T back() const { assert(!empty()); return End - 1; }
+  T back() const { assert(!empty()); return Traits::addOffset(End, -1); }
   IntRange drop_back(size_t length = 1) const {
     assert(length <= size());
-    return IntRange(Begin, End - length);
+    return IntRange(Begin, Traits::addOffset(End, -length));
   }
 
   IntRange slice(size_t start) const {
     assert(start <= size());
-    return IntRange(Begin + start, End);
+    return IntRange(Traits::addOffset(Begin, start), End);
   }
   IntRange slice(size_t start, size_t length) const {
     assert(start <= size());
-    return IntRange(Begin + start,
-                    Begin + start + std::min(length, End - (Begin + start)));
+    auto newBegin = Traits::addOffset(Begin, start);
+    auto newSize = std::min(length, size_t(Traits::distance(newBegin, End)));
+    return IntRange(newBegin, Traits::addOffset(newBegin, newSize));
   }
 
   bool operator==(IntRange other) const {
diff --git a/include/swift/IDE/SyntaxModel.h b/include/swift/IDE/SyntaxModel.h
index 138ce92..6e223c4 100644
--- a/include/swift/IDE/SyntaxModel.h
+++ b/include/swift/IDE/SyntaxModel.h
@@ -111,6 +111,7 @@
   ArrayExpression,
   DictionaryExpression,
   ObjectLiteralExpression,
+  TupleExpression
 };
 
 enum class SyntaxStructureElementKind : uint8_t {
diff --git a/include/swift/Option/Options.td b/include/swift/Option/Options.td
index 33d80e9..88bca35 100644
--- a/include/swift/Option/Options.td
+++ b/include/swift/Option/Options.td
@@ -641,6 +641,10 @@
   Flags<[FrontendOption, NoInteractiveOption]>,
   HelpText<"Generate instrumented code to collect execution counts">;
 
+def profile_use : CommaJoined<["-"], "profile-use=">,
+  Flags<[FrontendOption, NoInteractiveOption]>, MetaVarName<"<profdata>">,
+  HelpText<"Supply a profdata file to enable profile-guided optimization">;
+
 def profile_coverage_mapping : Flag<["-"], "profile-coverage-mapping">,
   Flags<[FrontendOption, NoInteractiveOption]>,
   HelpText<"Generate coverage data for use with profiled execution counts">;
diff --git a/include/swift/Reflection/MetadataSource.h b/include/swift/Reflection/MetadataSource.h
index 7b234b0..5fa9706 100644
--- a/include/swift/Reflection/MetadataSource.h
+++ b/include/swift/Reflection/MetadataSource.h
@@ -147,25 +147,6 @@
   }
 
   template <typename Allocator>
-  static const MetadataSource*
-  decodeParent(Allocator &A,
-               std::string::const_iterator &it,
-               const std::string::const_iterator &end) {
-    if (it == end || *it != 'P')
-      return nullptr;
-
-    ++it;
-    auto Child = decode(A, it, end);
-    if (!Child)
-      return nullptr;
-
-    if (it == end || *it != '_')
-      return nullptr;
-
-    return A.createParent(Child);
-  }
-
-  template <typename Allocator>
   static const MetadataSource *decode(Allocator &A,
                                       std::string::const_iterator &it,
                                       const std::string::const_iterator &end) {
@@ -180,8 +161,6 @@
         return decodeMetadataCapture(A, it, end);
       case 'G':
         return decodeGenericArgument(A, it, end);
-      case 'P':
-        return decodeParent(A, it, end);
       case 'S':
         ++it;
         return A.createSelf();
@@ -318,29 +297,6 @@
   }
 };
 
-/// Metadata gotten through the parent of a nominal type's metadata.
-class ParentMetadataSource final : public MetadataSource {
-  const MetadataSource *Child;
-public:
-  ParentMetadataSource(const MetadataSource *Child)
-    : MetadataSource(MetadataSourceKind::Parent),
-      Child(Child) {}
-
-  template <typename Allocator>
-  static const ParentMetadataSource*
-  create(Allocator &A, const MetadataSource *Child) {
-    return A.template make_source<ParentMetadataSource>(Child);
-  }
-
-  const MetadataSource *getChild() const {
-    return Child;
-  }
-
-  static bool classof(const MetadataSource *MS) {
-    return MS->getKind() == MetadataSourceKind::Parent;
-  }
-};
-
 /// A source of metadata from the Self metadata parameter passed via
 /// a witness_method convention function.
 class SelfMetadataSource final : public MetadataSource {
diff --git a/include/swift/Reflection/MetadataSourceBuilder.h b/include/swift/Reflection/MetadataSourceBuilder.h
index 2df9d85..3117b10 100644
--- a/include/swift/Reflection/MetadataSourceBuilder.h
+++ b/include/swift/Reflection/MetadataSourceBuilder.h
@@ -59,11 +59,6 @@
     return ClosureBindingMetadataSource::create(*this, Index);
   }
 
-  const ParentMetadataSource *
-  createParent(const MetadataSource *Child) {
-    return ParentMetadataSource::create(*this, Child);
-  }
-
   const SelfMetadataSource *
   createSelf() {
     return SelfMetadataSource::create(*this);
diff --git a/include/swift/Reflection/MetadataSources.def b/include/swift/Reflection/MetadataSources.def
index 60fe4ef..b4dfe28 100644
--- a/include/swift/Reflection/MetadataSources.def
+++ b/include/swift/Reflection/MetadataSources.def
@@ -20,6 +20,5 @@
 METADATA_SOURCE(ReferenceCapture, MetadataSource)
 METADATA_SOURCE(MetadataCapture, MetadataSource)
 METADATA_SOURCE(GenericArgument, MetadataSource)
-METADATA_SOURCE(Parent, MetadataSource)
 METADATA_SOURCE(Self, MetadataSource)
 METADATA_SOURCE(SelfWitnessTable, MetadataSource)
diff --git a/include/swift/Reflection/ReflectionContext.h b/include/swift/Reflection/ReflectionContext.h
index bc7a5c3..920c1d2 100644
--- a/include/swift/Reflection/ReflectionContext.h
+++ b/include/swift/Reflection/ReflectionContext.h
@@ -50,7 +50,6 @@
   using super::getBuilder;
   using super::readIsaMask;
   using super::readTypeFromMetadata;
-  using super::readParentFromMetadata;
   using super::readGenericArgFromMetadata;
   using super::readMetadataFromInstance;
   using typename super::StoredPointer;
@@ -460,10 +459,6 @@
       auto Base = cast<GenericArgumentMetadataSource>(MS)->getSource();
       return isMetadataSourceReady(Base, Builder);
     }
-    case MetadataSourceKind::Parent: {
-      auto Base = cast<ParentMetadataSource>(MS)->getChild();
-      return isMetadataSourceReady(Base, Builder);
-    }
     case MetadataSourceKind::Self:
     case MetadataSourceKind::SelfWitnessTable:
       return true;
@@ -548,19 +543,6 @@
 
       return Arg;
     }
-    case MetadataSourceKind::Parent: {
-      auto Base = readMetadataSource(Context,
-          cast<ParentMetadataSource>(MS)->getChild(),
-          Builder);
-      if (!Base.first)
-        break;
-
-      auto Parent = readParentFromMetadata(Base.second);
-      if (!Parent.first)
-        break;
-
-      return Parent;
-    }
     case MetadataSourceKind::Self:
     case MetadataSourceKind::SelfWitnessTable:
       break;
diff --git a/include/swift/Reflection/TypeRefBuilder.h b/include/swift/Reflection/TypeRefBuilder.h
index 2be00c3..b339432 100644
--- a/include/swift/Reflection/TypeRefBuilder.h
+++ b/include/swift/Reflection/TypeRefBuilder.h
@@ -178,6 +178,11 @@
   }
 
   const NominalTypeRef *createNominalType(
+                                    const Optional<std::string> &mangledName) {
+    return NominalTypeRef::create(*this, *mangledName, nullptr);
+  }
+
+  const NominalTypeRef *createNominalType(
                                     const Optional<std::string> &mangledName,
                                     const TypeRef *parent) {
     return NominalTypeRef::create(*this, *mangledName, parent);
@@ -185,6 +190,12 @@
 
   const BoundGenericTypeRef *
   createBoundGenericType(const Optional<std::string> &mangledName,
+                         const std::vector<const TypeRef *> &args) {
+    return BoundGenericTypeRef::create(*this, *mangledName, args, nullptr);
+  }
+
+  const BoundGenericTypeRef *
+  createBoundGenericType(const Optional<std::string> &mangledName,
                          const std::vector<const TypeRef *> &args,
                          const TypeRef *parent) {
     return BoundGenericTypeRef::create(*this, *mangledName, args, parent);
diff --git a/include/swift/Remote/MetadataReader.h b/include/swift/Remote/MetadataReader.h
index 396e964..d26bc9f 100644
--- a/include/swift/Remote/MetadataReader.h
+++ b/include/swift/Remote/MetadataReader.h
@@ -934,33 +934,6 @@
     swift_runtime_unreachable("Unhandled IsaEncodingKind in switch.");
   }
 
-  /// Read the parent type metadata from a nested nominal type metadata.
-  std::pair<bool, StoredPointer>
-  readParentFromMetadata(StoredPointer metadata) {
-    auto Meta = readMetadata(metadata);
-    if (!Meta)
-      return std::make_pair(false, 0);
-
-    auto descriptorAddress = readAddressOfNominalTypeDescriptor(Meta);
-    if (!descriptorAddress)
-      return std::make_pair(false, 0);
-
-    // Read the nominal type descriptor.
-    auto descriptor = readNominalTypeDescriptor(descriptorAddress);
-    if (!descriptor)
-      return std::make_pair(false, 0);
-
-    // Read the parent type if the type has one.
-    if (descriptor->GenericParams.Flags.hasParent()) {
-      StoredPointer parentAddress = getNominalParent(Meta, descriptor);
-      if (!parentAddress)
-        return std::make_pair(false, 0);
-      return std::make_pair(true, parentAddress);
-    }
-
-    return std::make_pair(false, 0);
-  }
-
   /// Read a single generic type argument from a bound generic type
   /// metadata.
   std::pair<bool, StoredPointer>
@@ -1308,32 +1281,6 @@
     return OwnedProtocolDescriptorRef(Casted);
   }
 
-  StoredPointer getNominalParent(MetadataRef metadata,
-                                 NominalTypeDescriptorRef descriptor) {
-    // If this is metadata for some sort of value type, the parent type
-    // is at a fixed offset.
-    if (auto valueMetadata = dyn_cast<TargetValueMetadata<Runtime>>(metadata)) {
-      return valueMetadata->Parent;
-    }
-
-    // If this is metadata for a class type, the parent type for the
-    // most-derived class is at an offset stored in the most-derived
-    // nominal type descriptor.
-    if (auto classMetadata = dyn_cast<TargetClassMetadata<Runtime>>(metadata)) {
-      // If it does, it's immediately before the generic parameters.
-      auto offsetToParent
-        = sizeof(StoredPointer) * (descriptor->GenericParams.Offset - 1);
-      RemoteAddress addressOfParent(metadata.getAddress() + offsetToParent);
-      StoredPointer parentAddress;
-      if (!Reader->readInteger(addressOfParent, &parentAddress))
-        return StoredPointer();
-      return parentAddress;
-    }
-
-    // Otherwise, we don't know how to access its parent.  This is a failure.
-    return StoredPointer();
-  }
-
   std::vector<BuiltType>
   getGenericSubst(MetadataRef metadata, NominalTypeDescriptorRef descriptor) {
     std::vector<BuiltType> substitutions;
@@ -1387,23 +1334,13 @@
     if (!typeDecl)
       return BuiltType();
 
-    // Read the parent type if the type has one.
-    BuiltType parent = BuiltType();
-    if (descriptor->GenericParams.Flags.hasParent()) {
-      StoredPointer parentAddress = getNominalParent(metadata, descriptor);
-      if (!parentAddress)
-        return BuiltType();
-      parent = readTypeFromMetadata(parentAddress);
-      if (!parent) return BuiltType();
-    }
-
     BuiltType nominal;
     if (descriptor->GenericParams.NumPrimaryParams) {
       auto args = getGenericSubst(metadata, descriptor);
       if (args.empty()) return BuiltType();
-      nominal = Builder.createBoundGenericType(typeDecl, args, parent);
+      nominal = Builder.createBoundGenericType(typeDecl, args);
     } else {
-      nominal = Builder.createNominalType(typeDecl, parent);
+      nominal = Builder.createNominalType(typeDecl);
     }
     if (!nominal) return BuiltType();
 
diff --git a/include/swift/Runtime/Metadata.h b/include/swift/Runtime/Metadata.h
index 87ccf64..5207f0c 100644
--- a/include/swift/Runtime/Metadata.h
+++ b/include/swift/Runtime/Metadata.h
@@ -1102,6 +1102,13 @@
 };
 using HeapMetadata = TargetHeapMetadata<InProcess>;
 
+struct GenericContextDescriptor {
+  /// The number of primary type parameters. This is always less than or equal
+  /// to NumGenericRequirements; it counts only the type parameters
+  /// and not any required witness tables.
+  uint32_t NumPrimaryParams;
+};
+
 /// Header for a generic parameter descriptor. This is a variable-sized
 /// structure that describes how to find and parse a generic parameter vector
 /// within the type metadata for an instance of a nominal type.
@@ -1109,8 +1116,7 @@
   /// The offset to the first generic argument from the start of
   /// metadata record.
   ///
-  /// This is meaningful if either NumGenericRequirements is nonzero or
-  /// (for classes) if Flags.hasParent() is true.
+  /// This is meaningful if NumGenericRequirements is nonzero.
   uint32_t Offset;
 
   /// The amount of generic requirement data in the metadata record, in
@@ -1126,6 +1132,10 @@
   /// and not any required witness tables.
   uint32_t NumPrimaryParams;
 
+  /// The number of types that this type is nested inside of, including itself
+  /// (so this value is at least 1).
+  uint16_t NestingDepth;
+
   /// Flags for this generic parameter descriptor.
   GenericParameterDescriptorFlags Flags;
 
@@ -1135,7 +1145,12 @@
 
   /// True if the nominal type is generic in any way.
   bool isGeneric() const {
-    return hasGenericRequirements() || Flags.hasGenericParent();
+    return hasGenericRequirements();
+  }
+
+  GenericContextDescriptor getContext(unsigned depth) const {
+    assert(depth < NestingDepth);
+    return ((const GenericContextDescriptor *)(this + 1))[depth];
   }
 
   // TODO: add meaningful descriptions of the generic requirements.
@@ -1316,12 +1331,13 @@
         !GenericParams.Flags.hasVTable())
       return nullptr;
 
-    auto asWords = reinterpret_cast<const void * const*>(this + 1);
+    auto asWords = reinterpret_cast<const uint32_t *>(this + 1);
 
     // TODO: Once we emit reflective descriptions of generic requirements,
     // skip the right number of words here.
 
-    return reinterpret_cast<const VTableDescriptor *>(asWords);
+    return reinterpret_cast<const VTableDescriptor *>(asWords
+        + GenericParams.NestingDepth);
   }
 
   /// The generic parameter descriptor header. This describes how to find and
@@ -1567,17 +1583,6 @@
     return getter(this);
   }
 
-  /// Return the parent type for a given level in the class hierarchy, or
-  /// null if that level does not have a parent type.
-  const TargetMetadata<Runtime> *
-  getParentType(const TargetNominalTypeDescriptor<Runtime> *theClass) const {
-    if (!theClass->GenericParams.Flags.hasParent())
-      return nullptr;
-
-    auto metadataAsWords = reinterpret_cast<const Metadata * const *>(this);
-    return metadataAsWords[theClass->GenericParams.Offset - 1];
-  }
-
   StoredPointer offsetToDescriptorOffset() const {
     return offsetof(TargetClassMetadata<Runtime>, Description);
   }
@@ -1745,22 +1750,15 @@
   using StoredPointer = typename Runtime::StoredPointer;
   TargetValueMetadata(MetadataKind Kind,
     ConstTargetMetadataPointer<Runtime, TargetNominalTypeDescriptor>
-                      description,
-    ConstTargetMetadataPointer<Runtime, swift::TargetMetadata> parent)
+                      description)
     : TargetMetadata<Runtime>(Kind),
-      Description(description),
-      Parent(parent)
+      Description(description)
   {}
 
   /// An out-of-line description of the type.
   ConstTargetFarRelativeDirectPointer<Runtime, TargetNominalTypeDescriptor>
   Description;
 
-  /// The parent type of this member type, or null if this is not a
-  /// member type.  It's acceptable to make this a direct pointer because
-  /// parent types are relatively uncommon.
-  TargetPointer<Runtime, const TargetMetadata<Runtime>> Parent;
-
   static bool classof(const TargetMetadata<Runtime> *metadata) {
     return metadata->getKind() == MetadataKind::Struct
       || metadata->getKind() == MetadataKind::Enum
@@ -1785,11 +1783,6 @@
   StoredPointer offsetToDescriptorOffset() const {
     return offsetof(TargetValueMetadata<Runtime>, Description);
   }
-
-  StoredPointer offsetToParentOffset() const {
-    return offsetof(TargetValueMetadata<Runtime>, Parent);
-  }
-  
 };
 using ValueMetadata = TargetValueMetadata<InProcess>;
 
diff --git a/include/swift/SIL/DebugUtils.h b/include/swift/SIL/DebugUtils.h
index b8cbb76..3df6dd5 100644
--- a/include/swift/SIL/DebugUtils.h
+++ b/include/swift/SIL/DebugUtils.h
@@ -143,6 +143,16 @@
   return NonDebugUses.begin() == NonDebugUses.end();
 }
 
+/// Return true if all of the results of the given instruction have no uses
+/// except debug instructions.
+inline bool onlyHaveDebugUsesOfAllResults(SILInstruction *I) {
+  for (auto result : I->getResults()) {
+    if (!onlyHaveDebugUses(result))
+      return false;
+  }
+  return true;
+}
+
 /// Returns true if a value (e.g. SILInstruction) has exactly one use which is
 /// not a debug instruction.
 inline bool hasOneNonDebugUse(SILValue V) {
@@ -169,16 +179,26 @@
 /// incremented.
 inline void eraseFromParentWithDebugInsts(SILInstruction *I,
                                           SILBasicBlock::iterator &InstIter) {
-  while (!I->use_empty()) {
-    auto *User = I->use_begin()->getUser();
-    assert(isDebugInst(User));
-    if (InstIter != SILBasicBlock::iterator() &&
-        InstIter != I->getParent()->end() &&
-        &*InstIter == User) {
-      InstIter++;
+  auto results = I->getResults();
+
+  bool foundAny;
+  do {
+    foundAny = false;
+    for (auto result : results) {
+      while (!result->use_empty()) {
+        foundAny = true;
+        auto *User = result->use_begin()->getUser();
+        assert(isDebugInst(User));
+        if (InstIter != SILBasicBlock::iterator() &&
+            InstIter != I->getParent()->end() &&
+            &*InstIter == User) {
+          InstIter++;
+        }
+        User->eraseFromParent();
+      }
     }
-    User->eraseFromParent();
-  }
+  } while (foundAny);
+
   I->eraseFromParent();
 }
 
diff --git a/include/swift/SIL/DynamicCasts.h b/include/swift/SIL/DynamicCasts.h
index 8f33fd7..aa46086 100644
--- a/include/swift/SIL/DynamicCasts.h
+++ b/include/swift/SIL/DynamicCasts.h
@@ -18,6 +18,8 @@
 #ifndef SWIFT_SIL_DYNAMICCASTS_H
 #define SWIFT_SIL_DYNAMICCASTS_H
 
+#include "swift/Basic/ProfileCounter.h"
+
 namespace swift {
 
 class CanType;
@@ -78,10 +80,10 @@
 /// using a scalar cast operation.
 void emitIndirectConditionalCastWithScalar(
     SILBuilder &B, ModuleDecl *M, SILLocation loc,
-    CastConsumptionKind consumption,
-    SILValue src, CanType sourceType,
-    SILValue dest, CanType targetType,
-    SILBasicBlock *trueBB, SILBasicBlock *falseBB);
+    CastConsumptionKind consumption, SILValue src, CanType sourceType,
+    SILValue dest, CanType targetType, SILBasicBlock *trueBB,
+    SILBasicBlock *falseBB, ProfileCounter TrueCount = ProfileCounter(),
+    ProfileCounter FalseCount = ProfileCounter());
 
 /// \brief Does the type conform to the _ObjectiveCBridgeable protocol.
 bool isObjectiveCBridgeable(ModuleDecl *M, CanType Ty);
diff --git a/include/swift/SIL/Notifications.h b/include/swift/SIL/Notifications.h
index 49f9980..e51c208 100644
--- a/include/swift/SIL/Notifications.h
+++ b/include/swift/SIL/Notifications.h
@@ -15,7 +15,7 @@
 
 namespace swift {
 
-class ValueBase;
+class SILNode;
 
 /// A protocol (or interface) for handling value deletion notifications.
 ///
@@ -29,7 +29,7 @@
   virtual ~DeleteNotificationHandler() {}
 
   /// Handle the invalidation message for the value \p Value.
-  virtual void handleDeleteNotification(swift::ValueBase *Value) { }
+  virtual void handleDeleteNotification(SILNode *value) { }
 
   /// Returns True if the pass, analysis or other entity wants to receive
   /// notifications. This callback is called once when the class is being
diff --git a/include/swift/SIL/PatternMatch.h b/include/swift/SIL/PatternMatch.h
index 85624de..bf4f912 100644
--- a/include/swift/SIL/PatternMatch.h
+++ b/include/swift/SIL/PatternMatch.h
@@ -296,19 +296,24 @@
 //                             Unary Instructions
 //===----------------------------------------------------------------------===//
 
-template<typename OpMatchTy, ValueKind Kind>
+template<typename OpMatchTy, SILInstructionKind Kind>
 struct UnaryOp_match {
   OpMatchTy OpMatch;
 
   UnaryOp_match(const OpMatchTy &Op) : OpMatch(Op) { }
 
-  template<typename OpTy>
-  bool match(OpTy *V) {
-    if (V->getKind() != Kind)
+  bool match(SILNode *node) {
+    if (node->getKind() != SILNodeKind(Kind))
       return false;
 
-    auto *I = dyn_cast<SILInstruction>(V);
-    if (!I || I->getNumOperands() != 1)
+    return match(cast<SILInstruction>(node));
+  }
+
+  bool match(SILInstruction *I) {
+    if (I->getKind() != Kind)
+      return false;
+
+    if (I->getNumOperands() != 1)
       return false;
 
     return OpMatch.match(I->getOperand(0));
@@ -319,7 +324,7 @@
 // further matchers to the operands of the unary operation.
 #define UNARY_OP_MATCH_WITH_ARG_MATCHER(Class)        \
   template <typename Ty>                              \
-  UnaryOp_match<Ty, ValueKind::Class>                 \
+  UnaryOp_match<Ty, SILInstructionKind::Class>        \
   m_##Class(const Ty &T) {                            \
     return T;                                         \
   }
@@ -393,20 +398,25 @@
 //                            Binary Instructions
 //===----------------------------------------------------------------------===//
 
-template<typename LHSTy, typename RHSTy, ValueKind Kind>
+template<typename LHSTy, typename RHSTy, SILInstructionKind Kind>
 struct BinaryOp_match {
   LHSTy L;
   RHSTy R;
 
   BinaryOp_match(const LHSTy &LHS, const RHSTy &RHS) : L(LHS), R(RHS) {}
 
-  template<typename OpTy>
-  bool match(OpTy *V) {
-    if (V->getKind() != Kind)
+  bool match(SILNode *node) {
+    if (node->getKind() != SILNodeKind(Kind))
       return false;
 
-    auto *I = dyn_cast<SILInstruction>(V);
-    if (!I || I->getNumOperands() != 2)
+    return match(cast<SILInstruction>(node));
+  }
+
+  bool match(SILInstruction *I) {
+    if (I->getKind() != Kind)
+      return false;
+
+    if (I->getNumOperands() != 2)
       return false;
 
     return L.match((ValueBase *)I->getOperand(0)) &&
@@ -415,7 +425,7 @@
 };
 
 template <typename LTy, typename RTy>
-BinaryOp_match<LTy, RTy, ValueKind::IndexRawPointerInst>
+BinaryOp_match<LTy, RTy, SILInstructionKind::IndexRawPointerInst>
 m_IndexRawPointerInst(const LTy &Left, const RTy &Right) {
   return {Left, Right};
 }
diff --git a/include/swift/SIL/Projection.h b/include/swift/SIL/Projection.h
index c42274d..2371cb7 100644
--- a/include/swift/SIL/Projection.h
+++ b/include/swift/SIL/Projection.h
@@ -228,8 +228,10 @@
   Projection() = delete;
 
   explicit Projection(SILValue V)
-      : Projection(dyn_cast<SILInstruction>(V)) {}
-  explicit Projection(SILInstruction *I);
+      : Projection(dyn_cast<SingleValueInstruction>(V)) {}
+  explicit Projection(SILInstruction *I)
+      : Projection(dyn_cast<SingleValueInstruction>(I)) {}
+  explicit Projection(SingleValueInstruction *I);
 
   Projection(ProjectionKind Kind, unsigned NewIndex)
       : Value(Kind, NewIndex) {}
@@ -255,7 +257,7 @@
 
   /// Determine if I is a value projection instruction whose corresponding
   /// projection equals this projection.
-  bool matchesObjectProjection(SILInstruction *I) const {
+  bool matchesObjectProjection(SingleValueInstruction *I) const {
     Projection P(I);
     return P.isValid() && P == *this;
   }
@@ -264,17 +266,17 @@
   /// type differences and this Projection is representable as a value
   /// projection, create the relevant value projection and return it. Otherwise,
   /// return nullptr.
-  NullablePtr<SILInstruction>
+  NullablePtr<SingleValueInstruction>
   createObjectProjection(SILBuilder &B, SILLocation Loc, SILValue Base) const;
 
   /// If Base's type matches this Projections type ignoring Address vs Object
   /// type differences and this projection is representable as an address
   /// projection, create the relevant address projection and return
   /// it. Otherwise, return nullptr.
-  NullablePtr<SILInstruction>
+  NullablePtr<SingleValueInstruction>
   createAddressProjection(SILBuilder &B, SILLocation Loc, SILValue Base) const;
 
-  NullablePtr<SILInstruction>
+  NullablePtr<SingleValueInstruction>
   createProjection(SILBuilder &B, SILLocation Loc, SILValue Base) const {
     if (Base->getType().isAddress()) {
       return createAddressProjection(B, Loc, Base);
@@ -370,13 +372,16 @@
 
   /// Returns true if this instruction projects from an address type to an
   /// address subtype.
-  static bool isAddressProjection(SILValue V) {
+  static SingleValueInstruction *isAddressProjection(SILValue V) {
     switch (V->getKind()) {
     default:
-      return false;
+      return nullptr;
     case ValueKind::IndexAddrInst: {
+      auto I = cast<IndexAddrInst>(V);
       unsigned Scalar;
-      return getIntegerIndex(cast<IndexAddrInst>(V)->getIndex(), Scalar);
+      if (getIntegerIndex(I->getIndex(), Scalar))
+        return I;
+      return nullptr;
     }
     case ValueKind::StructElementAddrInst:
     case ValueKind::RefElementAddrInst:
@@ -384,20 +389,20 @@
     case ValueKind::ProjectBoxInst:
     case ValueKind::TupleElementAddrInst:
     case ValueKind::UncheckedTakeEnumDataAddrInst:
-      return true;
+      return cast<SingleValueInstruction>(V);
     }
   }
 
   /// Returns true if this instruction projects from an object type to an object
   /// subtype.
-  static bool isObjectProjection(SILValue V) {
+  static SingleValueInstruction *isObjectProjection(SILValue V) {
     switch (V->getKind()) {
     default:
-      return false;
+      return nullptr;
     case ValueKind::StructExtractInst:
     case ValueKind::TupleExtractInst:
     case ValueKind::UncheckedEnumDataInst:
-      return true;
+      return cast<SingleValueInstruction>(V);
     }
   }
 
@@ -465,7 +470,7 @@
   /// This can be used with getFirstLevelProjections to project out/reform
   /// values. We do not need to use the original projections here since to build
   /// aggregate instructions the order is the only important thing.
-  static NullablePtr<SILInstruction>
+  static NullablePtr<SingleValueInstruction>
   createAggFromFirstLevelProjections(SILBuilder &B, SILLocation Loc,
                                      SILType BaseType,
                                      llvm::SmallVectorImpl<SILValue> &Values);
@@ -788,10 +793,10 @@
   ProjectionTreeNode *getChildForProjection(ProjectionTree &Tree,
                                                const Projection &P);
 
-  NullablePtr<SILInstruction> createProjection(SILBuilder &B, SILLocation Loc,
-                                               SILValue Arg) const;
+  NullablePtr<SingleValueInstruction>
+  createProjection(SILBuilder &B, SILLocation Loc, SILValue Arg) const;
 
-  SILInstruction *
+  SingleValueInstruction *
   createAggregate(SILBuilder &B, SILLocation Loc,
                   ArrayRef<SILValue> Args) const;
 
diff --git a/include/swift/SIL/SILArgument.h b/include/swift/SIL/SILArgument.h
index c7ec76e..34764b4 100644
--- a/include/swift/SIL/SILArgument.h
+++ b/include/swift/SIL/SILArgument.h
@@ -22,6 +22,7 @@
 
 class SILBasicBlock;
 class SILModule;
+class SILUndef;
 
 // Map an argument index onto a SILArgumentConvention.
 inline SILArgumentConvention
@@ -58,9 +59,11 @@
 
   const ValueDecl *getDecl() const { return Decl; }
 
-  static bool classof(const ValueBase *V) {
-    return V->getKind() >= ValueKind::First_SILArgument &&
-           V->getKind() <= ValueKind::Last_SILArgument;
+  static bool classof(const SILInstruction *) = delete;
+  static bool classof(const SILUndef *) = delete;
+  static bool classof(const SILNode *node) {
+    return node->getKind() >= SILNodeKind::First_SILArgument &&
+           node->getKind() <= SILNodeKind::Last_SILArgument;
   }
 
   unsigned getIndex() const {
@@ -165,8 +168,10 @@
   /// payload argument is the enum itself (the operand of the switch_enum).
   SILValue getSingleIncomingValue() const;
 
-  static bool classof(const ValueBase *V) {
-    return V->getKind() == ValueKind::SILPHIArgument;
+  static bool classof(const SILInstruction *) = delete;
+  static bool classof(const SILUndef *) = delete;
+  static bool classof(const SILNode *node) {
+    return node->getKind() == SILNodeKind::SILPHIArgument;
   }
 
 private:
@@ -216,8 +221,10 @@
     return getArgumentConvention() == P;
   }
 
-  static bool classof(const ValueBase *V) {
-    return V->getKind() == ValueKind::SILFunctionArgument;
+  static bool classof(const SILInstruction *) = delete;
+  static bool classof(const SILUndef *) = delete;
+  static bool classof(const SILNode *node) {
+    return node->getKind() == SILNodeKind::SILFunctionArgument;
   }
 
 private:
diff --git a/include/swift/SIL/SILBasicBlock.h b/include/swift/SIL/SILBasicBlock.h
index 6f861e3..ae02555 100644
--- a/include/swift/SIL/SILBasicBlock.h
+++ b/include/swift/SIL/SILBasicBlock.h
@@ -389,13 +389,7 @@
       I.dropAllReferences();
   }
 
-  void eraseInstructions() {
-   for (auto It = begin(); It != end();) {
-      auto *Inst = &*It++;
-      Inst->replaceAllUsesWithUndef();
-      Inst->eraseFromParent();
-    }
-  }
+  void eraseInstructions();
 
 private:
   friend class SILArgument;
diff --git a/include/swift/SIL/SILBuilder.h b/include/swift/SIL/SILBuilder.h
index 58c86d9..b075883 100644
--- a/include/swift/SIL/SILBuilder.h
+++ b/include/swift/SIL/SILBuilder.h
@@ -13,6 +13,7 @@
 #ifndef SWIFT_SIL_SILBUILDER_H
 #define SWIFT_SIL_SILBUILDER_H
 
+#include "swift/Basic/ProfileCounter.h"
 #include "swift/SIL/SILArgument.h"
 #include "swift/SIL/SILDebugScope.h"
 #include "swift/SIL/SILFunction.h"
@@ -1084,27 +1085,33 @@
         getSILDebugLocation(Loc), Operand, Element));
   }
 
-  SelectEnumInst *createSelectEnum(
-      SILLocation Loc, SILValue Operand, SILType Ty, SILValue DefaultValue,
-      ArrayRef<std::pair<EnumElementDecl *, SILValue>> CaseValues) {
-    return insert(SelectEnumInst::create(getSILDebugLocation(Loc), Operand,
-                                 Ty, DefaultValue, CaseValues, getFunction()));
+  SelectEnumInst *
+  createSelectEnum(SILLocation Loc, SILValue Operand, SILType Ty,
+                   SILValue DefaultValue,
+                   ArrayRef<std::pair<EnumElementDecl *, SILValue>> CaseValues,
+                   Optional<ArrayRef<ProfileCounter>> CaseCounts = None,
+                   ProfileCounter DefaultCount = ProfileCounter()) {
+    return insert(SelectEnumInst::create(
+        getSILDebugLocation(Loc), Operand, Ty, DefaultValue, CaseValues,
+        getFunction(), CaseCounts, DefaultCount));
   }
 
   SelectEnumAddrInst *createSelectEnumAddr(
       SILLocation Loc, SILValue Operand, SILType Ty, SILValue DefaultValue,
-      ArrayRef<std::pair<EnumElementDecl *, SILValue>> CaseValues) {
+      ArrayRef<std::pair<EnumElementDecl *, SILValue>> CaseValues,
+      Optional<ArrayRef<ProfileCounter>> CaseCounts = None,
+      ProfileCounter DefaultCount = ProfileCounter()) {
     return insert(SelectEnumAddrInst::create(
         getSILDebugLocation(Loc), Operand, Ty, DefaultValue, CaseValues,
-                                             getFunction()));
+        getFunction(), CaseCounts, DefaultCount));
   }
 
   SelectValueInst *createSelectValue(
       SILLocation Loc, SILValue Operand, SILType Ty, SILValue DefaultResult,
       ArrayRef<std::pair<SILValue, SILValue>> CaseValuesAndResults) {
-    return insert(SelectValueInst::create(getSILDebugLocation(Loc), Operand,
-                                          Ty, DefaultResult,
-                                          CaseValuesAndResults, getFunction()));
+    return insert(SelectValueInst::create(getSILDebugLocation(Loc), Operand, Ty,
+                                          DefaultResult, CaseValuesAndResults,
+                                          getFunction()));
   }
 
   TupleExtractInst *createTupleExtract(SILLocation Loc, SILValue Operand,
@@ -1525,12 +1532,12 @@
   // Create an UncheckedRefCast if the source and dest types are legal,
   // otherwise return null.
   // Unwrap or wrap optional types as needed.
-  SILInstruction *tryCreateUncheckedRefCast(SILLocation Loc, SILValue Op,
-                                            SILType ResultTy);
+  SingleValueInstruction *tryCreateUncheckedRefCast(SILLocation Loc, SILValue Op,
+                                                    SILType ResultTy);
 
   // Create the appropriate cast instruction based on result type.
-  SILInstruction *createUncheckedBitCast(SILLocation Loc, SILValue Op,
-                                         SILType Ty);
+  SingleValueInstruction *createUncheckedBitCast(SILLocation Loc, SILValue Op,
+                                                 SILType Ty);
 
   //===--------------------------------------------------------------------===//
   // Runtime failure
@@ -1589,28 +1596,33 @@
         new (getModule()) ThrowInst(getSILDebugLocation(Loc), errorValue));
   }
 
-  CondBranchInst *createCondBranch(SILLocation Loc, SILValue Cond,
-                                   SILBasicBlock *Target1,
-                                   SILBasicBlock *Target2) {
-    return insertTerminator(CondBranchInst::create(getSILDebugLocation(Loc),
-                                       Cond, Target1, Target2, getFunction()));
+  CondBranchInst *
+  createCondBranch(SILLocation Loc, SILValue Cond, SILBasicBlock *Target1,
+                   SILBasicBlock *Target2,
+                   ProfileCounter Target1Count = ProfileCounter(),
+                   ProfileCounter Target2Count = ProfileCounter()) {
+    return insertTerminator(
+        CondBranchInst::create(getSILDebugLocation(Loc), Cond, Target1, Target2,
+                               Target1Count, Target2Count, getFunction()));
   }
 
-  CondBranchInst *createCondBranch(SILLocation Loc, SILValue Cond,
-                                   SILBasicBlock *Target1,
-                                   ArrayRef<SILValue> Args1,
-                                   SILBasicBlock *Target2,
-                                   ArrayRef<SILValue> Args2) {
-    return insertTerminator(CondBranchInst::create(
-        getSILDebugLocation(Loc), Cond, Target1, Args1, Target2, Args2,
-                            getFunction()));
+  CondBranchInst *
+  createCondBranch(SILLocation Loc, SILValue Cond, SILBasicBlock *Target1,
+                   ArrayRef<SILValue> Args1, SILBasicBlock *Target2,
+                   ArrayRef<SILValue> Args2,
+                   ProfileCounter Target1Count = ProfileCounter(),
+                   ProfileCounter Target2Count = ProfileCounter()) {
+    return insertTerminator(
+        CondBranchInst::create(getSILDebugLocation(Loc), Cond, Target1, Args1,
+                               Target2, Args2, Target1Count, Target2Count, getFunction()));
   }
 
-  CondBranchInst *createCondBranch(SILLocation Loc, SILValue Cond,
-                                   SILBasicBlock *Target1,
-                                   OperandValueArrayRef Args1,
-                                   SILBasicBlock *Target2,
-                                   OperandValueArrayRef Args2) {
+  CondBranchInst *
+  createCondBranch(SILLocation Loc, SILValue Cond, SILBasicBlock *Target1,
+                   OperandValueArrayRef Args1, SILBasicBlock *Target2,
+                   OperandValueArrayRef Args2,
+                   ProfileCounter Target1Count = ProfileCounter(),
+                   ProfileCounter Target2Count = ProfileCounter()) {
     SmallVector<SILValue, 6> ArgsCopy1;
     SmallVector<SILValue, 6> ArgsCopy2;
 
@@ -1622,10 +1634,9 @@
     for (auto I = Args2.begin(), E = Args2.end(); I != E; ++I)
       ArgsCopy2.push_back(*I);
 
-    return insertTerminator(CondBranchInst::create(getSILDebugLocation(Loc),
-                                                   Cond, Target1, ArgsCopy1,
-                                                   Target2, ArgsCopy2,
-                                                   getFunction()));
+    return insertTerminator(CondBranchInst::create(
+        getSILDebugLocation(Loc), Cond, Target1, ArgsCopy1, Target2, ArgsCopy2,
+        Target1Count, Target2Count, getFunction()));
   }
 
   BranchInst *createBranch(SILLocation Loc, SILBasicBlock *TargetBlock) {
@@ -1652,16 +1663,22 @@
 
   SwitchEnumInst *createSwitchEnum(
       SILLocation Loc, SILValue Operand, SILBasicBlock *DefaultBB,
-      ArrayRef<std::pair<EnumElementDecl *, SILBasicBlock *>> CaseBBs) {
+      ArrayRef<std::pair<EnumElementDecl *, SILBasicBlock *>> CaseBBs,
+      Optional<ArrayRef<ProfileCounter>> CaseCounts = None,
+      ProfileCounter DefaultCount = ProfileCounter()) {
     return insertTerminator(SwitchEnumInst::create(
-        getSILDebugLocation(Loc), Operand, DefaultBB, CaseBBs, getFunction()));
+        getSILDebugLocation(Loc), Operand, DefaultBB, CaseBBs, getFunction(),
+        CaseCounts, DefaultCount));
   }
 
   SwitchEnumAddrInst *createSwitchEnumAddr(
       SILLocation Loc, SILValue Operand, SILBasicBlock *DefaultBB,
-      ArrayRef<std::pair<EnumElementDecl *, SILBasicBlock *>> CaseBBs) {
+      ArrayRef<std::pair<EnumElementDecl *, SILBasicBlock *>> CaseBBs,
+      Optional<ArrayRef<ProfileCounter>> CaseCounts = None,
+      ProfileCounter DefaultCount = ProfileCounter()) {
     return insertTerminator(SwitchEnumAddrInst::create(
-        getSILDebugLocation(Loc), Operand, DefaultBB, CaseBBs, getFunction()));
+        getSILDebugLocation(Loc), Operand, DefaultBB, CaseBBs, getFunction(),
+        CaseCounts, DefaultCount));
   }
 
   DynamicMethodBranchInst *
@@ -1673,13 +1690,15 @@
                               Member, HasMethodBB, NoMethodBB, getFunction()));
   }
 
-  CheckedCastBranchInst *createCheckedCastBranch(SILLocation Loc, bool isExact,
-                                                 SILValue op, SILType destTy,
-                                                 SILBasicBlock *successBB,
-                                                 SILBasicBlock *failureBB) {
+  CheckedCastBranchInst *
+  createCheckedCastBranch(SILLocation Loc, bool isExact, SILValue op,
+                          SILType destTy, SILBasicBlock *successBB,
+                          SILBasicBlock *failureBB,
+                          ProfileCounter Target1Count = ProfileCounter(),
+                          ProfileCounter Target2Count = ProfileCounter()) {
     return insertTerminator(CheckedCastBranchInst::create(
         getSILDebugLocation(Loc), isExact, op, destTy, successBB, failureBB,
-        getFunction(), OpenedArchetypes));
+        getFunction(), OpenedArchetypes, Target1Count, Target2Count));
   }
 
   CheckedCastValueBranchInst *
@@ -1695,10 +1714,12 @@
   createCheckedCastAddrBranch(SILLocation Loc, CastConsumptionKind consumption,
                               SILValue src, CanType sourceType, SILValue dest,
                               CanType targetType, SILBasicBlock *successBB,
-                              SILBasicBlock *failureBB) {
+                              SILBasicBlock *failureBB,
+                              ProfileCounter Target1Count = ProfileCounter(),
+                              ProfileCounter Target2Count = ProfileCounter()) {
     return insertTerminator(new (getModule()) CheckedCastAddrBranchInst(
         getSILDebugLocation(Loc), consumption, src, sourceType, dest,
-        targetType, successBB, failureBB));
+        targetType, successBB, failureBB, Target1Count, Target2Count));
   }
 
   //===--------------------------------------------------------------------===//
diff --git a/include/swift/SIL/SILCloner.h b/include/swift/SIL/SILCloner.h
index 6e05444..a3f2bfa 100644
--- a/include/swift/SIL/SILCloner.h
+++ b/include/swift/SIL/SILCloner.h
@@ -35,11 +35,12 @@
 /// basic block, or function; subclasses that want to handle those should
 /// implement the appropriate visit functions and/or provide other entry points.
 template<typename ImplClass>
-class SILCloner : protected SILVisitor<ImplClass> {
-  friend class SILVisitor<ImplClass, SILValue>;
+class SILCloner : protected SILInstructionVisitor<ImplClass> {
+  friend class SILVisitorBase<ImplClass>;
+  friend class SILInstructionVisitor<ImplClass>;
 
 public:
-  using SILVisitor<ImplClass>::asImpl;
+  using SILInstructionVisitor<ImplClass>::asImpl;
 
   explicit SILCloner(SILFunction &F,
                      SILOpenedArchetypesTracker &OpenedArchetypesTracker)
@@ -70,19 +71,13 @@
   SILBuilder &getBuilder() { return Builder; }
 
 protected:
-  void beforeVisit(ValueBase *V) {
-    if (auto I = dyn_cast<SILInstruction>(V)) {
-      // Update the set of available opened archetypes with the opened
-      // archetypes used by the current instruction.
-     doPreProcess(I);
-    }
+  void beforeVisit(SILInstruction *I) {
+    // Update the set of available opened archetypes with the opened
+    // archetypes used by the current instruction.
+    doPreProcess(I);
   }
 
-#define VALUE(CLASS, PARENT) \
-  void visit##CLASS(CLASS *I) {                                       \
-    llvm_unreachable("SILCloner visiting non-instruction?");          \
-  }
-#define INST(CLASS, PARENT, TEXTUALNAME, MEMBEHAVIOR, RELEASINGBEHAVIOR)       \
+#define INST(CLASS, PARENT) \
   void visit##CLASS(CLASS *I);
 #include "swift/SIL/SILNodes.def"
 
@@ -250,7 +245,6 @@
   SILBuilder Builder;
   SILBasicBlock *InsertBeforeBB;
   llvm::DenseMap<SILValue, SILValue> ValueMap;
-  llvm::DenseMap<SILInstruction*, SILInstruction*> InstructionMap;
 
   // Use MapVector to ensure that the order of block predecessors is
   // deterministic.
@@ -352,13 +346,6 @@
   if (VI != ValueMap.end())
     return VI->second;
 
-  if (auto *I = dyn_cast<SILInstruction>(Value)) {
-    auto II = InstructionMap.find(I);
-    if (II != InstructionMap.end())
-      return SILValue(II->second);
-    llvm_unreachable("Unmapped instruction while cloning?");
-  }
-
   // If we have undef, just remap the type.
   if (auto *U = dyn_cast<SILUndef>(Value)) {
     auto type = getOpType(U->getType());
@@ -380,15 +367,26 @@
 
 template<typename ImplClass>
 void
-SILCloner<ImplClass>::postProcess(SILInstruction *Orig,
-                                  SILInstruction *Cloned) {
-  assert((Orig->getDebugScope() ? Cloned->getDebugScope()!=nullptr : true) &&
+SILCloner<ImplClass>::postProcess(SILInstruction *orig,
+                                  SILInstruction *cloned) {
+  assert((orig->getDebugScope() ? cloned->getDebugScope()!=nullptr : true) &&
          "cloned function dropped debug scope");
-  // Remove any previous mappings for the Orig instruction.
-  // If this is not done and there is a mapping for Orig in the map already,
-  // then this new mapping will be silently ignored.
-  InstructionMap.erase(Orig);
-  InstructionMap.insert(std::make_pair(Orig, Cloned));
+
+  // It sometimes happens that an instruction with no results gets mapped
+  // to an instruction with results, e.g. when specializing a cast.
+  // Just ignore this.
+  auto origResults = orig->getResults();
+  if (origResults.empty()) return;
+
+  // Otherwise, map the results over one-by-one.
+  auto clonedResults = cloned->getResults();
+  assert(origResults.size() == clonedResults.size());
+  for (auto i : indices(origResults)) {
+    SILValue origResult = origResults[i], clonedResult = clonedResults[i];
+    auto insertion = ValueMap.insert(std::make_pair(origResult, clonedResult));
+    if (!insertion.second)
+      insertion.first->second = clonedResult;
+  }
 }
 
 /// \brief Recursively visit a callee's BBs in depth-first preorder (only
@@ -454,7 +452,7 @@
 
       for (auto *Inst : ToRemove) {
         // Replace any non-dead results with SILUndef values
-        Inst->replaceAllUsesWithUndef();
+        Inst->replaceAllUsesOfAllResultsWithUndef();
         Inst->eraseFromParent();
       }
     }
@@ -2121,7 +2119,8 @@
                                   getOpValue(Inst->getCondition()),
                                   getOpBasicBlock(Inst->getTrueBB()), TrueArgs,
                                   getOpBasicBlock(Inst->getFalseBB()),
-                                  FalseArgs));
+                                  FalseArgs, Inst->getTrueBBCount(),
+                                  Inst->getFalseBBCount()));
 }
 
 template<typename ImplClass>
@@ -2129,13 +2128,15 @@
 SILCloner<ImplClass>::visitCheckedCastBranchInst(CheckedCastBranchInst *Inst) {
   SILBasicBlock *OpSuccBB = getOpBasicBlock(Inst->getSuccessBB());
   SILBasicBlock *OpFailBB = getOpBasicBlock(Inst->getFailureBB());
+  auto TrueCount = Inst->getTrueBBCount();
+  auto FalseCount = Inst->getFalseBBCount();
   getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
   doPostProcess(Inst,
-       getBuilder().createCheckedCastBranch(getOpLocation(Inst->getLoc()),
-                                            Inst->isExact(),
-                                            getOpValue(Inst->getOperand()),
-                                            getOpType(Inst->getCastType()),
-                                            OpSuccBB, OpFailBB));
+                getBuilder().createCheckedCastBranch(
+                    getOpLocation(Inst->getLoc()), Inst->isExact(),
+                    getOpValue(Inst->getOperand()),
+                    getOpType(Inst->getCastType()), OpSuccBB, OpFailBB,
+                    TrueCount, FalseCount));
 }
 
 template <typename ImplClass>
@@ -2160,12 +2161,13 @@
   CanType SrcType = getOpASTType(Inst->getSourceType());
   CanType TargetType = getOpASTType(Inst->getTargetType());
   getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
+  auto TrueCount = Inst->getTrueBBCount();
+  auto FalseCount = Inst->getFalseBBCount();
   doPostProcess(Inst,
-       getBuilder().createCheckedCastAddrBranch(getOpLocation(Inst->getLoc()),
-                                                Inst->getConsumptionKind(),
-                                                SrcValue, SrcType,
-                                                DestValue, TargetType,
-                                                OpSuccBB, OpFailBB));
+                getBuilder().createCheckedCastAddrBranch(
+                    getOpLocation(Inst->getLoc()), Inst->getConsumptionKind(),
+                    SrcValue, SrcType, DestValue, TargetType, OpSuccBB,
+                    OpFailBB, TrueCount, FalseCount));
 }
   
 template<typename ImplClass>
diff --git a/include/swift/SIL/SILFunction.h b/include/swift/SIL/SILFunction.h
index 60e14dd..fe27083 100644
--- a/include/swift/SIL/SILFunction.h
+++ b/include/swift/SIL/SILFunction.h
@@ -17,6 +17,7 @@
 #ifndef SWIFT_SIL_SILFUNCTION_H
 #define SWIFT_SIL_SILFUNCTION_H
 
+#include "swift/Basic/ProfileCounter.h"
 #include "swift/SIL/SILBasicBlock.h"
 #include "swift/SIL/SILDebugScope.h"
 #include "swift/SIL/SILLinkage.h"
@@ -180,6 +181,10 @@
   /// The function's effects attribute.
   EffectsKind EffectsKindAttr;
 
+  /// Has value if there's a profile for this function
+  /// Contains Function Entry Count
+  ProfileCounter EntryCount;
+
   /// True if this function is inlined at least once. This means that the
   /// debug info keeps a pointer to this function.
   bool Inlined = false;
@@ -204,9 +209,9 @@
               CanSILFunctionType loweredType, GenericEnvironment *genericEnv,
               Optional<SILLocation> loc, IsBare_t isBareSILFunction,
               IsTransparent_t isTrans, IsSerialized_t isSerialized,
-              IsThunk_t isThunk, SubclassScope classSubclassScope,
-              Inline_t inlineStrategy, EffectsKind E,
-              SILFunction *insertBefore,
+              ProfileCounter entryCount, IsThunk_t isThunk,
+              SubclassScope classSubclassScope, Inline_t inlineStrategy,
+              EffectsKind E, SILFunction *insertBefore,
               const SILDebugScope *debugScope);
 
   static SILFunction *
@@ -214,7 +219,7 @@
          CanSILFunctionType loweredType, GenericEnvironment *genericEnv,
          Optional<SILLocation> loc, IsBare_t isBareSILFunction,
          IsTransparent_t isTrans, IsSerialized_t isSerialized,
-         IsThunk_t isThunk = IsNotThunk,
+         ProfileCounter entryCount, IsThunk_t isThunk = IsNotThunk,
          SubclassScope classSubclassScope = SubclassScope::NotApplicable,
          Inline_t inlineStrategy = InlineDefault,
          EffectsKind EffectsKindAttr = EffectsKind::Unspecified,
@@ -236,6 +241,8 @@
     return SILFunctionConventions(LoweredType, getModule());
   }
 
+  ProfileCounter getEntryCount() const { return EntryCount; }
+
   bool isNoReturnFunction() const;
 
   /// Unsafely rewrite the lowered type of this function.
@@ -776,9 +783,12 @@
   /// '@function_mangled_name'.
   void printName(raw_ostream &OS) const;
 
-  /// Assigns consecutive numbers to all SILValues in the function.
-  void numberValues(llvm::DenseMap<const ValueBase*,
-                    unsigned> &ValueToNumberMap) const;
+  /// Assigns consecutive numbers to all the SILNodes in the function.
+  /// For instructions, both the instruction node and the value nodes of
+  /// any results will be assigned numbers; the instruction node will
+  /// be numbered the same as the first result, if there are any results.
+  void numberValues(llvm::DenseMap<const SILNode*, unsigned> &nodeToNumberMap)
+    const;
 
   ASTContext &getASTContext() const;
 
diff --git a/include/swift/SIL/SILInstruction.h b/include/swift/SIL/SILInstruction.h
index 288bf2b..3efedff 100644
--- a/include/swift/SIL/SILInstruction.h
+++ b/include/swift/SIL/SILInstruction.h
@@ -23,10 +23,12 @@
 #include "swift/AST/TypeAlignments.h"
 #include "swift/Basic/Compiler.h"
 #include "swift/Basic/NullablePtr.h"
+#include "swift/Basic/ProfileCounter.h"
+#include "swift/Basic/Range.h"
 #include "swift/SIL/Consumption.h"
 #include "swift/SIL/SILAllocated.h"
-#include "swift/SIL/SILFunctionConventions.h"
 #include "swift/SIL/SILDeclRef.h"
+#include "swift/SIL/SILFunctionConventions.h"
 #include "swift/SIL/SILLocation.h"
 #include "swift/SIL/SILSuccessor.h"
 #include "swift/SIL/SILValue.h"
@@ -62,21 +64,45 @@
 
 // An enum class for SILInstructions that enables exhaustive switches over
 // instructions.
-enum class SILInstructionKind : std::underlying_type<ValueKind>::type {
-#define INST(Id, Parent, TextualName, MemoryBehavior, ReleasingBehavior)       \
-  Id = static_cast<std::underlying_type<ValueKind>::type>(ValueKind::Id),
+enum class SILInstructionKind : std::underlying_type<SILNodeKind>::type {
+#define INST(ID, PARENT) \
+  ID = unsigned(SILNodeKind::ID),
+#define INST_RANGE(ID, FIRST, LAST) \
+  First_##ID = unsigned(SILNodeKind::First_##ID), \
+  Last_##ID = unsigned(SILNodeKind::Last_##ID),
 #include "SILNodes.def"
 };
 
+/// Return a range which can be used to easily iterate over all
+/// SILInstructionKinds.
+inline IntRange<SILInstructionKind> allSILInstructionKinds() {
+  return IntRange<SILInstructionKind>(
+            SILInstructionKind(SILNodeKind::First_SILInstruction),
+            SILInstructionKind(unsigned(SILNodeKind::Last_SILInstruction) + 1));
+}
+
 /// Map SILInstruction's mnemonic name to its SILInstructionKind.
 SILInstructionKind getSILInstructionKind(StringRef InstName);
 
 /// Map SILInstructionKind to a corresponding SILInstruction name.
 StringRef getSILInstructionName(SILInstructionKind Kind);
 
-/// This is the root class for all instructions that can be used as the contents
-/// of a Swift SILBasicBlock.
-class SILInstruction : public ValueBase,public llvm::ilist_node<SILInstruction>{
+/// This is the root class for all instructions that can be used as the
+/// contents of a Swift SILBasicBlock.
+///
+/// Most instructions are defined in terms of two basic kinds of
+/// structure: a list of operand values upon which the instruction depends
+/// and a list of result values upon which other instructions can depend.
+///
+/// The operands can be divided into two sets:
+///   - the formal operands of the instruction, which reflect its
+///     direct value dependencies, and
+///   - the type-dependent operands, which reflect dependencies that are
+///     not captured by the formal operands; currently, these dependencies
+///     only arise due to certain instructions (e.g. open_existential_addr)
+///     that bind new archetypes in the local context.
+class SILInstruction
+    : public SILNode, public llvm::ilist_node<SILInstruction> {
   friend llvm::ilist_traits<SILInstruction>;
   friend llvm::ilist_traits<SILBasicBlock>;
   friend SILBasicBlock;
@@ -107,10 +133,22 @@
   static int NumCreatedInstructions;
   static int NumDeletedInstructions;
 
+  // Helper functions used by the ArrayRefViews below.
+  static SILValue projectValueBaseAsSILValue(const ValueBase &value) {
+    return &value;
+  }
+  static SILType projectValueBaseType(const ValueBase &value) {
+    return value.getType();
+  }
+
+  /// An internal method which retrieves the result values of the
+  /// instruction as an array of ValueBase objects.
+  ArrayRef<ValueBase> getResultsImpl() const;
+
 protected:
-  SILInstruction(ValueKind Kind, SILDebugLocation DebugLoc,
-                 SILType Ty = SILType())
-      : ValueBase(Kind, Ty), ParentBB(0), Location(DebugLoc) {
+  SILInstruction(SILInstructionKind kind, SILDebugLocation DebugLoc)
+      : SILNode(SILNodeKind(kind), SILNodeStorageLocation::Instruction),
+        ParentBB(nullptr), Location(DebugLoc) {
     NumCreatedInstructions++;
   }
 
@@ -150,6 +188,22 @@
     MayRelease,
   };
 
+  LLVM_ATTRIBUTE_ALWAYS_INLINE
+  SILInstructionKind getKind() const {
+    return SILInstructionKind(SILNode::getKind());
+  }
+
+  SILNode *getCanonicalSILNodeInObject() {
+    assert(isCanonicalSILNodeInObject() &&
+           "the SILInstruction subobject is always canonical");
+    return this;
+  }
+  const SILNode *getCanonicalSILNodeInObject() const {
+    assert(isCanonicalSILNodeInObject() &&
+           "the SILInstruction subobject is always canonical");
+    return this;
+  }
+
   const SILBasicBlock *getParent() const { return ParentBB; }
   SILBasicBlock *getParent() { return ParentBB; }
 
@@ -189,6 +243,22 @@
   /// \brief Drops all uses that belong to this instruction.
   void dropAllReferences();
 
+  /// \brief Replace all uses of all results of this instruction with undef.
+  void replaceAllUsesOfAllResultsWithUndef();
+
+  /// \brief Replace all uses of all results of this instruction
+  /// with the parwise-corresponding results of the given instruction.
+  void replaceAllUsesPairwiseWith(SILInstruction *other);
+
+  /// \brief Are there uses of any of the results of this instruction?
+  bool hasUsesOfAnyResult() const {
+    for (auto result : getResults()) {
+      if (!result->use_empty())
+        return true;
+    }
+    return false;
+  }
+
   /// Return the array of operands for this instruction.
   ArrayRef<Operand> getAllOperands() const;
 
@@ -248,6 +318,20 @@
     getAllOperands()[Num1].swap(getAllOperands()[Num2]);
   }
 
+  using ResultArrayRef =
+    ArrayRefView<ValueBase,SILValue,projectValueBaseAsSILValue>;
+
+  /// Return the list of results produced by this instruction.
+  ResultArrayRef getResults() const { return getResultsImpl(); }
+
+  using ResultTypeArrayRef =
+    ArrayRefView<ValueBase,SILType,projectValueBaseType>;
+
+  /// Return the types of the results produced by this instruction.
+  ResultTypeArrayRef getResultTypes() const {
+    return getResultsImpl();
+  }
+
   MemoryBehavior getMemoryBehavior() const;
   ReleasingBehavior getReleasingBehavior() const;
 
@@ -272,14 +356,16 @@
   /// using \p opEqual to compare operands.
   ///
   template <typename OpCmp>
-  bool isIdenticalTo(const SILInstruction *RHS, OpCmp opEqual) const {
+  bool isIdenticalTo(const SILInstruction *RHS, OpCmp &&opEqual) const {
     // Quick check if both instructions have the same kind, number of operands,
     // and types. This should filter out most cases.
     if (getKind() != RHS->getKind() ||
-        getNumOperands() != RHS->getNumOperands() ||
-        getType() != RHS->getType()) {
+        getNumOperands() != RHS->getNumOperands()) {
       return false;
     }
+
+    if (getResultTypes() != RHS->getResultTypes())
+      return false;
     
     // Check operands.
     for (unsigned i = 0, e = getNumOperands(); i != e; ++i)
@@ -328,11 +414,6 @@
   /// The first operand must be the allocating instruction.
   bool isDeallocatingStack() const;
 
-  static bool classof(const ValueBase *V) {
-    return V->getKind() >= ValueKind::First_SILInstruction &&
-           V->getKind() <= ValueKind::Last_SILInstruction;
-  }
-
   /// Create a new copy of this instruction, which retains all of the operands
   /// and other information of this one.  If an insertion point is specified,
   /// then the new instruction is inserted before the specified point, otherwise
@@ -362,8 +443,33 @@
   static int getNumDeletedInstructions() {
     return NumDeletedInstructions;
   }
+
+  /// Pretty-print the value.
+  void dump() const;
+  void print(raw_ostream &OS) const;
+
+  /// Pretty-print the value in context, preceded by its operands (if the
+  /// value represents the result of an instruction) and followed by its
+  /// users.
+  void dumpInContext() const;
+  void printInContext(raw_ostream &OS) const;
+
+  static bool classof(const SILNode *N) {
+    return N->getKind() >= SILNodeKind::First_SILInstruction &&
+           N->getKind() <= SILNodeKind::Last_SILInstruction;
+  }
+  static bool classof(const SILInstruction *I) { return true; }
+
+  /// This is supportable but usually suggests a logic mistake.
+  static bool classof(const ValueBase *) = delete;
 };
 
+inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
+                                     const SILInstruction &I) {
+  I.print(OS);
+  return OS;
+}
+
 /// Returns the combined behavior of \p B1 and \p B2.
 inline SILInstruction::MemoryBehavior
 combineMemoryBehavior(SILInstruction::MemoryBehavior B1,
@@ -386,48 +492,187 @@
 llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
                               SILInstruction::ReleasingBehavior B);
 
+/// An instruction which always produces a single value.
+///
+/// Because this instruction is both a SILInstruction and a ValueBase,
+/// both of which inherit from SILNode, it introduces the need for
+/// some care when working with SILNodes.  See the comment on SILNode.
+class SingleValueInstruction : public SILInstruction, public ValueBase {
+  static bool isSingleValueInstKind(SILNodeKind kind) {
+    return kind >= SILNodeKind::First_SingleValueInstruction &&
+           kind <= SILNodeKind::Last_SingleValueInstruction;
+  }
+
+  friend class SILInstruction;
+  ArrayRef<ValueBase> getResultsImpl() const {
+    return ArrayRef<ValueBase>(this, 1);
+  }
+public:
+  SingleValueInstruction(SILInstructionKind kind, SILDebugLocation loc,
+                         SILType type)
+    : SILInstruction(kind, loc),
+      ValueBase(ValueKind(kind), type) {
+  }
+
+  using SILInstruction::getFunction;
+  using SILInstruction::getModule;
+  using SILInstruction::getKind;
+  using SILInstruction::operator new;
+  using SILInstruction::dumpInContext;
+  using SILInstruction::print;
+  using SILInstruction::printInContext;
+
+  // Redeclare because lldb currently doesn't know about using-declarations
+  void dump() const;
+
+  void operator delete(void *Ptr, size_t) SWIFT_DELETE_OPERATOR_DELETED
+
+  ValueKind getValueKind() const {
+    return ValueBase::getKind();
+  }
+
+  SILNode *getCanonicalSILNodeInObject() {
+    assert(SILInstruction::isCanonicalSILNodeInObject() &&
+           "the SILInstruction subobject is always canonical");
+    return static_cast<SILInstruction*>(this);
+  }
+  const SILNode *getCanonicalSILNodeInObject() const {
+    assert(SILInstruction::isCanonicalSILNodeInObject() &&
+           "the SILInstruction subobject is always canonical");
+    return static_cast<const SILInstruction*>(this);
+  }
+
+  SingleValueInstruction *clone(SILInstruction *insertPt = nullptr) {
+    return cast<SingleValueInstruction>(SILInstruction::clone(insertPt));
+  }
+
+  /// Override this to reflect the more efficient access pattern.
+  ResultArrayRef getResults() const {
+    return getResultsImpl();
+  }
+
+  static bool classof(const SILNode *node) {
+    return isSingleValueInstKind(node->getKind());
+  }
+};
+
+// Resolve ambiguities.
+inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
+                                     const SingleValueInstruction &I) {
+  I.print(OS);
+  return OS;
+}
+
+inline SingleValueInstruction *SILNode::castToSingleValueInstruction() {
+  assert(isa<SingleValueInstruction>(this));
+
+  // We do reference static_casts to convince the host compiler to do
+  // null-unchecked conversions.
+
+  // If we're in the value slot, cast through ValueBase.
+  if (getStorageLoc() == SILNodeStorageLocation::Value) {
+    return &static_cast<SingleValueInstruction&>(
+                                         static_cast<ValueBase&>(*this));
+
+  // Otherwise, cast through SILInstruction.
+  } else {
+    return &static_cast<SingleValueInstruction&>(
+                                         static_cast<SILInstruction&>(*this));
+  }
+}
+
+#define DEFINE_ABSTRACT_SINGLE_VALUE_INST_BOILERPLATE(ID)       \
+  static bool classof(const SILNode *node) {                    \
+    return node->getKind() >= SILNodeKind::First_##ID &&        \
+           node->getKind() <= SILNodeKind::Last_##ID;           \
+  }                                                             \
+  static bool classof(const SingleValueInstruction *inst) {     \
+    return inst->getKind() >= SILInstructionKind::First_##ID && \
+           inst->getKind() <= SILInstructionKind::Last_##ID;    \
+  }
+
+/// A subclass of SILInstruction which does not produce any values.
+class NonValueInstruction : public SILInstruction {
+public:
+  NonValueInstruction(SILInstructionKind kind, SILDebugLocation loc)
+    : SILInstruction(kind, loc) {}
+
+  /// Doesn't produce any results.
+  SILType getType() const = delete;
+  ResultArrayRef getResults() const = delete;
+};
+#define DEFINE_ABSTRACT_NON_VALUE_INST_BOILERPLATE(ID)          \
+  static bool classof(const ValueBase *value) = delete;         \
+  static bool classof(const SILNode *node) {                    \
+    return node->getKind() >= SILNodeKind::First_##ID &&        \
+           node->getKind() <= SILNodeKind::Last_##ID;           \
+  }
+
+/// A helper class for defining some basic boilerplate.
+template <SILInstructionKind Kind, typename Base,
+          bool IsSingleResult =
+            std::is_base_of<SingleValueInstruction, Base>::value>
+class InstructionBase;
+
+template <SILInstructionKind Kind, typename Base>
+class InstructionBase<Kind, Base, /*HasResult*/ true> : public Base {
+protected:
+  template <typename... As>
+  InstructionBase(As &&...args)
+    : Base(Kind, std::forward<As>(args)...) {}
+
+public:
+  /// Override to statically return the kind.
+  static constexpr SILInstructionKind getKind() {
+    return Kind;
+  }
+
+  static bool classof(const SILNode *node) {
+    return node->getKind() == SILNodeKind(Kind);
+  }
+  static bool classof(const SingleValueInstruction *I) { // resolve ambiguities
+    return I->getKind() == Kind;
+  }
+};
+
+template <SILInstructionKind Kind, typename Base>
+class InstructionBase<Kind, Base, /*HasResult*/ false> : public Base {
+protected:
+  template <typename... As>
+  InstructionBase(As &&...args)
+    : Base(Kind, std::forward<As>(args)...) {}
+
+public:
+  static constexpr SILInstructionKind getKind() {
+    return Kind;
+  }
+
+  /// Can never dynamically succeed.
+  static bool classof(const ValueBase *value) = delete;
+
+  static bool classof(const SILNode *node) {
+    return node->getKind() == SILNodeKind(Kind);
+  }
+};
+
 /// A template base class for instructions that take a single SILValue operand
 /// and has no result or a single value result.
-template<ValueKind KIND, typename BASE = SILInstruction, bool HAS_RESULT = true>
-class UnaryInstructionBase : public BASE {
+template<SILInstructionKind Kind, typename Base>
+class UnaryInstructionBase : public InstructionBase<Kind, Base> {
   // Space for 1 operand.
   FixedOperandList<1> Operands;
 
-  /// Check HAS_RESULT in enable_if predicates by injecting a dependency on
-  /// a template argument.
-  template<typename X>
-  struct has_result {
-    enum { value = HAS_RESULT };
-  };
-
 public:
-  UnaryInstructionBase(SILDebugLocation DebugLoc, SILValue Operand)
-      : BASE(KIND, DebugLoc), Operands(this, Operand) {}
-
-  template <typename X = void>
-  UnaryInstructionBase(
-      SILDebugLocation DebugLoc, SILValue Operand,
-      typename std::enable_if<has_result<X>::value, SILType>::type Ty)
-      : BASE(KIND, DebugLoc, Ty), Operands(this, Operand) {}
-
-  template <typename X = void, typename... A>
-  UnaryInstructionBase(
-      SILDebugLocation DebugLoc, SILValue Operand,
-      typename std::enable_if<has_result<X>::value, SILType>::type Ty,
-      A &&... args)
-      : BASE(KIND, DebugLoc, Ty, std::forward<A>(args)...),
-        Operands(this, Operand) {}
+  template <typename... A>
+  UnaryInstructionBase(SILDebugLocation loc, SILValue op, A &&... args)
+      : InstructionBase<Kind, Base>(loc, std::forward<A>(args)...),
+        Operands(this, op) {}
 
   SILValue getOperand() const { return Operands[0].get(); }
   void setOperand(SILValue V) { Operands[0].set(V); }
 
   Operand &getOperandRef() { return Operands[0]; }
 
-  /// getType() is ok if this is known to only have one type.
-  template<typename X = void>
-  typename std::enable_if<has_result<X>::value, SILType>::type
-  getType() const { return ValueBase::getType(); }
-
   ArrayRef<Operand> getAllOperands() const { return Operands.asArray(); }
   MutableArrayRef<Operand> getAllOperands() { return Operands.asArray(); }
 
@@ -438,10 +683,6 @@
   MutableArrayRef<Operand> getTypeDependentOperands() {
     return {};
   }
-
-  static bool classof(const ValueBase *V) {
-    return V->getKind() == KIND;
-  }
 };
 
 /// A template base class for instructions that take a single regular SILValue
@@ -449,24 +690,18 @@
 /// or a single value result. The operands are tail allocated after the
 /// instruction. Further trailing data can be allocated as well if
 /// TRAILING_TYPES are provided.
-template<ValueKind KIND, typename DERIVED,
-         typename BASE, bool HAS_RESULT,
-         typename... TRAILING_TYPES>
-class UnaryInstructionWithTypeDependentOperandsBase :
-  public BASE,
-  protected llvm::TrailingObjects<DERIVED, Operand, TRAILING_TYPES...> {
-
-  /// Check HAS_RESULT in enable_if predicates by injecting a dependency on
-  /// a template argument.
-  template<typename X>
-  struct has_result {
-    enum { value = HAS_RESULT };
-  };
+template<SILInstructionKind Kind,
+         typename Derived,
+         typename Base,
+         typename... OtherTrailingTypes>
+class UnaryInstructionWithTypeDependentOperandsBase
+    : public InstructionBase<Kind, Base>,
+      protected llvm::TrailingObjects<Derived, Operand, OtherTrailingTypes...> {
 
 protected:
-  friend llvm::TrailingObjects<DERIVED, Operand, TRAILING_TYPES...>;
+  friend llvm::TrailingObjects<Derived, Operand, OtherTrailingTypes...>;
 
-  typedef llvm::TrailingObjects<DERIVED, Operand, TRAILING_TYPES...>
+  typedef llvm::TrailingObjects<Derived, Operand, OtherTrailingTypes...>
       TrailingObjects;
 
   using TrailingObjects::totalSizeToAlloc;
@@ -476,6 +711,17 @@
   unsigned NumOperands;
 
 public:
+  template <typename... Args>
+  UnaryInstructionWithTypeDependentOperandsBase(
+      SILDebugLocation debugLoc, SILValue operand,
+      ArrayRef<SILValue> typeDependentOperands,
+      Args &&...args)
+        : InstructionBase<Kind, Base>(debugLoc, std::forward<Args>(args)...),
+          NumOperands(1 + typeDependentOperands.size()) {
+    TrailingOperandsList::InitOperandsList(getAllOperands().begin(), this,
+                                           operand, typeDependentOperands);
+  }
+
   // Destruct tail allocated objects.
   ~UnaryInstructionWithTypeDependentOperandsBase() {
     Operand *Operands = &getAllOperands()[0];
@@ -489,39 +735,6 @@
     return NumOperands;
   }
 
-  UnaryInstructionWithTypeDependentOperandsBase(
-      SILDebugLocation DebugLoc, SILValue Operand,
-      ArrayRef<SILValue> TypeDependentOperands)
-      : BASE(KIND, DebugLoc), NumOperands(1 + TypeDependentOperands.size()) {
-    TrailingOperandsList::InitOperandsList(getAllOperands().begin(), this,
-                                           Operand, TypeDependentOperands);
-  }
-
-  template <typename X = void>
-  UnaryInstructionWithTypeDependentOperandsBase(
-      SILDebugLocation DebugLoc, SILValue Operand,
-      ArrayRef<SILValue> TypeDependentOperands,
-      typename std::enable_if<has_result<X>::value, SILType>::type Ty)
-      : BASE(KIND, DebugLoc, Ty),
-        NumOperands(1 + TypeDependentOperands.size())
-  {
-    TrailingOperandsList::InitOperandsList(getAllOperands().begin(), this,
-                                           Operand, TypeDependentOperands);
-  }
-
-  template <typename X = void, typename... A>
-  UnaryInstructionWithTypeDependentOperandsBase(
-      SILDebugLocation DebugLoc, SILValue Operand,
-      ArrayRef<SILValue> TypeDependentOperands,
-      typename std::enable_if<has_result<X>::value, SILType>::type Ty,
-      A &&... args)
-      : BASE(KIND, DebugLoc, Ty, std::forward<A>(args)...),
-        NumOperands(1 + TypeDependentOperands.size())
-  {
-    TrailingOperandsList::InitOperandsList(getAllOperands().begin(), this,
-                                           Operand, TypeDependentOperands);
-  }
-
   unsigned getNumTypeDependentOperands() const {
     return NumOperands - 1;
   }
@@ -531,11 +744,6 @@
 
   Operand &getOperandRef() { return getAllOperands()[0]; }
 
-  /// getType() is ok if this is known to only have one type.
-  template<typename X = void>
-  typename std::enable_if<has_result<X>::value, SILType>::type
-  getType() const { return ValueBase::getType(); }
-
   ArrayRef<Operand> getAllOperands() const {
     return {TrailingObjects::template getTrailingObjects<Operand>(),
             static_cast<size_t>(NumOperands)};
@@ -553,10 +761,6 @@
   MutableArrayRef<Operand> getTypeDependentOperands() {
     return getAllOperands().slice(1);
   }
-
-  static bool classof(const ValueBase *V) {
-    return V->getKind() == KIND;
-  }
 };
 
 /// Holds common debug information about local variables and function
@@ -609,17 +813,13 @@
 
 /// Abstract base class for allocation instructions, like alloc_stack, alloc_box
 /// and alloc_ref, etc.
-class AllocationInst : public SILInstruction {
+class AllocationInst : public SingleValueInstruction {
 protected:
-  AllocationInst(ValueKind Kind, SILDebugLocation DebugLoc, SILType Ty)
-      : SILInstruction(Kind, DebugLoc, Ty) {}
+  AllocationInst(SILInstructionKind Kind, SILDebugLocation DebugLoc, SILType Ty)
+      : SingleValueInstruction(Kind, DebugLoc, Ty) {}
 
 public:
-
-  static bool classof(const ValueBase *V) {
-    return V->getKind() >= ValueKind::First_AllocationInst &&
-      V->getKind() <= ValueKind::Last_AllocationInst;
-  }
+  DEFINE_ABSTRACT_SINGLE_VALUE_INST_BOILERPLATE(AllocationInst)
 };
 
 /// Base class for allocation/deallocation instructions where the allocation
@@ -643,7 +843,8 @@
 /// AllocStackInst - This represents the allocation of an unboxed (i.e., no
 /// reference count) stack memory.  The memory is provided uninitialized.
 class AllocStackInst final
-    : public AllocationInst,
+    : public InstructionBase<SILInstructionKind::AllocStackInst,
+                             AllocationInst>,
       private llvm::TrailingObjects<AllocStackInst, Operand, char> {
   friend TrailingObjects;
   friend SILBuilder;
@@ -704,10 +905,6 @@
   MutableArrayRef<Operand> getTypeDependentOperands() {
     return getAllOperands();
   }
-
-  static bool classof(const ValueBase *V) {
-    return V->getKind() == ValueKind::AllocStackInst;
-  }
 };
 
 /// The base class for AllocRefInst and AllocRefDynamicInst.
@@ -716,7 +913,7 @@
       public StackPromotable {
 protected:
 
-  AllocRefInstBase(ValueKind Kind,
+  AllocRefInstBase(SILInstructionKind Kind,
                    SILDebugLocation DebugLoc,
                    SILType ObjectType,
                    bool objc, bool canBeOnStack,
@@ -774,7 +971,9 @@
 /// returned uninitialized.
 /// Optionally, the allocated instance contains space for one or more tail-
 /// allocated arrays.
-class AllocRefInst final : public AllocRefInstBase {
+class AllocRefInst final
+    : public InstructionBase<SILInstructionKind::AllocRefInst,
+                             AllocRefInstBase> {
   friend SILBuilder;
 
   AllocRefInst(SILDebugLocation DebugLoc, SILFunction &F,
@@ -782,8 +981,8 @@
                bool objc, bool canBeOnStack,
                ArrayRef<SILType> ElementTypes,
                ArrayRef<SILValue> AllOperands)
-      : AllocRefInstBase(ValueKind::AllocRefInst, DebugLoc, ObjectType, objc,
-                         canBeOnStack, ElementTypes, AllOperands) {
+      : InstructionBase(DebugLoc, ObjectType, objc,
+                        canBeOnStack, ElementTypes, AllOperands) {
     static_assert(sizeof(AllocRefInst) == sizeof(AllocRefInstBase),
                   "subclass has extra storage");
   }
@@ -803,10 +1002,6 @@
   MutableArrayRef<Operand> getTypeDependentOperands() {
     return getAllOperands().slice(NumTailTypes);
   }
-
-  static bool classof(const ValueBase *V) {
-    return V->getKind() == ValueKind::AllocRefInst;
-  }
 };
 
 /// AllocRefDynamicInst - This represents the primitive allocation of
@@ -815,7 +1010,9 @@
 /// instance is returned uninitialized.
 /// Optionally, the allocated instance contains space for one or more tail-
 /// allocated arrays.
-class AllocRefDynamicInst final : public AllocRefInstBase {
+class AllocRefDynamicInst final
+    : public InstructionBase<SILInstructionKind::AllocRefDynamicInst,
+                             AllocRefInstBase> {
   friend SILBuilder;
 
   AllocRefDynamicInst(SILDebugLocation DebugLoc,
@@ -823,9 +1020,7 @@
                       bool objc,
                       ArrayRef<SILType> ElementTypes,
                       ArrayRef<SILValue> AllOperands)
-      : AllocRefInstBase(ValueKind::AllocRefDynamicInst, DebugLoc,
-                         ty, objc, false,
-                         ElementTypes, AllOperands) {
+      : InstructionBase(DebugLoc, ty, objc, false, ElementTypes, AllOperands) {
     static_assert(sizeof(AllocRefInst) == sizeof(AllocRefInstBase),
                   "subclass has extra storage");
   }
@@ -849,19 +1044,14 @@
   MutableArrayRef<Operand> getTypeDependentOperands() {
     return getAllOperands().slice(NumTailTypes + 1);
   }
-
-  static bool classof(const ValueBase *V) {
-    return V->getKind() == ValueKind::AllocRefDynamicInst;
-  }
 };
 
 /// AllocValueBufferInst - Allocate memory in a value buffer.
 class AllocValueBufferInst final
     : public UnaryInstructionWithTypeDependentOperandsBase<
-                                  ValueKind::AllocValueBufferInst,
+                                  SILInstructionKind::AllocValueBufferInst,
                                   AllocValueBufferInst,
-                                  AllocationInst,
-                                  true> {
+                                  AllocationInst> {
   friend SILBuilder;
 
   AllocValueBufferInst(SILDebugLocation DebugLoc, SILType valueType,
@@ -883,7 +1073,8 @@
 /// is an address pointing to the contained element. The contained
 /// element is uninitialized.
 class AllocBoxInst final
-    : public AllocationInst,
+    : public InstructionBase<SILInstructionKind::AllocBoxInst,
+                             AllocationInst>,
       private llvm::TrailingObjects<AllocBoxInst, Operand, char> {
   friend TrailingObjects;
   friend SILBuilder;
@@ -946,10 +1137,6 @@
   MutableArrayRef<Operand> getTypeDependentOperands() {
     return getAllOperands();
   }
-
-  static bool classof(const ValueBase *V) {
-    return V->getKind() == ValueKind::AllocBoxInst;
-  }
 };
 
 /// This represents the allocation of a heap box for an existential container.
@@ -958,7 +1145,8 @@
 /// is an address pointing to the contained element. The contained
 /// value is uninitialized.
 class AllocExistentialBoxInst final
-    : public AllocationInst,
+    : public InstructionBase<SILInstructionKind::AllocExistentialBoxInst,
+                             AllocationInst>,
       private llvm::TrailingObjects<AllocExistentialBoxInst, Operand> {
   friend TrailingObjects;
   friend SILBuilder;
@@ -1008,10 +1196,6 @@
   MutableArrayRef<Operand> getTypeDependentOperands() {
     return getAllOperands();
   }
-
-  static bool classof(const ValueBase *V) {
-    return V->getKind() == ValueKind::AllocExistentialBoxInst;
-  }
 };
 
 /// GenericSpecializationInformation - provides information about a generic
@@ -1088,7 +1272,7 @@
 
 protected:
   template <class... As>
-  ApplyInstBase(ValueKind kind, SILDebugLocation DebugLoc, SILValue callee,
+  ApplyInstBase(SILInstructionKind kind, SILDebugLocation DebugLoc, SILValue callee,
                 SILType substCalleeType, SubstitutionList substitutions,
                 ArrayRef<SILValue> args,
                 ArrayRef<SILValue> TypeDependentOperands,
@@ -1344,7 +1528,9 @@
 };
 
 /// ApplyInst - Represents the full application of a function value.
-class ApplyInst : public ApplyInstBase<ApplyInst, SILInstruction> {
+class ApplyInst
+    : public InstructionBase<SILInstructionKind::ApplyInst,
+                             ApplyInstBase<ApplyInst, SingleValueInstruction>> {
   friend SILBuilder;
 
   ApplyInst(SILDebugLocation DebugLoc, SILValue Callee,
@@ -1363,10 +1549,6 @@
          const GenericSpecializationInformation *SpecializationInfo);
 
 public:
-  static bool classof(const ValueBase *V) {
-    return V->getKind() == ValueKind::ApplyInst;
-  }
-  
   /// Returns true if the called function has an error result but is not actually
   /// throwing an error.
   bool isNonThrowing() const {
@@ -1377,7 +1559,9 @@
 /// PartialApplyInst - Represents the creation of a closure object by partial
 /// application of a function value.
 class PartialApplyInst
-    : public ApplyInstBase<PartialApplyInst, SILInstruction> {
+    : public InstructionBase<SILInstructionKind::PartialApplyInst,
+                             ApplyInstBase<PartialApplyInst,
+                                           SingleValueInstruction>> {
   friend SILBuilder;
 
   PartialApplyInst(SILDebugLocation DebugLoc, SILValue Callee,
@@ -1399,10 +1583,6 @@
   CanSILFunctionType getFunctionType() const {
     return getType().castTo<SILFunctionType>();
   }
-
-  static bool classof(const ValueBase *V) {
-    return V->getKind() == ValueKind::PartialApplyInst;
-  }
 };
 
 //===----------------------------------------------------------------------===//
@@ -1410,21 +1590,20 @@
 //===----------------------------------------------------------------------===//
 
 /// Abstract base class for literal instructions.
-class LiteralInst : public SILInstruction {
+class LiteralInst : public SingleValueInstruction {
 protected:
-  LiteralInst(ValueKind Kind, SILDebugLocation DebugLoc, SILType Ty)
-      : SILInstruction(Kind, DebugLoc, Ty) {}
+  LiteralInst(SILInstructionKind Kind, SILDebugLocation DebugLoc, SILType Ty)
+      : SingleValueInstruction(Kind, DebugLoc, Ty) {}
 
 public:
 
-  static bool classof(const ValueBase *V) {
-    return V->getKind() >= ValueKind::First_LiteralInst &&
-      V->getKind() <= ValueKind::Last_LiteralInst;
-  }
+  DEFINE_ABSTRACT_SINGLE_VALUE_INST_BOILERPLATE(LiteralInst)
 };
 
 /// FunctionRefInst - Represents a reference to a SIL function.
-class FunctionRefInst : public LiteralInst {
+class FunctionRefInst
+    : public InstructionBase<SILInstructionKind::FunctionRefInst,
+                             LiteralInst> {
   friend SILBuilder;
 
   SILFunction *Function;
@@ -1451,10 +1630,6 @@
 
   ArrayRef<Operand> getAllOperands() const { return {}; }
   MutableArrayRef<Operand> getAllOperands() { return {}; }
-
-  static bool classof(const ValueBase *V) {
-    return V->getKind() == ValueKind::FunctionRefInst;
-  }
 };
 
 /// Component of a KeyPathInst.
@@ -1821,9 +1996,9 @@
 
 /// Instantiates a key path object.
 class KeyPathInst final
-  : public SILInstruction,
-    private llvm::TrailingObjects<KeyPathInst, Substitution, Operand>
-{
+    : public InstructionBase<SILInstructionKind::KeyPathInst,
+                             SingleValueInstruction>,
+      private llvm::TrailingObjects<KeyPathInst, Substitution, Operand> {
   friend SILBuilder;
   friend TrailingObjects;
   
@@ -1864,10 +2039,6 @@
     return const_cast<KeyPathInst*>(this)->getSubstitutions();
   }
   
-  static bool classof(const ValueBase *V) {
-    return V->getKind() == ValueKind::KeyPathInst;
-  }
-  
   void dropReferencedPattern();
   
   ~KeyPathInst();
@@ -1875,7 +2046,9 @@
 
 /// Represents an invocation of builtin functionality provided by the code
 /// generator.
-class BuiltinInst : public SILInstruction {
+class BuiltinInst
+    : public InstructionBase<SILInstructionKind::BuiltinInst,
+                             SingleValueInstruction> {
   friend SILBuilder;
 
   /// The name of the builtin to invoke.
@@ -1963,15 +2136,13 @@
   OperandValueArrayRef getArguments() const {
     return Operands.asValueArray();
   }
-  
-  static bool classof(const ValueBase *V) {
-    return V->getKind() == ValueKind::BuiltinInst;
-  }
 };
   
 /// Initializes a SIL global variable. Only valid once, before any
 /// usages of the global via GlobalAddrInst.
-class AllocGlobalInst : public SILInstruction {
+class AllocGlobalInst
+    : public InstructionBase<SILInstructionKind::AllocGlobalInst,
+                             SILInstruction> {
   friend SILBuilder;
 
   SILGlobalVariable *Global;
@@ -1979,12 +2150,6 @@
   AllocGlobalInst(SILDebugLocation DebugLoc, SILGlobalVariable *Global);
 
 public:
-  // FIXME: This constructor should be private but is currently used
-  //        in the SILParser.
-
-  /// Create a placeholder instruction with an unset global reference.
-  AllocGlobalInst(SILDebugLocation DebugLoc);
-
   /// Return the referenced global variable.
   SILGlobalVariable *getReferencedGlobal() const { return Global; }
   
@@ -1992,10 +2157,6 @@
 
   ArrayRef<Operand> getAllOperands() const { return {}; }
   MutableArrayRef<Operand> getAllOperands() { return {}; }
-
-  static bool classof(const ValueBase *V) {
-    return V->getKind() == ValueKind::AllocGlobalInst;
-  }
 };
 
 /// The base class for global_addr and global_value.
@@ -2003,9 +2164,9 @@
   SILGlobalVariable *Global;
 
 protected:
-  GlobalAccessInst(ValueKind valueKind, SILDebugLocation DebugLoc,
-                    SILGlobalVariable *Global, SILType Ty)
-      : LiteralInst(valueKind, DebugLoc, Ty), Global(Global) { }
+  GlobalAccessInst(SILInstructionKind kind, SILDebugLocation loc,
+                   SILType ty, SILGlobalVariable *global)
+      : LiteralInst(kind, loc, ty), Global(global) { }
 
 public:
   /// Return the referenced global variable.
@@ -2019,7 +2180,9 @@
 
 /// Gives the address of a SIL global variable. Only valid after an
 /// AllocGlobalInst.
-class GlobalAddrInst : public GlobalAccessInst {
+class GlobalAddrInst
+    : public InstructionBase<SILInstructionKind::GlobalAddrInst,
+                             GlobalAccessInst> {
   friend SILBuilder;
 
   GlobalAddrInst(SILDebugLocation DebugLoc, SILGlobalVariable *Global);
@@ -2029,31 +2192,27 @@
 
   /// Create a placeholder instruction with an unset global reference.
   GlobalAddrInst(SILDebugLocation DebugLoc, SILType Ty)
-      : GlobalAccessInst(ValueKind::GlobalAddrInst, DebugLoc, nullptr, Ty) { }
-
-  static bool classof(const ValueBase *V) {
-    return V->getKind() == ValueKind::GlobalAddrInst;
-  }
+      : InstructionBase(DebugLoc, Ty, nullptr) { }
 };
 
 /// Gives the value of a global variable.
 ///
 /// The referenced global variable must be a statically initialized object.
 /// TODO: in future we might support global variables in general.
-class GlobalValueInst : public GlobalAccessInst {
+class GlobalValueInst
+    : public InstructionBase<SILInstructionKind::GlobalValueInst,
+                             GlobalAccessInst> {
   friend SILBuilder;
 
   GlobalValueInst(SILDebugLocation DebugLoc, SILGlobalVariable *Global);
-public:
-  static bool classof(const ValueBase *V) {
-    return V->getKind() == ValueKind::GlobalValueInst;
-  }
 };
 
 /// IntegerLiteralInst - Encapsulates an integer constant, as defined originally
 /// by an IntegerLiteralExpr.
-class IntegerLiteralInst final : public LiteralInst,
-    private llvm::TrailingObjects<IntegerLiteralInst, llvm::APInt::WordType> {
+class IntegerLiteralInst final
+    : public InstructionBase<SILInstructionKind::IntegerLiteralInst,
+                             LiteralInst>,
+      private llvm::TrailingObjects<IntegerLiteralInst, llvm::APInt::WordType> {
   friend TrailingObjects;
   friend SILBuilder;
 
@@ -2074,16 +2233,14 @@
 
   ArrayRef<Operand> getAllOperands() const { return {}; }
   MutableArrayRef<Operand> getAllOperands() { return {}; }
-
-  static bool classof(const ValueBase *V) {
-    return V->getKind() == ValueKind::IntegerLiteralInst;
-  }
 };
 
 /// FloatLiteralInst - Encapsulates a floating point constant, as defined
 /// originally by a FloatLiteralExpr.
-class FloatLiteralInst final : public LiteralInst,
-    private llvm::TrailingObjects<FloatLiteralInst, llvm::APInt::WordType> {
+class FloatLiteralInst final
+    : public InstructionBase<SILInstructionKind::FloatLiteralInst,
+                             LiteralInst>,
+      private llvm::TrailingObjects<FloatLiteralInst, llvm::APInt::WordType> {
   friend TrailingObjects;
   friend SILBuilder;
 
@@ -2105,17 +2262,15 @@
 
   ArrayRef<Operand> getAllOperands() const { return {}; }
   MutableArrayRef<Operand> getAllOperands() { return {}; }
-
-  static bool classof(const ValueBase *V) {
-    return V->getKind() == ValueKind::FloatLiteralInst;
-  }
 };
 
 /// StringLiteralInst - Encapsulates a string constant, as defined originally by
 /// a StringLiteralExpr.  This produces the address of the string data as a
 /// Builtin.RawPointer.
-class StringLiteralInst final : public LiteralInst,
-    private llvm::TrailingObjects<StringLiteralInst, char> {
+class StringLiteralInst final
+    : public InstructionBase<SILInstructionKind::StringLiteralInst,
+                             LiteralInst>,
+      private llvm::TrailingObjects<StringLiteralInst, char> {
   friend TrailingObjects;
   friend SILBuilder;
 
@@ -2152,10 +2307,6 @@
 
   ArrayRef<Operand> getAllOperands() const { return {}; }
   MutableArrayRef<Operand> getAllOperands() { return {}; }
-
-  static bool classof(const ValueBase *V) {
-    return V->getKind() == ValueKind::StringLiteralInst;
-  }
 };
 
 /// ConstStringLiteralInst - Encapsulates a string constant, as defined
@@ -2163,7 +2314,8 @@
 /// a StringLiteralExpr.  This produces the address of the string data as a
 /// Builtin.RawPointer.
 class ConstStringLiteralInst final
-    : public LiteralInst,
+    : public InstructionBase<SILInstructionKind::ConstStringLiteralInst,
+                             LiteralInst>,
       private llvm::TrailingObjects<ConstStringLiteralInst, char> {
   friend TrailingObjects;
   friend SILBuilder;
@@ -2198,11 +2350,8 @@
 
   ArrayRef<Operand> getAllOperands() const { return {}; }
   MutableArrayRef<Operand> getAllOperands() { return {}; }
-
-  static bool classof(const ValueBase *V) {
-    return V->getKind() == ValueKind::ConstStringLiteralInst;
-  }
 };
+
 //===----------------------------------------------------------------------===//
 // Memory instructions.
 //===----------------------------------------------------------------------===//
@@ -2220,7 +2369,8 @@
 
 /// LoadInst - Represents a load from a memory location.
 class LoadInst
-  : public UnaryInstructionBase<ValueKind::LoadInst>
+  : public UnaryInstructionBase<SILInstructionKind::LoadInst,
+                                SingleValueInstruction>
 {
   friend SILBuilder;
 
@@ -2251,7 +2401,9 @@
 };
 
 /// StoreInst - Represents a store from a memory location.
-class StoreInst : public SILInstruction {
+class StoreInst
+    : public InstructionBase<SILInstructionKind::StoreInst,
+                             NonValueInstruction> {
   friend SILBuilder;
 
 private:
@@ -2275,10 +2427,6 @@
   ArrayRef<Operand> getAllOperands() const { return Operands.asArray(); }
   MutableArrayRef<Operand> getAllOperands() { return Operands.asArray(); }
 
-  static bool classof(const ValueBase *V) {
-    return V->getKind() == ValueKind::StoreInst;
-  }
-
   StoreOwnershipQualifier getOwnershipQualifier() const {
     return OwnershipQualifier;
   }
@@ -2286,7 +2434,9 @@
 
 /// Represents a load of a borrowed value. Must be paired with an end_borrow
 /// instruction in its use-def list.
-class LoadBorrowInst : public UnaryInstructionBase<ValueKind::LoadBorrowInst> {
+class LoadBorrowInst :
+    public UnaryInstructionBase<SILInstructionKind::LoadBorrowInst,
+                                SingleValueInstruction> {
   friend class SILBuilder;
 
   LoadBorrowInst(SILDebugLocation DebugLoc, SILValue LValue)
@@ -2297,7 +2447,8 @@
 /// Represents the begin scope of a borrowed value. Must be paired with an
 /// end_borrow instruction in its use-def list.
 class BeginBorrowInst
-    : public UnaryInstructionBase<ValueKind::BeginBorrowInst> {
+    : public UnaryInstructionBase<SILInstructionKind::BeginBorrowInst,
+                                  SingleValueInstruction> {
   friend class SILBuilder;
 
   BeginBorrowInst(SILDebugLocation DebugLoc, SILValue LValue)
@@ -2307,7 +2458,9 @@
 
 /// Represents a store of a borrowed value into an address. Returns the borrowed
 /// address. Must be paired with an end_borrow in its use-def list.
-class StoreBorrowInst : public SILInstruction {
+class StoreBorrowInst
+    : public InstructionBase<SILInstructionKind::StoreBorrowInst,
+                             SingleValueInstruction> {
   friend class SILBuilder;
 
 public:
@@ -2328,10 +2481,6 @@
 
   ArrayRef<Operand> getAllOperands() const { return Operands.asArray(); }
   MutableArrayRef<Operand> getAllOperands() { return Operands.asArray(); }
-
-  static bool classof(const ValueBase *V) {
-    return V->getKind() == ValueKind::StoreBorrowInst;
-  }
 };
 
 /// Represents the end of a borrow scope for a value or address from another
@@ -2340,7 +2489,9 @@
 /// The semantics of the instruction here is that the "dest" SILValue can not be
 /// used after this instruction and the "src" SILValue must stay alive up to
 /// EndBorrowInst.
-class EndBorrowInst : public SILInstruction {
+class EndBorrowInst
+    : public InstructionBase<SILInstructionKind::EndBorrowInst,
+                             NonValueInstruction> {
   friend class SILBuilder;
 
 public:
@@ -2363,10 +2514,6 @@
 
   ArrayRef<Operand> getAllOperands() const { return Operands.asArray(); }
   MutableArrayRef<Operand> getAllOperands() { return Operands.asArray(); }
-
-  static bool classof(const ValueBase *V) {
-    return V->getKind() == ValueKind::EndBorrowInst;
-  }
 };
 
 /// Represents the end of a borrow scope for an argument. The reason why this is
@@ -2374,7 +2521,8 @@
 /// specific SSA value. Instead it is borrowed from potentially many different
 /// incoming values.
 class EndBorrowArgumentInst
-    : public UnaryInstructionBase<ValueKind::EndBorrowArgumentInst> {
+    : public UnaryInstructionBase<SILInstructionKind::EndBorrowArgumentInst,
+                                  NonValueInstruction> {
   friend class SILBuilder;
 
   EndBorrowArgumentInst(SILDebugLocation DebugLoc, SILArgument *Arg);
@@ -2429,7 +2577,8 @@
 /// Begins an access scope. Must be paired with an end_access instruction
 /// along every path.
 class BeginAccessInst
-    : public UnaryInstructionBase<ValueKind::BeginAccessInst> {
+    : public UnaryInstructionBase<SILInstructionKind::BeginAccessInst,
+                                  SingleValueInstruction> {
   friend class SILBuilder;
 
   SILAccessKind AccessKind;
@@ -2478,7 +2627,9 @@
 };
 
 /// Represents the end of an access scope.
-class EndAccessInst : public UnaryInstructionBase<ValueKind::EndAccessInst> {
+class EndAccessInst
+    : public UnaryInstructionBase<SILInstructionKind::EndAccessInst,
+                                  NonValueInstruction> {
   friend class SILBuilder;
 
   bool Aborting;
@@ -2531,7 +2682,9 @@
 ///
 /// This should only be used in materializeForSet, and eventually it should
 /// be removed entirely.
-class BeginUnpairedAccessInst : public SILInstruction {
+class BeginUnpairedAccessInst
+    : public InstructionBase<SILInstructionKind::BeginUnpairedAccessInst,
+                             NonValueInstruction> {
   friend class SILBuilder;
 
   FixedOperandList<2> Operands;
@@ -2542,8 +2695,7 @@
   BeginUnpairedAccessInst(SILDebugLocation loc, SILValue addr, SILValue buffer,
                           SILAccessKind accessKind,
                           SILAccessEnforcement enforcement)
-    : SILInstruction(ValueKind::BeginUnpairedAccessInst,
-                     loc, addr->getType()),
+    : InstructionBase(loc),
       Operands(this, addr, buffer),
       AccessKind(accessKind), Enforcement(enforcement) {
   }
@@ -2581,15 +2733,12 @@
   MutableArrayRef<Operand> getTypeDependentOperands() {
     return {};
   }
-
-  static bool classof(const ValueBase *V) {
-    return V->getKind() == ValueKind::BeginUnpairedAccessInst;
-  }
 };
 
 /// Ends an unpaired access.
 class EndUnpairedAccessInst
-    : public UnaryInstructionBase<ValueKind::EndUnpairedAccessInst> {
+    : public UnaryInstructionBase<SILInstructionKind::EndUnpairedAccessInst,
+                                  NonValueInstruction> {
   friend class SILBuilder;
 
   SILAccessEnforcement Enforcement;
@@ -2632,7 +2781,9 @@
 /// AssignInst - Represents an abstract assignment to a memory location, which
 /// may either be an initialization or a store sequence.  This is only valid in
 /// Raw SIL.
-class AssignInst : public SILInstruction {
+class AssignInst
+    : public InstructionBase<SILInstructionKind::AssignInst,
+                             NonValueInstruction> {
   friend SILBuilder;
 
   enum {
@@ -2656,10 +2807,6 @@
 
   ArrayRef<Operand> getAllOperands() const { return Operands.asArray(); }
   MutableArrayRef<Operand> getAllOperands() { return Operands.asArray(); }
-
-  static bool classof(const ValueBase *V) {
-    return V->getKind() == ValueKind::AssignInst;
-  }
 };
 
 /// Abstract base class for instructions that mark storage as uninitialized.
@@ -2668,7 +2815,8 @@
 /// this point and needs to be initialized by the end of the function and before
 /// any escape point for this instruction.  This is only valid in Raw SIL.
 class MarkUninitializedInst
-  : public UnaryInstructionBase<ValueKind::MarkUninitializedInst> {
+    : public UnaryInstructionBase<SILInstructionKind::MarkUninitializedInst,
+                                  SingleValueInstruction> {
   friend SILBuilder;
 
 public:
@@ -2724,7 +2872,9 @@
 /// the logical initialization state of the property.
 ///
 /// This is only valid in Raw SIL.
-class MarkUninitializedBehaviorInst final : public SILInstruction,
+class MarkUninitializedBehaviorInst final
+    : public InstructionBase<SILInstructionKind::MarkUninitializedBehaviorInst,
+                             SingleValueInstruction>,
       private llvm::TrailingObjects<MarkUninitializedBehaviorInst, Substitution>
 {
   friend SILBuilder;
@@ -2791,16 +2941,14 @@
 
   ArrayRef<Operand> getAllOperands() const { return Operands.asArray(); }
   MutableArrayRef<Operand> getAllOperands() { return Operands.asArray(); }
-  
-  static bool classof(const ValueBase *V) {
-    return V->getKind() == ValueKind::MarkUninitializedBehaviorInst;
-  }
 };
 
 /// MarkFunctionEscape - Represents the escape point of set of variables due to
 /// a function definition which uses the variables.  This is only valid in Raw
 /// SIL.
-class MarkFunctionEscapeInst : public SILInstruction {
+class MarkFunctionEscapeInst
+    : public InstructionBase<SILInstructionKind::MarkFunctionEscapeInst,
+                             NonValueInstruction> {
   friend SILBuilder;
 
   TailAllocatedOperandList<0> Operands;
@@ -2828,17 +2976,14 @@
 
   ArrayRef<Operand> getAllOperands() const { return Operands.asArray(); }
   MutableArrayRef<Operand> getAllOperands() { return Operands.asArray(); }
-
-  static bool classof(const ValueBase *V) {
-    return V->getKind() == ValueKind::MarkFunctionEscapeInst;
-  }
 };
 
 /// Define the start or update to a symbolic variable value (for loadable
 /// types).
 class DebugValueInst final
-  : public UnaryInstructionBase<ValueKind::DebugValueInst>,
-    private llvm::TrailingObjects<DebugValueInst, char> {
+    : public UnaryInstructionBase<SILInstructionKind::DebugValueInst,
+                                  NonValueInstruction>,
+      private llvm::TrailingObjects<DebugValueInst, char> {
   friend TrailingObjects;
   friend SILBuilder;
   TailAllocatedDebugVariable VarInfo;
@@ -2863,7 +3008,8 @@
 /// Define the start or update to a symbolic variable value (for address-only
 /// types) .
 class DebugValueAddrInst final
-  : public UnaryInstructionBase<ValueKind::DebugValueAddrInst>,
+  : public UnaryInstructionBase<SILInstructionKind::DebugValueAddrInst,
+                                NonValueInstruction>,
     private llvm::TrailingObjects<DebugValueAddrInst, char> {
   friend TrailingObjects;
   friend SILBuilder;
@@ -2887,8 +3033,9 @@
 
 
 /// An abstract class representing a load from some kind of reference storage.
-template <ValueKind K>
-class LoadReferenceInstBase : public UnaryInstructionBase<K> {
+template <SILInstructionKind K>
+class LoadReferenceInstBase
+    : public UnaryInstructionBase<K, SingleValueInstruction> {
   static SILType getResultType(SILType operandTy) {
     assert(operandTy.isAddress() && "loading from non-address operand?");
     auto refType = cast<ReferenceStorageType>(operandTy.getSwiftRValueType());
@@ -2899,7 +3046,8 @@
 
 protected:
   LoadReferenceInstBase(SILDebugLocation loc, SILValue lvalue, IsTake_t isTake)
-    : UnaryInstructionBase<K>(loc, lvalue, getResultType(lvalue->getType())),
+    : UnaryInstructionBase<K, SingleValueInstruction>(loc, lvalue,
+                                             getResultType(lvalue->getType())),
       IsTake(unsigned(isTake)) {
   }
 
@@ -2908,15 +3056,16 @@
 };
 
 /// An abstract class representing a store to some kind of reference storage.
-template <ValueKind K>
-class StoreReferenceInstBase : public SILInstruction {
+template <SILInstructionKind K>
+class StoreReferenceInstBase : public InstructionBase<K, NonValueInstruction> {
   enum { Src, Dest };
   FixedOperandList<2> Operands;
   unsigned IsInitializationOfDest : 1; // FIXME: pack this somewhere
 protected:
   StoreReferenceInstBase(SILDebugLocation loc, SILValue src, SILValue dest,
                          IsInitialization_t isInit)
-    : SILInstruction(K, loc), Operands(this, src, dest),
+    : InstructionBase<K, NonValueInstruction>(loc),
+      Operands(this, src, dest),
       IsInitializationOfDest(unsigned(isInit)) {
   }
 
@@ -2933,15 +3082,11 @@
 
   ArrayRef<Operand> getAllOperands() const { return Operands.asArray(); }
   MutableArrayRef<Operand> getAllOperands() { return Operands.asArray(); }
-
-  static bool classof(const ValueBase *V) {
-    return V->getKind() == K;
-  }
 };
 
 /// Represents a load from a @weak memory location.
 class LoadWeakInst
-  : public LoadReferenceInstBase<ValueKind::LoadWeakInst>
+  : public LoadReferenceInstBase<SILInstructionKind::LoadWeakInst>
 {
   friend SILBuilder;
 
@@ -2954,7 +3099,7 @@
 
 /// Represents a store to a @weak memory location.
 class StoreWeakInst
-  : public StoreReferenceInstBase<ValueKind::StoreWeakInst>
+  : public StoreReferenceInstBase<SILInstructionKind::StoreWeakInst>
 {
   friend SILBuilder;
 
@@ -2968,7 +3113,7 @@
 /// This is only required for address-only unowned references; for loadable
 /// unowned references, it's better to use a load and a strong_retain_unowned.
 class LoadUnownedInst
-  : public LoadReferenceInstBase<ValueKind::LoadUnownedInst>
+  : public LoadReferenceInstBase<SILInstructionKind::LoadUnownedInst>
 {
   friend SILBuilder;
 
@@ -2984,7 +3129,7 @@
 /// This is only required for address-only unowned references; for loadable
 /// unowned references, it's better to use a ref_to_unowned and a store.
 class StoreUnownedInst
-  : public StoreReferenceInstBase<ValueKind::StoreUnownedInst>
+  : public StoreReferenceInstBase<SILInstructionKind::StoreUnownedInst>
 {
   friend SILBuilder;
 
@@ -2998,7 +3143,9 @@
 ///   %1 = load %src
 ///   store %1 to %dest
 /// but a copy instruction must be used for address-only types.
-class CopyAddrInst : public SILInstruction {
+class CopyAddrInst
+    : public InstructionBase<SILInstructionKind::CopyAddrInst,
+                             NonValueInstruction> {
   friend SILBuilder;
 
 public:
@@ -3047,10 +3194,6 @@
 
   ArrayRef<Operand> getAllOperands() const { return Operands.asArray(); }
   MutableArrayRef<Operand> getAllOperands() { return Operands.asArray(); }
-
-  static bool classof(const ValueBase *V) {
-    return V->getKind() == ValueKind::CopyAddrInst;
-  }
 };
 
 /// BindMemoryInst -
@@ -3058,7 +3201,8 @@
 /// Binds memory at the raw pointer %0 to type $T with enough capacity
 /// to hold $1 values.
 class BindMemoryInst final :
-    public SILInstruction,
+    public InstructionBase<SILInstructionKind::BindMemoryInst,
+                           NonValueInstruction>,
     protected llvm::TrailingObjects<BindMemoryInst, Operand> {
 
   typedef llvm::TrailingObjects<BindMemoryInst, Operand> TrailingObjects;
@@ -3120,10 +3264,6 @@
   MutableArrayRef<Operand> getTypeDependentOperands() {
     return getAllOperands().slice(2);
   }
-
-  static bool classof(const ValueBase *V) {
-    return V->getKind() == ValueKind::BindMemoryInst;
-  }
 };
 
 //===----------------------------------------------------------------------===//
@@ -3133,10 +3273,10 @@
 /// ConversionInst - Abstract class representing instructions that convert
 /// values.
 ///
-class ConversionInst : public SILInstruction {
+class ConversionInst : public SingleValueInstruction {
 protected:
-  ConversionInst(ValueKind Kind, SILDebugLocation DebugLoc, SILType Ty)
-      : SILInstruction(Kind, DebugLoc, Ty) {}
+  ConversionInst(SILInstructionKind Kind, SILDebugLocation DebugLoc, SILType Ty)
+      : SingleValueInstruction(Kind, DebugLoc, Ty) {}
 
 public:
   /// All conversion instructions take the converted value, whose reference
@@ -3145,18 +3285,15 @@
   /// affect the reference identity.
   SILValue getConverted() const { return getOperand(0); }
   
-  static bool classof(const ValueBase *V) {
-    return V->getKind() >= ValueKind::First_ConversionInst &&
-      V->getKind() <= ValueKind::Last_ConversionInst;
-  }
+  DEFINE_ABSTRACT_SINGLE_VALUE_INST_BOILERPLATE(ConversionInst)
 };
 
 /// ConvertFunctionInst - Change the type of a function value without
 /// affecting how it will codegen.
 class ConvertFunctionInst final
     : public UnaryInstructionWithTypeDependentOperandsBase<
-          ValueKind::ConvertFunctionInst, ConvertFunctionInst, ConversionInst,
-          /* HAS_RESULT */ true> {
+          SILInstructionKind::ConvertFunctionInst,
+          ConvertFunctionInst, ConversionInst> {
   friend SILBuilder;
 
   ConvertFunctionInst(SILDebugLocation DebugLoc, SILValue Operand,
@@ -3172,7 +3309,7 @@
 /// ThinFunctionToPointerInst - Convert a thin function pointer to a
 /// Builtin.RawPointer.
 class ThinFunctionToPointerInst
-  : public UnaryInstructionBase<ValueKind::ThinFunctionToPointerInst,
+  : public UnaryInstructionBase<SILInstructionKind::ThinFunctionToPointerInst,
                                 ConversionInst>
 {
   friend SILBuilder;
@@ -3186,8 +3323,9 @@
 /// function pointer.
 class PointerToThinFunctionInst final
     : public UnaryInstructionWithTypeDependentOperandsBase<
-          ValueKind::PointerToThinFunctionInst, PointerToThinFunctionInst,
-          ConversionInst, /* HAS_RESULT */ true> {
+          SILInstructionKind::PointerToThinFunctionInst,
+          PointerToThinFunctionInst,
+          ConversionInst> {
   friend SILBuilder;
 
   PointerToThinFunctionInst(SILDebugLocation DebugLoc, SILValue operand,
@@ -3202,9 +3340,10 @@
 };
 
 /// UpcastInst - Perform a conversion of a class instance to a supertype.
-class UpcastInst final : public UnaryInstructionWithTypeDependentOperandsBase<
-                             ValueKind::UpcastInst, UpcastInst, ConversionInst,
-                             /* HAS_RESULT */ true>
+class UpcastInst final
+    : public UnaryInstructionWithTypeDependentOperandsBase<
+                             SILInstructionKind::UpcastInst,
+                             UpcastInst, ConversionInst>
 
 {
   friend SILBuilder;
@@ -3221,7 +3360,8 @@
 
 /// AddressToPointerInst - Convert a SIL address to a Builtin.RawPointer value.
 class AddressToPointerInst
-  : public UnaryInstructionBase<ValueKind::AddressToPointerInst, ConversionInst>
+  : public UnaryInstructionBase<SILInstructionKind::AddressToPointerInst,
+                                ConversionInst>
 {
   friend SILBuilder;
 
@@ -3231,7 +3371,8 @@
 
 /// PointerToAddressInst - Convert a Builtin.RawPointer value to a SIL address.
 class PointerToAddressInst
-  : public UnaryInstructionBase<ValueKind::PointerToAddressInst, ConversionInst>
+  : public UnaryInstructionBase<SILInstructionKind::PointerToAddressInst,
+                                ConversionInst>
 {
   friend SILBuilder;
 
@@ -3257,10 +3398,9 @@
 /// checks.
 class UncheckedRefCastInst final
   : public UnaryInstructionWithTypeDependentOperandsBase<
-                                ValueKind::UncheckedRefCastInst,
+                                SILInstructionKind::UncheckedRefCastInst,
                                 UncheckedRefCastInst,
-                                ConversionInst,
-                                /* HAS_RESULT */ true>
+                                ConversionInst>
 {
   friend SILBuilder;
 
@@ -3277,7 +3417,9 @@
 /// checks. This is a variant of UncheckedRefCast that works on address types,
 /// thus encapsulates an implicit load and take of the reference followed by a
 /// store and initialization of a new reference.
-class UncheckedRefCastAddrInst : public SILInstruction {
+class UncheckedRefCastAddrInst
+    : public InstructionBase<SILInstructionKind::UncheckedRefCastAddrInst,
+                             NonValueInstruction> {
 public:
   enum {
     /// the value being stored
@@ -3305,18 +3447,13 @@
 
   ArrayRef<Operand> getAllOperands() const { return Operands.asArray(); }
   MutableArrayRef<Operand> getAllOperands() { return Operands.asArray(); }
-
-  static bool classof(const ValueBase *V) {
-    return V->getKind() == ValueKind::UncheckedRefCastAddrInst;
-  }
 };
 
 class UncheckedAddrCastInst final
   : public UnaryInstructionWithTypeDependentOperandsBase<
-                                ValueKind::UncheckedAddrCastInst,
+                                SILInstructionKind::UncheckedAddrCastInst,
                                 UncheckedAddrCastInst,
-                                ConversionInst,
-                                true>
+                                ConversionInst>
 {
   friend SILBuilder;
 
@@ -3332,10 +3469,9 @@
 /// Convert a value's binary representation to a trivial type of the same size.
 class UncheckedTrivialBitCastInst final
   : public UnaryInstructionWithTypeDependentOperandsBase<
-                                ValueKind::UncheckedTrivialBitCastInst,
+                                SILInstructionKind::UncheckedTrivialBitCastInst,
                                 UncheckedTrivialBitCastInst,
-                                ConversionInst,
-                                true>
+                                ConversionInst>
 {
   friend SILBuilder;
 
@@ -3353,10 +3489,9 @@
 /// Bitwise copy a value into another value of the same size or smaller.
 class UncheckedBitwiseCastInst final
   : public UnaryInstructionWithTypeDependentOperandsBase<
-                                ValueKind::UncheckedBitwiseCastInst,
+                                SILInstructionKind::UncheckedBitwiseCastInst,
                                 UncheckedBitwiseCastInst,
-                                ConversionInst,
-                                true>
+                                ConversionInst>
 {
   friend SILBuilder;
 
@@ -3372,31 +3507,27 @@
 
 /// Build a Builtin.BridgeObject from a heap object reference by bitwise-or-ing
 /// in bits from a word.
-class RefToBridgeObjectInst : public ConversionInst {
+class RefToBridgeObjectInst
+    : public InstructionBase<SILInstructionKind::RefToBridgeObjectInst,
+                             ConversionInst> {
   friend SILBuilder;
 
   FixedOperandList<2> Operands;
   RefToBridgeObjectInst(SILDebugLocation DebugLoc, SILValue ConvertedValue,
                         SILValue MaskValue, SILType BridgeObjectTy)
-      : ConversionInst(ValueKind::RefToBridgeObjectInst, DebugLoc,
-                       BridgeObjectTy),
+      : InstructionBase(DebugLoc, BridgeObjectTy),
         Operands(this, ConvertedValue, MaskValue) {}
 
 public:
-  
   SILValue getBitsOperand() const { return Operands[1].get(); }
   
   ArrayRef<Operand> getAllOperands() const { return Operands.asArray(); }
   MutableArrayRef<Operand> getAllOperands() { return Operands.asArray(); }
-  
-  static bool classof(const ValueBase *V) {
-    return V->getKind() == ValueKind::RefToBridgeObjectInst;
-  }
 };
 
 /// Extract the heap object reference from a BridgeObject.
 class BridgeObjectToRefInst
-  : public UnaryInstructionBase<ValueKind::BridgeObjectToRefInst,
+  : public UnaryInstructionBase<SILInstructionKind::BridgeObjectToRefInst,
                                 ConversionInst>
 {
   friend SILBuilder;
@@ -3408,7 +3539,7 @@
 
 /// Retrieve the bit pattern of a BridgeObject.
 class BridgeObjectToWordInst
-  : public UnaryInstructionBase<ValueKind::BridgeObjectToWordInst,
+  : public UnaryInstructionBase<SILInstructionKind::BridgeObjectToWordInst,
                                 ConversionInst>
 {
   friend SILBuilder;
@@ -3420,7 +3551,8 @@
 
 /// RefToRawPointer - Convert a reference type to a Builtin.RawPointer.
 class RefToRawPointerInst
-  : public UnaryInstructionBase<ValueKind::RefToRawPointerInst, ConversionInst>
+  : public UnaryInstructionBase<SILInstructionKind::RefToRawPointerInst,
+                                ConversionInst>
 {
   friend SILBuilder;
 
@@ -3430,7 +3562,8 @@
 
 /// RawPointerToRefInst - Convert a Builtin.RawPointer to a reference type.
 class RawPointerToRefInst
-  : public UnaryInstructionBase<ValueKind::RawPointerToRefInst, ConversionInst>
+  : public UnaryInstructionBase<SILInstructionKind::RawPointerToRefInst,
+                                ConversionInst>
 {
   friend SILBuilder;
 
@@ -3443,7 +3576,8 @@
 ///
 /// This does nothing at runtime; it just changes the formal type.
 class RefToUnownedInst
-  : public UnaryInstructionBase<ValueKind::RefToUnownedInst, ConversionInst>
+  : public UnaryInstructionBase<SILInstructionKind::RefToUnownedInst,
+                                ConversionInst>
 {
   friend SILBuilder;
 
@@ -3456,7 +3590,8 @@
 ///
 /// This does nothing at runtime; it just changes the formal type.
 class UnownedToRefInst
-  : public UnaryInstructionBase<ValueKind::UnownedToRefInst, ConversionInst>
+  : public UnaryInstructionBase<SILInstructionKind::UnownedToRefInst,
+                                ConversionInst>
 {
   friend SILBuilder;
 
@@ -3469,7 +3604,8 @@
 ///
 /// This does nothing at runtime; it just changes the formal type.
 class RefToUnmanagedInst
-  : public UnaryInstructionBase<ValueKind::RefToUnmanagedInst, ConversionInst>
+  : public UnaryInstructionBase<SILInstructionKind::RefToUnmanagedInst,
+                                ConversionInst>
 {
   friend SILBuilder;
 
@@ -3482,7 +3618,8 @@
 ///
 /// This does nothing at runtime; it just changes the formal type.
 class UnmanagedToRefInst
-  : public UnaryInstructionBase<ValueKind::UnmanagedToRefInst, ConversionInst>
+  : public UnaryInstructionBase<SILInstructionKind::UnmanagedToRefInst,
+                                ConversionInst>
 {
   friend SILBuilder;
 
@@ -3494,8 +3631,8 @@
 /// context to convert the value to a thick function type.
 class ThinToThickFunctionInst final
     : public UnaryInstructionWithTypeDependentOperandsBase<
-          ValueKind::ThinToThickFunctionInst, ThinToThickFunctionInst,
-          ConversionInst, /* HAS_RESULT */ true> {
+          SILInstructionKind::ThinToThickFunctionInst, ThinToThickFunctionInst,
+          ConversionInst> {
   friend SILBuilder;
 
   ThinToThickFunctionInst(SILDebugLocation DebugLoc, SILValue Operand,
@@ -3519,7 +3656,7 @@
 /// Given a thick metatype value, produces an Objective-C metatype
 /// value.
 class ThickToObjCMetatypeInst
-  : public UnaryInstructionBase<ValueKind::ThickToObjCMetatypeInst,
+  : public UnaryInstructionBase<SILInstructionKind::ThickToObjCMetatypeInst,
                                 ConversionInst>
 {
   friend SILBuilder;
@@ -3532,7 +3669,7 @@
 /// Given an Objective-C metatype value, produces a thick metatype
 /// value.
 class ObjCToThickMetatypeInst
-  : public UnaryInstructionBase<ValueKind::ObjCToThickMetatypeInst,
+  : public UnaryInstructionBase<SILInstructionKind::ObjCToThickMetatypeInst,
                                 ConversionInst>
 {
   friend SILBuilder;
@@ -3544,7 +3681,7 @@
 
 /// Given an Objective-C metatype value, convert it to an AnyObject value.
 class ObjCMetatypeToObjectInst
-  : public UnaryInstructionBase<ValueKind::ObjCMetatypeToObjectInst,
+  : public UnaryInstructionBase<SILInstructionKind::ObjCMetatypeToObjectInst,
                                 ConversionInst>
 {
   friend SILBuilder;
@@ -3557,7 +3694,7 @@
 /// Given an Objective-C existential metatype value, convert it to an AnyObject
 /// value.
 class ObjCExistentialMetatypeToObjectInst
-  : public UnaryInstructionBase<ValueKind::ObjCExistentialMetatypeToObjectInst,
+  : public UnaryInstructionBase<SILInstructionKind::ObjCExistentialMetatypeToObjectInst,
                                 ConversionInst>
 {
   friend SILBuilder;
@@ -3568,13 +3705,14 @@
 };
 
 /// Return the Objective-C Protocol class instance for a protocol.
-class ObjCProtocolInst : public SILInstruction
-{
+class ObjCProtocolInst
+    : public InstructionBase<SILInstructionKind::ObjCProtocolInst,
+                             SingleValueInstruction> {
   friend SILBuilder;
 
   ProtocolDecl *Proto;
   ObjCProtocolInst(SILDebugLocation DebugLoc, ProtocolDecl *Proto, SILType Ty)
-      : SILInstruction(ValueKind::ObjCProtocolInst, DebugLoc, Ty),
+      : InstructionBase(DebugLoc, Ty),
         Proto(Proto) {}
 
 public:
@@ -3582,14 +3720,12 @@
 
   ArrayRef<Operand> getAllOperands() const { return {}; }
   MutableArrayRef<Operand> getAllOperands() { return {}; }
-
-  static bool classof(const ValueBase *V) {
-    return V->getKind() == ValueKind::ObjCProtocolInst;
-  }
 };
 
 /// Test that an address or reference type is not null.
-class IsNonnullInst : public UnaryInstructionBase<ValueKind::IsNonnullInst> {
+class IsNonnullInst
+    : public UnaryInstructionBase<SILInstructionKind::IsNonnullInst,
+                                  SingleValueInstruction> {
   friend SILBuilder;
 
   IsNonnullInst(SILDebugLocation DebugLoc, SILValue Operand, SILType BoolTy)
@@ -3600,10 +3736,9 @@
 /// Perform an unconditional checked cast that aborts if the cast fails.
 class UnconditionalCheckedCastInst final
   : public UnaryInstructionWithTypeDependentOperandsBase<
-                                ValueKind::UnconditionalCheckedCastInst,
+                                SILInstructionKind::UnconditionalCheckedCastInst,
                                 UnconditionalCheckedCastInst,
-                                ConversionInst,
-                                true>
+                                ConversionInst>
 {
   friend SILBuilder;
 
@@ -3634,8 +3769,9 @@
 
 /// Perform an unconditional checked cast that aborts if the cast fails.
 /// The result of the checked cast is left in the destination address.
-class UnconditionalCheckedCastAddrInst : public SILInstruction
-{
+class UnconditionalCheckedCastAddrInst
+    : public InstructionBase<SILInstructionKind::UnconditionalCheckedCastAddrInst,
+                             NonValueInstruction> {
   friend SILBuilder;
 
   enum {
@@ -3664,18 +3800,14 @@
 
   ArrayRef<Operand> getAllOperands() const { return Operands.asArray(); }
   MutableArrayRef<Operand> getAllOperands() { return Operands.asArray(); }
-
-  static bool classof(const ValueBase *V) {
-    return V->getKind() == ValueKind::UnconditionalCheckedCastAddrInst;
-  }
 };
 
 /// Perform an unconditional checked cast that aborts if the cast fails.
 /// The result of the checked cast is left in the destination.
 class UnconditionalCheckedCastValueInst final
     : public UnaryInstructionWithTypeDependentOperandsBase<
-          ValueKind::UnconditionalCheckedCastValueInst,
-          UnconditionalCheckedCastValueInst, ConversionInst, true> {
+          SILInstructionKind::UnconditionalCheckedCastValueInst,
+          UnconditionalCheckedCastValueInst, ConversionInst> {
   friend SILBuilder;
 
   UnconditionalCheckedCastValueInst(SILDebugLocation DebugLoc, SILValue Operand,
@@ -3690,7 +3822,9 @@
 };
 
 /// StructInst - Represents a constructed loadable struct.
-class StructInst : public SILInstruction {
+class StructInst
+    : public InstructionBase<SILInstructionKind::StructInst,
+                             SingleValueInstruction> {
   friend SILBuilder;
 
   TailAllocatedOperandList<0> Operands;
@@ -3779,15 +3913,11 @@
     assert(s && "A struct should always have a StructDecl associated with it");
     return s;
   }
-
-  static bool classof(const ValueBase *V) {
-    return V->getKind() == ValueKind::StructInst;
-  }
 };
 
 /// RefCountingInst - An abstract class of instructions which
 /// manipulate the reference count of their object operand.
-class RefCountingInst : public SILInstruction {
+class RefCountingInst : public NonValueInstruction {
 public:
   /// The atomicity of a reference counting operation to be used.
   enum class Atomicity : bool {
@@ -3799,30 +3929,24 @@
 protected:
   Atomicity atomicity;
 protected:
-  RefCountingInst(ValueKind Kind, SILDebugLocation DebugLoc)
-      : SILInstruction(Kind, DebugLoc), atomicity(Atomicity::Atomic) {}
-
-  RefCountingInst(ValueKind Kind, SILDebugLocation DebugLoc, SILType Type)
-      : SILInstruction(Kind, DebugLoc, Type), atomicity(Atomicity::Atomic) {}
+  RefCountingInst(SILInstructionKind Kind, SILDebugLocation DebugLoc)
+      : NonValueInstruction(Kind, DebugLoc), atomicity(Atomicity::Atomic) {}
 
 public:
-  static bool classof(const ValueBase *V) {
-    return V->getKind() >= ValueKind::First_RefCountingInst &&
-           V->getKind() <= ValueKind::Last_RefCountingInst;
-  }
-
   void setAtomicity(Atomicity flag) { atomicity = flag; }
   void setNonAtomic() { atomicity = Atomicity::NonAtomic; }
   void setAtomic() { atomicity = Atomicity::Atomic; }
   Atomicity getAtomicity() const { return atomicity; }
   bool isNonAtomic() const { return atomicity == Atomicity::NonAtomic; }
   bool isAtomic() const { return atomicity == Atomicity::Atomic; }
+
+  DEFINE_ABSTRACT_NON_VALUE_INST_BOILERPLATE(RefCountingInst)
 };
 
 /// RetainValueInst - Copies a loadable value.
-class RetainValueInst : public UnaryInstructionBase<ValueKind::RetainValueInst,
-                                                    RefCountingInst,
-                                                    /*HasValue*/ false> {
+class RetainValueInst
+    : public UnaryInstructionBase<SILInstructionKind::RetainValueInst,
+                                  RefCountingInst> {
   friend SILBuilder;
 
   RetainValueInst(SILDebugLocation DebugLoc, SILValue operand,
@@ -3834,8 +3958,8 @@
 
 /// RetainValueAddrInst - Copies a loadable value by address.
 class RetainValueAddrInst
-    : public UnaryInstructionBase<ValueKind::RetainValueAddrInst,
-                                  RefCountingInst, /*HasValue*/ false> {
+    : public UnaryInstructionBase<SILInstructionKind::RetainValueAddrInst,
+                                  RefCountingInst> {
   friend SILBuilder;
 
   RetainValueAddrInst(SILDebugLocation DebugLoc, SILValue operand,
@@ -3846,9 +3970,9 @@
 };
 
 /// ReleaseValueInst - Destroys a loadable value.
-class ReleaseValueInst : public UnaryInstructionBase<ValueKind::ReleaseValueInst,
-                                                     RefCountingInst,
-                                                     /*HasValue*/ false> {
+class ReleaseValueInst
+    : public UnaryInstructionBase<SILInstructionKind::ReleaseValueInst,
+                                  RefCountingInst> {
   friend SILBuilder;
 
   ReleaseValueInst(SILDebugLocation DebugLoc, SILValue operand,
@@ -3860,8 +3984,8 @@
 
 /// ReleaseValueInst - Destroys a loadable value by address.
 class ReleaseValueAddrInst
-    : public UnaryInstructionBase<ValueKind::ReleaseValueAddrInst,
-                                  RefCountingInst, /*HasValue*/ false> {
+    : public UnaryInstructionBase<SILInstructionKind::ReleaseValueAddrInst,
+                                  RefCountingInst> {
   friend SILBuilder;
 
   ReleaseValueAddrInst(SILDebugLocation DebugLoc, SILValue operand,
@@ -3875,9 +3999,8 @@
 /// in ownership qualified SIL. Please do not use this EVER unless you are
 /// implementing a part of the stdlib called Unmanaged.
 class UnmanagedRetainValueInst
-    : public UnaryInstructionBase<ValueKind::UnmanagedRetainValueInst,
-                                  RefCountingInst,
-                                  /*HasValue*/ false> {
+    : public UnaryInstructionBase<SILInstructionKind::UnmanagedRetainValueInst,
+                                  RefCountingInst> {
   friend SILBuilder;
 
   UnmanagedRetainValueInst(SILDebugLocation DebugLoc, SILValue operand,
@@ -3891,9 +4014,8 @@
 /// use in ownership qualified SIL. Please do not use this EVER unless you are
 /// implementing a part of the stdlib called Unmanaged.
 class UnmanagedReleaseValueInst
-    : public UnaryInstructionBase<ValueKind::UnmanagedReleaseValueInst,
-                                  RefCountingInst,
-                                  /*HasValue*/ false> {
+    : public UnaryInstructionBase<SILInstructionKind::UnmanagedReleaseValueInst,
+                                  RefCountingInst> {
   friend SILBuilder;
 
   UnmanagedReleaseValueInst(SILDebugLocation DebugLoc, SILValue operand,
@@ -3906,9 +4028,8 @@
 /// Transfers ownership of a loadable value to the current autorelease
 /// pool. Unmanaged, so it is ignored from an ownership balancing perspective.
 class UnmanagedAutoreleaseValueInst
-                  : public UnaryInstructionBase<ValueKind::UnmanagedAutoreleaseValueInst,
-                                                RefCountingInst,
-                                                /*HasValue*/ false> {
+    : public UnaryInstructionBase<SILInstructionKind::UnmanagedAutoreleaseValueInst,
+                                  RefCountingInst> {
   friend SILBuilder;
 
   UnmanagedAutoreleaseValueInst(SILDebugLocation DebugLoc, SILValue operand,
@@ -3920,9 +4041,8 @@
 
 /// Transfers ownership of a loadable value to the current autorelease pool.
 class AutoreleaseValueInst
-                  : public UnaryInstructionBase<ValueKind::AutoreleaseValueInst,
-                                                RefCountingInst,
-                                                /*HasValue*/ false> {
+    : public UnaryInstructionBase<SILInstructionKind::AutoreleaseValueInst,
+                                  RefCountingInst> {
   friend SILBuilder;
 
   AutoreleaseValueInst(SILDebugLocation DebugLoc, SILValue operand,
@@ -3937,9 +4057,8 @@
 /// This is the same operation what's done by a strong_release immediately
 /// before it calls the deallocator of the object.
 class SetDeallocatingInst
-                 : public UnaryInstructionBase<ValueKind::SetDeallocatingInst,
-                                                RefCountingInst,
-                                                /*HasValue*/ false> {
+    : public UnaryInstructionBase<SILInstructionKind::SetDeallocatingInst,
+                                  RefCountingInst> {
   friend SILBuilder;
 
   SetDeallocatingInst(SILDebugLocation DebugLoc, SILValue operand,
@@ -3956,21 +4075,36 @@
 /// operations.  (This should generally be straightforward, as pin and
 /// unpin may be conservatively assumed to have arbitrary
 /// side-effects.)
+///
+/// This can't be a RefCountingInst because it returns a value.
 class StrongPinInst
-  : public UnaryInstructionBase<ValueKind::StrongPinInst, RefCountingInst,
-                                /*HasResult*/ true>
+  : public UnaryInstructionBase<SILInstructionKind::StrongPinInst,
+                                SingleValueInstruction>
 {
+public:
+  using Atomicity = RefCountingInst::Atomicity;
+
+private:
   friend SILBuilder;
+  Atomicity atomicity;
 
   StrongPinInst(SILDebugLocation DebugLoc, SILValue operand,
                 Atomicity atomicity);
+
+public:
+  void setAtomicity(Atomicity flag) { atomicity = flag; }
+  void setNonAtomic() { atomicity = Atomicity::NonAtomic; }
+  void setAtomic() { atomicity = Atomicity::Atomic; }
+  Atomicity getAtomicity() const { return atomicity; }
+  bool isNonAtomic() const { return atomicity == Atomicity::NonAtomic; }
+  bool isAtomic() const { return atomicity == Atomicity::Atomic; }
 };
 
 /// StrongUnpinInst - Given that the operand is the result of a
 /// strong_pin instruction, unpin it.
 class StrongUnpinInst
-  : public UnaryInstructionBase<ValueKind::StrongUnpinInst, RefCountingInst,
-                                /*HasResult*/ false>
+  : public UnaryInstructionBase<SILInstructionKind::StrongUnpinInst,
+                                RefCountingInst>
 {
   friend SILBuilder;
 
@@ -3985,7 +4119,9 @@
 ///
 /// This instruction can only appear at the end of a gobal variable's
 /// static initializer list.
-class ObjectInst : public SILInstruction {
+class ObjectInst
+    : public InstructionBase<SILInstructionKind::ObjectInst,
+                             SingleValueInstruction> {
   friend SILBuilder;
 
   unsigned NumBaseElements;
@@ -4025,15 +4161,13 @@
 
   ArrayRef<Operand> getAllOperands() const { return Operands.asArray(); }
   MutableArrayRef<Operand> getAllOperands() { return Operands.asArray(); }
-
-  static bool classof(const ValueBase *V) {
-    return V->getKind() == ValueKind::ObjectInst;
-  }
 };
 
 
 /// TupleInst - Represents a constructed loadable tuple.
-class TupleInst : public SILInstruction {
+class TupleInst
+    : public InstructionBase<SILInstructionKind::TupleInst,
+                             SingleValueInstruction> {
   friend SILBuilder;
 
   TailAllocatedOperandList<0> Operands;
@@ -4071,10 +4205,6 @@
   ArrayRef<Operand> getAllOperands() const { return Operands.asArray(); }
   MutableArrayRef<Operand> getAllOperands() { return Operands.asArray(); }
 
-  static bool classof(const ValueBase *V) {
-    return V->getKind() == ValueKind::TupleInst;
-  }
-
   TupleType *getTupleType() const {
     return getType().getSwiftRValueType()->castTo<TupleType>();
   }
@@ -4112,7 +4242,9 @@
 
 /// Represents a loadable enum constructed from one of its
 /// elements.
-class EnumInst : public SILInstruction {
+class EnumInst
+    : public InstructionBase<SILInstructionKind::EnumInst,
+                             SingleValueInstruction> {
   friend SILBuilder;
 
   Optional<FixedOperandList<1>> OptionalOperand;
@@ -4120,7 +4252,7 @@
 
   EnumInst(SILDebugLocation DebugLoc, SILValue Operand,
            EnumElementDecl *Element, SILType ResultTy)
-      : SILInstruction(ValueKind::EnumInst, DebugLoc, ResultTy),
+      : InstructionBase(DebugLoc, ResultTy),
         Element(Element) {
     if (Operand) {
       OptionalOperand.emplace(this, Operand);
@@ -4143,16 +4275,13 @@
     return OptionalOperand
       ? OptionalOperand->asArray() : MutableArrayRef<Operand>{};
   }
-
-  static bool classof(const ValueBase *V) {
-    return V->getKind() == ValueKind::EnumInst;
-  }
 };
 
 /// Unsafely project the data for an enum case out of an enum without checking
 /// the tag.
 class UncheckedEnumDataInst
-  : public UnaryInstructionBase<ValueKind::UncheckedEnumDataInst>
+  : public UnaryInstructionBase<SILInstructionKind::UncheckedEnumDataInst,
+                                SingleValueInstruction>
 {
   friend SILBuilder;
 
@@ -4186,7 +4315,8 @@
 /// Projects the address of the data for a case inside an uninitialized enum in
 /// order to initialize the payload for that case.
 class InitEnumDataAddrInst
-  : public UnaryInstructionBase<ValueKind::InitEnumDataAddrInst>
+  : public UnaryInstructionBase<SILInstructionKind::InitEnumDataAddrInst,
+                                SingleValueInstruction>
 {
   friend SILBuilder;
 
@@ -4203,9 +4333,8 @@
 /// InjectEnumAddrInst - Tags an enum as containing a case. The data for
 /// that case, if any, must have been written into the enum first.
 class InjectEnumAddrInst
-  : public UnaryInstructionBase<ValueKind::InjectEnumAddrInst,
-                                SILInstruction,
-                                /*HAS_RESULT*/ false>
+  : public UnaryInstructionBase<SILInstructionKind::InjectEnumAddrInst,
+                                NonValueInstruction>
 {
   friend SILBuilder;
 
@@ -4222,7 +4351,8 @@
 /// Invalidate an enum value and take ownership of its payload data
 /// without moving it in memory.
 class UncheckedTakeEnumDataAddrInst
-  : public UnaryInstructionBase<ValueKind::UncheckedTakeEnumDataAddrInst>
+  : public UnaryInstructionBase<SILInstructionKind::UncheckedTakeEnumDataAddrInst,
+                                SingleValueInstruction>
 {
   friend SILBuilder;
 
@@ -4259,7 +4389,7 @@
 // The template parameter represents a type of case values to be compared
 // with the operand of a select instruction.
 template <class Derived, class T>
-class SelectInstBase : public SILInstruction {
+class SelectInstBase : public SingleValueInstruction {
 protected:
   unsigned NumCases : 31;
   unsigned HasDefault : 1;
@@ -4269,10 +4399,10 @@
   TailAllocatedOperandList<1> Operands;
 
 public:
-  SelectInstBase(ValueKind kind, SILDebugLocation DebugLoc, SILType type,
-                 unsigned numCases, bool hasDefault,
+  SelectInstBase(SILInstructionKind kind, SILDebugLocation DebugLoc,
+                 SILType type, unsigned numCases, bool hasDefault,
                  ArrayRef<SILValue> operands, SILValue operand)
-      : SILInstruction(kind, DebugLoc, type), NumCases(numCases),
+      : SingleValueInstruction(kind, DebugLoc, type), NumCases(numCases),
         HasDefault(hasDefault), Operands(this, operands, operand) {}
 
   SILValue getOperand() const { return Operands[0].get(); }
@@ -4309,17 +4439,19 @@
   }
 
 protected:
-  SelectEnumInstBase(
-      ValueKind Kind, SILDebugLocation DebugLoc, SILValue Enum, SILType Type,
-      SILValue DefaultValue,
-      ArrayRef<std::pair<EnumElementDecl *, SILValue>> CaseValues);
-
+  SelectEnumInstBase(SILInstructionKind kind, SILDebugLocation debugLoc,
+                     SILType type, SILValue enumValue, SILValue defaultValue,
+                     ArrayRef<std::pair<EnumElementDecl *, SILValue>> cases,
+                     Optional<ArrayRef<ProfileCounter>> CaseCounts,
+                     ProfileCounter DefaultCount);
   template <typename SELECT_ENUM_INST>
   static SELECT_ENUM_INST *
   createSelectEnum(SILDebugLocation DebugLoc, SILValue Enum, SILType Type,
                    SILValue DefaultValue,
                    ArrayRef<std::pair<EnumElementDecl *, SILValue>> CaseValues,
-                   SILFunction &F);
+                   SILFunction &F,
+                   Optional<ArrayRef<ProfileCounter>> CaseCounts,
+                   ProfileCounter DefaultCount);
 
 public:
   SILValue getEnumOperand() const { return getOperand(); }
@@ -4360,7 +4492,9 @@
 };
   
 /// Select one of a set of values based on the case of an enum.
-class SelectEnumInst : public SelectEnumInstBase {
+class SelectEnumInst
+    : public InstructionBase<SILInstructionKind::SelectEnumInst,
+                             SelectEnumInstBase> {
   friend SILBuilder;
 
 private:
@@ -4368,48 +4502,46 @@
 
   SelectEnumInst(SILDebugLocation DebugLoc, SILValue Operand, SILType Type,
                  SILValue DefaultValue,
-                 ArrayRef<std::pair<EnumElementDecl *, SILValue>> CaseValues)
-      : SelectEnumInstBase(ValueKind::SelectEnumInst, DebugLoc, Operand, Type,
-                           DefaultValue, CaseValues) {}
-
+                 ArrayRef<std::pair<EnumElementDecl *, SILValue>> CaseValues,
+                 Optional<ArrayRef<ProfileCounter>> CaseCounts,
+                 ProfileCounter DefaultCount)
+      : InstructionBase(DebugLoc, Type, Operand, DefaultValue, CaseValues,
+                        CaseCounts, DefaultCount) {}
   static SelectEnumInst *
   create(SILDebugLocation DebugLoc, SILValue Operand, SILType Type,
          SILValue DefaultValue,
          ArrayRef<std::pair<EnumElementDecl *, SILValue>> CaseValues,
-         SILFunction &F);
-
-public:
-  static bool classof(const ValueBase *V) {
-    return V->getKind() == ValueKind::SelectEnumInst;
-  }
+         SILFunction &F, Optional<ArrayRef<ProfileCounter>> CaseCounts,
+         ProfileCounter DefaultCount);
 };
 
 /// Select one of a set of values based on the case of an enum.
-class SelectEnumAddrInst : public SelectEnumInstBase {
+class SelectEnumAddrInst
+    : public InstructionBase<SILInstructionKind::SelectEnumAddrInst,
+                             SelectEnumInstBase> {
   friend SILBuilder;
   friend SelectEnumInstBase;
 
   SelectEnumAddrInst(
       SILDebugLocation DebugLoc, SILValue Operand, SILType Type,
       SILValue DefaultValue,
-      ArrayRef<std::pair<EnumElementDecl *, SILValue>> CaseValues)
-      : SelectEnumInstBase(ValueKind::SelectEnumAddrInst, DebugLoc, Operand,
-                           Type, DefaultValue, CaseValues) {}
-
+      ArrayRef<std::pair<EnumElementDecl *, SILValue>> CaseValues,
+      Optional<ArrayRef<ProfileCounter>> CaseCounts,
+      ProfileCounter DefaultCount)
+      : InstructionBase(DebugLoc, Type, Operand, DefaultValue, CaseValues,
+                        CaseCounts, DefaultCount) {}
   static SelectEnumAddrInst *
   create(SILDebugLocation DebugLoc, SILValue Operand, SILType Type,
          SILValue DefaultValue,
          ArrayRef<std::pair<EnumElementDecl *, SILValue>> CaseValues,
-         SILFunction &F);
-
-public:
-  static bool classof(const ValueBase *V) {
-    return V->getKind() == ValueKind::SelectEnumAddrInst;
-  }
+         SILFunction &F, Optional<ArrayRef<ProfileCounter>> CaseCounts,
+         ProfileCounter DefaultCount);
 };
 
 /// Select on a value of a builtin integer type.
-class SelectValueInst : public SelectInstBase<SelectValueInst, SILValue> {
+class SelectValueInst
+    : public InstructionBase<SILInstructionKind::SelectValueInst,
+                             SelectInstBase<SelectValueInst, SILValue>> {
   friend SILBuilder;
 
   SelectValueInst(SILDebugLocation DebugLoc, SILValue Operand, SILType Type,
@@ -4438,16 +4570,13 @@
     assert(HasDefault && "doesn't have a default");
     return getCaseBuf()[NumCases*2];
   }
-
-  static bool classof(const ValueBase *V) {
-    return V->getKind() == ValueKind::SelectValueInst;
-  }
 };
 
 /// MetatypeInst - Represents the production of an instance of a given metatype
 /// named statically.
 class MetatypeInst final
-    : public SILInstruction,
+    : public InstructionBase<SILInstructionKind::MetatypeInst,
+                             SingleValueInstruction>,
       private llvm::TrailingObjects<MetatypeInst, Operand> {
   friend TrailingObjects;
   friend SILBuilder;
@@ -4485,15 +4614,12 @@
   MutableArrayRef<Operand> getTypeDependentOperands() {
     return { getTrailingObjects<Operand>(), NumOperands };
   }
-
-  static bool classof(const ValueBase *V) {
-    return V->getKind() == ValueKind::MetatypeInst;
-  }
 };
 
 /// Represents loading a dynamic metatype from a value.
 class ValueMetatypeInst
-  : public UnaryInstructionBase<ValueKind::ValueMetatypeInst>
+  : public UnaryInstructionBase<SILInstructionKind::ValueMetatypeInst,
+                                SingleValueInstruction>
 {
   friend SILBuilder;
 
@@ -4504,7 +4630,8 @@
 /// ExistentialMetatype - Represents loading a dynamic metatype from an
 /// existential container.
 class ExistentialMetatypeInst
-  : public UnaryInstructionBase<ValueKind::ExistentialMetatypeInst>
+  : public UnaryInstructionBase<SILInstructionKind::ExistentialMetatypeInst,
+                                SingleValueInstruction>
 {
   friend SILBuilder;
 
@@ -4515,7 +4642,8 @@
 
 /// Extract a numbered element out of a value of tuple type.
 class TupleExtractInst
-  : public UnaryInstructionBase<ValueKind::TupleExtractInst>
+  : public UnaryInstructionBase<SILInstructionKind::TupleExtractInst,
+                                SingleValueInstruction>
 {
   friend SILBuilder;
 
@@ -4544,7 +4672,8 @@
 
 /// Derive the address of a numbered element from the address of a tuple.
 class TupleElementAddrInst
-  : public UnaryInstructionBase<ValueKind::TupleElementAddrInst>
+  : public UnaryInstructionBase<SILInstructionKind::TupleElementAddrInst,
+                                SingleValueInstruction>
 {
   friend SILBuilder;
 
@@ -4565,7 +4694,8 @@
 
 /// Extract a physical, fragile field out of a value of struct type.
 class StructExtractInst
-  : public UnaryInstructionBase<ValueKind::StructExtractInst>
+  : public UnaryInstructionBase<SILInstructionKind::StructExtractInst,
+                                SingleValueInstruction>
 {
   friend SILBuilder;
 
@@ -4607,7 +4737,8 @@
 
 /// Derive the address of a physical field from the address of a struct.
 class StructElementAddrInst
-  : public UnaryInstructionBase<ValueKind::StructElementAddrInst>
+  : public UnaryInstructionBase<SILInstructionKind::StructElementAddrInst,
+                                SingleValueInstruction>
 {
   friend SILBuilder;
 
@@ -4641,7 +4772,8 @@
 /// RefElementAddrInst - Derive the address of a named element in a reference
 /// type instance.
 class RefElementAddrInst
-  : public UnaryInstructionBase<ValueKind::RefElementAddrInst>
+  : public UnaryInstructionBase<SILInstructionKind::RefElementAddrInst,
+                                SingleValueInstruction>
 {
   friend SILBuilder;
 
@@ -4675,7 +4807,8 @@
 /// RefTailAddrInst - Derive the address of the first element of the first
 /// tail-allocated array in a reference type instance.
 class RefTailAddrInst
-  : public UnaryInstructionBase<ValueKind::RefTailAddrInst>
+  : public UnaryInstructionBase<SILInstructionKind::RefTailAddrInst,
+                                SingleValueInstruction>
 {
   friend SILBuilder;
 
@@ -4694,13 +4827,13 @@
 
 /// MethodInst - Abstract base for instructions that implement dynamic
 /// method lookup.
-class MethodInst : public SILInstruction {
+class MethodInst : public SingleValueInstruction {
   SILDeclRef Member;
   bool Volatile;
 public:
-  MethodInst(ValueKind Kind, SILDebugLocation DebugLoc, SILType Ty,
+  MethodInst(SILInstructionKind Kind, SILDebugLocation DebugLoc, SILType Ty,
              SILDeclRef Member, bool Volatile = false)
-      : SILInstruction(Kind, DebugLoc, Ty), Member(Member), Volatile(Volatile) {
+      : SingleValueInstruction(Kind, DebugLoc, Ty), Member(Member), Volatile(Volatile) {
   }
 
   SILDeclRef getMember() const { return Member; }
@@ -4708,17 +4841,15 @@
   /// True if this dynamic dispatch is semantically required.
   bool isVolatile() const { return Volatile; }
 
-  static bool classof(const ValueBase *V) {
-    return V->getKind() >= ValueKind::First_MethodInst &&
-      V->getKind() <= ValueKind::Last_MethodInst;
-  }
+  DEFINE_ABSTRACT_SINGLE_VALUE_INST_BOILERPLATE(MethodInst)
 };
 
 /// ClassMethodInst - Given the address of a value of class type and a method
 /// constant, extracts the implementation of that method for the dynamic
 /// instance type of the class.
 class ClassMethodInst
-  : public UnaryInstructionBase<ValueKind::ClassMethodInst, MethodInst>
+    : public UnaryInstructionBase<SILInstructionKind::ClassMethodInst,
+                                  MethodInst>
 {
   friend SILBuilder;
 
@@ -4731,7 +4862,7 @@
 /// constant, extracts the implementation of that method for the superclass of
 /// the static type of the class.
 class SuperMethodInst
-  : public UnaryInstructionBase<ValueKind::SuperMethodInst, MethodInst>
+  : public UnaryInstructionBase<SILInstructionKind::SuperMethodInst, MethodInst>
 {
   friend SILBuilder;
 
@@ -4744,7 +4875,8 @@
 /// and a protocol method constant, extracts the implementation of that method
 /// for the type.
 class WitnessMethodInst final
-    : public MethodInst,
+    : public InstructionBase<SILInstructionKind::WitnessMethodInst,
+                             MethodInst>,
       llvm::TrailingObjects<WitnessMethodInst, Operand> {
   friend TrailingObjects;
   friend SILBuilder;
@@ -4757,8 +4889,7 @@
                     ProtocolConformanceRef Conformance, SILDeclRef Member,
                     SILType Ty, ArrayRef<SILValue> TypeDependentOperands,
                     bool Volatile = false)
-      : MethodInst(ValueKind::WitnessMethodInst, DebugLoc, Ty, Member,
-                   Volatile),
+      : InstructionBase(DebugLoc, Ty, Member, Volatile),
         LookupType(LookupType), Conformance(Conformance),
         NumOperands(TypeDependentOperands.size()) {
     TrailingOperandsList::InitOperandsList(getAllOperands().begin(), this,
@@ -4802,10 +4933,6 @@
   MutableArrayRef<Operand> getTypeDependentOperands() {
     return { getTrailingObjects<Operand>(), NumOperands };
   }
-
-  static bool classof(const ValueBase *V) {
-    return V->getKind() == ValueKind::WitnessMethodInst;
-  }
 };
 
 /// Given the address of a value of AnyObject protocol type and a method
@@ -4814,10 +4941,9 @@
 /// can fail at run-time
 class DynamicMethodInst final
   : public UnaryInstructionWithTypeDependentOperandsBase<
-                                   ValueKind::DynamicMethodInst,
+                                   SILInstructionKind::DynamicMethodInst,
                                    DynamicMethodInst,
-                                   MethodInst,
-                                   true>
+                                   MethodInst>
 {
   friend SILBuilder;
 
@@ -4844,7 +4970,8 @@
 /// existential by returning a pointer to a fresh archetype T, which also
 /// captures the (dynamic) conformances.
 class OpenExistentialAddrInst
-  : public UnaryInstructionBase<ValueKind::OpenExistentialAddrInst>
+  : public UnaryInstructionBase<SILInstructionKind::OpenExistentialAddrInst,
+                                SingleValueInstruction>
 {
   friend SILBuilder;
   OpenedExistentialAccess ForAccess;
@@ -4860,7 +4987,8 @@
 /// existential by returning a pointer to a fresh archetype T, which also
 /// captures the (dynamic) conformances.
 class OpenExistentialValueInst
-    : public UnaryInstructionBase<ValueKind::OpenExistentialValueInst> {
+    : public UnaryInstructionBase<SILInstructionKind::OpenExistentialValueInst,
+                                  SingleValueInstruction> {
   friend SILBuilder;
 
   OpenExistentialValueInst(SILDebugLocation DebugLoc, SILValue Operand,
@@ -4871,7 +4999,8 @@
 /// existential by returning a pointer to a fresh archetype T, which also
 /// captures the (dynamic) conformances.
 class OpenExistentialRefInst
-  : public UnaryInstructionBase<ValueKind::OpenExistentialRefInst>
+  : public UnaryInstructionBase<SILInstructionKind::OpenExistentialRefInst,
+                                SingleValueInstruction>
 {
   friend SILBuilder;
 
@@ -4884,7 +5013,8 @@
 /// archetype metatype T.Type, which also captures the (dynamic)
 /// conformances.
 class OpenExistentialMetatypeInst
-  : public UnaryInstructionBase<ValueKind::OpenExistentialMetatypeInst>
+  : public UnaryInstructionBase<SILInstructionKind::OpenExistentialMetatypeInst,
+                                SingleValueInstruction>
 {
   friend SILBuilder;
 
@@ -4896,7 +5026,8 @@
 /// "opens" the existential by returning a pointer to a fresh
 /// archetype T, which also captures the (dynamic) conformances.
 class OpenExistentialBoxInst
-  : public UnaryInstructionBase<ValueKind::OpenExistentialBoxInst>
+  : public UnaryInstructionBase<SILInstructionKind::OpenExistentialBoxInst,
+                                SingleValueInstruction>
 {
   friend SILBuilder;
 
@@ -4907,7 +5038,8 @@
 /// Given a boxed existential container, "opens" the existential by returning a
 /// fresh archetype T, which also captures the (dynamic) conformances.
 class OpenExistentialBoxValueInst
-  : public UnaryInstructionBase<ValueKind::OpenExistentialBoxValueInst>
+  : public UnaryInstructionBase<SILInstructionKind::OpenExistentialBoxValueInst,
+                                SingleValueInstruction>
 {
   friend SILBuilder;
 
@@ -4921,10 +5053,9 @@
 /// concrete value inside the existential container.
 class InitExistentialAddrInst final
   : public UnaryInstructionWithTypeDependentOperandsBase<
-                                ValueKind::InitExistentialAddrInst,
+                                SILInstructionKind::InitExistentialAddrInst,
                                 InitExistentialAddrInst,
-                                SILInstruction,
-                                true>
+                                SingleValueInstruction>
 {
   friend SILBuilder;
 
@@ -4966,8 +5097,8 @@
 /// concrete value inside the existential container.
 class InitExistentialValueInst final
     : public UnaryInstructionWithTypeDependentOperandsBase<
-          ValueKind::InitExistentialValueInst, InitExistentialValueInst,
-          SILInstruction, true> {
+          SILInstructionKind::InitExistentialValueInst, InitExistentialValueInst,
+          SingleValueInstruction> {
   friend SILBuilder;
 
   CanType ConcreteType;
@@ -5000,10 +5131,9 @@
 /// class instance.
 class InitExistentialRefInst final
   : public UnaryInstructionWithTypeDependentOperandsBase<
-                                ValueKind::InitExistentialRefInst,
+                                SILInstructionKind::InitExistentialRefInst,
                                 InitExistentialRefInst,
-                                SILInstruction,
-                                true>
+                                SingleValueInstruction>
 {
   friend SILBuilder;
 
@@ -5042,10 +5172,9 @@
 /// the metatype.
 class InitExistentialMetatypeInst final
   : public UnaryInstructionWithTypeDependentOperandsBase<
-                                  ValueKind::InitExistentialMetatypeInst,
+                                  SILInstructionKind::InitExistentialMetatypeInst,
                                   InitExistentialMetatypeInst,
-                                  SILInstruction,
-                                  true,
+                                  SingleValueInstruction,
                                   ProtocolConformanceRef>
 {
   friend SILBuilder;
@@ -5088,9 +5217,8 @@
 /// existentials; a fully-initialized existential can be destroyed with
 /// DestroyAddrInst and deallocated with DeallocStackInst.
 class DeinitExistentialAddrInst
-  : public UnaryInstructionBase<ValueKind::DeinitExistentialAddrInst,
-                                SILInstruction,
-                                /*HAS_RESULT*/ false>
+  : public UnaryInstructionBase<SILInstructionKind::DeinitExistentialAddrInst,
+                                NonValueInstruction>
 {
   friend SILBuilder;
 
@@ -5099,8 +5227,8 @@
 };
 
 class DeinitExistentialValueInst
-    : public UnaryInstructionBase<ValueKind::DeinitExistentialValueInst,
-                                  SILInstruction, /*HAS_RESULT*/ false> {
+    : public UnaryInstructionBase<SILInstructionKind::DeinitExistentialValueInst,
+                                  NonValueInstruction> {
   friend SILBuilder;
 
   DeinitExistentialValueInst(SILDebugLocation DebugLoc, SILValue Existential)
@@ -5109,8 +5237,8 @@
 
 /// Projects the capture storage address from a @block_storage address.
 class ProjectBlockStorageInst
-  : public UnaryInstructionBase<ValueKind::ProjectBlockStorageInst,
-                                SILInstruction>
+  : public UnaryInstructionBase<SILInstructionKind::ProjectBlockStorageInst,
+                                SingleValueInstruction>
 {
   friend SILBuilder;
 
@@ -5122,7 +5250,9 @@
 
 /// Initializes a block header, creating a block that
 /// invokes a given thin cdecl function.
-class InitBlockStorageHeaderInst : public SILInstruction {
+class InitBlockStorageHeaderInst
+    : public InstructionBase<SILInstructionKind::InitBlockStorageHeaderInst,
+                             SingleValueInstruction> {
   friend SILBuilder;
 
   enum { BlockStorage, InvokeFunction };
@@ -5139,8 +5269,7 @@
   InitBlockStorageHeaderInst(SILDebugLocation DebugLoc, SILValue BlockStorage,
                              SILValue InvokeFunction, SILType BlockType,
                              SubstitutionList Subs)
-      : SILInstruction(ValueKind::InitBlockStorageHeaderInst, DebugLoc,
-                       BlockType),
+      : InstructionBase(DebugLoc, BlockType),
         NumSubstitutions(Subs.size()),
         Operands(this, BlockStorage, InvokeFunction) {
     memcpy(getSubstitutionsStorage(), Subs.begin(),
@@ -5163,17 +5292,12 @@
 
   ArrayRef<Operand> getAllOperands() const { return Operands.asArray(); }
   MutableArrayRef<Operand> getAllOperands() { return Operands.asArray(); }
-
-  static bool classof(const ValueBase *V) {
-    return V->getKind() == ValueKind::InitBlockStorageHeaderInst;
-  }
 };
 
 /// StrongRetainInst - Increase the strong reference count of an object.
 class StrongRetainInst
-  : public UnaryInstructionBase<ValueKind::StrongRetainInst,
-                                RefCountingInst,
-                                /*HAS_RESULT*/ false>
+  : public UnaryInstructionBase<SILInstructionKind::StrongRetainInst,
+                                RefCountingInst>
 {
   friend SILBuilder;
 
@@ -5190,8 +5314,8 @@
 /// zero.  It can be deallocated when both its strong reference and
 /// weak reference counts reach zero.
 class StrongReleaseInst
-  : public UnaryInstructionBase<ValueKind::StrongReleaseInst,
-                                RefCountingInst, /*HAS_RESULT*/ false>
+  : public UnaryInstructionBase<SILInstructionKind::StrongReleaseInst,
+                                RefCountingInst>
 {
   friend SILBuilder;
 
@@ -5207,8 +5331,8 @@
 ///
 /// The operand must be an @unowned type.
 class StrongRetainUnownedInst :
-    public UnaryInstructionBase<ValueKind::StrongRetainUnownedInst,
-                                RefCountingInst, /*HAS_RESULT*/ false>
+    public UnaryInstructionBase<SILInstructionKind::StrongRetainUnownedInst,
+                                RefCountingInst>
 {
   friend SILBuilder;
 
@@ -5221,8 +5345,8 @@
 
 /// UnownedRetainInst - Increase the unowned reference count of an object.
 class UnownedRetainInst :
-    public UnaryInstructionBase<ValueKind::UnownedRetainInst,
-                                RefCountingInst, /*HAS_RESULT*/ false>
+    public UnaryInstructionBase<SILInstructionKind::UnownedRetainInst,
+                                RefCountingInst>
 {
   friend SILBuilder;
 
@@ -5235,8 +5359,8 @@
 
 /// UnownedReleaseInst - Decrease the unowned reference count of an object.
 class UnownedReleaseInst :
-     public UnaryInstructionBase<ValueKind::UnownedReleaseInst,
-                                 RefCountingInst, /*HAS_RESULT*/ false>
+     public UnaryInstructionBase<SILInstructionKind::UnownedReleaseInst,
+                                 RefCountingInst>
 {
   friend SILBuilder;
 
@@ -5250,8 +5374,8 @@
 /// FixLifetimeInst - An artificial use of a value for the purposes of ARC or
 /// RVO optimizations.
 class FixLifetimeInst :
-  public UnaryInstructionBase<ValueKind::FixLifetimeInst,
-                              SILInstruction, /*HAS_RESULT*/ false>
+  public UnaryInstructionBase<SILInstructionKind::FixLifetimeInst,
+                              NonValueInstruction>
 {
   friend SILBuilder;
 
@@ -5273,8 +5397,8 @@
 /// destroyers, without an actual release being emitted (avoiding the runtime
 /// assert).
 class EndLifetimeInst
-    : public UnaryInstructionBase<ValueKind::EndLifetimeInst, SILInstruction,
-                                  /*HAS_RESULT*/ false> {
+    : public UnaryInstructionBase<SILInstructionKind::EndLifetimeInst,
+                                  NonValueInstruction> {
   friend SILBuilder;
 
   EndLifetimeInst(SILDebugLocation DebugLoc, SILValue Operand)
@@ -5287,7 +5411,8 @@
 /// constraints, we need to be able to convert a guaranteed parameter to an owned
 /// parameter.
 class UncheckedOwnershipConversionInst
-    : public UnaryInstructionBase<ValueKind::UncheckedOwnershipConversionInst> {
+    : public UnaryInstructionBase<SILInstructionKind::UncheckedOwnershipConversionInst,
+                                  SingleValueInstruction> {
   friend SILBuilder;
 
   ValueOwnershipKind Kind;
@@ -5303,15 +5428,16 @@
 
 /// MarkDependenceInst - Marks that one value depends on another for
 /// validity in a non-obvious way.
-class MarkDependenceInst : public SILInstruction {
+class MarkDependenceInst
+    : public InstructionBase<SILInstructionKind::MarkDependenceInst,
+                             SingleValueInstruction> {
   friend SILBuilder;
 
   enum { Value, Base };
   FixedOperandList<2> Operands;
 
   MarkDependenceInst(SILDebugLocation DebugLoc, SILValue value, SILValue base)
-      : SILInstruction(ValueKind::MarkDependenceInst, DebugLoc,
-                       value->getType()),
+      : InstructionBase(DebugLoc, value->getType()),
         Operands{this, value, base} {}
 
 public:
@@ -5320,17 +5446,13 @@
 
   ArrayRef<Operand> getAllOperands() const { return Operands.asArray(); }
   MutableArrayRef<Operand> getAllOperands() { return Operands.asArray(); }
-
-  static bool classof(const ValueBase *V) {
-    return V->getKind() == ValueKind::MarkDependenceInst;
-  }
 };
 
 /// Promote an Objective-C block that is on the stack to the heap, or simply
 /// retain a block that is already on the heap.
-class CopyBlockInst :
-    public UnaryInstructionBase<ValueKind::CopyBlockInst,
-                                SILInstruction, /*HAS_RESULT*/ true>
+class CopyBlockInst
+    : public UnaryInstructionBase<SILInstructionKind::CopyBlockInst,
+                                  SingleValueInstruction>
 {
   friend SILBuilder;
 
@@ -5338,7 +5460,9 @@
       : UnaryInstructionBase(DebugLoc, operand, operand->getType()) {}
 };
 
-class CopyValueInst : public UnaryInstructionBase<ValueKind::CopyValueInst> {
+class CopyValueInst
+    : public UnaryInstructionBase<SILInstructionKind::CopyValueInst,
+                                  SingleValueInstruction> {
   friend class SILBuilder;
 
   CopyValueInst(SILDebugLocation DebugLoc, SILValue operand)
@@ -5346,7 +5470,8 @@
 };
 
 class CopyUnownedValueInst
-    : public UnaryInstructionBase<ValueKind::CopyUnownedValueInst> {
+    : public UnaryInstructionBase<SILInstructionKind::CopyUnownedValueInst,
+                                  SingleValueInstruction> {
   friend class SILBuilder;
 
   CopyUnownedValueInst(SILDebugLocation DebugLoc, SILValue operand,
@@ -5356,7 +5481,8 @@
 };
 
 class DestroyValueInst
-    : public UnaryInstructionBase<ValueKind::DestroyValueInst> {
+    : public UnaryInstructionBase<SILInstructionKind::DestroyValueInst,
+                                  NonValueInstruction> {
   friend class SILBuilder;
 
   DestroyValueInst(SILDebugLocation DebugLoc, SILValue operand)
@@ -5365,7 +5491,9 @@
 
 /// Given an object reference, return true iff it is non-nil and refers
 /// to a native swift object with strong reference count of 1.
-class IsUniqueInst : public UnaryInstructionBase<ValueKind::IsUniqueInst>
+class IsUniqueInst
+    : public UnaryInstructionBase<SILInstructionKind::IsUniqueInst,
+                                  SingleValueInstruction>
 {
   friend SILBuilder;
 
@@ -5376,8 +5504,9 @@
 /// Given an object reference, return true iff it is non-nil and either refers
 /// to a native swift object with strong reference count of 1 or refers to a
 /// pinned object (for simultaneous access to multiple subobjects).
-class IsUniqueOrPinnedInst :
-    public UnaryInstructionBase<ValueKind::IsUniqueOrPinnedInst> {
+class IsUniqueOrPinnedInst
+    : public UnaryInstructionBase<SILInstructionKind::IsUniqueOrPinnedInst,
+                                  SingleValueInstruction> {
   friend SILBuilder;
 
   IsUniqueOrPinnedInst(SILDebugLocation DebugLoc, SILValue Operand,
@@ -5390,22 +5519,19 @@
 //===----------------------------------------------------------------------===//
 
 /// DeallocationInst - An abstract parent class for Dealloc{Stack, Box, Ref}.
-class DeallocationInst : public SILInstruction {
+class DeallocationInst : public NonValueInstruction {
 protected:
-  DeallocationInst(ValueKind Kind, SILDebugLocation DebugLoc)
-      : SILInstruction(Kind, DebugLoc) {}
+  DeallocationInst(SILInstructionKind Kind, SILDebugLocation DebugLoc)
+      : NonValueInstruction(Kind, DebugLoc) {}
 
 public:
-  static bool classof(const ValueBase *V) {
-    return V->getKind() >= ValueKind::First_DeallocationInst &&
-      V->getKind() <= ValueKind::Last_DeallocationInst;
-  }
+  DEFINE_ABSTRACT_NON_VALUE_INST_BOILERPLATE(DeallocationInst)
 };
 
 /// DeallocStackInst - Deallocate stack memory allocated by alloc_stack.
 class DeallocStackInst :
-    public UnaryInstructionBase<ValueKind::DeallocStackInst, DeallocationInst,
-                                /*HAS_RESULT*/ false> {
+    public UnaryInstructionBase<SILInstructionKind::DeallocStackInst,
+                                DeallocationInst> {
   friend SILBuilder;
 
   DeallocStackInst(SILDebugLocation DebugLoc, SILValue operand)
@@ -5421,8 +5547,8 @@
 /// It is undefined behavior if the type of the operand does not match the
 /// most derived type of the allocated instance.
 class DeallocRefInst :
-  public UnaryInstructionBase<ValueKind::DeallocRefInst, DeallocationInst,
-                              /*HAS_RESULT*/ false>,
+  public UnaryInstructionBase<SILInstructionKind::DeallocRefInst,
+                              DeallocationInst>,
   public StackPromotable {
   friend SILBuilder;
 
@@ -5442,7 +5568,9 @@
 ///
 /// The metatype value can either be the static self type (in a designated
 /// initializer) or a dynamic self type (in a convenience initializer).
-class DeallocPartialRefInst : public DeallocationInst {
+class DeallocPartialRefInst
+    : public InstructionBase<SILInstructionKind::DeallocPartialRefInst,
+                             DeallocationInst> {
   friend SILBuilder;
 
 private:
@@ -5450,7 +5578,7 @@
 
   DeallocPartialRefInst(SILDebugLocation DebugLoc, SILValue Operand,
                         SILValue Metatype)
-      : DeallocationInst(ValueKind::DeallocPartialRefInst, DebugLoc),
+      : InstructionBase(DebugLoc),
         Operands(this, Operand, Metatype) {}
 
 public:
@@ -5459,16 +5587,12 @@
   
   SILValue getInstance() const { return getOperand(0); }
   SILValue getMetatype() const { return getOperand(1); }
-
-  static bool classof(const ValueBase *V) {
-    return V->getKind() == ValueKind::DeallocPartialRefInst;
-  }
 };
 
 /// Deallocate memory allocated for an unsafe value buffer.
-class DeallocValueBufferInst :
-  public UnaryInstructionBase<ValueKind::DeallocValueBufferInst,
-                              DeallocationInst, /*HAS_RESULT*/ true> {
+class DeallocValueBufferInst
+    : public UnaryInstructionBase<SILInstructionKind::DeallocValueBufferInst,
+                                  DeallocationInst> {
   friend SILBuilder;
 
   SILType ValueType;
@@ -5487,9 +5611,9 @@
 ///
 /// This does not destroy the boxed value instance; it must either be
 /// uninitialized or have been manually destroyed.
-class DeallocBoxInst :
-  public UnaryInstructionBase<ValueKind::DeallocBoxInst, DeallocationInst,
-                              /*HAS_RESULT*/ false>
+class DeallocBoxInst
+    : public UnaryInstructionBase<SILInstructionKind::DeallocBoxInst,
+                                  DeallocationInst>
 {
   friend SILBuilder;
 
@@ -5503,10 +5627,9 @@
 ///
 /// This does not destroy the boxed value instance; it must either be
 /// uninitialized or have been manually destroyed.
-class DeallocExistentialBoxInst :
-  public UnaryInstructionBase<ValueKind::DeallocExistentialBoxInst,
-                              DeallocationInst,
-                              /*HAS_RESULT*/ false>
+class DeallocExistentialBoxInst
+    : public UnaryInstructionBase<SILInstructionKind::DeallocExistentialBoxInst,
+                                  DeallocationInst>
 {
   friend SILBuilder;
 
@@ -5526,9 +5649,9 @@
 ///   release_value %1
 /// but a destroy instruction can be used for types that cannot be loaded,
 /// such as resilient value types.
-class DestroyAddrInst : public UnaryInstructionBase<ValueKind::DestroyAddrInst,
-                                                    SILInstruction,
-                                                    /*HAS_RESULT*/ false>
+class DestroyAddrInst
+    : public UnaryInstructionBase<SILInstructionKind::DestroyAddrInst,
+                                  NonValueInstruction>
 {
   friend SILBuilder;
 
@@ -5538,9 +5661,9 @@
 
 /// Project out the address of the value
 /// stored in the given Builtin.UnsafeValueBuffer.
-class ProjectValueBufferInst :
-  public UnaryInstructionBase<ValueKind::ProjectValueBufferInst,
-                              SILInstruction, /*HasResult*/ true> {
+class ProjectValueBufferInst
+    : public UnaryInstructionBase<SILInstructionKind::ProjectValueBufferInst,
+                                  SingleValueInstruction> {
   friend SILBuilder;
 
   ProjectValueBufferInst(SILDebugLocation DebugLoc, SILType valueType,
@@ -5552,9 +5675,9 @@
 };
 
 /// Project out the address of the value in a box.
-class ProjectBoxInst :
-  public UnaryInstructionBase<ValueKind::ProjectBoxInst,
-                              SILInstruction, /*HasResult*/ true> {
+class ProjectBoxInst
+    : public UnaryInstructionBase<SILInstructionKind::ProjectBoxInst,
+                                  SingleValueInstruction> {
   friend SILBuilder;
 
   unsigned Index;
@@ -5572,9 +5695,9 @@
 };
 
 /// Project out the address of the value in an existential box.
-class ProjectExistentialBoxInst :
-  public UnaryInstructionBase<ValueKind::ProjectExistentialBoxInst,
-                              SILInstruction, /*HasResult*/ true> {
+class ProjectExistentialBoxInst
+    : public UnaryInstructionBase<SILInstructionKind::ProjectExistentialBoxInst,
+                                  SingleValueInstruction> {
   friend SILBuilder;
   
   ProjectExistentialBoxInst(SILDebugLocation DebugLoc, SILType valueType,
@@ -5587,9 +5710,9 @@
 //===----------------------------------------------------------------------===//
 
 /// Trigger a runtime failure if the given Int1 value is true.
-class CondFailInst : public UnaryInstructionBase<ValueKind::CondFailInst,
-                                                 SILInstruction,
-                                                 /*HAS_RESULT*/ false>
+class CondFailInst
+    : public UnaryInstructionBase<SILInstructionKind::CondFailInst,
+                                  NonValueInstruction>
 {
   friend SILBuilder;
 
@@ -5602,18 +5725,13 @@
 //===----------------------------------------------------------------------===//
 
 /// Abstract base class for indexing instructions.
-class IndexingInst : public SILInstruction {
+class IndexingInst : public SingleValueInstruction {
   enum { Base, Index };
   FixedOperandList<2> Operands;
 public:
-  IndexingInst(ValueKind Kind, SILDebugLocation DebugLoc, SILValue Operand,
-               SILValue Index)
-      : SILInstruction(Kind, DebugLoc, Operand->getType()),
-        Operands{this, Operand, Index} {}
-
-  IndexingInst(ValueKind Kind, SILDebugLocation DebugLoc, SILValue Operand,
-               SILValue Index, SILType ResultTy)
-      : SILInstruction(Kind, DebugLoc, ResultTy),
+  IndexingInst(SILInstructionKind Kind, SILDebugLocation DebugLoc,
+               SILType ResultTy, SILValue Operand, SILValue Index)
+      : SingleValueInstruction(Kind, DebugLoc, ResultTy),
         Operands{this, Operand, Index} {}
 
   SILValue getBase() const { return Operands[Base].get(); }
@@ -5622,44 +5740,35 @@
   ArrayRef<Operand> getAllOperands() const { return Operands.asArray(); }
   MutableArrayRef<Operand> getAllOperands() { return Operands.asArray(); }
 
-  static bool classof(const ValueBase *V) {
-    return V->getKind() >= ValueKind::First_IndexingInst
-        && V->getKind() <= ValueKind::Last_IndexingInst;
-  }
+  DEFINE_ABSTRACT_SINGLE_VALUE_INST_BOILERPLATE(IndexingInst)
 };
 
 /// IndexAddrInst - "%2 : $*T = index_addr %0 : $*T, %1 : $Builtin.Word"
 /// This takes an address and indexes it, striding by the pointed-
 /// to type.  This is used to index into arrays of uniform elements.
-class IndexAddrInst : public IndexingInst {
+class IndexAddrInst
+    : public InstructionBase<SILInstructionKind::IndexAddrInst,
+                             IndexingInst> {
   friend SILBuilder;
 
   enum { Base, Index };
 
   IndexAddrInst(SILDebugLocation DebugLoc, SILValue Operand, SILValue Index)
-      : IndexingInst(ValueKind::IndexAddrInst, DebugLoc, Operand, Index) {}
-
-public:
-  static bool classof(const ValueBase *V) {
-    return V->getKind() == ValueKind::IndexAddrInst;
-  }
+      : InstructionBase(DebugLoc, Operand->getType(), Operand, Index) {}
 };
 
 /// TailAddrInst - like IndexingInst, but aligns-up the resulting address to a
 /// tail-allocated element type.
-class TailAddrInst : public IndexingInst {
+class TailAddrInst
+    : public InstructionBase<SILInstructionKind::TailAddrInst,
+                             IndexingInst> {
   friend SILBuilder;
 
   TailAddrInst(SILDebugLocation DebugLoc, SILValue Operand, SILValue Count,
                SILType ResultTy)
-      : IndexingInst(ValueKind::TailAddrInst, DebugLoc, Operand, Count,
-                     ResultTy) {}
+      : InstructionBase(DebugLoc, ResultTy, Operand, Count) {}
 
 public:
-  static bool classof(const ValueBase *V) {
-    return V->getKind() == ValueKind::TailAddrInst;
-  }
-
   SILType getTailType() const { return getType().getObjectType(); }
 };
 
@@ -5668,19 +5777,16 @@
 ///   = index_raw_pointer %0 : $Builtin.RawPointer, %1 : $Builtin.Word
 /// This takes an address and indexes it, striding by the pointed-
 /// to type.  This is used to index into arrays of uniform elements.
-class IndexRawPointerInst : public IndexingInst {
+class IndexRawPointerInst
+    : public InstructionBase<SILInstructionKind::IndexRawPointerInst,
+                             IndexingInst> {
   friend SILBuilder;
 
   enum { Base, Index };
 
   IndexRawPointerInst(SILDebugLocation DebugLoc, SILValue Operand,
                       SILValue Index)
-      : IndexingInst(ValueKind::IndexRawPointerInst, DebugLoc, Operand, Index) {
-  }
-
-public:
-  static bool classof(const ValueBase *V) {
-    return V->getKind() == ValueKind::IndexRawPointerInst;
+      : InstructionBase(DebugLoc, Operand->getType(), Operand, Index) {
   }
 };
 
@@ -5689,33 +5795,16 @@
 //===----------------------------------------------------------------------===//
 
 enum class TermKind {
-#define TERMINATOR(Id, Parent, TextualName, MemBehavior, MayRelease) Id,
+#define TERMINATOR(Id, TextualName, Parent, MemBehavior, MayRelease) \
+  Id = unsigned(SILInstructionKind::Id),
 #include "SILNodes.def"
 };
 
-struct ValueKindAsTermKind {
-  TermKind K;
-
-  ValueKindAsTermKind(ValueKind V) {
-    switch (V) {
-#define TERMINATOR(Id, Parent, TextualName, MemBehavior, MayRelease)           \
-  case ValueKind::Id:                                                          \
-    K = TermKind::Id;                                                          \
-    break;
-#include "SILNodes.def"
-    default:
-      llvm_unreachable("Not a terminator kind?!");
-    }
-  }
-
-  operator TermKind() const { return K; }
-};
-
 /// This class defines a "terminating instruction" for a SILBasicBlock.
-class TermInst : public SILInstruction {
+class TermInst : public NonValueInstruction {
 protected:
-  TermInst(ValueKind K, SILDebugLocation DebugLoc)
-      : SILInstruction(K, DebugLoc) {}
+  TermInst(SILInstructionKind K, SILDebugLocation DebugLoc)
+      : NonValueInstruction(K, DebugLoc) {}
 
 public:
 
@@ -5728,27 +5817,26 @@
     return const_cast<TermInst*>(this)->getSuccessors();
   }
 
-  static bool classof(const ValueBase *V) {
-    return V->getKind() >= ValueKind::First_TermInst &&
-           V->getKind() <= ValueKind::Last_TermInst;
-  }
+  DEFINE_ABSTRACT_NON_VALUE_INST_BOILERPLATE(TermInst)
 
   bool isBranch() const { return !getSuccessors().empty(); }
 
   /// Returns true if this terminator exits the function.
   bool isFunctionExiting() const;
 
-  TermKind getTermKind() const { return ValueKindAsTermKind(getKind()); }
+  TermKind getTermKind() const { return TermKind(getKind()); }
 };
 
 /// UnreachableInst - Position in the code which would be undefined to reach.
 /// These are always implicitly generated, e.g. when falling off the end of a
 /// function or after a no-return function call.
-class UnreachableInst : public TermInst {
+class UnreachableInst
+    : public InstructionBase<SILInstructionKind::UnreachableInst,
+                             TermInst> {
   friend SILBuilder;
 
   UnreachableInst(SILDebugLocation DebugLoc)
-      : TermInst(ValueKind::UnreachableInst, DebugLoc) {}
+      : InstructionBase(DebugLoc) {}
 
 public:
   SuccessorListTy getSuccessors() {
@@ -5758,16 +5846,11 @@
 
   ArrayRef<Operand> getAllOperands() const { return {}; }
   MutableArrayRef<Operand> getAllOperands() { return {}; }
-
-  static bool classof(const ValueBase *V) {
-    return V->getKind() == ValueKind::UnreachableInst;
-  }
 };
 
 /// ReturnInst - Representation of a ReturnStmt.
 class ReturnInst
-  : public UnaryInstructionBase<ValueKind::ReturnInst, TermInst,
-                                /*HAS_RESULT*/ false>
+  : public UnaryInstructionBase<SILInstructionKind::ReturnInst, TermInst>
 {
   friend SILBuilder;
 
@@ -5790,8 +5873,7 @@
 /// ThrowInst - Throw a typed error (which, in our system, is
 /// essentially just a funny kind of return).
 class ThrowInst
-  : public UnaryInstructionBase<ValueKind::ThrowInst, TermInst,
-                                /*HAS_RESULT*/ false>
+  : public UnaryInstructionBase<SILInstructionKind::ThrowInst, TermInst>
 {
   friend SILBuilder;
 
@@ -5811,7 +5893,9 @@
 };
 
 /// BranchInst - An unconditional branch.
-class BranchInst : public TermInst {
+class BranchInst
+    : public InstructionBase<SILInstructionKind::BranchInst,
+                             TermInst> {
   friend SILBuilder;
 
   SILSuccessor DestBB;
@@ -5847,14 +5931,12 @@
 
   ArrayRef<Operand> getAllOperands() const { return Operands.asArray(); }
   MutableArrayRef<Operand> getAllOperands() { return Operands.asArray(); }
-
-  static bool classof(const ValueBase *V) {
-    return V->getKind() == ValueKind::BranchInst;
-  }
 };
 
 /// A conditional branch.
-class CondBranchInst : public TermInst {
+class CondBranchInst
+    : public InstructionBase<SILInstructionKind::CondBranchInst,
+                             TermInst> {
   friend SILBuilder;
 
 public:
@@ -5878,22 +5960,24 @@
   TailAllocatedOperandList<1> Operands;
   CondBranchInst(SILDebugLocation DebugLoc, SILValue Condition,
                  SILBasicBlock *TrueBB, SILBasicBlock *FalseBB,
-                 ArrayRef<SILValue> Args, unsigned NumTrue, unsigned NumFalse);
+                 ArrayRef<SILValue> Args, unsigned NumTrue, unsigned NumFalse,
+                 ProfileCounter TrueBBCount, ProfileCounter FalseBBCount);
 
   /// Construct a CondBranchInst that will branch to TrueBB or FalseBB based on
   /// the Condition value. Both blocks must not take any arguments.
   static CondBranchInst *create(SILDebugLocation DebugLoc, SILValue Condition,
                                 SILBasicBlock *TrueBB, SILBasicBlock *FalseBB,
-                                SILFunction &F);
+                                ProfileCounter TrueBBCount,
+                                ProfileCounter FalseBBCount, SILFunction &F);
 
   /// Construct a CondBranchInst that will either branch to TrueBB and pass
   /// TrueArgs or branch to FalseBB and pass FalseArgs based on the Condition
   /// value.
-  static CondBranchInst *create(SILDebugLocation DebugLoc, SILValue Condition,
-                                SILBasicBlock *TrueBB,
-                                ArrayRef<SILValue> TrueArgs,
-                                SILBasicBlock *FalseBB,
-                                ArrayRef<SILValue> FalseArgs, SILFunction &F);
+  static CondBranchInst *
+  create(SILDebugLocation DebugLoc, SILValue Condition, SILBasicBlock *TrueBB,
+         ArrayRef<SILValue> TrueArgs, SILBasicBlock *FalseBB,
+         ArrayRef<SILValue> FalseArgs, ProfileCounter TrueBBCount,
+         ProfileCounter FalseBBCount, SILFunction &F);
 
 public:
   SILValue getCondition() const { return Operands[ConditionIdx].get(); }
@@ -5910,6 +5994,11 @@
   SILBasicBlock *getFalseBB() { return DestBBs[1]; }
   const SILBasicBlock *getFalseBB() const { return DestBBs[1]; }
 
+  /// The number of times the True branch was executed.
+  ProfileCounter getTrueBBCount() const { return DestBBs[0].getCount(); }
+  /// The number of times the False branch was executed.
+  ProfileCounter getFalseBBCount() const { return DestBBs[1].getCount(); }
+
   /// Get the arguments to the true BB.
   OperandValueArrayRef getTrueArgs() const;
   /// Get the arguments to the false BB.
@@ -5967,14 +6056,12 @@
 
   ArrayRef<Operand> getAllOperands() const { return Operands.asArray(); }
   MutableArrayRef<Operand> getAllOperands() { return Operands.asArray(); }
-
-  static bool classof(const ValueBase *V) {
-    return V->getKind() == ValueKind::CondBranchInst;
-  }
 };
 
 /// A switch on a value of a builtin type.
-class SwitchValueInst : public TermInst {
+class SwitchValueInst
+    : public InstructionBase<SILInstructionKind::SwitchValueInst,
+                             TermInst> {
   friend SILBuilder;
 
   unsigned NumCases : 31;
@@ -6035,10 +6122,6 @@
     assert(HasDefault && "doesn't have a default");
     return getSuccessorBuf()[NumCases];
   }
-
-  static bool classof(const ValueBase *V) {
-    return V->getKind() == ValueKind::SwitchValueInst;
-  }
 };
 
 /// Common implementation for the switch_enum and
@@ -6075,15 +6158,17 @@
 
 protected:
   SwitchEnumInstBase(
-      ValueKind Kind, SILDebugLocation DebugLoc, SILValue Operand,
+      SILInstructionKind Kind, SILDebugLocation DebugLoc, SILValue Operand,
       SILBasicBlock *DefaultBB,
-      ArrayRef<std::pair<EnumElementDecl *, SILBasicBlock *>> CaseBBs);
+      ArrayRef<std::pair<EnumElementDecl *, SILBasicBlock *>> CaseBBs,
+      Optional<ArrayRef<ProfileCounter>> Counts, ProfileCounter DefaultCount);
 
   template <typename SWITCH_ENUM_INST>
   static SWITCH_ENUM_INST *createSwitchEnum(
       SILDebugLocation DebugLoc, SILValue Operand, SILBasicBlock *DefaultBB,
       ArrayRef<std::pair<EnumElementDecl *, SILBasicBlock *>> CaseBBs,
-      SILFunction &F);
+      SILFunction &F, Optional<ArrayRef<ProfileCounter>> Counts,
+      ProfileCounter DefaultCount);
 
 public:
   /// Clean up tail-allocated successor records for the switch cases.
@@ -6105,6 +6190,10 @@
     assert(i < NumCases && "case out of bounds");
     return {getCaseBuf()[i], getSuccessorBuf()[i].getBB()};
   }
+  ProfileCounter getCaseCount(unsigned i) const {
+    assert(i < NumCases && "case out of bounds");
+    return getSuccessorBuf()[i].getCount();
+  }
 
   // Swap the cases at indices \p i and \p j.
   void swapCase(unsigned i, unsigned j);
@@ -6133,16 +6222,22 @@
     assert(HasDefault && "doesn't have a default");
     return getSuccessorBuf()[NumCases];
   }
+  ProfileCounter getDefaultCount() const {
+    assert(HasDefault && "doesn't have a default");
+    return getSuccessorBuf()[NumCases].getCount();
+  }
 
-  static bool classof(const ValueBase *V) {
-    return V->getKind() >= ValueKind::SwitchEnumInst &&
-           V->getKind() <= ValueKind::SwitchEnumAddrInst;
+  static bool classof(const SILInstruction *I) {
+    return I->getKind() >= SILInstructionKind::SwitchEnumInst &&
+           I->getKind() <= SILInstructionKind::SwitchEnumAddrInst;
   }
 };
 
 /// A switch on a loadable enum's discriminator. The data for each case is
 /// passed into the corresponding destination block as an argument.
-class SwitchEnumInst : public SwitchEnumInstBase {
+class SwitchEnumInst
+    : public InstructionBase<SILInstructionKind::SwitchEnumInst,
+                             SwitchEnumInstBase> {
   friend SILBuilder;
 
 private:
@@ -6150,23 +6245,22 @@
 
   SwitchEnumInst(
       SILDebugLocation DebugLoc, SILValue Operand, SILBasicBlock *DefaultBB,
-      ArrayRef<std::pair<EnumElementDecl *, SILBasicBlock *>> CaseBBs)
-      : SwitchEnumInstBase(ValueKind::SwitchEnumInst, DebugLoc, Operand,
-                           DefaultBB, CaseBBs) {}
-
+      ArrayRef<std::pair<EnumElementDecl *, SILBasicBlock *>> CaseBBs,
+      Optional<ArrayRef<ProfileCounter>> CaseCounts,
+      ProfileCounter DefaultCount)
+      : InstructionBase(DebugLoc, Operand, DefaultBB, CaseBBs, CaseCounts,
+                        DefaultCount) {}
   static SwitchEnumInst *
   create(SILDebugLocation DebugLoc, SILValue Operand, SILBasicBlock *DefaultBB,
          ArrayRef<std::pair<EnumElementDecl *, SILBasicBlock *>> CaseBBs,
-         SILFunction &F);
-
-public:
-  static bool classof(const ValueBase *V) {
-    return V->getKind() == ValueKind::SwitchEnumInst;
-  }
+         SILFunction &F, Optional<ArrayRef<ProfileCounter>> CaseCounts,
+         ProfileCounter DefaultCount);
 };
 
 /// A switch on an enum's discriminator in memory.
-class SwitchEnumAddrInst : public SwitchEnumInstBase {
+class SwitchEnumAddrInst
+    : public InstructionBase<SILInstructionKind::SwitchEnumAddrInst,
+                             SwitchEnumInstBase> {
   friend SILBuilder;
 
 private:
@@ -6174,19 +6268,16 @@
 
   SwitchEnumAddrInst(
       SILDebugLocation DebugLoc, SILValue Operand, SILBasicBlock *DefaultBB,
-      ArrayRef<std::pair<EnumElementDecl *, SILBasicBlock *>> CaseBBs)
-      : SwitchEnumInstBase(ValueKind::SwitchEnumAddrInst, DebugLoc, Operand,
-                           DefaultBB, CaseBBs) {}
-
+      ArrayRef<std::pair<EnumElementDecl *, SILBasicBlock *>> CaseBBs,
+      Optional<ArrayRef<ProfileCounter>> CaseCounts,
+      ProfileCounter DefaultCount)
+      : InstructionBase(DebugLoc, Operand, DefaultBB, CaseBBs, CaseCounts,
+                        DefaultCount) {}
   static SwitchEnumAddrInst *
   create(SILDebugLocation DebugLoc, SILValue Operand, SILBasicBlock *DefaultBB,
          ArrayRef<std::pair<EnumElementDecl *, SILBasicBlock *>> CaseBBs,
-         SILFunction &F);
-
-public:
-  static bool classof(const ValueBase *V) {
-    return V->getKind() == ValueKind::SwitchEnumAddrInst;
-  }
+         SILFunction &F, Optional<ArrayRef<ProfileCounter>> CaseCounts,
+         ProfileCounter DefaultCount);
 };
 
 /// Branch on the existence of an Objective-C method in the dynamic type of
@@ -6194,7 +6285,9 @@
 ///
 /// If the method exists, branches to the first BB, providing it with the
 /// method reference; otherwise, branches to the second BB.
-class DynamicMethodBranchInst : public TermInst {
+class DynamicMethodBranchInst
+    : public InstructionBase<SILInstructionKind::DynamicMethodBranchInst,
+                             TermInst> {
   friend SILBuilder;
 
   SILDeclRef Member;
@@ -6231,10 +6324,6 @@
 
   ArrayRef<Operand> getAllOperands() const { return Operands.asArray(); }
   MutableArrayRef<Operand> getAllOperands() { return Operands.asArray(); }
-
-  static bool classof(const ValueBase *V) {
-    return V->getKind() == ValueKind::DynamicMethodBranchInst;
-  }
 };
 
 /// Perform a checked cast operation and branch on whether the cast succeeds.
@@ -6242,10 +6331,9 @@
 /// argument.
 class CheckedCastBranchInst final:
   public UnaryInstructionWithTypeDependentOperandsBase<
-                              ValueKind::CheckedCastBranchInst,
+                              SILInstructionKind::CheckedCastBranchInst,
                               CheckedCastBranchInst,
-                              TermInst,
-                              false> {
+                              TermInst> {
   friend SILBuilder;
 
   SILType DestTy;
@@ -6256,17 +6344,20 @@
   CheckedCastBranchInst(SILDebugLocation DebugLoc, bool IsExact,
                         SILValue Operand,
                         ArrayRef<SILValue> TypeDependentOperands,
-                        SILType DestTy,
-                        SILBasicBlock *SuccessBB, SILBasicBlock *FailureBB)
+                        SILType DestTy, SILBasicBlock *SuccessBB,
+                        SILBasicBlock *FailureBB, ProfileCounter Target1Count,
+                        ProfileCounter Target2Count)
       : UnaryInstructionWithTypeDependentOperandsBase(DebugLoc, Operand,
-                                               TypeDependentOperands),
-        DestTy(DestTy), IsExact(IsExact),
-        DestBBs{{this, SuccessBB}, {this, FailureBB}} {}
+                                                      TypeDependentOperands),
+        DestTy(DestTy),
+        IsExact(IsExact), DestBBs{{this, SuccessBB, Target1Count},
+                                  {this, FailureBB, Target2Count}} {}
 
   static CheckedCastBranchInst *
   create(SILDebugLocation DebugLoc, bool IsExact, SILValue Operand,
          SILType DestTy, SILBasicBlock *SuccessBB, SILBasicBlock *FailureBB,
-         SILFunction &F, SILOpenedArchetypesState &OpenedArchetypes);
+         SILFunction &F, SILOpenedArchetypesState &OpenedArchetypes,
+         ProfileCounter Target1Count, ProfileCounter Target2Count);
 
 public:
   bool isExact() const { return IsExact; }
@@ -6294,9 +6385,10 @@
   SILBasicBlock *getFailureBB() { return DestBBs[1]; }
   const SILBasicBlock *getFailureBB() const { return DestBBs[1]; }
 
-  static bool classof(const ValueBase *V) {
-    return V->getKind() == ValueKind::CheckedCastBranchInst;
-  }
+  /// The number of times the True branch was executed
+  ProfileCounter getTrueBBCount() const { return DestBBs[0].getCount(); }
+  /// The number of times the False branch was executed
+  ProfileCounter getFalseBBCount() const { return DestBBs[1].getCount(); }
 };
 
 /// Perform a checked cast operation and branch on whether the cast succeeds.
@@ -6304,8 +6396,9 @@
 /// argument.
 class CheckedCastValueBranchInst final
     : public UnaryInstructionWithTypeDependentOperandsBase<
-          ValueKind::CheckedCastValueBranchInst, CheckedCastValueBranchInst,
-          TermInst, false> {
+          SILInstructionKind::CheckedCastValueBranchInst,
+          CheckedCastValueBranchInst,
+          TermInst> {
   friend SILBuilder;
 
   SILType DestTy;
@@ -6346,15 +6439,13 @@
   const SILBasicBlock *getSuccessBB() const { return DestBBs[0]; }
   SILBasicBlock *getFailureBB() { return DestBBs[1]; }
   const SILBasicBlock *getFailureBB() const { return DestBBs[1]; }
-
-  static bool classof(const ValueBase *V) {
-    return V->getKind() == ValueKind::CheckedCastValueBranchInst;
-  }
 };
 
 /// Perform a checked cast operation and branch on whether the cast succeeds.
 /// The result of the checked cast is left in the destination address.
-class CheckedCastAddrBranchInst : public TermInst {
+class CheckedCastAddrBranchInst
+    : public InstructionBase<SILInstructionKind::CheckedCastAddrBranchInst,
+                             TermInst> {
   friend SILBuilder;
 
   CastConsumptionKind ConsumptionKind;
@@ -6374,11 +6465,13 @@
   CheckedCastAddrBranchInst(SILDebugLocation DebugLoc,
                             CastConsumptionKind consumptionKind, SILValue src,
                             CanType srcType, SILValue dest, CanType targetType,
-                            SILBasicBlock *successBB, SILBasicBlock *failureBB)
-      : TermInst(ValueKind::CheckedCastAddrBranchInst, DebugLoc),
-        ConsumptionKind(consumptionKind), Operands{this, src, dest},
-        DestBBs{{this, successBB}, {this, failureBB}}, SourceType(srcType),
-        TargetType(targetType) {}
+                            SILBasicBlock *successBB, SILBasicBlock *failureBB,
+                            ProfileCounter Target1Count,
+                            ProfileCounter Target2Count)
+      : InstructionBase(DebugLoc), ConsumptionKind(consumptionKind),
+        Operands{this, src, dest}, DestBBs{{this, successBB, Target1Count},
+                                           {this, failureBB, Target2Count}},
+        SourceType(srcType), TargetType(targetType) {}
 
 public:
   CastConsumptionKind getConsumptionKind() const { return ConsumptionKind; }
@@ -6404,9 +6497,10 @@
   SILBasicBlock *getFailureBB() { return DestBBs[1]; }
   const SILBasicBlock *getFailureBB() const { return DestBBs[1]; }
 
-  static bool classof(const ValueBase *V) {
-    return V->getKind() == ValueKind::CheckedCastAddrBranchInst;
-  }
+  /// The number of times the True branch was executed.
+  ProfileCounter getTrueBBCount() const { return DestBBs[0].getCount(); }
+  /// The number of times the False branch was executed.
+  ProfileCounter getFalseBBCount() const { return DestBBs[1].getCount(); }
 };
 
 /// A private abstract class to store the destinations of a TryApplyInst.
@@ -6421,7 +6515,7 @@
   SILSuccessor DestBBs[2];
 
 protected:
-  TryApplyInstBase(ValueKind valueKind, SILDebugLocation Loc,
+  TryApplyInstBase(SILInstructionKind valueKind, SILDebugLocation Loc,
                    SILBasicBlock *normalBB, SILBasicBlock *errorBB);
 
 public:
@@ -6447,7 +6541,8 @@
 /// TryApplyInst - Represents the full application of a function that
 /// can produce an error.
 class TryApplyInst
-    : public ApplyInstBase<TryApplyInst, TryApplyInstBase> {
+    : public InstructionBase<SILInstructionKind::TryApplyInst,
+                             ApplyInstBase<TryApplyInst, TryApplyInstBase>> {
   friend SILBuilder;
 
   TryApplyInst(SILDebugLocation DebugLoc, SILValue callee,
@@ -6463,11 +6558,6 @@
          SILBasicBlock *normalBB, SILBasicBlock *errorBB, SILFunction &F,
          SILOpenedArchetypesState &OpenedArchetypes,
          const GenericSpecializationInformation *SpecializationInfo);
-
-public:
-  static bool classof(const ValueBase *V) {
-    return V->getKind() == ValueKind::TryApplyInst;
-  }
 };
 
 /// An apply instruction.
@@ -6479,7 +6569,7 @@
 
 public:
   ApplySite() : Inst(nullptr) {}
-  explicit ApplySite(ValueBase *inst)
+  explicit ApplySite(SILInstruction *inst)
     : Inst(static_cast<SILInstruction*>(inst)) {
     assert(classof(inst) && "not an apply instruction?");
   }
@@ -6491,8 +6581,17 @@
     return Inst->getModule();
   }
 
-  static ApplySite isa(ValueBase *inst) {
-    return (classof(inst) ? ApplySite(inst) : ApplySite());
+  static ApplySite isa(SILNode *node) {
+    switch (node->getKind()) {
+    case SILNodeKind::ApplyInst:
+      return ApplySite(cast<ApplyInst>(node));
+    case SILNodeKind::TryApplyInst:
+      return ApplySite(cast<TryApplyInst>(node));
+    case SILNodeKind::PartialApplyInst:
+      return ApplySite(cast<PartialApplyInst>(node));
+    default:
+      return ApplySite();
+    }
   }
 
   explicit operator bool() const {
@@ -6507,11 +6606,11 @@
 
 #define FOREACH_IMPL_RETURN(OPERATION) do {                             \
     switch (Inst->getKind()) {                                          \
-    case ValueKind::ApplyInst:                                          \
+    case SILInstructionKind::ApplyInst:                                          \
       return cast<ApplyInst>(Inst)->OPERATION;                          \
-    case ValueKind::PartialApplyInst:                                   \
+    case SILInstructionKind::PartialApplyInst:                                   \
       return cast<PartialApplyInst>(Inst)->OPERATION;                   \
-    case ValueKind::TryApplyInst:                                       \
+    case SILInstructionKind::TryApplyInst:                                       \
       return cast<TryApplyInst>(Inst)->OPERATION;                       \
     default:                                                            \
       llvm_unreachable("not an apply instruction!");                    \
@@ -6627,9 +6726,9 @@
   /// The arguments passed to this instruction, without self.
   OperandValueArrayRef getArgumentsWithoutSelf() const {
     switch (Inst->getKind()) {
-    case ValueKind::ApplyInst:
+    case SILInstructionKind::ApplyInst:
       return cast<ApplyInst>(Inst)->getArgumentsWithoutSelf();
-    case ValueKind::TryApplyInst:
+    case SILInstructionKind::TryApplyInst:
       return cast<TryApplyInst>(Inst)->getArgumentsWithoutSelf();
     default:
       llvm_unreachable("not implemented for this instruction!");
@@ -6643,10 +6742,10 @@
   // argument. Returns 0 for full applies. May return > 0 for partial applies.
   unsigned getCalleeArgIndexOfFirstAppliedArg() const {
     switch (Inst->getKind()) {
-    case ValueKind::ApplyInst:
-    case ValueKind::TryApplyInst:
+    case SILInstructionKind::ApplyInst:
+    case SILInstructionKind::TryApplyInst:
       return 0;
-    case ValueKind::PartialApplyInst:
+    case SILInstructionKind::PartialApplyInst:
       // The arguments to partial_apply are a suffix of the arguments to the
       // the actually-called function.
       return getSubstCalleeConv().getNumSILArguments() - getNumArguments();
@@ -6680,9 +6779,9 @@
   /// Return the self argument passed to this instruction.
   bool hasSelfArgument() const {
     switch (Inst->getKind()) {
-    case ValueKind::ApplyInst:
+    case SILInstructionKind::ApplyInst:
       return cast<ApplyInst>(Inst)->hasSelfArgument();
-    case ValueKind::TryApplyInst:
+    case SILInstructionKind::TryApplyInst:
       return cast<TryApplyInst>(Inst)->hasSelfArgument();
     default:
       llvm_unreachable("not implemented for this instruction!");
@@ -6692,9 +6791,9 @@
   /// Return the self argument passed to this instruction.
   SILValue getSelfArgument() const {
     switch (Inst->getKind()) {
-    case ValueKind::ApplyInst:
+    case SILInstructionKind::ApplyInst:
       return cast<ApplyInst>(Inst)->getSelfArgument();
-    case ValueKind::TryApplyInst:
+    case SILInstructionKind::TryApplyInst:
       return cast<TryApplyInst>(Inst)->getSelfArgument();
     default:
       llvm_unreachable("not implemented for this instruction!");
@@ -6704,9 +6803,9 @@
   /// Return the self operand passed to this instruction.
   Operand &getSelfArgumentOperand() {
     switch (Inst->getKind()) {
-    case ValueKind::ApplyInst:
+    case SILInstructionKind::ApplyInst:
       return cast<ApplyInst>(Inst)->getSelfArgumentOperand();
-    case ValueKind::TryApplyInst:
+    case SILInstructionKind::TryApplyInst:
       return cast<TryApplyInst>(Inst)->getSelfArgumentOperand();
     default:
       llvm_unreachable("not implemented for this instruction!");
@@ -6728,10 +6827,10 @@
     return lhs.getInstruction() != rhs.getInstruction();
   }
 
-  static bool classof(const ValueBase *inst) {
-    return (inst->getKind() == ValueKind::ApplyInst ||
-            inst->getKind() == ValueKind::PartialApplyInst ||
-            inst->getKind() == ValueKind::TryApplyInst);
+  static bool classof(const SILInstruction *inst) {
+    return (inst->getKind() == SILInstructionKind::ApplyInst ||
+            inst->getKind() == SILInstructionKind::PartialApplyInst ||
+            inst->getKind() == SILInstructionKind::TryApplyInst);
   }
 };
 
@@ -6741,14 +6840,21 @@
 
 public:
   FullApplySite() : ApplySite() {}
-  explicit FullApplySite(ValueBase *inst) : ApplySite(inst) {
+  explicit FullApplySite(SILInstruction *inst) : ApplySite(inst) {
     assert(classof(inst) && "not an apply instruction?");
   }
   FullApplySite(ApplyInst *inst) : ApplySite(inst) {}
   FullApplySite(TryApplyInst *inst) : ApplySite(inst) {}
 
-  static FullApplySite isa(ValueBase *inst) {
-    return (classof(inst) ? FullApplySite(inst) : FullApplySite());
+  static FullApplySite isa(SILNode *node) {
+    switch (node->getKind()) {
+    case SILNodeKind::ApplyInst:
+      return FullApplySite(cast<ApplyInst>(node));
+    case SILNodeKind::TryApplyInst:
+      return FullApplySite(cast<TryApplyInst>(node));
+    default:
+      return FullApplySite();
+    }
   }
 
   bool hasIndirectSILResults() const {
@@ -6771,9 +6877,9 @@
     return FullApplySite(p);
   }
 
-  static bool classof(const ValueBase *inst) {
-    return (inst->getKind() == ValueKind::ApplyInst ||
-            inst->getKind() == ValueKind::TryApplyInst);
+  static bool classof(const SILInstruction *inst) {
+    return (inst->getKind() == SILInstructionKind::ApplyInst ||
+            inst->getKind() == SILInstructionKind::TryApplyInst);
   }
 };
 
diff --git a/include/swift/SIL/SILModule.h b/include/swift/SIL/SILModule.h
index f9dc6ed..dc6c399 100644
--- a/include/swift/SIL/SILModule.h
+++ b/include/swift/SIL/SILModule.h
@@ -20,21 +20,22 @@
 #include "swift/AST/ASTContext.h"
 #include "swift/AST/Builtins.h"
 #include "swift/AST/Module.h"
-#include "swift/AST/SILOptions.h"
 #include "swift/AST/SILLayout.h"
+#include "swift/AST/SILOptions.h"
 #include "swift/Basic/LangOptions.h"
+#include "swift/Basic/ProfileCounter.h"
 #include "swift/Basic/Range.h"
+#include "swift/SIL/Notifications.h"
 #include "swift/SIL/SILCoverageMap.h"
 #include "swift/SIL/SILDeclRef.h"
 #include "swift/SIL/SILDefaultWitnessTable.h"
 #include "swift/SIL/SILFunction.h"
 #include "swift/SIL/SILGlobalVariable.h"
-#include "swift/SIL/Notifications.h"
+#include "swift/SIL/SILPrintContext.h"
 #include "swift/SIL/SILType.h"
 #include "swift/SIL/SILVTable.h"
 #include "swift/SIL/SILWitnessTable.h"
 #include "swift/SIL/TypeLowering.h"
-#include "swift/SIL/SILPrintContext.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/FoldingSet.h"
 #include "llvm/ADT/Optional.h"
@@ -248,7 +249,7 @@
 
   /// Send the invalidation message that \p V is being deleted to all
   /// registered handlers. The order of handlers is deterministic but arbitrary.
-  void notifyDeleteHandlers(ValueBase *V);
+  void notifyDeleteHandlers(SILNode *node);
 
   /// \brief This converts Swift types to SILTypes.
   mutable Lowering::TypeConverter Types;
@@ -483,12 +484,12 @@
 
   /// \brief Return the declaration of a utility function that can,
   /// but needn't, be shared between modules.
-  SILFunction *getOrCreateSharedFunction(SILLocation loc,
-                                         StringRef name,
+  SILFunction *getOrCreateSharedFunction(SILLocation loc, StringRef name,
                                          CanSILFunctionType type,
                                          IsBare_t isBareSILFunction,
                                          IsTransparent_t isTransparent,
                                          IsSerialized_t isSerialized,
+                                         ProfileCounter entryCount,
                                          IsThunk_t isThunk);
 
   /// \brief Return the declaration of a function, or create it if it doesn't
@@ -497,30 +498,34 @@
       SILLocation loc, StringRef name, SILLinkage linkage,
       CanSILFunctionType type, IsBare_t isBareSILFunction,
       IsTransparent_t isTransparent, IsSerialized_t isSerialized,
+      ProfileCounter entryCount = ProfileCounter(),
       IsThunk_t isThunk = IsNotThunk,
       SubclassScope subclassScope = SubclassScope::NotApplicable);
 
   /// \brief Return the declaration of a function, or create it if it doesn't
   /// exist.
-  SILFunction *getOrCreateFunction(SILLocation loc,
-                                   SILDeclRef constant,
-                                   ForDefinition_t forDefinition);
+  SILFunction *
+  getOrCreateFunction(SILLocation loc, SILDeclRef constant,
+                      ForDefinition_t forDefinition,
+                      ProfileCounter entryCount = ProfileCounter());
 
   /// \brief Create a function declaration.
   ///
   /// This signature is a direct copy of the signature of SILFunction::create()
   /// in order to simplify refactoring all SILFunction creation use-sites to use
   /// SILModule. Eventually the uses should probably be refactored.
-  SILFunction *createFunction(
-      SILLinkage linkage, StringRef name, CanSILFunctionType loweredType,
-      GenericEnvironment *genericEnv, Optional<SILLocation> loc,
-      IsBare_t isBareSILFunction, IsTransparent_t isTrans,
-      IsSerialized_t isSerialized, IsThunk_t isThunk = IsNotThunk,
-      SubclassScope subclassScope = SubclassScope::NotApplicable,
-      Inline_t inlineStrategy = InlineDefault,
-      EffectsKind EK = EffectsKind::Unspecified,
-      SILFunction *InsertBefore = nullptr,
-      const SILDebugScope *DebugScope = nullptr);
+  SILFunction *
+  createFunction(SILLinkage linkage, StringRef name,
+                 CanSILFunctionType loweredType, GenericEnvironment *genericEnv,
+                 Optional<SILLocation> loc, IsBare_t isBareSILFunction,
+                 IsTransparent_t isTrans, IsSerialized_t isSerialized,
+                 ProfileCounter entryCount = ProfileCounter(),
+                 IsThunk_t isThunk = IsNotThunk,
+                 SubclassScope subclassScope = SubclassScope::NotApplicable,
+                 Inline_t inlineStrategy = InlineDefault,
+                 EffectsKind EK = EffectsKind::Unspecified,
+                 SILFunction *InsertBefore = nullptr,
+                 const SILDebugScope *DebugScope = nullptr);
 
   /// Look up the SILWitnessTable representing the lowering of a protocol
   /// conformance, and collect the substitutions to apply to the referenced
diff --git a/include/swift/SIL/SILNode.h b/include/swift/SIL/SILNode.h
new file mode 100644
index 0000000..4da965e
--- /dev/null
+++ b/include/swift/SIL/SILNode.h
@@ -0,0 +1,301 @@
+//===--- SILNode.h - Node base class for SIL --------------------*- 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 SILNode class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SWIFT_SIL_SILNODE_H
+#define SWIFT_SIL_SILNODE_H
+
+#include "llvm/Support/Compiler.h"
+#include "llvm/ADT/DenseMapInfo.h"
+#include "swift/Basic/LLVM.h"
+#include <type_traits>
+
+namespace swift {
+
+class SILBasicBlock;
+class SILFunction;
+class SILInstruction;
+class SILModule;
+class SingleValueInstruction;
+class ValueBase;
+
+/// An enumeration which contains values for all the nodes in SILNodes.def.
+/// Other enumerators, like ValueKind and SILInstructionind, ultimately
+/// take their values from this enumerator.
+enum class SILNodeKind {
+#define NODE(ID, PARENT) \
+  ID,
+#define NODE_RANGE(ID, FIRST, LAST) \
+  First_##ID = FIRST, \
+  Last_##ID = LAST,
+#include "swift/SIL/SILNodes.def"
+};
+
+enum {
+  NumSILNodeKindBits = 8
+};
+static_assert(unsigned(SILNodeKind::Last_SILNode) < (1 << NumSILNodeKindBits),
+              "SILNodeKind fits in NumSILNodeKindBits bits");
+
+/// A SILNode is a node in the use-def graph of a SILFunction.  It is
+/// either an instruction or a defined value which can be used by an
+/// instruction.  A defined value may be an instruction result, a basic
+/// block argument, or the special 'undef' value.
+///
+/// The 'node' intuition is slightly imprecise because a single instruction
+/// may be composed of multiple SILNodes: one for the instruction itself
+/// and one for each value it produces.  When an instruction kind always
+/// produces exactly one value, the cast machinery (isa, cast, and dyn_cast)
+/// works to make both nodes appear to be the same object: there is a value
+/// kind exactly equal to the instruction kind and the value node can be
+/// directly cast to the instruction's class.  When an instruction kind
+/// never produces values, it has no corresponding value kind, and it is
+/// a compile-time error to attempt to cast a value node to the instruction
+/// class.  When an instruction kind can have multiple values (not yet
+/// implemented), its value nodes have a different kind from the
+/// instruction kind and it is a static error to attempt to cast a value
+/// node to the instruction kind.
+///
+/// Another way of interpreting SILNode is that there is a SILNode for
+/// everything that can be numbered in SIL assembly (plus 'undef', which
+/// is not conventionally numbered).  Instructions without results are
+/// still numbered in SIL in order to describe the users lists of an
+/// instruction or argument.  Instructions with multiple results are
+/// numbered using their first result.
+///
+/// SILNode is a base class of both SILInstruction and ValueBase.
+/// Because there can be multiple SILNodes within a single instruction
+/// object, some care must be taken when working with SILNode pointers.
+/// These precautions only apply to SILNode* and not its subclasses.
+///
+/// - There may have multiple SILNode* values that refer to the same
+///   instruction.  Data structures and algorithms that rely on
+///   uniqueness of a SILNode* should generally make sure that they're
+///   working with the canonical SILNode*; see getCanonicalSILNodeInObject().
+///
+/// - Do not use builtin C++ casts to downcast a SILNode*.  A static_cast
+///   from SILNode* to SILInstruction* only works if the referenced
+///   SILNode is the base subobject of the object's SILInstruction
+///   subobject.  If the SILNode is actually the base subobject of a
+///   ValueBase subobject, the cast will yield a corrupted value.
+///   Always use the LLVM casts (cast<>, dyn_cast<>, etc.) instead.
+class alignas(8) SILNode {
+protected:
+  enum class SILNodeStorageLocation {
+    Value,
+    Instruction
+  };
+
+private:
+  const unsigned Kind : NumSILNodeKindBits;
+  const unsigned StorageLoc : 1;
+  const unsigned IsCanonical : 1;
+
+  // TODO: Pack other things in here.
+
+  SILNodeStorageLocation getStorageLoc() const {
+    return SILNodeStorageLocation(StorageLoc);
+  }
+
+  const SILNode *getCanonicalSILNodeSlowPath() const;
+
+protected:
+  SILNode(SILNodeKind kind, SILNodeStorageLocation storageLoc)
+    : Kind(unsigned(kind)),
+      StorageLoc(unsigned(storageLoc)),
+      IsCanonical(storageLoc == SILNodeStorageLocation::Instruction ||
+                  !hasMultipleSILNodes(kind)) {}
+
+public:
+
+  /// Does the given kind of node have multiple SILNode bases?
+  static bool hasMultipleSILNodes(SILNodeKind kind) {
+    // Currently only SingleValueInstructions.  Note that multi-result
+    // instructions shouldn't return true for this.
+    return kind >= SILNodeKind::First_SingleValueInstruction &&
+           kind <= SILNodeKind::Last_SingleValueInstruction;
+  }
+
+  /// Is this SILNode the canonical SILNode subobject in this object?
+  bool isCanonicalSILNodeInObject() const {
+    return IsCanonical;
+  }
+
+  /// Return a pointer to the canonical SILNode subobject in this object.
+  SILNode *getCanonicalSILNodeInObject() {
+    if (IsCanonical) return this;
+    return const_cast<SILNode*>(getCanonicalSILNodeSlowPath());
+  }
+  const SILNode *getCanonicalSILNodeInObject() const {
+    if (IsCanonical) return this;
+    return getCanonicalSILNodeSlowPath();
+  }
+
+  LLVM_ATTRIBUTE_ALWAYS_INLINE
+  SILNodeKind getKind() const {
+    return SILNodeKind(Kind);
+  }
+
+  /// If this is a SILArgument or a SILInstruction get its parent basic block,
+  /// otherwise return null.
+  SILBasicBlock *getParentBlock() const;
+
+  /// If this is a SILArgument or a SILInstruction get its parent function,
+  /// otherwise return null.
+  SILFunction *getFunction() const;
+
+  /// If this is a SILArgument or a SILInstruction get its parent module,
+  /// otherwise return null.
+  SILModule *getModule() const;
+
+  /// Pretty-print the node.  If the node is an instruction, the output
+  /// will be valid SIL assembly; otherwise, it will be an arbitrary
+  /// format suitable for debugging.
+  void print(raw_ostream &OS) const;
+  void dump() const;
+
+  /// Pretty-print the node in context, preceded by its operands (if the
+  /// value represents the result of an instruction) and followed by its
+  /// users.
+  void printInContext(raw_ostream &OS) const;
+  void dumpInContext() const;
+
+  // Cast to SingleValueInstruction.  This is an implementation detail
+  // of the cast machinery.  At a high level, all you need to know is to
+  // never use static_cast to downcast a SILNode.
+  SingleValueInstruction *castToSingleValueInstruction();
+  const SingleValueInstruction *castToSingleValueInstruction() const {
+    return const_cast<SILNode*>(this)->castToSingleValueInstruction();
+  }
+
+  static bool classof(const SILNode *node) {
+    return true;
+  }
+};
+
+inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
+                                     const SILNode &node) {
+  node.print(OS);
+  return OS;
+}
+
+template <class To> struct cast_sil_node_is_unambiguous {
+  // The only ambiguity right now is between the value and instruction
+  // nodes on a SingleValueInstruction.
+  static constexpr bool value =
+    // If the destination type isn't a subclass of ValueBase or
+    // SILInstruction, there's no ambiguity.
+       (!std::is_base_of<SILInstruction, To>::value &&
+        !std::is_base_of<ValueBase, To>::value)
+
+    // If the destination type is a proper subclass of ValueBase
+    // that isn't a subclass of SILInstruction, there's no ambiguity.
+    || (std::is_base_of<ValueBase, To>::value &&
+        !std::is_same<ValueBase, To>::value &&
+        !std::is_base_of<SILInstruction, To>::value)
+
+    // If the destination type is a proper subclass of SILInstruction
+    // that isn't a subclass of ValueBase, there's no ambiguity.
+    || (std::is_base_of<SILInstruction, To>::value &&
+        !std::is_same<SILInstruction, To>::value &&
+        !std::is_base_of<ValueBase, To>::value);
+};
+
+template <class To,
+          bool IsSingleValueInstruction =
+            std::is_base_of<SingleValueInstruction, To>::value,
+          bool IsKnownUnambiguous =
+            cast_sil_node_is_unambiguous<To>::value>
+struct cast_sil_node;
+
+// If all complete objects of the destination type are known to only
+// contain a single node, we can just use a static_cast.
+template <class To>
+struct cast_sil_node<To, /*single value*/ false, /*unambiguous*/ true> {
+  static To *doit(SILNode *node) {
+    return &static_cast<To&>(*node);
+  }
+};
+
+// If we're casting to a subclass of SingleValueInstruction, we don't
+// need to dynamically check whether the node is an SVI.  In fact,
+// we can't, because the static_cast will be ambiguous.
+template <class To>
+struct cast_sil_node<To, /*single value*/ true, /*unambiguous*/ false> {
+  static To *doit(SILNode *node) {
+    auto svi = node->castToSingleValueInstruction();
+    return &static_cast<To&>(*svi);
+  }
+};
+
+// Otherwise, we need to dynamically check which case we're in.
+template <class To>
+struct cast_sil_node<To, /*single value*/ false, /*unambiguous*/ false> {
+  static To *doit(SILNode *node) {
+    // If the node isn't dynamically a SingleValueInstruction, then this
+    // is indeed the SILNode subobject that's statically observable in To.
+    if (!SILNode::hasMultipleSILNodes(node->getKind())) {
+      return &static_cast<To&>(*node);
+    }
+
+    auto svi = node->castToSingleValueInstruction();
+    return &static_cast<To&>(*svi);
+  }
+};
+
+} // end namespace swift
+
+namespace llvm {
+
+/// Completely take over cast<>'ing from SILNode*.  A static_cast to
+/// ValueBase* or SILInstruction* can be quite wrong.
+template <class To>
+struct cast_convert_val<To, swift::SILNode*, swift::SILNode*> {
+  using ret_type = typename cast_retty<To, swift::SILNode*>::ret_type;
+  static ret_type doit(swift::SILNode *node) {
+    return swift::cast_sil_node<To>::doit(node);
+  }
+};
+template <class To>
+struct cast_convert_val<To, const swift::SILNode *, const swift::SILNode *> {
+  using ret_type = typename cast_retty<To, const swift::SILNode*>::ret_type;
+  static ret_type doit(const swift::SILNode *node) {
+    return swift::cast_sil_node<To>::doit(const_cast<swift::SILNode*>(node));
+  }
+};
+
+// We don't support casting from SILNode references yet.
+template <class To, class From>
+struct cast_convert_val<To, swift::SILNode, From>;
+template <class To, class From>
+struct cast_convert_val<To, const swift::SILNode, From>;
+
+/// ValueBase * is always at least eight-byte aligned; make the three tag bits
+/// available through PointerLikeTypeTraits.
+template<>
+class PointerLikeTypeTraits<swift::SILNode *> {
+public:
+  static inline void *getAsVoidPointer(swift::SILNode *I) {
+    return (void*)I;
+  }
+  static inline swift::SILNode *getFromVoidPointer(void *P) {
+    return (swift::SILNode *)P;
+  }
+  enum { NumLowBitsAvailable = 3 };
+};
+
+} // end namespace llvm
+
+#endif
diff --git a/include/swift/SIL/SILNodes.def b/include/swift/SIL/SILNodes.def
index 2894d6b..4cf2af4 100644
--- a/include/swift/SIL/SILNodes.def
+++ b/include/swift/SIL/SILNodes.def
@@ -14,60 +14,182 @@
 //
 //===----------------------------------------------------------------------===//
 
-/// VALUE(Id, Parent)
-///   The expression enumerator value is a ValueKind.  The node's class name is
+/// NODE(ID, PARENT)
+///
+///   A concrete subclass of SILNode.  ID is the name of the class as well
+///   as a member of SILNodeKind.  PARENT is the name of its abstract
+///   superclass.
+#ifndef NODE
+#define NODE(ID, PARENT)
+#endif
+
+/// SINGLE_VALUE_INST(Id, Parent, TextualName, MemBehavior, MayRelease)
+///
+///   A concrete subclass of SingleValueInstruction, which inherits from
+///   both ValueBase and SILInstruction.  ID is a member of both ValueKind
+///   and SILInstructionKind.
+#ifndef SINGLE_VALUE_INST
+#ifdef VALUE
+#define SINGLE_VALUE_INST(ID, NAME, PARENT, MEMBEHAVIOR, MAYRELEASE) \
+  VALUE(ID, PARENT)
+#else
+#define SINGLE_VALUE_INST(ID, NAME, PARENT, MEMBEHAVIOR, MAYRELEASE) \
+  FULL_INST(ID, NAME, PARENT, MEMBEHAVIOR, MAYRELEASE)
+#endif
+#endif
+
+/// VALUE(ID, PARENT)
+///
+///   A concrete subclass of ValueBase.  ID is a member of ValueKind.
+///   ID is a member of ValueKind.  The node's class name is
 ///   Id, and the name of its base class (in the SILValue hierarchy) is Parent.
 #ifndef VALUE
-#define VALUE(Id, Parent)
+#define VALUE(ID, PARENT) NODE(ID, PARENT)
 #endif
 
-/// ARGUMENT(Id, Parent)
-///   The expression enumerator value is a ValueKind. The node's class name is
-///   Id and the name of its base class (in the SILValue hierarchy) is Parent.
+/// ARGUMENT(ID, PARENT)
+///
+///   A concrete subclass of SILArgument, which is a subclass of ValueBase.
 #ifndef ARGUMENT
-#define ARGUMENT(Id, Parent) VALUE(Id, Parent)
+#define ARGUMENT(ID, PARENT) VALUE(ID, PARENT)
 #endif
 
-/// INST(Id, Parent, TextualName, MemBehavior, MayRelease)
+/// INST(ID, PARENT)
 ///
-///   The expression enumerator value is a ValueKind.  The node's class name is
-///   Id, and the name of its base class (in the SILInstruction hierarchy) is
-///   Parent. TextualName is the textual name of the instruction. MemBehavior is
-///   an enum value that reflects the memory behavior of the
-///   instruction. MayRelease indicates whether the execution of the instruction
-///   may result in memory being released.
+///   A concrete subclass of SILInstruction.  ID is a member of
+///   SILInstructionKind.
 #ifndef INST
-#define INST(Id, Parent, TextualName, MemBehavior, MayRelease) VALUE(Id, Parent)
+#define INST(ID, PARENT) NODE(ID, PARENT)
 #endif
 
-/// TERMINATOR(Id, Parent, TextualName, MemBehavior, MayRelease)
-///   Expands for terminator instructions. The expression enumerator value is a
-///   ValueKind.  The node's class name is Id, and the name of its base class
-///   (in the SILInstruction hierarchy) is Parent. TextualName is the name of
-///   the instruction in textual SIL.  MemBehavior is an enum value that
-///   reflects the memory behavior of the instruction. MayRelease indicates
-///   whether the execution of the instruction may result in memory being
-///   released.
-#ifndef TERMINATOR
-#define TERMINATOR(Id, Parent, TextualName, MemBehavior, MayRelease)     \
-      INST(Id, Parent, TextualName, MemBehavior, MayRelease)
-#endif
-
-/// An abstract value base is an abstract base class in the hierarchy; it is
-/// never a most-derived type, and it does not have an enumerator in ValueKind.
+/// FULL_INST(ID, NAME, PARENT, MEMBEHAVIOR, MAYRELEASE)
 ///
-/// Most metaprograms do not care about abstract expressions, so the default
-/// is to ignore them.
-#ifndef ABSTRACT_VALUE
-#define ABSTRACT_VALUE(Id, Parent)
+///   A macro which includes a bunch of secondary information about
+///   an instruction.  In addition to the information from INST:
+///
+///   NAME is the name of the instruction in SIL assembly.
+///   The argument will be a bare identifier, not a string literal.
+///
+///   MEMBEHAVIOR is an enum value that reflects the memory behavior of
+///   the instruction.
+///
+///   MAYRELEASE indicates whether the execution of the
+///   instruction may result in memory being released.
+#ifndef FULL_INST
+#define FULL_INST(ID, NAME, PARENT, MEMBEHAVIOR, MAYRELEASE) INST(ID, PARENT)
 #endif
 
-/// A convenience for determining the range of values.  These will always
-/// appear immediately after the last member.
-#ifndef VALUE_RANGE
-#define VALUE_RANGE(Id, First, Last)
+/// NON_VALUE_INST(ID, NAME, PARENT, MEMBEHAVIOR, MAYRELEASE)
+///
+///   ID is a SILInstructionKind and the name of a subclass of SILInstruction
+///   that does not inherit from ValueBase.
+#ifndef NON_VALUE_INST
+#define NON_VALUE_INST(ID, NAME, PARENT, MEMBEHAVIOR, MAYRELEASE) \
+  FULL_INST(ID, NAME, PARENT, MEMBEHAVIOR, MAYRELEASE)
 #endif
 
+/// TERMINATOR(ID, NAME, PARENT, MEMBEHAVIOR, MAYRELEASE)
+///
+///   ID is a member of TerminatorKind and the name of a subclass of TermInst.
+#ifndef TERMINATOR
+#define TERMINATOR(ID, NAME, PARENT, MEMBEHAVIOR, MAYRELEASE) \
+  NON_VALUE_INST(ID, NAME, PARENT, MEMBEHAVIOR, MAYRELEASE)
+#endif
+
+/// ABSTRACT_NODE(ID, PARENT)
+///
+///   An abstract class in the SILNode hierarchy.   It does not have an
+///   enumerator in SILNodeKind and is never the most-derived type of a
+///   node.  ID is the name of the class.
+///
+///   PARENT is the name of its abstract superclass in the node
+///   hierarchy, which will be either a subject of an ABSTRACT_NODE
+///   entry or SILNode.  SingleValueInstruction considers its superclass
+///   to be SILInstruction for the purposes of the node hierarchy.
+#ifndef ABSTRACT_NODE
+#define ABSTRACT_NODE(ID, PARENT)
+#endif
+
+// Handle SingleValueInstruction.
+#ifdef ABSTRACT_VALUE
+#define ABSTRACT_VALUE_AND_INST(ID, VALUE_PARENT, INST_PARENT) \
+  ABSTRACT_VALUE(ID, VALUE_PARENT)
+#else
+#define ABSTRACT_VALUE_AND_INST(ID, VALUE_PARENT, INST_PARENT) \
+  ABSTRACT_INST(ID, INST_PARENT)
+#endif
+
+/// ABSTRACT_SINGLE_VALUE_INST(ID, PARENT)
+///
+///   An abstract subclass of SingleValueInstruction, which is therefore
+///   in both the ValueBase and SILInstruction hierarchies.
+#ifndef ABSTRACT_SINGLE_VALUE_INST
+#ifdef ABSTRACT_VALUE
+#define ABSTRACT_SINGLE_VALUE_INST(ID, PARENT) ABSTRACT_VALUE(ID, PARENT)
+#else
+#define ABSTRACT_SINGLE_VALUE_INST(ID, PARENT) ABSTRACT_INST(ID, PARENT)
+#endif
+#endif
+
+/// ABSTRACT_VALUE(ID, PARENT)
+///
+///   An abstract class in the ValueBase hierarchy.   It does not have an
+///   enumerator in ValueKind and is never the most-derived type of a
+///   node.  ID is the name of the class.
+///
+///   PARENT is the name of its abstract superclass in the ValueBase
+///   hierarchy, which be either a subject of an ABSTRACT_VALUE
+///   entry or ValueBase.
+#ifndef ABSTRACT_VALUE
+#define ABSTRACT_VALUE(ID, PARENT) ABSTRACT_NODE(ID, PARENT)
+#endif
+
+/// ABSTRACT_INST(ID, PARENT)
+///
+///   An abstract class in the SILInstruction hierarchy.   It does not
+///   enumerator in SILInstructionKind and is never the most-derived type
+///   of a node.  ID is the name of the class.
+///
+///   PARENT is the name of its abstract superclass in the SILInstruction
+///   hierarchy, which be either a subject of an ABSTRACT_INST
+///   entry or SILInstruction.
+#ifndef ABSTRACT_INST
+#define ABSTRACT_INST(ID, PARENT) ABSTRACT_NODE(ID, PARENT)
+#endif
+
+/// NODE_RANGE(ID, PARENT)
+///
+///   The enumerator range of an abstract class in the SILNode hierarchy.
+///   This will always appear right after the last member of the class.
+#ifndef NODE_RANGE
+#define NODE_RANGE(ID, FIRST, LAST)
+#endif
+
+#ifndef SINGLE_VALUE_INST_RANGE
+#ifdef VALUE_RANGE
+#define SINGLE_VALUE_INST_RANGE(ID, FIRST, LAST) VALUE_RANGE(ID, FIRST, LAST)
+#else
+#define SINGLE_VALUE_INST_RANGE(ID, FIRST, LAST) INST_RANGE(ID, FIRST, LAST)
+#endif
+#endif
+
+/// VALUE_RANGE(ID, PARENT)
+///
+///   The enumerator range of an abstract class in the ValueBase hierarchy.
+#ifndef VALUE_RANGE
+#define VALUE_RANGE(ID, FIRST, LAST) NODE_RANGE(ID, FIRST, LAST)
+#endif
+
+/// INST_RANGE(ID, PARENT)
+///
+///   The enumerator range of an abstract class in the SILInstruction
+///   hierarchy.
+#ifndef INST_RANGE
+#define INST_RANGE(ID, FIRST, LAST) NODE_RANGE(ID, FIRST, LAST)
+#endif
+
+ABSTRACT_NODE(ValueBase, SILNode)
+
 ABSTRACT_VALUE(SILArgument, ValueBase)
   ARGUMENT(SILPHIArgument, SILArgument)
   ARGUMENT(SILFunctionArgument, SILArgument)
@@ -75,219 +197,118 @@
 
 VALUE(SILUndef, ValueBase)
 
-// Please keep the order of instructions consistent with the order of their
-// descriptions in the SIL reference in docs/SIL.rst.
+ABSTRACT_NODE(SILInstruction, SILNode)
 
-ABSTRACT_VALUE(SILInstruction, ValueBase)
+ABSTRACT_VALUE_AND_INST(SingleValueInstruction, ValueBase, SILInstruction)
   // Allocation instructions.
-  ABSTRACT_VALUE(AllocationInst, SILInstruction)
-    INST(AllocStackInst, AllocationInst, alloc_stack, None, DoesNotRelease)
-    INST(AllocRefInst, AllocationInst, alloc_ref, None, DoesNotRelease)
-    INST(AllocRefDynamicInst, AllocationInst, alloc_ref_dynamic, None, DoesNotRelease)
-    INST(AllocValueBufferInst, AllocationInst, alloc_value_buffer, None, DoesNotRelease)
-    INST(AllocBoxInst, AllocationInst, alloc_box, None, DoesNotRelease)
-    INST(AllocExistentialBoxInst, AllocationInst, alloc_existential_box, MayWrite, DoesNotRelease)
-    VALUE_RANGE(AllocationInst, AllocStackInst, AllocExistentialBoxInst)
+  ABSTRACT_SINGLE_VALUE_INST(AllocationInst, SingleValueInstruction)
+    SINGLE_VALUE_INST(AllocStackInst, alloc_stack,
+                      AllocationInst, None, DoesNotRelease)
+    SINGLE_VALUE_INST(AllocRefInst, alloc_ref,
+                      AllocationInst, None, DoesNotRelease)
+    SINGLE_VALUE_INST(AllocRefDynamicInst, alloc_ref_dynamic,
+                      AllocationInst, None, DoesNotRelease)
+    SINGLE_VALUE_INST(AllocValueBufferInst, alloc_value_buffer,
+                      AllocationInst, None, DoesNotRelease)
+    SINGLE_VALUE_INST(AllocBoxInst, alloc_box,
+                      AllocationInst, None, DoesNotRelease)
+    SINGLE_VALUE_INST(AllocExistentialBoxInst, alloc_existential_box,
+                      AllocationInst, MayWrite, DoesNotRelease)
+    SINGLE_VALUE_INST_RANGE(AllocationInst, AllocStackInst, AllocExistentialBoxInst)
 
-  // Deallocation instructions.
-  ABSTRACT_VALUE(DeallocationInst, SILInstruction)
-    INST(DeallocStackInst, DeallocationInst, dealloc_stack, MayHaveSideEffects, DoesNotRelease)
-    INST(DeallocRefInst, DeallocationInst, dealloc_ref, MayHaveSideEffects, DoesNotRelease)
-    INST(DeallocPartialRefInst, DeallocationInst, dealloc_partial_ref, MayHaveSideEffects,
-         DoesNotRelease)
-    INST(DeallocValueBufferInst, DeallocationInst, dealloc_value_buffer, MayHaveSideEffects,
-         DoesNotRelease)
-    INST(DeallocBoxInst, DeallocationInst, dealloc_box, MayHaveSideEffects, DoesNotRelease)
-    INST(DeallocExistentialBoxInst, DeallocationInst, dealloc_existential_box, MayHaveSideEffects,
-         DoesNotRelease)
-    VALUE_RANGE(DeallocationInst, DeallocStackInst, DeallocExistentialBoxInst)
-
-  // Accessing memory
-  INST(LoadInst, SILInstruction, load, MayRead, DoesNotRelease)
-  INST(LoadBorrowInst, SILInstruction, load_borrow, MayRead, DoesNotRelease)
-  INST(BeginBorrowInst, SILInstruction, begin_borrow, MayHaveSideEffects, DoesNotRelease)
-  INST(EndBorrowInst, SILInstruction, end_borrow, MayHaveSideEffects, DoesNotRelease)
-  INST(EndBorrowArgumentInst, SILInstruction, end_borrow_argument, MayHaveSideEffects, DoesNotRelease)
-  INST(BeginAccessInst, SILInstruction, begin_access, MayHaveSideEffects, DoesNotRelease)
-  INST(EndAccessInst, SILInstruction, end_access, MayHaveSideEffects, DoesNotRelease)
-  INST(BeginUnpairedAccessInst, SILInstruction, begin_unpaired_access, MayHaveSideEffects, DoesNotRelease)
-  INST(EndUnpairedAccessInst, SILInstruction, end_unpaired_access, MayHaveSideEffects, DoesNotRelease)
-  INST(LoadUnownedInst, SILInstruction, load_unowned, MayRead, DoesNotRelease)
-  INST(LoadWeakInst, SILInstruction, load_weak, MayRead, DoesNotRelease)
-  INST(StoreInst, SILInstruction, store, MayWrite, DoesNotRelease)
-  INST(StoreBorrowInst, SILInstruction, store_borrow, MayWrite, DoesNotRelease)
-  INST(AssignInst, SILInstruction, assign, MayWrite, DoesNotRelease)
-  INST(MarkUninitializedInst, SILInstruction, mark_uninitialized, None, DoesNotRelease)
-  INST(MarkUninitializedBehaviorInst, SILInstruction, mark_uninitialized_behavior, None, DoesNotRelease)
-  INST(MarkFunctionEscapeInst, SILInstruction, mark_function_escape, None, DoesNotRelease)
-  INST(DebugValueInst, SILInstruction, debug_value, None, DoesNotRelease)
-  INST(DebugValueAddrInst, SILInstruction, debug_value_addr, None, DoesNotRelease)
-  INST(StoreUnownedInst, SILInstruction, store_unowned, MayWrite, DoesNotRelease)
-  INST(StoreWeakInst, SILInstruction, store_weak, MayWrite, DoesNotRelease)
-  INST(CopyAddrInst, SILInstruction, copy_addr, MayHaveSideEffects, MayRelease)
-  INST(DestroyAddrInst, SILInstruction, destroy_addr, MayHaveSideEffects, MayRelease)
-  INST(ProjectValueBufferInst, SILInstruction, project_value_buffer, MayRead, DoesNotRelease)
-  INST(ProjectBoxInst, SILInstruction, project_box, None, DoesNotRelease)
-  INST(ProjectExistentialBoxInst, SILInstruction, project_existential_box, None, DoesNotRelease)
-  ABSTRACT_VALUE(IndexingInst, SILInstruction)
-    INST(IndexAddrInst, IndexingInst, index_addr, None, DoesNotRelease)
-    INST(TailAddrInst, IndexingInst, tail_addr, None, DoesNotRelease)
-    INST(IndexRawPointerInst, IndexingInst, index_raw_pointer, None, DoesNotRelease)
-    VALUE_RANGE(IndexingInst, IndexAddrInst, IndexRawPointerInst)
-
-  // BindMemory has no physical side effect. Semantically it writes to
-  // its affected memory region because any reads or writes accessing
-  // that memory must be dependent on the bind operation.
-  INST(BindMemoryInst, SILInstruction, bind_memory, MayWrite, DoesNotRelease)
-
-  // Reference Counting
-  ABSTRACT_VALUE(RefCountingInst, SILInstruction)
-    INST(StrongRetainInst, RefCountingInst, strong_retain, MayHaveSideEffects, DoesNotRelease)
-    INST(StrongReleaseInst, RefCountingInst, strong_release, MayHaveSideEffects, MayRelease)
-    INST(StrongRetainUnownedInst, RefCountingInst, strong_retain_unowned, MayHaveSideEffects,
-         DoesNotRelease)
-    INST(StrongPinInst, RefCountingInst, strong_pin, MayHaveSideEffects, DoesNotRelease)
-    INST(StrongUnpinInst, RefCountingInst, strong_unpin, MayHaveSideEffects, DoesNotRelease)
-    INST(UnownedRetainInst, RefCountingInst, unowned_retain, MayHaveSideEffects, DoesNotRelease)
-    INST(UnownedReleaseInst, RefCountingInst, unowned_release, MayHaveSideEffects,
-         MayRelease)
-    INST(UnmanagedRetainValueInst, RefCountingInst, unmanaged_retain_value, MayHaveSideEffects, DoesNotRelease)
-    INST(UnmanagedReleaseValueInst, RefCountingInst, unmanaged_release_value, MayHaveSideEffects, MayRelease)
-    INST(UnmanagedAutoreleaseValueInst, RefCountingInst, unmanaged_autorelease_value, MayHaveSideEffects, DoesNotRelease)
-    INST(RetainValueInst, RefCountingInst, retain_value, MayHaveSideEffects, DoesNotRelease)
-    INST(RetainValueAddrInst, RefCountingInst, retain_value_addr, MayHaveSideEffects, DoesNotRelease)
-    INST(ReleaseValueInst, RefCountingInst, release_value, MayHaveSideEffects, MayRelease)
-    INST(ReleaseValueAddrInst, RefCountingInst, release_value_addr, MayHaveSideEffects, MayRelease)
-    INST(SetDeallocatingInst, RefCountingInst, set_deallocating, MayHaveSideEffects,
-         DoesNotRelease)
-    INST(AutoreleaseValueInst, RefCountingInst, autorelease_value, MayHaveSideEffects,
-         DoesNotRelease)
-    VALUE_RANGE(RefCountingInst, StrongRetainInst, AutoreleaseValueInst)
-  // FIXME: Is MayHaveSideEffects appropriate?
-  INST(FixLifetimeInst, SILInstruction, fix_lifetime, MayHaveSideEffects, DoesNotRelease)
-  INST(MarkDependenceInst, SILInstruction, mark_dependence, None, DoesNotRelease)
-  INST(CopyBlockInst, SILInstruction, copy_block, MayHaveSideEffects, DoesNotRelease)
-  INST(CopyValueInst, SILInstruction, copy_value, MayHaveSideEffects, DoesNotRelease)
-  INST(CopyUnownedValueInst, SILInstruction, copy_unowned_value, MayHaveSideEffects, DoesNotRelease)
-  INST(DestroyValueInst, SILInstruction, destroy_value, MayHaveSideEffects, MayRelease)
-  INST(EndLifetimeInst, SILInstruction, end_lifetime, MayHaveSideEffects, MayRelease)
-  INST(UncheckedOwnershipConversionInst, SILInstruction, unchecked_ownership_conversion, MayHaveSideEffects, MayRelease)
-
-  // IsUnique does not actually write to memory but should be modeled
-  // as such. Its operand is a pointer to an object reference. The
-  // optimizer should not assume that the same object is pointed to after
-  // the isUnique instruction. It appears to write a new object reference.
-  INST(IsUniqueInst, SILInstruction, is_unique, MayHaveSideEffects, DoesNotRelease)
-  INST(IsUniqueOrPinnedInst, SILInstruction, is_unique_or_pinned, MayHaveSideEffects, DoesNotRelease)
-
-  INST(AllocGlobalInst, SILInstruction, alloc_global, MayHaveSideEffects, DoesNotRelease)
+  ABSTRACT_SINGLE_VALUE_INST(IndexingInst, SingleValueInstruction)
+    SINGLE_VALUE_INST(IndexAddrInst, index_addr,
+                      IndexingInst, None, DoesNotRelease)
+    SINGLE_VALUE_INST(TailAddrInst, tail_addr,
+                      IndexingInst, None, DoesNotRelease)
+    SINGLE_VALUE_INST(IndexRawPointerInst, index_raw_pointer,
+                      IndexingInst, None, DoesNotRelease)
+    SINGLE_VALUE_INST_RANGE(IndexingInst, IndexAddrInst, IndexRawPointerInst)
 
   // Literals
-  ABSTRACT_VALUE(LiteralInst, SILInstruction)
-    INST(FunctionRefInst, LiteralInst, function_ref, None, DoesNotRelease)
-    INST(GlobalAddrInst, LiteralInst, global_addr, None, DoesNotRelease)
-    INST(GlobalValueInst, LiteralInst, global_value, None, DoesNotRelease)
-    INST(IntegerLiteralInst, LiteralInst, integer_literal, None, DoesNotRelease)
-    INST(FloatLiteralInst, LiteralInst, float_literal, None, DoesNotRelease)
-    INST(StringLiteralInst, LiteralInst, string_literal, None, DoesNotRelease)
-    INST(ConstStringLiteralInst, LiteralInst, const_string_literal, None, DoesNotRelease)
-    VALUE_RANGE(LiteralInst, FunctionRefInst, ConstStringLiteralInst)
+  ABSTRACT_SINGLE_VALUE_INST(LiteralInst, SingleValueInstruction)
+    SINGLE_VALUE_INST(FunctionRefInst, function_ref,
+                      LiteralInst, None, DoesNotRelease)
+    SINGLE_VALUE_INST(GlobalAddrInst, global_addr,
+                      LiteralInst, None, DoesNotRelease)
+    SINGLE_VALUE_INST(GlobalValueInst, global_value,
+                      LiteralInst, None, DoesNotRelease)
+    SINGLE_VALUE_INST(IntegerLiteralInst, integer_literal,
+                      LiteralInst, None, DoesNotRelease)
+    SINGLE_VALUE_INST(FloatLiteralInst, float_literal,
+                      LiteralInst, None, DoesNotRelease)
+    SINGLE_VALUE_INST(StringLiteralInst, string_literal,
+                      LiteralInst, None, DoesNotRelease)
+    SINGLE_VALUE_INST(ConstStringLiteralInst, const_string_literal,
+                      LiteralInst, None, DoesNotRelease)
+    SINGLE_VALUE_INST_RANGE(LiteralInst, FunctionRefInst, ConstStringLiteralInst)
 
   // Dynamic Dispatch
-  ABSTRACT_VALUE(MethodInst, SILInstruction)
-    INST(ClassMethodInst, MethodInst, class_method, None, DoesNotRelease)
-    INST(SuperMethodInst, MethodInst, super_method, None, DoesNotRelease)
-    INST(WitnessMethodInst, MethodInst, witness_method, None, DoesNotRelease)
-    INST(DynamicMethodInst, MethodInst, dynamic_method, None, DoesNotRelease)
-    VALUE_RANGE(MethodInst, ClassMethodInst, DynamicMethodInst)
-
-  // Function Application
-  INST(ApplyInst, SILInstruction, apply, MayHaveSideEffects, MayRelease)
-  INST(PartialApplyInst, SILInstruction, partial_apply, MayHaveSideEffects, DoesNotRelease)
-  INST(BuiltinInst, SILInstruction, builtin, MayHaveSideEffects, MayRelease)
-
-  // Metatypes
-  INST(MetatypeInst, SILInstruction, metatype, None, DoesNotRelease)
-  INST(ValueMetatypeInst, SILInstruction, value_metatype, MayRead, DoesNotRelease)
-  INST(ExistentialMetatypeInst, SILInstruction, existential_metatype, MayRead, DoesNotRelease)
-  INST(ObjCProtocolInst, SILInstruction, objc_protocol, None, DoesNotRelease)
-
-  // Aggregate Types
-  INST(ObjectInst, SILInstruction, object, None, DoesNotRelease)
-  INST(TupleInst, SILInstruction, tuple, None, DoesNotRelease)
-  INST(TupleExtractInst, SILInstruction, tuple_extract, None, DoesNotRelease)
-  INST(TupleElementAddrInst, SILInstruction, tuple_element_addr, None, DoesNotRelease)
-  INST(StructInst, SILInstruction, struct, None, DoesNotRelease)
-  INST(StructExtractInst, SILInstruction, struct_extract, None, DoesNotRelease)
-  INST(StructElementAddrInst, SILInstruction, struct_element_addr, None, DoesNotRelease)
-  INST(RefElementAddrInst, SILInstruction, ref_element_addr, None, DoesNotRelease)
-  INST(RefTailAddrInst, SILInstruction, ref_tail_addr, None, DoesNotRelease)
-
-  // Enums
-  INST(EnumInst, SILInstruction, enum, None, DoesNotRelease)
-  INST(UncheckedEnumDataInst, SILInstruction, unchecked_enum_data, None, DoesNotRelease)
-  INST(InitEnumDataAddrInst, SILInstruction, init_enum_data_addr, None, DoesNotRelease)
-  INST(UncheckedTakeEnumDataAddrInst, SILInstruction, unchecked_take_enum_data_addr, MayWrite, DoesNotRelease)
-  INST(InjectEnumAddrInst, SILInstruction, inject_enum_addr, MayWrite, DoesNotRelease)
-  INST(SelectEnumInst, SILInstruction, select_enum, None, DoesNotRelease)
-  INST(SelectEnumAddrInst, SILInstruction, select_enum_addr, MayRead, DoesNotRelease)
-  INST(SelectValueInst, SILInstruction, select_value, None, DoesNotRelease)
-
-  // Protocol and Protocol Composition Types
-  INST(InitExistentialAddrInst, SILInstruction, init_existential_addr, MayWrite, DoesNotRelease)
-  INST(InitExistentialValueInst, SILInstruction, init_existential_value, MayWrite, DoesNotRelease)
-  INST(DeinitExistentialAddrInst, SILInstruction, deinit_existential_addr, MayHaveSideEffects,
-       DoesNotRelease)
-  INST(DeinitExistentialValueInst, SILInstruction, deinit_existential_value, MayHaveSideEffects,
-       DoesNotRelease)
-  INST(OpenExistentialAddrInst, SILInstruction, open_existential_addr, MayRead, DoesNotRelease)
-  INST(InitExistentialRefInst, SILInstruction, init_existential_ref, None, DoesNotRelease)
-  INST(OpenExistentialRefInst, SILInstruction, open_existential_ref, None, DoesNotRelease)
-  INST(InitExistentialMetatypeInst, SILInstruction, init_existential_metatype, None, DoesNotRelease)
-  INST(OpenExistentialMetatypeInst, SILInstruction, open_existential_metatype, None, DoesNotRelease)
-  INST(OpenExistentialBoxInst, SILInstruction, open_existential_box, MayRead, DoesNotRelease)
-  INST(OpenExistentialValueInst, SILInstruction, open_existential_value, MayRead, DoesNotRelease)
-  INST(OpenExistentialBoxValueInst, SILInstruction, open_existential_box_value, MayRead, DoesNotRelease)
-
-  // Blocks
-  INST(ProjectBlockStorageInst, SILInstruction, project_block_storage, None, DoesNotRelease)
-  INST(InitBlockStorageHeaderInst, SILInstruction, init_block_storage_header, None, DoesNotRelease)
-
-  // Key paths
-  // TODO: The only "side effect" is potentially retaining the returned key path
-  // object; is there a more specific effect?
-  INST(KeyPathInst, SILInstruction, keypath, MayHaveSideEffects, DoesNotRelease)
+  ABSTRACT_SINGLE_VALUE_INST(MethodInst, SingleValueInstruction)
+    SINGLE_VALUE_INST(ClassMethodInst, class_method,
+                      MethodInst, None, DoesNotRelease)
+    SINGLE_VALUE_INST(SuperMethodInst, super_method,
+                      MethodInst, None, DoesNotRelease)
+    SINGLE_VALUE_INST(WitnessMethodInst, witness_method,
+                      MethodInst, None, DoesNotRelease)
+    SINGLE_VALUE_INST(DynamicMethodInst, dynamic_method,
+                      MethodInst, None, DoesNotRelease)
+    SINGLE_VALUE_INST_RANGE(MethodInst, ClassMethodInst, DynamicMethodInst)
 
   // Conversions
-  ABSTRACT_VALUE(ConversionInst, SILInstruction)
-    INST(UpcastInst, ConversionInst, upcast, None, DoesNotRelease)
-    INST(AddressToPointerInst, ConversionInst, address_to_pointer, None, DoesNotRelease)
-    INST(PointerToAddressInst, ConversionInst, pointer_to_address, None, DoesNotRelease)
-    INST(UncheckedRefCastInst, ConversionInst, unchecked_ref_cast, None, DoesNotRelease)
-    INST(UncheckedAddrCastInst, ConversionInst, unchecked_addr_cast, None, DoesNotRelease)
-    INST(UncheckedTrivialBitCastInst, ConversionInst, unchecked_trivial_bit_cast, None, DoesNotRelease)
-    INST(UncheckedBitwiseCastInst, ConversionInst, unchecked_bitwise_cast, None, DoesNotRelease)
-    INST(RefToRawPointerInst, ConversionInst, ref_to_raw_pointer, None, DoesNotRelease)
-    INST(RawPointerToRefInst, ConversionInst, raw_pointer_to_ref, None, DoesNotRelease)
-    INST(RefToUnownedInst, ConversionInst, ref_to_unowned, None, DoesNotRelease)
-    INST(UnownedToRefInst, ConversionInst, unowned_to_ref, None, DoesNotRelease)
-    INST(RefToUnmanagedInst, ConversionInst, ref_to_unmanaged, None, DoesNotRelease)
-    INST(UnmanagedToRefInst, ConversionInst, unmanaged_to_ref, None, DoesNotRelease)
-    INST(ConvertFunctionInst, ConversionInst, convert_function, None, DoesNotRelease)
-    INST(ThinFunctionToPointerInst, ConversionInst, thin_function_to_pointer, None, DoesNotRelease)
-    INST(PointerToThinFunctionInst, ConversionInst, pointer_to_thin_function, None, DoesNotRelease)
-    INST(RefToBridgeObjectInst, ConversionInst, ref_to_bridge_object, None, DoesNotRelease)
-    INST(BridgeObjectToRefInst, ConversionInst, bridge_object_to_ref, None, DoesNotRelease)
-    INST(BridgeObjectToWordInst, ConversionInst, bridge_object_to_word, None, DoesNotRelease)
-    INST(ThinToThickFunctionInst, ConversionInst, thin_to_thick_function, None, DoesNotRelease)
-    INST(ThickToObjCMetatypeInst, ConversionInst, thick_to_objc_metatype, None, DoesNotRelease)
-    INST(ObjCToThickMetatypeInst, ConversionInst, objc_to_thick_metatype, None, DoesNotRelease)
-    INST(ObjCMetatypeToObjectInst, ConversionInst, objc_metatype_to_object, None, DoesNotRelease)
-    INST(ObjCExistentialMetatypeToObjectInst, ConversionInst, objc_existential_metatype_to_object, None,
-         DoesNotRelease)
+  ABSTRACT_SINGLE_VALUE_INST(ConversionInst, SingleValueInstruction)
+    SINGLE_VALUE_INST(UpcastInst, upcast,
+                      ConversionInst, None, DoesNotRelease)
+    SINGLE_VALUE_INST(AddressToPointerInst, address_to_pointer,
+                      ConversionInst, None, DoesNotRelease)
+    SINGLE_VALUE_INST(PointerToAddressInst, pointer_to_address,
+                      ConversionInst, None, DoesNotRelease)
+    SINGLE_VALUE_INST(UncheckedRefCastInst, unchecked_ref_cast,
+                      ConversionInst, None, DoesNotRelease)
+    SINGLE_VALUE_INST(UncheckedAddrCastInst, unchecked_addr_cast,
+                      ConversionInst, None, DoesNotRelease)
+    SINGLE_VALUE_INST(UncheckedTrivialBitCastInst, unchecked_trivial_bit_cast,
+                      ConversionInst, None, DoesNotRelease)
+    SINGLE_VALUE_INST(UncheckedBitwiseCastInst, unchecked_bitwise_cast,
+                      ConversionInst, None, DoesNotRelease)
+    SINGLE_VALUE_INST(RefToRawPointerInst, ref_to_raw_pointer,
+                      ConversionInst, None, DoesNotRelease)
+    SINGLE_VALUE_INST(RawPointerToRefInst, raw_pointer_to_ref,
+                      ConversionInst, None, DoesNotRelease)
+    SINGLE_VALUE_INST(RefToUnownedInst, ref_to_unowned,
+                      ConversionInst, None, DoesNotRelease)
+    SINGLE_VALUE_INST(UnownedToRefInst, unowned_to_ref,
+                      ConversionInst, None, DoesNotRelease)
+    SINGLE_VALUE_INST(RefToUnmanagedInst, ref_to_unmanaged,
+                      ConversionInst, None, DoesNotRelease)
+    SINGLE_VALUE_INST(UnmanagedToRefInst, unmanaged_to_ref,
+                      ConversionInst, None, DoesNotRelease)
+    SINGLE_VALUE_INST(ConvertFunctionInst, convert_function,
+                      ConversionInst, None, DoesNotRelease)
+    SINGLE_VALUE_INST(ThinFunctionToPointerInst, thin_function_to_pointer,
+                      ConversionInst, None, DoesNotRelease)
+    SINGLE_VALUE_INST(PointerToThinFunctionInst, pointer_to_thin_function,
+                      ConversionInst, None, DoesNotRelease)
+    SINGLE_VALUE_INST(RefToBridgeObjectInst, ref_to_bridge_object,
+                      ConversionInst, None, DoesNotRelease)
+    SINGLE_VALUE_INST(BridgeObjectToRefInst, bridge_object_to_ref,
+                      ConversionInst, None, DoesNotRelease)
+    SINGLE_VALUE_INST(BridgeObjectToWordInst, bridge_object_to_word,
+                      ConversionInst, None, DoesNotRelease)
+    SINGLE_VALUE_INST(ThinToThickFunctionInst, thin_to_thick_function,
+                      ConversionInst, None, DoesNotRelease)
+    SINGLE_VALUE_INST(ThickToObjCMetatypeInst, thick_to_objc_metatype,
+                      ConversionInst, None, DoesNotRelease)
+    SINGLE_VALUE_INST(ObjCToThickMetatypeInst, objc_to_thick_metatype,
+                      ConversionInst, None, DoesNotRelease)
+    SINGLE_VALUE_INST(ObjCMetatypeToObjectInst, objc_metatype_to_object,
+                      ConversionInst, None, DoesNotRelease)
+    SINGLE_VALUE_INST(ObjCExistentialMetatypeToObjectInst, objc_existential_metatype_to_object,
+                      ConversionInst, None, DoesNotRelease)
     // unconditional_checked_cast_value reads the source value and produces
     // a new value with a potentially different representation.
-    INST(UnconditionalCheckedCastValueInst, ConversionInst, unconditional_checked_cast_value, MayRead, MayRelease)
+    SINGLE_VALUE_INST(UnconditionalCheckedCastValueInst, unconditional_checked_cast_value,
+                      ConversionInst, MayRead, MayRelease)
     // unconditional_checked_cast_inst is only MayRead to prevent a subsequent
     // release of the cast's source from being hoisted above the cast:
     // retain X
@@ -299,41 +320,314 @@
     // should never happen.  Since unconditional_checked_cast is a
     // scalar cast that doesn't affect the value's representation, its
     // side effect can then be modeled as None.
-    INST(UnconditionalCheckedCastInst, ConversionInst, unconditional_checked_cast, MayRead, DoesNotRelease)
-    VALUE_RANGE(ConversionInst, UpcastInst, UnconditionalCheckedCastInst)
-  INST(IsNonnullInst, SILInstruction, is_nonnull, None, DoesNotRelease)
-  INST(UnconditionalCheckedCastAddrInst, SILInstruction, unconditional_checked_cast_addr, MayHaveSideEffects,
-       MayRelease)
-  INST(UncheckedRefCastAddrInst, SILInstruction, unchecked_ref_cast_addr, MayHaveSideEffects,
+    SINGLE_VALUE_INST(UnconditionalCheckedCastInst, unconditional_checked_cast,
+                      ConversionInst, MayRead, DoesNotRelease)
+    SINGLE_VALUE_INST_RANGE(ConversionInst, UpcastInst, UnconditionalCheckedCastInst)
+
+  SINGLE_VALUE_INST(MarkDependenceInst, mark_dependence,
+                    SingleValueInstruction, None, DoesNotRelease)
+  SINGLE_VALUE_INST(CopyBlockInst, copy_block,
+                    SingleValueInstruction, MayHaveSideEffects, DoesNotRelease)
+  SINGLE_VALUE_INST(CopyValueInst, copy_value,
+                    SingleValueInstruction, MayHaveSideEffects, DoesNotRelease)
+  SINGLE_VALUE_INST(CopyUnownedValueInst, copy_unowned_value,
+                    SingleValueInstruction, MayHaveSideEffects, DoesNotRelease)
+  SINGLE_VALUE_INST(UncheckedOwnershipConversionInst, unchecked_ownership_conversion,
+                    SingleValueInstruction, MayHaveSideEffects, MayRelease)
+  SINGLE_VALUE_INST(StrongPinInst, strong_pin,
+                    SingleValueInstruction, MayHaveSideEffects, DoesNotRelease)
+
+  // IsUnique does not actually write to memory but should be modeled
+  // as such. Its operand is a pointer to an object reference. The
+  // optimizer should not assume that the same object is pointed to after
+  // the isUnique instruction. It appears to write a new object reference.
+  SINGLE_VALUE_INST(IsUniqueInst, is_unique,
+                    SingleValueInstruction, MayHaveSideEffects, DoesNotRelease)
+  SINGLE_VALUE_INST(IsUniqueOrPinnedInst, is_unique_or_pinned,
+                    SingleValueInstruction, MayHaveSideEffects, DoesNotRelease)
+
+  // Accessing memory
+  SINGLE_VALUE_INST(LoadInst, load,
+                    SingleValueInstruction, MayRead, DoesNotRelease)
+  SINGLE_VALUE_INST(LoadBorrowInst, load_borrow,
+                    SingleValueInstruction, MayRead, DoesNotRelease)
+  SINGLE_VALUE_INST(BeginBorrowInst, begin_borrow,
+                    SingleValueInstruction, MayHaveSideEffects, DoesNotRelease)
+  SINGLE_VALUE_INST(StoreBorrowInst, store_borrow,
+                    SILInstruction, MayWrite, DoesNotRelease)
+  SINGLE_VALUE_INST(BeginAccessInst, begin_access,
+                    SingleValueInstruction, MayHaveSideEffects, DoesNotRelease)
+  SINGLE_VALUE_INST(LoadUnownedInst, load_unowned,
+                    SingleValueInstruction, MayRead, DoesNotRelease)
+  SINGLE_VALUE_INST(LoadWeakInst, load_weak,
+                    SingleValueInstruction, MayRead, DoesNotRelease)
+  SINGLE_VALUE_INST(MarkUninitializedInst, mark_uninitialized,
+                    SingleValueInstruction, None, DoesNotRelease)
+  SINGLE_VALUE_INST(MarkUninitializedBehaviorInst, mark_uninitialized_behavior,
+                    SingleValueInstruction, None, DoesNotRelease)
+  SINGLE_VALUE_INST(ProjectValueBufferInst, project_value_buffer,
+                    SingleValueInstruction, MayRead, DoesNotRelease)
+  SINGLE_VALUE_INST(ProjectBoxInst, project_box,
+                    SingleValueInstruction, None, DoesNotRelease)
+  SINGLE_VALUE_INST(ProjectExistentialBoxInst, project_existential_box,
+                    SingleValueInstruction, None, DoesNotRelease)
+
+  // Function Application
+  SINGLE_VALUE_INST(ApplyInst, apply,
+                    SingleValueInstruction, MayHaveSideEffects, MayRelease)
+  SINGLE_VALUE_INST(BuiltinInst, builtin,
+                    SingleValueInstruction, MayHaveSideEffects, MayRelease)
+  SINGLE_VALUE_INST(PartialApplyInst, partial_apply,
+                    SingleValueInstruction, MayHaveSideEffects, DoesNotRelease)
+  
+  // Metatypes
+  SINGLE_VALUE_INST(MetatypeInst, metatype,
+                    SingleValueInstruction, None, DoesNotRelease)
+  SINGLE_VALUE_INST(ValueMetatypeInst, value_metatype,
+                    SingleValueInstruction, MayRead, DoesNotRelease)
+  SINGLE_VALUE_INST(ExistentialMetatypeInst, existential_metatype,
+                    SingleValueInstruction, MayRead, DoesNotRelease)
+  SINGLE_VALUE_INST(ObjCProtocolInst, objc_protocol,
+                    SingleValueInstruction, None, DoesNotRelease)
+
+  // Aggregate Types
+  SINGLE_VALUE_INST(ObjectInst, object,
+                    SingleValueInstruction, None, DoesNotRelease)
+  SINGLE_VALUE_INST(TupleInst, tuple,
+                    SingleValueInstruction, None, DoesNotRelease)
+  SINGLE_VALUE_INST(TupleExtractInst, tuple_extract,
+                    SingleValueInstruction, None, DoesNotRelease)
+  SINGLE_VALUE_INST(TupleElementAddrInst, tuple_element_addr,
+                    SingleValueInstruction, None, DoesNotRelease)
+  SINGLE_VALUE_INST(StructInst, struct,
+                    SingleValueInstruction, None, DoesNotRelease)
+  SINGLE_VALUE_INST(StructExtractInst, struct_extract,
+                    SingleValueInstruction, None, DoesNotRelease)
+  SINGLE_VALUE_INST(StructElementAddrInst, struct_element_addr,
+                    SingleValueInstruction, None, DoesNotRelease)
+  SINGLE_VALUE_INST(RefElementAddrInst, ref_element_addr,
+                    SingleValueInstruction, None, DoesNotRelease)
+  SINGLE_VALUE_INST(RefTailAddrInst, ref_tail_addr,
+                    SingleValueInstruction, None, DoesNotRelease)
+
+  // Enums
+  SINGLE_VALUE_INST(EnumInst, enum,
+                    SingleValueInstruction, None, DoesNotRelease)
+  SINGLE_VALUE_INST(UncheckedEnumDataInst, unchecked_enum_data,
+                    SingleValueInstruction, None, DoesNotRelease)
+  SINGLE_VALUE_INST(InitEnumDataAddrInst, init_enum_data_addr,
+                    SingleValueInstruction, None, DoesNotRelease)
+  SINGLE_VALUE_INST(UncheckedTakeEnumDataAddrInst, unchecked_take_enum_data_addr,
+                    SingleValueInstruction, MayWrite, DoesNotRelease)
+  SINGLE_VALUE_INST(SelectEnumInst, select_enum,
+                    SingleValueInstruction, None, DoesNotRelease)
+  SINGLE_VALUE_INST(SelectEnumAddrInst, select_enum_addr,
+                    SingleValueInstruction, MayRead, DoesNotRelease)
+  SINGLE_VALUE_INST(SelectValueInst, select_value,
+                    SingleValueInstruction, None, DoesNotRelease)
+
+  // Protocol and Protocol Composition Types
+  SINGLE_VALUE_INST(InitExistentialAddrInst, init_existential_addr,
+                    SingleValueInstruction, MayWrite, DoesNotRelease)
+  SINGLE_VALUE_INST(InitExistentialValueInst, init_existential_value,
+                    SingleValueInstruction, MayWrite, DoesNotRelease)
+  SINGLE_VALUE_INST(OpenExistentialAddrInst, open_existential_addr,
+                    SingleValueInstruction, MayRead, DoesNotRelease)
+  SINGLE_VALUE_INST(InitExistentialRefInst, init_existential_ref,
+                    SingleValueInstruction, None, DoesNotRelease)
+  SINGLE_VALUE_INST(OpenExistentialRefInst, open_existential_ref,
+                    SingleValueInstruction, None, DoesNotRelease)
+  SINGLE_VALUE_INST(InitExistentialMetatypeInst, init_existential_metatype,
+                    SingleValueInstruction, None, DoesNotRelease)
+  SINGLE_VALUE_INST(OpenExistentialMetatypeInst, open_existential_metatype,
+                    SingleValueInstruction, None, DoesNotRelease)
+  SINGLE_VALUE_INST(OpenExistentialBoxInst, open_existential_box,
+                    SingleValueInstruction, MayRead, DoesNotRelease)
+  SINGLE_VALUE_INST(OpenExistentialValueInst, open_existential_value,
+                    SingleValueInstruction, MayRead, DoesNotRelease)
+  SINGLE_VALUE_INST(OpenExistentialBoxValueInst, open_existential_box_value,
+                    SingleValueInstruction, MayRead, DoesNotRelease)
+
+  // Blocks
+  SINGLE_VALUE_INST(ProjectBlockStorageInst, project_block_storage,
+                    SingleValueInstruction, None, DoesNotRelease)
+  SINGLE_VALUE_INST(InitBlockStorageHeaderInst, init_block_storage_header,
+                    SingleValueInstruction, None, DoesNotRelease)
+
+  // Key paths
+  // TODO: The only "side effect" is potentially retaining the returned key path
+  // object; is there a more specific effect?
+  SINGLE_VALUE_INST(KeyPathInst, keypath,
+                    SingleValueInstruction, MayHaveSideEffects, DoesNotRelease)
+
+  SINGLE_VALUE_INST(IsNonnullInst, is_nonnull,
+                    SingleValueInstruction, None, DoesNotRelease)
+
+  SINGLE_VALUE_INST_RANGE(SingleValueInstruction, AllocStackInst, IsNonnullInst)
+
+NODE_RANGE(ValueBase, SILPHIArgument, IsNonnullInst)
+
+// Terminators
+ABSTRACT_INST(TermInst, SILInstruction)
+  TERMINATOR(UnreachableInst, unreachable,
+             TermInst, None, DoesNotRelease)
+  TERMINATOR(ReturnInst, return,
+             TermInst, None, DoesNotRelease)
+  TERMINATOR(ThrowInst, throw,
+             TermInst, None, DoesNotRelease)
+  TERMINATOR(TryApplyInst, try_apply,
+             TermInst, MayHaveSideEffects, MayRelease)
+  TERMINATOR(BranchInst, br,
+             TermInst, None, DoesNotRelease)
+  TERMINATOR(CondBranchInst, cond_br,
+             TermInst, None, DoesNotRelease)
+  TERMINATOR(SwitchValueInst, switch_value,
+             TermInst, None, DoesNotRelease)
+  TERMINATOR(SwitchEnumInst, switch_enum,
+             TermInst, None, DoesNotRelease)
+  TERMINATOR(SwitchEnumAddrInst, switch_enum_addr,
+             TermInst, MayRead, DoesNotRelease)
+  TERMINATOR(DynamicMethodBranchInst, dynamic_method_br,
+             TermInst, None, DoesNotRelease)
+  TERMINATOR(CheckedCastBranchInst, checked_cast_br,
+             TermInst, None, DoesNotRelease)
+  TERMINATOR(CheckedCastAddrBranchInst, checked_cast_addr_br,
+             TermInst, MayHaveSideEffects, MayRelease)
+  TERMINATOR(CheckedCastValueBranchInst, checked_cast_value_br,
+             TermInst, None, DoesNotRelease)
+  INST_RANGE(TermInst, UnreachableInst, CheckedCastValueBranchInst)
+
+// Deallocation instructions.
+ABSTRACT_INST(DeallocationInst, SILInstruction)
+  NON_VALUE_INST(DeallocStackInst, dealloc_stack,
+                 DeallocationInst, MayHaveSideEffects, DoesNotRelease)
+  NON_VALUE_INST(DeallocRefInst, dealloc_ref,
+                 DeallocationInst, MayHaveSideEffects, DoesNotRelease)
+  NON_VALUE_INST(DeallocPartialRefInst, dealloc_partial_ref,
+                 DeallocationInst, MayHaveSideEffects, DoesNotRelease)
+  NON_VALUE_INST(DeallocValueBufferInst, dealloc_value_buffer,
+                 DeallocationInst, MayHaveSideEffects, DoesNotRelease)
+  NON_VALUE_INST(DeallocBoxInst, dealloc_box,
+                 DeallocationInst, MayHaveSideEffects, DoesNotRelease)
+  NON_VALUE_INST(DeallocExistentialBoxInst, dealloc_existential_box,
+                 DeallocationInst, MayHaveSideEffects, DoesNotRelease)
+  INST_RANGE(DeallocationInst, DeallocStackInst, DeallocExistentialBoxInst)
+
+// Reference Counting
+ABSTRACT_INST(RefCountingInst, SILInstruction)
+  NON_VALUE_INST(StrongRetainInst, strong_retain,
+                 RefCountingInst, MayHaveSideEffects, DoesNotRelease)
+  NON_VALUE_INST(StrongReleaseInst, strong_release,
+                 RefCountingInst, MayHaveSideEffects, MayRelease)
+  NON_VALUE_INST(StrongRetainUnownedInst, strong_retain_unowned,
+                 RefCountingInst, MayHaveSideEffects,
        DoesNotRelease)
+  NON_VALUE_INST(StrongUnpinInst, strong_unpin,
+                 RefCountingInst, MayHaveSideEffects, DoesNotRelease)
+  NON_VALUE_INST(UnownedRetainInst, unowned_retain,
+                 RefCountingInst, MayHaveSideEffects, DoesNotRelease)
+  NON_VALUE_INST(UnownedReleaseInst, unowned_release,
+                 RefCountingInst, MayHaveSideEffects,
+       MayRelease)
+  NON_VALUE_INST(UnmanagedRetainValueInst, unmanaged_retain_value,
+                 RefCountingInst, MayHaveSideEffects, DoesNotRelease)
+  NON_VALUE_INST(UnmanagedReleaseValueInst, unmanaged_release_value,
+                 RefCountingInst, MayHaveSideEffects, MayRelease)
+  NON_VALUE_INST(UnmanagedAutoreleaseValueInst, unmanaged_autorelease_value,
+                 RefCountingInst, MayHaveSideEffects, DoesNotRelease)
+  NON_VALUE_INST(RetainValueInst, retain_value,
+                 RefCountingInst, MayHaveSideEffects, DoesNotRelease)
+  NON_VALUE_INST(RetainValueAddrInst, retain_value_addr,
+                 RefCountingInst, MayHaveSideEffects, DoesNotRelease)
+  NON_VALUE_INST(ReleaseValueInst, release_value,
+                 RefCountingInst, MayHaveSideEffects, MayRelease)
+  NON_VALUE_INST(ReleaseValueAddrInst, release_value_addr,
+                 RefCountingInst, MayHaveSideEffects, MayRelease)
+  NON_VALUE_INST(SetDeallocatingInst, set_deallocating,
+                 RefCountingInst, MayHaveSideEffects,
+       DoesNotRelease)
+  NON_VALUE_INST(AutoreleaseValueInst, autorelease_value,
+                 RefCountingInst, MayHaveSideEffects,
+       DoesNotRelease)
+  INST_RANGE(RefCountingInst, StrongRetainInst, AutoreleaseValueInst)
 
-  // Runtime failure
-  // FIXME: Special MemBehavior for runtime failure?
-  INST(CondFailInst, SILInstruction, cond_fail, MayHaveSideEffects, DoesNotRelease)
+// BindMemory has no physical side effect. Semantically it writes to
+// its affected memory region because any reads or writes accessing
+// that memory must be dependent on the bind operation.
+NON_VALUE_INST(BindMemoryInst, bind_memory,
+               SILInstruction, MayWrite, DoesNotRelease)
 
-  // Terminators
-  ABSTRACT_VALUE(TermInst, SILInstruction)
-    TERMINATOR(UnreachableInst, TermInst, unreachable, None, DoesNotRelease)
-    TERMINATOR(ReturnInst, TermInst, return, None, DoesNotRelease)
-    TERMINATOR(ThrowInst, TermInst, throw, None, DoesNotRelease)
-    TERMINATOR(TryApplyInst, TermInst, try_apply, MayHaveSideEffects, MayRelease)
-    TERMINATOR(BranchInst, TermInst, br, None, DoesNotRelease)
-    TERMINATOR(CondBranchInst, TermInst, cond_br, None, DoesNotRelease)
-    TERMINATOR(SwitchValueInst, TermInst, switch_value, None, DoesNotRelease)
-    TERMINATOR(SwitchEnumInst, TermInst, switch_enum, None, DoesNotRelease)
-    TERMINATOR(SwitchEnumAddrInst, TermInst, switch_enum_addr, MayRead, DoesNotRelease)
-    TERMINATOR(DynamicMethodBranchInst, TermInst, dynamic_method_br, None, DoesNotRelease)
-    TERMINATOR(CheckedCastBranchInst, TermInst, checked_cast_br, None, DoesNotRelease)
-    TERMINATOR(CheckedCastAddrBranchInst, TermInst, checked_cast_addr_br, MayHaveSideEffects,
-               MayRelease)
-    TERMINATOR(CheckedCastValueBranchInst, TermInst, checked_cast_value_br, None, DoesNotRelease)
-    VALUE_RANGE(TermInst, UnreachableInst, CheckedCastValueBranchInst)
+// FIXME: Is MayHaveSideEffects appropriate?
+NON_VALUE_INST(FixLifetimeInst, fix_lifetime,
+               SILInstruction, MayHaveSideEffects, DoesNotRelease)
 
-  VALUE_RANGE(SILInstruction, AllocStackInst, CheckedCastValueBranchInst)
+NON_VALUE_INST(DestroyValueInst, destroy_value,
+               SILInstruction, MayHaveSideEffects, MayRelease)
+NON_VALUE_INST(EndBorrowInst, end_borrow,
+               SILInstruction, MayHaveSideEffects, DoesNotRelease)
+NON_VALUE_INST(EndBorrowArgumentInst, end_borrow_argument,
+               SILInstruction, MayHaveSideEffects, DoesNotRelease)
+NON_VALUE_INST(EndAccessInst, end_access,
+               SILInstruction, MayHaveSideEffects, DoesNotRelease)
+NON_VALUE_INST(BeginUnpairedAccessInst, begin_unpaired_access,
+               SILInstruction, MayHaveSideEffects, DoesNotRelease)
+NON_VALUE_INST(EndUnpairedAccessInst, end_unpaired_access,
+               SILInstruction, MayHaveSideEffects, DoesNotRelease)
+NON_VALUE_INST(StoreInst, store,
+               SILInstruction, MayWrite, DoesNotRelease)
+NON_VALUE_INST(AssignInst, assign,
+               SILInstruction, MayWrite, DoesNotRelease)
+NON_VALUE_INST(MarkFunctionEscapeInst, mark_function_escape,
+               SILInstruction, None, DoesNotRelease)
+NON_VALUE_INST(DebugValueInst, debug_value,
+               SILInstruction, None, DoesNotRelease)
+NON_VALUE_INST(DebugValueAddrInst, debug_value_addr,
+               SILInstruction, None, DoesNotRelease)
+NON_VALUE_INST(StoreUnownedInst, store_unowned,
+               SILInstruction, MayWrite, DoesNotRelease)
+NON_VALUE_INST(StoreWeakInst, store_weak,
+               SILInstruction, MayWrite, DoesNotRelease)
+NON_VALUE_INST(CopyAddrInst, copy_addr,
+               SILInstruction, MayHaveSideEffects, MayRelease)
+NON_VALUE_INST(DestroyAddrInst, destroy_addr,
+               SILInstruction, MayHaveSideEffects, MayRelease)
+NON_VALUE_INST(EndLifetimeInst, end_lifetime,
+               SILInstruction, MayHaveSideEffects, MayRelease)
+NON_VALUE_INST(InjectEnumAddrInst, inject_enum_addr,
+               SILInstruction, MayWrite, DoesNotRelease)
+NON_VALUE_INST(DeinitExistentialAddrInst, deinit_existential_addr,
+               SILInstruction, MayHaveSideEffects, DoesNotRelease)
+NON_VALUE_INST(DeinitExistentialValueInst, deinit_existential_value,
+               SILInstruction, MayHaveSideEffects, DoesNotRelease)
+NON_VALUE_INST(UnconditionalCheckedCastAddrInst, unconditional_checked_cast_addr,
+               SILInstruction, MayHaveSideEffects, MayRelease)
+NON_VALUE_INST(UncheckedRefCastAddrInst, unchecked_ref_cast_addr,
+               SILInstruction, MayHaveSideEffects, DoesNotRelease)
+NON_VALUE_INST(AllocGlobalInst, alloc_global,
+               SILInstruction, MayHaveSideEffects, DoesNotRelease)
 
+// Runtime failure
+// FIXME: Special MemBehavior for runtime failure?
+NON_VALUE_INST(CondFailInst, cond_fail,
+               SILInstruction, MayHaveSideEffects, DoesNotRelease)
+
+NODE_RANGE(SILInstruction, AllocStackInst, CondFailInst)
+NODE_RANGE(SILNode, SILPHIArgument, CondFailInst)
+
+#undef SINGLE_VALUE_INST_RANGE
+#undef INST_RANGE
 #undef VALUE_RANGE
+#undef NODE_RANGE
+#undef ABSTRACT_SINGLE_VALUE_INST
+#undef ABSTRACT_INST
 #undef ABSTRACT_VALUE
+#undef ABSTRACT_NODE
+#undef ABSTRACT_VALUE_AND_INST
 #undef TERMINATOR
+#undef NON_VALUE_INST
+#undef SINGLE_VALUE_INST
+#undef FULL_INST
 #undef INST
 #undef ARGUMENT
 #undef VALUE
+#undef NODE
diff --git a/include/swift/SIL/SILOpenedArchetypesTracker.h b/include/swift/SIL/SILOpenedArchetypesTracker.h
index f8046fd..508eb36 100644
--- a/include/swift/SIL/SILOpenedArchetypesTracker.h
+++ b/include/swift/SIL/SILOpenedArchetypesTracker.h
@@ -31,7 +31,8 @@
 /// The intended clients of this class are SILGen, SIL deserializers, etc.
 class SILOpenedArchetypesTracker : public DeleteNotificationHandler {
 public:
-  typedef llvm::DenseMap<ArchetypeType *, SILValue> OpenedArchetypeDefsMap;
+  using OpenedArchetypeDefsMap =
+    llvm::DenseMap<ArchetypeType*, SingleValueInstruction*>;
 
   SILOpenedArchetypesTracker(SILOpenedArchetypesTracker &Tracker)
       : SILOpenedArchetypesTracker(Tracker.F, Tracker) {}
@@ -57,19 +58,13 @@
   }
 
   // Register a definition of a given opened archetype.
-  void addOpenedArchetypeDef(CanArchetypeType archetype, SILValue Def);
+  void addOpenedArchetypeDef(CanArchetypeType archetype,
+                             SingleValueInstruction *def);
 
-  void removeOpenedArchetypeDef(CanArchetypeType archetype, SILValue Def) {
-    auto FoundDef = getOpenedArchetypeDef(archetype);
-    assert(FoundDef &&
-           "Opened archetype definition is not registered in SILFunction");
-    if (FoundDef == Def)
-      OpenedArchetypeDefs.erase(archetype);
-  }
-
-  // Return the SILValue defining a given archetype.
-  // If the defining value is not known, return an empty SILValue.
-  SILValue getOpenedArchetypeDef(CanArchetypeType archetype) const {
+  // Return the SILInstruciton* defining a given archetype.
+  // If the defining value is not known, return a null instruction.
+  SingleValueInstruction *
+  getOpenedArchetypeDef(CanArchetypeType archetype) const {
     return OpenedArchetypeDefs.lookup(archetype);
   }
 
@@ -107,7 +102,7 @@
   bool needsNotifications() { return true; }
 
   // Handle notifications about removals of instructions.
-  void handleDeleteNotification(swift::ValueBase *Value);
+  void handleDeleteNotification(SILNode *node);
 
   // Dump the contents.
   void dump() const;
diff --git a/include/swift/SIL/SILPrintContext.h b/include/swift/SIL/SILPrintContext.h
index 69ff784..1ac3c3e 100644
--- a/include/swift/SIL/SILPrintContext.h
+++ b/include/swift/SIL/SILPrintContext.h
@@ -50,7 +50,7 @@
   //
   const void *ContextFunctionOrBlock = nullptr;
   llvm::DenseMap<const SILBasicBlock *, unsigned> BlocksToIDMap;
-  llvm::DenseMap<const ValueBase *, unsigned> ValueToIDMap;
+  llvm::DenseMap<const SILNode *, unsigned> ValueToIDMap;
 
   llvm::raw_ostream &OutStream;
 
@@ -96,7 +96,7 @@
 
   SILPrintContext::ID getID(const SILBasicBlock *Block);
 
-  SILPrintContext::ID getID(SILValue V);
+  SILPrintContext::ID getID(const SILNode *node);
 
   /// Returns true if the \p Scope has and ID assigned.
   bool hasScopeID(const SILDebugScope *Scope) const {
diff --git a/include/swift/SIL/SILSuccessor.h b/include/swift/SIL/SILSuccessor.h
index 2f63aa9..6ed9390 100644
--- a/include/swift/SIL/SILSuccessor.h
+++ b/include/swift/SIL/SILSuccessor.h
@@ -13,6 +13,7 @@
 #ifndef SWIFT_SIL_SILSUCCESSOR_H
 #define SWIFT_SIL_SILSUCCESSOR_H
 
+#include "swift/Basic/ProfileCounter.h"
 #include <cassert>
 #include <cstddef>
 #include <iterator>
@@ -40,6 +41,9 @@
   /// If non-null, this is the BasicBlock that the terminator branches to.
   SILBasicBlock *SuccessorBlock = nullptr;
 
+  /// If hasValue, this is the profiled execution count of the edge
+  ProfileCounter Count;
+
   /// A pointer to the SILSuccessor that represents the previous SILSuccessor in the
   /// predecessor list for SuccessorBlock.
   ///
@@ -53,14 +57,14 @@
   SILSuccessor *Next = nullptr;
 
 public:
-  SILSuccessor() {}
+  SILSuccessor(ProfileCounter Count = ProfileCounter()) : Count(Count) {}
 
-  SILSuccessor(TermInst *CI)
-    : ContainingInst(CI) {
-  }
+  SILSuccessor(TermInst *CI, ProfileCounter Count = ProfileCounter())
+      : ContainingInst(CI), Count(Count) {}
 
-  SILSuccessor(TermInst *CI, SILBasicBlock *Succ)
-    : ContainingInst(CI) {
+  SILSuccessor(TermInst *CI, SILBasicBlock *Succ,
+               ProfileCounter Count = ProfileCounter())
+      : ContainingInst(CI), Count(Count) {
     *this = Succ;
   }
   
@@ -72,7 +76,9 @@
   
   operator SILBasicBlock*() const { return SuccessorBlock; }
   SILBasicBlock *getBB() const { return SuccessorBlock; }
-  
+
+  ProfileCounter getCount() const { return Count; }
+
   // Do not copy or move these.
   SILSuccessor(const SILSuccessor &) = delete;
   SILSuccessor(SILSuccessor &&) = delete;
diff --git a/include/swift/SIL/SILUndef.h b/include/swift/SIL/SILUndef.h
index a62fe12..b1bd8c5 100644
--- a/include/swift/SIL/SILUndef.h
+++ b/include/swift/SIL/SILUndef.h
@@ -17,7 +17,9 @@
 #include "swift/SIL/SILValue.h"
 
 namespace swift {
-  class SILModule;
+class SILArgument;
+class SILInstruction;
+class SILModule;
 
 class SILUndef : public ValueBase {
   void operator=(const SILArgument &) = delete;
@@ -32,8 +34,10 @@
   template<class OwnerTy>
   static SILUndef *getSentinelValue(SILType Ty, OwnerTy Owner) { return new (*Owner) SILUndef(Ty); }
 
-  static bool classof(const ValueBase *V) {
-    return V->getKind() == ValueKind::SILUndef;
+  static bool classof(const SILArgument *) = delete;
+  static bool classof(const SILInstruction *) = delete;
+  static bool classof(const SILNode *node) {
+    return node->getKind() == SILNodeKind::SILUndef;
   }
 };
 
diff --git a/include/swift/SIL/SILValue.h b/include/swift/SIL/SILValue.h
index 4de46f2..ce81ab5 100644
--- a/include/swift/SIL/SILValue.h
+++ b/include/swift/SIL/SILValue.h
@@ -18,6 +18,7 @@
 #define SWIFT_SIL_SILVALUE_H
 
 #include "swift/Basic/Range.h"
+#include "swift/SIL/SILNode.h"
 #include "swift/SIL/SILType.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/Hashing.h"
@@ -31,19 +32,20 @@
 class PostOrderFunctionInfo;
 class ReversePostOrderInfo;
 class Operand;
-class SILBasicBlock;
-class SILFunction;
 class SILInstruction;
 class SILLocation;
-class SILModule;
 class DeadEndBlocks;
 class ValueBaseUseIterator;
 class ValueUseIterator;
 
-enum class ValueKind {
-#define VALUE(Id, Parent) Id,
-#define VALUE_RANGE(Id, FirstId, LastId)                                       \
-  First_##Id = FirstId, Last_##Id = LastId,
+/// An enumeration which contains values for all the concrete ValueBase
+/// subclasses.
+enum class ValueKind : std::underlying_type<SILNodeKind>::type {
+#define VALUE(ID, PARENT) \
+  ID = unsigned(SILNodeKind::ID),
+#define VALUE_RANGE(ID, FIRST, LAST) \
+  First_##ID = unsigned(SILNodeKind::First_##ID), \
+  Last_##ID = unsigned(SILNodeKind::Last_##ID),
 #include "swift/SIL/SILNodes.def"
 };
 
@@ -132,31 +134,26 @@
 
 /// This is the base class of the SIL value hierarchy, which represents a
 /// runtime computed value. Things like SILInstruction derive from this.
-class alignas(8) ValueBase : public SILAllocated<ValueBase> {
+class ValueBase : public SILNode, public SILAllocated<ValueBase> {
   SILType Type;
   Operand *FirstUse = nullptr;
   friend class Operand;
 
-  const ValueKind Kind;
-
   ValueBase(const ValueBase &) = delete;
   ValueBase &operator=(const ValueBase &) = delete;
 
 protected:
-  ValueBase(ValueKind Kind, SILType Ty)
-    : Type(Ty), Kind(Kind) {}
+  ValueBase(ValueKind kind, SILType type)
+    : SILNode(SILNodeKind(kind), SILNodeStorageLocation::Value),
+      Type(type) {}
 
 public:
   ~ValueBase() {
     assert(use_empty() && "Cannot destroy a value that still has uses!");
   }
 
-
-  ValueKind getKind() const { return Kind; }
-
-  /// True if the "value" is actually a value that can be used by other
-  /// instructions.
-  bool hasValue() const { return !Type.isNull(); }
+  LLVM_ATTRIBUTE_ALWAYS_INLINE
+  ValueKind getKind() const { return ValueKind(SILNode::getKind()); }
 
   SILType getType() const {
     return Type;
@@ -173,6 +170,9 @@
   /// same type as the result of this instruction.
   void replaceAllUsesWithUndef();
 
+  /// Is this value a direct result of the given instruction?
+  bool isResultOf(SILInstruction *I) const;
+
   /// Returns true if this value has no uses.
   /// To ignore debug-info instructions use swift::onlyHaveDebugUses instead
   /// (see comment in DebugUtils.h).
@@ -201,37 +201,32 @@
   template <class T>
   inline T *getSingleUserOfType();
 
-  /// Pretty-print the value.
-  void dump() const;
-  void print(raw_ostream &OS) const;
+  /// Return the instruction that defines this value, or null if it is
+  /// not defined by an instruction.
+  const SILInstruction *getDefiningInstruction() const {
+    return const_cast<ValueBase*>(this)->getDefiningInstruction();
+  }
+  SILInstruction *getDefiningInstruction();
 
-  /// Pretty-print the value in context, preceded by its operands (if the
-  /// value represents the result of an instruction) and followed by its
-  /// users.
-  void dumpInContext() const;
-  void printInContext(raw_ostream &OS) const;
+  struct DefiningInstructionResult {
+    SILInstruction *Instruction;
+    size_t ResultIndex;
+  };
 
+  /// Return the instruction that defines this value and the appropriate
+  /// result index, or None if it is not defined by an instruction.
+  Optional<DefiningInstructionResult> getDefiningInstructionResult();
+
+  static bool classof(const SILNode *N) {
+    return N->getKind() >= SILNodeKind::First_ValueBase &&
+           N->getKind() <= SILNodeKind::Last_ValueBase;
+  }
   static bool classof(const ValueBase *V) { return true; }
 
-  /// If this is a SILArgument or a SILInstruction get its parent basic block,
-  /// otherwise return null.
-  SILBasicBlock *getParentBlock() const;
-
-  /// If this is a SILArgument or a SILInstruction get its parent function,
-  /// otherwise return null.
-  SILFunction *getFunction() const;
-
-  /// If this is a SILArgument or a SILInstruction get its parent module,
-  /// otherwise return null.
-  SILModule *getModule() const;
+  /// This is supportable but usually suggests a logic mistake.
+  static bool classof(const SILInstruction *) = delete;
 };
 
-inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
-                                     const ValueBase &V) {
-  V.print(OS);
-  return OS;
-}
-
 } // end namespace swift
 
 namespace llvm {
@@ -783,12 +778,6 @@
   return OS;
 }
 
-/// Map a SILValue mnemonic name to its ValueKind.
-ValueKind getSILValueKind(StringRef Name);
-
-/// Map ValueKind to a corresponding mnemonic name.
-StringRef getSILValueName(ValueKind Kind);
-
 } // end namespace swift
 
 
diff --git a/include/swift/SIL/SILVisitor.h b/include/swift/SIL/SILVisitor.h
index 439553c..86554bb 100644
--- a/include/swift/SIL/SILVisitor.h
+++ b/include/swift/SIL/SILVisitor.h
@@ -24,80 +24,136 @@
 
 namespace swift {
 
-/// SILVisitor - This is a simple visitor class for Swift SIL nodes, allowing
-/// clients to walk over entire SIL functions, blocks, or instructions.
-template<typename ImplClass, typename ValueRetTy = void>
-class SILVisitor {
+/// A helper class for all the SIL visitors.
+/// You probably shouldn't use this directly.
+template <typename ImplClass, typename RetTy = void, typename... ArgTys>
+class SILVisitorBase {
 public:
   ImplClass &asImpl() { return static_cast<ImplClass &>(*this); }
 
-  // Perform any required pre-processing before visiting.
-  // Sub-classes can override it to provide their custom
-  // pre-processing steps.
-  void beforeVisit(ValueBase *V) {
+  void visitSILBasicBlock(SILBasicBlock *BB, ArgTys... args) {
+    asImpl().visitBasicBlockArguments(BB, args...);
+
+    for (auto &I : *BB)
+      asImpl().visit(&I, args...);
+  }
+  void visitSILBasicBlock(SILBasicBlock &BB, ArgTys... args) {
+    asImpl().visitSILBasicBlock(&BB, args...);
   }
 
-  ValueRetTy visit(ValueBase *V) {
-    asImpl().beforeVisit(V);
+  void visitSILFunction(SILFunction *F, ArgTys... args) {
+    for (auto &BB : *F)
+      asImpl().visitSILBasicBlock(&BB, args...);
+  }
+  void visitSILFunction(SILFunction &F, ArgTys... args) {
+    asImpl().visitSILFunction(&F, args...);
+  }
+};
 
+/// SILValueVisitor - This is a simple visitor class for Swift SIL nodes,
+/// allowing clients to walk over entire SIL functions, blocks, or instructions.
+template <typename ImplClass, typename RetTy = void, typename... ArgTys>
+class SILValueVisitor
+       : public SILVisitorBase<ImplClass, RetTy, ArgTys...> {
+  using super = SILVisitorBase<ImplClass, RetTy, ArgTys...>;
+public:
+  using super::asImpl;
+
+  RetTy visit(ValueBase *V, ArgTys... args) {
     switch (V->getKind()) {
 #define VALUE(CLASS, PARENT)                                \
   case ValueKind::CLASS:                                    \
-    return asImpl().visit##CLASS(static_cast<CLASS*>(V));
+    return asImpl().visit##CLASS(static_cast<CLASS*>(V),    \
+                                 std::forward<ArgTys>(args)...);
 #include "swift/SIL/SILNodes.def"
     }
     llvm_unreachable("Not reachable, all cases handled");
   }
 
   // Define default dispatcher implementations chain to parent nodes.
-#define VALUE(CLASS, PARENT)                                    \
-  ValueRetTy visit##CLASS(CLASS *I) {                           \
-    return asImpl().visit##PARENT(I);                           \
+#define VALUE(CLASS, PARENT)                                         \
+  RetTy visit##CLASS(CLASS *I, ArgTys... args) {                     \
+    return asImpl().visit##PARENT(I, std::forward<ArgTys>(args)...); \
   }
 #define ABSTRACT_VALUE(CLASS, PARENT) VALUE(CLASS, PARENT)
 #include "swift/SIL/SILNodes.def"
-
-  void visitSILBasicBlock(SILBasicBlock *BB) {
-    asImpl().visitBasicBlockArguments(BB);
-      
-    for (auto &I : *BB)
-      asImpl().visit(&I);
-  }
-  void visitSILBasicBlock(SILBasicBlock &BB) {
-    asImpl().visitSILBasicBlock(&BB);
-  }
-
-  void visitBasicBlockArguments(SILBasicBlock *BB) {
-    for (auto argI = BB->args_begin(), argEnd = BB->args_end(); argI != argEnd;
-         ++argI)
-      asImpl().visit(*argI);
-  }
-
-  void visitSILFunction(SILFunction *F) {
-    for (auto &BB : *F)
-      asImpl().visitSILBasicBlock(&BB);
-  }
-  void visitSILFunction(SILFunction &F) {
-    asImpl().visitSILFunction(&F);
-  }
 };
 
-/// A simple convenience class for a visitor that should only visit
-/// SIL instructions.
-template<typename ImplClass, typename ValueRetTy = void>
-class SILInstructionVisitor : public SILVisitor<ImplClass, ValueRetTy> {
+/// A visitor that should only visit SIL instructions.
+template <typename ImplClass, typename RetTy = void, typename... ArgTys>
+class SILInstructionVisitor
+       : public SILVisitorBase<ImplClass, RetTy, ArgTys...> {
+  using super = SILVisitorBase<ImplClass, RetTy, ArgTys...>;
 public:
-  void visitBasicBlockArguments(SILBasicBlock *BB) {}
+  using super::asImpl;
 
-  ValueRetTy visitSILArgument(SILArgument *A) {
-    llvm_unreachable("should only be visiting instructions");
-  }
-  ValueRetTy visitSILUndef(SILUndef *U) {
-    llvm_unreachable("should only be visiting instructions");
+  // Perform any required pre-processing before visiting.
+  // Sub-classes can override it to provide their custom
+  // pre-processing steps.
+  void beforeVisit(SILInstruction *inst) {}
+
+  RetTy visit(SILInstruction *inst, ArgTys... args) {
+    asImpl().beforeVisit(inst, args...);
+
+    switch (inst->getKind()) {
+#define INST(CLASS, PARENT)                                             \
+    case SILInstructionKind::CLASS:                                     \
+      return asImpl().visit##CLASS(static_cast<CLASS*>(inst),           \
+                                   std::forward<ArgTys>(args)...);
+#include "swift/SIL/SILNodes.def"
+    }
+    llvm_unreachable("Not reachable, all cases handled");
   }
 
-  ValueRetTy visit(SILInstruction *I) {
-    return SILVisitor<ImplClass, ValueRetTy>::visit(I);
+  // Define default dispatcher implementations chain to parent nodes.
+#define INST(CLASS, PARENT)                                             \
+  RetTy visit##CLASS(CLASS *inst, ArgTys... args) {                     \
+    return asImpl().visit##PARENT(inst, std::forward<ArgTys>(args)...); \
+  }
+#define ABSTRACT_INST(CLASS, PARENT) INST(CLASS, PARENT)
+#include "swift/SIL/SILNodes.def"
+
+  void visitBasicBlockArguments(SILBasicBlock *BB, ArgTys... args) {}
+};
+
+/// A visitor that should visit all SIL nodes.
+template <typename ImplClass, typename RetTy = void, typename... ArgTys>
+class SILNodeVisitor
+       : public SILVisitorBase<ImplClass, RetTy, ArgTys...> {
+  using super = SILVisitorBase<ImplClass, RetTy, ArgTys...>;
+public:
+  using super::asImpl;
+
+  // Perform any required pre-processing before visiting.
+  // Sub-classes can override it to provide their custom
+  // pre-processing steps.
+  void beforeVisit(SILNode *I, ArgTys... args) {}
+
+  RetTy visit(SILNode *node, ArgTys... args) {
+    asImpl().beforeVisit(node, args...);
+
+    switch (node->getKind()) {
+#define NODE(CLASS, PARENT)                                             \
+    case SILNodeKind::CLASS:                                            \
+      return asImpl().visit##CLASS(cast<CLASS>(node),                   \
+                                   std::forward<ArgTys>(args)...);
+#include "swift/SIL/SILNodes.def"
+    }
+    llvm_unreachable("Not reachable, all cases handled");
+  }
+
+  // Define default dispatcher implementations chain to parent nodes.
+#define NODE(CLASS, PARENT)                                             \
+  RetTy visit##CLASS(CLASS *node, ArgTys... args) {                     \
+    return asImpl().visit##PARENT(node, std::forward<ArgTys>(args)...); \
+  }
+#define ABSTRACT_NODE(CLASS, PARENT) NODE(CLASS, PARENT)
+#include "swift/SIL/SILNodes.def"
+
+  void visitBasicBlockArguments(SILBasicBlock *BB, ArgTys... args) {
+    for (auto argI = BB->args_begin(), argEnd = BB->args_end(); argI != argEnd;
+         ++argI)
+      asImpl().visit(*argI, args...);
   }
 };
 
diff --git a/include/swift/SIL/TypeSubstCloner.h b/include/swift/SIL/TypeSubstCloner.h
index 6fc7156..872f3c7 100644
--- a/include/swift/SIL/TypeSubstCloner.h
+++ b/include/swift/SIL/TypeSubstCloner.h
@@ -31,7 +31,7 @@
 /// TypeSubstCloner - a utility class for cloning code while remapping types.
 template<typename ImplClass>
 class TypeSubstCloner : public SILClonerWithScopes<ImplClass> {
-  friend class SILVisitor<ImplClass>;
+  friend class SILInstructionVisitor<ImplClass>;
   friend class SILCloner<ImplClass>;
 
   typedef SILClonerWithScopes<ImplClass> super;
@@ -185,7 +185,7 @@
   }
 
   void visitApplyInst(ApplyInst *Inst) {
-    ApplySiteCloningHelper Helper(ApplySite::isa(Inst), *this);
+    ApplySiteCloningHelper Helper(ApplySite(Inst), *this);
     ApplyInst *N =
         getBuilder().createApply(getOpLocation(Inst->getLoc()),
                                  Helper.getCallee(), Helper.getSubstitutions(),
@@ -196,7 +196,7 @@
   }
 
   void visitTryApplyInst(TryApplyInst *Inst) {
-    ApplySiteCloningHelper Helper(ApplySite::isa(Inst), *this);
+    ApplySiteCloningHelper Helper(ApplySite(Inst), *this);
     TryApplyInst *N = getBuilder().createTryApply(
         getOpLocation(Inst->getLoc()), Helper.getCallee(),
         Helper.getSubstitutions(), Helper.getArguments(),
@@ -208,7 +208,7 @@
   }
 
   void visitPartialApplyInst(PartialApplyInst *Inst) {
-    ApplySiteCloningHelper Helper(ApplySite::isa(Inst), *this);
+    ApplySiteCloningHelper Helper(ApplySite(Inst), *this);
     auto ParamConvention =
         Inst->getType().getAs<SILFunctionType>()->getCalleeConvention();
     PartialApplyInst *N = getBuilder().createPartialApply(
@@ -232,14 +232,15 @@
     SILBuilderWithPostProcess<TypeSubstCloner, 16> B(this, inst);
     B.setCurrentDebugScope(super::getOpScope(inst->getDebugScope()));
 
+    auto TrueCount = inst->getTrueBBCount();
+    auto FalseCount = inst->getFalseBBCount();
+
     // Try to use the scalar cast instruction.
     if (canUseScalarCheckedCastInstructions(B.getModule(),
                                             sourceType, targetType)) {
-      emitIndirectConditionalCastWithScalar(B, SwiftMod, loc,
-                                            inst->getConsumptionKind(),
-                                            src, sourceType,
-                                            dest, targetType,
-                                            succBB, failBB);
+      emitIndirectConditionalCastWithScalar(
+          B, SwiftMod, loc, inst->getConsumptionKind(), src, sourceType, dest,
+          targetType, succBB, failBB, TrueCount, FalseCount);
       return;
     }
 
diff --git a/include/swift/SILOptimizer/Analysis/ARCAnalysis.h b/include/swift/SILOptimizer/Analysis/ARCAnalysis.h
index 9d8c067..5cee6ef 100644
--- a/include/swift/SILOptimizer/Analysis/ARCAnalysis.h
+++ b/include/swift/SILOptimizer/Analysis/ARCAnalysis.h
@@ -376,12 +376,12 @@
 /// Gets the (GuaranteedValue, Token) tuple from a call to "unsafeGuaranteed"
 /// if the tuple elements are identified by a single tuple_extract use.
 /// Otherwise, returns a (nullptr, nullptr) tuple.
-std::pair<SILInstruction *, SILInstruction *>
+std::pair<SingleValueInstruction *, SingleValueInstruction *>
 getSingleUnsafeGuaranteedValueResult(BuiltinInst *UnsafeGuaranteedInst);
 
 /// Get the single builtin "unsafeGuaranteedEnd" user of a builtin
 /// "unsafeGuaranteed"'s token.
-BuiltinInst *getUnsafeGuaranteedEndUser(SILInstruction *UnsafeGuaranteedToken);
+BuiltinInst *getUnsafeGuaranteedEndUser(SILValue UnsafeGuaranteedToken);
 
 /// Walk forwards from an unsafeGuaranteedEnd builtin instruction looking for a
 /// release on the reference returned by the matching unsafeGuaranteed builtin
diff --git a/include/swift/SILOptimizer/Analysis/AliasAnalysis.h b/include/swift/SILOptimizer/Analysis/AliasAnalysis.h
index 2b6c7fa..c74f03c 100644
--- a/include/swift/SILOptimizer/Analysis/AliasAnalysis.h
+++ b/include/swift/SILOptimizer/Analysis/AliasAnalysis.h
@@ -125,7 +125,7 @@
   /// NOTE: we do not use the same ValueEnumerator for the alias cache, 
   /// as when either cache is cleared, we can not clear the ValueEnumerator
   /// because doing so could give rise to collisions in the other cache.
-  ValueEnumerator<ValueBase*> MemoryBehaviorValueBaseToIndex;
+  ValueEnumerator<SILNode*> MemoryBehaviorNodeToIndex;
 
   AliasResult aliasAddressProjection(SILValue V1, SILValue V2,
                                      SILValue O1, SILValue O2);
@@ -138,12 +138,17 @@
   /// Returns True if memory of type \p T1 and \p T2 may alias.
   bool typesMayAlias(SILType T1, SILType T2);
 
-  virtual void handleDeleteNotification(ValueBase *I) override {
-    // The pointer I is going away.  We can't scan the whole cache and remove
-    // all of the occurrences of the pointer. Instead we remove the pointer
-    // from the cache that translates pointers to indices.
-    AliasValueBaseToIndex.invalidateValue(I);
-    MemoryBehaviorValueBaseToIndex.invalidateValue(I);
+  virtual void handleDeleteNotification(SILNode *node) override {
+    assert(node->isCanonicalSILNodeInObject());
+
+    // The pointer 'node' is going away.  We can't scan the whole cache
+    // and remove all of the occurrences of the pointer. Instead we remove
+    // the pointer from the cache that translates pointers to indices.
+    auto value = dyn_cast<ValueBase>(node);
+    if (!value) return;
+
+    AliasValueBaseToIndex.invalidateValue(value);
+    MemoryBehaviorNodeToIndex.invalidateValue(node);
   }
 
   virtual bool needsNotifications() override { return true; }
@@ -261,7 +266,8 @@
   AliasKeyTy toAliasKey(SILValue V1, SILValue V2, SILType Type1, SILType Type2);
 
   /// Encodes the memory behavior query as a MemBehaviorKeyTy.
-  MemBehaviorKeyTy toMemoryBehaviorKey(SILValue V1, SILValue V2, RetainObserveKind K);
+  MemBehaviorKeyTy toMemoryBehaviorKey(SILInstruction *V1, SILValue V2,
+                                       RetainObserveKind K);
 
   virtual void invalidate() override {
     AliasCache.clear();
diff --git a/include/swift/SILOptimizer/Analysis/ArraySemantic.h b/include/swift/SILOptimizer/Analysis/ArraySemantic.h
index f4db8ae..42a96c0 100644
--- a/include/swift/SILOptimizer/Analysis/ArraySemantic.h
+++ b/include/swift/SILOptimizer/Analysis/ArraySemantic.h
@@ -49,17 +49,31 @@
 class ArraySemanticsCall {
   ApplyInst *SemanticsCall;
 
+  void initialize(ApplyInst *apply, StringRef semanticString,
+                  bool matchPartialName);
+
 public:
+  /// Match calls with any array semantic.
+  template <class NodeTy>
+  ArraySemanticsCall(NodeTy node)
+    : ArraySemanticsCall(node, "array.", /*allow partial*/ true) {}
+
+  /// Match calls with a specific array semantic.
+  template <class NodeTy>
+  ArraySemanticsCall(NodeTy node, StringRef semanticName)
+    : ArraySemanticsCall(node, semanticName, /*allow partial*/ false) {}
+
   /// Match array semantic calls.
-  ArraySemanticsCall(ValueBase *V, StringRef SemanticStr,
+  ArraySemanticsCall(ApplyInst *apply, StringRef SemanticStr,
                      bool MatchPartialName);
 
-  /// Match any array semantics call.
-  ArraySemanticsCall(ValueBase *V) : ArraySemanticsCall(V, "array.", true) {}
+  /// Match array semantic calls.
+  ArraySemanticsCall(SILInstruction *I, StringRef semanticName,
+                     bool matchPartialName);
 
-  /// Match a specific array semantic call.
-  ArraySemanticsCall(ValueBase *V, StringRef SemanticStr)
-      : ArraySemanticsCall(V, SemanticStr, false) {}
+  /// Match array semantic calls.
+  ArraySemanticsCall(SILValue V, StringRef semanticName,
+                     bool matchPartialName);
 
   /// Can we hoist this call.
   bool canHoist(SILInstruction *To, DominanceInfo *DT) const;
@@ -156,6 +170,8 @@
   /// Get the semantics call as an ApplyInst.
   operator ApplyInst *() const { return SemanticsCall; }
 
+  SILValue getCallResult() const { return SemanticsCall; }
+
   /// Is this a semantics call.
   operator bool() const { return SemanticsCall != nullptr; }
 
diff --git a/include/swift/SILOptimizer/Analysis/EpilogueARCAnalysis.h b/include/swift/SILOptimizer/Analysis/EpilogueARCAnalysis.h
index 55aca7c..0c60732 100644
--- a/include/swift/SILOptimizer/Analysis/EpilogueARCAnalysis.h
+++ b/include/swift/SILOptimizer/Analysis/EpilogueARCAnalysis.h
@@ -224,7 +224,7 @@
   llvm::DenseMap<SILValue, ARCInstructions> EpilogueReleaseInstCache;
 
 public:
-  void handleDeleteNotification(ValueBase *V) {
+  void handleDeleteNotification(SILNode *node) {
     // Being conservative and clear everything for now.
     EpilogueRetainInstCache.clear();
     EpilogueReleaseInstCache.clear();
@@ -277,17 +277,17 @@
   EpilogueARCAnalysis(const EpilogueARCAnalysis &) = delete;
   EpilogueARCAnalysis &operator=(const EpilogueARCAnalysis &) = delete;
 
-  virtual void handleDeleteNotification(ValueBase *V) override {
+  virtual void handleDeleteNotification(SILNode *node) override {
     // If the parent function of this instruction was just turned into an
     // external declaration, bail. This happens during SILFunction destruction.
-    SILFunction *F = V->getFunction();
+    SILFunction *F = node->getFunction();
     if (F->isExternalDeclaration()) {
       return;
     }
 
     // If we do have an analysis, tell it to handle its delete notifications.
     if (auto A = maybeGet(F)) {
-      A.get()->handleDeleteNotification(V);
+      A.get()->handleDeleteNotification(node);
     }
   }
 
diff --git a/include/swift/SILOptimizer/Analysis/EscapeAnalysis.h b/include/swift/SILOptimizer/Analysis/EscapeAnalysis.h
index 11dd680..21549b3 100644
--- a/include/swift/SILOptimizer/Analysis/EscapeAnalysis.h
+++ b/include/swift/SILOptimizer/Analysis/EscapeAnalysis.h
@@ -378,10 +378,10 @@
     CGNode *ReturnNode = nullptr;
 
     /// The list of use points.
-    llvm::SmallVector<ValueBase *, 16> UsePointTable;
+    llvm::SmallVector<SILNode *, 16> UsePointTable;
 
     /// Mapping of use points to bit indices in CGNode::UsePoints.
-    llvm::DenseMap<ValueBase *, int> UsePoints;
+    llvm::DenseMap<SILNode *, int> UsePoints;
 
     /// The allocator for nodes.
     llvm::SpecificBumpPtrAllocator<CGNode> NodeAllocator;
@@ -486,14 +486,15 @@
     }
 
     /// Adds an argument/instruction in which the node's value is used.
-    int addUsePoint(CGNode *Node, ValueBase *V) {
+    int addUsePoint(CGNode *Node, SILNode *User) {
       if (Node->getEscapeState() >= EscapeState::Global)
         return -1;
 
+      User = User->getCanonicalSILNodeInObject();
       int Idx = (int)UsePoints.size();
-      assert(UsePoints.count(V) == 0 && "value is already a use-point");
-      UsePoints[V] = Idx;
-      UsePointTable.push_back(V);
+      assert(UsePoints.count(User) == 0 && "value is already a use-point");
+      UsePoints[User] = Idx;
+      UsePointTable.push_back(User);
       assert(UsePoints.size() == UsePointTable.size());
       Node->setUsePointBit(Idx);
       return Idx;
@@ -567,15 +568,15 @@
       return Node->UsePoints.count();
     }
 
-    /// Returns true if \p V is a use of \p Node, i.e. V may (indirectly)
-    /// somehow refer to the Node's value.
+    /// Returns true if \p UsePoint is a use of \p Node, i.e. UsePoint may
+    /// (indirectly) somehow refer to the Node's value.
     /// Use-points are only values which are relevant for lifeness computation,
     /// e.g. release or apply instructions.
-    bool isUsePoint(ValueBase *V, CGNode *Node);
+    bool isUsePoint(SILNode *UsePoint, CGNode *Node);
 
     /// Returns all use points of \p Node in \p UsePoints.
     void getUsePoints(CGNode *Node,
-                      llvm::SmallVectorImpl<ValueBase *> &UsePoints);
+                      llvm::SmallVectorImpl<SILNode *> &UsePoints);
 
     /// Computes the use point information.
     void computeUsePoints();
@@ -671,9 +672,9 @@
   /// See EscapeAnalysis::NodeType::Value.
   bool isPointer(ValueBase *V);
 
-  /// If V is a pointer, set it to global escaping.
-  void setEscapesGlobal(ConnectionGraph *ConGraph, ValueBase *V) {
-    if (CGNode *Node = ConGraph->getNode(V, this))
+  /// If \p pointer is a pointer, set it to global escaping.
+  void setEscapesGlobal(ConnectionGraph *ConGraph, ValueBase *pointer) {
+    if (CGNode *Node = ConGraph->getNode(pointer, this))
       ConGraph->setEscapesGlobal(Node);
   }
 
@@ -740,7 +741,7 @@
 
   /// Returns true if the value \p V can escape to the \p UsePoint, where
   /// \p UsePoint is either a release-instruction or a function call.
-  bool canEscapeToUsePoint(SILValue V, ValueBase *UsePoint,
+  bool canEscapeToUsePoint(SILValue V, SILNode *UsePoint,
                            ConnectionGraph *ConGraph);
 
   friend struct ::CGForDotView;
@@ -818,7 +819,7 @@
   /// Notify the analysis about changed witness or vtables.
   virtual void invalidateFunctionTables() override { }
 
-  virtual void handleDeleteNotification(ValueBase *I) override;
+  virtual void handleDeleteNotification(SILNode *N) override;
 
   virtual bool needsNotifications() override { return true; }
 
diff --git a/include/swift/SILOptimizer/Analysis/IVAnalysis.h b/include/swift/SILOptimizer/Analysis/IVAnalysis.h
index f72d93e..0ab7f82 100644
--- a/include/swift/SILOptimizer/Analysis/IVAnalysis.h
+++ b/include/swift/SILOptimizer/Analysis/IVAnalysis.h
@@ -25,7 +25,7 @@
 
 class IVInfo : public SCCVisitor<IVInfo> {
 public:
-  typedef llvm::SmallVectorImpl<ValueBase *> SCCType;
+  typedef llvm::SmallVectorImpl<SILNode *> SCCType;
   friend SCCVisitor;
 
 public:
diff --git a/include/swift/SILOptimizer/Analysis/RCIdentityAnalysis.h b/include/swift/SILOptimizer/Analysis/RCIdentityAnalysis.h
index c011957..595ee73 100644
--- a/include/swift/SILOptimizer/Analysis/RCIdentityAnalysis.h
+++ b/include/swift/SILOptimizer/Analysis/RCIdentityAnalysis.h
@@ -55,11 +55,16 @@
   /// unchecked_trivial_bit_cast.
   void getRCUsers(SILValue V, llvm::SmallVectorImpl<SILInstruction *> &Users);
 
-  void handleDeleteNotification(ValueBase *V) {
+  void handleDeleteNotification(SILNode *node) {
+    auto value = dyn_cast<ValueBase>(node);
+    if (!value)
+      return;
+
     // Check the cache. If we don't find it, there is nothing to do.
-    auto Iter = RCCache.find(SILValue(V));
+    auto Iter = RCCache.find(SILValue(value));
     if (Iter == RCCache.end())
       return;
+
     // Then erase Iter from the cache.
     RCCache.erase(Iter);
   }
@@ -84,14 +89,14 @@
   RCIdentityAnalysis(const RCIdentityAnalysis &) = delete;
   RCIdentityAnalysis &operator=(const RCIdentityAnalysis &) = delete;
 
-  virtual void handleDeleteNotification(ValueBase *V) override {
+  virtual void handleDeleteNotification(SILNode *node) override {
     // If the parent function of this instruction was just turned into an
     // external declaration, bail. This happens during SILFunction destruction.
-    SILFunction *F = V->getFunction();
+    SILFunction *F = node->getFunction();
     if (F->isExternalDeclaration()) {
       return;
     }
-    get(F)->handleDeleteNotification(V);
+    get(F)->handleDeleteNotification(node);
   }
 
   virtual bool needsNotifications() override { return true; }
diff --git a/include/swift/SILOptimizer/Utils/Local.h b/include/swift/SILOptimizer/Utils/Local.h
index 817b505..267f38e 100644
--- a/include/swift/SILOptimizer/Utils/Local.h
+++ b/include/swift/SILOptimizer/Utils/Local.h
@@ -102,7 +102,7 @@
 /// value itself)
 void eraseUsesOfValue(SILValue V);
 
-FullApplySite findApplyFromDevirtualizedResult(SILInstruction *I);
+FullApplySite findApplyFromDevirtualizedResult(SILValue value);
 
 /// Check that this is a partial apply of a reabstraction thunk and return the
 /// argument of the partial apply if it is.
@@ -158,7 +158,7 @@
 
 /// Tries to optimize a given apply instruction if it is a concatenation of
 /// string literals. Returns a new instruction if optimization was possible.
-SILInstruction *tryToConcatenateStrings(ApplyInst *AI, SILBuilder &B);
+SingleValueInstruction *tryToConcatenateStrings(ApplyInst *AI, SILBuilder &B);
 
 /// Tries to perform jump-threading on all checked_cast_br instruction in
 /// function \p Fn.
@@ -193,7 +193,7 @@
 ///
 /// In the future this should be extended to be less conservative with users.
 bool
-tryDeleteDeadClosure(SILInstruction *Closure,
+tryDeleteDeadClosure(SingleValueInstruction *Closure,
                      InstModCallbacks Callbacks = InstModCallbacks());
 
 /// Given a SILValue argument to a partial apply \p Arg and the associated
@@ -227,8 +227,10 @@
 
   /// Constructor for the value \p Def considering all the value's uses.
   ValueLifetimeAnalysis(SILInstruction *Def) : DefValue(Def) {
-    for (Operand *Op : Def->getUses()) {
-      UserSet.insert(Op->getUser());
+    for (auto result : Def->getResults()) {
+      for (Operand *op : result->getUses()) {
+        UserSet.insert(op->getUser());
+      }
     }
     propagateLiveness();
   }
@@ -268,7 +270,7 @@
 
   /// Returns true if the value is alive at the begin of block \p BB.
   bool isAliveAtBeginOfBlock(SILBasicBlock *BB) {
-    return LiveBlocks.count(BB) && BB != DefValue->getParentBlock();
+    return LiveBlocks.count(BB) && BB != DefValue->getParent();
   }
 
   /// For debug dumping.
@@ -295,7 +297,7 @@
 
 /// Base class for BB cloners.
 class BaseThreadingCloner : public SILClonerWithScopes<BaseThreadingCloner> {
-  friend class SILVisitor<BaseThreadingCloner>;
+  friend class SILInstructionVisitor<BaseThreadingCloner>;
   friend class SILCloner<BaseThreadingCloner>;
 
   protected:
@@ -321,7 +323,7 @@
 
   SILValue remapValue(SILValue Value) {
     // If this is a use of an instruction in another block, then just use it.
-    if (auto SI = dyn_cast<SILInstruction>(Value)) {
+    if (auto SI = Value->getDefiningInstruction()) {
       if (SI->getParent() != FromBB)
         return Value;
     } else if (auto BBArg = dyn_cast<SILArgument>(Value)) {
@@ -340,8 +342,13 @@
     SILCloner<BaseThreadingCloner>::postProcess(Orig, Cloned);
     // A terminator defines no values. Keeping terminators in the AvailVals list
     // is problematic because terminators get replaced during SSA update.
-    if (!isa<TermInst>(Orig))
-      AvailVals.push_back(std::make_pair(Orig, SILValue(Cloned)));
+    auto results = Orig->getResults();
+    assert(results.size() == Cloned->getResults().size());
+    if (!results.empty()) {
+      auto clonedResults = Cloned->getResults();
+      for (size_t i = 0, e = results.size(); i != e; ++i)
+        AvailVals.push_back(std::make_pair(results[i], clonedResults[i]));
+    }
   }
 };
 
@@ -428,7 +435,8 @@
 /// \brief This is a helper class used to optimize casts.
 class CastOptimizer {
   // Callback to be called when uses of an instruction should be replaced.
-  std::function<void (SILInstruction *I, ValueBase *V)> ReplaceInstUsesAction;
+  std::function<void (SingleValueInstruction *I, ValueBase *V)>
+    ReplaceInstUsesAction;
 
   // Callback to call when an instruction needs to be erased.
   std::function<void (SILInstruction *)> EraseInstAction;
@@ -474,7 +482,7 @@
                                           SILInstruction *TrapInst);
 
 public:
-  CastOptimizer(std::function<void (SILInstruction *I, ValueBase *V)> ReplaceInstUsesAction,
+  CastOptimizer(std::function<void (SingleValueInstruction *I, ValueBase *V)> ReplaceInstUsesAction,
                 std::function<void (SILInstruction *)> EraseAction,
                 std::function<void ()> WillSucceedAction,
                 std::function<void ()> WillFailAction = [](){})
@@ -488,7 +496,7 @@
   // couldn't use the single constructor version which has three default
   // arguments. It seems the number of the default argument with lambda is
   // limited.
-  CastOptimizer(std::function<void (SILInstruction *I, ValueBase *V)> ReplaceInstUsesAction,
+  CastOptimizer(std::function<void (SingleValueInstruction *I, ValueBase *V)> ReplaceInstUsesAction,
                 std::function<void (SILInstruction *)> EraseAction = [](SILInstruction*){})
     : CastOptimizer(ReplaceInstUsesAction, EraseAction, [](){}, [](){}) {}
 
@@ -581,20 +589,20 @@
   ValueBaseUseIterator OrigUseChain;
   ValueBaseUseIterator CurrentIter;
 
-  static bool isExpect(Operand *Use) {
+  static BuiltinInst *isExpect(Operand *Use) {
     if (auto *BI = dyn_cast<BuiltinInst>(Use->getUser()))
       if (BI->getIntrinsicInfo().ID == llvm::Intrinsic::expect)
-        return true;
-    return false;
+        return BI;
+    return nullptr;
   }
 
   // Advance through expect users to their users until we encounter a user that
   // is not an expect.
   void advanceThroughExpects() {
     while (CurrentIter == OrigUseChain &&
-           CurrentIter != ValueBaseUseIterator(nullptr) &&
-           isExpect(*CurrentIter)) {
-      auto *Expect = CurrentIter->getUser();
+           CurrentIter != ValueBaseUseIterator(nullptr)) {
+      auto *Expect = isExpect(*CurrentIter);
+      if (!Expect) return;
       CurrentIter = Expect->use_begin();
       // Expect with no users advance to next item in original use chain.
       if (CurrentIter == Expect->use_end())
@@ -663,7 +671,7 @@
 /// An example of how this is useful is in cases where one is splitting up an
 /// aggregate and reforming it, the reformed aggregate may have extract
 /// operations from it. These can be simplified and removed.
-bool simplifyUsers(SILInstruction *I);
+bool simplifyUsers(SingleValueInstruction *I);
 
 ///  True if a type can be expanded
 /// without a significant increase to code size.
@@ -687,7 +695,7 @@
 /// The sequence is traversed inside out, i.e.
 /// starting with the innermost struct_element_addr
 void replaceLoadSequence(SILInstruction *I,
-                         SILInstruction *Value,
+                         SILValue Value,
                          SILBuilder &B);
 
 
diff --git a/include/swift/SILOptimizer/Utils/SCCVisitor.h b/include/swift/SILOptimizer/Utils/SCCVisitor.h
index ffe1354..ccddb5b 100644
--- a/include/swift/SILOptimizer/Utils/SCCVisitor.h
+++ b/include/swift/SILOptimizer/Utils/SCCVisitor.h
@@ -39,13 +39,13 @@
 template <typename ImplClass>
 class SCCVisitor {
 public:
-  SCCVisitor(SILFunction &F) : F(F), CurrentNum(0) {}
+  SCCVisitor(SILFunction &F) : F(F) {}
   ~SCCVisitor() {
     cleanup();
   }
   ImplClass &asImpl() {  return static_cast<ImplClass &>(*this); }
 
-  void visit(llvm::SmallVectorImpl<ValueBase *> &SCC) { }
+  void visit(llvm::SmallVectorImpl<SILNode *> &SCC) { }
 
   void run() {
     llvm::ReversePostOrderTraversal<SILFunction *> RPOT(&F);
@@ -53,8 +53,7 @@
     for (auto Iter = RPOT.begin(), E = RPOT.end(); Iter != E; ++Iter) {
       auto *BB = *Iter;
       for (auto &I : *BB)
-        if (!Visited.count(&I))
-          DFS(&I);
+        maybeDFS(&I);
     }
 
     cleanup();
@@ -62,20 +61,19 @@
 
 private:
   struct DFSInfo {
-    ValueBase *Value;
+    SILNode *Node;
     int DFSNum;
     int LowNum;
 
-    DFSInfo(ValueBase *Value, int Num) : Value(Value), DFSNum(Num),
-                                         LowNum(Num) {}
+    DFSInfo(SILNode *node, int num) : Node(node), DFSNum(num), LowNum(num) {}
   };
 
   SILFunction &F;
-  int CurrentNum;
+  int CurrentNum = 0;
 
-  llvm::DenseSet<ValueBase *> Visited;
-  llvm::SetVector<ValueBase *> DFSStack;
-  typedef llvm::DenseMap<ValueBase *, DFSInfo *> ValueInfoMapType;
+  llvm::DenseSet<SILNode *> Visited;
+  llvm::SetVector<SILNode *> DFSStack;
+  typedef llvm::DenseMap<SILNode *, DFSInfo *> ValueInfoMapType;
   ValueInfoMapType ValueInfoMap;
 
   void cleanup() {
@@ -88,25 +86,26 @@
     CurrentNum = 0;
   }
 
-  DFSInfo &addDFSInfo(ValueBase *Value) {
-    typename ValueInfoMapType::iterator Iter;
-    bool Inserted;
+  DFSInfo &addDFSInfo(SILNode *node) {
+    assert(node->isCanonicalSILNodeInObject());
 
-    auto MapEntry = std::make_pair(Value, new DFSInfo(Value, CurrentNum++));
-    std::tie(Iter, Inserted) = ValueInfoMap.insert(MapEntry);
-    assert(Inserted && "Cannot add DFS info more than once for a value!");
-    return *Iter->second;
+    auto entry = std::make_pair(node, new DFSInfo(node, CurrentNum++));
+    auto insertion = ValueInfoMap.insert(entry);
+    assert(insertion.second && "Cannot add DFS info more than once!");
+    return *insertion.first->second;
   }
 
-  DFSInfo &getDFSInfo(ValueBase *Value) {
-    assert(ValueInfoMap.find(Value) != ValueInfoMap.end() &&
+  DFSInfo &getDFSInfo(SILNode *node) {
+    assert(node->isCanonicalSILNodeInObject());
+    auto it = ValueInfoMap.find(node);
+    assert(it != ValueInfoMap.end() &&
            "Expected to find value in DFS info map!");
 
-    return *ValueInfoMap.find(Value)->second;
+    return *it->second;
   }
 
   void getArgsForTerminator(TermInst *Term, SILBasicBlock *SuccBB, int Index,
-                            llvm::SmallVectorImpl<ValueBase *> &Operands) {
+                            llvm::SmallVectorImpl<SILValue> &Operands) {
     switch (Term->getTermKind()) {
     case TermKind::BranchInst:
       return Operands.push_back(cast<BranchInst>(Term)->getArg(Index));
@@ -143,15 +142,15 @@
     }
   }
 
-  void collectOperandsForUser(ValueBase *User,
-                              llvm::SmallVectorImpl<ValueBase *> &Operands) {
-    if (auto *I = dyn_cast<SILInstruction>(User)) {
+  void collectOperandsForUser(SILNode *node,
+                              llvm::SmallVectorImpl<SILValue> &Operands) {
+    if (auto *I = dyn_cast<SILInstruction>(node)) {
       for (auto &O : I->getAllOperands())
         Operands.push_back(O.get());
       return;
     }
 
-    if (auto *A = dyn_cast<SILArgument>(User)) {
+    if (auto *A = dyn_cast<SILArgument>(node)) {
       auto *BB = A->getParent();
       auto Index = A->getIndex();
 
@@ -161,47 +160,52 @@
     }
   }
 
-  // Is Value currently on our DFS stack?
-  bool onStack(ValueBase *Value) {
-    return DFSStack.count(Value);
+  void maybeDFS(SILInstruction *inst) {
+    (void) maybeDFSCanonicalNode(inst->getCanonicalSILNodeInObject());
   }
 
-  /// Do depth-first through the value graph, finding the strongly
-  /// component that User is a part of, and call visit() with that SCC.
-  void DFS(ValueBase *User) {
-    assert(!Visited.count(User) &&
-           "Attempting to visit a value twice in DFS search!");
+  /// Continue a DFS from the given node, finding the strongly
+  /// component that User is a part of, calling visit() with that SCC,
+  /// and returning the DFSInfo for the node.
+  /// But if we've already visited the node, just return null.
+  DFSInfo *maybeDFSCanonicalNode(SILNode *node) {
+    assert(node->isCanonicalSILNodeInObject() && "should already be canonical");
 
-    DFSStack.insert(User);
-    Visited.insert(User);
+    if (!Visited.insert(node).second)
+      return nullptr;
 
-    auto &UserInfo = addDFSInfo(User);
+    DFSStack.insert(node);
 
-    llvm::SmallVector<ValueBase *, 4> Operands;
-    collectOperandsForUser(User, Operands);
+    auto &nodeInfo = addDFSInfo(node);
+
+    llvm::SmallVector<SILValue, 4> operands;
+    collectOperandsForUser(node, operands);
 
     // Visit each unvisited operand, updating the lowest DFS number we've seen
     // reachable in User's SCC.
-    for (auto *Opnd : Operands) {
-      if (!Visited.count(Opnd)) {
-        DFS(Opnd);
-        UserInfo.LowNum = std::min(UserInfo.LowNum, getDFSInfo(Opnd).LowNum);
-      } else if (onStack(Opnd)) {
-        UserInfo.LowNum = std::min(UserInfo.LowNum, getDFSInfo(Opnd).DFSNum);
+    for (SILValue operandValue : operands) {
+      SILNode *operandNode = operandValue->getCanonicalSILNodeInObject();
+      if (auto operandNodeInfo = maybeDFSCanonicalNode(operandNode)) {
+        nodeInfo.LowNum = std::min(nodeInfo.LowNum, operandNodeInfo->LowNum);
+      } else if (DFSStack.count(operandNode)) {
+        auto operandNodeInfo = &getDFSInfo(operandNode);
+        nodeInfo.LowNum = std::min(nodeInfo.LowNum, operandNodeInfo->DFSNum);
       }
     }
 
     // If User is the head of its own SCC, pop that SCC off the DFS stack.
-    if (UserInfo.DFSNum == UserInfo.LowNum) {
-      llvm::SmallVector<ValueBase *, 4> SCC;
-      ValueBase *PoppedValue;
+    if (nodeInfo.DFSNum == nodeInfo.LowNum) {
+      llvm::SmallVector<SILNode *, 4> SCC;
+      SILNode *poppedNode;
       do {
-        PoppedValue = DFSStack.pop_back_val();
-        SCC.push_back(PoppedValue);
-      } while (PoppedValue != User);
+        poppedNode = DFSStack.pop_back_val();
+        SCC.push_back(poppedNode);
+      } while (poppedNode != node);
 
       asImpl().visit(SCC);
     }
+
+    return &nodeInfo;
   }
 };
 
diff --git a/include/swift/SILOptimizer/Utils/SILInliner.h b/include/swift/SILOptimizer/Utils/SILInliner.h
index a7f5921..b059e36 100644
--- a/include/swift/SILOptimizer/Utils/SILInliner.h
+++ b/include/swift/SILOptimizer/Utils/SILInliner.h
@@ -37,7 +37,7 @@
 
 class SILInliner : public TypeSubstCloner<SILInliner> {
 public:
-  friend class SILVisitor<SILInliner>;
+  friend class SILInstructionVisitor<SILInliner>;
   friend class SILCloner<SILInliner>;
   
   enum class InlineKind {
diff --git a/include/swift/SILOptimizer/Utils/SILSSAUpdater.h b/include/swift/SILOptimizer/Utils/SILSSAUpdater.h
index 7c599c3..671c0a0 100644
--- a/include/swift/SILOptimizer/Utils/SILSSAUpdater.h
+++ b/include/swift/SILOptimizer/Utils/SILSSAUpdater.h
@@ -31,7 +31,7 @@
 
 /// Independent utility that canonicalizes BB arguments by reusing structurally
 /// equivalent arguments and replacing the original arguments with casts.
-SILInstruction *replaceBBArgWithCast(SILPHIArgument *Arg);
+SILValue replaceBBArgWithCast(SILPHIArgument *Arg);
 
 /// This class updates SSA for a set of SIL instructions defined in multiple
 /// blocks.
diff --git a/include/swift/SILOptimizer/Utils/StackNesting.h b/include/swift/SILOptimizer/Utils/StackNesting.h
index 105ae28..78adaa2 100644
--- a/include/swift/SILOptimizer/Utils/StackNesting.h
+++ b/include/swift/SILOptimizer/Utils/StackNesting.h
@@ -79,10 +79,10 @@
   ///
   /// Each stack location is allocated by a single allocation instruction.
   struct StackLoc {
-    StackLoc(SILInstruction *Alloc) : Alloc(Alloc) { }
+    StackLoc(AllocationInst *Alloc) : Alloc(Alloc) { }
 
     /// Back-link to the allocation instruction.
-    SILInstruction *Alloc;
+    AllocationInst *Alloc;
 
     /// Bit-set which represents all alive locations at this allocation.
     /// It obviously includes this location itself. And it includes all "outer"
@@ -91,7 +91,7 @@
   };
 
   /// Mapping from stack allocations (= locations) to bit numbers.
-  llvm::DenseMap<SILInstruction *, unsigned> StackLoc2BitNumbers;
+  llvm::DenseMap<SingleValueInstruction *, unsigned> StackLoc2BitNumbers;
 
   /// The list of stack locations. The index into this array is also the bit
   /// number in the bit-sets.
diff --git a/include/swift/Serialization/ModuleFormat.h b/include/swift/Serialization/ModuleFormat.h
index 08f2d2e..5341b09 100644
--- a/include/swift/Serialization/ModuleFormat.h
+++ b/include/swift/Serialization/ModuleFormat.h
@@ -54,7 +54,7 @@
 /// in source control, you should also update the comment to briefly
 /// describe what change you made. The content of this comment isn't important;
 /// it just ensures a conflict if two people change the module format.
-const uint16_t VERSION_MINOR = 366; // Last change: default argument resilience expansion
+const uint16_t VERSION_MINOR = 367; // Last change: SIL values vs. instructions
 
 using DeclID = PointerEmbeddedInt<unsigned, 31>;
 using DeclIDField = BCFixed<31>;
diff --git a/lib/AST/GenericSignature.cpp b/lib/AST/GenericSignature.cpp
index 161da23..594d466 100644
--- a/lib/AST/GenericSignature.cpp
+++ b/lib/AST/GenericSignature.cpp
@@ -912,8 +912,7 @@
 
     // We are at an explicit or inferred requirement.
     assert(source->kind == RequirementSource::Explicit ||
-           source->kind == RequirementSource::Inferred ||
-           source->kind == RequirementSource::QuietlyInferred);
+           source->kind == RequirementSource::Inferred);
 
     // Skip trivial path elements. These occur when querying a requirement
     // signature.
diff --git a/lib/AST/GenericSignatureBuilder.cpp b/lib/AST/GenericSignatureBuilder.cpp
index f0b85ea..c8319b3 100644
--- a/lib/AST/GenericSignatureBuilder.cpp
+++ b/lib/AST/GenericSignatureBuilder.cpp
@@ -340,7 +340,6 @@
   switch (kind) {
   case Explicit:
   case Inferred:
-  case QuietlyInferred:
   case RequirementSignatureSelf:
   case NestedTypeNameMatch:
   case ConcreteTypeBinding:
@@ -449,16 +448,13 @@
   return nullptr;
 }
 
-bool RequirementSource::isInferredRequirement(bool includeQuietInferred) const {
+bool RequirementSource::isInferredRequirement() const {
   for (auto source = this; source; source = source->parent) {
     switch (source->kind) {
     case Inferred:
     case InferredProtocolRequirement:
-      return true;
-
-    case QuietlyInferred:
     case NestedTypeNameMatch:
-      return includeQuietInferred;
+      return true;
 
     case ConcreteTypeBinding:
     case EquivalentType:
@@ -479,7 +475,7 @@
 }
 
 unsigned RequirementSource::classifyDiagKind() const {
-  if (isInferredRequirement(/*includeQuietInferred=*/false)) return 2;
+  if (isInferredRequirement()) return 2;
   if (isDerivedRequirement()) return 1;
   return 0;
 }
@@ -488,7 +484,6 @@
   switch (kind) {
   case Explicit:
   case Inferred:
-  case QuietlyInferred:
     return false;
 
   case NestedTypeNameMatch:
@@ -691,7 +686,6 @@
 
     case Explicit:
     case Inferred:
-    case QuietlyInferred:
     case NestedTypeNameMatch:
     case ConcreteTypeBinding:
       rootPA = parentPA;
@@ -779,14 +773,13 @@
 
 const RequirementSource *RequirementSource::forInferred(
                                               PotentialArchetype *root,
-                                              const TypeRepr *typeRepr,
-                                              bool quietly) {
+                                              const TypeRepr *typeRepr) {
   WrittenRequirementLoc writtenLoc = typeRepr;
   auto &builder = *root->getBuilder();
   REQUIREMENT_SOURCE_FACTORY_BODY(
-      (nodeID, quietly ? QuietlyInferred : Inferred, nullptr, root,
+      (nodeID, Inferred, nullptr, root,
        writtenLoc.getOpaqueValue(), nullptr),
-       (quietly ? QuietlyInferred : Inferred, root, nullptr, writtenLoc),
+       (Inferred, root, nullptr, writtenLoc),
        0, writtenLoc);
 }
 
@@ -916,7 +909,6 @@
   switch (kind) {
   case Explicit:
   case Inferred:
-  case QuietlyInferred:
   case RequirementSignatureSelf:
   case NestedTypeNameMatch:
   case ConcreteTypeBinding:
@@ -999,7 +991,6 @@
   case RequirementSource::ConcreteTypeBinding:
   case RequirementSource::Explicit:
   case RequirementSource::Inferred:
-  case RequirementSource::QuietlyInferred:
   case RequirementSource::RequirementSignatureSelf: {
     auto rootPA = getRootPotentialArchetype();
     if (visitor(rootPA, this)) return nullptr;
@@ -1175,10 +1166,6 @@
     out << "Inferred";
     break;
 
-  case QuietlyInferred:
-    out << "Quietly inferred";
-    break;
-
   case NestedTypeNameMatch:
     out << "Nested type match";
     break;
@@ -1292,12 +1279,7 @@
     return RequirementSource::forAbstract(pa);
 
   case Inferred:
-    return RequirementSource::forInferred(pa, storage.get<const TypeRepr *>(),
-                                          /*quietly=*/false);
-
-  case QuietlyInferred:
-    return RequirementSource::forInferred(pa, storage.get<const TypeRepr *>(),
-                                          /*quietly=*/true);
+    return RequirementSource::forInferred(pa, storage.get<const TypeRepr *>());
 
   case AbstractProtocol: {
     // Derive the dependent type on which this requirement was written. It is
@@ -1350,7 +1332,6 @@
     return true;
 
   case Inferred:
-  case QuietlyInferred:
   case NestedTypeNameMatch:
     return false;
 
@@ -1366,7 +1347,6 @@
     case RequirementSource::Concrete:
     case RequirementSource::Explicit:
     case RequirementSource::Inferred:
-    case RequirementSource::QuietlyInferred:
     case RequirementSource::NestedTypeNameMatch:
     case RequirementSource::ConcreteTypeBinding:
     case RequirementSource::Parent:
@@ -1388,7 +1368,6 @@
         == RequirementSource::RequirementSignatureSelf;
 
     case RequirementSource::Inferred:
-    case RequirementSource::QuietlyInferred:
     case RequirementSource::InferredProtocolRequirement:
     case RequirementSource::RequirementSignatureSelf:
     case RequirementSource::Concrete:
@@ -1408,10 +1387,9 @@
                                                   const TypeRepr *typeRepr) const {
   switch (kind) {
   case Explicit:
-    return forInferred(typeRepr, /*quietly=*/false);
+    return forInferred(typeRepr);
 
   case Inferred:
-  case QuietlyInferred:
   case Resolved:
   case NestedTypeNameMatch:
     return *this;
@@ -3619,10 +3597,10 @@
   assert(allNested.back() == nestedPA);
   if (allNested.size() > 1) {
     auto firstPA = allNested.front();
-    auto quietlyInferredSource =
-      FloatingRequirementSource::forInferred(nullptr, /*quietly=*/true);
+    auto inferredSource =
+      FloatingRequirementSource::forInferred(nullptr);
 
-    addSameTypeRequirement(firstPA, nestedPA, quietlyInferredSource,
+    addSameTypeRequirement(firstPA, nestedPA, inferredSource,
                            UnresolvedHandlingKind::GenerateConstraints);
     return;
   }
@@ -3977,8 +3955,7 @@
 
     // We are inferring requirements.
     if (forInferred) {
-      return FloatingRequirementSource::forInferred(typeRepr,
-                                                    /*quietly=*/false);
+      return FloatingRequirementSource::forInferred(typeRepr);
     }
 
     // Explicit requirement.
@@ -4126,10 +4103,10 @@
     if (inferForModule) {
       inferRequirements(*inferForModule, TypeLoc::withoutLoc(firstType),
                         FloatingRequirementSource::forInferred(
-                            nullptr, /*quietly=*/false));
+                            nullptr));
       inferRequirements(*inferForModule, TypeLoc::withoutLoc(secondType),
                         FloatingRequirementSource::forInferred(
-                            nullptr, /*quietly=*/false));
+                            nullptr));
     }
 
     return addTypeRequirement(firstType, secondType, source,
@@ -4143,8 +4120,7 @@
 
     if (inferForModule) {
       inferRequirements(*inferForModule, TypeLoc::withoutLoc(firstType),
-                        FloatingRequirementSource::forInferred(
-                            nullptr, /*quietly=*/false));
+                        FloatingRequirementSource::forInferred(nullptr));
     }
 
     return addLayoutRequirement(firstType, req.getLayoutConstraint(), source,
@@ -4160,10 +4136,10 @@
     if (inferForModule) {
       inferRequirements(*inferForModule, TypeLoc::withoutLoc(firstType),
                         FloatingRequirementSource::forInferred(
-                            nullptr, /*quietly=*/false));
+                            nullptr));
       inferRequirements(*inferForModule, TypeLoc::withoutLoc(secondType),
                         FloatingRequirementSource::forInferred(
-                            nullptr, /*quietly=*/false));
+                            nullptr));
     }
 
     return addSameTypeRequirement(
@@ -4237,7 +4213,7 @@
   for (auto P : *params) {
     inferRequirements(module, P->getTypeLoc(),
                       FloatingRequirementSource::forInferred(
-                          P->getTypeLoc().getTypeRepr(), /*quietly=*/false));
+                          P->getTypeLoc().getTypeRepr()));
   }
 }
 
@@ -4292,20 +4268,6 @@
         continue;
       }
 
-      // We prefer constraints rooted at inferred requirements to ones rooted
-      // on explicit requirements, because the former won't be diagnosed
-      // directly.
-      bool thisIsInferred = constraint.source->isInferredRequirement(
-                              /*includeQuietInferred=*/false);
-      bool representativeIsInferred =
-          representativeConstraint->source->isInferredRequirement(
-            /*includeQuietInferred=*/false);
-      if (thisIsInferred != representativeIsInferred) {
-        if (thisIsInferred)
-          representativeConstraint = constraint;
-        continue;
-      }
-
       // We prefer derived constraints to non-derived constraints.
       bool thisIsDerived = constraint.source->isDerivedRequirement();
       bool representativeIsDerived =
@@ -4317,6 +4279,17 @@
         continue;
       }
 
+      // We prefer constraints that are explicit to inferred constraints.
+      bool thisIsInferred = constraint.source->isInferredRequirement();
+      bool representativeIsInferred =
+        representativeConstraint->source->isInferredRequirement();
+      if (thisIsInferred != representativeIsInferred) {
+        if (thisIsInferred)
+          representativeConstraint = constraint;
+
+        continue;
+      }
+
       // We prefer constraints with locations to constraints without locations.
       bool thisHasValidSourceLoc = constraint.source->getLoc().isValid();
       bool representativeHasValidSourceLoc =
@@ -4873,7 +4846,8 @@
   bool diagnosedConflictingRepresentative = false;
   for (const auto &constraint : constraints) {
     // Leave the representative alone.
-    if (constraint == *representativeConstraint) continue;
+    if (representativeConstraint && constraint == *representativeConstraint)
+      continue;
 
     switch (checkConstraint(constraint)) {
     case ConstraintRelation::Unrelated:
@@ -4937,9 +4911,9 @@
       // If this requirement is not derived or inferred (but has a useful
       // location) complain that it is redundant.
       if (!constraint.source->isDerivedRequirement() &&
-          !constraint.source->isInferredRequirement(
-            /*includeQuietInferred=*/true) &&
-          constraint.source->getLoc().isValid()) {
+          !constraint.source->isInferredRequirement() &&
+          constraint.source->getLoc().isValid() &&
+          !representativeConstraint->source->isInferredRequirement()) {
         Diags.diagnose(constraint.source->getLoc(),
                        redundancyDiag,
                        constraint.archetype->getDependentType(genericParams),
@@ -5191,12 +5165,8 @@
         return lhs.target < rhs.target;
 
       // Prefer non-inferred requirement sources.
-      bool lhsIsInferred =
-      lhs.constraint.source->isInferredRequirement(
-                                            /*includeQuietInferred=*/false);
-      bool rhsIsInferred =
-      rhs.constraint.source->isInferredRequirement(
-                                            /*includeQuietInferred=*/false);
+      bool lhsIsInferred = lhs.constraint.source->isInferredRequirement();
+      bool rhsIsInferred = rhs.constraint.source->isInferredRequirement();
       if (lhsIsInferred != rhsIsInferred)
         return rhsIsInferred;;
 
@@ -5615,8 +5585,7 @@
       // If the source/destination are identical, complain.
       if (constraint.archetype == constraint.value) {
         if (!constraint.source->isDerivedRequirement() &&
-            !constraint.source->isInferredRequirement(
-               /*includeQuietInferred=*/true) &&
+            !constraint.source->isInferredRequirement() &&
             constraint.source->getLoc().isValid()) {
           Diags.diagnose(constraint.source->getLoc(),
                          diag::redundant_same_type_constraint,
@@ -5734,8 +5703,8 @@
           return true;
 
         // If the constraint source is inferred, don't diagnose it.
-        if (lhs.constraint.source->isInferredRequirement(
-              /*includeQuietInferred=*/true))
+        if (lhs.constraint.source->isInferredRequirement() ||
+            rhs.constraint.source->isInferredRequirement())
           return true;
 
         Diags.diagnose(lhs.constraint.source->getLoc(),
@@ -5765,9 +5734,9 @@
       // not part of the spanning tree.
       if (connected[edge.source] && connected[edge.target]) {
         if (edge.constraint.source->getLoc().isValid() &&
-            !edge.constraint.source->isInferredRequirement(
-              /*includeQuietInferred=*/true) &&
-            firstEdge.constraint.source->getLoc().isValid()) {
+            !edge.constraint.source->isInferredRequirement() &&
+            firstEdge.constraint.source->getLoc().isValid() &&
+            !firstEdge.constraint.source->isInferredRequirement()) {
           Diags.diagnose(edge.constraint.source->getLoc(),
                          diag::redundant_same_type_constraint,
                          edge.constraint.archetype->getDependentType(
@@ -5926,11 +5895,13 @@
 
       if (auto existing = equivClass->findAnyConcreteConstraintAsWritten(
                             representativeConstraint.archetype)) {
-        Diags.diagnose(existing->source->getLoc(),
-                       diag::same_type_redundancy_here,
-                       existing->source->classifyDiagKind(),
-                       existing->archetype->getDependentType(genericParams),
-                       existing->value);
+        if (!existing->source->isInferredRequirement()) {
+          Diags.diagnose(existing->source->getLoc(),
+                         diag::same_type_redundancy_here,
+                         existing->source->classifyDiagKind(),
+                         existing->archetype->getDependentType(genericParams),
+                         existing->value);
+        }
       }
     }
   }
@@ -6226,22 +6197,8 @@
   for (auto param : sig->getGenericParams())
     addGenericParameter(param);
 
-  // Add the requirements, queuing up same-type requirements until the end.
-  // FIXME: Queuing up same-type requirements is a hack that works around
-  // problems when referencing associated types. These issues primarily
-  // occur when building canonical generic environments
-  SmallVector<Requirement, 4> sameTypeRequirements;
-  for (auto &reqt : sig->getRequirements()) {
-    if (reqt.getKind() == RequirementKind::SameType)
-      sameTypeRequirements.push_back(reqt);
-    else
-      addRequirement(reqt, FloatingRequirementSource::forAbstract(), nullptr);
-  }
-
-  // Handle same-type requirements.
-  for (auto &reqt : sameTypeRequirements) {
+  for (auto &reqt : sig->getRequirements())
     addRequirement(reqt, FloatingRequirementSource::forAbstract(), nullptr);
-  }
 }
 
 /// Collect the set of requirements placed on the given generic parameters and
diff --git a/lib/AST/TypeJoinMeet.cpp b/lib/AST/TypeJoinMeet.cpp
index 3620c4a..ac5284a 100644
--- a/lib/AST/TypeJoinMeet.cpp
+++ b/lib/AST/TypeJoinMeet.cpp
@@ -15,9 +15,9 @@
 //
 //===----------------------------------------------------------------------===//
 #include "swift/AST/ASTContext.h"
+#include "swift/AST/CanTypeVisitor.h"
 #include "swift/AST/Decl.h"
 #include "swift/AST/Type.h"
-#include "swift/AST/TypeVisitor.h"
 #include "swift/AST/Types.h"
 #include "llvm/ADT/SmallPtrSet.h"
 using namespace swift;
@@ -26,43 +26,33 @@
 // 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 : TypeVisitor<TypeJoin, Type> {
-  Type First;
+struct TypeJoin : CanTypeVisitor<TypeJoin, CanType> {
+  CanType First;
 
-  TypeJoin(Type First) : First(First) {
+  TypeJoin(CanType First) : First(First) {
     assert(First && "Unexpected null type!");
   }
 
-  static Type getSuperclassJoin(Type first, Type second);
+  static CanType getSuperclassJoin(CanType first, CanType second);
 
-  Type visitClassType(Type second);
-  Type visitBoundGenericClassType(Type second);
-  Type visitArchetypeType(Type second);
-  Type visitDynamicSelfType(Type second);
-  Type visitMetatypeType(Type second);
-  Type visitExistentialMetatypeType(Type second);
-  Type visitBoundGenericEnumType(Type second);
+  CanType visitClassType(CanType second);
+  CanType visitBoundGenericClassType(CanType second);
+  CanType visitArchetypeType(CanType second);
+  CanType visitDynamicSelfType(CanType second);
+  CanType visitMetatypeType(CanType second);
+  CanType visitExistentialMetatypeType(CanType second);
+  CanType visitBoundGenericEnumType(CanType second);
 
-  Type visitOptionalType(Type second);
+  CanType visitOptionalType(CanType second);
 
-  Type visitType(Type second) {
+  CanType visitType(CanType second) {
     // FIXME: Implement all the visitors.
     //    llvm_unreachable("Unimplemented type visitor!");
     return First->getASTContext().TheAnyType;
   }
 
 public:
-  static Type join(Type first, Type second) {
-    if (!first || !second) {
-      if (first)
-        return ErrorType::get(first->getASTContext());
-
-      if (second)
-        return ErrorType::get(second->getASTContext());
-
-      return Type();
-    }
-
+  static CanType join(CanType first, CanType second) {
     assert(!first->hasTypeVariable() && !second->hasTypeVariable() &&
            "Cannot compute join of types involving type variables");
 
@@ -72,7 +62,7 @@
            "Expected simple type!");
 
     // If the types are equivalent, the join is obvious.
-    if (first->isEqual(second))
+    if (first == second)
       return first;
 
     // Until we handle all the combinations of joins, we need to make
@@ -85,23 +75,19 @@
   }
 };
 
-Type TypeJoin::getSuperclassJoin(Type first, Type second) {
-  if (!first || !second)
-    return TypeJoin::join(first, second);
-
+CanType TypeJoin::getSuperclassJoin(CanType first, CanType second) {
   if (!first->mayHaveSuperclass() || !second->mayHaveSuperclass())
     return first->getASTContext().TheAnyType;
 
   /// Walk the superclasses of `first` looking for `second`. Record them
   /// for our second step.
   llvm::SmallPtrSet<CanType, 8> superclassesOfFirst;
-  CanType canSecond = second->getCanonicalType();
   for (Type super = first; super; super = super->getSuperclass()) {
-    CanType canSuper = super->getCanonicalType();
+    auto canSuper = super->getCanonicalType();
 
     // If we have found the second type, we're done.
-    if (canSuper == canSecond)
-      return super;
+    if (canSuper == second)
+      return canSuper;
 
     superclassesOfFirst.insert(canSuper);
   }
@@ -109,94 +95,104 @@
   // Look through the superclasses of second to determine if any were also
   // superclasses of first.
   for (Type super = second; super; super = super->getSuperclass()) {
-    CanType canSuper = super->getCanonicalType();
+    auto canSuper = super->getCanonicalType();
 
     // If we found the first type, we're done.
     if (superclassesOfFirst.count(canSuper))
-      return super;
+      return canSuper;
   }
 
   // There is no common superclass; we're done.
   return first->getASTContext().TheAnyType;
 }
 
-Type TypeJoin::visitClassType(Type second) {
+CanType TypeJoin::visitClassType(CanType second) {
   return getSuperclassJoin(First, second);
 }
 
-Type TypeJoin::visitBoundGenericClassType(Type second) {
+CanType TypeJoin::visitBoundGenericClassType(CanType second) {
   return getSuperclassJoin(First, second);
 }
 
-Type TypeJoin::visitArchetypeType(Type second) {
+CanType TypeJoin::visitArchetypeType(CanType second) {
   return getSuperclassJoin(First, second);
 }
 
-Type TypeJoin::visitDynamicSelfType(Type second) {
+CanType TypeJoin::visitDynamicSelfType(CanType second) {
   return getSuperclassJoin(First, second);
 }
 
-Type TypeJoin::visitMetatypeType(Type second) {
+CanType TypeJoin::visitMetatypeType(CanType second) {
   if (First->getKind() != second->getKind())
     return First->getASTContext().TheAnyType;
 
-  auto firstInstance = First->castTo<AnyMetatypeType>()->getInstanceType();
-  auto secondInstance = second->castTo<AnyMetatypeType>()->getInstanceType();
+  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);
+  return MetatypeType::get(joinInstance)->getCanonicalType();
 }
 
-Type TypeJoin::visitExistentialMetatypeType(Type second) {
+CanType TypeJoin::visitExistentialMetatypeType(CanType second) {
   if (First->getKind() != second->getKind())
     return First->getASTContext().TheAnyType;
 
-  auto firstInstance = First->castTo<AnyMetatypeType>()->getInstanceType();
-  auto secondInstance = second->castTo<AnyMetatypeType>()->getInstanceType();
+  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 ExistentialMetatypeType::get(joinInstance);
+  return ExistentialMetatypeType::get(joinInstance)->getCanonicalType();
 }
 
-Type TypeJoin::visitBoundGenericEnumType(Type second) {
+CanType TypeJoin::visitBoundGenericEnumType(CanType second) {
   if (First->getKind() != second->getKind())
     return First->getASTContext().TheAnyType;
 
   OptionalTypeKind otk1, otk2;
-  Type objectType1 = First->getAnyOptionalObjectType(otk1);
-  Type objectType2 = second->getAnyOptionalObjectType(otk2);
+  auto firstObject = First->getAnyOptionalObjectType(otk1);
+  auto secondObject = second->getAnyOptionalObjectType(otk2);
   if (otk1 == OTK_Optional || otk2 == OTK_Optional) {
+    auto canFirst = firstObject->getCanonicalType();
+    auto canSecond = secondObject->getCanonicalType();
+
     // Compute the join of the unwrapped type. If there is none, we're done.
-    Type unwrappedJoin = join(objectType1 ? objectType1 : First,
-                              objectType2 ? objectType2 : second);
+    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);
+    return OptionalType::get(unwrappedJoin)->getCanonicalType();
   }
 
   // FIXME: More general joins of enums need to be handled.
   return First->getASTContext().TheAnyType;
 }
 
-Type TypeJoin::visitOptionalType(Type second) {
-  auto canFirst = First->getCanonicalType();
-  auto canSecond = second->getCanonicalType();
+Type Type::join(Type first, Type second) {
+  assert(first && second && "Unexpected null type!");
 
-  return TypeJoin::join(canFirst, canSecond);
-}
+  if (!first || !second) {
+    if (first)
+      return Type(ErrorType::get(first->getASTContext()));
 
-Type Type::join(Type type1, Type type2) {
-  assert(type1 && type2 && "Unexpected null type!");
+    if (second)
+      return Type(ErrorType::get(second->getASTContext()));
 
-  return TypeJoin::join(type1, type2);
+    return Type();
+  }
+
+  return TypeJoin::join(first->getCanonicalType(), second->getCanonicalType());
 }
diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp
index ca99376..16f22e8 100644
--- a/lib/ClangImporter/ImportDecl.cpp
+++ b/lib/ClangImporter/ImportDecl.cpp
@@ -4341,9 +4341,10 @@
       SmallVector<TypeLoc, 4> inheritedTypes;
       Type superclassType;
       if (decl->getSuperClass()) {
-        auto clangSuperclassType =
-          Impl.getClangASTContext().getObjCObjectPointerType(
-              clang::QualType(decl->getSuperClassType(), 0));
+        clang::QualType clangSuperclassType =
+          decl->getSuperClassType()->stripObjCKindOfTypeAndQuals(clangCtx);
+        clangSuperclassType =
+          clangCtx.getObjCObjectPointerType(clangSuperclassType);
         superclassType = Impl.importType(clangSuperclassType,
                                          ImportTypeKind::Abstract,
                                          isInSystemModule(dc),
diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp
index c1b126c..265bbea 100644
--- a/lib/Driver/Driver.cpp
+++ b/lib/Driver/Driver.cpp
@@ -162,6 +162,18 @@
                    "-warnings-as-errors", "-suppress-warnings");
   }
 
+  // Check for conflicting profiling flags
+  const Arg *ProfileGenerate = Args.getLastArg(options::OPT_profile_generate);
+  const Arg *ProfileUse = Args.getLastArg(options::OPT_profile_use);
+  if (ProfileGenerate && ProfileUse)
+    diags.diagnose(SourceLoc(), diag::error_conflicting_options,
+                   "-profile-generate", "-profile-use");
+
+  // Check if the profdata is missing
+  if (ProfileUse && !llvm::sys::fs::exists(ProfileUse->getValue()))
+    diags.diagnose(SourceLoc(), diag::error_profile_missing,
+                  ProfileUse->getValue());
+
   // Check for missing debug option when verifying debug info.
   if (Args.hasArg(options::OPT_verify_debug_info)) {
     bool hasDebugOption = true;
diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp
index f0e03d0..968bf8c 100644
--- a/lib/Driver/ToolChains.cpp
+++ b/lib/Driver/ToolChains.cpp
@@ -144,6 +144,7 @@
   inputArgs.AddLastArg(arguments, options::OPT_warn_swift3_objc_inference);
   inputArgs.AddLastArg(arguments, options::OPT_suppress_warnings);
   inputArgs.AddLastArg(arguments, options::OPT_profile_generate);
+  inputArgs.AddLastArg(arguments, options::OPT_profile_use);
   inputArgs.AddLastArg(arguments, options::OPT_profile_coverage_mapping);
   inputArgs.AddLastArg(arguments, options::OPT_warnings_as_errors);
   inputArgs.AddLastArg(arguments, options::OPT_sanitize_EQ);
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index 92ba309..19c3a9f 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -1458,6 +1458,9 @@
     Opts.ExternalPassPipelineFilename = A->getValue();
 
   Opts.GenerateProfile |= Args.hasArg(OPT_profile_generate);
+  const Arg *ProfileUse = Args.getLastArg(OPT_profile_use);
+  Opts.UseProfile = ProfileUse ? ProfileUse->getValue() : "";
+
   Opts.EmitProfileCoverageMapping |= Args.hasArg(OPT_profile_coverage_mapping);
   Opts.EnableGuaranteedClosureContexts |=
     Args.hasArg(OPT_enable_guaranteed_closure_contexts);
@@ -1639,6 +1642,9 @@
   }
 
   Opts.GenerateProfile |= Args.hasArg(OPT_profile_generate);
+  const Arg *ProfileUse = Args.getLastArg(OPT_profile_use);
+  Opts.UseProfile = ProfileUse ? ProfileUse->getValue() : "";
+
   Opts.PrintInlineTree |= Args.hasArg(OPT_print_llvm_inline_tree);
 
   Opts.UseSwiftCall = Args.hasArg(OPT_enable_swiftcall);
diff --git a/lib/IDE/Refactoring.cpp b/lib/IDE/Refactoring.cpp
index f6bba17..3bf103b 100644
--- a/lib/IDE/Refactoring.cpp
+++ b/lib/IDE/Refactoring.cpp
@@ -619,21 +619,17 @@
 class TokenBasedRefactoringAction : public RefactoringAction {
 protected:
   ResolvedCursorInfo CursorInfo;
-  bool CanProceed;
 public:
   TokenBasedRefactoringAction(ModuleDecl *MD, RefactoringOptions &Opts,
                               SourceEditConsumer &EditConsumer,
                               DiagnosticConsumer &DiagConsumer) :
   RefactoringAction(MD, Opts, EditConsumer, DiagConsumer) {
     // We can only proceed with valid location and source file.
-    CanProceed = StartLoc.isValid() && TheFile;
-    if (!CanProceed)
-      return;
-
-    // Resolve the sema token and save it for later use.
-    CursorInfoResolver Resolver(*TheFile);
-    CursorInfo = Resolver.resolve(StartLoc);
-    CanProceed = CursorInfo.isValid();
+    if (StartLoc.isValid() && TheFile) {
+      // Resolve the sema token and save it for later use.
+      CursorInfoResolver Resolver(*TheFile);
+      CursorInfo = Resolver.resolve(StartLoc);
+    }
   }
 };
 
@@ -644,8 +640,11 @@
                           SourceEditConsumer &EditConsumer,                   \
                           DiagnosticConsumer &DiagConsumer) :                 \
     TokenBasedRefactoringAction(MD, Opts, EditConsumer, DiagConsumer) {}      \
-  static bool isApplicable(ResolvedCursorInfo Tok);                           \
   bool performChange() override;                                              \
+  static bool isApplicable(ResolvedCursorInfo Tok, DiagnosticEngine &Diag);   \
+  bool isApplicable() {                                                       \
+    return RefactoringAction##KIND::isApplicable(CursorInfo, DiagEngine) ;    \
+  }                                                                           \
 };
 #include "swift/IDE/RefactoringKinds.def"
 
@@ -671,10 +670,14 @@
     RangeBasedRefactoringAction(MD, Opts, EditConsumer, DiagConsumer) {}      \
   bool performChange() override;                                              \
   static bool isApplicable(ResolvedRangeInfo Info, DiagnosticEngine &Diag);   \
+  bool isApplicable() {                                                       \
+    return RefactoringAction##KIND::isApplicable(RangeInfo, DiagEngine) ;     \
+  }                                                                           \
 };
 #include "swift/IDE/RefactoringKinds.def"
 
-bool RefactoringActionLocalRename::isApplicable(ResolvedCursorInfo CursorInfo) {
+bool RefactoringActionLocalRename::
+isApplicable(ResolvedCursorInfo CursorInfo, DiagnosticEngine &Diag) {
   if (CursorInfo.Kind != CursorInfoKind::ValueRef)
     return false;
   auto RenameOp = getAvailableRenameForDecl(CursorInfo.ValueD);
@@ -1036,8 +1039,6 @@
 }
 
 bool RefactoringActionExtractFunction::performChange() {
-  if (!isApplicable(RangeInfo, DiagEngine))
-    return true;
   // Check if the new name is ok.
   if (!Lexer::isIdentifier(PreferredName)) {
     DiagEngine.diagnose(SourceLoc(), diag::invalid_name, PreferredName);
@@ -1420,8 +1421,6 @@
 }
 
 bool RefactoringActionExtractExpr::performChange() {
-  if (!isApplicable(RangeInfo, DiagEngine))
-    return true;
   return RefactoringActionExtractExprBase(TheFile, RangeInfo,
                                           DiagEngine, false, PreferredName,
                                           EditConsumer).performChange();
@@ -1442,8 +1441,6 @@
   }
 }
 bool RefactoringActionExtractRepeatedExpr::performChange() {
-  if (!isApplicable(RangeInfo, DiagEngine))
-    return true;
   return RefactoringActionExtractExprBase(TheFile, RangeInfo,
                                           DiagEngine, true, PreferredName,
                                           EditConsumer).performChange();
@@ -1523,7 +1520,8 @@
   return Walker.IfInfo;
 }
 
-bool RefactoringActionCollapseNestedIfExpr::isApplicable(ResolvedCursorInfo Tok) {
+bool RefactoringActionCollapseNestedIfExpr::
+isApplicable(ResolvedCursorInfo Tok, DiagnosticEngine &Diag) {
   return findCollapseNestedIfTarget(Tok).isValid();
 }
 
@@ -1752,22 +1750,17 @@
   return NonWitnessedReqs;
 }
 
-bool RefactoringActionFillProtocolStub::isApplicable(ResolvedCursorInfo Tok) {
+bool RefactoringActionFillProtocolStub::
+isApplicable(ResolvedCursorInfo Tok, DiagnosticEngine &Diag) {
   return FillProtocolStubContext::getContextFromCursorInfo(Tok).canProceed();
 };
 
 bool RefactoringActionFillProtocolStub::performChange() {
-  // If the base class says no proceeding, respect it.
-  if (!CanProceed)
-    return true;
-
   // Get the filling protocol context from the input token.
   FillProtocolStubContext Context = FillProtocolStubContext::
-  getContextFromCursorInfo(CursorInfo);
+    getContextFromCursorInfo(CursorInfo);
 
-  // If the filling context disallows continue, abort.
-  if (!Context.canProceed())
-    return true;
+  assert(Context.canProceed());
   assert(!Context.getFillingContents().empty());
   assert(Context.getFillingContext());
   llvm::SmallString<128> Text;
@@ -1807,21 +1800,22 @@
   return collectAvailableRefactorings(SF, Tok, Scratch, /*Exclude rename*/false);
 }
 
-bool RefactoringActionExpandDefault::isApplicable(ResolvedCursorInfo CursorInfo) {
+bool RefactoringActionExpandDefault::
+isApplicable(ResolvedCursorInfo CursorInfo, DiagnosticEngine &Diag) {
+  auto Exit = [&](bool Applicable) {
+    if (!Applicable)
+      Diag.diagnose(SourceLoc(), diag::invalid_default_location);
+    return Applicable;
+  };
   if (CursorInfo.Kind != CursorInfoKind::StmtStart)
-    return false;
+    return Exit(false);
   if (auto *CS = dyn_cast<CaseStmt>(CursorInfo.TrailingStmt)) {
-    return CS->isDefault();
+    return Exit(CS->isDefault());
   }
-  return false;
+  return Exit(false);
 }
 
 bool RefactoringActionExpandDefault::performChange() {
-  if (!isApplicable(CursorInfo)) {
-    DiagEngine.diagnose(SourceLoc(), diag::invalid_default_location);
-    return true;
-  }
-
   // Try to find the switch statement enclosing the default statement.
   auto *CS = static_cast<CaseStmt*>(CursorInfo.TrailingStmt);
   auto IsSwitch = [](ASTNode Node) {
@@ -1911,7 +1905,8 @@
   return Walker.Target;
 }
 
-bool RefactoringActionLocalizeString::isApplicable(ResolvedCursorInfo Tok) {
+bool RefactoringActionLocalizeString::
+isApplicable(ResolvedCursorInfo Tok, DiagnosticEngine &Diag) {
   return findLocalizeTarget(Tok);
 }
 
@@ -1954,7 +1949,8 @@
   return ConvertToCharRange(TargetNode.getSourceRange());
 }
 
-bool RefactoringActionConvertToDoCatch::isApplicable(ResolvedCursorInfo Tok) {
+bool RefactoringActionConvertToDoCatch::
+isApplicable(ResolvedCursorInfo Tok, DiagnosticEngine &Diag) {
   if (!Tok.TrailingExpr)
     return false;
   return isa<ForceTryExpr>(Tok.TrailingExpr);
@@ -1962,8 +1958,7 @@
 
 bool RefactoringActionConvertToDoCatch::performChange() {
   auto *TryExpr = dyn_cast<ForceTryExpr>(CursorInfo.TrailingExpr);
-  if (!TryExpr)
-    return true;
+  assert(TryExpr);
   auto Range = findSourceRangeToWrapInCatch(CursorInfo, TheFile, SM);
   if (!Range.isValid())
     return true;
@@ -1973,7 +1968,8 @@
   OS << "\n} catch {\n" << getCodePlaceholder() << "\n}";
 
   // Delete ! from try! expression
-  auto ExclaimRange = CharSourceRange(TryExpr->getExclaimLoc(), 1);
+  auto ExclaimLen = getKeywordLen(tok::exclaim_postfix);
+  auto ExclaimRange = CharSourceRange(TryExpr->getExclaimLoc(), ExclaimLen);
   EditConsumer.accept(SM, ExclaimRange, "");
   return false;
 }
@@ -2042,7 +2038,7 @@
 }
 
 bool RefactoringActionSimplifyNumberLiteral::
-isApplicable(ResolvedCursorInfo Tok) {
+isApplicable(ResolvedCursorInfo Tok, DiagnosticEngine &Diag) {
   if (auto *Literal = getTrailingNumberLiteral(Tok)) {
     llvm::SmallString<64> Buffer;
     llvm::raw_svector_ostream OS(Buffer);
@@ -2257,8 +2253,9 @@
       AllKinds.push_back(RenameOp.getValue());
     }
   }
+  DiagnosticEngine DiagEngine(SF->getASTContext().SourceMgr);
 #define CURSOR_REFACTORING(KIND, NAME, ID)                                     \
-  if (RefactoringAction##KIND::isApplicable(CursorInfo))                       \
+  if (RefactoringAction##KIND::isApplicable(CursorInfo, DiagEngine))           \
     AllKinds.push_back(RefactoringKind::KIND);
 #include "swift/IDE/RefactoringKinds.def"
 
@@ -2323,8 +2320,13 @@
 
   switch (Opts.Kind) {
 #define SEMANTIC_REFACTORING(KIND, NAME, ID)                                   \
-    case RefactoringKind::KIND: return RefactoringAction##KIND(M, Opts,        \
-      EditConsumer, DiagConsumer).performChange();
+case RefactoringKind::KIND: {                                                  \
+      RefactoringAction##KIND Action(M, Opts, EditConsumer, DiagConsumer);     \
+      if (RefactoringKind::KIND == RefactoringKind::LocalRename ||             \
+          Action.isApplicable())                                               \
+        return Action.performChange();                                         \
+      return true;                                                             \
+  }
 #include "swift/IDE/RefactoringKinds.def"
     case RefactoringKind::GlobalRename:
     case RefactoringKind::FindGlobalRenameRanges:
diff --git a/lib/IDE/SwiftSourceDocInfo.cpp b/lib/IDE/SwiftSourceDocInfo.cpp
index e2215ea..2644a9e 100644
--- a/lib/IDE/SwiftSourceDocInfo.cpp
+++ b/lib/IDE/SwiftSourceDocInfo.cpp
@@ -189,10 +189,15 @@
       }
     }
     auto IsProperCursorLocation = E->getStartLoc() == LocToResolve;
-    // Handle cursor placement between try and ! in ForceTryExpr.
+    // Handle cursor placement after `try` in ForceTry and OptionalTry Expr.
+    auto CheckLocation = [&IsProperCursorLocation, this](SourceLoc Loc) {
+      IsProperCursorLocation = Loc == LocToResolve || IsProperCursorLocation;
+    };
     if (auto *FTE = dyn_cast<ForceTryExpr>(E)) {
-      IsProperCursorLocation = LocToResolve == FTE->getExclaimLoc() ||
-      IsProperCursorLocation;
+      CheckLocation(FTE->getExclaimLoc());
+    }
+    if (auto *OTE = dyn_cast<OptionalTryExpr>(E)) {
+      CheckLocation(OTE->getQuestionLoc());
     }
     // Keep track of trailing expressions.
     if (!E->isImplicit() && IsProperCursorLocation)
diff --git a/lib/IDE/SyntaxModel.cpp b/lib/IDE/SyntaxModel.cpp
index d6465b0..d43c0bc 100644
--- a/lib/IDE/SyntaxModel.cpp
+++ b/lib/IDE/SyntaxModel.cpp
@@ -507,10 +507,24 @@
     SN.BodyRange = innerCharSourceRangeFromSourceRange(SM, E->getSourceRange());
     pushStructureNode(SN, E);
   } else if (auto *Tup = dyn_cast<TupleExpr>(E)) {
-    for (unsigned I = 0; I < Tup->getNumElements(); ++ I) {
-      SourceLoc NameLoc = Tup->getElementNameLoc(I);
-      if (NameLoc.isValid())
-        passTokenNodesUntil(NameLoc, PassNodesBehavior::ExcludeNodeAtLocation);
+    if (isCurrentCallArgExpr(Tup)) {
+      for (unsigned I = 0; I < Tup->getNumElements(); ++ I) {
+        SourceLoc NameLoc = Tup->getElementNameLoc(I);
+        if (NameLoc.isValid())
+          passTokenNodesUntil(NameLoc, PassNodesBehavior::ExcludeNodeAtLocation);
+      }
+    } else {
+      SyntaxStructureNode SN;
+      SN.Kind = SyntaxStructureKind::TupleExpression;
+      SN.Range = charSourceRangeFromSourceRange(SM, Tup->getSourceRange());
+      SN.BodyRange = innerCharSourceRangeFromSourceRange(SM,
+                                                         Tup->getSourceRange());
+
+      for (auto *Elem : Tup->getElements()) {
+        addExprElem(Elem, SN);
+      }
+
+      pushStructureNode(SN, Tup);
     }
   }
 
diff --git a/lib/IDE/TypeReconstruction.cpp b/lib/IDE/TypeReconstruction.cpp
index 78baaf1..927b5ca 100644
--- a/lib/IDE/TypeReconstruction.cpp
+++ b/lib/IDE/TypeReconstruction.cpp
@@ -694,7 +694,7 @@
   // and they bear no connection to their original variable at the interface
   // level
   CanFunctionType swift_can_func_type =
-    CanFunctionType::get(AnyFunctionType::CanParamArrayRef({}),
+    CanFunctionType::get(AnyFunctionType::CanParamArrayRef(),
                          ast->TheRawPointerType,
                          AnyFunctionType::ExtInfo());
   result._types.push_back(swift_can_func_type.getPointer());
diff --git a/lib/IRGen/ClassMetadataVisitor.h b/lib/IRGen/ClassMetadataVisitor.h
index 7d70d2b..a6faa37 100644
--- a/lib/IRGen/ClassMetadataVisitor.h
+++ b/lib/IRGen/ClassMetadataVisitor.h
@@ -105,11 +105,6 @@
       }
     }
 
-    // Add a reference to the parent class, if applicable.
-    if (theClass->getDeclContext()->isTypeContext()) {
-      asImpl().addParentMetadataRef(theClass, type);
-    }
-
     // Add space for the generic parameters, if applicable.
     // Note that we only add references for the immediate parameters;
     // parameters for the parent context are handled by the parent.
@@ -161,7 +156,6 @@
   void addIVarDestroyer() { addPointer(); }
   void addValueWitnessTable() { addPointer(); }
   void addDestructorFunction() { addPointer(); }
-  void addParentMetadataRef(ClassDecl *forClass, Type classType) {addPointer();}
   void addSuperClass() { addPointer(); }
   void addClassFlags() { addInt32(); }
   void addInstanceAddressPoint() { addInt32(); }
diff --git a/lib/IRGen/EnumMetadataVisitor.h b/lib/IRGen/EnumMetadataVisitor.h
index 917c6ca..bc8334a 100644
--- a/lib/IRGen/EnumMetadataVisitor.h
+++ b/lib/IRGen/EnumMetadataVisitor.h
@@ -49,7 +49,6 @@
 
     // EnumMetadata header.
     asImpl().addNominalTypeDescriptor();
-    asImpl().addParentMetadataRef();
 
     // If changing this layout, you must update the magic number in
     // emitParentMetadataRef.
@@ -83,7 +82,6 @@
   void addMetadataFlags() { addPointer(); }
   void addValueWitnessTable() { addPointer(); }
   void addNominalTypeDescriptor() { addPointer(); }
-  void addParentMetadataRef() { addPointer(); }
   void addGenericArgument(CanType argument) { addPointer(); }
   void addGenericWitnessTable(CanType argument, ProtocolConformanceRef conf) {
     addPointer();
diff --git a/lib/IRGen/Fulfillment.cpp b/lib/IRGen/Fulfillment.cpp
index 449acb8..739b4f5 100644
--- a/lib/IRGen/Fulfillment.cpp
+++ b/lib/IRGen/Fulfillment.cpp
@@ -70,12 +70,12 @@
   case TypeKind::Tuple:
     return cast<TupleType>(type)->getNumElements() == 0;
 
-  // Nominal types might have parents.
+  // Nominal types might have generic parents.
   case TypeKind::Class:
   case TypeKind::Enum:
   case TypeKind::Protocol:
   case TypeKind::Struct:
-    return !cast<NominalType>(type)->getParent();
+    return !cast<NominalType>(type)->getDecl()->isGenericContext();
 
   // Bound generic types have type arguments.
   case TypeKind::BoundGenericClass:
@@ -125,14 +125,17 @@
     return hadFulfillment;
   }
 
+  if (keys.isInterestingType(type)) {
+    if (auto superclassTy = keys.getSuperclassBound(type)) {
+      return searchNominalTypeMetadata(IGM, superclassTy, source,
+                                       std::move(path), keys);
+    }
+  }
+
   // Inexact metadata will be a problem if we ever try to use this
   // to remember that we already have the metadata for something.
-  if (auto nomTy = dyn_cast<NominalType>(type)) {
-    return searchNominalTypeMetadata(IGM, nomTy, source, std::move(path), keys);
-  }
-  if (auto boundTy = dyn_cast<BoundGenericType>(type)) {
-    return searchBoundGenericTypeMetadata(IGM, boundTy, source,
-                                          std::move(path), keys);
+  if (isa<NominalType>(type) || isa<BoundGenericType>(type)) {
+    return searchNominalTypeMetadata(IGM, type, source, std::move(path), keys);
   }
 
   // TODO: tuples
@@ -203,47 +206,27 @@
 }
 
 
-bool FulfillmentMap::searchParentTypeMetadata(IRGenModule &IGM,
-                                              NominalTypeDecl *decl,
-                                              CanType parent,
-                                              unsigned source,
-                                              MetadataPath &&path,
-                                        const InterestingKeysCallback &keys) {
-  // We might not have a parent type.
-  if (!parent) return false;
-
-  // If we do, it has to be nominal one way or another.
-  path.addNominalParentComponent();
-  return searchTypeMetadata(IGM, parent, IsExact, source, std::move(path),keys);
-}
-
 bool FulfillmentMap::searchNominalTypeMetadata(IRGenModule &IGM,
-                                               CanNominalType type,
+                                               CanType type,
                                                unsigned source,
                                                MetadataPath &&path,
                                          const InterestingKeysCallback &keys) {
-  // Nominal types add no generic arguments themselves, but they
-  // may have the arguments of their parents.
-  return searchParentTypeMetadata(IGM, type->getDecl(), type.getParent(),
-                                  source, std::move(path), keys);
-}
-
-bool FulfillmentMap::searchBoundGenericTypeMetadata(IRGenModule &IGM,
-                                                    CanBoundGenericType type,
-                                                    unsigned source,
-                                                    MetadataPath &&path,
-                                         const InterestingKeysCallback &keys) {
   // Objective-C generics don't preserve their generic parameters at runtime,
   // so they aren't able to fulfill type metadata requirements.
-  if (type->getDecl()->hasClangNode()) {
+  if (type.getAnyNominal()->hasClangNode()) {
     return false;
   }
   
+  auto *nominal = type.getAnyNominal();
+  if (!nominal->isGenericContext() || isa<ProtocolDecl>(nominal)) {
+    return false;
+  }
+
   bool hadFulfillment = false;
 
-  GenericTypeRequirements requirements(IGM, type->getDecl());
+  GenericTypeRequirements requirements(IGM, nominal);
   requirements.enumerateFulfillments(
-      IGM, type->getContextSubstitutionMap(IGM.getSwiftModule(), type->getDecl()),
+      IGM, type->getContextSubstitutionMap(IGM.getSwiftModule(), nominal),
       [&](unsigned reqtIndex, CanType arg,
           Optional<ProtocolConformanceRef> conf) {
     // Skip uninteresting type arguments.
@@ -289,11 +272,6 @@
                          std::move(argPath), keys, interestingConformances);
   });
 
-  // Also match against the parent.  The polymorphic type
-  // will start with any arguments from the parent.
-  hadFulfillment |= searchParentTypeMetadata(IGM, type->getDecl(),
-                                             type.getParent(),
-                                             source, std::move(path), keys);
   return hadFulfillment;
 }
 
@@ -318,21 +296,6 @@
   }
 }
 
-bool FulfillmentMap::Everything::isInterestingType(CanType type) const {
-  return true;
-}
-bool FulfillmentMap::Everything::hasInterestingType(CanType type) const {
-  return true;
-}
-bool FulfillmentMap::Everything
-                   ::hasLimitedInterestingConformances(CanType type) const {
-  return false;
-}
-GenericSignature::ConformsToArray
-FulfillmentMap::Everything::getInterestingConformances(CanType type) const{
-  return {};
-}
-
 void FulfillmentMap::dump() const {
   auto &out = llvm::errs();
   for (auto &entry : Fulfillments) {
diff --git a/lib/IRGen/Fulfillment.h b/lib/IRGen/Fulfillment.h
index 82b66ba..65737b6 100644
--- a/lib/IRGen/Fulfillment.h
+++ b/lib/IRGen/Fulfillment.h
@@ -66,17 +66,10 @@
     virtual GenericSignature::ConformsToArray
       getInterestingConformances(CanType type) const = 0;
 
-    virtual ~InterestingKeysCallback() = default;
-  };
+    /// Return the limited interesting conformances for an interesting type.
+    virtual CanType getSuperclassBound(CanType type) const = 0;
 
-  /// An implementation of InterestingKeysCallback that returns everything
-  /// fulfillable.
-  struct Everything : InterestingKeysCallback {
-    bool isInterestingType(CanType type) const override;
-    bool hasInterestingType(CanType type) const override;
-    bool hasLimitedInterestingConformances(CanType type) const override;
-    GenericSignature::ConformsToArray
-      getInterestingConformances(CanType type) const override;
+    virtual ~InterestingKeysCallback() = default;
   };
 
   FulfillmentMap() = default;
@@ -140,19 +133,10 @@
   }
 
 private:
-  bool searchParentTypeMetadata(IRGenModule &IGM, NominalTypeDecl *typeDecl,
-                                CanType parent,
-                                unsigned source, MetadataPath &&path,
-                                const InterestingKeysCallback &keys);
-
-  bool searchNominalTypeMetadata(IRGenModule &IGM, CanNominalType type,
+  bool searchNominalTypeMetadata(IRGenModule &IGM, CanType type,
                                  unsigned source, MetadataPath &&path,
                                  const InterestingKeysCallback &keys);
 
-  bool searchBoundGenericTypeMetadata(IRGenModule &IGM, CanBoundGenericType type,
-                                      unsigned source, MetadataPath &&path,
-                                      const InterestingKeysCallback &keys);
-
   /// Search the given witness table for useful fulfillments.
   ///
   /// \return true if any fulfillments were added by this search.
@@ -168,5 +152,3 @@
 }
 
 #endif
-
-
diff --git a/lib/IRGen/GenDecl.cpp b/lib/IRGen/GenDecl.cpp
index c2bea3e..fdd329d 100644
--- a/lib/IRGen/GenDecl.cpp
+++ b/lib/IRGen/GenDecl.cpp
@@ -2561,8 +2561,9 @@
                                            NominalTypeDecl *nominal,
                                            ArrayRef<llvm::Type *> genericArgs,
                                            ForDefinition_t forDefinition) {
-  assert(!genericArgs.empty());
   assert(nominal->isGenericContext());
+  assert(!genericArgs.empty() ||
+         nominal->getGenericSignature()->areAllParamsConcrete());
   IRGen.addLazyTypeMetadata(nominal);
 
   auto type = nominal->getDeclaredType()->getCanonicalType();
diff --git a/lib/IRGen/GenMeta.cpp b/lib/IRGen/GenMeta.cpp
index 174a627..2219b15 100644
--- a/lib/IRGen/GenMeta.cpp
+++ b/lib/IRGen/GenMeta.cpp
@@ -142,8 +142,7 @@
     static unsigned getNumGenericArguments(IRGenModule &IGM,
                                            NominalTypeDecl *nominal) {
       GenericTypeRequirements requirements(IGM, nominal);
-      return unsigned(requirements.hasParentType())
-               + requirements.getNumTypeRequirements();
+      return requirements.getNumTypeRequirements();
     }
 
     void collectTypes(IRGenModule &IGM, NominalTypeDecl *nominal) {
@@ -153,10 +152,6 @@
 
     void collectTypes(IRGenModule &IGM,
                       const GenericTypeRequirements &requirements) {
-      if (requirements.hasParentType()) {
-        Types.push_back(IGM.TypeMetadataPtrTy);
-      }
-
       for (auto &requirement : requirements.getRequirements()) {
         if (requirement.Protocol) {
           Types.push_back(IGM.WitnessTablePtrTy);
@@ -181,10 +176,6 @@
 
       GenericTypeRequirements requirements(IGF.IGM, decl);
 
-      if (requirements.hasParentType()) {
-        Values.push_back(IGF.emitTypeMetadataRef(parentType));
-      }
-
       auto subs =
         type->getContextSubstitutionMap(IGF.IGM.getSwiftModule(), decl);
       requirements.enumerateFulfillments(IGF.IGM, subs,
@@ -217,14 +208,6 @@
              ->getCanonicalType();
   };
 
-  // If we have a parent type, it's the first parameter.
-  if (requirements.hasParentType()) {
-    auto parentType = getInContext(requirements.getParentType());
-    llvm::Value *parentMetadata = IGF.Builder.CreateLoad(array);
-    array = IGF.Builder.CreateConstArrayGEP(array, 1, IGF.IGM.getPointerSize());
-    IGF.bindLocalTypeDataFromTypeMetadata(parentType, IsExact, parentMetadata);
-  }
-
   // Okay, bind everything else from the context.
   requirements.bindFromBuffer(IGF, array, getInContext);
 }
@@ -372,7 +355,9 @@
   // Grab the substitutions.
   GenericArguments genericArgs;
   genericArgs.collect(IGF, theType);
-  assert(genericArgs.Values.size() > 0 && "no generic args?!");
+  assert((genericArgs.Values.size() > 0 ||
+          theDecl->getGenericSignature()->areAllParamsConcrete())
+         && "no generic args?!");
 
   // Call the generic metadata accessor function.
   llvm::Function *accessor =
@@ -1147,7 +1132,9 @@
   for (auto &arg : IGF.CurFn->args())
     genericArgs.Values.push_back(&arg);
   assert(genericArgs.Values.size() == genericArgs.Types.size());
-  assert(genericArgs.Values.size() > 0 && "no generic args?!");
+  assert((genericArgs.Values.size() > 0 ||
+          nominal->getGenericSignature()->areAllParamsConcrete())
+         && "no generic args?!");
 
   // Slam that information directly into the generic arguments buffer.
   auto argsBufferTy =
@@ -1684,7 +1671,7 @@
         // All function types look like () -> ().
         // FIXME: It'd be nice not to have to call through the runtime here.
         return IGF.emitTypeMetadataRef(
-                 CanFunctionType::get(AnyFunctionType::CanParamArrayRef({ }),
+                 CanFunctionType::get(AnyFunctionType::CanParamArrayRef(),
                                       C.TheEmptyTupleType,
                                       AnyFunctionType::ExtInfo()));
       case SILFunctionType::Representation::Block:
@@ -1866,7 +1853,7 @@
       case SILFunctionType::Representation::Thick:
         // All function types look like () -> ().
         return emitFromValueWitnessTable(
-                 CanFunctionType::get(AnyFunctionType::CanParamArrayRef({}),
+                 CanFunctionType::get(AnyFunctionType::CanParamArrayRef(),
                                       C.TheEmptyTupleType,
                                       AnyFunctionType::ExtInfo()));
       case SILFunctionType::Representation::Block:
@@ -2184,23 +2171,58 @@
 
       // GenericParameterDescriptorFlags Flags;
       GenericParameterDescriptorFlags flags;
-      if (ntd->getDeclContext()->isTypeContext())
-        flags = flags.withHasParent(true);
-      if (requirements.hasParentType())
-        flags = flags.withHasGenericParent(true);
       if (auto *cd = dyn_cast<ClassDecl>(ntd)) {
         auto &layout = IGM.getMetadataLayout(cd);
         if (layout.getVTableSize() > 0)
           flags = flags.withHasVTable(true);
       }
-      B.addInt32(flags.getIntValue());
+
+      // Calculate the number of generic parameters at each nesting depth.
+      unsigned totalGenericParams = 0;
+      SmallVector<unsigned, 2> numPrimaryParams;
+      for (auto *outer = ntd; outer != nullptr;
+           outer = outer->getDeclContext()
+               ->getAsNominalTypeOrNominalTypeExtensionContext()) {
+        unsigned genericParamsAtDepth = 0;
+        if (auto *genericParams = outer->getGenericParams()) {
+          for (auto *paramDecl : *genericParams) {
+            auto contextTy = ntd->mapTypeIntoContext(
+                paramDecl->getDeclaredInterfaceType());
+            // Skip parameters which have been made concrete, because they do
+            // not appear in type metadata.
+            //
+            // FIXME: We should emit information about same-type constraints
+            // as well as conformance constraints, so that clients can
+            // reconstruct the full generic signature of the type, including
+            // fully-concrete parameters.
+            if (contextTy->is<ArchetypeType>()) {
+              totalGenericParams++;
+              genericParamsAtDepth++;
+            }
+          }
+        }
+        numPrimaryParams.push_back(genericParamsAtDepth);
+      }
+
+      // This assertion will fail once we have generic types nested
+      // inside generic functions or other local generic contexts.
+      assert(totalGenericParams == requirements.getNumTypeRequirements());
+
+      // Emit the nesting depth.
+      B.addInt16(numPrimaryParams.size());
+
+      // Emit the flags.
+      B.addInt16(flags.getIntValue());
+
+      // Emit the number of generic parameters at each nesting depth.
+      std::reverse(numPrimaryParams.begin(), numPrimaryParams.end());
+      for (auto count : numPrimaryParams)
+        B.addInt32(count);
 
       // TODO: provide reflective descriptions of the type and
       // conformance requirements stored here.
-
-      // };
     }
-    
+
     llvm::Constant *emit() {
       asImpl().layout();
 
@@ -3487,7 +3509,6 @@
     using super = ClassMetadataBuilderBase<ClassMetadataBuilder>;
 
     bool HasUnfilledSuperclass = false;
-    bool HasUnfilledParent = false;
 
     Size AddressPoint;
 
@@ -3534,22 +3555,6 @@
       }
     }
 
-    void addParentMetadataRef(ClassDecl *forClass, Type classType) {
-      CanType parentType = classType->getCanonicalType().getNominalParent();
-
-      if (auto metadata =
-            tryEmitConstantTypeMetadataRef(IGM, parentType,
-                                           SymbolReferenceKind::Absolute)) {
-        B.add(metadata.getValue());
-      } else {
-        // Leave a null pointer placeholder to be filled by in-place
-        // initialization.
-        B.addNullPointer(IGM.TypeMetadataPtrTy);
-        if (forClass == Target)
-          HasUnfilledParent = true;
-      }
-    }
-
     bool canBeConstant() {
       // TODO: the metadata global can actually be constant in a very
       // special case: it's not a pattern, ObjC interoperation isn't
@@ -3566,7 +3571,7 @@
       [&](IRGenFunction &IGF, llvm::Constant *cacheVar) -> llvm::Value* {
         // There's an interesting special case where we can do the
         // initialization idempotently and thus avoid the need for a lock.
-        if (!HasUnfilledSuperclass && !HasUnfilledParent &&
+        if (!HasUnfilledSuperclass &&
             isFinishInitializationIdempotent()) {
           auto type = Target->getDeclaredType()->getCanonicalType();
           auto metadata =
@@ -3604,18 +3609,6 @@
         IGF.Builder.CreateStore(superclassMetadata, superField);
       }
 
-      // Initialize the class's own parent pointer if it has one and it
-      // wasn't emitted as a constant.
-      if (HasUnfilledParent) {
-        auto parentType = type.getParent();
-        assert(parentType);
-        llvm::Value *parentMetadata = IGF.emitTypeMetadataRef(parentType);
-
-        auto parentSlot =
-          emitAddressOfParentMetadataSlot(IGF, metadata, type->getDecl());
-        IGF.Builder.CreateStore(parentMetadata, parentSlot);
-      }
-
       metadata = emitFinishInitializationOfClassMetadata(IGF, metadata);
 
       return metadata;
@@ -3647,12 +3640,6 @@
       HasDependentMetadata = true;
     }
 
-    void addParentMetadataRef(ClassDecl *forClass, Type classType) {
-      CanType parentType = classType->getCanonicalType().getNominalParent();
-      this->addFillOp(parentType, None, /*relative*/ false);
-      B.addNullPointer(IGM.TypeMetadataPtrTy);
-    }
-
     void addSuperClass() {
       // Filled in by the runtime.
       B.addNullPointer(IGM.TypeMetadataPtrTy);
@@ -4362,71 +4349,13 @@
 // Value types (structs and enums)
 //===----------------------------------------------------------------------===//
 
-namespace {
-  template <class Impl, class Base>
-  class ValueTypeMetadataBuilderBase : public Base {
-    using super = Base;
-
-  protected:
-    using super::asImpl;
-    using super::IGM;
-    using super::Target;
-    ConstantStructBuilder &B;
-
-    template <class DeclTy>
-    ValueTypeMetadataBuilderBase(IRGenModule &IGM, DeclTy *theDecl,
-                                 ConstantStructBuilder &B)
-      : super(IGM, theDecl), B(B) {}
-
-    CanType getParentType() const {
-      Type type = Target->getDeclaredTypeInContext();
-      Type parentType = type->getNominalParent();
-      if (parentType)
-        return parentType->getCanonicalType();
-      return CanType();
-    }
-
-  public:
-    void addParentMetadataRef() {
-      llvm::Constant *parentMetadata = nullptr;
-      if (auto parentType = getParentType()) {
-        parentMetadata =
-          tryEmitConstantTypeMetadataRef(IGM, parentType,
-                                         SymbolReferenceKind::Absolute)
-            .getDirectValue();
-        if (!parentMetadata) {
-          asImpl().flagUnfilledParent();
-        }
-      }
-
-      if (!parentMetadata)
-        parentMetadata = llvm::ConstantPointerNull::get(IGM.TypeMetadataPtrTy);
-      B.add(parentMetadata);
-    }
-  };
-} // end anonymous namespace
-
 static llvm::Value *
 emitInPlaceValueTypeMetadataInitialization(IRGenFunction &IGF,
                                            CanNominalType type,
-                                           llvm::Value *metadata,
-                                           bool hasUnfilledParent) {
+                                           llvm::Value *metadata) {
   // All the value types are basically similar.
   assert(isa<StructType>(type) || isa<EnumType>(type));
 
-  // Initialize the parent-metadata field if it wasn't done statically.
-  if (hasUnfilledParent) {
-    CanType parentType = type.getParent();
-    assert(parentType);
-
-    // Value types hold the parent metadata as a far relative
-    // indirectable pointer.
-    llvm::Value *parentMetadata = IGF.emitTypeMetadataRef(parentType);
-    Address addr =
-      emitAddressOfParentMetadataSlot(IGF, metadata, type->getDecl());
-    IGF.Builder.CreateStore(parentMetadata, addr);
-  }
-
   // Set up the value witness table if it's dependent.
   SILType loweredType = IGF.IGM.getLoweredType(AbstractionPattern(type), type);
   auto &ti = IGF.IGM.getTypeInfo(loweredType);
@@ -4445,8 +4374,7 @@
 /// Create an access function for the type metadata of the given
 /// non-generic nominal type.
 static void createInPlaceValueTypeMetadataAccessFunction(IRGenModule &IGM,
-                                                      NominalTypeDecl *typeDecl,
-                                                      bool hasUnfilledParent) {
+                                                      NominalTypeDecl *typeDecl) {
   assert(!typeDecl->isGenericContext());
   auto type =
     cast<NominalType>(typeDecl->getDeclaredType()->getCanonicalType());
@@ -4456,8 +4384,7 @@
                                            llvm::Constant *cacheVariable) {
     return emitInPlaceTypeMetadataAccessFunctionBody(IGF, type, cacheVariable,
       [&](IRGenFunction &IGF, llvm::Value *metadata) {
-        return emitInPlaceValueTypeMetadataInitialization(IGF, type, metadata,
-                                                          hasUnfilledParent);
+        return emitInPlaceValueTypeMetadataInitialization(IGF, type, metadata);
       });
   });
 }
@@ -4469,19 +4396,18 @@
 namespace {
   /// An adapter for laying out struct metadata.
   template <class Impl>
-  class StructMetadataBuilderBase
-         : public ValueTypeMetadataBuilderBase<Impl,StructMetadataVisitor<Impl>>{
-    using super = ValueTypeMetadataBuilderBase<Impl,StructMetadataVisitor<Impl>>;
+  class StructMetadataBuilderBase : public StructMetadataVisitor<Impl> {
+    using super = StructMetadataVisitor<Impl>;
 
   protected:
+    ConstantStructBuilder &B;
     using super::IGM;
     using super::Target;
     using super::asImpl;
-    using super::B;
 
     StructMetadataBuilderBase(IRGenModule &IGM, StructDecl *theStruct,
                               ConstantStructBuilder &B)
-      : super(IGM, theStruct, B) {
+      : super(IGM, theStruct), B(B) {
     }
 
   public:
@@ -4525,23 +4451,18 @@
   class StructMetadataBuilder :
     public StructMetadataBuilderBase<StructMetadataBuilder> {
 
-    bool HasUnfilledParent = false;
     bool HasUnfilledFieldOffset = false;
   public:
     StructMetadataBuilder(IRGenModule &IGM, StructDecl *theStruct,
                           ConstantStructBuilder &B)
       : StructMetadataBuilderBase(IGM, theStruct, B) {}
 
-    void flagUnfilledParent() {
-      HasUnfilledParent = true;
-    }
-
     void flagUnfilledFieldOffset() {
       HasUnfilledFieldOffset = true;
     }
 
     bool canBeConstant() {
-      return !HasUnfilledParent && !HasUnfilledFieldOffset;
+      return !HasUnfilledFieldOffset;
     }
 
     void addValueWitnessTable() {
@@ -4550,8 +4471,7 @@
     }
 
     void createMetadataAccessFunction() {
-      createInPlaceValueTypeMetadataAccessFunction(IGM, Target,
-                                                   HasUnfilledParent);
+      createInPlaceValueTypeMetadataAccessFunction(IGM, Target);
     }
   };
   
@@ -4591,15 +4511,6 @@
                                     {metadataPattern, arguments});
     }
 
-    void addParentMetadataRef() {
-      // Override to always use a fill op instead of a relocation.
-      if (CanType parentType = getParentType()) {
-        addFillOp(parentType, None, /*relative*/ false);
-      }
-
-      B.addInt(IGM.IntPtrTy, 0);
-    }
-
     void flagUnfilledFieldOffset() {
       // We just assume this might happen.
     }
@@ -4665,19 +4576,18 @@
 namespace {
 
 template<class Impl>
-class EnumMetadataBuilderBase
-       : public ValueTypeMetadataBuilderBase<Impl, EnumMetadataVisitor<Impl>> {
-  using super = ValueTypeMetadataBuilderBase<Impl, EnumMetadataVisitor<Impl>>;
+class EnumMetadataBuilderBase : public EnumMetadataVisitor<Impl> {
+  using super = EnumMetadataVisitor<Impl>;
 
 protected:
+  ConstantStructBuilder &B;
   using super::IGM;
   using super::Target;
-  using super::B;
 
 public:
   EnumMetadataBuilderBase(IRGenModule &IGM, EnumDecl *theEnum,
                           ConstantStructBuilder &B)
-  : super(IGM, theEnum, B) {
+  : super(IGM, theEnum), B(B) {
   }
   
   void addMetadataFlags() {
@@ -4705,7 +4615,6 @@
   
 class EnumMetadataBuilder
   : public EnumMetadataBuilderBase<EnumMetadataBuilder> {
-  bool HasUnfilledParent = false;
   bool HasUnfilledPayloadSize = false;
 
 public:
@@ -4733,17 +4642,12 @@
     B.addInt(IGM.IntPtrTy, strategy.getPayloadSizeForMetadata());
   }
 
-  void flagUnfilledParent() {
-    HasUnfilledParent = true;
-  }
-
   bool canBeConstant() {
-    return !HasUnfilledParent && !HasUnfilledPayloadSize;
+    return !HasUnfilledPayloadSize;
   }
 
   void createMetadataAccessFunction() {
-    createInPlaceValueTypeMetadataAccessFunction(IGM, Target,
-                                                 HasUnfilledParent);
+    createInPlaceValueTypeMetadataAccessFunction(IGM, Target);
   }
 };
   
@@ -4763,15 +4667,6 @@
                                   {metadataPattern, arguments});
   }
 
-  void addParentMetadataRef() {
-    // Override to always use a fill op instead of a relocation.
-    if (CanType parentType = getParentType()) {
-      addFillOp(parentType, None, /*relative*/ false);
-    }
-
-    B.addInt(IGM.IntPtrTy, 0);
-  }
-  
   void addValueWitnessTable() {
     B.add(getValueWitnessTableForGenericValueType(IGM, Target,
                                                   HasDependentVWT));
@@ -4905,14 +4800,6 @@
 
     Size AddressPoint = Size::invalid();
 
-    bool computeUnfilledParent() {
-      if (auto parentType = asImpl().getTargetType().getNominalParent()) {
-        return !tryEmitConstantTypeMetadataRef(IGM, parentType,
-                                               SymbolReferenceKind::Absolute);
-      }
-      return false;
-    }
-
   public:
     void layout() {
       if (asImpl().requiresInitializationFunction())
@@ -5027,41 +4914,25 @@
     public ForeignMetadataBuilderBase<ForeignStructMetadataBuilder,
                       StructMetadataBuilderBase<ForeignStructMetadataBuilder>>
   {
-    bool HasUnfilledParent = false;
   public:
     ForeignStructMetadataBuilder(IRGenModule &IGM, StructDecl *target,
                                  ConstantStructBuilder &builder)
-        : ForeignMetadataBuilderBase(IGM, target, builder) {
-      HasUnfilledParent = computeUnfilledParent();
-    }
+        : ForeignMetadataBuilderBase(IGM, target, builder) {}
     
     CanType getTargetType() const {
       return Target->getDeclaredType()->getCanonicalType();
     }
 
     bool requiresInitializationFunction() const {
-      return HasUnfilledParent;
+      return false;
     }
-    void emitInitialization(IRGenFunction &IGF, llvm::Value *metadata) {
-      if (HasUnfilledParent) {
-        auto parentType = getTargetType().getNominalParent();
-        auto parentMetadata = IGF.emitTypeMetadataRef(parentType);
-
-        Address slot =
-          emitAddressOfParentMetadataSlot(IGF, metadata, this->Target);
-        IGF.Builder.CreateStore(parentMetadata, slot);
-      }
-    }
+    void emitInitialization(IRGenFunction &IGF, llvm::Value *metadata) {}
 
     void addValueWitnessTable() {
       auto type = this->Target->getDeclaredType()->getCanonicalType();
       B.add(emitValueWitnessTable(IGM, type));
     }
 
-    void flagUnfilledParent() {
-      assert(HasUnfilledParent);
-    }
-
     void flagUnfilledFieldOffset() {
       llvm_unreachable("foreign type with non-fixed layout?");
     }
@@ -5072,31 +4943,19 @@
     public ForeignMetadataBuilderBase<ForeignEnumMetadataBuilder,
                       EnumMetadataBuilderBase<ForeignEnumMetadataBuilder>>
   {
-    bool HasUnfilledParent = false;
   public:
     ForeignEnumMetadataBuilder(IRGenModule &IGM, EnumDecl *target,
                                ConstantStructBuilder &builder)
-      : ForeignMetadataBuilderBase(IGM, target, builder) {
-      HasUnfilledParent = computeUnfilledParent();
-    }
+      : ForeignMetadataBuilderBase(IGM, target, builder) {}
     
     CanType getTargetType() const {
       return Target->getDeclaredType()->getCanonicalType();
     }
 
     bool requiresInitializationFunction() const {
-      return HasUnfilledParent;
+      return false;
     }
-    void emitInitialization(IRGenFunction &IGF, llvm::Value *metadata) {
-      if (HasUnfilledParent) {
-        auto parentType = getTargetType().getNominalParent();
-        auto parentMetadata = IGF.emitTypeMetadataRef(parentType);
-
-        Address slot =
-          emitAddressOfParentMetadataSlot(IGF, metadata, this->Target);
-        IGF.Builder.CreateStore(parentMetadata, slot);
-      }
-    }
+    void emitInitialization(IRGenFunction &IGF, llvm::Value *metadata) {}
 
     void addValueWitnessTable() {
       auto type = this->Target->getDeclaredType()->getCanonicalType();
@@ -5106,10 +4965,6 @@
     void addPayloadSize() const {
       llvm_unreachable("nongeneric enums shouldn't need payload size in metadata");
     }
-
-    void flagUnfilledParent() {
-      assert(HasUnfilledParent);
-    }
   };
 } // end anonymous namespace
 
diff --git a/lib/IRGen/GenProto.cpp b/lib/IRGen/GenProto.cpp
index 7ddf897..3982e34 100644
--- a/lib/IRGen/GenProto.cpp
+++ b/lib/IRGen/GenProto.cpp
@@ -95,6 +95,12 @@
     return Generics->getConformsTo(t, M);
   }
 
+  CanType getSuperclassBound(Type t) {
+    if (auto superclassTy = Generics->getSuperclassBound(t, M))
+      return superclassTy->getCanonicalType();
+    return CanType();
+  }
+
 public:
   PolymorphicConvention(IRGenModule &IGM, CanSILFunctionType fnType);
 
@@ -291,6 +297,9 @@
     getInterestingConformances(CanType type) const override {
       return Self.getConformsTo(type);
     }
+    CanType getSuperclassBound(CanType type) const override {
+      return Self.getSuperclassBound(type);
+    }
   } callbacks(*this);
   return Fulfillments.searchTypeMetadata(IGM, type, isExact, sourceIndex,
                                          std::move(path), callbacks);
@@ -367,6 +376,15 @@
         return;
       }
 
+      if (isa<GenericTypeParamType>(type)) {
+        if (auto superclassTy = getSuperclassBound(type)) {
+          considerNewTypeSource(MetadataSource::Kind::ClassPointer,
+                                paramIndex, superclassTy, IsInexact);
+          return;
+
+        }
+      }
+
       // Thick metatypes are sources of metadata.
       if (auto metatypeTy = dyn_cast<MetatypeType>(type)) {
         if (metatypeTy->getRepresentation() != MetatypeRepresentation::Thick)
@@ -1284,6 +1302,11 @@
           getInterestingConformances(CanType type) const override {
             llvm_unreachable("no limits");
           }
+          CanType getSuperclassBound(CanType type) const override {
+            if (auto superclassTy = cast<ArchetypeType>(type)->getSuperclass())
+              return superclassTy->getCanonicalType();
+            return CanType();
+          }
         } callback;
         Fulfillments->searchTypeMetadata(IGM, ConcreteType, IsExact,
                                          /*sourceIndex*/ 0, MetadataPath(),
@@ -2023,15 +2046,17 @@
   case Component::Kind::NominalTypeArgument:
   case Component::Kind::NominalTypeArgumentConformance: {
     assert(sourceKey.Kind == LocalTypeDataKind::forTypeMetadata());
-    auto generic = cast<BoundGenericType>(sourceKey.Type);
+    auto type = sourceKey.Type;
+    if (auto archetypeTy = dyn_cast<ArchetypeType>(type))
+      type = archetypeTy->getSuperclass()->getCanonicalType();
+    auto *nominal = type.getAnyNominal();
     auto reqtIndex = component.getPrimaryIndex();
 
-    GenericTypeRequirements requirements(IGF.IGM, generic->getDecl());
+    GenericTypeRequirements requirements(IGF.IGM, nominal);
     auto &requirement = requirements.getRequirements()[reqtIndex];
 
     auto module = IGF.getSwiftModule();
-    auto subs = generic->getContextSubstitutionMap(module,
-                                                   generic->getDecl());
+    auto subs = sourceKey.Type->getContextSubstitutionMap(module, nominal);
     auto sub = requirement.TypeParameter.subst(subs)->getCanonicalType();
 
     // In either case, we need to change the type.
@@ -2041,7 +2066,7 @@
     if (component.getKind() == Component::Kind::NominalTypeArgument) {
       assert(!requirement.Protocol && "index mismatch!");
       if (source) {
-        source = emitArgumentMetadataRef(IGF, generic->getDecl(),
+        source = emitArgumentMetadataRef(IGF, nominal,
                                          requirements, reqtIndex, source);
         setTypeMetadataName(IGF.IGM, source, sourceKey.Type);
       }
@@ -2057,7 +2082,7 @@
 
       if (source) {
         auto protocol = conformance.getRequirement();
-        source = emitArgumentWitnessTableRef(IGF, generic->getDecl(),
+        source = emitArgumentWitnessTableRef(IGF, nominal,
                                              requirements, reqtIndex, source);
         setProtocolWitnessTableName(IGF.IGM, source, sourceKey.Type, protocol);
       }
@@ -2066,25 +2091,6 @@
     return source;
   }
 
-  case Component::Kind::NominalParent: {
-    assert(sourceKey.Kind == LocalTypeDataKind::forTypeMetadata());
-    NominalTypeDecl *nominalDecl;
-    if (auto nominal = dyn_cast<NominalType>(sourceKey.Type)) {
-      nominalDecl = nominal->getDecl();
-      sourceKey.Type = nominal.getParent();
-    } else {
-      auto generic = cast<BoundGenericType>(sourceKey.Type);
-      nominalDecl = generic->getDecl();
-      sourceKey.Type = generic.getParent();
-    }
-
-    if (source) {
-      source = emitParentMetadataRef(IGF, nominalDecl, source);
-      setTypeMetadataName(IGF.IGM, source, sourceKey.Type);
-    }
-    return source;
-  }
-
   case Component::Kind::OutOfLineBaseProtocol: {
     auto conformance = sourceKey.Kind.getProtocolConformance();
     auto protocol = conformance.getRequirement();
@@ -2184,9 +2190,6 @@
       out << "nominal_type_argument_conformance["
           << component.getPrimaryIndex() << "]";
       break;
-    case Component::Kind::NominalParent:
-      out << "nominal_parent";
-      break;
     case Component::Kind::Impossible:
       out << "impossible";
       break;
@@ -2573,28 +2576,9 @@
   // Construct a representative function type.
   auto generics = ncGenerics->getCanonicalSignature();
   CanSILFunctionType fnType = [&]() -> CanSILFunctionType {
-    CanType type = typeDecl->getDeclaredInterfaceType()->getCanonicalType();
-    if (auto nominal = dyn_cast<NominalType>(type)) {
-      ParentType = nominal.getParent();
-    } else {
-      ParentType = cast<BoundGenericType>(type).getParent();
-    }
-
-    // Ignore the existence of the parent type if it has no type parameters.
-    if (ParentType && !ParentType->hasTypeParameter())
-      ParentType = CanType();
-
-    SmallVector<SILParameterInfo, 1> params;
-    if (ParentType) {
-      auto parentMetatype =
-        CanMetatypeType::get(ParentType, MetatypeRepresentation::Thick);
-      params.push_back(SILParameterInfo(parentMetatype,
-                                        ParameterConvention::Direct_Unowned));
-    }
-
     return SILFunctionType::get(generics, SILFunctionType::ExtInfo(),
                                 /*callee*/ ParameterConvention::Direct_Unowned,
-                                params, /*results*/ {}, /*error*/ None,
+                                /*params*/ {}, /*results*/ {}, /*error*/ None,
                                 IGM.Context);
   }();
 
diff --git a/lib/IRGen/GenReflection.cpp b/lib/IRGen/GenReflection.cpp
index 5e4d832..f282d27 100644
--- a/lib/IRGen/GenReflection.cpp
+++ b/lib/IRGen/GenReflection.cpp
@@ -71,12 +71,6 @@
     OS << '_';
   }
 
-  void visitParentMetadataSource(const ParentMetadataSource *P) {
-    OS << 'P';
-    visit(P->getChild());
-    OS << '_';
-  }
-
   void visitSelfMetadataSource(const SelfMetadataSource *S) {
     OS << 'S';
   }
@@ -158,13 +152,6 @@
   }
 
   void
-  visitParentMetadataSource(const ParentMetadataSource *P) {
-    printHeader("parent-of");
-    printRec(P->getChild());
-    closeForm();
-  }
-
-  void
   visitSelfMetadataSource(const SelfMetadataSource *S) {
     printHeader("self");
     closeForm();
@@ -928,7 +915,7 @@
     // extra inhabitants as these. But maybe it's best not to codify
     // that in the ABI anyway.
     CanType thinFunction = CanFunctionType::get(
-      AnyFunctionType::CanParamArrayRef({}), Context.TheEmptyTupleType,
+      AnyFunctionType::CanParamArrayRef(), Context.TheEmptyTupleType,
       AnyFunctionType::ExtInfo().withRepresentation(
           FunctionTypeRepresentation::Thin));
     BuiltinTypes.insert(thinFunction);
diff --git a/lib/IRGen/GenericRequirement.h b/lib/IRGen/GenericRequirement.h
index 9839224..48cdccd 100644
--- a/lib/IRGen/GenericRequirement.h
+++ b/lib/IRGen/GenericRequirement.h
@@ -97,7 +97,6 @@
 /// anything fulfillable from its parent type metadata).
 class GenericTypeRequirements {
   NominalTypeDecl *TheDecl;
-  CanType ParentType;
   llvm::SmallVector<GenericRequirement, 4> Requirements;
 
 public:
@@ -108,15 +107,6 @@
     return Requirements;
   }
 
-  /// Does this generic type have 
-  bool hasParentType() const {
-    return bool(ParentType);
-  }
-
-  CanType getParentType() const {
-    return ParentType;
-  }
-
   /// Return the number of entries required in order to store this data.
   unsigned getStorageSizeInWords() const {
     return Requirements.size();
diff --git a/lib/IRGen/IRGenModule.cpp b/lib/IRGen/IRGenModule.cpp
index 707c3b5f..15a9c9f 100644
--- a/lib/IRGen/IRGenModule.cpp
+++ b/lib/IRGen/IRGenModule.cpp
@@ -39,6 +39,7 @@
 #include "llvm/IR/DataLayout.h"
 #include "llvm/IR/DerivedTypes.h"
 #include "llvm/IR/Intrinsics.h"
+#include "llvm/IR/MDBuilder.h"
 #include "llvm/IR/Module.h"
 #include "llvm/IR/Type.h"
 #include "llvm/ADT/PointerUnion.h"
@@ -1126,6 +1127,16 @@
   emitLazyObjCProtocolDefinitions();
 }
 
+llvm::MDNode *IRGenModule::createProfileWeights(uint64_t TrueCount,
+                                                uint64_t FalseCount) const {
+  uint64_t MaxWeight = std::max(TrueCount, FalseCount);
+  uint64_t Scale = (MaxWeight > UINT32_MAX) ? UINT32_MAX : 1;
+  uint32_t ScaledTrueCount = (TrueCount / Scale) + 1;
+  uint32_t ScaledFalseCount = (FalseCount / Scale) + 1;
+  llvm::MDBuilder MDHelper(getLLVMContext());
+  return MDHelper.createBranchWeights(ScaledTrueCount, ScaledFalseCount);
+}
+
 void IRGenModule::unimplemented(SourceLoc loc, StringRef message) {
   Context.Diags.diagnose(loc, diag::irgen_unimplemented, message);
 }
diff --git a/lib/IRGen/IRGenModule.h b/lib/IRGen/IRGenModule.h
index a474122..a9ac937 100644
--- a/lib/IRGen/IRGenModule.h
+++ b/lib/IRGen/IRGenModule.h
@@ -1089,6 +1089,12 @@
   void emitRuntimeRegistration();
   void emitVTableStubs();
   void emitTypeVerifier();
+
+  /// Create llvm metadata which encodes the branch weights given by
+  /// \p TrueCount and \p FalseCount.
+  llvm::MDNode *createProfileWeights(uint64_t TrueCount,
+                                     uint64_t FalseCount) const;
+
 private:
   void emitGlobalDecl(Decl *D);
 };
diff --git a/lib/IRGen/IRGenSIL.cpp b/lib/IRGen/IRGenSIL.cpp
index 9252938..a4c0580 100644
--- a/lib/IRGen/IRGenSIL.cpp
+++ b/lib/IRGen/IRGenSIL.cpp
@@ -2179,8 +2179,8 @@
   Explosion result;
   emission.emitToExplosion(result);
 
-  if (isa<ApplyInst>(i)) {
-    setLoweredExplosion(i, result);
+  if (auto apply = dyn_cast<ApplyInst>(i)) {
+    setLoweredExplosion(apply, result);
   } else {
     auto tryApplyInst = cast<TryApplyInst>(i);
 
@@ -3062,7 +3062,14 @@
   addIncomingSILArgumentsToPHINodes(*this, trueBB, i->getTrueArgs());
   addIncomingSILArgumentsToPHINodes(*this, falseBB, i->getFalseArgs());
 
-  Builder.CreateCondBr(condValue, trueBB.bb, falseBB.bb);
+  llvm::MDNode *Weights = nullptr;
+  auto TrueBBCount = i->getTrueBBCount();
+  auto FalseBBCount = i->getFalseBBCount();
+  if (TrueBBCount || FalseBBCount)
+    Weights = IGM.createProfileWeights(TrueBBCount ? TrueBBCount.getValue() : 0,
+        FalseBBCount ? FalseBBCount.getValue() : 0);
+
+  Builder.CreateCondBr(condValue, trueBB.bb, falseBB.bb, Weights);
 }
 
 void IRGenSILFunction::visitRetainValueInst(swift::RetainValueInst *i) {
@@ -3456,7 +3463,7 @@
   unsigned ArgNo = i->getVarInfo().ArgNo;
   emitDebugVariableDeclaration(
       emitShadowCopy(Addr, i->getDebugScope(), Name, ArgNo), DbgTy,
-      i->getType(), i->getDebugScope(), Decl, Name, ArgNo,
+      SILType(), i->getDebugScope(), Decl, Name, ArgNo,
       DbgTy.isImplicitlyIndirect() ? DirectValue : IndirectValue);
 }
 
@@ -3692,8 +3699,7 @@
 
   (void) Decl;
 
-  bool isEntryBlock =
-      i->getParentBlock() == i->getFunction()->getEntryBlock();
+  bool isEntryBlock = (i->getParent() == i->getFunction()->getEntryBlock());
   auto addr =
       type.allocateStack(*this, i->getElementType(), isEntryBlock, dbgname);
 
diff --git a/lib/IRGen/LoadableByAddress.cpp b/lib/IRGen/LoadableByAddress.cpp
index b338777..181012b 100644
--- a/lib/IRGen/LoadableByAddress.cpp
+++ b/lib/IRGen/LoadableByAddress.cpp
@@ -41,7 +41,7 @@
 ///
 /// TODO: This should be a common utility.
 static SILLocation getLocForValue(SILValue value) {
-  if (auto *instr = dyn_cast<SILInstruction>(value)) {
+  if (auto *instr = value->getDefiningInstruction()) {
     return instr->getLoc();
   }
   if (auto *arg = dyn_cast<SILArgument>(value)) {
@@ -377,9 +377,9 @@
   // All args for which we did a load
   llvm::DenseMap<SILValue, SILValue> argsToLoadedValueMap;
   // All applies for which we did an alloc
-  llvm::DenseMap<SILValue, SILValue> applyRetToAllocMap;
+  llvm::DenseMap<SILInstruction *, SILValue> applyRetToAllocMap;
   // recerse map of the one above
-  llvm::DenseMap<SILInstruction *, SILValue> allocToApplyRetMap;
+  llvm::DenseMap<SILInstruction *, SILInstruction*> allocToApplyRetMap;
   // All call sites with SILArgument that needs to be re-written
   // Calls are removed from the set when rewritten.
   SmallVector<SILInstruction *, 16> applies;
@@ -392,7 +392,7 @@
   // All struct_extract instrs that should be converted to struct_element_addr
   SmallVector<StructExtractInst *, 16> structExtractInstsToMod;
   // All tuple instructions for which the return type is a function type
-  SmallVector<SILInstruction *, 8> tupleInstsToMod;
+  SmallVector<SingleValueInstruction *, 8> tupleInstsToMod;
   // All allock stack instructions to modify
   SmallVector<AllocStackInst *, 8> allocStackInstsToMod;
   // All pointer to address instructions to modify
@@ -401,7 +401,7 @@
   SmallVector<RetainValueInst *, 16> retainInstsToMod;
   SmallVector<ReleaseValueInst *, 16> releaseInstsToMod;
   // All result types instrs for which we need to convert the ResultTy
-  llvm::SetVector<SILInstruction *> resultTyInstsToMod;
+  llvm::SetVector<SingleValueInstruction *> resultTyInstsToMod;
   // All instructions that use the large struct that are not covered above
   SmallVector<SILInstruction *, 16> instsToMod;
   // All function-exiting terminators (return or throw instructions).
@@ -443,10 +443,10 @@
   void visitStructExtractInst(StructExtractInst *instr);
   void visitRetainInst(RetainValueInst *instr);
   void visitReleaseInst(ReleaseValueInst *instr);
-  void visitResultTyInst(SILInstruction *instr);
+  void visitResultTyInst(SingleValueInstruction *instr);
   void visitDebugValueInst(DebugValueInst *instr);
   void visitDestroyValueInst(DestroyValueInst *instr);
-  void visitTupleInst(SILInstruction *instr);
+  void visitTupleInst(SingleValueInstruction *instr);
   void visitAllocStackInst(AllocStackInst *instr);
   void visitPointerToAddressInst(PointerToAddressInst *instr);
   void visitReturnInst(ReturnInst *instr);
@@ -467,82 +467,82 @@
     for (auto &II : *BB) {
       SILInstruction *currIns = &II;
       switch (currIns->getKind()) {
-      case ValueKind::ApplyInst:
-      case ValueKind::TryApplyInst:
-      case ValueKind::PartialApplyInst: {
+      case SILInstructionKind::ApplyInst:
+      case SILInstructionKind::TryApplyInst:
+      case SILInstructionKind::PartialApplyInst: {
         visitApply(ApplySite(currIns));
         break;
       }
-      case ValueKind::ClassMethodInst:
-      case ValueKind::SuperMethodInst:
-      case ValueKind::DynamicMethodInst:
-      case ValueKind::WitnessMethodInst: {
+      case SILInstructionKind::ClassMethodInst:
+      case SILInstructionKind::SuperMethodInst:
+      case SILInstructionKind::DynamicMethodInst:
+      case SILInstructionKind::WitnessMethodInst: {
         // TODO Any more instructions to add here?
         auto *MI = dyn_cast<MethodInst>(currIns);
         visitMethodInst(MI);
         break;
       }
-      case ValueKind::StructExtractInst:
-      case ValueKind::StructElementAddrInst:
-      case ValueKind::RefTailAddrInst:
-      case ValueKind::RefElementAddrInst:
-      case ValueKind::BeginAccessInst:
-      case ValueKind::EnumInst: {
+      case SILInstructionKind::StructExtractInst:
+      case SILInstructionKind::StructElementAddrInst:
+      case SILInstructionKind::RefTailAddrInst:
+      case SILInstructionKind::RefElementAddrInst:
+      case SILInstructionKind::BeginAccessInst:
+      case SILInstructionKind::EnumInst: {
         // TODO Any more instructions to add here?
-        visitResultTyInst(currIns);
+        visitResultTyInst(cast<SingleValueInstruction>(currIns));
         break;
       }
-      case ValueKind::StoreInst: {
+      case SILInstructionKind::StoreInst: {
         auto *SI = dyn_cast<StoreInst>(currIns);
         visitStoreInst(SI);
         break;
       }
-      case ValueKind::RetainValueInst: {
+      case SILInstructionKind::RetainValueInst: {
         auto *RETI = dyn_cast<RetainValueInst>(currIns);
         visitRetainInst(RETI);
         break;
       }
-      case ValueKind::ReleaseValueInst: {
+      case SILInstructionKind::ReleaseValueInst: {
         auto *RELI = dyn_cast<ReleaseValueInst>(currIns);
         visitReleaseInst(RELI);
         break;
       }
-      case ValueKind::DebugValueInst: {
+      case SILInstructionKind::DebugValueInst: {
         auto *DI = dyn_cast<DebugValueInst>(currIns);
         visitDebugValueInst(DI);
         break;
       }
-      case ValueKind::DestroyValueInst: {
+      case SILInstructionKind::DestroyValueInst: {
         auto *DI = dyn_cast<DestroyValueInst>(currIns);
         visitDestroyValueInst(DI);
         break;
       }
-      case ValueKind::SwitchEnumInst: {
+      case SILInstructionKind::SwitchEnumInst: {
         auto *SEI = dyn_cast<SwitchEnumInst>(currIns);
         visitSwitchEnumInst(SEI);
         break;
       }
-      case ValueKind::TupleElementAddrInst:
-      case ValueKind::TupleExtractInst: {
-        visitTupleInst(currIns);
+      case SILInstructionKind::TupleElementAddrInst:
+      case SILInstructionKind::TupleExtractInst: {
+        visitTupleInst(cast<SingleValueInstruction>(currIns));
         break;
       }
-      case ValueKind::AllocStackInst: {
+      case SILInstructionKind::AllocStackInst: {
         auto *ASI = dyn_cast<AllocStackInst>(currIns);
         visitAllocStackInst(ASI);
         break;
       }
-      case ValueKind::PointerToAddressInst: {
+      case SILInstructionKind::PointerToAddressInst: {
         auto *PTA = dyn_cast<PointerToAddressInst>(currIns);
         visitPointerToAddressInst(PTA);
         break;
       }
-      case ValueKind::ReturnInst: {
+      case SILInstructionKind::ReturnInst: {
         auto *RI = dyn_cast<ReturnInst>(currIns);
         visitReturnInst(RI);
         break;
       }
-      case ValueKind::DeallocStackInst: {
+      case SILInstructionKind::DeallocStackInst: {
         auto *DI = dyn_cast<DeallocStackInst>(currIns);
         visitDeallocInst(DI);
         break;
@@ -748,7 +748,7 @@
   }
 }
 
-void LargeValueVisitor::visitResultTyInst(SILInstruction *instr) {
+void LargeValueVisitor::visitResultTyInst(SingleValueInstruction *instr) {
   GenericEnvironment *genEnv = instr->getFunction()->getGenericEnvironment();
   auto loweredTy = instr->getFunction()->getLoweredFunctionType();
   if (!genEnv && loweredTy->isPolymorphic()) {
@@ -767,7 +767,7 @@
   }
 }
 
-void LargeValueVisitor::visitTupleInst(SILInstruction *instr) {
+void LargeValueVisitor::visitTupleInst(SingleValueInstruction *instr) {
   SILType currSILType = instr->getType().getObjectType();
   CanType currCanType = currSILType.getSwiftRValueType();
   if (auto funcType = dyn_cast<SILFunctionType>(currCanType)) {
@@ -853,7 +853,7 @@
   void convertIndirectBasicBlockArgs();
   void convertApplyResults();
   void allocateForArg(SILValue value);
-  AllocStackInst *allocateForApply(SILValue value, SILType type);
+  AllocStackInst *allocateForApply(SILInstruction *apply, SILType type);
   SILArgument *replaceArgType(SILBuilder &argBuilder, SILArgument *arg,
                               SILType newSILType);
 };
@@ -889,49 +889,49 @@
   for (auto *user : optimizableLoad->getUses()) {
     SILInstruction *userIns = user->getUser();
     switch (userIns->getKind()) {
-    case ValueKind::CopyAddrInst:
-    case ValueKind::DeallocStackInst:
+    case SILInstructionKind::CopyAddrInst:
+    case SILInstructionKind::DeallocStackInst:
       break;
-    case ValueKind::ApplyInst:
-    case ValueKind::TryApplyInst:
-    case ValueKind::PartialApplyInst: {
+    case SILInstructionKind::ApplyInst:
+    case SILInstructionKind::TryApplyInst:
+    case SILInstructionKind::PartialApplyInst: {
       if (std::find(pass.applies.begin(), pass.applies.end(), userIns) ==
           pass.applies.end()) {
         pass.applies.push_back(userIns);
       }
       break;
     }
-    case ValueKind::RetainValueInst: {
+    case SILInstructionKind::RetainValueInst: {
       auto *insToInsert = dyn_cast<RetainValueInst>(userIns);
       assert(insToInsert && "Unexpected cast failure");
       pass.retainInstsToMod.push_back(insToInsert);
       break;
     }
-    case ValueKind::ReleaseValueInst: {
+    case SILInstructionKind::ReleaseValueInst: {
       auto *insToInsert = dyn_cast<ReleaseValueInst>(userIns);
       assert(insToInsert && "Unexpected cast failure");
       pass.releaseInstsToMod.push_back(insToInsert);
       break;
     }
-    case ValueKind::StoreInst: {
+    case SILInstructionKind::StoreInst: {
       auto *insToInsert = dyn_cast<StoreInst>(userIns);
       assert(insToInsert && "Unexpected cast failure");
       pass.storeInstsToMod.push_back(insToInsert);
       break;
     }
-    case ValueKind::DebugValueInst: {
+    case SILInstructionKind::DebugValueInst: {
       auto *insToInsert = dyn_cast<DebugValueInst>(userIns);
       assert(insToInsert && "Unexpected cast failure");
       pass.debugInstsToMod.push_back(insToInsert);
       break;
     }
-    case ValueKind::DestroyValueInst: {
+    case SILInstructionKind::DestroyValueInst: {
       auto *insToInsert = dyn_cast<DestroyValueInst>(userIns);
       assert(insToInsert && "Unexpected cast failure");
       pass.destroyValueInstsToMod.push_back(insToInsert);
       break;
     }
-    case ValueKind::StructExtractInst: {
+    case SILInstructionKind::StructExtractInst: {
       auto *instToInsert = dyn_cast<StructExtractInst>(userIns);
       if (std::find(pass.structExtractInstsToMod.begin(),
                     pass.structExtractInstsToMod.end(),
@@ -940,7 +940,7 @@
       }
       break;
     }
-    case ValueKind::SwitchEnumInst: {
+    case SILInstructionKind::SwitchEnumInst: {
       auto *instToInsert = dyn_cast<SwitchEnumInst>(userIns);
       if (std::find(pass.switchEnumInstsToMod.begin(),
                     pass.switchEnumInstsToMod.end(),
@@ -963,9 +963,9 @@
   for (auto *user : unoptimizableLoad->getUses()) {
     SILInstruction *userIns = user->getUser();
     switch (userIns->getKind()) {
-    case ValueKind::ApplyInst:
-    case ValueKind::TryApplyInst:
-    case ValueKind::PartialApplyInst: {
+    case SILInstructionKind::ApplyInst:
+    case SILInstructionKind::TryApplyInst:
+    case SILInstructionKind::PartialApplyInst: {
       ApplySite site(userIns);
       SILValue callee = site.getCallee();
       if (callee == unoptimizableLoad) {
@@ -1017,12 +1017,12 @@
   for (auto *user : unoptimizableLoad->getUses()) {
     SILInstruction *userIns = user->getUser();
     switch (userIns->getKind()) {
-    case ValueKind::CopyAddrInst:
-    case ValueKind::DeallocStackInst:
+    case SILInstructionKind::CopyAddrInst:
+    case SILInstructionKind::DeallocStackInst:
       break;
-    case ValueKind::ApplyInst:
-    case ValueKind::TryApplyInst:
-    case ValueKind::PartialApplyInst: {
+    case SILInstructionKind::ApplyInst:
+    case SILInstructionKind::TryApplyInst:
+    case SILInstructionKind::PartialApplyInst: {
       ApplySite site(userIns);
       if (!modifiableApply(site, pass.Mod)) {
         break;
@@ -1049,48 +1049,48 @@
       usersToMod.push_back(user);
       break;
     }
-    case ValueKind::RetainValueInst: {
+    case SILInstructionKind::RetainValueInst: {
       auto *insToInsert = dyn_cast<RetainValueInst>(userIns);
       assert(insToInsert && "Unexpected cast failure");
       pass.retainInstsToMod.push_back(insToInsert);
       usersToMod.push_back(user);
       break;
     }
-    case ValueKind::ReleaseValueInst: {
+    case SILInstructionKind::ReleaseValueInst: {
       auto *insToInsert = dyn_cast<ReleaseValueInst>(userIns);
       assert(insToInsert && "Unexpected cast failure");
       pass.releaseInstsToMod.push_back(insToInsert);
       usersToMod.push_back(user);
       break;
     }
-    case ValueKind::StoreInst: {
+    case SILInstructionKind::StoreInst: {
       auto *insToInsert = dyn_cast<StoreInst>(userIns);
       assert(insToInsert && "Unexpected cast failure");
       pass.storeInstsToMod.push_back(insToInsert);
       usersToMod.push_back(user);
       break;
     }
-    case ValueKind::DebugValueInst: {
+    case SILInstructionKind::DebugValueInst: {
       auto *insToInsert = dyn_cast<DebugValueInst>(userIns);
       assert(insToInsert && "Unexpected cast failure");
       pass.debugInstsToMod.push_back(insToInsert);
       usersToMod.push_back(user);
       break;
     }
-    case ValueKind::DestroyValueInst: {
+    case SILInstructionKind::DestroyValueInst: {
       auto *insToInsert = dyn_cast<DestroyValueInst>(userIns);
       assert(insToInsert && "Unexpected cast failure");
       pass.destroyValueInstsToMod.push_back(insToInsert);
       usersToMod.push_back(user);
       break;
     }
-    case ValueKind::StructExtractInst: {
+    case SILInstructionKind::StructExtractInst: {
       auto *instToInsert = dyn_cast<StructExtractInst>(userIns);
       pass.structExtractInstsToMod.push_back(instToInsert);
       usersToMod.push_back(user);
       break;
     }
-    case ValueKind::SwitchEnumInst: {
+    case SILInstructionKind::SwitchEnumInst: {
       auto *instToInsert = dyn_cast<SwitchEnumInst>(userIns);
       pass.switchEnumInstsToMod.push_back(instToInsert);
       usersToMod.push_back(user);
@@ -1234,7 +1234,7 @@
       if (!ApplySite::isa(currIns)) {
         continue;
       }
-      if (dyn_cast<PartialApplyInst>(currIns)) {
+      if (isa<PartialApplyInst>(currIns)) {
         continue;
       }
       auto applySite = ApplySite(currIns);
@@ -1263,8 +1263,10 @@
       }
       auto newSILType = getNewSILType(genEnv, resultStorageType, pass.Mod);
       auto *newVal = allocateForApply(currIns, newSILType.getObjectType());
-      currIns->replaceAllUsesWith(newVal);
-      if (auto tryApplyIns = dyn_cast<TryApplyInst>(currIns)) {
+      if (auto apply = dyn_cast<ApplyInst>(currIns)) {
+        apply->replaceAllUsesWith(newVal);
+      } else {
+        auto tryApplyIns = cast<TryApplyInst>(currIns);
         auto *normalBB = tryApplyIns->getNormalBB();
         SILBuilder argBuilder(normalBB->begin());
         assert(normalBB->getNumArguments() == 1 &&
@@ -1338,8 +1340,7 @@
     assert(pass.allocToApplyRetMap.find(allocInstr) !=
                pass.allocToApplyRetMap.end() &&
            "Alloc is not for apply results");
-    auto *applyInst =
-        dyn_cast<SILInstruction>(pass.allocToApplyRetMap[allocInstr]);
+    auto *applyInst = pass.allocToApplyRetMap[allocInstr];
     assert(applyInst && "Value is not an apply");
     auto II = applyInst->getIterator();
     SILBuilder loadBuilder(II);
@@ -1388,14 +1389,15 @@
   }
 }
 
-AllocStackInst *LoadableStorageAllocation::allocateForApply(SILValue value,
-                                                            SILType type) {
+AllocStackInst *
+LoadableStorageAllocation::allocateForApply(SILInstruction *apply,
+                                            SILType type) {
   SILBuilder allocBuilder(pass.F->begin()->begin());
-  auto *allocInstr = allocBuilder.createAllocStack(getLocForValue(value), type);
+  auto *allocInstr = allocBuilder.createAllocStack(apply->getLoc(), type);
 
   pass.largeLoadableArgs.push_back(allocInstr);
-  pass.allocToApplyRetMap[allocInstr] = value;
-  pass.applyRetToAllocMap[value] = allocInstr;
+  pass.allocToApplyRetMap[allocInstr] = apply;
+  pass.applyRetToAllocMap[apply] = allocInstr;
 
   for (TermInst *termInst : pass.returnInsts) {
     SILBuilder deallocBuilder(termInst);
@@ -1429,7 +1431,7 @@
 
 private:
   llvm::SetVector<SILFunction *> modFuncs;
-  llvm::SetVector<SILInstruction *> conversionInstrs;
+  llvm::SetVector<SingleValueInstruction *> conversionInstrs;
   llvm::SetVector<BuiltinInst *> builtinInstrs;
   llvm::SetVector<LoadInst *> loadInstrsOfFunc;
   llvm::SetVector<UncheckedEnumDataInst *> uncheckedEnumDataOfFunc;
@@ -1437,7 +1439,7 @@
       uncheckedTakeEnumDataAddrOfFunc;
   llvm::SetVector<StoreInst *> storeToBlockStorageInstrs;
   llvm::DenseSet<SILInstruction *> modApplies;
-  llvm::DenseMap<SILValue, SILValue> allApplyRetToAllocMap;
+  llvm::DenseMap<SILInstruction *, SILValue> allApplyRetToAllocMap;
 };
 } // end anonymous namespace
 
@@ -1462,14 +1464,13 @@
       SILBuilder copyBuilder(storeUser);
       SILValue tgt = storeUser->getDest();
       createOutlinedCopyCall(copyBuilder, allocInstr, tgt, pass);
-      storeUser->replaceAllUsesWith(tgt);
-      storeUser->getParent()->erase(storeUser);
+      storeUser->eraseFromParent();
     }
   }
 }
 
 static void allocateAndSetForInstrOperand(StructLoweringState &pass,
-                                          SILInstruction *instrOperand) {
+                                          SingleValueInstruction *instrOperand){
   assert(instrOperand->getType().isObject());
   SILBuilder allocBuilder(pass.F->begin()->begin());
   AllocStackInst *allocInstr = allocBuilder.createAllocStack(
@@ -1535,21 +1536,21 @@
   setInstrUsers(pass, allocInstr, value, store);
 }
 
-static bool allUsesAreReplaceable(SILInstruction *instr,
+static bool allUsesAreReplaceable(SingleValueInstruction *instr,
                                   irgen::IRGenModule &Mod) {
   bool allUsesAreReplaceable = true;
   for (auto *user : instr->getUses()) {
     SILInstruction *userIns = user->getUser();
     switch (userIns->getKind()) {
-    case ValueKind::RetainValueInst:
-    case ValueKind::ReleaseValueInst:
-    case ValueKind::StoreInst:
-    case ValueKind::DebugValueInst:
-    case ValueKind::DestroyValueInst:
+    case SILInstructionKind::RetainValueInst:
+    case SILInstructionKind::ReleaseValueInst:
+    case SILInstructionKind::StoreInst:
+    case SILInstructionKind::DebugValueInst:
+    case SILInstructionKind::DestroyValueInst:
       break;
-    case ValueKind::ApplyInst:
-    case ValueKind::TryApplyInst:
-    case ValueKind::PartialApplyInst: {
+    case SILInstructionKind::ApplyInst:
+    case SILInstructionKind::TryApplyInst:
+    case SILInstructionKind::PartialApplyInst: {
       // Replaceable only if it is not the function pointer
       ApplySite site(userIns);
       if (!modifiableApply(site, Mod)) {
@@ -1573,8 +1574,8 @@
       }
       break;
     }
-    case ValueKind::StructExtractInst:
-    case ValueKind::SwitchEnumInst: {
+    case SILInstructionKind::StructExtractInst:
+    case SILInstructionKind::SwitchEnumInst: {
       break;
     }
     default:
@@ -1584,7 +1585,7 @@
   return allUsesAreReplaceable;
 }
 
-static void castTupleInstr(SILInstruction *instr, IRGenModule &Mod) {
+static void castTupleInstr(SingleValueInstruction *instr, IRGenModule &Mod) {
   SILType currSILType = instr->getType().getObjectType();
   CanType currCanType = currSILType.getSwiftRValueType();
   SILFunctionType *funcType = dyn_cast<SILFunctionType>(currCanType);
@@ -1601,15 +1602,15 @@
   auto II = instr->getIterator();
   ++II;
   SILBuilder castBuilder(II);
-  SILInstruction *castInstr = nullptr;
+  SingleValueInstruction *castInstr = nullptr;
   switch (instr->getKind()) {
   // Add cast to the new sil function type:
-  case ValueKind::TupleExtractInst: {
+  case SILInstructionKind::TupleExtractInst: {
     castInstr = castBuilder.createUncheckedBitCast(instr->getLoc(), instr,
                                                    newSILType.getObjectType());
     break;
   }
-  case ValueKind::TupleElementAddrInst: {
+  case SILInstructionKind::TupleElementAddrInst: {
     castInstr = castBuilder.createUncheckedAddrCast(
         instr->getLoc(), instr, newSILType.getAddressType());
     break;
@@ -1725,9 +1726,8 @@
       }
       SILBasicBlock *defaultBB =
           instr->hasDefault() ? instr->getDefaultBB() : nullptr;
-      auto *newInstr = enumBuilder.createSwitchEnumAddr(
+      enumBuilder.createSwitchEnumAddr(
           instr->getLoc(), copiedValue, defaultBB, caseBBs);
-      instr->replaceAllUsesWith(newInstr);
       instr->getParent()->erase(instr);
     }
 
@@ -1780,8 +1780,7 @@
         SILValue currOperand = operand.get();
         SILType silType = currOperand->getType();
         if (isLargeLoadableType(genEnv, silType, pass.Mod)) {
-          SILInstruction *currOperandInstr =
-              dyn_cast<SILInstruction>(currOperand);
+          auto currOperandInstr = dyn_cast<SingleValueInstruction>(currOperand);
           // Get its storage location as a new operand
           if (!currOperandInstr) {
             allocateAndSetForArgumentOperand(pass, currOperand, applyInst);
@@ -1826,7 +1825,7 @@
     }
   }
 
-  for (SILInstruction *instr : pass.tupleInstsToMod) {
+  for (SingleValueInstruction *instr : pass.tupleInstsToMod) {
     castTupleInstr(instr, pass.Mod);
   }
 
@@ -1896,71 +1895,68 @@
 
     SILBuilder copyBuilder(instr);
     createOutlinedCopyCall(copyBuilder, src, tgt, pass);
-    instr->replaceAllUsesWith(tgt);
     instr->getParent()->erase(instr);
   }
 
   for (RetainValueInst *instr : pass.retainInstsToMod) {
     SILBuilder retainBuilder(instr);
-    auto *newInstr = retainBuilder.createRetainValueAddr(
+    retainBuilder.createRetainValueAddr(
         instr->getLoc(), instr->getOperand(), instr->getAtomicity());
-    instr->replaceAllUsesWith(newInstr);
     instr->getParent()->erase(instr);
   }
 
   for (ReleaseValueInst *instr : pass.releaseInstsToMod) {
     SILBuilder releaseBuilder(instr);
-    auto *newInstr = releaseBuilder.createReleaseValueAddr(
+    releaseBuilder.createReleaseValueAddr(
         instr->getLoc(), instr->getOperand(), instr->getAtomicity());
-    instr->replaceAllUsesWith(newInstr);
     instr->getParent()->erase(instr);
   }
 
-  for (SILInstruction *instr : pass.resultTyInstsToMod) {
+  for (SingleValueInstruction *instr : pass.resultTyInstsToMod) {
     // Update the return type of these instrs
     // Note: The operand was already updated!
     SILType currSILType = instr->getType().getObjectType();
     SILType newSILType = getNewSILType(genEnv, currSILType, pass.Mod);
     SILBuilder resultTyBuilder(instr);
     SILLocation Loc = instr->getLoc();
-    SILInstruction *newInstr = nullptr;
+    SingleValueInstruction *newInstr = nullptr;
     switch (instr->getKind()) {
-    case ValueKind::StructExtractInst: {
-      auto *convInstr = dyn_cast<StructExtractInst>(instr);
+    case SILInstructionKind::StructExtractInst: {
+      auto *convInstr = cast<StructExtractInst>(instr);
       newInstr = resultTyBuilder.createStructExtract(
           Loc, convInstr->getOperand(), convInstr->getField(),
           newSILType.getObjectType());
       break;
     }
-    case ValueKind::StructElementAddrInst: {
-      auto *convInstr = dyn_cast<StructElementAddrInst>(instr);
+    case SILInstructionKind::StructElementAddrInst: {
+      auto *convInstr = cast<StructElementAddrInst>(instr);
       newInstr = resultTyBuilder.createStructElementAddr(
           Loc, convInstr->getOperand(), convInstr->getField(),
           newSILType.getAddressType());
       break;
     }
-    case ValueKind::RefTailAddrInst: {
-      auto *convInstr = dyn_cast<RefTailAddrInst>(instr);
+    case SILInstructionKind::RefTailAddrInst: {
+      auto *convInstr = cast<RefTailAddrInst>(instr);
       newInstr = resultTyBuilder.createRefTailAddr(Loc, convInstr->getOperand(),
                                                    newSILType.getAddressType());
       break;
     }
-    case ValueKind::RefElementAddrInst: {
-      auto *convInstr = dyn_cast<RefElementAddrInst>(instr);
+    case SILInstructionKind::RefElementAddrInst: {
+      auto *convInstr = cast<RefElementAddrInst>(instr);
       newInstr = resultTyBuilder.createRefElementAddr(
           Loc, convInstr->getOperand(), convInstr->getField(),
           newSILType.getAddressType());
       break;
     }
-    case ValueKind::BeginAccessInst: {
-      auto *convInstr = dyn_cast<BeginAccessInst>(instr);
+    case SILInstructionKind::BeginAccessInst: {
+      auto *convInstr = cast<BeginAccessInst>(instr);
       newInstr = resultTyBuilder.createBeginAccess(Loc, convInstr->getOperand(),
                                                    convInstr->getAccessKind(),
                                                    convInstr->getEnforcement());
       break;
     }
-    case ValueKind::EnumInst: {
-      auto *convInstr = dyn_cast<EnumInst>(instr);
+    case SILInstructionKind::EnumInst: {
+      auto *convInstr = cast<EnumInst>(instr);
       SILValue operand =
           convInstr->hasOperand() ? convInstr->getOperand() : SILValue();
       newInstr = resultTyBuilder.createEnum(
@@ -1971,7 +1967,7 @@
       llvm_unreachable("Unhandled aggrTy instr");
     }
     instr->replaceAllUsesWith(newInstr);
-    instr->getParent()->erase(instr);
+    instr->eraseFromParent();
   }
 
   for (MethodInst *instr : pass.methodInstsToMod) {
@@ -1993,19 +1989,19 @@
     MethodInst *newInstr = nullptr;
 
     switch (instr->getKind()) {
-    case ValueKind::ClassMethodInst: {
+    case SILInstructionKind::ClassMethodInst: {
       SILValue selfValue = instr->getOperand(0);
       newInstr = methodBuilder.createClassMethod(loc, selfValue, member,
                                                  newSILType, isVolatile);
       break;
     }
-    case ValueKind::SuperMethodInst: {
+    case SILInstructionKind::SuperMethodInst: {
       SILValue selfValue = instr->getOperand(0);
       newInstr = methodBuilder.createSuperMethod(loc, selfValue, member,
                                                  newSILType, isVolatile);
       break;
     }
-    case ValueKind::DynamicMethodInst: {
+    case SILInstructionKind::DynamicMethodInst: {
       auto *DMI = dyn_cast<DynamicMethodInst>(instr);
       assert(DMI && "ValueKind is Witness Method but dyn_cast failed");
       SILValue selfValue = instr->getOperand(0);
@@ -2013,7 +2009,7 @@
                                                    newSILType, isVolatile);
       break;
     }
-    case ValueKind::WitnessMethodInst: {
+    case SILInstructionKind::WitnessMethodInst: {
       auto *WMI = dyn_cast<WitnessMethodInst>(instr);
       assert(WMI && "ValueKind is Witness Method but dyn_cast failed");
       newInstr = methodBuilder.createWitnessMethod(
@@ -2045,7 +2041,7 @@
       auto IIR = instr->getReverseIterator();
       for (++IIR; IIR != instr->getParent()->rend(); ++IIR) {
         auto *currIIInstr = &(*IIR);
-        if (currIIInstr->getKind() != ValueKind::DeallocStackInst) {
+        if (currIIInstr->getKind() != SILInstructionKind::DeallocStackInst) {
           // got the right location - stop.
           --IIR;
           break;
@@ -2068,9 +2064,8 @@
     auto emptyTy = retBuilder.getModule().Types.getLoweredType(
         TupleType::getEmpty(retBuilder.getModule().getASTContext()));
     auto newRetTuple = retBuilder.createTuple(regLoc, emptyTy, {});
-    auto newRet = retBuilder.createReturn(newRetTuple->getLoc(), newRetTuple);
-    instr->replaceAllUsesWith(newRet);
-    instr->getParent()->erase(instr);
+    retBuilder.createReturn(newRetTuple->getLoc(), newRetTuple);
+    instr->eraseFromParent();
   }
 }
 
@@ -2222,11 +2217,10 @@
   // Collect common info
   ApplySite applySite = ApplySite(applyInst);
   SILValue callee = applySite.getCallee();
-  if (ApplySite::isa(callee)) {
+  if (auto site = ApplySite::isa(callee)) {
     // We need to re-create the callee's apply before recreating this one
     // else verification will fail with wrong SubstCalleeType
-    auto calleInstr = dyn_cast<SILInstruction>(callee);
-    assert(calleInstr && "Expected ApplySite Instr");
+    auto calleInstr = site.getInstruction();
     if (modApplies.find(calleInstr) != modApplies.end()) {
       recreateSingleApply(calleInstr);
       modApplies.erase(calleInstr);
@@ -2252,12 +2246,12 @@
   // If we turned a direct result into an indirect parameter
   // Find the new alloc we created earlier.
   // and pass it as first parameter:
-  if (applyInst->getKind() != ValueKind::PartialApplyInst &&
+  if (applyInst->getKind() != SILInstructionKind::PartialApplyInst &&
       modResultType(genEnv, origCanType, *currIRMod) &&
       modifiableApply(applySite, *getIRGenModule())) {
     assert(allApplyRetToAllocMap.find(applyInst) !=
            allApplyRetToAllocMap.end());
-    auto newAlloc = allApplyRetToAllocMap[applyInst];
+    auto newAlloc = allApplyRetToAllocMap.find(applyInst)->second;
     callArgs.push_back(newAlloc);
   }
   SmallVector<Substitution, 4> newSubs =
@@ -2270,39 +2264,35 @@
     callArgs.push_back(currOperand);
   }
   // Recreate apply with new operands due to substitution-type cache
-  SILInstruction *newApply = nullptr;
   switch (applyInst->getKind()) {
-  case ValueKind::ApplyInst: {
-    auto *castedApply = dyn_cast<ApplyInst>(applyInst);
-    assert(castedApply && "ValueKind is ApplyInst but cast to it failed");
-    newApply = applyBuilder.createApply(castedApply->getLoc(), callee, newSubs,
-                                        callArgs, castedApply->isNonThrowing());
-    applyInst->replaceAllUsesWith(newApply);
+  case SILInstructionKind::ApplyInst: {
+    auto *castedApply = cast<ApplyInst>(applyInst);
+    SILValue newApply =
+      applyBuilder.createApply(castedApply->getLoc(), callee, newSubs,
+                               callArgs, castedApply->isNonThrowing());
+    castedApply->replaceAllUsesWith(newApply);
     break;
   }
-  case ValueKind::TryApplyInst: {
-    auto *castedApply = dyn_cast<TryApplyInst>(applyInst);
-    assert(castedApply && "ValueKind is TryApplyInst but cast to it failed");
-    newApply = applyBuilder.createTryApply(
+  case SILInstructionKind::TryApplyInst: {
+    auto *castedApply = cast<TryApplyInst>(applyInst);
+    applyBuilder.createTryApply(
         castedApply->getLoc(), callee, newSubs, callArgs,
         castedApply->getNormalBB(), castedApply->getErrorBB());
-    applyInst->replaceAllUsesWith(newApply);
     break;
   }
-  case ValueKind::PartialApplyInst: {
-    auto *castedApply = dyn_cast<PartialApplyInst>(applyInst);
-    assert(castedApply &&
-           "ValueKind is PartialApplyInst but cast to it failed");
+  case SILInstructionKind::PartialApplyInst: {
+    auto *castedApply = cast<PartialApplyInst>(applyInst);
     // Change the type of the Closure
     auto partialApplyConvention = castedApply->getType()
                                       .getSwiftRValueType()
                                       ->getAs<SILFunctionType>()
                                       ->getCalleeConvention();
 
-    newApply = applyBuilder.createPartialApply(castedApply->getLoc(), callee,
-                                               newSubs, callArgs,
-                                               partialApplyConvention);
-    applyInst->replaceAllUsesWith(newApply);
+    auto newApply =
+      applyBuilder.createPartialApply(castedApply->getLoc(), callee,
+                                      newSubs, callArgs,
+                                      partialApplyConvention);
+    castedApply->replaceAllUsesWith(newApply);
     break;
   }
   default:
@@ -2351,7 +2341,7 @@
     SILType newType = getNewSILType(genEnv, origType, *currIRMod);
     auto caseTy = enumInstr->getOperand()->getType().getEnumElementType(
         enumInstr->getElement(), F->getModule());
-    SILInstruction *newInstr = nullptr;
+    SingleValueInstruction *newInstr = nullptr;
     if (caseTy != newType) {
       auto *takeEnum = enumBuilder.createUncheckedEnumData(
           enumInstr->getLoc(), enumInstr->getOperand(), enumInstr->getElement(),
@@ -2385,7 +2375,7 @@
     SILType newType = getNewSILType(genEnv, origType, *currIRMod);
     auto caseTy = enumInstr->getOperand()->getType().getEnumElementType(
         enumInstr->getElement(), F->getModule());
-    SILInstruction *newInstr = nullptr;
+    SingleValueInstruction *newInstr = nullptr;
     if (caseTy != origType.getObjectType()) {
       auto *takeEnum = enumBuilder.createUncheckedTakeEnumDataAddr(
           enumInstr->getLoc(), enumInstr->getOperand(), enumInstr->getElement(),
@@ -2405,9 +2395,7 @@
 void LoadableByAddress::fixStoreToBlockStorageInstrs() {
   for (auto *instr : storeToBlockStorageInstrs) {
     auto dest = instr->getDest();
-    ProjectBlockStorageInst *destBlock =
-        dyn_cast<ProjectBlockStorageInst>(dest);
-    assert(destBlock && "Expected Block Storage dest");
+    auto destBlock = cast<ProjectBlockStorageInst>(dest);
     SILType destType = destBlock->getType();
     auto src = instr->getSrc();
     SILType srcType = src->getType();
@@ -2447,28 +2435,23 @@
     SILType newType =
         getNewSILFunctionType(genEnv, currSILFunctionType, *currIRMod);
     SILBuilder convBuilder(convInstr);
-    SILInstruction *newInstr = nullptr;
+    SingleValueInstruction *newInstr = nullptr;
     switch (convInstr->getKind()) {
-    case ValueKind::ThinToThickFunctionInst: {
-      ThinToThickFunctionInst *instr =
-          dyn_cast<ThinToThickFunctionInst>(convInstr);
-      assert(instr && "Unexpected conversion instruction");
+    case SILInstructionKind::ThinToThickFunctionInst: {
+      auto instr = cast<ThinToThickFunctionInst>(convInstr);
       newInstr = convBuilder.createThinToThickFunction(
           instr->getLoc(), instr->getOperand(), newType);
       break;
     }
-    case ValueKind::ThinFunctionToPointerInst: {
-      ThinFunctionToPointerInst *instr =
-          dyn_cast<ThinFunctionToPointerInst>(convInstr);
-      assert(instr && "Unexpected conversion instruction");
+    case SILInstructionKind::ThinFunctionToPointerInst: {
+      auto instr = cast<ThinFunctionToPointerInst>(convInstr);
       newType = getNewSILType(genEnv, instr->getType(), *getIRGenModule());
       newInstr = convBuilder.createThinFunctionToPointer(
           instr->getLoc(), instr->getOperand(), newType);
       break;
     }
-    case ValueKind::ConvertFunctionInst: {
-      auto *instr = dyn_cast<ConvertFunctionInst>(convInstr);
-      assert(instr && "Unexpected conversion instruction");
+    case SILInstructionKind::ConvertFunctionInst: {
+      auto instr = cast<ConvertFunctionInst>(convInstr);
       newInstr = convBuilder.createConvertFunction(
           instr->getLoc(), instr->getOperand(), newType);
       break;
@@ -2549,26 +2532,27 @@
             for (auto *user : FRI->getUses()) {
               SILInstruction *currInstr = user->getUser();
               switch (currInstr->getKind()) {
-              case ValueKind::ApplyInst:
-              case ValueKind::TryApplyInst:
-              case ValueKind::PartialApplyInst: {
+              case SILInstructionKind::ApplyInst:
+              case SILInstructionKind::TryApplyInst:
+              case SILInstructionKind::PartialApplyInst: {
                 if (modApplies.count(currInstr) == 0) {
                   modApplies.insert(currInstr);
                 }
                 break;
               }
-              case ValueKind::ThinFunctionToPointerInst:
-              case ValueKind::ThinToThickFunctionInst: {
-                conversionInstrs.insert(currInstr);
+              case SILInstructionKind::ThinFunctionToPointerInst:
+              case SILInstructionKind::ThinToThickFunctionInst: {
+                conversionInstrs.insert(
+                              cast<SingleValueInstruction>(currInstr));
                 break;
               }
-              case ValueKind::BuiltinInst: {
-                auto *instr = dyn_cast<BuiltinInst>(currInstr);
+              case SILInstructionKind::BuiltinInst: {
+                auto *instr = cast<BuiltinInst>(currInstr);
                 builtinInstrs.insert(instr);
                 break;
               }
-              case ValueKind::DebugValueAddrInst:
-              case ValueKind::DebugValueInst: {
+              case SILInstructionKind::DebugValueAddrInst:
+              case SILInstructionKind::DebugValueInst: {
                 break;
               }
               default:
diff --git a/lib/IRGen/LocalTypeData.cpp b/lib/IRGen/LocalTypeData.cpp
index 3deddfb..fe2fc05 100644
--- a/lib/IRGen/LocalTypeData.cpp
+++ b/lib/IRGen/LocalTypeData.cpp
@@ -254,12 +254,34 @@
                                                     CanType type,
                                                     IsExact_t isExact,
                                                     llvm::Value *metadata) {
+  struct Callback : FulfillmentMap::InterestingKeysCallback {
+    bool isInterestingType(CanType type) const override {
+      return true;
+    }
+    bool hasInterestingType(CanType type) const override {
+      return true;
+    }
+    bool hasLimitedInterestingConformances(CanType type) const override {
+      return false;
+    }
+    GenericSignature::ConformsToArray
+    getInterestingConformances(CanType type) const override {
+      llvm_unreachable("no limits");
+    }
+    CanType getSuperclassBound(CanType type) const override {
+      if (auto arch = dyn_cast<ArchetypeType>(type))
+        if (auto superclassTy = arch->getSuperclass())
+          return superclassTy->getCanonicalType();
+      return CanType();
+    }
+  } callbacks;
+
   // Look for anything at all that's fulfilled by this.  If we don't find
   // anything, stop.
   FulfillmentMap fulfillments;
   if (!fulfillments.searchTypeMetadata(IGF.IGM, type, isExact,
                                        /*source*/ 0, MetadataPath(),
-                                       FulfillmentMap::Everything())) {
+                                       callbacks)) {
     return;
   }
 
diff --git a/lib/IRGen/MetadataLayout.cpp b/lib/IRGen/MetadataLayout.cpp
index 8fde127..fcda034 100644
--- a/lib/IRGen/MetadataLayout.cpp
+++ b/lib/IRGen/MetadataLayout.cpp
@@ -126,12 +126,6 @@
 
 /******************************* NOMINAL TYPES ********************************/
 
-Offset NominalMetadataLayout::getParentOffset(IRGenFunction &IGF) const {
-  assert(Parent.isValid());
-  assert(Parent.isStatic() && "resilient metadata layout unsupported!");
-  return Offset(Parent.getStaticOffset());
-}
-
 Size
 NominalMetadataLayout::getStaticGenericRequirementsOffset() const {
   assert(GenericRequirements.isValid());
@@ -146,24 +140,6 @@
   return Offset(GenericRequirements.getStaticOffset());
 }
 
-/// Given a reference to some metadata, derive a reference to the
-/// type's parent type.
-llvm::Value *irgen::emitParentMetadataRef(IRGenFunction &IGF,
-                                          NominalTypeDecl *decl,
-                                          llvm::Value *metadata) {
-  auto slot = emitAddressOfParentMetadataSlot(IGF, metadata, decl);
-  return IGF.emitInvariantLoad(slot);
-}
-
-Address irgen::emitAddressOfParentMetadataSlot(IRGenFunction &IGF,
-                                               llvm::Value *metadata,
-                                               NominalTypeDecl *decl) {
-  auto offset = IGF.IGM.getMetadataLayout(decl).getParentOffset(IGF);
-  return IGF.emitAddressAtOffset(metadata, offset,
-                                 IGF.IGM.TypeMetadataPtrTy,
-                                 IGF.IGM.getPointerAlignment());
-}
-
 static llvm::Value *emitLoadOfGenericRequirement(IRGenFunction &IGF,
                                                  llvm::Value *metadata,
                                                  NominalTypeDecl *decl,
@@ -246,12 +222,6 @@
       super::addInstanceAlignMask();
     }
 
-    void addParentMetadataRef(ClassDecl *forClass, Type classType) {
-      if (forClass == Target)
-        Layout.Parent = getNextOffset();
-      super::addParentMetadataRef(forClass, classType);
-    }
-
     void noteStartOfGenericRequirements(ClassDecl *forClass) {
       if (forClass == Target)
         Layout.GenericRequirements = getNextOffset();
@@ -404,11 +374,6 @@
       super::addPayloadSize();
     }
 
-    void addParentMetadataRef() {
-      Layout.Parent = getNextOffset();
-      super::addParentMetadataRef();
-    }
-
     void noteStartOfGenericRequirements() {
       Layout.GenericRequirements = getNextOffset();
       super::noteStartOfGenericRequirements();
@@ -441,11 +406,6 @@
     Scanner(IRGenModule &IGM, StructDecl *decl, StructMetadataLayout &layout)
       : super(IGM, decl), Layout(layout) {}
 
-    void addParentMetadataRef() {
-      Layout.Parent = getNextOffset();
-      super::addParentMetadataRef();
-    }
-
     void noteStartOfGenericRequirements() {
       Layout.GenericRequirements = getNextOffset();
       super::noteStartOfGenericRequirements();
diff --git a/lib/IRGen/MetadataLayout.h b/lib/IRGen/MetadataLayout.h
index 1c817ad..42ec292 100644
--- a/lib/IRGen/MetadataLayout.h
+++ b/lib/IRGen/MetadataLayout.h
@@ -120,7 +120,6 @@
 class NominalMetadataLayout : public MetadataLayout {
 protected:
   StoredOffset GenericRequirements;
-  StoredOffset Parent;
 
   NominalMetadataLayout(Kind kind) : MetadataLayout(kind) {}
 
@@ -134,8 +133,6 @@
 
   Offset getGenericRequirementsOffset(IRGenFunction &IGF) const;
 
-  Offset getParentOffset(IRGenFunction &IGF) const;
-
   static bool classof(const MetadataLayout *layout) {
     return true; // No non-nominal metadata for now.
   }
@@ -287,11 +284,6 @@
   }
 };
 
-/// Emit the address of the 'parent' slot in the given nominal-type metadata.
-Address emitAddressOfParentMetadataSlot(IRGenFunction &IGF,
-                                        llvm::Value *metadata,
-                                        NominalTypeDecl *decl);
-
 /// Emit the address of the field-offset slot in the given class metadata.
 Address emitAddressOfClassFieldOffset(IRGenFunction &IGF,
                                       llvm::Value *metadata,
diff --git a/lib/IRGen/MetadataPath.h b/lib/IRGen/MetadataPath.h
index 001cae0..0dd1566 100644
--- a/lib/IRGen/MetadataPath.h
+++ b/lib/IRGen/MetadataPath.h
@@ -61,9 +61,6 @@
 
       // Everything past this point has no index.
 
-      /// The parent metadata of a nominal type.
-      NominalParent,
-
       /// An impossible path.
       Impossible,
     };
@@ -102,7 +99,6 @@
       case Kind::OutOfLineBaseProtocol:
       case Kind::NominalTypeArgumentConformance:
       case Kind::NominalTypeArgument:
-      case Kind::NominalParent:
         return OperationCost::Load;
 
       case Kind::AssociatedConformance:
@@ -144,11 +140,6 @@
     Path.push_back(Component(Component::Kind::Impossible));
   }
 
-  /// Add a step to this path which gets the parent metadata.
-  void addNominalParentComponent() {
-    Path.push_back(Component(Component::Kind::NominalParent));
-  }
-
   /// Add a step to this path which gets the type metadata stored at
   /// requirement index n in a generic type metadata.
   void addNominalTypeArgumentComponent(unsigned index) {
@@ -208,9 +199,6 @@
 
     for (auto C : Path) {
       switch (C.getKind()) {
-      case Component::Kind::NominalParent:
-        Root = A.createParent(Root);
-        continue;
       case Component::Kind::NominalTypeArgument:
         Root = A.createGenericArgument(C.getPrimaryIndex(), Root);
         continue;
diff --git a/lib/IRGen/NominalMetadataVisitor.h b/lib/IRGen/NominalMetadataVisitor.h
index 214032f..3944a4e 100644
--- a/lib/IRGen/NominalMetadataVisitor.h
+++ b/lib/IRGen/NominalMetadataVisitor.h
@@ -67,8 +67,7 @@
     GenericTypeRequirements requirements(IGM, typeDecl);
     if (requirements.empty()) return;
 
-    auto subs = type->castTo<BoundGenericType>()
-                    ->getContextSubstitutionMap(IGM.getSwiftModule(),
+    auto subs = type->getContextSubstitutionMap(IGM.getSwiftModule(),
                                                 typeDecl);
     requirements.enumerateFulfillments(IGM, subs,
                     [&](unsigned reqtIndex, CanType argType,
diff --git a/lib/IRGen/StructMetadataVisitor.h b/lib/IRGen/StructMetadataVisitor.h
index 3910b75..17dc558 100644
--- a/lib/IRGen/StructMetadataVisitor.h
+++ b/lib/IRGen/StructMetadataVisitor.h
@@ -47,7 +47,6 @@
 
     // StructMetadata header.
     asImpl().addNominalTypeDescriptor();
-    asImpl().addParentMetadataRef();
 
     // If changing this layout, you must update the magic number in
     // emitParentMetadataRef.
@@ -80,7 +79,6 @@
   void addMetadataFlags() { addPointer(); }
   void addValueWitnessTable() { addPointer(); }
   void addNominalTypeDescriptor() { addPointer(); }
-  void addParentMetadataRef() { addPointer(); }
   void addFieldOffset(VarDecl*) { addPointer(); }
   void addGenericArgument(CanType argument) { addPointer(); }
   void addGenericWitnessTable(CanType argument, ProtocolConformanceRef conf) {
diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp
index c7b950c..79565bb 100644
--- a/lib/Parse/ParseStmt.cpp
+++ b/lib/Parse/ParseStmt.cpp
@@ -579,7 +579,12 @@
 ParserResult<BraceStmt> Parser::parseBraceItemList(Diag<> ID) {
   if (Tok.isNot(tok::l_brace)) {
     diagnose(Tok, ID);
-    return nullptr;
+
+    // Attempt to recover by looking for a left brace on the same line
+    while (Tok.isNot(tok::eof, tok::l_brace) && !Tok.isAtStartOfLine())
+      skipSingle();
+    if (Tok.isNot(tok::l_brace))
+      return nullptr;
   }
   SourceLoc LBLoc = consumeToken(tok::l_brace);
 
diff --git a/lib/ParseSIL/ParseSIL.cpp b/lib/ParseSIL/ParseSIL.cpp
index 0e1526f..f389d26 100644
--- a/lib/ParseSIL/ParseSIL.cpp
+++ b/lib/ParseSIL/ParseSIL.cpp
@@ -352,7 +352,7 @@
       SourceLoc Tmp;
       return parseTypedValueRef(Result, Tmp, B);
     }
-    bool parseSILOpcode(ValueKind &Opcode, SourceLoc &OpcodeLoc,
+    bool parseSILOpcode(SILInstructionKind &Opcode, SourceLoc &OpcodeLoc,
                         StringRef &OpcodeName);
     bool parseSILDebugVar(SILDebugVariable &Var);
 
@@ -365,7 +365,7 @@
                                bool parsedComma = false);
     bool parseSILInstruction(SILBuilder &B);
     bool parseCallInstruction(SILLocation InstLoc,
-                              ValueKind Opcode, SILBuilder &B,
+                              SILInstructionKind Opcode, SILBuilder &B,
                               SILInstruction *&ResultVal);
     bool parseSILFunctionRef(SILLocation InstLoc, SILFunction *&ResultFn);
 
@@ -1389,16 +1389,16 @@
 
 /// getInstructionKind - This method maps the string form of a SIL instruction
 /// opcode to an enum.
-bool SILParser::parseSILOpcode(ValueKind &Opcode, SourceLoc &OpcodeLoc,
+bool SILParser::parseSILOpcode(SILInstructionKind &Opcode, SourceLoc &OpcodeLoc,
                                StringRef &OpcodeName) {
   OpcodeLoc = P.Tok.getLoc();
   OpcodeName = P.Tok.getText();
   // Parse this textually to avoid Swift keywords (like 'return') from
   // interfering with opcode recognition.
-  Optional<ValueKind> MaybeOpcode =
-      llvm::StringSwitch<Optional<ValueKind>>(OpcodeName)
-#define INST(Id, Parent, TextualName, MemBehavior, MayRelease)                 \
-  .Case(#TextualName, ValueKind::Id)
+  Optional<SILInstructionKind> MaybeOpcode =
+      llvm::StringSwitch<Optional<SILInstructionKind>>(OpcodeName)
+#define FULL_INST(Id, TextualName, Parent, MemBehavior, MayRelease) \
+  .Case(#TextualName, SILInstructionKind::Id)
 #include "swift/SIL/SILNodes.def"
           .Default(None);
 
@@ -1815,19 +1815,46 @@
     return true;
   }
 
-  StringRef ResultName;
-  SourceLoc ResultNameLoc;
+  SmallVector<std::pair<StringRef, SourceLoc>, 4> resultNames;
+  SourceLoc resultClauseBegin;
 
   // If the instruction has a name '%foo =', parse it.
   if (P.Tok.is(tok::sil_local_name)) {
-    ResultName = P.Tok.getText();
-    ResultNameLoc = P.Tok.getLoc();
+    resultClauseBegin = P.Tok.getLoc();
+    resultNames.push_back(std::make_pair(P.Tok.getText(), P.Tok.getLoc()));
     P.consumeToken(tok::sil_local_name);
+
+  // If the instruction has a '(%foo, %bar) = ', parse it.
+  } else if (P.consumeIf(tok::l_paren)) {
+    resultClauseBegin = P.PreviousLoc;
+
+    if (!P.consumeIf(tok::r_paren)) {
+      while (true) {
+        if (!P.Tok.is(tok::sil_local_name)) {
+          P.diagnose(P.Tok, diag::expected_sil_value_name);
+          return true;
+        }
+
+        resultNames.push_back(std::make_pair(P.Tok.getText(), P.Tok.getLoc()));
+        P.consumeToken(tok::sil_local_name);
+
+        if (P.consumeIf(tok::comma))
+          continue;
+        if (P.consumeIf(tok::r_paren))
+          break;
+
+        P.diagnose(P.Tok, diag::expected_tok_in_sil_instr, ",");
+        return true;
+      }
+    }
+  }
+
+  if (resultClauseBegin.isValid()) {
     if (P.parseToken(tok::equal, diag::expected_equal_in_sil_instr))
       return true;
   }
-  
-  ValueKind Opcode;
+
+  SILInstructionKind Opcode;
   SourceLoc OpcodeLoc;
   StringRef OpcodeName;
   
@@ -1895,12 +1922,7 @@
   // opcode we find.
   SILInstruction *ResultVal;
   switch (Opcode) {
-  case ValueKind::SILPHIArgument:
-  case ValueKind::SILFunctionArgument:
-  case ValueKind::SILUndef:
-    llvm_unreachable("not an instruction");
-
-  case ValueKind::AllocBoxInst: {
+  case SILInstructionKind::AllocBoxInst: {
     SILType Ty;
     if (parseSILType(Ty)) return true;
     SILDebugVariable VarInfo;
@@ -1911,13 +1933,13 @@
     ResultVal = B.createAllocBox(InstLoc, Ty.castTo<SILBoxType>(), VarInfo);
     break;
   }
-  case ValueKind::ApplyInst:
-  case ValueKind::PartialApplyInst:
-  case ValueKind::TryApplyInst:
+  case SILInstructionKind::ApplyInst:
+  case SILInstructionKind::PartialApplyInst:
+  case SILInstructionKind::TryApplyInst:
     if (parseCallInstruction(InstLoc, Opcode, B, ResultVal))
       return true;
     break;
-  case ValueKind::IntegerLiteralInst: {
+  case SILInstructionKind::IntegerLiteralInst: {
     SILType Ty;
     if (parseSILType(Ty) ||
         P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ","))
@@ -1955,7 +1977,7 @@
     ResultVal = B.createIntegerLiteral(InstLoc, Ty, value);
     break;
   }
-  case ValueKind::FloatLiteralInst: {
+  case SILInstructionKind::FloatLiteralInst: {
     SILType Ty;
     if (parseSILType(Ty) ||
         P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ","))
@@ -1988,7 +2010,7 @@
     P.consumeToken(tok::integer_literal);
     break;
   }
-  case ValueKind::StringLiteralInst: {
+  case SILInstructionKind::StringLiteralInst: {
     if (P.Tok.getKind() != tok::identifier) {
       P.diagnose(P.Tok, diag::sil_string_no_encoding);
       return true;
@@ -2025,7 +2047,7 @@
     break;
   }
 
-  case ValueKind::ConstStringLiteralInst: {
+  case SILInstructionKind::ConstStringLiteralInst: {
     if (P.Tok.getKind() != tok::identifier) {
       P.diagnose(P.Tok, diag::sil_string_no_encoding);
       return true;
@@ -2060,7 +2082,7 @@
     break;
   }
 
-  case ValueKind::AllocValueBufferInst: {
+  case SILInstructionKind::AllocValueBufferInst: {
     SILType Ty;
     if (parseSILType(Ty) ||
         parseVerbatim("in") ||
@@ -2070,7 +2092,7 @@
     ResultVal = B.createAllocValueBuffer(InstLoc, Ty, Val);
     break;
   }
-  case ValueKind::ProjectValueBufferInst: {
+  case SILInstructionKind::ProjectValueBufferInst: {
     SILType Ty;
     if (parseSILType(Ty) ||
         parseVerbatim("in") ||
@@ -2080,7 +2102,7 @@
     ResultVal = B.createProjectValueBuffer(InstLoc, Ty, Val);
     break;
   }
-  case ValueKind::DeallocValueBufferInst: {
+  case SILInstructionKind::DeallocValueBufferInst: {
     SILType Ty;
     if (parseSILType(Ty) ||
         parseVerbatim("in") ||
@@ -2091,7 +2113,7 @@
     break;
   }
 
-  case ValueKind::ProjectBoxInst: {
+  case SILInstructionKind::ProjectBoxInst: {
     if (parseTypedValueRef(Val, B) ||
         P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ","))
       return true;
@@ -2114,7 +2136,7 @@
     break;
   }
       
-  case ValueKind::ProjectExistentialBoxInst: {
+  case SILInstructionKind::ProjectExistentialBoxInst: {
     SILType Ty;
     if (parseSILType(Ty) ||
         parseVerbatim("in") ||
@@ -2125,7 +2147,7 @@
     break;
   }
       
-  case ValueKind::FunctionRefInst: {
+  case SILInstructionKind::FunctionRefInst: {
     SILFunction *Fn;
     if (parseSILFunctionRef(InstLoc, Fn) ||
         parseSILDebugLocation(InstLoc, B))
@@ -2133,7 +2155,7 @@
     ResultVal = B.createFunctionRef(InstLoc, Fn);
     break;
   }
-  case ValueKind::BuiltinInst: {
+  case SILInstructionKind::BuiltinInst: {
     if (P.Tok.getKind() != tok::string_literal) {
       P.diagnose(P.Tok, diag::expected_tok_in_sil_instr,"builtin name");
       return true;
@@ -2208,7 +2230,7 @@
     ResultVal = B.createBuiltin(InstLoc, Id, ResultTy, subs, Args);
     break;
   }
-  case ValueKind::OpenExistentialAddrInst:
+  case SILInstructionKind::OpenExistentialAddrInst:
     if (parseOpenExistAddrKind() || parseTypedValueRef(Val, B)
         || parseVerbatim("to") || parseSILType(Ty)
         || parseSILDebugLocation(InstLoc, B))
@@ -2217,7 +2239,7 @@
     ResultVal = B.createOpenExistentialAddr(InstLoc, Val, Ty, AccessKind);
     break;
 
-  case ValueKind::OpenExistentialBoxInst:
+  case SILInstructionKind::OpenExistentialBoxInst:
     if (parseTypedValueRef(Val, B) || parseVerbatim("to") || parseSILType(Ty)
         || parseSILDebugLocation(InstLoc, B))
       return true;
@@ -2225,28 +2247,28 @@
     ResultVal = B.createOpenExistentialBox(InstLoc, Val, Ty);
     break;
 
-  case ValueKind::OpenExistentialBoxValueInst:
+  case SILInstructionKind::OpenExistentialBoxValueInst:
     if (parseTypedValueRef(Val, B) || parseVerbatim("to") || parseSILType(Ty)
         || parseSILDebugLocation(InstLoc, B))
       return true;
     ResultVal = B.createOpenExistentialBoxValue(InstLoc, Val, Ty);
     break;
 
-  case ValueKind::OpenExistentialMetatypeInst:
+  case SILInstructionKind::OpenExistentialMetatypeInst:
     if (parseTypedValueRef(Val, B) || parseVerbatim("to") || parseSILType(Ty)
         || parseSILDebugLocation(InstLoc, B))
       return true;
     ResultVal = B.createOpenExistentialMetatype(InstLoc, Val, Ty);
     break;
 
-  case ValueKind::OpenExistentialRefInst:
+  case SILInstructionKind::OpenExistentialRefInst:
     if (parseTypedValueRef(Val, B) || parseVerbatim("to") || parseSILType(Ty)
         || parseSILDebugLocation(InstLoc, B))
       return true;
     ResultVal = B.createOpenExistentialRef(InstLoc, Val, Ty);
     break;
 
-  case ValueKind::OpenExistentialValueInst:
+  case SILInstructionKind::OpenExistentialValueInst:
     if (parseTypedValueRef(Val, B) || parseVerbatim("to") || parseSILType(Ty)
         || parseSILDebugLocation(InstLoc, B))
       return true;
@@ -2254,14 +2276,14 @@
     break;
 
 #define UNARY_INSTRUCTION(ID) \
-  case ValueKind::ID##Inst:                   \
+  case SILInstructionKind::ID##Inst:                   \
     if (parseTypedValueRef(Val, B)) return true; \
     if (parseSILDebugLocation(InstLoc, B)) return true; \
     ResultVal = B.create##ID(InstLoc, Val);   \
     break;
 
 #define REFCOUNTING_INSTRUCTION(ID)                                            \
-  case ValueKind::ID##Inst: {                                                  \
+  case SILInstructionKind::ID##Inst: {                                                  \
     Atomicity atomicity = Atomicity::Atomic;                                   \
     StringRef Optional;                                                        \
     if (parseSILOptional(Optional, *this)) {                                   \
@@ -2308,14 +2330,14 @@
 #undef UNARY_INSTRUCTION
 #undef REFCOUNTING_INSTRUCTION
 
- case ValueKind::DebugValueInst:
- case ValueKind::DebugValueAddrInst: {
+ case SILInstructionKind::DebugValueInst:
+ case SILInstructionKind::DebugValueAddrInst: {
    SILDebugVariable VarInfo;
    if (parseTypedValueRef(Val, B) ||
        parseSILDebugVar(VarInfo) ||
        parseSILDebugLocation(InstLoc, B))
      return true;
-   if (Opcode == ValueKind::DebugValueInst)
+   if (Opcode == SILInstructionKind::DebugValueInst)
      ResultVal = B.createDebugValue(InstLoc, Val, VarInfo);
    else
      ResultVal = B.createDebugValueAddr(InstLoc, Val, VarInfo);
@@ -2323,7 +2345,7 @@
  }
 
  // unchecked_ownership_conversion <reg> : <type>, <ownership> to <ownership>
- case ValueKind::UncheckedOwnershipConversionInst: {
+ case SILInstructionKind::UncheckedOwnershipConversionInst: {
    ValueOwnershipKind LHSKind = ValueOwnershipKind::Any;
    ValueOwnershipKind RHSKind = ValueOwnershipKind::Any;
    SourceLoc Loc;
@@ -2345,7 +2367,7 @@
    break;
  }
 
- case ValueKind::LoadInst: {
+ case SILInstructionKind::LoadInst: {
    LoadOwnershipQualifier Qualifier;
    SourceLoc AddrLoc;
 
@@ -2357,7 +2379,7 @@
    break;
  }
 
- case ValueKind::LoadBorrowInst: {
+ case SILInstructionKind::LoadBorrowInst: {
    SourceLoc AddrLoc;
 
    if (parseTypedValueRef(Val, AddrLoc, B) || parseSILDebugLocation(InstLoc, B))
@@ -2367,7 +2389,7 @@
    break;
  }
 
- case ValueKind::BeginBorrowInst: {
+ case SILInstructionKind::BeginBorrowInst: {
    SourceLoc AddrLoc;
 
    if (parseTypedValueRef(Val, AddrLoc, B) || parseSILDebugLocation(InstLoc, B))
@@ -2377,8 +2399,8 @@
    break;
  }
 
- case ValueKind::LoadUnownedInst:
- case ValueKind::LoadWeakInst: {
+ case SILInstructionKind::LoadUnownedInst:
+ case SILInstructionKind::LoadWeakInst: {
    bool isTake = false;
    SourceLoc addrLoc;
    if (parseSILOptional(isTake, *this, "take") ||
@@ -2386,7 +2408,7 @@
        parseSILDebugLocation(InstLoc, B))
      return true;
 
-   if (Opcode == ValueKind::LoadUnownedInst) {
+   if (Opcode == SILInstructionKind::LoadUnownedInst) {
      if (!Val->getType().is<UnownedStorageType>()) {
        P.diagnose(addrLoc, diag::sil_operand_not_unowned_address, "source",
                   OpcodeName);
@@ -2404,7 +2426,7 @@
    break;
   }
 
-  case ValueKind::MarkDependenceInst: {
+  case SILInstructionKind::MarkDependenceInst: {
     SILValue Base;
     if (parseTypedValueRef(Val, B) ||
         parseVerbatim("on") ||
@@ -2416,7 +2438,7 @@
     break;
   }
 
-  case ValueKind::KeyPathInst: {
+  case SILInstructionKind::KeyPathInst: {
     SmallVector<KeyPathPatternComponent, 4> components;
     SILType Ty;
     if (parseSILType(Ty)
@@ -2762,28 +2784,28 @@
   }
 
   // Conversion instructions.
-  case ValueKind::UncheckedRefCastInst:
-  case ValueKind::UncheckedAddrCastInst:
-  case ValueKind::UncheckedTrivialBitCastInst:
-  case ValueKind::UncheckedBitwiseCastInst:
-  case ValueKind::UpcastInst:
-  case ValueKind::AddressToPointerInst:
-  case ValueKind::BridgeObjectToRefInst:
-  case ValueKind::BridgeObjectToWordInst:
-  case ValueKind::RefToRawPointerInst:
-  case ValueKind::RawPointerToRefInst:
-  case ValueKind::RefToUnownedInst:
-  case ValueKind::UnownedToRefInst:
-  case ValueKind::RefToUnmanagedInst:
-  case ValueKind::UnmanagedToRefInst:
-  case ValueKind::ThinFunctionToPointerInst:
-  case ValueKind::PointerToThinFunctionInst:
-  case ValueKind::ThinToThickFunctionInst:
-  case ValueKind::ThickToObjCMetatypeInst:
-  case ValueKind::ObjCToThickMetatypeInst:
-  case ValueKind::ConvertFunctionInst:
-  case ValueKind::ObjCExistentialMetatypeToObjectInst:
-  case ValueKind::ObjCMetatypeToObjectInst: {
+  case SILInstructionKind::UncheckedRefCastInst:
+  case SILInstructionKind::UncheckedAddrCastInst:
+  case SILInstructionKind::UncheckedTrivialBitCastInst:
+  case SILInstructionKind::UncheckedBitwiseCastInst:
+  case SILInstructionKind::UpcastInst:
+  case SILInstructionKind::AddressToPointerInst:
+  case SILInstructionKind::BridgeObjectToRefInst:
+  case SILInstructionKind::BridgeObjectToWordInst:
+  case SILInstructionKind::RefToRawPointerInst:
+  case SILInstructionKind::RawPointerToRefInst:
+  case SILInstructionKind::RefToUnownedInst:
+  case SILInstructionKind::UnownedToRefInst:
+  case SILInstructionKind::RefToUnmanagedInst:
+  case SILInstructionKind::UnmanagedToRefInst:
+  case SILInstructionKind::ThinFunctionToPointerInst:
+  case SILInstructionKind::PointerToThinFunctionInst:
+  case SILInstructionKind::ThinToThickFunctionInst:
+  case SILInstructionKind::ThickToObjCMetatypeInst:
+  case SILInstructionKind::ObjCToThickMetatypeInst:
+  case SILInstructionKind::ConvertFunctionInst:
+  case SILInstructionKind::ObjCExistentialMetatypeToObjectInst:
+  case SILInstructionKind::ObjCMetatypeToObjectInst: {
     SILType Ty;
     Identifier ToToken;
     SourceLoc ToLoc;
@@ -2801,76 +2823,76 @@
 
     switch (Opcode) {
     default: llvm_unreachable("Out of sync with parent switch");
-    case ValueKind::UncheckedRefCastInst:
+    case SILInstructionKind::UncheckedRefCastInst:
       ResultVal = B.createUncheckedRefCast(InstLoc, Val, Ty);
       break;
-    case ValueKind::UncheckedAddrCastInst:
+    case SILInstructionKind::UncheckedAddrCastInst:
       ResultVal = B.createUncheckedAddrCast(InstLoc, Val, Ty);
       break;
-    case ValueKind::UncheckedTrivialBitCastInst:
+    case SILInstructionKind::UncheckedTrivialBitCastInst:
       ResultVal = B.createUncheckedTrivialBitCast(InstLoc, Val, Ty);
       break;
-    case ValueKind::UncheckedBitwiseCastInst:
+    case SILInstructionKind::UncheckedBitwiseCastInst:
       ResultVal = B.createUncheckedBitwiseCast(InstLoc, Val, Ty);
       break;
-    case ValueKind::UpcastInst:
+    case SILInstructionKind::UpcastInst:
       ResultVal = B.createUpcast(InstLoc, Val, Ty);
       break;
-    case ValueKind::ConvertFunctionInst:
+    case SILInstructionKind::ConvertFunctionInst:
       ResultVal = B.createConvertFunction(InstLoc, Val, Ty);
       break;
-    case ValueKind::AddressToPointerInst:
+    case SILInstructionKind::AddressToPointerInst:
       ResultVal = B.createAddressToPointer(InstLoc, Val, Ty);
       break;
-    case ValueKind::BridgeObjectToRefInst:
+    case SILInstructionKind::BridgeObjectToRefInst:
       ResultVal = B.createBridgeObjectToRef(InstLoc, Val, Ty);
       break;
-    case ValueKind::BridgeObjectToWordInst:
+    case SILInstructionKind::BridgeObjectToWordInst:
       ResultVal = B.createBridgeObjectToWord(InstLoc, Val);
       break;
-    case ValueKind::RefToRawPointerInst:
+    case SILInstructionKind::RefToRawPointerInst:
       ResultVal = B.createRefToRawPointer(InstLoc, Val, Ty);
       break;
-    case ValueKind::RawPointerToRefInst:
+    case SILInstructionKind::RawPointerToRefInst:
       ResultVal = B.createRawPointerToRef(InstLoc, Val, Ty);
       break;
-    case ValueKind::RefToUnownedInst:
+    case SILInstructionKind::RefToUnownedInst:
       ResultVal = B.createRefToUnowned(InstLoc, Val, Ty);
       break;
-    case ValueKind::UnownedToRefInst:
+    case SILInstructionKind::UnownedToRefInst:
       ResultVal = B.createUnownedToRef(InstLoc, Val, Ty);
       break;
-    case ValueKind::RefToUnmanagedInst:
+    case SILInstructionKind::RefToUnmanagedInst:
       ResultVal = B.createRefToUnmanaged(InstLoc, Val, Ty);
       break;
-    case ValueKind::UnmanagedToRefInst:
+    case SILInstructionKind::UnmanagedToRefInst:
       ResultVal = B.createUnmanagedToRef(InstLoc, Val, Ty);
       break;
-    case ValueKind::ThinFunctionToPointerInst:
+    case SILInstructionKind::ThinFunctionToPointerInst:
       ResultVal = B.createThinFunctionToPointer(InstLoc, Val, Ty);
       break;
-    case ValueKind::PointerToThinFunctionInst:
+    case SILInstructionKind::PointerToThinFunctionInst:
       ResultVal = B.createPointerToThinFunction(InstLoc, Val, Ty);
       break;
-    case ValueKind::ThinToThickFunctionInst:
+    case SILInstructionKind::ThinToThickFunctionInst:
       ResultVal = B.createThinToThickFunction(InstLoc, Val, Ty);
       break;
-    case ValueKind::ThickToObjCMetatypeInst:
+    case SILInstructionKind::ThickToObjCMetatypeInst:
       ResultVal = B.createThickToObjCMetatype(InstLoc, Val, Ty);
       break;
-    case ValueKind::ObjCToThickMetatypeInst:
+    case SILInstructionKind::ObjCToThickMetatypeInst:
       ResultVal = B.createObjCToThickMetatype(InstLoc, Val, Ty);
       break;
-    case ValueKind::ObjCMetatypeToObjectInst:
+    case SILInstructionKind::ObjCMetatypeToObjectInst:
       ResultVal = B.createObjCMetatypeToObject(InstLoc, Val, Ty);
       break;
-    case ValueKind::ObjCExistentialMetatypeToObjectInst:
+    case SILInstructionKind::ObjCExistentialMetatypeToObjectInst:
       ResultVal = B.createObjCExistentialMetatypeToObject(InstLoc, Val, Ty);
       break;
     }
     break;
   }
-  case ValueKind::PointerToAddressInst: {
+  case SILInstructionKind::PointerToAddressInst: {
     SILType Ty;
     Identifier ToToken;
     SourceLoc ToLoc;
@@ -2897,7 +2919,7 @@
                                          isStrict, isInvariant);
     break;
   }
-  case ValueKind::RefToBridgeObjectInst: {
+  case SILInstructionKind::RefToBridgeObjectInst: {
     SILValue BitsVal;
     if (parseTypedValueRef(Val, B) ||
         P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") ||
@@ -2908,7 +2930,7 @@
     break;
   }
 
-  case ValueKind::CheckedCastAddrBranchInst: {
+  case SILInstructionKind::CheckedCastAddrBranchInst: {
     Identifier consumptionKindToken;
     SourceLoc consumptionKindLoc;
     if (parseSILIdentifier(consumptionKindToken, consumptionKindLoc,
@@ -2940,7 +2962,7 @@
         getBBForReference(FailureBBName, FailureBBLoc));
     break;
   }
-  case ValueKind::UncheckedRefCastAddrInst:
+  case SILInstructionKind::UncheckedRefCastAddrInst:
     if (parseSourceAndDestAddress() || parseSILDebugLocation(InstLoc, B))
       return true;
 
@@ -2948,7 +2970,7 @@
                                              DestAddr, TargetType);
     break;
 
-  case ValueKind::UnconditionalCheckedCastAddrInst:
+  case SILInstructionKind::UnconditionalCheckedCastAddrInst:
     if (parseSourceAndDestAddress() || parseSILDebugLocation(InstLoc, B))
       return true;
 
@@ -2956,7 +2978,7 @@
         InstLoc, SourceAddr, SourceType, DestAddr, TargetType);
     break;
 
-  case ValueKind::UnconditionalCheckedCastValueInst:
+  case SILInstructionKind::UnconditionalCheckedCastValueInst:
     if (parseTypedValueRef(Val, B) || parseVerbatim("to") || parseSILType(Ty)
         || parseSILDebugLocation(InstLoc, B))
       return true;
@@ -2964,7 +2986,7 @@
     ResultVal = B.createUnconditionalCheckedCastValue(InstLoc, Val, Ty);
     break;
 
-  case ValueKind::UnconditionalCheckedCastInst:
+  case SILInstructionKind::UnconditionalCheckedCastInst:
     if (parseTypedValueRef(Val, B) || parseVerbatim("to") || parseSILType(Ty))
       return true;
 
@@ -2974,9 +2996,9 @@
     ResultVal = B.createUnconditionalCheckedCast(InstLoc, Val, Ty);
     break;
 
-  case ValueKind::CheckedCastBranchInst: {
+  case SILInstructionKind::CheckedCastBranchInst: {
     bool isExact = false;
-    if (Opcode == ValueKind::CheckedCastBranchInst &&
+    if (Opcode == SILInstructionKind::CheckedCastBranchInst &&
         parseSILOptional(isExact, *this, "exact"))
       return true;
 
@@ -2990,7 +3012,7 @@
         getBBForReference(FailureBBName, FailureBBLoc));
     break;
   }
-  case ValueKind::CheckedCastValueBranchInst:
+  case SILInstructionKind::CheckedCastValueBranchInst:
     if (parseTypedValueRef(Val, B) || parseVerbatim("to") || parseSILType(Ty)
         || parseConditionalBranchDestinations())
       return true;
@@ -3000,7 +3022,7 @@
         getBBForReference(FailureBBName, FailureBBLoc));
     break;
 
-  case ValueKind::MarkUninitializedInst: {
+  case SILInstructionKind::MarkUninitializedInst: {
     if (P.parseToken(tok::l_square, diag::expected_tok_in_sil_instr, "["))
       return true;
     
@@ -3040,7 +3062,7 @@
     break;
   }
   
-  case ValueKind::MarkUninitializedBehaviorInst: {
+  case SILInstructionKind::MarkUninitializedBehaviorInst: {
     UnresolvedValueName InitStorageFuncName, StorageName,
                         SetterFuncName, SelfName;
     SmallVector<ParsedSubstitution, 4> ParsedInitStorageSubs,
@@ -3109,7 +3131,7 @@
     break;
   }
   
-  case ValueKind::MarkFunctionEscapeInst: {
+  case SILInstructionKind::MarkFunctionEscapeInst: {
     SmallVector<SILValue, 4> OpList;
     do {
       if (parseTypedValueRef(Val, B)) return true;
@@ -3122,7 +3144,7 @@
     break;
   }
 
-  case ValueKind::StoreInst: {
+  case SILInstructionKind::StoreInst: {
     UnresolvedValueName From;
     SourceLoc ToLoc, AddrLoc;
     Identifier ToToken;
@@ -3158,7 +3180,7 @@
     break;
   }
 
-  case ValueKind::EndBorrowInst: {
+  case SILInstructionKind::EndBorrowInst: {
     UnresolvedValueName BorrowedFromName, BorrowedValueName;
     SourceLoc ToLoc;
     Identifier ToToken;
@@ -3188,18 +3210,18 @@
     break;
   }
 
-  case ValueKind::BeginAccessInst:
-  case ValueKind::BeginUnpairedAccessInst:
-  case ValueKind::EndAccessInst:
-  case ValueKind::EndUnpairedAccessInst: {
+  case SILInstructionKind::BeginAccessInst:
+  case SILInstructionKind::BeginUnpairedAccessInst:
+  case SILInstructionKind::EndAccessInst:
+  case SILInstructionKind::EndUnpairedAccessInst: {
     ParsedEnum<SILAccessKind> kind;
     ParsedEnum<SILAccessEnforcement> enforcement;
     ParsedEnum<bool> aborting;
 
-    bool isBeginAccess = (Opcode == ValueKind::BeginAccessInst ||
-                          Opcode == ValueKind::BeginUnpairedAccessInst);
+    bool isBeginAccess = (Opcode == SILInstructionKind::BeginAccessInst ||
+                          Opcode == SILInstructionKind::BeginUnpairedAccessInst);
     bool wantsEnforcement = (isBeginAccess ||
-                             Opcode == ValueKind::EndUnpairedAccessInst);
+                             Opcode == SILInstructionKind::EndUnpairedAccessInst);
 
     while (P.consumeIf(tok::l_square)) {
       Identifier ident;
@@ -3271,7 +3293,7 @@
 
     SILValue bufferVal;
     SourceLoc bufferLoc;
-    if (Opcode == ValueKind::BeginUnpairedAccessInst &&
+    if (Opcode == SILInstructionKind::BeginUnpairedAccessInst &&
         (P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") ||
          parseTypedValueRef(bufferVal, bufferLoc, B)))
       return true;
@@ -3285,11 +3307,11 @@
       return true;
     }
 
-    if (Opcode == ValueKind::BeginAccessInst) {
+    if (Opcode == SILInstructionKind::BeginAccessInst) {
       ResultVal = B.createBeginAccess(InstLoc, addrVal, *kind, *enforcement);
-    } else if (Opcode == ValueKind::EndAccessInst) {
+    } else if (Opcode == SILInstructionKind::EndAccessInst) {
       ResultVal = B.createEndAccess(InstLoc, addrVal, *aborting);
-    } else if (Opcode == ValueKind::BeginUnpairedAccessInst) {
+    } else if (Opcode == SILInstructionKind::BeginUnpairedAccessInst) {
       ResultVal = B.createBeginUnpairedAccess(InstLoc, addrVal, bufferVal,
                                               *kind, *enforcement);
     } else {
@@ -3299,10 +3321,10 @@
     break;
   }
 
-  case ValueKind::StoreBorrowInst:
-  case ValueKind::AssignInst:
-  case ValueKind::StoreUnownedInst:
-  case ValueKind::StoreWeakInst: {
+  case SILInstructionKind::StoreBorrowInst:
+  case SILInstructionKind::AssignInst:
+  case SILInstructionKind::StoreUnownedInst:
+  case SILInstructionKind::StoreWeakInst: {
     UnresolvedValueName from;
 
     SourceLoc toLoc, addrLoc;
@@ -3312,8 +3334,8 @@
     if (parseValueName(from) ||
         parseSILIdentifier(toToken, toLoc,
                            diag::expected_tok_in_sil_instr, "to") ||
-        ((Opcode == ValueKind::StoreWeakInst ||
-          Opcode == ValueKind::StoreUnownedInst) &&
+        ((Opcode == SILInstructionKind::StoreWeakInst ||
+          Opcode == SILInstructionKind::StoreUnownedInst) &&
          parseSILOptional(isInit, *this, "initialization")) ||
         parseTypedValueRef(addrVal, addrLoc, B) ||
         parseSILDebugLocation(InstLoc, B))
@@ -3330,14 +3352,14 @@
       return true;
     }
 
-    if (Opcode == ValueKind::StoreBorrowInst) {
+    if (Opcode == SILInstructionKind::StoreBorrowInst) {
       SILType valueTy = addrVal->getType().getObjectType();
       ResultVal = B.createStoreBorrow(
           InstLoc, getLocalValue(from, valueTy, InstLoc, B), addrVal);
       break;
     }
 
-    if (Opcode == ValueKind::StoreUnownedInst) {
+    if (Opcode == SILInstructionKind::StoreUnownedInst) {
       auto refType = addrVal->getType().getAs<UnownedStorageType>();
       if (!refType) {
         P.diagnose(addrLoc, diag::sil_operand_not_unowned_address,
@@ -3351,7 +3373,7 @@
       break;
     }
 
-    if (Opcode == ValueKind::StoreWeakInst) {
+    if (Opcode == SILInstructionKind::StoreWeakInst) {
       auto refType = addrVal->getType().getAs<WeakStorageType>();
       if (!refType) {
         P.diagnose(addrLoc, diag::sil_operand_not_weak_address,
@@ -3367,35 +3389,35 @@
 
     SILType ValType = addrVal->getType().getObjectType();
 
-    assert(Opcode == ValueKind::AssignInst);
+    assert(Opcode == SILInstructionKind::AssignInst);
     ResultVal = B.createAssign(InstLoc,
                                getLocalValue(from, ValType, InstLoc, B),
                                addrVal);
     break;
   }
-  case ValueKind::AllocStackInst:
-  case ValueKind::MetatypeInst: {
+  case SILInstructionKind::AllocStackInst:
+  case SILInstructionKind::MetatypeInst: {
 
     SILType Ty;
     if (parseSILType(Ty))
       return true;
 
-    if (Opcode == ValueKind::AllocStackInst) {
+    if (Opcode == SILInstructionKind::AllocStackInst) {
       SILDebugVariable VarInfo;
       if (parseSILDebugVar(VarInfo) ||
           parseSILDebugLocation(InstLoc, B))
         return true;
       ResultVal = B.createAllocStack(InstLoc, Ty, VarInfo);
     } else {
-      assert(Opcode == ValueKind::MetatypeInst);
+      assert(Opcode == SILInstructionKind::MetatypeInst);
       if (parseSILDebugLocation(InstLoc, B))
         return true;
       ResultVal = B.createMetatype(InstLoc, Ty);
     }
     break;
   }
-  case ValueKind::AllocRefInst:
-  case ValueKind::AllocRefDynamicInst: {
+  case SILInstructionKind::AllocRefInst:
+  case SILInstructionKind::AllocRefDynamicInst: {
     bool IsObjC = false;
     bool OnStack = false;
     SmallVector<SILType, 2> ElementTypes;
@@ -3429,7 +3451,7 @@
       P.parseToken(tok::r_square, diag::expected_in_attribute_list);
     }
     SILValue Metadata;
-    if (Opcode == ValueKind::AllocRefDynamicInst) {
+    if (Opcode == SILInstructionKind::AllocRefDynamicInst) {
       if (parseTypedValueRef(Metadata, B) ||
           P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ","))
         return true;
@@ -3446,7 +3468,7 @@
       P.diagnose(P.Tok, diag::sil_objc_with_tail_elements);
       return true;
     }
-    if (Opcode == ValueKind::AllocRefDynamicInst) {
+    if (Opcode == SILInstructionKind::AllocRefDynamicInst) {
       if (OnStack)
         return true;
 
@@ -3459,13 +3481,13 @@
     break;
   }
 
-  case ValueKind::DeallocStackInst:
+  case SILInstructionKind::DeallocStackInst:
     if (parseTypedValueRef(Val, B) ||
         parseSILDebugLocation(InstLoc, B))
       return true;
     ResultVal = B.createDeallocStack(InstLoc, Val);
     break;
-  case ValueKind::DeallocRefInst: {
+  case SILInstructionKind::DeallocRefInst: {
     bool OnStack = false;
     if (parseSILOptional(OnStack, *this, "stack"))
       return true;
@@ -3476,7 +3498,7 @@
     ResultVal = B.createDeallocRef(InstLoc, Val, OnStack);
     break;
   }
-  case ValueKind::DeallocPartialRefInst: {
+  case SILInstructionKind::DeallocPartialRefInst: {
     SILValue Metatype, Instance;
     if (parseTypedValueRef(Instance, B) ||
         P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") ||
@@ -3487,15 +3509,15 @@
     ResultVal = B.createDeallocPartialRef(InstLoc, Instance, Metatype);
     break;
   }
-  case ValueKind::DeallocBoxInst:
+  case SILInstructionKind::DeallocBoxInst:
     if (parseTypedValueRef(Val, B) ||
         parseSILDebugLocation(InstLoc, B))
       return true;
 
     ResultVal = B.createDeallocBox(InstLoc, Val);
     break;
-  case ValueKind::ValueMetatypeInst:
-  case ValueKind::ExistentialMetatypeInst: {
+  case SILInstructionKind::ValueMetatypeInst:
+  case SILInstructionKind::ExistentialMetatypeInst: {
     SILType Ty;
     if (parseSILType(Ty) ||
         P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") ||
@@ -3504,19 +3526,19 @@
       return true;
     switch (Opcode) {
     default: llvm_unreachable("Out of sync with parent switch");
-    case ValueKind::ValueMetatypeInst:
+    case SILInstructionKind::ValueMetatypeInst:
       ResultVal = B.createValueMetatype(InstLoc, Ty, Val);
       break;
-    case ValueKind::ExistentialMetatypeInst:
+    case SILInstructionKind::ExistentialMetatypeInst:
       ResultVal = B.createExistentialMetatype(InstLoc, Ty, Val);
       break;
-    case ValueKind::DeallocBoxInst:
+    case SILInstructionKind::DeallocBoxInst:
       ResultVal = B.createDeallocBox(InstLoc, Val);
       break;
     }
     break;
   }
-  case ValueKind::DeallocExistentialBoxInst: {
+  case SILInstructionKind::DeallocExistentialBoxInst: {
     CanType ConcreteTy;
     if (parseTypedValueRef(Val, B)
         || P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",")
@@ -3528,7 +3550,7 @@
     ResultVal = B.createDeallocExistentialBox(InstLoc, ConcreteTy, Val);
     break;
   }
-  case ValueKind::TupleInst: {
+  case SILInstructionKind::TupleInst: {
     // Tuple instructions have two different syntaxes, one for simple tuple
     // types, one for complicated ones.
     if (P.Tok.isNot(tok::sil_dollar)) {
@@ -3603,7 +3625,7 @@
     ResultVal = B.createTuple(InstLoc, Ty, OpList);
     break;
   }
-  case ValueKind::EnumInst: {
+  case SILInstructionKind::EnumInst: {
     SILType Ty;
     SILDeclRef Elt;
     SILValue Operand;
@@ -3624,9 +3646,9 @@
                               cast<EnumElementDecl>(Elt.getDecl()), Ty);
     break;
   }
-  case ValueKind::InitEnumDataAddrInst:
-  case ValueKind::UncheckedEnumDataInst:
-  case ValueKind::UncheckedTakeEnumDataAddrInst: {
+  case SILInstructionKind::InitEnumDataAddrInst:
+  case SILInstructionKind::UncheckedEnumDataInst:
+  case SILInstructionKind::UncheckedTakeEnumDataAddrInst: {
     SILValue Operand;
     SILDeclRef EltRef;
     if (parseTypedValueRef(Operand, B) ||
@@ -3639,14 +3661,14 @@
     auto ResultTy = Operand->getType().getEnumElementType(Elt, SILMod);
     
     switch (Opcode) {
-    case swift::ValueKind::InitEnumDataAddrInst:
+    case swift::SILInstructionKind::InitEnumDataAddrInst:
       ResultVal = B.createInitEnumDataAddr(InstLoc, Operand, Elt, ResultTy);
       break;
-    case swift::ValueKind::UncheckedTakeEnumDataAddrInst:
+    case swift::SILInstructionKind::UncheckedTakeEnumDataAddrInst:
       ResultVal = B.createUncheckedTakeEnumDataAddr(InstLoc, Operand, Elt,
                                                     ResultTy);
       break;
-    case swift::ValueKind::UncheckedEnumDataInst:
+    case swift::SILInstructionKind::UncheckedEnumDataInst:
       ResultVal = B.createUncheckedEnumData(InstLoc, Operand, Elt, ResultTy);
       break;
     default:
@@ -3654,7 +3676,7 @@
     }
     break;
   }
-  case ValueKind::InjectEnumAddrInst: {
+  case SILInstructionKind::InjectEnumAddrInst: {
     SILValue Operand;
     SILDeclRef EltRef;
     if (parseTypedValueRef(Operand, B) ||
@@ -3667,8 +3689,8 @@
     ResultVal = B.createInjectEnumAddr(InstLoc, Operand, Elt);
     break;
   }
-  case ValueKind::TupleElementAddrInst:
-  case ValueKind::TupleExtractInst: {
+  case SILInstructionKind::TupleElementAddrInst:
+  case SILInstructionKind::TupleExtractInst: {
     SourceLoc NameLoc;
     if (parseTypedValueRef(Val, B) ||
         P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ","))
@@ -3686,7 +3708,7 @@
     if (parseSILDebugLocation(InstLoc, B))
       return true;
     auto ResultTy = TT->getElement(Field).getType()->getCanonicalType();
-    if (Opcode == ValueKind::TupleElementAddrInst)
+    if (Opcode == SILInstructionKind::TupleElementAddrInst)
       ResultVal = B.createTupleElementAddr(InstLoc, Val, Field,
                                   SILType::getPrimitiveAddressType(ResultTy));
     else
@@ -3694,21 +3716,21 @@
                           SILType::getPrimitiveObjectType(ResultTy));
     break;
   }
-  case ValueKind::ReturnInst: {
+  case SILInstructionKind::ReturnInst: {
     if (parseTypedValueRef(Val, B) ||
         parseSILDebugLocation(InstLoc, B))
       return true;
     ResultVal = B.createReturn(InstLoc, Val);
     break;
   }
-  case ValueKind::ThrowInst: {
+  case SILInstructionKind::ThrowInst: {
     if (parseTypedValueRef(Val, B) ||
         parseSILDebugLocation(InstLoc, B))
       return true;
     ResultVal = B.createThrow(InstLoc, Val);
     break;
   }
-  case ValueKind::BranchInst: {
+  case SILInstructionKind::BranchInst: {
     Identifier BBName;
     SourceLoc NameLoc;
     if (parseSILIdentifier(BBName, NameLoc, diag::expected_sil_block_name))
@@ -3727,7 +3749,7 @@
                                Args);
     break;
   }
-  case ValueKind::CondBranchInst: {
+  case SILInstructionKind::CondBranchInst: {
     UnresolvedValueName Cond;
     Identifier BBName, BBName2;
     SourceLoc NameLoc, NameLoc2;
@@ -3753,15 +3775,15 @@
                                    Args2);
     break;
   }
-  case ValueKind::UnreachableInst:
+  case SILInstructionKind::UnreachableInst:
     if (parseSILDebugLocation(InstLoc, B))
       return true;
     ResultVal = B.createUnreachable(InstLoc);
     break;
     
-  case ValueKind::ClassMethodInst:
-  case ValueKind::SuperMethodInst:
-  case ValueKind::DynamicMethodInst: {
+  case SILInstructionKind::ClassMethodInst:
+  case SILInstructionKind::SuperMethodInst:
+  case SILInstructionKind::DynamicMethodInst: {
     bool IsVolatile = false;
     if (parseSILOptional(IsVolatile, *this, "volatile"))
       return true;
@@ -3783,22 +3805,22 @@
 
     switch (Opcode) {
     default: llvm_unreachable("Out of sync with parent switch");
-    case ValueKind::ClassMethodInst:
+    case SILInstructionKind::ClassMethodInst:
       ResultVal = B.createClassMethod(InstLoc, Val, Member, MethodTy,
                                       IsVolatile);
       break;
-    case ValueKind::SuperMethodInst:
+    case SILInstructionKind::SuperMethodInst:
       ResultVal = B.createSuperMethod(InstLoc, Val, Member, MethodTy,
                                       IsVolatile);
       break;
-    case ValueKind::DynamicMethodInst:
+    case SILInstructionKind::DynamicMethodInst:
       ResultVal = B.createDynamicMethod(InstLoc, Val, Member, MethodTy,
                                        IsVolatile);
       break;
     }
     break;
   }
-  case ValueKind::WitnessMethodInst: {
+  case SILInstructionKind::WitnessMethodInst: {
     bool IsVolatile = false;
     if (parseSILOptional(IsVolatile, *this, "volatile"))
       return true;
@@ -3845,7 +3867,7 @@
                                       MethodTy, IsVolatile);
     break;
   }
-  case ValueKind::CopyAddrInst: {
+  case SILInstructionKind::CopyAddrInst: {
     bool IsTake = false, IsInit = false;
     UnresolvedValueName SrcLName;
     SILValue DestLVal;
@@ -3875,7 +3897,7 @@
                                  IsInitialization_t(IsInit));
     break;
   }
-  case ValueKind::BindMemoryInst: {
+  case SILInstructionKind::BindMemoryInst: {
     SILValue IndexVal;
     Identifier ToToken;
     SourceLoc ToLoc;
@@ -3896,8 +3918,8 @@
     ResultVal = B.createBindMemory(InstLoc, Val, IndexVal, EltTy);
     break;
   }
-  case ValueKind::ObjectInst:
-  case ValueKind::StructInst: {
+  case SILInstructionKind::ObjectInst:
+  case SILInstructionKind::StructInst: {
     SILType Ty;
     if (parseSILType(Ty) ||
         P.parseToken(tok::l_paren, diag::expected_tok_in_sil_instr, "("))
@@ -3908,7 +3930,7 @@
     unsigned NumBaseElems = 0;
     if (P.Tok.isNot(tok::r_paren)) {
       do {
-        if (Opcode == ValueKind::ObjectInst) {
+        if (Opcode == SILInstructionKind::ObjectInst) {
           if (parseSILOptional(OpsAreTailElems, *this, "tail_elems"))
             return true;
         }
@@ -3923,15 +3945,15 @@
         parseSILDebugLocation(InstLoc, B))
       return true;
 
-    if (Opcode == ValueKind::StructInst) {
+    if (Opcode == SILInstructionKind::StructInst) {
       ResultVal = B.createStruct(InstLoc, Ty, OpList);
     } else {
       ResultVal = B.createObject(InstLoc, Ty, OpList, NumBaseElems);
     }
     break;
   }
-  case ValueKind::StructElementAddrInst:
-  case ValueKind::StructExtractInst: {
+  case SILInstructionKind::StructElementAddrInst:
+  case SILInstructionKind::StructExtractInst: {
     ValueDecl *FieldV;
     SourceLoc NameLoc = P.Tok.getLoc();
     if (parseTypedValueRef(Val, B) ||
@@ -3948,7 +3970,7 @@
     // FIXME: substitution means this type should be explicit to improve
     // performance.
     auto ResultTy = Val->getType().getFieldType(Field, SILMod);
-    if (Opcode == ValueKind::StructElementAddrInst)
+    if (Opcode == SILInstructionKind::StructElementAddrInst)
       ResultVal = B.createStructElementAddr(InstLoc, Val, Field,
                                             ResultTy.getAddressType());
     else
@@ -3956,7 +3978,7 @@
                                         ResultTy.getObjectType());
     break;
   }
-  case ValueKind::RefElementAddrInst: {
+  case SILInstructionKind::RefElementAddrInst: {
     ValueDecl *FieldV;
     SourceLoc NameLoc;
     if (parseTypedValueRef(Val, B) ||
@@ -3973,7 +3995,7 @@
     ResultVal = B.createRefElementAddr(InstLoc, Val, Field, ResultTy);
     break;
   }
-  case ValueKind::RefTailAddrInst: {
+  case SILInstructionKind::RefTailAddrInst: {
     SourceLoc NameLoc;
     SILType ResultObjTy;
     if (parseTypedValueRef(Val, B) ||
@@ -3985,7 +4007,7 @@
     ResultVal = B.createRefTailAddr(InstLoc, Val, ResultTy);
     break;
   }
-  case ValueKind::IsNonnullInst: {
+  case SILInstructionKind::IsNonnullInst: {
     SourceLoc Loc;
     if (parseTypedValueRef(Val, Loc, B) ||
         parseSILDebugLocation(InstLoc, B))
@@ -3993,7 +4015,7 @@
     ResultVal = B.createIsNonnull(InstLoc, Val);
     break;
   }
-  case ValueKind::IndexAddrInst: {
+  case SILInstructionKind::IndexAddrInst: {
     SILValue IndexVal;
     if (parseTypedValueRef(Val, B) ||
         P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") ||
@@ -4003,7 +4025,7 @@
     ResultVal = B.createIndexAddr(InstLoc, Val, IndexVal);
     break;
   }
-  case ValueKind::TailAddrInst: {
+  case SILInstructionKind::TailAddrInst: {
     SILValue IndexVal;
     SILType ResultObjTy;
     if (parseTypedValueRef(Val, B) ||
@@ -4017,7 +4039,7 @@
     ResultVal = B.createTailAddr(InstLoc, Val, IndexVal, ResultTy);
     break;
   }
-  case ValueKind::IndexRawPointerInst: {
+  case SILInstructionKind::IndexRawPointerInst: {
     SILValue IndexVal;
     if (parseTypedValueRef(Val, B) ||
         P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") ||
@@ -4027,7 +4049,7 @@
     ResultVal = B.createIndexRawPointer(InstLoc, Val, IndexVal);
     break;
   }
-  case ValueKind::ObjCProtocolInst: {
+  case SILInstructionKind::ObjCProtocolInst: {
     Identifier ProtocolName;
     SILType Ty;
     if (P.parseToken(tok::pound, diag::expected_sil_constant) ||
@@ -4049,7 +4071,7 @@
     ResultVal = B.createObjCProtocol(InstLoc, cast<ProtocolDecl>(VD), Ty);
     break;
   }
-  case ValueKind::AllocGlobalInst: {
+  case SILInstructionKind::AllocGlobalInst: {
     Identifier GlobalName;
     SourceLoc IdLoc;
     if (P.parseToken(tok::at_sign, diag::expected_sil_value_name) ||
@@ -4067,8 +4089,8 @@
     ResultVal = B.createAllocGlobal(InstLoc, global);
     break;
   }
-  case ValueKind::GlobalAddrInst:
-  case ValueKind::GlobalValueInst: {
+  case SILInstructionKind::GlobalAddrInst:
+  case SILInstructionKind::GlobalValueInst: {
     Identifier GlobalName;
     SourceLoc IdLoc;
     SILType Ty;
@@ -4086,7 +4108,7 @@
       return true;
     }
 
-    SILType expectedType = (Opcode == ValueKind::GlobalAddrInst ?
+    SILType expectedType = (Opcode == SILInstructionKind::GlobalAddrInst ?
                             global->getLoweredType().getAddressType() :
                             global->getLoweredType());
     if (expectedType != Ty) {
@@ -4096,15 +4118,15 @@
       return true;
     }
 
-    if (Opcode == ValueKind::GlobalAddrInst) {
+    if (Opcode == SILInstructionKind::GlobalAddrInst) {
       ResultVal = B.createGlobalAddr(InstLoc, global);
     } else {
       ResultVal = B.createGlobalValue(InstLoc, global);
     }
     break;
   }
-  case ValueKind::SelectEnumInst:
-  case ValueKind::SelectEnumAddrInst: {
+  case SILInstructionKind::SelectEnumInst:
+  case SILInstructionKind::SelectEnumAddrInst: {
     if (parseTypedValueRef(Val, B))
       return true;
 
@@ -4158,7 +4180,7 @@
           caseName.first,
           getLocalValue(caseName.second, ResultType, InstLoc, B)));
 
-    if (Opcode == ValueKind::SelectEnumInst)
+    if (Opcode == SILInstructionKind::SelectEnumInst)
       ResultVal = B.createSelectEnum(InstLoc, Val, ResultType,
                                      DefaultValue, CaseValues);
     else
@@ -4167,8 +4189,8 @@
     break;
   }
       
-  case ValueKind::SwitchEnumInst:
-  case ValueKind::SwitchEnumAddrInst: {
+  case SILInstructionKind::SwitchEnumInst:
+  case SILInstructionKind::SwitchEnumAddrInst: {
     if (parseTypedValueRef(Val, B))
       return true;
 
@@ -4202,13 +4224,13 @@
     }
     if (parseSILDebugLocation(InstLoc, B))
       return true;
-    if (Opcode == ValueKind::SwitchEnumInst)
+    if (Opcode == SILInstructionKind::SwitchEnumInst)
       ResultVal = B.createSwitchEnum(InstLoc, Val, DefaultBB, CaseBBs);
     else
       ResultVal = B.createSwitchEnumAddr(InstLoc, Val, DefaultBB, CaseBBs);
     break;
   }
-  case ValueKind::SwitchValueInst: {
+  case SILInstructionKind::SwitchValueInst: {
     if (parseTypedValueRef(Val, B))
       return true;
 
@@ -4291,7 +4313,7 @@
     ResultVal = B.createSwitchValue(InstLoc, Val, DefaultBB, CaseBBs);
     break;
   }
-  case ValueKind::SelectValueInst: {
+  case SILInstructionKind::SelectValueInst: {
     if (parseTypedValueRef(Val, B))
       return true;
 
@@ -4353,20 +4375,20 @@
                                     DefaultValue, CaseValues);
     break;
   }
-  case ValueKind::DeinitExistentialAddrInst: {
+  case SILInstructionKind::DeinitExistentialAddrInst: {
     if (parseTypedValueRef(Val, B) ||
         parseSILDebugLocation(InstLoc, B))
       return true;
     ResultVal = B.createDeinitExistentialAddr(InstLoc, Val);
     break;
   }
-  case ValueKind::DeinitExistentialValueInst: {
+  case SILInstructionKind::DeinitExistentialValueInst: {
     if (parseTypedValueRef(Val, B) || parseSILDebugLocation(InstLoc, B))
       return true;
     ResultVal = B.createDeinitExistentialValue(InstLoc, Val);
     break;
   }
-  case ValueKind::InitExistentialAddrInst: {
+  case SILInstructionKind::InitExistentialAddrInst: {
     CanType Ty;
     SourceLoc TyLoc;
     if (parseTypedValueRef(Val, B) ||
@@ -4394,7 +4416,7 @@
                                         conformances);
     break;
   }
-  case ValueKind::InitExistentialValueInst: {
+  case SILInstructionKind::InitExistentialValueInst: {
     CanType FormalConcreteTy;
     SILType ExistentialTy;
     SourceLoc TyLoc;
@@ -4415,7 +4437,7 @@
         InstLoc, ExistentialTy, FormalConcreteTy, Val, conformances);
     break;
   }
-  case ValueKind::AllocExistentialBoxInst: {
+  case SILInstructionKind::AllocExistentialBoxInst: {
     SILType ExistentialTy;
     CanType ConcreteFormalTy;
     SourceLoc TyLoc;
@@ -4437,7 +4459,7 @@
     
     break;
   }
-  case ValueKind::InitExistentialRefInst: {
+  case SILInstructionKind::InitExistentialRefInst: {
     CanType FormalConcreteTy;
     SILType ExistentialTy;
     SourceLoc TyLoc;
@@ -4462,7 +4484,7 @@
                                            conformances);
     break;
   }
-  case ValueKind::InitExistentialMetatypeInst: {
+  case SILInstructionKind::InitExistentialMetatypeInst: {
     SourceLoc TyLoc;
     SILType ExistentialTy;
     if (parseTypedValueRef(Val, B) ||
@@ -4487,7 +4509,7 @@
                                                 conformances);
     break;
   }
-  case ValueKind::DynamicMethodBranchInst: {
+  case SILInstructionKind::DynamicMethodBranchInst: {
     SILDeclRef Member;
     Identifier BBName, BBName2;
     SourceLoc NameLoc, NameLoc2;
@@ -4508,7 +4530,7 @@
                                                               NameLoc2));
     break;
   }
-  case ValueKind::ProjectBlockStorageInst: {
+  case SILInstructionKind::ProjectBlockStorageInst: {
     if (parseTypedValueRef(Val, B) ||
         parseSILDebugLocation(InstLoc, B))
       return true;
@@ -4516,7 +4538,7 @@
     ResultVal = B.createProjectBlockStorage(InstLoc, Val);
     break;
   }
-  case ValueKind::InitBlockStorageHeaderInst: {
+  case SILInstructionKind::InitBlockStorageHeaderInst: {
     Identifier invoke, type;
     SourceLoc invokeLoc, typeLoc;
     
@@ -4572,14 +4594,24 @@
   }
   }
 
-  // Store the named value if we had a name.
-  if (ResultNameLoc.isValid())
-    setLocalValue(ResultVal, ResultName, ResultNameLoc);
+  // Match the results clause if we had one.
+  if (resultClauseBegin.isValid()) {
+    auto results = ResultVal->getResults();
+    if (results.size() != resultNames.size()) {
+      P.diagnose(resultClauseBegin, diag::wrong_result_count_in_sil_instr,
+                 results.size());
+    } else {
+      for (size_t i : indices(results)) {
+        setLocalValue(results[i], resultNames[i].first, resultNames[i].second);
+      }
+    }
+  }
+
   return false;
 }
 
 bool SILParser::parseCallInstruction(SILLocation InstLoc,
-                                     ValueKind Opcode, SILBuilder &B,
+                                     SILInstructionKind Opcode, SILBuilder &B,
                                      SILInstruction *&ResultVal) {
   UnresolvedValueName FnName;
   SmallVector<UnresolvedValueName, 4> ArgNames;
@@ -4652,7 +4684,7 @@
 
   switch (Opcode) {
   default: llvm_unreachable("Unexpected case");
-  case ValueKind::ApplyInst : {
+  case SILInstructionKind::ApplyInst : {
     if (parseSILDebugLocation(InstLoc, B))
       return true;
     if (substConv.getNumSILArguments() != ArgNames.size()) {
@@ -4671,7 +4703,7 @@
     ResultVal = B.createApply(InstLoc, FnVal, subs, Args, IsNonThrowingApply);
     break;
   }
-  case ValueKind::PartialApplyInst: {
+  case SILInstructionKind::PartialApplyInst: {
     if (parseSILDebugLocation(InstLoc, B))
       return true;
     if (substFTI->getParameters().size() < ArgNames.size()) {
@@ -4694,7 +4726,7 @@
                                      PartialApplyConvention);
     break;
   }
-  case ValueKind::TryApplyInst: {
+  case SILInstructionKind::TryApplyInst: {
     Identifier normalBBName, errorBBName;
     SourceLoc normalBBLoc, errorBBLoc;
     if (P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") ||
diff --git a/lib/RemoteAST/RemoteAST.cpp b/lib/RemoteAST/RemoteAST.cpp
index 508f84d..7501eee 100644
--- a/lib/RemoteAST/RemoteAST.cpp
+++ b/lib/RemoteAST/RemoteAST.cpp
@@ -21,6 +21,7 @@
 #include "swift/AST/Decl.h"
 #include "swift/AST/Module.h"
 #include "swift/AST/NameLookup.h"
+#include "swift/AST/SubstitutionMap.h"
 #include "swift/AST/Types.h"
 #include "swift/AST/TypeRepr.h"
 #include "swift/Basic/Mangler.h"
@@ -133,6 +134,14 @@
 
   NominalTypeDecl *createNominalTypeDecl(const Demangle::NodePointer &node);
 
+  Type createNominalType(NominalTypeDecl *decl) {
+    // If the declaration is generic, fail.
+    if (decl->isGenericContext())
+      return Type();
+
+    return decl->getDeclaredType();
+  }
+
   Type createNominalType(NominalTypeDecl *decl, Type parent) {
     // If the declaration is generic, fail.
     if (decl->getGenericParams())
@@ -145,6 +154,36 @@
     return NominalType::get(decl, parent, Ctx);
   }
 
+  Type createBoundGenericType(NominalTypeDecl *decl, ArrayRef<Type> args) {
+    // If the declaration isn't generic, fail.
+    if (!decl->isGenericContext())
+      return Type();
+
+    // Build a SubstitutionMap.
+    auto *genericSig = decl->getGenericSignature();
+    auto genericParams = genericSig->getSubstitutableParams();
+    if (genericParams.size() != args.size())
+      return Type();
+
+    auto subMap = genericSig->getSubstitutionMap(
+        [&](SubstitutableType *t) -> Type {
+          for (unsigned i = 0, e = genericParams.size(); i < e; ++i) {
+            if (t->isEqual(genericParams[i]))
+              return args[i];
+          }
+          return Type();
+        },
+        // FIXME: Wrong module
+        LookUpConformanceInModule(decl->getParentModule()));
+
+    auto origType = decl->getDeclaredInterfaceType();
+
+    // FIXME: We're not checking that the type satisfies the generic
+    // requirements of the signature here.
+    auto substType = origType.subst(subMap);
+    return substType;
+  }
+
   Type createBoundGenericType(NominalTypeDecl *decl, ArrayRef<Type> args,
                               Type parent) {
     // If the declaration isn't generic, fail.
diff --git a/lib/SIL/Dominance.cpp b/lib/SIL/Dominance.cpp
index 09b406d..eb27420 100644
--- a/lib/SIL/Dominance.cpp
+++ b/lib/SIL/Dominance.cpp
@@ -63,7 +63,7 @@
 
 /// Does value A properly dominate instruction B?
 bool DominanceInfo::properlyDominates(SILValue a, SILInstruction *b) {
-  if (auto *Inst = dyn_cast<SILInstruction>(a)) {
+  if (auto *Inst = a->getDefiningInstruction()) {
     return properlyDominates(Inst, b);
   }
   if (auto *Arg = dyn_cast<SILArgument>(a)) {
diff --git a/lib/SIL/DynamicCasts.cpp b/lib/SIL/DynamicCasts.cpp
index 314e578..669c0d3 100644
--- a/lib/SIL/DynamicCasts.cpp
+++ b/lib/SIL/DynamicCasts.cpp
@@ -1175,14 +1175,12 @@
 
 /// Carry out the operations required for an indirect conditional cast
 /// using a scalar cast operation.
-void swift::
-emitIndirectConditionalCastWithScalar(SILBuilder &B, ModuleDecl *M,
-                                      SILLocation loc,
-                                      CastConsumptionKind consumption,
-                                      SILValue src, CanType sourceType,
-                                      SILValue dest, CanType targetType,
-                                      SILBasicBlock *indirectSuccBB,
-                                      SILBasicBlock *indirectFailBB) {
+void swift::emitIndirectConditionalCastWithScalar(
+    SILBuilder &B, ModuleDecl *M, SILLocation loc,
+    CastConsumptionKind consumption, SILValue src, CanType sourceType,
+    SILValue dest, CanType targetType, SILBasicBlock *indirectSuccBB,
+    SILBasicBlock *indirectFailBB, ProfileCounter TrueCount,
+    ProfileCounter FalseCount) {
   assert(canUseScalarCheckedCastInstructions(B.getModule(),
                                              sourceType, targetType));
 
@@ -1207,7 +1205,7 @@
 
   SILType targetValueType = dest->getType().getObjectType();
   B.createCheckedCastBranch(loc, /*exact*/ false, srcValue, targetValueType,
-                            scalarSuccBB, scalarFailBB);
+                            scalarSuccBB, scalarFailBB, TrueCount, FalseCount);
 
   // Emit the success block.
   B.setInsertionPoint(scalarSuccBB); {
diff --git a/lib/SIL/InstructionUtils.cpp b/lib/SIL/InstructionUtils.cpp
index 695c402..b2455bf 100644
--- a/lib/SIL/InstructionUtils.cpp
+++ b/lib/SIL/InstructionUtils.cpp
@@ -40,7 +40,7 @@
       case ValueKind::StructElementAddrInst:
       case ValueKind::TupleElementAddrInst:
       case ValueKind::UncheckedTakeEnumDataAddrInst:
-        V2 = cast<SILInstruction>(V2)->getOperand(0);
+        V2 = cast<SingleValueInstruction>(V2)->getOperand(0);
         break;
       default:
         break;
@@ -63,16 +63,15 @@
 
 static bool isRCIdentityPreservingCast(ValueKind Kind) {
   switch (Kind) {
-    case ValueKind::UpcastInst:
-    case ValueKind::UncheckedRefCastInst:
-    case ValueKind::UncheckedRefCastAddrInst:
-    case ValueKind::UnconditionalCheckedCastInst:
-    case ValueKind::UnconditionalCheckedCastValueInst:
-    case ValueKind::RefToBridgeObjectInst:
-    case ValueKind::BridgeObjectToRefInst:
-      return true;
-    default:
-      return false;
+  case ValueKind::UpcastInst:
+  case ValueKind::UncheckedRefCastInst:
+  case ValueKind::UnconditionalCheckedCastInst:
+  case ValueKind::UnconditionalCheckedCastValueInst:
+  case ValueKind::RefToBridgeObjectInst:
+  case ValueKind::BridgeObjectToRefInst:
+    return true;
+  default:
+    return false;
   }
 }
 
@@ -127,7 +126,7 @@
     auto K = V->getKind();
     if (isRCIdentityPreservingCast(K) ||
         K == ValueKind::UncheckedTrivialBitCastInst) {
-      V = cast<SILInstruction>(V)->getOperand(0);
+      V = cast<SingleValueInstruction>(V)->getOperand(0);
       continue;
     }
 
@@ -143,7 +142,7 @@
     if (isRCIdentityPreservingCast(K)
         || K == ValueKind::UncheckedTrivialBitCastInst
         || K == ValueKind::MarkDependenceInst) {
-      V = cast<SILInstruction>(V)->getOperand(0);
+      V = cast<SingleValueInstruction>(V)->getOperand(0);
       continue;
     }
     
@@ -157,8 +156,8 @@
   
   V = stripSinglePredecessorArgs(V);
   
-  while (isa<UpcastInst>(V))
-    V = stripSinglePredecessorArgs(cast<UpcastInst>(V)->getOperand());
+  while (auto upcast = dyn_cast<UpcastInst>(V))
+    V = stripSinglePredecessorArgs(upcast->getOperand());
   
   return V;
 }
@@ -184,7 +183,7 @@
     V = stripSinglePredecessorArgs(V);
     if (!Projection::isAddressProjection(V))
       return V;
-    V = cast<SILInstruction>(V)->getOperand(0);
+    V = cast<SingleValueInstruction>(V)->getOperand(0);
   }
 }
 
@@ -193,7 +192,7 @@
     V = stripSinglePredecessorArgs(V);
     if (!Projection::isAddressProjection(V))
       return V;
-    auto *Inst = cast<SILInstruction>(V);
+    auto *Inst = cast<SingleValueInstruction>(V);
     if (Inst->getNumOperands() > 1)
       return V;
     V = Inst->getOperand(0);
@@ -205,7 +204,7 @@
     V = stripSinglePredecessorArgs(V);
     if (!Projection::isObjectProjection(V))
       return V;
-    V = cast<SILInstruction>(V)->getOperand(0);
+    V = cast<SingleValueInstruction>(V)->getOperand(0);
   }
 }
 
@@ -242,7 +241,7 @@
 
 struct OwnershipQualifiedKindVisitor : SILInstructionVisitor<OwnershipQualifiedKindVisitor, OwnershipQualifiedKind> {
 
-  OwnershipQualifiedKind visitValueBase(ValueBase *V) {
+  OwnershipQualifiedKind visitSILInstruction(SILInstruction *I) {
     return OwnershipQualifiedKind::NotApplicable;
   }
 
diff --git a/lib/SIL/Linker.h b/lib/SIL/Linker.h
index 20be5a0..a1a23e6 100644
--- a/lib/SIL/Linker.h
+++ b/lib/SIL/Linker.h
@@ -70,7 +70,7 @@
   SILVTable *processClassDecl(const ClassDecl *C);
 
   /// We do not want to visit callee functions if we just have a value base.
-  bool visitValueBase(ValueBase *V) { return false; }
+  bool visitSILInstruction(SILInstruction *I) { return false; }
 
   bool visitApplyInst(ApplyInst *AI);
   bool visitPartialApplyInst(PartialApplyInst *PAI);
diff --git a/lib/SIL/LoopInfo.cpp b/lib/SIL/LoopInfo.cpp
index 1e2cc87..65271c9 100644
--- a/lib/SIL/LoopInfo.cpp
+++ b/lib/SIL/LoopInfo.cpp
@@ -39,7 +39,7 @@
   // The deallocation of a stack allocation must be in the loop, otherwise the
   // deallocation will be fed by a phi node of two allocations.
   if (I->isAllocatingStack()) {
-    for (auto *UI : I->getUses()) {
+    for (auto *UI : cast<SingleValueInstruction>(I)->getUses()) {
       if (UI->getUser()->isDeallocatingStack()) {
         if (!contains(UI->getUser()->getParent()))
           return false;
@@ -64,7 +64,8 @@
       isa<OpenExistentialMetatypeInst>(I) ||
       isa<OpenExistentialValueInst>(I) || isa<OpenExistentialBoxInst>(I) ||
       isa<OpenExistentialBoxValueInst>(I)) {
-    for (auto *UI : I->getUses())
+    SingleValueInstruction *OI = cast<SingleValueInstruction>(I);
+    for (auto *UI : OI->getUses())
       if (!contains(UI->getUser()))
         return false;
     return true;
diff --git a/lib/SIL/Projection.cpp b/lib/SIL/Projection.cpp
index 62927dd..85188ca 100644
--- a/lib/SIL/Projection.cpp
+++ b/lib/SIL/Projection.cpp
@@ -58,7 +58,7 @@
 //                               Projection
 //===----------------------------------------------------------------------===//
 
-Projection::Projection(SILInstruction *I) : Value() {
+Projection::Projection(SingleValueInstruction *I) : Value() {
   if (!I)
     return;
   /// Initialize given the specific instruction type and verify with asserts
@@ -68,7 +68,7 @@
   // be None so the Projection will be invalid.
   default:
     return;
-  case ValueKind::StructElementAddrInst: {
+  case SILInstructionKind::StructElementAddrInst: {
     auto *SEAI = cast<StructElementAddrInst>(I);
     Value = ValueTy(ProjectionKind::Struct, SEAI->getFieldNo());
     assert(getKind() == ProjectionKind::Struct);
@@ -77,7 +77,7 @@
            SEAI->getType());
     break;
   }
-  case ValueKind::StructExtractInst: {
+  case SILInstructionKind::StructExtractInst: {
     auto *SEI = cast<StructExtractInst>(I);
     Value = ValueTy(ProjectionKind::Struct, SEI->getFieldNo());
     assert(getKind() == ProjectionKind::Struct);
@@ -86,7 +86,7 @@
            SEI->getType());
     break;
   }
-  case ValueKind::RefElementAddrInst: {
+  case SILInstructionKind::RefElementAddrInst: {
     auto *REAI = cast<RefElementAddrInst>(I);
     Value = ValueTy(ProjectionKind::Class, REAI->getFieldNo());
     assert(getKind() == ProjectionKind::Class);
@@ -95,14 +95,14 @@
            REAI->getType());
     break;
   }
-  case ValueKind::RefTailAddrInst: {
+  case SILInstructionKind::RefTailAddrInst: {
     auto *RTAI = cast<RefTailAddrInst>(I);
     auto *Ty = RTAI->getTailType().getSwiftRValueType().getPointer();
     Value = ValueTy(ProjectionKind::TailElems, Ty);
     assert(getKind() == ProjectionKind::TailElems);
     break;
   }
-  case ValueKind::ProjectBoxInst: {
+  case SILInstructionKind::ProjectBoxInst: {
     auto *PBI = cast<ProjectBoxInst>(I);
     Value = ValueTy(ProjectionKind::Box, static_cast<uintptr_t>(0));
     assert(getKind() == ProjectionKind::Box);
@@ -112,7 +112,7 @@
     (void) PBI;
     break;
   }
-  case ValueKind::TupleExtractInst: {
+  case SILInstructionKind::TupleExtractInst: {
     auto *TEI = cast<TupleExtractInst>(I);
     Value = ValueTy(ProjectionKind::Tuple, TEI->getFieldNo());
     assert(getKind() == ProjectionKind::Tuple);
@@ -121,7 +121,7 @@
            TEI->getType());
     break;
   }
-  case ValueKind::TupleElementAddrInst: {
+  case SILInstructionKind::TupleElementAddrInst: {
     auto *TEAI = cast<TupleElementAddrInst>(I);
     Value = ValueTy(ProjectionKind::Tuple, TEAI->getFieldNo());
     assert(getKind() == ProjectionKind::Tuple);
@@ -130,7 +130,7 @@
            TEAI->getType());
     break;
   }
-  case ValueKind::UncheckedEnumDataInst: {
+  case SILInstructionKind::UncheckedEnumDataInst: {
     auto *UEDI = cast<UncheckedEnumDataInst>(I);
     Value = ValueTy(ProjectionKind::Enum, UEDI->getElementNo());
     assert(getKind() == ProjectionKind::Enum);
@@ -139,7 +139,7 @@
            UEDI->getType());
     break;
   }
-  case ValueKind::UncheckedTakeEnumDataAddrInst: {
+  case SILInstructionKind::UncheckedTakeEnumDataAddrInst: {
     auto *UTEDAI = cast<UncheckedTakeEnumDataAddrInst>(I);
     Value = ValueTy(ProjectionKind::Enum, UTEDAI->getElementNo());
     assert(getKind() == ProjectionKind::Enum);
@@ -148,7 +148,7 @@
            UTEDAI->getType());
     break;
   }
-  case ValueKind::IndexAddrInst: {
+  case SILInstructionKind::IndexAddrInst: {
     // We can represent all integers provided here since getIntegerIndex only
     // returns 32 bit values. When that changes, this code will need to be
     // updated and a MaxLargeIndex will need to be used here. Currently we
@@ -163,7 +163,7 @@
     }
     break;
   }
-  case ValueKind::UpcastInst: {
+  case SILInstructionKind::UpcastInst: {
     auto *Ty = I->getType().getSwiftRValueType().getPointer();
     assert(Ty->isCanonical());
     Value = ValueTy(ProjectionKind::Upcast, Ty);
@@ -172,7 +172,7 @@
            I->getType());
     break;
   }
-  case ValueKind::UncheckedRefCastInst: {
+  case SILInstructionKind::UncheckedRefCastInst: {
     auto *Ty = I->getType().getSwiftRValueType().getPointer();
     assert(Ty->isCanonical());
     Value = ValueTy(ProjectionKind::RefCast, Ty);
@@ -181,8 +181,8 @@
            I->getType());
     break;
   }
-  case ValueKind::UncheckedBitwiseCastInst:
-  case ValueKind::UncheckedAddrCastInst: {
+  case SILInstructionKind::UncheckedBitwiseCastInst:
+  case SILInstructionKind::UncheckedAddrCastInst: {
     auto *Ty = I->getType().getSwiftRValueType().getPointer();
     assert(Ty->isCanonical());
     Value = ValueTy(ProjectionKind::BitwiseCast, Ty);
@@ -194,7 +194,7 @@
   }
 }
 
-NullablePtr<SILInstruction>
+NullablePtr<SingleValueInstruction>
 Projection::createObjectProjection(SILBuilder &B, SILLocation Loc,
                                    SILValue Base) const {
   SILType BaseTy = Base->getType();
@@ -232,7 +232,7 @@
   llvm_unreachable("Unhandled ProjectionKind in switch.");
 }
 
-NullablePtr<SILInstruction>
+NullablePtr<SingleValueInstruction>
 Projection::createAddressProjection(SILBuilder &B, SILLocation Loc,
                                     SILValue Base) const {
   SILType BaseTy = Base->getType();
@@ -361,7 +361,7 @@
     if (!AP.isValid())
       break;
     P.Path.push_back(AP);
-    Iter = cast<SILInstruction>(*Iter).getOperand(0);
+    Iter = cast<SingleValueInstruction>(*Iter).getOperand(0);
   }
 
   // Return None if we have an empty projection list or if Start == Iter.
@@ -774,7 +774,7 @@
   }
 }
 
-NullablePtr<SILInstruction>
+NullablePtr<SingleValueInstruction>
 Projection::
 createAggFromFirstLevelProjections(SILBuilder &B, SILLocation Loc,
                                    SILType BaseType,
@@ -804,7 +804,7 @@
       break;
     case ProjectionKind::Enum:
       if (auto *EI = dyn_cast<EnumInst>(I)) {
-        if (EI->getElement() == getEnumElementDecl(I->getType())) {
+        if (EI->getElement() == getEnumElementDecl(EI->getType())) {
           assert(EI->hasOperand() && "expected data operand");
           return EI->getOperand();
         }
@@ -853,7 +853,7 @@
   return Tree.getNode(Parent.getValue());
 }
 
-NullablePtr<SILInstruction>
+NullablePtr<SingleValueInstruction>
 ProjectionTreeNode::
 createProjection(SILBuilder &B, SILLocation Loc, SILValue Arg) const {
   if (!Proj)
@@ -876,8 +876,17 @@
 
     DEBUG(llvm::dbgs() << "        " << *User);
 
-    // First try to create a Projection for User.
-    auto P = Projection(User);
+    // The projections we can handle are always single-value instructions.
+    auto projectionInst = dyn_cast<SingleValueInstruction>(User);
+    if (!projectionInst) {
+      DEBUG(llvm::dbgs() << "            Failed to create projection. Adding "
+            "to non projection user!\n");
+      addNonProjectionUser(Op);
+      continue;
+    }
+
+    // Check whether the user is such a projection.
+    auto P = Projection(projectionInst);
 
     // If we fail to create a projection, add User as a user to this node and
     // continue.
@@ -890,8 +899,6 @@
 
     DEBUG(llvm::dbgs() << "            Created projection.\n");
 
-    assert(User->hasValue() && "Projections should have a value");
-
     // we have a projection to the next level children, create the next
     // level children nodes lazily.
     if (!Initialized)
@@ -906,7 +913,7 @@
       DEBUG(llvm::dbgs() << "            Found child for projection: "
             << ChildNode->getType() << "\n");
 
-      SILValue V = SILValue(User);
+      SILValue V = SILValue(projectionInst);
       Worklist.push_back({V, ChildNode});
     } else {
       DEBUG(llvm::dbgs() << "            Did not find a child for projection!. "
@@ -993,7 +1000,7 @@
   createNextLevelChildrenForTuple(Tree, TT);
 }
 
-SILInstruction *
+SingleValueInstruction *
 ProjectionTreeNode::
 createAggregate(SILBuilder &B, SILLocation Loc, ArrayRef<SILValue> Args) const {
   assert(Initialized && "Node must be initialized to create aggregates");
@@ -1042,7 +1049,7 @@
     });
   }
 
-  SILInstruction *createInstruction() const {
+  SingleValueInstruction *createInstruction() const {
     assert(isComplete() && "Cannot create instruction until the aggregate is "
            "complete");
     assert(!Invalidated && "Must not be invalidated to create an instruction");
@@ -1157,7 +1164,7 @@
   }
 
   // Form and return the aggregate.
-  NullablePtr<swift::SILInstruction> AI =
+  NullablePtr<SingleValueInstruction> AI =
       Projection::createAggFromFirstLevelProjections(Builder, Loc,
                                                      Node->getType(),
                                                      ChildValues);
@@ -1293,8 +1300,9 @@
       // projection to the worklist for processing.
       for (unsigned ChildIdx : reversed(Node->ChildProjections)) {
         const ProjectionTreeNode *ChildNode = getNode(ChildIdx);
-        SILInstruction *I = ChildNode->createProjection(B, Loc, V).get();
-        DEBUG(llvm::dbgs() << "    Adding Child: " << I->getType() << ": " << *I);
+        auto I = ChildNode->createProjection(B, Loc, V).get();
+        DEBUG(llvm::dbgs() << "    Adding Child: " << I->getType() << ": "
+                           << *I);
         Worklist.push_back(std::make_tuple(ChildNode, SILValue(I)));
       }
     } else {
diff --git a/lib/SIL/SILBasicBlock.cpp b/lib/SIL/SILBasicBlock.cpp
index e989698..957136d 100644
--- a/lib/SIL/SILBasicBlock.cpp
+++ b/lib/SIL/SILBasicBlock.cpp
@@ -95,6 +95,14 @@
   InstList.remove(I);
 }
 
+void SILBasicBlock::eraseInstructions() {
+ for (auto It = begin(); It != end();) {
+    auto *Inst = &*It++;
+    Inst->replaceAllUsesOfAllResultsWithUndef();
+    Inst->eraseFromParent();
+  }
+}
+
 /// Returns the iterator following the erased instruction.
 SILBasicBlock::iterator SILBasicBlock::erase(SILInstruction *I) {
   // Notify the delete handlers that this instruction is going away.
diff --git a/lib/SIL/SILBuilder.cpp b/lib/SIL/SILBuilder.cpp
index 36f4f67..06d7bff 100644
--- a/lib/SIL/SILBuilder.cpp
+++ b/lib/SIL/SILBuilder.cpp
@@ -90,9 +90,9 @@
 
 // If legal, create an unchecked_ref_cast from the given operand and result
 // type, otherwise return null.
-SILInstruction *SILBuilder::tryCreateUncheckedRefCast(SILLocation Loc,
-                                                      SILValue Op,
-                                                      SILType ResultTy) {
+SingleValueInstruction *
+SILBuilder::tryCreateUncheckedRefCast(SILLocation Loc, SILValue Op,
+                                      SILType ResultTy) {
   if (!SILType::canRefCast(Op->getType(), ResultTy, getModule()))
     return nullptr;
 
@@ -101,9 +101,8 @@
 }
 
 // Create the appropriate cast instruction based on result type.
-SILInstruction *SILBuilder::createUncheckedBitCast(SILLocation Loc,
-                                                   SILValue Op,
-                                                   SILType Ty) {
+SingleValueInstruction *
+SILBuilder::createUncheckedBitCast(SILLocation Loc, SILValue Op, SILType Ty) {
   if (Ty.isTrivial(getModule()))
     return insert(UncheckedTrivialBitCastInst::create(
         getSILDebugLocation(Loc), Op, Ty, getFunction(), OpenedArchetypes));
@@ -415,21 +414,30 @@
 
   while (I && I->getNumOperands() == 1 &&
          I->getNumTypeDependentOperands() == 0) {
-    I = dyn_cast<SILInstruction>(I->getOperand(0));
-    if (!I || !Visited.insert(I).second)
+    // All the open instructions are single-value instructions.
+    auto SVI = dyn_cast<SingleValueInstruction>(I->getOperand(0));
+    // Within SimplifyCFG this function may be called for an instruction
+    // within unreachable code. And within an unreachable block it can happen
+    // that defs do not dominate uses (because there is no dominance defined).
+    // To avoid the infinite loop when following the chain of instructions via
+    // their operands, bail if the operand is not an instruction or this
+    // instruction was seen already.
+    if (!SVI || !Visited.insert(SVI).second)
       return;
     // If it is a definition of an opened archetype,
     // register it and exit.
-    auto Archetype = getOpenedArchetypeOf(I);
-    if (!Archetype)
+    auto Archetype = getOpenedArchetypeOf(SVI);
+    if (!Archetype) {
+      I = SVI;
       continue;
+    }
     auto Def = OpenedArchetypes.getOpenedArchetypeDef(Archetype);
     // Return if it is a known open archetype.
     if (Def)
       return;
     // Otherwise register it and return.
     if (OpenedArchetypesTracker)
-      OpenedArchetypesTracker->addOpenedArchetypeDef(Archetype, I);
+      OpenedArchetypesTracker->addOpenedArchetypeDef(Archetype, SVI);
     return;
   }
 
diff --git a/lib/SIL/SILFunction.cpp b/lib/SIL/SILFunction.cpp
index 1e4747e..318f18f 100644
--- a/lib/SIL/SILFunction.cpp
+++ b/lib/SIL/SILFunction.cpp
@@ -57,7 +57,8 @@
     SILModule &M, SILLinkage linkage, StringRef name,
     CanSILFunctionType loweredType, GenericEnvironment *genericEnv,
     Optional<SILLocation> loc, IsBare_t isBareSILFunction,
-    IsTransparent_t isTrans, IsSerialized_t isSerialized, IsThunk_t isThunk,
+    IsTransparent_t isTrans, IsSerialized_t isSerialized,
+    ProfileCounter entryCount, IsThunk_t isThunk,
     SubclassScope classSubclassScope, Inline_t inlineStrategy, EffectsKind E,
     SILFunction *insertBefore, const SILDebugScope *debugScope) {
   // Get a StringMapEntry for the function.  As a sop to error cases,
@@ -72,8 +73,8 @@
 
   auto fn = new (M) SILFunction(M, linkage, name, loweredType, genericEnv, loc,
                                 isBareSILFunction, isTrans, isSerialized,
-                                isThunk, classSubclassScope, inlineStrategy, E,
-                                insertBefore, debugScope);
+                                entryCount, isThunk, classSubclassScope,
+                                inlineStrategy, E, insertBefore, debugScope);
 
   if (entry) entry->setValue(fn);
   return fn;
@@ -84,18 +85,18 @@
                          GenericEnvironment *genericEnv,
                          Optional<SILLocation> Loc, IsBare_t isBareSILFunction,
                          IsTransparent_t isTrans, IsSerialized_t isSerialized,
-                         IsThunk_t isThunk, SubclassScope classSubclassScope,
+                         ProfileCounter entryCount, IsThunk_t isThunk,
+                         SubclassScope classSubclassScope,
                          Inline_t inlineStrategy, EffectsKind E,
                          SILFunction *InsertBefore,
                          const SILDebugScope *DebugScope)
     : Module(Module), Name(Name), LoweredType(LoweredType),
       GenericEnv(genericEnv), SpecializationInfo(nullptr),
-      DebugScope(DebugScope), Bare(isBareSILFunction),
-      Transparent(isTrans), Serialized(isSerialized), Thunk(isThunk),
+      DebugScope(DebugScope), Bare(isBareSILFunction), Transparent(isTrans),
+      Serialized(isSerialized), Thunk(isThunk),
       ClassSubclassScope(unsigned(classSubclassScope)), GlobalInitFlag(false),
       InlineStrategy(inlineStrategy), Linkage(unsigned(Linkage)),
-      KeepAsPublic(false), EffectsKindAttr(E) {
-
+      KeepAsPublic(false), EffectsKindAttr(E), EntryCount(entryCount) {
   if (InsertBefore)
     Module.functions.insert(SILModule::iterator(InsertBefore), this);
   else
@@ -139,15 +140,25 @@
   return SILDeclRef::isClangGenerated(getClangNode());
 }
 
-void SILFunction::numberValues(llvm::DenseMap<const ValueBase*,
-                               unsigned> &ValueToNumberMap) const {
+void SILFunction::numberValues(llvm::DenseMap<const SILNode*, unsigned> &
+                                 ValueToNumberMap) const {
   unsigned idx = 0;
   for (auto &BB : *this) {
     for (auto I = BB.args_begin(), E = BB.args_end(); I != E; ++I)
       ValueToNumberMap[*I] = idx++;
     
-    for (auto &I : BB)
-      ValueToNumberMap[&I] = idx++;
+    for (auto &I : BB) {
+      auto results = I.getResults();
+      if (results.empty()) {
+        ValueToNumberMap[&I] = idx++;
+      } else {
+        // Assign the instruction node the first result ID.
+        ValueToNumberMap[&I] = idx;
+        for (auto result : results) {
+          ValueToNumberMap[result] = idx++;
+        }
+      }
+    }
   }
 }
 
diff --git a/lib/SIL/SILFunctionType.cpp b/lib/SIL/SILFunctionType.cpp
index 4a51087..dbb400d 100644
--- a/lib/SIL/SILFunctionType.cpp
+++ b/lib/SIL/SILFunctionType.cpp
@@ -100,6 +100,9 @@
   assert(getRepresentation() == SILFunctionTypeRepresentation::WitnessMethod);
   auto selfTy = getSelfInstanceType();
   if (auto paramTy = dyn_cast<GenericTypeParamType>(selfTy)) {
+    auto superclass = GenericSig->getSuperclassBound(paramTy, M);
+    if (superclass)
+      return nullptr;
     assert(paramTy->getDepth() == 0 && paramTy->getIndex() == 0);
     auto protos = GenericSig->getConformsTo(paramTy, M);
     assert(protos.size() == 1);
diff --git a/lib/SIL/SILGlobalVariable.cpp b/lib/SIL/SILGlobalVariable.cpp
index bffc48f..58612ac 100644
--- a/lib/SIL/SILGlobalVariable.cpp
+++ b/lib/SIL/SILGlobalVariable.cpp
@@ -79,7 +79,7 @@
 bool SILGlobalVariable::isValidStaticInitializerInst(const SILInstruction *I,
                                                      SILModule &M) {
   switch (I->getKind()) {
-    case ValueKind::BuiltinInst: {
+    case SILInstructionKind::BuiltinInst: {
       auto *bi = cast<BuiltinInst>(I);
       switch (M.getBuiltinInfo(bi->getName()).ID) {
         case BuiltinValueKind::PtrToInt:
@@ -91,7 +91,7 @@
       }
       return false;
     }
-    case ValueKind::StringLiteralInst:
+    case SILInstructionKind::StringLiteralInst:
       switch (cast<StringLiteralInst>(I)->getEncoding()) {
         case StringLiteralInst::Encoding::UTF8:
         case StringLiteralInst::Encoding::UTF16:
@@ -102,11 +102,11 @@
           return false;
       }
       return false;
-    case ValueKind::StructInst:
-    case ValueKind::TupleInst:
-    case ValueKind::IntegerLiteralInst:
-    case ValueKind::FloatLiteralInst:
-    case ValueKind::ObjectInst:
+    case SILInstructionKind::StructInst:
+    case SILInstructionKind::TupleInst:
+    case SILInstructionKind::IntegerLiteralInst:
+    case SILInstructionKind::FloatLiteralInst:
+    case SILInstructionKind::ObjectInst:
       return true;
     default:
       return false;
diff --git a/lib/SIL/SILInstruction.cpp b/lib/SIL/SILInstruction.cpp
index 90fc0f3..ca7832d 100644
--- a/lib/SIL/SILInstruction.cpp
+++ b/lib/SIL/SILInstruction.cpp
@@ -94,8 +94,8 @@
 //===----------------------------------------------------------------------===//
 
 // Assert that all subclasses of ValueBase implement classof.
-#define VALUE(CLASS, PARENT) \
-  ASSERT_IMPLEMENTS_STATIC(CLASS, PARENT, classof, bool(const ValueBase*));
+#define NODE(CLASS, PARENT) \
+  ASSERT_IMPLEMENTS_STATIC(CLASS, PARENT, classof, bool(const SILNode*));
 #include "swift/SIL/SILNodes.def"
 
 SILFunction *SILInstruction::getFunction() {
@@ -113,7 +113,11 @@
 /// block and deletes it.
 ///
 void SILInstruction::eraseFromParent() {
-  assert(use_empty() && "There are uses of instruction being deleted.");
+#ifndef NDEBUG
+  for (auto result : getResults()) {
+    assert(result->use_empty() && "Uses of SILInstruction remain at deletion.");
+  }
+#endif
   getParent()->erase(this);
 }
 
@@ -168,16 +172,33 @@
   }
 }
 
+ArrayRef<ValueBase> SILInstruction::getResultsImpl() const {
+  switch (getKind()) {
+#define NON_VALUE_INST(ID, NAME, PARENT, MEMBEHAVIOR, MAYRELEASE) \
+  case SILInstructionKind::ID:
+#include "swift/SIL/SILNodes.def"
+    return {};
+
+#define SINGLE_VALUE_INST(ID, NAME, PARENT, MEMBEHAVIOR, MAYRELEASE) \
+  case SILInstructionKind::ID:
+#include "swift/SIL/SILNodes.def"
+    return static_cast<const SingleValueInstruction *>(this)->getResultsImpl();
+
+  // add any multi-result instructions here...
+  }
+  llvm_unreachable("bad kind");
+}
+
 // Initialize the static members of SILInstruction.
 int SILInstruction::NumCreatedInstructions = 0;
 int SILInstruction::NumDeletedInstructions = 0;
 
 /// Map a SILInstruction name to its SILInstructionKind.
-SILInstructionKind swift::getSILInstructionKind(StringRef InstName) {
-  auto Kind = getSILValueKind(InstName);
-  if (Kind >= ValueKind::First_SILInstruction &&
-      Kind <= ValueKind::Last_SILInstruction)
-    return SILInstructionKind(Kind);
+SILInstructionKind swift::getSILInstructionKind(StringRef name) {
+#define FULL_INST(ID, NAME, PARENT, MEMBEHAVIOR, MAYRELEASE)  \
+  if (name == #NAME)                                          \
+    return SILInstructionKind::ID;
+#include "swift/SIL/SILNodes.def"
 
 #ifdef NDEBUG
   llvm::errs() << "Unknown SIL instruction name\n";
@@ -187,15 +208,45 @@
 }
 
 /// Map SILInstructionKind to a corresponding SILInstruction name.
-StringRef swift::getSILInstructionName(SILInstructionKind Kind) {
-  return getSILValueName(ValueKind(Kind));
+StringRef swift::getSILInstructionName(SILInstructionKind kind) {
+  switch (kind) {
+#define FULL_INST(ID, NAME, PARENT, MEMBEHAVIOR, MAYRELEASE)  \
+  case SILInstructionKind::ID:                                \
+    return #NAME;
+#include "swift/SIL/SILNodes.def"
+  }
+  llvm_unreachable("bad kind");
+}
+
+void SILInstruction::replaceAllUsesOfAllResultsWithUndef() {
+  for (auto result : getResults()) {
+    result->replaceAllUsesWithUndef();
+  }
+}
+
+void SILInstruction::replaceAllUsesPairwiseWith(SILInstruction *other) {
+  auto results = getResults();
+
+  // If we don't have any results, fast-path out without asking the other
+  // instruction for its results.
+  if (results.empty()) {
+    assert(other->getResults().empty());
+    return;
+  }
+
+  // Replace values with the corresponding values of the other instruction.
+  auto otherResults = other->getResults();
+  assert(results.size() == otherResults.size());
+  for (auto i : indices(results)) {
+    results[i]->replaceAllUsesWith(otherResults[i]);
+  }
 }
 
 namespace {
 class InstructionDestroyer
     : public SILInstructionVisitor<InstructionDestroyer> {
 public:
-#define INST(CLASS, PARENT, TEXTUALNAME, MEMBEHAVIOR, MAYRELEASE)              \
+#define INST(CLASS, PARENT) \
   void visit##CLASS(CLASS *I) { I->~CLASS(); }
 #include "swift/SIL/SILNodes.def"
   };
@@ -216,7 +267,7 @@
     InstructionIdentityComparer(const SILInstruction *L) : LHS(L) { }
 
     /// Make sure we only process instructions we know how to process.
-    bool visitValueBase(const ValueBase *RHS) {
+    bool visitSILInstruction(const SILInstruction *RHS) {
       return false;
     }
 
@@ -735,14 +786,10 @@
 }
 
 namespace {
-  class AllOperandsAccessor : public SILVisitor<AllOperandsAccessor,
-                                                ArrayRef<Operand> > {
+  class AllOperandsAccessor : public SILInstructionVisitor<AllOperandsAccessor,
+                                                           ArrayRef<Operand> > {
   public:
-#define VALUE(CLASS, PARENT) \
-    ArrayRef<Operand> visit##CLASS(const CLASS *I) {                    \
-      llvm_unreachable("accessing non-instruction " #CLASS);            \
-    }
-#define INST(CLASS, PARENT, TEXTUALNAME, MEMBEHAVIOR, RELEASINGBEHAVIOR)       \
+#define INST(CLASS, PARENT)                                                    \
   ArrayRef<Operand> visit##CLASS(const CLASS *I) {                             \
     ASSERT_IMPLEMENTS(CLASS, SILInstruction, getAllOperands,                   \
                       ArrayRef<Operand>() const);                              \
@@ -752,14 +799,10 @@
   };
 
   class AllOperandsMutableAccessor
-    : public SILVisitor<AllOperandsMutableAccessor,
-                        MutableArrayRef<Operand> > {
+    : public SILInstructionVisitor<AllOperandsMutableAccessor,
+                                   MutableArrayRef<Operand> > {
   public:
-#define VALUE(CLASS, PARENT) \
-    MutableArrayRef<Operand> visit##CLASS(const CLASS *I) {             \
-      llvm_unreachable("accessing non-instruction " #CLASS);            \
-    }
-#define INST(CLASS, PARENT, TEXTUALNAME, MEMBEHAVIOR, RELEASINGBEHAVIOR)       \
+#define INST(CLASS, PARENT)                                                    \
   MutableArrayRef<Operand> visit##CLASS(CLASS *I) {                            \
     ASSERT_IMPLEMENTS(CLASS, SILInstruction, getAllOperands,                   \
                       MutableArrayRef<Operand>());                             \
@@ -773,14 +816,10 @@
                                                      ExpectedType)>::value)
 
   class TypeDependentOperandsAccessor
-      : public SILVisitor<TypeDependentOperandsAccessor,
-                          ArrayRef<Operand>> {
+      : public SILInstructionVisitor<TypeDependentOperandsAccessor,
+                                     ArrayRef<Operand>> {
   public:
-#define VALUE(CLASS, PARENT) \
-    ArrayRef<Operand> visit##CLASS(const CLASS *I) {                    \
-      llvm_unreachable("accessing non-instruction " #CLASS);            \
-    }
-#define INST(CLASS, PARENT, TEXTUALNAME, MEMBEHAVIOR, RELEASINGBEHAVIOR)       \
+#define INST(CLASS, PARENT)                                                    \
   ArrayRef<Operand> visit##CLASS(const CLASS *I) {                             \
     if (!IMPLEMENTS_METHOD(CLASS, SILInstruction, getTypeDependentOperands,    \
                            ArrayRef<Operand>() const))                         \
@@ -791,14 +830,10 @@
   };
 
   class TypeDependentOperandsMutableAccessor
-    : public SILVisitor<TypeDependentOperandsMutableAccessor,
-                        MutableArrayRef<Operand> > {
+    : public SILInstructionVisitor<TypeDependentOperandsMutableAccessor,
+                                   MutableArrayRef<Operand> > {
   public:
-#define VALUE(CLASS, PARENT) \
-    MutableArrayRef<Operand> visit##CLASS(const CLASS *I) {             \
-      llvm_unreachable("accessing non-instruction " #CLASS);            \
-    }
-#define INST(CLASS, PARENT, TEXTUALNAME, MEMBEHAVIOR, RELEASINGBEHAVIOR)       \
+#define INST(CLASS, PARENT)                                                    \
   MutableArrayRef<Operand> visit##CLASS(CLASS *I) {                            \
     if (!IMPLEMENTS_METHOD(CLASS, SILInstruction, getTypeDependentOperands,    \
                            MutableArrayRef<Operand>()))                        \
@@ -868,28 +903,20 @@
   }
 
   switch (getKind()) {
-#define INST(CLASS, PARENT, TEXTUALNAME, MEMBEHAVIOR, RELEASINGBEHAVIOR)       \
-  case ValueKind::CLASS:                                                       \
+#define FULL_INST(CLASS, TEXTUALNAME, PARENT, MEMBEHAVIOR, RELEASINGBEHAVIOR)  \
+  case SILInstructionKind::CLASS:                                              \
     return MemoryBehavior::MEMBEHAVIOR;
 #include "swift/SIL/SILNodes.def"
-  case ValueKind::SILPHIArgument:
-  case ValueKind::SILFunctionArgument:
-  case ValueKind::SILUndef:
-    llvm_unreachable("Non-instructions are unreachable.");
   }
   llvm_unreachable("We've just exhausted the switch.");
 }
 
 SILInstruction::ReleasingBehavior SILInstruction::getReleasingBehavior() const {
   switch (getKind()) {
-#define INST(CLASS, PARENT, TEXTUALNAME, MEMBEHAVIOR, RELEASINGBEHAVIOR)       \
-  case ValueKind::CLASS:                                                       \
+#define FULL_INST(CLASS, TEXTUALNAME, PARENT, MEMBEHAVIOR, RELEASINGBEHAVIOR)  \
+  case SILInstructionKind::CLASS:                                              \
     return ReleasingBehavior::RELEASINGBEHAVIOR;
 #include "swift/SIL/SILNodes.def"
-  case ValueKind::SILPHIArgument:
-  case ValueKind::SILFunctionArgument:
-  case ValueKind::SILUndef:
-    llvm_unreachable("Non-instructions are unreachable.");
   }
   llvm_unreachable("We've just exhausted the switch.");
 }
@@ -914,37 +941,37 @@
   default:
     llvm_unreachable("Unhandled releasing instruction!");
 
-  case ValueKind::ApplyInst:
-  case ValueKind::TryApplyInst:
-  case ValueKind::DestroyAddrInst:
-  case ValueKind::StrongReleaseInst:
-  case ValueKind::UnownedReleaseInst:
-  case ValueKind::ReleaseValueInst:
-  case ValueKind::ReleaseValueAddrInst:
+  case SILInstructionKind::ApplyInst:
+  case SILInstructionKind::TryApplyInst:
+  case SILInstructionKind::DestroyAddrInst:
+  case SILInstructionKind::StrongReleaseInst:
+  case SILInstructionKind::UnownedReleaseInst:
+  case SILInstructionKind::ReleaseValueInst:
+  case SILInstructionKind::ReleaseValueAddrInst:
     return true;
 
-  case ValueKind::DestroyValueInst:
+  case SILInstructionKind::DestroyValueInst:
     assert(!SILModuleConventions(getModule()).useLoweredAddresses());
     return true;
 
-  case ValueKind::UnconditionalCheckedCastAddrInst:
-  case ValueKind::UnconditionalCheckedCastValueInst:
+  case SILInstructionKind::UnconditionalCheckedCastAddrInst:
+  case SILInstructionKind::UnconditionalCheckedCastValueInst:
     return true;
 
-  case ValueKind::CheckedCastAddrBranchInst: {
+  case SILInstructionKind::CheckedCastAddrBranchInst: {
     // Failing casts with take_always can release.
     auto *Cast = cast<CheckedCastAddrBranchInst>(this);
     return Cast->getConsumptionKind() == CastConsumptionKind::TakeAlways;
   }
 
-  case ValueKind::CopyAddrInst: {
+  case SILInstructionKind::CopyAddrInst: {
     auto *CopyAddr = cast<CopyAddrInst>(this);
     // copy_addr without initialization can cause a release.
     return CopyAddr->isInitializationOfDest() ==
            IsInitialization_t::IsNotInitialization;
   }
 
-  case ValueKind::BuiltinInst: {
+  case SILInstructionKind::BuiltinInst: {
     auto *BI = cast<BuiltinInst>(this);
     // Builtins without side effects also do not release.
     if (!BI->mayHaveSideEffects())
@@ -976,8 +1003,8 @@
 
 bool SILInstruction::mayReleaseOrReadRefCount() const {
   switch (getKind()) {
-  case ValueKind::IsUniqueInst:
-  case ValueKind::IsUniqueOrPinnedInst:
+  case SILInstructionKind::IsUniqueInst:
+  case SILInstructionKind::IsUniqueOrPinnedInst:
     return true;
   default:
     return mayRelease();
@@ -987,7 +1014,7 @@
 namespace {
   class TrivialCloner : public SILCloner<TrivialCloner> {
     friend class SILCloner<TrivialCloner>;
-    friend class SILVisitor<TrivialCloner>;
+    friend class SILInstructionVisitor<TrivialCloner>;
     SILInstruction *Result = nullptr;
     TrivialCloner(SILFunction *F) : SILCloner(*F) {}
   public:
@@ -1084,9 +1111,9 @@
 
 bool SILInstruction::mayTrap() const {
   switch(getKind()) {
-  case ValueKind::CondFailInst:
-  case ValueKind::UnconditionalCheckedCastInst:
-  case ValueKind::UnconditionalCheckedCastAddrInst:
+  case SILInstructionKind::CondFailInst:
+  case SILInstructionKind::UnconditionalCheckedCastInst:
+  case SILInstructionKind::UnconditionalCheckedCastAddrInst:
     return true;
   default:
     return false;
diff --git a/lib/SIL/SILInstructions.cpp b/lib/SIL/SILInstructions.cpp
index e3fa6c5..23c9ab2 100644
--- a/lib/SIL/SILInstructions.cpp
+++ b/lib/SIL/SILInstructions.cpp
@@ -131,8 +131,7 @@
                                ArrayRef<SILValue> TypeDependentOperands,
                                SILFunction &F,
                                SILDebugVariable Var)
-    : AllocationInst(ValueKind::AllocStackInst, Loc,
-                     elementType.getAddressType()),
+    : InstructionBase(Loc, elementType.getAddressType()),
       NumOperands(TypeDependentOperands.size()),
       VarInfo(Var, getTrailingObjects<char>()) {
   TrailingOperandsList::InitOperandsList(getAllOperands().begin(), this,
@@ -159,7 +158,7 @@
   return getLoc().getAsASTNode<VarDecl>();
 }
 
-AllocRefInstBase::AllocRefInstBase(ValueKind Kind,
+AllocRefInstBase::AllocRefInstBase(SILInstructionKind Kind,
                                    SILDebugLocation Loc,
                                    SILType ObjectType,
                                    bool objc, bool canBeOnStack,
@@ -231,8 +230,7 @@
 AllocBoxInst::AllocBoxInst(SILDebugLocation Loc, CanSILBoxType BoxType,
                            ArrayRef<SILValue> TypeDependentOperands,
                            SILFunction &F, SILDebugVariable Var)
-    : AllocationInst(ValueKind::AllocBoxInst, Loc,
-                     SILType::getPrimitiveObjectType(BoxType)),
+    : InstructionBase(Loc, SILType::getPrimitiveObjectType(BoxType)),
       NumOperands(TypeDependentOperands.size()),
       VarInfo(Var, getTrailingObjects<char>()) {
   TrailingOperandsList::InitOperandsList(getAllOperands().begin(), this,
@@ -294,8 +292,7 @@
     SILDebugLocation Loc, SILType ExistentialType, CanType ConcreteType,
     ArrayRef<ProtocolConformanceRef> Conformances,
     ArrayRef<SILValue> TypeDependentOperands, SILFunction *Parent)
-    : AllocationInst(ValueKind::AllocExistentialBoxInst, Loc,
-                     ExistentialType.getObjectType()),
+    : InstructionBase(Loc, ExistentialType.getObjectType()),
       NumOperands(TypeDependentOperands.size()),
       ConcreteType(ConcreteType), Conformances(Conformances) {
   TrailingOperandsList::InitOperandsList(getAllOperands().begin(), this,
@@ -374,7 +371,7 @@
 BuiltinInst::BuiltinInst(SILDebugLocation Loc, Identifier Name,
                          SILType ReturnType, SubstitutionList Subs,
                          ArrayRef<SILValue> Args)
-    : SILInstruction(ValueKind::BuiltinInst, Loc, ReturnType), Name(Name),
+    : InstructionBase(Loc, ReturnType), Name(Name),
       NumSubstitutions(Subs.size()), Operands(this, Args) {
   static_assert(IsTriviallyCopyable<Substitution>::value,
                 "assuming Substitution is trivially copyable");
@@ -402,8 +399,8 @@
                      ArrayRef<SILValue> Args, ArrayRef<SILValue> TypeDependentOperands,
                      bool isNonThrowing,
                      const GenericSpecializationInformation *SpecializationInfo)
-    : ApplyInstBase(ValueKind::ApplyInst, Loc, Callee, SubstCalleeTy, Subs,
-                    Args, TypeDependentOperands, SpecializationInfo, Result) {
+    : InstructionBase(Loc, Callee, SubstCalleeTy, Subs, Args,
+                      TypeDependentOperands, SpecializationInfo, Result) {
   setNonThrowing(isNonThrowing);
 }
 
@@ -452,9 +449,9 @@
     // PartialApplyInst
     // should derive the type of its result by partially applying the callee's
     // type.
-    : ApplyInstBase(ValueKind::PartialApplyInst, Loc, Callee, SubstCalleeTy,
-                    Subs, Args, TypeDependentOperands, SpecializationInfo,
-                    ClosureType) {}
+    : InstructionBase(Loc, Callee, SubstCalleeTy, Subs,
+                      Args, TypeDependentOperands, SpecializationInfo,
+                      ClosureType) {}
 
 PartialApplyInst *PartialApplyInst::create(
     SILDebugLocation Loc, SILValue Callee, ArrayRef<SILValue> Args,
@@ -476,10 +473,11 @@
                                         SpecializationInfo);
 }
 
-TryApplyInstBase::TryApplyInstBase(ValueKind valueKind, SILDebugLocation Loc,
+TryApplyInstBase::TryApplyInstBase(SILInstructionKind kind,
+                                   SILDebugLocation loc,
                                    SILBasicBlock *normalBB,
                                    SILBasicBlock *errorBB)
-    : TermInst(valueKind, Loc), DestBBs{{this, normalBB}, {this, errorBB}} {}
+    : TermInst(kind, loc), DestBBs{{this, normalBB}, {this, errorBB}} {}
 
 TryApplyInst::TryApplyInst(
     SILDebugLocation Loc, SILValue callee, SILType substCalleeTy,
@@ -487,9 +485,9 @@
     ArrayRef<SILValue> TypeDependentOperands, SILBasicBlock *normalBB,
     SILBasicBlock *errorBB,
     const GenericSpecializationInformation *SpecializationInfo)
-    : ApplyInstBase(ValueKind::TryApplyInst, Loc, callee, substCalleeTy, subs,
-                    args, TypeDependentOperands, SpecializationInfo, normalBB,
-                    errorBB) {}
+    : InstructionBase(Loc, callee, substCalleeTy, subs, args,
+                      TypeDependentOperands, SpecializationInfo, normalBB,
+                      errorBB) {}
 
 TryApplyInst *TryApplyInst::create(
     SILDebugLocation Loc, SILValue callee, SubstitutionList subs,
@@ -509,7 +507,7 @@
 }
 
 FunctionRefInst::FunctionRefInst(SILDebugLocation Loc, SILFunction *F)
-    : LiteralInst(ValueKind::FunctionRefInst, Loc, F->getLoweredType()),
+    : InstructionBase(Loc, F->getLoweredType()),
       Function(F) {
   F->incrementRefCount();
 }
@@ -527,21 +525,18 @@
 
 AllocGlobalInst::AllocGlobalInst(SILDebugLocation Loc,
                                  SILGlobalVariable *Global)
-    : SILInstruction(ValueKind::AllocGlobalInst, Loc),
+    : InstructionBase(Loc),
       Global(Global) {}
 
-AllocGlobalInst::AllocGlobalInst(SILDebugLocation Loc)
-    : SILInstruction(ValueKind::AllocGlobalInst, Loc) {}
-
 GlobalAddrInst::GlobalAddrInst(SILDebugLocation DebugLoc,
                                SILGlobalVariable *Global)
-      : GlobalAccessInst(ValueKind::GlobalAddrInst, DebugLoc, Global,
-                          Global->getLoweredType().getAddressType()) {}
+    : InstructionBase(DebugLoc, Global->getLoweredType().getAddressType(),
+                      Global) {}
 
 GlobalValueInst::GlobalValueInst(SILDebugLocation DebugLoc,
                                  SILGlobalVariable *Global)
-      : GlobalAccessInst(ValueKind::GlobalValueInst, DebugLoc, Global,
-                          Global->getLoweredType().getObjectType()) {}
+    : InstructionBase(DebugLoc, Global->getLoweredType().getObjectType(),
+                      Global) {}
 
 
 const IntrinsicInfo &BuiltinInst::getIntrinsicInfo() const {
@@ -571,7 +566,7 @@
 
 IntegerLiteralInst::IntegerLiteralInst(SILDebugLocation Loc, SILType Ty,
                                        const llvm::APInt &Value)
-    : LiteralInst(ValueKind::IntegerLiteralInst, Loc, Ty),
+    : InstructionBase(Loc, Ty),
       numBits(Value.getBitWidth()) {
   std::uninitialized_copy_n(Value.getRawData(), Value.getNumWords(),
                             getTrailingObjects<llvm::APInt::WordType>());
@@ -616,7 +611,7 @@
 
 FloatLiteralInst::FloatLiteralInst(SILDebugLocation Loc, SILType Ty,
                                    const APInt &Bits)
-    : LiteralInst(ValueKind::FloatLiteralInst, Loc, Ty),
+    : InstructionBase(Loc, Ty),
       numBits(Bits.getBitWidth()) {
         std::uninitialized_copy_n(Bits.getRawData(), Bits.getNumWords(),
                                   getTrailingObjects<llvm::APInt::WordType>());
@@ -660,7 +655,7 @@
 
 StringLiteralInst::StringLiteralInst(SILDebugLocation Loc, StringRef Text,
                                      Encoding encoding, SILType Ty)
-    : LiteralInst(ValueKind::StringLiteralInst, Loc, Ty), Length(Text.size()),
+    : InstructionBase(Loc, Ty), Length(Text.size()),
       TheEncoding(encoding) {
   memcpy(getTrailingObjects<char>(), Text.data(), Text.size());
 }
@@ -684,7 +679,7 @@
 ConstStringLiteralInst::ConstStringLiteralInst(SILDebugLocation Loc,
                                                StringRef Text,
                                                Encoding encoding, SILType Ty)
-    : LiteralInst(ValueKind::ConstStringLiteralInst, Loc, Ty),
+    : InstructionBase(Loc, Ty),
       Length(Text.size()), TheEncoding(encoding) {
   memcpy(getTrailingObjects<char>(), Text.data(), Text.size());
 }
@@ -709,17 +704,17 @@
 StoreInst::StoreInst(
     SILDebugLocation Loc, SILValue Src, SILValue Dest,
     StoreOwnershipQualifier Qualifier = StoreOwnershipQualifier::Unqualified)
-    : SILInstruction(ValueKind::StoreInst, Loc), Operands(this, Src, Dest),
+    : InstructionBase(Loc), Operands(this, Src, Dest),
       OwnershipQualifier(Qualifier) {}
 
 StoreBorrowInst::StoreBorrowInst(SILDebugLocation DebugLoc, SILValue Src,
                                  SILValue Dest)
-    : SILInstruction(ValueKind::StoreBorrowInst, DebugLoc, Dest->getType()),
+    : InstructionBase(DebugLoc, Dest->getType()),
       Operands(this, Src, Dest) {}
 
 EndBorrowInst::EndBorrowInst(SILDebugLocation DebugLoc, SILValue Src,
                              SILValue Dest)
-    : SILInstruction(ValueKind::EndBorrowInst, DebugLoc),
+    : InstructionBase(DebugLoc),
       Operands(this, Src, Dest) {}
 
 EndBorrowArgumentInst::EndBorrowArgumentInst(SILDebugLocation DebugLoc,
@@ -747,7 +742,7 @@
 }
 
 AssignInst::AssignInst(SILDebugLocation Loc, SILValue Src, SILValue Dest)
-    : SILInstruction(ValueKind::AssignInst, Loc), Operands(this, Src, Dest) {}
+    : InstructionBase(Loc), Operands(this, Src, Dest) {}
 
 MarkFunctionEscapeInst *
 MarkFunctionEscapeInst::create(SILDebugLocation Loc,
@@ -760,7 +755,7 @@
 
 MarkFunctionEscapeInst::MarkFunctionEscapeInst(SILDebugLocation Loc,
                                                ArrayRef<SILValue> Elems)
-    : SILInstruction(ValueKind::MarkFunctionEscapeInst, Loc),
+    : InstructionBase(Loc),
       Operands(this, Elems) {}
 
 static SILType getPinResultType(SILType operandType) {
@@ -777,7 +772,7 @@
 CopyAddrInst::CopyAddrInst(SILDebugLocation Loc, SILValue SrcLValue,
                            SILValue DestLValue, IsTake_t isTakeOfSrc,
                            IsInitialization_t isInitializationOfDest)
-    : SILInstruction(ValueKind::CopyAddrInst, Loc), IsTakeOfSrc(isTakeOfSrc),
+    : InstructionBase(Loc), IsTakeOfSrc(isTakeOfSrc),
       IsInitializationOfDest(isInitializationOfDest),
       Operands(this, SrcLValue, DestLValue) {}
 
@@ -800,7 +795,7 @@
                                SILValue Index,
                                SILType BoundType,
                                ArrayRef<SILValue> TypeDependentOperands)
-  : SILInstruction(ValueKind::BindMemoryInst, Loc),
+  : InstructionBase(Loc),
     BoundType(BoundType),
     NumOperands(NumFixedOpers + TypeDependentOperands.size()) {
   TrailingOperandsList::InitOperandsList(getAllOperands().begin(), this,
@@ -812,13 +807,13 @@
                                                    CanType srcType,
                                                    SILValue dest,
                                                    CanType targetType)
-    : SILInstruction(ValueKind::UncheckedRefCastAddrInst, Loc),
+    : InstructionBase(Loc),
       Operands(this, src, dest), SourceType(srcType), TargetType(targetType) {}
 
 UnconditionalCheckedCastAddrInst::UnconditionalCheckedCastAddrInst(
     SILDebugLocation Loc, SILValue src, CanType srcType, SILValue dest,
     CanType targetType)
-    : SILInstruction(ValueKind::UnconditionalCheckedCastAddrInst, Loc),
+    : InstructionBase(Loc),
       Operands(this, src, dest), SourceType(srcType), TargetType(targetType) {}
 
 StructInst *StructInst::create(SILDebugLocation Loc, SILType Ty,
@@ -831,7 +826,7 @@
 
 StructInst::StructInst(SILDebugLocation Loc, SILType Ty,
                        ArrayRef<SILValue> Elems)
-    : SILInstruction(ValueKind::StructInst, Loc, Ty), Operands(this, Elems) {
+    : InstructionBase(Loc, Ty), Operands(this, Elems) {
   assert(!Ty.getStructOrBoundGenericStruct()->hasUnreferenceableStorage());
 }
 
@@ -846,7 +841,7 @@
 
 ObjectInst::ObjectInst(SILDebugLocation Loc, SILType Ty,
                        ArrayRef<SILValue> Elems, unsigned NumBaseElements)
-    : SILInstruction(ValueKind::ObjectInst, Loc, Ty),
+    : InstructionBase(Loc, Ty),
       NumBaseElements(NumBaseElements), Operands(this, Elems) {}
 
 TupleInst *TupleInst::create(SILDebugLocation Loc, SILType Ty,
@@ -859,11 +854,11 @@
 
 TupleInst::TupleInst(SILDebugLocation Loc, SILType Ty,
                      ArrayRef<SILValue> Elems)
-    : SILInstruction(ValueKind::TupleInst, Loc, Ty), Operands(this, Elems) {}
+    : InstructionBase(Loc, Ty), Operands(this, Elems) {}
 
 MetatypeInst::MetatypeInst(SILDebugLocation Loc, SILType Metatype,
                            ArrayRef<SILValue> TypeDependentOperands)
-    : SILInstruction(ValueKind::MetatypeInst, Loc, Metatype),
+    : InstructionBase(Loc, Metatype),
       NumOperands(TypeDependentOperands.size()) {
   TrailingOperandsList::InitOperandsList(getAllOperands().begin(), this,
                                          TypeDependentOperands);
@@ -1038,31 +1033,32 @@
 
 
 TermInst::SuccessorListTy TermInst::getSuccessors() {
-#define TERMINATOR(TYPE, PARENT, TEXTUALNAME, EFFECT, RELEASING)               \
-  if (auto I = dyn_cast<TYPE>(this))                                           \
-    return I->getSuccessors();
+  switch (getKind()) {
+#define TERMINATOR(ID, NAME, PARENT, MEMBEHAVIOR, MAYRELEASE) \
+  case SILInstructionKind::ID: return cast<ID>(this)->getSuccessors();
 #include "swift/SIL/SILNodes.def"
-
-  llvm_unreachable("not a terminator?!");
+  default: llvm_unreachable("not a terminator");
+  }
+  llvm_unreachable("bad instruction kind");
 }
 
 bool TermInst::isFunctionExiting() const {
   switch (getTermKind()) {
-    case TermKind::BranchInst:
-    case TermKind::CondBranchInst:
-    case TermKind::SwitchValueInst:
-    case TermKind::SwitchEnumInst:
-    case TermKind::SwitchEnumAddrInst:
-    case TermKind::DynamicMethodBranchInst:
-    case TermKind::CheckedCastBranchInst:
-    case TermKind::CheckedCastValueBranchInst:
-    case TermKind::CheckedCastAddrBranchInst:
-    case TermKind::UnreachableInst:
-    case TermKind::TryApplyInst:
-      return false;
-    case TermKind::ReturnInst:
-    case TermKind::ThrowInst:
-      return true;
+  case TermKind::BranchInst:
+  case TermKind::CondBranchInst:
+  case TermKind::SwitchValueInst:
+  case TermKind::SwitchEnumInst:
+  case TermKind::SwitchEnumAddrInst:
+  case TermKind::DynamicMethodBranchInst:
+  case TermKind::CheckedCastBranchInst:
+  case TermKind::CheckedCastValueBranchInst:
+  case TermKind::CheckedCastAddrBranchInst:
+  case TermKind::UnreachableInst:
+  case TermKind::TryApplyInst:
+    return false;
+  case TermKind::ReturnInst:
+  case TermKind::ThrowInst:
+    return true;
   }
 
   llvm_unreachable("Unhandled TermKind in switch.");
@@ -1070,7 +1066,7 @@
 
 BranchInst::BranchInst(SILDebugLocation Loc, SILBasicBlock *DestBB,
                        ArrayRef<SILValue> Args)
-    : TermInst(ValueKind::BranchInst, Loc), DestBB(this, DestBB),
+    : InstructionBase(Loc), DestBB(this, DestBB),
       Operands(this, Args) {}
 
 BranchInst *BranchInst::create(SILDebugLocation Loc, SILBasicBlock *DestBB,
@@ -1090,26 +1086,32 @@
 CondBranchInst::CondBranchInst(SILDebugLocation Loc, SILValue Condition,
                                SILBasicBlock *TrueBB, SILBasicBlock *FalseBB,
                                ArrayRef<SILValue> Args, unsigned NumTrue,
-                               unsigned NumFalse)
-    : TermInst(ValueKind::CondBranchInst, Loc),
-      DestBBs{{this, TrueBB}, {this, FalseBB}}, NumTrueArgs(NumTrue),
-      NumFalseArgs(NumFalse), Operands(this, Args, Condition) {
+                               unsigned NumFalse, ProfileCounter TrueBBCount,
+                               ProfileCounter FalseBBCount)
+    : InstructionBase(Loc), DestBBs{{this, TrueBB, TrueBBCount},
+                                    {this, FalseBB, FalseBBCount}},
+      NumTrueArgs(NumTrue), NumFalseArgs(NumFalse),
+      Operands(this, Args, Condition) {
   assert(Args.size() == (NumTrueArgs + NumFalseArgs) &&
          "Invalid number of args");
   assert(TrueBB != FalseBB && "Identical destinations");
 }
 
-CondBranchInst *CondBranchInst::create(SILDebugLocation Loc,
-                                       SILValue Condition,
+CondBranchInst *CondBranchInst::create(SILDebugLocation Loc, SILValue Condition,
                                        SILBasicBlock *TrueBB,
-                                       SILBasicBlock *FalseBB, SILFunction &F) {
-  return create(Loc, Condition, TrueBB, {}, FalseBB, {}, F);
+                                       SILBasicBlock *FalseBB,
+                                       ProfileCounter TrueBBCount,
+                                       ProfileCounter FalseBBCount,
+                                       SILFunction &F) {
+  return create(Loc, Condition, TrueBB, {}, FalseBB, {}, TrueBBCount,
+                FalseBBCount, F);
 }
 
 CondBranchInst *
 CondBranchInst::create(SILDebugLocation Loc, SILValue Condition,
                        SILBasicBlock *TrueBB, ArrayRef<SILValue> TrueArgs,
                        SILBasicBlock *FalseBB, ArrayRef<SILValue> FalseArgs,
+                       ProfileCounter TrueBBCount, ProfileCounter FalseBBCount,
                        SILFunction &F) {
   SmallVector<SILValue, 4> Args;
   Args.append(TrueArgs.begin(), TrueArgs.end());
@@ -1119,7 +1121,8 @@
                               decltype(Operands)::getExtraSize(Args.size()),
                             alignof(CondBranchInst));
   return ::new (Buffer) CondBranchInst(Loc, Condition, TrueBB, FalseBB, Args,
-                                       TrueArgs.size(), FalseArgs.size());
+                                       TrueArgs.size(), FalseArgs.size(),
+                                       TrueBBCount, FalseBBCount);
 }
 
 OperandValueArrayRef CondBranchInst::getTrueArgs() const {
@@ -1209,7 +1212,7 @@
                                  SILBasicBlock *DefaultBB,
                                  ArrayRef<SILValue> Cases,
                                  ArrayRef<SILBasicBlock *> BBs)
-    : TermInst(ValueKind::SwitchValueInst, Loc), NumCases(Cases.size()),
+    : InstructionBase(Loc), NumCases(Cases.size()),
       HasDefault(bool(DefaultBB)), Operands(this, Cases, Operand) {
 
   // Initialize the successor array.
@@ -1281,9 +1284,9 @@
 SelectValueInst::SelectValueInst(SILDebugLocation Loc, SILValue Operand,
                                  SILType Type, SILValue DefaultResult,
                                  ArrayRef<SILValue> CaseValuesAndResults)
-    : SelectInstBase(ValueKind::SelectValueInst, Loc, Type,
-                     CaseValuesAndResults.size() / 2, bool(DefaultResult),
-                     CaseValuesAndResults, Operand) {
+    : InstructionBase(Loc, Type,
+                      CaseValuesAndResults.size() / 2, bool(DefaultResult),
+                      CaseValuesAndResults, Operand) {
 
   unsigned OperandBitWidth = 0;
 
@@ -1333,9 +1336,10 @@
 }
 
 SelectEnumInstBase::SelectEnumInstBase(
-    ValueKind Kind, SILDebugLocation Loc, SILValue Operand, SILType Ty,
+    SILInstructionKind Kind, SILDebugLocation Loc, SILType Ty, SILValue Operand,
     SILValue DefaultValue,
-    ArrayRef<std::pair<EnumElementDecl *, SILValue>> CaseValues)
+    ArrayRef<std::pair<EnumElementDecl *, SILValue>> CaseValues,
+    Optional<ArrayRef<ProfileCounter>> CaseCounts, ProfileCounter DefaultCount)
     : SelectInstBase(Kind, Loc, Ty, CaseValues.size(), bool(DefaultValue),
                      getCaseOperands(CaseValues, DefaultValue), Operand) {
   // Initialize the case and successor arrays.
@@ -1348,42 +1352,48 @@
 template <typename SELECT_ENUM_INST>
 SELECT_ENUM_INST *SelectEnumInstBase::createSelectEnum(
     SILDebugLocation Loc, SILValue Operand, SILType Ty, SILValue DefaultValue,
-    ArrayRef<std::pair<EnumElementDecl *, SILValue>> CaseValues,
-    SILFunction &F) {
+    ArrayRef<std::pair<EnumElementDecl *, SILValue>> CaseValues, SILFunction &F,
+    Optional<ArrayRef<ProfileCounter>> CaseCounts,
+    ProfileCounter DefaultCount) {
   // Allocate enough room for the instruction with tail-allocated
   // EnumElementDecl and operand arrays. There are `CaseBBs.size()` decls
   // and `CaseBBs.size() + (DefaultBB ? 1 : 0)` values.
   unsigned numCases = CaseValues.size();
 
   void *buf = F.getModule().allocateInst(
-    sizeof(SELECT_ENUM_INST) + sizeof(EnumElementDecl*) * numCases
-     + TailAllocatedOperandList<1>::getExtraSize(numCases + (bool)DefaultValue),
-    alignof(SELECT_ENUM_INST));
-  return ::new (buf) SELECT_ENUM_INST(Loc,Operand,Ty,DefaultValue,CaseValues);
+      sizeof(SELECT_ENUM_INST) + sizeof(EnumElementDecl *) * numCases +
+          sizeof(ProfileCounter) + TailAllocatedOperandList<1>::getExtraSize(
+                                       numCases + (bool)DefaultValue),
+      alignof(SELECT_ENUM_INST));
+  return ::new (buf) SELECT_ENUM_INST(Loc, Operand, Ty, DefaultValue,
+                                      CaseValues, CaseCounts, DefaultCount);
 }
 
 SelectEnumInst *SelectEnumInst::create(
-    SILDebugLocation Loc, SILValue Operand, SILType Type,
-    SILValue DefaultValue,
-    ArrayRef<std::pair<EnumElementDecl *, SILValue>> CaseValues,
-    SILFunction &F) {
+    SILDebugLocation Loc, SILValue Operand, SILType Type, SILValue DefaultValue,
+    ArrayRef<std::pair<EnumElementDecl *, SILValue>> CaseValues, SILFunction &F,
+    Optional<ArrayRef<ProfileCounter>> CaseCounts,
+    ProfileCounter DefaultCount) {
   return createSelectEnum<SelectEnumInst>(Loc, Operand, Type, DefaultValue,
-                                          CaseValues, F);
+                                          CaseValues, F, CaseCounts,
+                                          DefaultCount);
 }
 
 SelectEnumAddrInst *SelectEnumAddrInst::create(
-    SILDebugLocation Loc, SILValue Operand, SILType Type,
-    SILValue DefaultValue,
-    ArrayRef<std::pair<EnumElementDecl *, SILValue>> CaseValues,
-    SILFunction &F) {
+    SILDebugLocation Loc, SILValue Operand, SILType Type, SILValue DefaultValue,
+    ArrayRef<std::pair<EnumElementDecl *, SILValue>> CaseValues, SILFunction &F,
+    Optional<ArrayRef<ProfileCounter>> CaseCounts,
+    ProfileCounter DefaultCount) {
   return createSelectEnum<SelectEnumAddrInst>(Loc, Operand, Type, DefaultValue,
-                                              CaseValues, F);
+                                              CaseValues, F, CaseCounts,
+                                              DefaultCount);
 }
 
 SwitchEnumInstBase::SwitchEnumInstBase(
-    ValueKind Kind, SILDebugLocation Loc, SILValue Operand,
+    SILInstructionKind Kind, SILDebugLocation Loc, SILValue Operand,
     SILBasicBlock *DefaultBB,
-    ArrayRef<std::pair<EnumElementDecl *, SILBasicBlock *>> CaseBBs)
+    ArrayRef<std::pair<EnumElementDecl *, SILBasicBlock *>> CaseBBs,
+    Optional<ArrayRef<ProfileCounter>> CaseCounts, ProfileCounter DefaultCount)
     : TermInst(Kind, Loc), Operands(this, Operand), NumCases(CaseBBs.size()),
       HasDefault(bool(DefaultBB)) {
   // Initialize the case and successor arrays.
@@ -1391,11 +1401,17 @@
   auto *succs = getSuccessorBuf();
   for (unsigned i = 0, size = CaseBBs.size(); i < size; ++i) {
     cases[i] = CaseBBs[i].first;
-    ::new (succs + i) SILSuccessor(this, CaseBBs[i].second);
+    if (CaseCounts) {
+      ::new (succs + i)
+          SILSuccessor(this, CaseBBs[i].second, CaseCounts.getValue()[i]);
+    } else {
+      ::new (succs + i) SILSuccessor(this, CaseBBs[i].second);
+    }
   }
 
-  if (HasDefault)
-    ::new (succs + NumCases) SILSuccessor(this, DefaultBB);
+  if (HasDefault) {
+    ::new (succs + NumCases) SILSuccessor(this, DefaultBB, DefaultCount);
+  }
 }
 
 void SwitchEnumInstBase::swapCase(unsigned i, unsigned j) {
@@ -1493,18 +1509,20 @@
 SWITCH_ENUM_INST *SwitchEnumInstBase::createSwitchEnum(
     SILDebugLocation Loc, SILValue Operand, SILBasicBlock *DefaultBB,
     ArrayRef<std::pair<EnumElementDecl *, SILBasicBlock *>> CaseBBs,
-    SILFunction &F) {
+    SILFunction &F, Optional<ArrayRef<ProfileCounter>> CaseCounts,
+    ProfileCounter DefaultCount) {
   // Allocate enough room for the instruction with tail-allocated
   // EnumElementDecl and SILSuccessor arrays. There are `CaseBBs.size()` decls
   // and `CaseBBs.size() + (DefaultBB ? 1 : 0)` successors.
   unsigned numCases = CaseBBs.size();
   unsigned numSuccessors = numCases + (DefaultBB ? 1 : 0);
 
-  void *buf = F.getModule().allocateInst(sizeof(SWITCH_ENUM_INST)
-                                       + sizeof(EnumElementDecl*) * numCases
-                                       + sizeof(SILSuccessor) * numSuccessors,
-                                     alignof(SWITCH_ENUM_INST));
-  return ::new (buf) SWITCH_ENUM_INST(Loc, Operand, DefaultBB, CaseBBs);
+  void *buf = F.getModule().allocateInst(
+      sizeof(SWITCH_ENUM_INST) + sizeof(EnumElementDecl *) * numCases +
+          sizeof(SILSuccessor) * numSuccessors,
+      alignof(SWITCH_ENUM_INST));
+  return ::new (buf) SWITCH_ENUM_INST(Loc, Operand, DefaultBB, CaseBBs,
+                                      CaseCounts, DefaultCount);
 }
 
 NullablePtr<EnumElementDecl> SwitchEnumInstBase::getUniqueCaseForDefault() {
@@ -1537,17 +1555,19 @@
 SwitchEnumInst *SwitchEnumInst::create(
     SILDebugLocation Loc, SILValue Operand, SILBasicBlock *DefaultBB,
     ArrayRef<std::pair<EnumElementDecl *, SILBasicBlock *>> CaseBBs,
-    SILFunction &F) {
-  return
-    createSwitchEnum<SwitchEnumInst>(Loc, Operand, DefaultBB, CaseBBs, F);
+    SILFunction &F, Optional<ArrayRef<ProfileCounter>> CaseCounts,
+    ProfileCounter DefaultCount) {
+  return createSwitchEnum<SwitchEnumInst>(Loc, Operand, DefaultBB, CaseBBs, F,
+                                          CaseCounts, DefaultCount);
 }
 
 SwitchEnumAddrInst *SwitchEnumAddrInst::create(
     SILDebugLocation Loc, SILValue Operand, SILBasicBlock *DefaultBB,
     ArrayRef<std::pair<EnumElementDecl *, SILBasicBlock *>> CaseBBs,
-    SILFunction &F) {
-  return createSwitchEnum<SwitchEnumAddrInst>
-    (Loc, Operand, DefaultBB, CaseBBs, F);
+    SILFunction &F, Optional<ArrayRef<ProfileCounter>> CaseCounts,
+    ProfileCounter DefaultCount) {
+  return createSwitchEnum<SwitchEnumAddrInst>(Loc, Operand, DefaultBB, CaseBBs,
+                                              F, CaseCounts, DefaultCount);
 }
 
 DynamicMethodBranchInst::DynamicMethodBranchInst(SILDebugLocation Loc,
@@ -1555,7 +1575,7 @@
                                                  SILDeclRef Member,
                                                  SILBasicBlock *HasMethodBB,
                                                  SILBasicBlock *NoMethodBB)
-  : TermInst(ValueKind::DynamicMethodBranchInst, Loc),
+  : InstructionBase(Loc),
     Member(Member),
     DestBBs{{this, HasMethodBB}, {this, NoMethodBB}},
     Operands(this, Operand)
@@ -1760,7 +1780,7 @@
                                         SubstitutionList SetterSubs,
                                         SILValue Self,
                                         SILType Ty)
-  : SILInstruction(ValueKind::MarkUninitializedBehaviorInst, DebugLoc, Ty),
+  : InstructionBase(DebugLoc, Ty),
     Operands(this, InitStorage, Storage, Setter, Self),
     NumInitStorageSubstitutions(InitStorageSubs.size()),
     NumSetterSubstitutions(SetterSubs.size())
@@ -1908,7 +1928,8 @@
 CheckedCastBranchInst *CheckedCastBranchInst::create(
     SILDebugLocation DebugLoc, bool IsExact, SILValue Operand, SILType DestTy,
     SILBasicBlock *SuccessBB, SILBasicBlock *FailureBB, SILFunction &F,
-    SILOpenedArchetypesState &OpenedArchetypes) {
+    SILOpenedArchetypesState &OpenedArchetypes, ProfileCounter Target1Count,
+    ProfileCounter Target2Count) {
   SILModule &Mod = F.getModule();
   SmallVector<SILValue, 8> TypeDependentOperands;
   collectTypeDependentOperands(TypeDependentOperands, OpenedArchetypes, F,
@@ -1916,9 +1937,9 @@
   unsigned size =
       totalSizeToAlloc<swift::Operand>(1 + TypeDependentOperands.size());
   void *Buffer = Mod.allocateInst(size, alignof(CheckedCastBranchInst));
-  return ::new (Buffer) CheckedCastBranchInst(DebugLoc, IsExact, Operand,
-                                              TypeDependentOperands, DestTy,
-                                              SuccessBB, FailureBB);
+  return ::new (Buffer) CheckedCastBranchInst(
+      DebugLoc, IsExact, Operand, TypeDependentOperands, DestTy, SuccessBB,
+      FailureBB, Target1Count, Target2Count);
 }
 
 CheckedCastValueBranchInst *
@@ -2223,7 +2244,7 @@
                          SubstitutionList Subs,
                          ArrayRef<SILValue> Args,
                          SILType Ty)
-  : SILInstruction(ValueKind::KeyPathInst, Loc, Ty),
+  : InstructionBase(Loc, Ty),
     Pattern(Pattern), NumSubstitutions(Subs.size()),
     NumOperands(Pattern->getNumOperands())
 {
diff --git a/lib/SIL/SILModule.cpp b/lib/SIL/SILModule.cpp
index 6f5628b..a58001d 100644
--- a/lib/SIL/SILModule.cpp
+++ b/lib/SIL/SILModule.cpp
@@ -229,15 +229,11 @@
   witnessTables.erase(Wt);
 }
 
-SILFunction *SILModule::getOrCreateFunction(SILLocation loc,
-                                            StringRef name,
-                                            SILLinkage linkage,
-                                            CanSILFunctionType type,
-                                            IsBare_t isBareSILFunction,
-                                            IsTransparent_t isTransparent,
-                                            IsSerialized_t isSerialized,
-                                            IsThunk_t isThunk,
-                                            SubclassScope subclassScope) {
+SILFunction *SILModule::getOrCreateFunction(
+    SILLocation loc, StringRef name, SILLinkage linkage,
+    CanSILFunctionType type, IsBare_t isBareSILFunction,
+    IsTransparent_t isTransparent, IsSerialized_t isSerialized,
+    ProfileCounter entryCount, IsThunk_t isThunk, SubclassScope subclassScope) {
   if (auto fn = lookUpFunction(name)) {
     assert(fn->getLoweredFunctionType() == type);
     assert(fn->getLinkage() == linkage ||
@@ -245,9 +241,9 @@
     return fn;
   }
 
-  auto fn = SILFunction::create(*this, linkage, name, type, nullptr,
-                                loc, isBareSILFunction, isTransparent,
-                                isSerialized, isThunk, subclassScope);
+  auto fn = SILFunction::create(*this, linkage, name, type, nullptr, loc,
+                                isBareSILFunction, isTransparent, isSerialized,
+                                entryCount, isThunk, subclassScope);
   fn->setDebugScope(new (*this) SILDebugScope(loc, fn));
   return fn;
 }
@@ -282,7 +278,8 @@
 
 SILFunction *SILModule::getOrCreateFunction(SILLocation loc,
                                             SILDeclRef constant,
-                                            ForDefinition_t forDefinition) {
+                                            ForDefinition_t forDefinition,
+                                            ProfileCounter entryCount) {
 
   auto name = constant.mangle();
   auto constantType = Types.getConstantType(constant).castTo<SILFunctionType>();
@@ -320,11 +317,10 @@
   else if (constant.isAlwaysInline())
     inlineStrategy = AlwaysInline;
 
-  auto *F = SILFunction::create(*this, linkage, name,
-                                constantType, nullptr,
-                                None, IsNotBare, IsTrans, IsSer, IsNotThunk,
-                                constant.getSubclassScope(),
-                                inlineStrategy, EK);
+  auto *F =
+      SILFunction::create(*this, linkage, name, constantType, nullptr, None,
+                          IsNotBare, IsTrans, IsSer, entryCount, IsNotThunk,
+                          constant.getSubclassScope(), inlineStrategy, EK);
   F->setDebugScope(new (*this) SILDebugScope(loc, F));
 
   F->setGlobalInit(constant.isGlobal());
@@ -364,30 +360,26 @@
   return F;
 }
 
-
-SILFunction *SILModule::getOrCreateSharedFunction(SILLocation loc,
-                                                  StringRef name,
-                                                  CanSILFunctionType type,
-                                                  IsBare_t isBareSILFunction,
-                                                  IsTransparent_t isTransparent,
-                                                  IsSerialized_t isSerialized,
-                                                  IsThunk_t isThunk) {
-  return getOrCreateFunction(loc, name, SILLinkage::Shared,
-                             type, isBareSILFunction, isTransparent, isSerialized,
-                             isThunk, SubclassScope::NotApplicable);
+SILFunction *SILModule::getOrCreateSharedFunction(
+    SILLocation loc, StringRef name, CanSILFunctionType type,
+    IsBare_t isBareSILFunction, IsTransparent_t isTransparent,
+    IsSerialized_t isSerialized, ProfileCounter entryCount, IsThunk_t isThunk) {
+  return getOrCreateFunction(loc, name, SILLinkage::Shared, type,
+                             isBareSILFunction, isTransparent, isSerialized,
+                             entryCount, isThunk, SubclassScope::NotApplicable);
 }
 
 SILFunction *SILModule::createFunction(
     SILLinkage linkage, StringRef name, CanSILFunctionType loweredType,
     GenericEnvironment *genericEnv, Optional<SILLocation> loc,
     IsBare_t isBareSILFunction, IsTransparent_t isTrans,
-    IsSerialized_t isSerialized, IsThunk_t isThunk, SubclassScope subclassScope,
-    Inline_t inlineStrategy, EffectsKind EK, SILFunction *InsertBefore,
-    const SILDebugScope *DebugScope) {
+    IsSerialized_t isSerialized, ProfileCounter entryCount, IsThunk_t isThunk,
+    SubclassScope subclassScope, Inline_t inlineStrategy, EffectsKind EK,
+    SILFunction *InsertBefore, const SILDebugScope *DebugScope) {
   return SILFunction::create(*this, linkage, name, loweredType, genericEnv, loc,
-                             isBareSILFunction, isTrans, isSerialized, isThunk,
-                             subclassScope, inlineStrategy, EK, InsertBefore,
-                             DebugScope);
+                             isBareSILFunction, isTrans, isSerialized,
+                             entryCount, isThunk, subclassScope, inlineStrategy,
+                             EK, InsertBefore, DebugScope);
 }
 
 const IntrinsicInfo &SILModule::getIntrinsicInfo(Identifier ID) {
@@ -734,9 +726,9 @@
   NotificationHandlers.remove(Handler);
 }
 
-void SILModule::notifyDeleteHandlers(ValueBase *V) {
+void SILModule::notifyDeleteHandlers(SILNode *node) {
   for (auto *Handler : NotificationHandlers) {
-    Handler->handleDeleteNotification(V);
+    Handler->handleDeleteNotification(node);
   }
 }
 
diff --git a/lib/SIL/SILOpenedArchetypesTracker.cpp b/lib/SIL/SILOpenedArchetypesTracker.cpp
index 82552e1..e3e8b7f 100644
--- a/lib/SIL/SILOpenedArchetypesTracker.cpp
+++ b/lib/SIL/SILOpenedArchetypesTracker.cpp
@@ -16,7 +16,7 @@
 using namespace swift;
 
 void SILOpenedArchetypesTracker::addOpenedArchetypeDef(CanArchetypeType archetype,
-                                                       SILValue Def) {
+                                                       SingleValueInstruction *Def) {
   auto OldDef = getOpenedArchetypeDef(archetype);
   if (OldDef) {
     if (auto *OldI = dyn_cast<GlobalAddrInst>(OldDef)) {
@@ -25,7 +25,7 @@
       OldDef->replaceAllUsesWith(Def);
       // Remove the placeholder instruction.
       OldI->eraseFromParent();
-      OldDef = SILValue();
+      OldDef = nullptr;
     }
   }
   assert((!OldDef || OldDef == Def) &&
@@ -65,7 +65,7 @@
     auto &SILMod = CurF->getModule();
     // Create a placeholder representing a forward definition.
     // Add the placeholder at the beginning of the entry block.
-    SILValue Placeholder;
+    SingleValueInstruction *Placeholder;
     if (!CurF->getEntryBlock()->empty()) {
       SILBuilder B(CurF->getEntryBlock()->begin());
       Placeholder =
@@ -95,7 +95,9 @@
   auto Archetype = getOpenedArchetypeOf(I);
   if (!Archetype)
     return false;
-  addOpenedArchetypeDef(Archetype, I);
+  auto SVI =
+    const_cast<SingleValueInstruction*>(cast<SingleValueInstruction>(I));
+  addOpenedArchetypeDef(Archetype, SVI);
   return true;
 }
 
@@ -108,8 +110,8 @@
   bool Registered = false;
   for (auto &Op : I->getTypeDependentOperands()) {
     auto OpenedArchetypeDef = Op.get();
-    if (auto *DefInst = dyn_cast<SILInstruction>(OpenedArchetypeDef)) {
-      addOpenedArchetypeDef(getOpenedArchetypeOf(DefInst), OpenedArchetypeDef);
+    if (auto *DefInst = dyn_cast<SingleValueInstruction>(OpenedArchetypeDef)) {
+      addOpenedArchetypeDef(getOpenedArchetypeOf(DefInst), DefInst);
       Registered = true;
     }
   }
@@ -122,19 +124,23 @@
     const SILInstruction *I) {
   assert(I->getFunction() == getFunction() &&
          "Instruction does not belong to a proper SILFunction");
-  auto Archetype = getOpenedArchetypeOf(I);
+  auto archetype = getOpenedArchetypeOf(I);
   // Remove the archetype definition if it was registered before.
   // It may happen that this archetype was not registered in the
   // SILOpenedArchetypesTracker, because the tracker was created
   // without scanning the whole function and thus may not aware
   // of all opened archetypes of the function.
-  if (Archetype && getOpenedArchetypeDef(Archetype))
-    removeOpenedArchetypeDef(Archetype, I);
+  if (archetype) {
+    auto def = getOpenedArchetypeDef(archetype);
+    if (def == I) {
+      OpenedArchetypeDefs.erase(archetype);
+    }
+  }
 }
 
 void SILOpenedArchetypesTracker::handleDeleteNotification(
-    swift::ValueBase *Value) {
-  if (auto I = dyn_cast<SILInstruction>(Value))
+    swift::SILNode *node) {
+  if (auto I = dyn_cast<SILInstruction>(node))
     if (I->getFunction() == getFunction())
       unregisterOpenedArchetypes(I);
 }
@@ -145,7 +151,8 @@
   if (isa<OpenExistentialAddrInst>(I) || isa<OpenExistentialRefInst>(I) ||
       isa<OpenExistentialBoxInst>(I) || isa<OpenExistentialBoxValueInst>(I) ||
       isa<OpenExistentialMetatypeInst>(I) || isa<OpenExistentialValueInst>(I)) {
-    auto Ty = getOpenedArchetypeOf(I->getType().getSwiftRValueType());
+    auto SVI = cast<SingleValueInstruction>(I);
+    auto Ty = getOpenedArchetypeOf(SVI->getType().getSwiftRValueType());
     assert(Ty && Ty->isOpenedExistential() &&
            "Type should be an opened archetype");
     return Ty;
@@ -180,9 +187,9 @@
   // First perform a quick check.
   for (auto &Op : OpenedArchetypeOperands) {
     auto Def = Op.get();
-    if (isa<SILInstruction>(Def) &&
-        getOpenedArchetypeOf(cast<SILInstruction>(Def)) == archetypeTy)
-      return Def;
+    if (auto SVI = dyn_cast<SingleValueInstruction>(Def))
+      if (getOpenedArchetypeOf(SVI) == archetypeTy)
+        return Def;
   }
   // Then use a regular lookup.
   if (OpenedArchetypesTracker)
diff --git a/lib/SIL/SILOwnershipVerifier.cpp b/lib/SIL/SILOwnershipVerifier.cpp
index 1553796..307c4fc 100644
--- a/lib/SIL/SILOwnershipVerifier.cpp
+++ b/lib/SIL/SILOwnershipVerifier.cpp
@@ -191,23 +191,23 @@
 }
 
 // These operations forward both owned and guaranteed ownership.
-static bool isOwnershipForwardingValueKind(ValueKind K) {
+static bool isOwnershipForwardingValueKind(SILNodeKind K) {
   switch (K) {
-  case ValueKind::TupleInst:
-  case ValueKind::StructInst:
-  case ValueKind::EnumInst:
-  case ValueKind::OpenExistentialRefInst:
-  case ValueKind::UpcastInst:
-  case ValueKind::UncheckedRefCastInst:
-  case ValueKind::ConvertFunctionInst:
-  case ValueKind::RefToBridgeObjectInst:
-  case ValueKind::BridgeObjectToRefInst:
-  case ValueKind::UnconditionalCheckedCastInst:
-  case ValueKind::UncheckedEnumDataInst:
-  case ValueKind::MarkUninitializedInst:
-  case ValueKind::SelectEnumInst:
-  case ValueKind::SwitchEnumInst:
-  case ValueKind::CheckedCastBranchInst:
+  case SILNodeKind::TupleInst:
+  case SILNodeKind::StructInst:
+  case SILNodeKind::EnumInst:
+  case SILNodeKind::OpenExistentialRefInst:
+  case SILNodeKind::UpcastInst:
+  case SILNodeKind::UncheckedRefCastInst:
+  case SILNodeKind::ConvertFunctionInst:
+  case SILNodeKind::RefToBridgeObjectInst:
+  case SILNodeKind::BridgeObjectToRefInst:
+  case SILNodeKind::UnconditionalCheckedCastInst:
+  case SILNodeKind::UncheckedEnumDataInst:
+  case SILNodeKind::MarkUninitializedInst:
+  case SILNodeKind::SelectEnumInst:
+  case SILNodeKind::SwitchEnumInst:
+  case SILNodeKind::CheckedCastBranchInst:
     return true;
   default:
     return false;
@@ -216,12 +216,12 @@
 
 // These operations forward guaranteed ownership, but don't necessarily forward
 // owned values.
-static bool isGuaranteedForwardingValueKind(ValueKind K) {
+static bool isGuaranteedForwardingValueKind(SILNodeKind K) {
   switch (K) {
-  case ValueKind::TupleExtractInst:
-  case ValueKind::StructExtractInst:
-  case ValueKind::OpenExistentialValueInst:
-  case ValueKind::OpenExistentialBoxValueInst:
+  case SILNodeKind::TupleExtractInst:
+  case SILNodeKind::StructExtractInst:
+  case SILNodeKind::OpenExistentialValueInst:
+  case SILNodeKind::OpenExistentialBoxValueInst:
     return true;
   default:
     return isOwnershipForwardingValueKind(K);
@@ -229,15 +229,15 @@
 }
 
 static bool isGuaranteedForwardingValue(SILValue V) {
-  return isGuaranteedForwardingValueKind(V->getKind());
+  return isGuaranteedForwardingValueKind(SILNodeKind(V->getKind()));
 }
 
 static bool isGuaranteedForwardingInst(SILInstruction *I) {
-  return isGuaranteedForwardingValueKind(I->getKind());
+  return isGuaranteedForwardingValueKind(SILNodeKind(I->getKind()));
 }
 
 static bool isOwnershipForwardingInst(SILInstruction *I) {
-  return isOwnershipForwardingValueKind(I->getKind());
+  return isOwnershipForwardingValueKind(SILNodeKind(I->getKind()));
 }
 
 //===----------------------------------------------------------------------===//
@@ -403,17 +403,13 @@
     return Result.ShouldCheckForDataflowViolations;
   }
 
-  OwnershipUseCheckerResult visitValueBase(ValueBase *) {
-    llvm_unreachable("Unimplemented?!");
-  }
-
   OwnershipUseCheckerResult visitCallee(CanSILFunctionType SubstCalleeType);
   OwnershipUseCheckerResult
   checkTerminatorArgumentMatchesDestBB(SILBasicBlock *DestBB, unsigned OpIndex);
 
 // Create declarations for all instructions, so we get a warning at compile
 // time if any instructions do not have an implementation.
-#define INST(Id, Parent, TextualName, MemBehavior, MayRelease)                 \
+#define INST(Id, Parent) \
   OwnershipUseCheckerResult visit##Id(Id *);
 #include "swift/SIL/SILNodes.def"
 };
@@ -1691,20 +1687,28 @@
     // or trivial. We now split into two cases, if the user is a terminator or
     // not. If we do not have a terminator, then just add User->getUses() to the
     // worklist.
-    auto *TI = dyn_cast<TermInst>(User);
-    if (!TI) {
-      if (SILValue(User).getOwnershipKind() == ValueOwnershipKind::Trivial) {
+    if (auto *value = dyn_cast<SingleValueInstruction>(User)) {
+      if (SILValue(value).getOwnershipKind() == ValueOwnershipKind::Trivial) {
         continue;
       }
 
       // Now, we /must/ have a guaranteed subobject, so lets assert that the
       // user
       // is actually guaranteed and add the subobject's users to our worklist.
-      assert(SILValue(User).getOwnershipKind() ==
+      assert(SILValue(value).getOwnershipKind() ==
                  ValueOwnershipKind::Guaranteed &&
              "Our value is guaranteed and this is a forwarding instruction. "
              "Should have guaranteed ownership as well.");
-      std::copy(User->use_begin(), User->use_end(), std::back_inserter(Users));
+      std::copy(value->use_begin(), value->use_end(),
+                std::back_inserter(Users));
+      continue;
+    }
+
+    // TODO: MultiValueInstruction
+    assert(User->getResults().empty());
+
+    auto *TI = dyn_cast<TermInst>(User);
+    if (!TI) {
       continue;
     }
 
diff --git a/lib/SIL/SILPrinter.cpp b/lib/SIL/SILPrinter.cpp
index 586da8c..351c3c6 100644
--- a/lib/SIL/SILPrinter.cpp
+++ b/lib/SIL/SILPrinter.cpp
@@ -447,13 +447,12 @@
   
 /// SILPrinter class - This holds the internal implementation details of
 /// printing SIL structures.
-class SILPrinter : public SILVisitor<SILPrinter> {
+class SILPrinter : public SILInstructionVisitor<SILPrinter> {
   SILPrintContext &Ctx;
   struct {
     llvm::formatted_raw_ostream OS;
     PrintOptions ASTOptions;
   } PrintState;
-  SILValue subjectValue;
   unsigned LastBufferID;
 
   // Printers for the underlying stream.
@@ -464,6 +463,7 @@
   }
   SIMPLE_PRINTER(char)
   SIMPLE_PRINTER(unsigned)
+  SIMPLE_PRINTER(uint64_t)
   SIMPLE_PRINTER(StringRef)
   SIMPLE_PRINTER(Identifier)
   SIMPLE_PRINTER(ID)
@@ -644,7 +644,7 @@
   //===--------------------------------------------------------------------===//
   // SILInstruction Printing Logic
 
-  bool printTypeDependentOperands(SILInstruction *I) {
+  bool printTypeDependentOperands(const SILInstruction *I) {
     ArrayRef<Operand> TypeDepOps = I->getTypeDependentOperands();
     if (TypeDepOps.empty())
       return false;
@@ -659,10 +659,27 @@
 
   /// Print out the users of the SILValue \p V. Return true if we printed out
   /// either an id or a use list. Return false otherwise.
-  bool printUsersOfSILValue(SILValue V, bool printedSlashes) {
+  bool printUsersOfSILNode(const SILNode *node, bool printedSlashes) {
+    SILInstruction::ResultArrayRef values;
+    if (auto value = dyn_cast<ValueBase>(node)) {
+      // The base pointer of the ultimate ArrayRef here is just the
+      // ValueBase; we aren't forming a reference to a temporary array.
+      values = ArrayRef<ValueBase>(value, 1);
+    } else if (auto inst = dyn_cast<SILInstruction>(node)) {
+      values = inst->getResults();
+    }
 
-    if (V->hasValue() && V->use_empty())
-      return printedSlashes;
+    // If the set of values is empty, we need to print the ID of
+    // the instruction.  Otherwise, if none of the values has a use,
+    // we don't need to do anything.
+    if (!values.empty()) {
+      bool hasUse = false;
+      for (auto value : values) {
+        if (!value->use_empty()) hasUse = true;
+      }
+      if (!hasUse)
+        return printedSlashes;
+    }
 
     if (printedSlashes) {
       *this << "; ";
@@ -670,23 +687,21 @@
       PrintState.OS.PadToColumn(50);
       *this << "// ";
     }
-    if (!V->hasValue()) {
-      *this << "id: " << Ctx.getID(V);
+    if (values.empty()) {
+      *this << "id: " << Ctx.getID(node);
       return true;
     }
 
-    if (V->use_empty())
-      return true;
+    llvm::SmallVector<ID, 32> UserIDs;
+    for (auto value : values)
+      for (auto *Op : value->getUses())
+        UserIDs.push_back(Ctx.getID(Op->getUser()));
 
     *this << "user";
-    if (std::next(V->use_begin()) != V->use_end())
+    if (UserIDs.size() != 1)
       *this << 's';
     *this << ": ";
 
-    llvm::SmallVector<ID, 32> UserIDs;
-    for (auto *Op : V->getUses())
-      UserIDs.push_back(Ctx.getID(Op->getUser()));
-
     // If we are asked to, display the user ids sorted to give a stable use
     // order in the printer's output. This makes diffing large sections of SIL
     // significantly easier.
@@ -825,69 +840,114 @@
     }
   }
 
-  void printInstOpCode(SILInstruction *I) {
-    *this << getSILValueName(I->getKind()) << " ";
+  void printInstOpCode(const SILInstruction *I) {
+    *this << getSILInstructionName(I->getKind()) << " ";
   }
 
-  void print(SILValue V) {
-    if (auto *FRI = dyn_cast<FunctionRefInst>(V))
+  void print(const SILInstruction *I) {
+    if (auto *FRI = dyn_cast<FunctionRefInst>(I))
       *this << "  // function_ref "
             << demangleSymbol(FRI->getReferencedFunction()->getName())
             << "\n";
 
     *this << "  ";
 
-    SILInstruction *I = dyn_cast<SILInstruction>(V);
-
-    // Print result.
-    if (V->hasValue()) {
-      if (I && I->isStaticInitializerInst() && I == &I->getParent()->back()) {
-        *this << "%initval = ";
-      } else {
-        ID Name = Ctx.getID(V);
-        *this << Name << " = ";
+    // Print results.
+    auto results = I->getResults();
+    if (results.size() == 1 &&
+        I->isStaticInitializerInst() &&
+        I == &I->getParent()->back()) {
+      *this << "%initval = ";
+    } else if (results.size() == 1) {
+      ID Name = Ctx.getID(results[0]);
+      *this << Name << " = ";
+    } else if (results.size() > 1) {
+      *this << '(';
+      bool first = true;
+      for (auto result : results) {
+        if (first) {
+          first = false;
+        } else {
+          *this << ", ";
+        }
+        ID Name = Ctx.getID(result);
+        *this << Name;
       }
+      *this << ") = ";
     }
 
-    // First if we have a SILInstruction, print the opcode.
-    if (auto *I = dyn_cast<SILInstruction>(V))
-      printInstOpCode(I);
+    // Print the opcode.
+    printInstOpCode(I);
 
-    // Then print the value.
-    visit(V);
+    // Use the visitor to print the rest of the instruction.
+    visit(const_cast<SILInstruction*>(I));
 
+    // Maybe print debugging information.
     bool printedSlashes = false;
-    if (I) {
-      if (Ctx.printDebugInfo() && !I->isStaticInitializerInst()) {
-        auto &SM = I->getModule().getASTContext().SourceMgr;
-        printDebugLocRef(I->getLoc(), SM);
-        printDebugScopeRef(I->getDebugScope(), SM);
-      }
-      printedSlashes = printTypeDependentOperands(I);
+    if (Ctx.printDebugInfo() && !I->isStaticInitializerInst()) {
+      auto &SM = I->getModule().getASTContext().SourceMgr;
+      printDebugLocRef(I->getLoc(), SM);
+      printDebugScopeRef(I->getDebugScope(), SM);
     }
+    printedSlashes = printTypeDependentOperands(I);
 
     // Print users, or id for valueless instructions.
-    printedSlashes = printUsersOfSILValue(V, printedSlashes);
+    printedSlashes = printUsersOfSILNode(I, printedSlashes);
 
     // Print SIL location.
     if (Ctx.printVerbose()) {
-      if (I) {
-        printSILLocation(I->getLoc(), I->getModule(), I->getDebugScope(),
-                         printedSlashes);
-      }
+      printSILLocation(I->getLoc(), I->getModule(), I->getDebugScope(),
+                       printedSlashes);
     }
     
     *this << '\n';
   }
-  
-  void printInContext(SILValue V) {
-    subjectValue = V;
 
-    auto sortByID = [&](SILValue a, SILValue b) {
+  void print(const SILNode *node) {
+    switch (node->getKind()) {
+#define INST(ID, PARENT) \
+    case SILNodeKind::ID:
+#include "swift/SIL/SILNodes.def"
+      print(cast<SingleValueInstruction>(node));
+      return;
+
+    // TODO: MultiValueInstruction
+
+#define ARGUMENT(ID, PARENT) \
+    case SILNodeKind::ID:
+#include "swift/SIL/SILNodes.def"
+      printSILArgument(cast<SILArgument>(node));
+      return;
+
+    case SILNodeKind::SILUndef:
+      printSILUndef(cast<SILUndef>(node));
+      return;
+    }
+    llvm_unreachable("bad kind");
+  }
+
+  void printSILArgument(const SILArgument *arg) {
+    // This should really only happen during debugging.
+    *this << Ctx.getID(arg) << " = argument of "
+          << Ctx.getID(arg->getParent()) << " : " << arg->getType();
+
+    // Print users.
+    (void) printUsersOfSILNode(arg, false);
+
+    *this << '\n';
+  }
+
+  void printSILUndef(const SILUndef *undef) {
+    // This should really only happen during debugging.
+    *this << "undef<" << undef->getType() << ">\n";
+  }
+  
+  void printInContext(const SILNode *node) {
+    auto sortByID = [&](const SILNode *a, const SILNode *b) {
       return Ctx.getID(a).Number < Ctx.getID(b).Number;
     };
 
-    if (auto *I = dyn_cast<SILInstruction>(V)) {
+    if (auto *I = dyn_cast<SILInstruction>(node)) {
       auto operands = map<SmallVector<SILValue,4>>(I->getAllOperands(),
                                                    [](Operand const &o) {
                                                      return o.get();
@@ -900,30 +960,21 @@
     }
     
     *this << "-> ";
-    print(V);
-    
-    auto users = map<SmallVector<SILValue,4>>(V->getUses(),
-                                              [](Operand *o) {
-                                                return o->getUser();
-                                              });
-    std::sort(users.begin(), users.end(), sortByID);
-    for (auto &user : users) {
-      *this << "   ";
-      print(user);
+    print(node);
+
+    if (auto V = dyn_cast<ValueBase>(node)) {    
+      auto users = map<SmallVector<const SILInstruction*,4>>(V->getUses(),
+                                                       [](Operand *o) {
+                                                         return o->getUser();
+                                                       });
+      std::sort(users.begin(), users.end(), sortByID);
+      for (auto &user : users) {
+        *this << "   ";
+        print(user);
+      }
     }
   }
 
-  void visitSILArgument(SILArgument *A) {
-    // This should really only happen during debugging.
-    *this << "argument of " << Ctx.getID(A->getParent()) << " : "
-          << A->getType();
-  }
-
-  void visitSILUndef(SILUndef *A) {
-    // This should really only happen during debugging.
-    *this << "undef<" << A->getType() << ">";
-  }
-
   void printDebugVar(SILDebugVariable Var) {
     if (Var.Name.empty())
       return;
@@ -1279,6 +1330,10 @@
     *this << getIDAndType(CI->getOperand()) << " to " << CI->getCastType()
           << ", " << Ctx.getID(CI->getSuccessBB()) << ", "
           << Ctx.getID(CI->getFailureBB());
+    if (CI->getTrueBBCount())
+      *this << " !true_count(" << CI->getTrueBBCount().getValue() << ")";
+    if (CI->getFalseBBCount())
+      *this << " !false_count(" << CI->getFalseBBCount().getValue() << ")";
   }
 
   void visitCheckedCastValueBranchInst(CheckedCastValueBranchInst *CI) {
@@ -1305,6 +1360,10 @@
           << getIDAndType(CI->getDest()) << ", "
           << Ctx.getID(CI->getSuccessBB()) << ", "
           << Ctx.getID(CI->getFailureBB());
+    if (CI->getTrueBBCount())
+      *this << " !true_count(" << CI->getTrueBBCount().getValue() << ")";
+    if (CI->getFalseBBCount())
+      *this << " !false_count(" << CI->getFalseBBCount().getValue() << ")";
   }
 
   void printUncheckedConversionInst(ConversionInst *CI, SILValue operand) {
@@ -1657,6 +1716,11 @@
       *this << "[nonatomic] ";
     *this << getIDAndType(I->getOperand(0));
   }
+  void visitStrongPinInst(StrongPinInst *I) {
+    if (I->isNonAtomic())
+      *this << "[nonatomic] ";
+    *this << getIDAndType(I->getOperand());
+  }
   void visitIsUniqueInst(IsUniqueInst *CUI) {
     *this << getIDAndType(CUI->getOperand());
   }
@@ -1765,9 +1829,16 @@
       std::tie(elt, dest) = SOI->getCase(i);
       *this << ", case " << SILDeclRef(elt, SILDeclRef::Kind::EnumElement)
             << ": " << Ctx.getID(dest);
+      if (SOI->getCaseCount(i)) {
+        *this << " !case_count(" << SOI->getCaseCount(i).getValue() << ")";
+      }
     }
-    if (SOI->hasDefault())
+    if (SOI->hasDefault()) {
       *this << ", default " << Ctx.getID(SOI->getDefaultBB());
+      if (SOI->getDefaultCount()) {
+        *this << " !default_count(" << SOI->getDefaultCount().getValue() << ")";
+      }
+    }
   }
   
   void visitSwitchEnumInst(SwitchEnumInst *SOI) {
@@ -1842,6 +1913,10 @@
     printBranchArgs(CBI->getTrueArgs());
     *this << ", " << Ctx.getID(CBI->getFalseBB());
     printBranchArgs(CBI->getFalseArgs());
+    if (CBI->getTrueBBCount())
+      *this << " !true_count(" << CBI->getTrueBBCount().getValue() << ")";
+    if (CBI->getFalseBBCount())
+      *this << " !false_count(" << CBI->getFalseBBCount().getValue() << ")";
   }
   
   void visitKeyPathInst(KeyPathInst *KPI) {
@@ -1985,11 +2060,24 @@
 // Printing for SILInstruction, SILBasicBlock, SILFunction, and SILModule
 //===----------------------------------------------------------------------===//
 
-void ValueBase::dump() const {
+void SILNode::dump() const {
   print(llvm::errs());
 }
 
-void ValueBase::print(raw_ostream &OS) const {
+void SILNode::print(raw_ostream &OS) const {
+  SILPrintContext Ctx(OS);
+  SILPrinter(Ctx).print(this);
+}
+
+void SILInstruction::dump() const {
+  print(llvm::errs());
+}
+
+void SingleValueInstruction::dump() const {
+  SILInstruction::dump();
+}
+
+void SILInstruction::print(raw_ostream &OS) const {
   SILPrintContext Ctx(OS);
   SILPrinter(Ctx).print(this);
 }
@@ -2167,6 +2255,9 @@
   }
   
   if (!isExternalDeclaration()) {
+    if (auto eCount = getEntryCount()) {
+      OS << " !function_entry_count(" << eCount.getValue() << ")";
+    }
     OS << " {\n";
 
     SILPrinter(PrintCtx, (Aliases.empty() ? nullptr : &Aliases))
@@ -2429,10 +2520,18 @@
   OS << "\n\n";
 }
 
-void ValueBase::dumpInContext() const {
+void SILNode::dumpInContext() const {
   printInContext(llvm::errs());
 }
-void ValueBase::printInContext(llvm::raw_ostream &OS) const {
+void SILNode::printInContext(llvm::raw_ostream &OS) const {
+  SILPrintContext Ctx(OS);
+  SILPrinter(Ctx).printInContext(this);
+}
+
+void SILInstruction::dumpInContext() const {
+  printInContext(llvm::errs());
+}
+void SILInstruction::printInContext(llvm::raw_ostream &OS) const {
   SILPrintContext Ctx(OS);
   SILPrinter(Ctx).printInContext(this);
 }
@@ -2779,11 +2878,11 @@
   return R;
 }
 
-ID SILPrintContext::getID(SILValue V) {
-  if (isa<SILUndef>(V))
+ID SILPrintContext::getID(const SILNode *node) {
+  if (isa<SILUndef>(node))
     return {ID::SILUndef, 0};
   
-  SILBasicBlock *BB = V->getParentBlock();
+  SILBasicBlock *BB = node->getParentBlock();
   if (SILFunction *F = BB->getParent()) {
     setContext(F);
     // Lazily initialize the instruction -> ID mapping.
@@ -2795,10 +2894,26 @@
     if (ValueToIDMap.empty()) {
       unsigned idx = 0;
       for (auto &I : *BB) {
-        ValueToIDMap[&I] = idx++;
+        // Give the instruction itself the next ID.
+        ValueToIDMap[&I] = idx;
+
+        // If there are no results, make sure we don't reuse that ID.
+        auto results = I.getResults();
+        if (results.empty()) {
+          idx++;
+
+        // Otherwise, assign all of the results an index.  Note that
+        // we'll assign the same ID to both the instruction and the
+        // first result.
+        } else {
+          for (auto result : results) {
+            ValueToIDMap[result] = idx++;
+          }
+        }
       }
     }
   }
-  ID R = {ID::SSAValue, ValueToIDMap[V]};
+
+  ID R = {ID::SSAValue, ValueToIDMap[node]};
   return R;
 }
diff --git a/lib/SIL/SILValue.cpp b/lib/SIL/SILValue.cpp
index 6ed5a0e..d1c6c82 100644
--- a/lib/SIL/SILValue.cpp
+++ b/lib/SIL/SILValue.cpp
@@ -57,33 +57,59 @@
   }
 }
 
-SILBasicBlock *ValueBase::getParentBlock() const {
-  auto *NonConstThis = const_cast<ValueBase *>(this);
+SILInstruction *ValueBase::getDefiningInstruction() {
+  if (auto inst = dyn_cast<SingleValueInstruction>(this))
+    return inst;
+  // TODO: MultiValueInstruction
+  return nullptr;
+}
+
+Optional<ValueBase::DefiningInstructionResult>
+ValueBase::getDefiningInstructionResult() {
+  if (auto inst = dyn_cast<SingleValueInstruction>(this))
+    return DefiningInstructionResult{ inst, 0 };
+  // TODO: MultiValueInstruction
+  return None;
+}
+
+SILBasicBlock *SILNode::getParentBlock() const {
+  auto *NonConstThis = const_cast<SILNode *>(this);
   if (auto *Inst = dyn_cast<SILInstruction>(NonConstThis))
     return Inst->getParent();
+  // TODO: MultiValueInstruction
   if (auto *Arg = dyn_cast<SILArgument>(NonConstThis))
     return Arg->getParent();
   return nullptr;
 }
 
-SILFunction *ValueBase::getFunction() const {
-  auto *NonConstThis = const_cast<ValueBase *>(this);
+SILFunction *SILNode::getFunction() const {
+  auto *NonConstThis = const_cast<SILNode *>(this);
   if (auto *Inst = dyn_cast<SILInstruction>(NonConstThis))
     return Inst->getFunction();
+  // TODO: MultiValueInstruction
   if (auto *Arg = dyn_cast<SILArgument>(NonConstThis))
     return Arg->getFunction();
   return nullptr;
 }
 
-SILModule *ValueBase::getModule() const {
-  auto *NonConstThis = const_cast<ValueBase *>(this);
+SILModule *SILNode::getModule() const {
+  auto *NonConstThis = const_cast<SILNode *>(this);
   if (auto *Inst = dyn_cast<SILInstruction>(NonConstThis))
     return &Inst->getModule();
+  // TODO: MultiValueInstruction
   if (auto *Arg = dyn_cast<SILArgument>(NonConstThis))
     return &Arg->getModule();
   return nullptr;
 }
 
+const SILNode *SILNode::getCanonicalSILNodeSlowPath() const {
+  assert(getStorageLoc() != SILNodeStorageLocation::Instruction &&
+         hasMultipleSILNodes(getKind()));
+  return &static_cast<const SILInstruction &>(
+            static_cast<const SingleValueInstruction &>(
+              static_cast<const ValueBase &>(*this)));
+}
+
 //===----------------------------------------------------------------------===//
 //                             ValueOwnershipKind
 //===----------------------------------------------------------------------===//
@@ -183,9 +209,10 @@
   return Classifier.visit(const_cast<ValueBase *>(Value));
 }
 
+#if 0
 /// Map a SILValue mnemonic name to its ValueKind.
 ValueKind swift::getSILValueKind(StringRef Name) {
-#define INST(Id, Parent, TextualName, MemoryBehavior, ReleasingBehavior)       \
+#define SINGLE_VALUE_INST(Id, TextualName, Parent, MemoryBehavior, ReleasingBehavior)       \
   if (Name == #TextualName)                                                    \
     return ValueKind::Id;
 
@@ -206,16 +233,15 @@
 /// Map ValueKind to a corresponding mnemonic name.
 StringRef swift::getSILValueName(ValueKind Kind) {
   switch (Kind) {
-#define INST(Id, Parent, TextualName, MemoryBehavior, ReleasingBehavior)       \
+#define SINGLE_VALUE_INST(Id, TextualName, Parent, MemoryBehavior, ReleasingBehavior)       \
   case ValueKind::Id:                                                          \
-    return #TextualName;                                                       \
-    break;
+    return #TextualName;
 
 #define VALUE(Id, Parent)                                                      \
   case ValueKind::Id:                                                          \
-    return #Id;                                                                \
-    break;
+    return #Id;
 
 #include "swift/SIL/SILNodes.def"
   }
 }
+#endif
diff --git a/lib/SIL/SILVerifier.cpp b/lib/SIL/SILVerifier.cpp
index 0a97d1f..ef91739 100644
--- a/lib/SIL/SILVerifier.cpp
+++ b/lib/SIL/SILVerifier.cpp
@@ -79,11 +79,11 @@
 
 /// Metaprogramming-friendly base class.
 template <class Impl>
-class SILVerifierBase : public SILVisitor<Impl> {
+class SILVerifierBase : public SILInstructionVisitor<Impl> {
 public:
   // visitCLASS calls visitPARENT and checkCLASS.
   // checkCLASS does nothing by default.
-#define VALUE(CLASS, PARENT)                                    \
+#define INST(CLASS, PARENT)                                     \
   void visit##CLASS(CLASS *I) {                                 \
     static_cast<Impl*>(this)->visit##PARENT(I);                 \
     static_cast<Impl*>(this)->check##CLASS(I);                  \
@@ -91,10 +91,10 @@
   void check##CLASS(CLASS *I) {}
 #include "swift/SIL/SILNodes.def"
 
-  void visitValueBase(ValueBase *V) {
-    static_cast<Impl*>(this)->checkValueBase(V);
+  void visitSILInstruction(SILInstruction *I) {
+    static_cast<Impl*>(this)->checkSILInstruction(I);
   }
-  void checkValueBase(ValueBase *V) {}
+  void checkSILInstruction(SILInstruction *I) {}
 };
 } // end anonymous namespace
 
@@ -471,14 +471,14 @@
     // Check the SILLLocation attached to the instruction.
     checkInstructionsSILLocation(I);
 
-    checkLegalType(I->getFunction(), I, I);
-
     // Check ownership.
     SILFunction *F = I->getFunction();
     assert(F && "Expected value base with parent function");
 
-    // Check ownership.
-    checkValueBaseOwnership(I);
+    for (auto result : I->getResults()) {
+      checkLegalType(F, result, I);
+      checkValueBaseOwnership(result);
+    }
   }
 
   void checkValueBaseOwnership(ValueBase *V) {
@@ -486,10 +486,6 @@
     if (!isSILOwnershipEnabled())
       return;
 
-    // If V does not have a value, bail.
-    if (!V->hasValue())
-      return;
-
     SILFunction *F = V->getFunction();
     assert(F && "Expected value base with parent function");
     // If we do not have qualified ownership, then do not verify value base
@@ -518,32 +514,34 @@
     }
 
     // Verify that all of our uses are in this function.
-    for (Operand *use : I->getUses()) {
-      auto user = use->getUser();
-      require(user, "instruction user is null?");
-      require(isa<SILInstruction>(user),
-              "instruction used by non-instruction");
-      auto userI = cast<SILInstruction>(user);
-      require(userI->getParent(),
-              "instruction used by unparented instruction");
-      if (I->isStaticInitializerInst()) {
-        require(userI->getParent() == BB,
-              "instruction used by instruction not in same static initializer");
-      } else {
-        require(userI->getFunction() == &F,
-                "instruction used by instruction in different function");
-      }
+    for (auto result : I->getResults()) {
+      for (Operand *use : result->getUses()) {
+        auto user = use->getUser();
+        require(user, "instruction user is null?");
+        require(isa<SILInstruction>(user),
+                "instruction used by non-instruction");
+        auto userI = cast<SILInstruction>(user);
+        require(userI->getParent(),
+                "instruction used by unparented instruction");
+        if (I->isStaticInitializerInst()) {
+          require(userI->getParent() == BB,
+                "instruction used by instruction not in same static initializer");
+        } else {
+          require(userI->getFunction() == &F,
+                  "instruction used by instruction in different function");
+        }
 
-      auto operands = userI->getAllOperands();
-      require(operands.begin() <= use && use <= operands.end(),
-              "use doesn't actually belong to instruction it claims to");
+        auto operands = userI->getAllOperands();
+        require(operands.begin() <= use && use <= operands.end(),
+                "use doesn't actually belong to instruction it claims to");
+      }
     }
 
     // Verify some basis structural stuff about an instruction's operands.
     for (auto &operand : I->getAllOperands()) {
       require(operand.get(), "instruction has null operand");
 
-      if (auto *valueI = dyn_cast<SILInstruction>(operand.get())) {
+      if (auto *valueI = operand.get()->getDefiningInstruction()) {
         require(valueI->getParent(),
                 "instruction uses value of unparented instruction");
         if (I->isStaticInitializerInst()) {
@@ -598,7 +596,7 @@
     // Check the location kind.
     SILLocation L = I->getLoc();
     SILLocation::LocationKind LocKind = L.getKind();
-    ValueKind InstKind = I->getKind();
+    SILInstructionKind InstKind = I->getKind();
 
     // Check that there is at most one debug variable defined
     // for each argument slot. This catches SIL transformations
@@ -642,20 +640,20 @@
     // Fix incoming.
     if (LocKind == SILLocation::CleanupKind ||
         LocKind == SILLocation::InlinedKind)
-      require(InstKind != ValueKind::ReturnInst ||
-              InstKind != ValueKind::AutoreleaseReturnInst,
+      require(InstKind != SILInstructionKind::ReturnInst ||
+              InstKind != SILInstructionKind::AutoreleaseReturnInst,
         "cleanup and inlined locations are not allowed on return instructions");
 #endif
 
     if (LocKind == SILLocation::ReturnKind ||
         LocKind == SILLocation::ImplicitReturnKind)
-      require(InstKind == ValueKind::BranchInst ||
-              InstKind == ValueKind::ReturnInst ||
-              InstKind == ValueKind::UnreachableInst,
+      require(InstKind == SILInstructionKind::BranchInst ||
+              InstKind == SILInstructionKind::ReturnInst ||
+              InstKind == SILInstructionKind::UnreachableInst,
         "return locations are only allowed on branch and return instructions");
 
     if (LocKind == SILLocation::ArtificialUnreachableKind)
-      require(InstKind == ValueKind::UnreachableInst,
+      require(InstKind == SILInstructionKind::UnreachableInst,
         "artificial locations are only allowed on Unreachable instructions");
   }
 
@@ -876,9 +874,9 @@
         require((ValueBase *)V == AI->getFunction()->getSelfMetadataArgument(),
                 "wrong self metadata operand");
       } else {
-        require(isa<SILInstruction>(V),
+        require(isa<SingleValueInstruction>(V),
                 "opened archetype operand should refer to a SIL instruction");
-        auto Archetype = getOpenedArchetypeOf(cast<SILInstruction>(V));
+        auto Archetype = getOpenedArchetypeOf(cast<SingleValueInstruction>(V));
         require(Archetype,
                 "opened archetype operand should define an opened archetype");
         require(FoundOpenedArchetypes.count(Archetype),
@@ -1925,7 +1923,6 @@
   }
 
   void checkBindMemoryInst(BindMemoryInst *BI) {
-    require(!BI->getType(), "BI must not produce a type");
     require(BI->getBoundType(), "BI must have a bound type");
     require(BI->getBase()->getType().is<BuiltinRawPointerType>(),
             "bind_memory base be a RawPointer");
@@ -2343,34 +2340,34 @@
         if (inst->isTypeDependentOperand(*use))
           continue;
         switch (inst->getKind()) {
-        case ValueKind::ApplyInst:
-        case ValueKind::TryApplyInst:
-        case ValueKind::PartialApplyInst:
+        case SILInstructionKind::ApplyInst:
+        case SILInstructionKind::TryApplyInst:
+        case SILInstructionKind::PartialApplyInst:
           if (isConsumingOrMutatingApplyUse(use))
             return true;
           else
             break;
-        case ValueKind::CopyAddrInst:
+        case SILInstructionKind::CopyAddrInst:
           if (isConsumingOrMutatingCopyAddrUse(use))
             return true;
           else
             break;
-        case ValueKind::DestroyAddrInst:
+        case SILInstructionKind::DestroyAddrInst:
           return true;
-        case ValueKind::UncheckedAddrCastInst:
+        case SILInstructionKind::UncheckedAddrCastInst:
           // Escaping use lets be conservative here.
           return true;
-        case ValueKind::CheckedCastAddrBranchInst:
+        case SILInstructionKind::CheckedCastAddrBranchInst:
           if (cast<CheckedCastAddrBranchInst>(inst)->getConsumptionKind() !=
               CastConsumptionKind::CopyOnSuccess)
             return true;
           break;
-        case ValueKind::LoadInst:
+        case SILInstructionKind::LoadInst:
           // A 'non-taking' value load is harmless.
           return cast<LoadInst>(inst)->getOwnershipQualifier() ==
                  LoadOwnershipQualifier::Take;
           break;
-        case ValueKind::DebugValueAddrInst:
+        case SILInstructionKind::DebugValueAddrInst:
           // Harmless use.
           break;
         default:
@@ -4072,7 +4069,7 @@
   /// - flow-sensitive states must be equivalent on all paths into a block
   void verifyFlowSensitiveRules(SILFunction *F) {
     struct BBState {
-      std::vector<SILInstruction*> Stack;
+      std::vector<SingleValueInstruction*> Stack;
       std::set<BeginAccessInst*> Accesses;
     };
 
@@ -4090,7 +4087,7 @@
         CurInstruction = &i;
 
         if (i.isAllocatingStack()) {
-          state.Stack.push_back(&i);
+          state.Stack.push_back(cast<SingleValueInstruction>(&i));
 
         } else if (i.isDeallocatingStack()) {
           SILValue op = i.getOperand(0);
@@ -4263,7 +4260,13 @@
       require(FoundSelfInPredecessor, "Must be a successor of each predecessor.");
     }
     
-    SILVisitor::visitSILBasicBlock(BB);
+    SILInstructionVisitor::visitSILBasicBlock(BB);
+  }
+
+  void visitBasicBlockArguments(SILBasicBlock *BB) {
+    for (auto argI = BB->args_begin(), argEnd = BB->args_end(); argI != argEnd;
+         ++argI)
+      visitSILArgument(*argI);
   }
 
   void visitSILBasicBlocks(SILFunction *F) {
@@ -4496,11 +4499,12 @@
   for (const SILInstruction &I : StaticInitializerBlock) {
     assert(isValidStaticInitializerInst(&I, getModule()) &&
            "illegal static initializer");
-    if (&I == &StaticInitializerBlock.back()) {
-      assert(I.use_empty() && "Init value must not have another use");
+    auto init = cast<SingleValueInstruction>(&I);
+    if (init == &StaticInitializerBlock.back()) {
+      assert(init->use_empty() && "Init value must not have another use");
     } else {
-      assert(!I.use_empty() && "dead instruction in static initializer");
-      assert(!isa<ObjectInst>(&I) &&
+      assert(!init->use_empty() && "dead instruction in static initializer");
+      assert(!isa<ObjectInst>(init) &&
              "object instruction is only allowed for final initial value");
     }
     assert(I.getParent() == &StaticInitializerBlock);
diff --git a/lib/SIL/ValueOwnershipKindClassifier.cpp b/lib/SIL/ValueOwnershipKindClassifier.cpp
index 61a57fe..ebe7618 100644
--- a/lib/SIL/ValueOwnershipKindClassifier.cpp
+++ b/lib/SIL/ValueOwnershipKindClassifier.cpp
@@ -20,7 +20,6 @@
 #define CONSTANT_OWNERSHIP_INST(OWNERSHIP, INST)                               \
   ValueOwnershipKind ValueOwnershipKindClassifier::visit##INST##Inst(          \
       INST##Inst *Arg) {                                                       \
-    assert(Arg->hasValue() && "Expected to have a result");                    \
     if (ValueOwnershipKind::OWNERSHIP == ValueOwnershipKind::Trivial) {        \
       assert((Arg->getType().isAddress() ||                                    \
               Arg->getType().isTrivial(Arg->getModule())) &&                   \
@@ -60,9 +59,7 @@
 // not though.
 CONSTANT_OWNERSHIP_INST(Trivial, AddressToPointer)
 CONSTANT_OWNERSHIP_INST(Trivial, AllocStack)
-CONSTANT_OWNERSHIP_INST(Trivial, BindMemory)
 CONSTANT_OWNERSHIP_INST(Trivial, BeginAccess)
-CONSTANT_OWNERSHIP_INST(Trivial, BeginUnpairedAccess)
 CONSTANT_OWNERSHIP_INST(Trivial, BridgeObjectToWord)
 CONSTANT_OWNERSHIP_INST(Trivial, ClassMethod)
 CONSTANT_OWNERSHIP_INST(Trivial, DynamicMethod)
@@ -79,7 +76,6 @@
 CONSTANT_OWNERSHIP_INST(Trivial, IsNonnull)
 CONSTANT_OWNERSHIP_INST(Trivial, IsUnique)
 CONSTANT_OWNERSHIP_INST(Trivial, IsUniqueOrPinned)
-CONSTANT_OWNERSHIP_INST(Trivial, MarkFunctionEscape)
 CONSTANT_OWNERSHIP_INST(Trivial, MarkUninitializedBehavior)
 CONSTANT_OWNERSHIP_INST(Trivial, Metatype)
 CONSTANT_OWNERSHIP_INST(Trivial, ObjCToThickMetatype)
@@ -106,10 +102,8 @@
 CONSTANT_OWNERSHIP_INST(Trivial, ThinFunctionToPointer)
 CONSTANT_OWNERSHIP_INST(Trivial, TupleElementAddr)
 CONSTANT_OWNERSHIP_INST(Trivial, UncheckedAddrCast)
-CONSTANT_OWNERSHIP_INST(Trivial, UncheckedRefCastAddr)
 CONSTANT_OWNERSHIP_INST(Trivial, UncheckedTakeEnumDataAddr)
 CONSTANT_OWNERSHIP_INST(Trivial, UncheckedTrivialBitCast)
-CONSTANT_OWNERSHIP_INST(Trivial, UnconditionalCheckedCastAddr)
 CONSTANT_OWNERSHIP_INST(Trivial, ValueMetatype)
 CONSTANT_OWNERSHIP_INST(Trivial, WitnessMethod)
 CONSTANT_OWNERSHIP_INST(Trivial, StoreBorrow)
@@ -154,77 +148,6 @@
 CONSTANT_OR_TRIVIAL_OWNERSHIP_INST(Unowned, UncheckedBitwiseCast)
 #undef CONSTANT_OR_TRIVIAL_OWNERSHIP_INST
 
-// These are instructions that do not have any result, so we should never reach
-// this point in the code since we need a SILValue to compute
-// ValueOwnershipKind. We define methods so that all instructions have a method
-// on the visitor (causing the compiler to warn if a new instruction is added
-// within a method being added).
-#define NO_RESULT_OWNERSHIP_INST(INST)                                         \
-  ValueOwnershipKind ValueOwnershipKindClassifier::visit##INST##Inst(          \
-      INST##Inst *I) {                                                         \
-    assert(!I->hasValue() && "Expected an instruction without a result");      \
-    llvm_unreachable("Instruction without a result can not have ownership");   \
-  }
-NO_RESULT_OWNERSHIP_INST(DeallocStack)
-NO_RESULT_OWNERSHIP_INST(DeallocRef)
-NO_RESULT_OWNERSHIP_INST(DeallocPartialRef)
-NO_RESULT_OWNERSHIP_INST(DeallocValueBuffer)
-NO_RESULT_OWNERSHIP_INST(DeallocBox)
-NO_RESULT_OWNERSHIP_INST(DeallocExistentialBox)
-NO_RESULT_OWNERSHIP_INST(EndAccess)
-NO_RESULT_OWNERSHIP_INST(EndBorrow)
-NO_RESULT_OWNERSHIP_INST(EndBorrowArgument)
-NO_RESULT_OWNERSHIP_INST(EndUnpairedAccess)
-NO_RESULT_OWNERSHIP_INST(Store)
-NO_RESULT_OWNERSHIP_INST(StoreWeak)
-NO_RESULT_OWNERSHIP_INST(StoreUnowned)
-NO_RESULT_OWNERSHIP_INST(Assign)
-NO_RESULT_OWNERSHIP_INST(DebugValue)
-NO_RESULT_OWNERSHIP_INST(DebugValueAddr)
-NO_RESULT_OWNERSHIP_INST(CopyAddr)
-NO_RESULT_OWNERSHIP_INST(DestroyAddr)
-NO_RESULT_OWNERSHIP_INST(StrongRetain)
-NO_RESULT_OWNERSHIP_INST(StrongRelease)
-NO_RESULT_OWNERSHIP_INST(StrongRetainUnowned)
-NO_RESULT_OWNERSHIP_INST(StrongUnpin)
-NO_RESULT_OWNERSHIP_INST(UnmanagedRetainValue)
-NO_RESULT_OWNERSHIP_INST(UnmanagedReleaseValue)
-NO_RESULT_OWNERSHIP_INST(UnmanagedAutoreleaseValue)
-NO_RESULT_OWNERSHIP_INST(UnownedRetain)
-NO_RESULT_OWNERSHIP_INST(UnownedRelease)
-NO_RESULT_OWNERSHIP_INST(RetainValue)
-NO_RESULT_OWNERSHIP_INST(ReleaseValue)
-NO_RESULT_OWNERSHIP_INST(RetainValueAddr)
-NO_RESULT_OWNERSHIP_INST(ReleaseValueAddr)
-NO_RESULT_OWNERSHIP_INST(SetDeallocating)
-NO_RESULT_OWNERSHIP_INST(AutoreleaseValue)
-NO_RESULT_OWNERSHIP_INST(FixLifetime)
-NO_RESULT_OWNERSHIP_INST(DestroyValue)
-NO_RESULT_OWNERSHIP_INST(AllocGlobal)
-NO_RESULT_OWNERSHIP_INST(InjectEnumAddr)
-NO_RESULT_OWNERSHIP_INST(DeinitExistentialAddr)
-NO_RESULT_OWNERSHIP_INST(DeinitExistentialValue)
-NO_RESULT_OWNERSHIP_INST(CondFail)
-NO_RESULT_OWNERSHIP_INST(EndLifetime)
-
-// Terminators. These do not produce SILValue, so they do not have a
-// ValueOwnershipKind. They do have ownership implications in terms of the
-// SILArguments that they feed into. But that code is in SILArgument.
-NO_RESULT_OWNERSHIP_INST(Unreachable)
-NO_RESULT_OWNERSHIP_INST(Return)
-NO_RESULT_OWNERSHIP_INST(Throw)
-NO_RESULT_OWNERSHIP_INST(TryApply)
-NO_RESULT_OWNERSHIP_INST(Branch)
-NO_RESULT_OWNERSHIP_INST(CondBranch)
-NO_RESULT_OWNERSHIP_INST(SwitchValue)
-NO_RESULT_OWNERSHIP_INST(SwitchEnum)
-NO_RESULT_OWNERSHIP_INST(SwitchEnumAddr)
-NO_RESULT_OWNERSHIP_INST(DynamicMethodBranch)
-NO_RESULT_OWNERSHIP_INST(CheckedCastBranch)
-NO_RESULT_OWNERSHIP_INST(CheckedCastValueBranch)
-NO_RESULT_OWNERSHIP_INST(CheckedCastAddrBranch)
-#undef NO_RESULT_OWNERSHIP_INST
-
 // For a forwarding instruction, we loop over all operands and make sure that
 // all non-trivial values have the same ownership.
 ValueOwnershipKind
@@ -281,7 +204,6 @@
 #define FORWARDING_OWNERSHIP_INST(INST)                                        \
   ValueOwnershipKind ValueOwnershipKindClassifier::visit##INST##Inst(          \
       INST##Inst *I) {                                                         \
-    assert(I->hasValue() && "Expected to have a value");                       \
     return visitForwardingInst(I);                                             \
   }
 FORWARDING_OWNERSHIP_INST(BridgeObjectToRef)
@@ -404,7 +326,6 @@
                                         llvm::Intrinsic::ID ID) {
     // LLVM intrinsics do not traffic in ownership, so if we have a result, it
     // must be trivial.
-    assert(BI->hasValue() && "Can only get here if we have a SILValue");
     assert(BI->getType().isTrivial(BI->getModule()) &&
            "LLVM intrinsics should always be trivial");
     return ValueOwnershipKind::Trivial;
@@ -420,7 +341,6 @@
 #define CONSTANT_OWNERSHIP_BUILTIN(OWNERSHIP, ID)                              \
   ValueOwnershipKind ValueOwnershipKindBuiltinVisitor::visit##ID(              \
       BuiltinInst *BI, StringRef Attr) {                                       \
-    assert(BI->hasValue() && "Expected to have type");                         \
     if (ValueOwnershipKind::OWNERSHIP == ValueOwnershipKind::Trivial) {        \
       assert(BI->getType().isTrivial(BI->getModule()) &&                       \
              "Only trivial types can have trivial ownership");                 \
diff --git a/lib/SIL/ValueOwnershipKindClassifier.h b/lib/SIL/ValueOwnershipKindClassifier.h
index 6c16243..2d4c7fb 100644
--- a/lib/SIL/ValueOwnershipKindClassifier.h
+++ b/lib/SIL/ValueOwnershipKindClassifier.h
@@ -19,7 +19,7 @@
 namespace sil {
 
 class ValueOwnershipKindClassifier
-    : public SILVisitor<ValueOwnershipKindClassifier, ValueOwnershipKind> {
+    : public SILValueVisitor<ValueOwnershipKindClassifier, ValueOwnershipKind> {
 
 public:
   ValueOwnershipKindClassifier() = default;
@@ -33,9 +33,6 @@
     return visitForwardingInst(I, I->getAllOperands());
   }
 
-  ValueOwnershipKind visitValueBase(ValueBase *V) {
-    llvm_unreachable("unimplemented method on ValueBaseOwnershipVisitor");
-  }
 #define VALUE(Id, Parent) ValueOwnershipKind visit##Id(Id *ID);
 #include "swift/SIL/SILNodes.def"
 };
diff --git a/lib/SILGen/SILGen.cpp b/lib/SILGen/SILGen.cpp
index 5dfc2e1..aaa8b13 100644
--- a/lib/SILGen/SILGen.cpp
+++ b/lib/SILGen/SILGen.cpp
@@ -28,6 +28,7 @@
 #include "swift/SIL/SILArgument.h"
 #include "swift/SIL/SILDebugScope.h"
 #include "swift/Subsystems.h"
+#include "llvm/ProfileData/InstrProfReader.h"
 #include "llvm/Support/Debug.h"
 #include "ManagedValue.h"
 #include "RValue.h"
@@ -41,6 +42,16 @@
 SILGenModule::SILGenModule(SILModule &M, ModuleDecl *SM)
   : M(M), Types(M.Types), SwiftModule(SM), TopLevelSGF(nullptr),
     Profiler(nullptr) {
+  SILOptions &Opts = M.getOptions();
+  if (!Opts.UseProfile.empty()) {
+    auto ReaderOrErr = llvm::IndexedInstrProfReader::create(Opts.UseProfile);
+    if (auto E = ReaderOrErr.takeError()) {
+      diagnose(SourceLoc(), diag::profile_read_error, Opts.UseProfile,
+               llvm::toString(std::move(E)));
+      Opts.UseProfile.erase();
+    }
+    PGOReader = std::move(ReaderOrErr.get());
+  }
 }
 
 SILGenModule::~SILGenModule() {
@@ -429,8 +440,8 @@
                                    C);
 
   return M.createFunction(SILLinkage::Public, SWIFT_ENTRY_POINT_FUNCTION,
-                          topLevelType, nullptr, Loc, IsBare,
-                          IsNotTransparent, IsNotSerialized, IsNotThunk,
+                          topLevelType, nullptr, Loc, IsBare, IsNotTransparent,
+                          IsNotSerialized, ProfileCounter(), IsNotThunk,
                           SubclassScope::NotApplicable);
 }
 
@@ -483,6 +494,13 @@
   return nullptr;
 }
 
+static bool hasSILBody(FuncDecl *fd) {
+  if (fd->getAccessorKind() == AccessorKind::IsMaterializeForSet)
+    return !isa<ProtocolDecl>(fd->getDeclContext());
+
+  return fd->getBody(/*canSynthesize=*/false);
+}
+
 SILFunction *SILGenModule::getFunction(SILDeclRef constant,
                                        ForDefinition_t forDefinition) {
   // If we already emitted the function, return it (potentially preparing it
@@ -490,10 +508,18 @@
   if (auto emitted = getEmittedFunction(constant, forDefinition))
     return emitted;
 
+  ProfileCounter count = ProfileCounter();
+  if (constant.hasDecl()) {
+    if (auto *fd = constant.getFuncDecl()) {
+      if (hasSILBody(fd)) {
+        count = loadProfilerCount(fd->getBody(/*canSynthesize=*/false));
+      }
+    }
+  }
   // Note: Do not provide any SILLocation. You can set it afterwards.
   auto *F = M.getOrCreateFunction(constant.hasDecl() ? constant.getDecl()
                                                      : (Decl *)nullptr,
-                                  constant, forDefinition);
+                                  constant, forDefinition, count);
 
   assert(F && "SILFunction should have been defined");
 
@@ -673,13 +699,6 @@
   }
 }
 
-static bool hasSILBody(FuncDecl *fd) {
-  if (fd->getAccessorKind() == AccessorKind::IsMaterializeForSet)
-    return !isa<ProtocolDecl>(fd->getDeclContext());
-
-  return fd->getBody(/*canSynthesize=*/false);
-}
-
 void SILGenModule::emitFunction(FuncDecl *fd) {
   SILDeclRef::Loc decl = fd;
 
diff --git a/lib/SILGen/SILGen.h b/lib/SILGen/SILGen.h
index 5f41b31..b98e89a 100644
--- a/lib/SILGen/SILGen.h
+++ b/lib/SILGen/SILGen.h
@@ -19,11 +19,13 @@
 #include "swift/AST/ASTContext.h"
 #include "swift/AST/AnyFunctionRef.h"
 #include "swift/AST/DiagnosticEngine.h"
+#include "swift/Basic/ProfileCounter.h"
 #include "swift/SIL/SILDebugScope.h"
 #include "swift/SIL/SILFunction.h"
 #include "swift/SIL/SILModule.h"
 #include "swift/SIL/TypeLowering.h"
 #include "llvm/ADT/DenseMap.h"
+#include "llvm/ProfileData/InstrProfReader.h"
 #include <deque>
 
 namespace swift {
@@ -60,6 +62,24 @@
   /// disabled.
   std::unique_ptr<SILGenProfiling> Profiler;
 
+  /// The indexed profile data to be used for PGO, or nullptr.
+  std::unique_ptr<llvm::IndexedInstrProfReader> PGOReader;
+
+  /// Load the profiled execution count corresponding to \p N, if one is
+  /// available.
+  ProfileCounter loadProfilerCount(ASTNode N) {
+    if (PGOReader && Profiler && Profiler->hasRegionCounters())
+      return Profiler->getExecutionCount(N);
+    return ProfileCounter();
+  }
+
+  /// Get the PGO's node parent
+  Optional<ASTNode> getPGOParent(ASTNode Node) {
+    if (PGOReader && Profiler && Profiler->hasRegionCounters())
+      return Profiler->getPGOParent(Node);
+    return None;
+  }
+
   /// Mapping from SILDeclRefs to emitted SILFunctions.
   llvm::DenseMap<SILDeclRef, SILFunction*> emittedFunctions;
   /// Mapping from ProtocolConformances to emitted SILWitnessTables.
diff --git a/lib/SILGen/SILGenBuilder.cpp b/lib/SILGen/SILGenBuilder.cpp
index 4ce3707..fcb9238 100644
--- a/lib/SILGen/SILGenBuilder.cpp
+++ b/lib/SILGen/SILGenBuilder.cpp
@@ -558,9 +558,12 @@
 void SILGenBuilder::createCheckedCastBranch(SILLocation loc, bool isExact,
                                             ManagedValue operand, SILType type,
                                             SILBasicBlock *trueBlock,
-                                            SILBasicBlock *falseBlock) {
+                                            SILBasicBlock *falseBlock,
+                                            ProfileCounter Target1Count,
+                                            ProfileCounter Target2Count) {
   SILBuilder::createCheckedCastBranch(loc, isExact, operand.forward(SGF), type,
-                                      trueBlock, falseBlock);
+                                      trueBlock, falseBlock, Target1Count,
+                                      Target2Count);
 }
 
 void SILGenBuilder::createCheckedCastValueBranch(SILLocation loc,
@@ -713,16 +716,26 @@
   {
     // TODO: We could store the data in CaseBB form and not have to do this.
     llvm::SmallVector<DeclBlockPair, 8> caseBlocks;
+    llvm::SmallVector<ProfileCounter, 8> caseBlockCounts;
     std::transform(caseDataArray.begin(), caseDataArray.end(),
                    std::back_inserter(caseBlocks),
                    [](NormalCaseData &caseData) -> DeclBlockPair {
                      return {caseData.decl, caseData.block};
                    });
+    std::transform(caseDataArray.begin(), caseDataArray.end(),
+                   std::back_inserter(caseBlockCounts),
+                   [](NormalCaseData &caseData) -> ProfileCounter {
+                     return caseData.count;
+                   });
     SILBasicBlock *defaultBlock =
         defaultBlockData ? defaultBlockData->block : nullptr;
+    ProfileCounter defaultBlockCount =
+        defaultBlockData ? defaultBlockData->count : ProfileCounter();
+    ArrayRef<ProfileCounter> caseBlockCountsRef = caseBlockCounts;
     if (isAddressOnly) {
       builder.createSwitchEnumAddr(loc, optional.getValue(), defaultBlock,
-                                   caseBlocks);
+                                   caseBlocks, caseBlockCountsRef,
+                                   defaultBlockCount);
     } else {
       if (optional.getType().isAddress()) {
         // TODO: Refactor this into a maybe load.
@@ -733,7 +746,8 @@
         }
       }
       builder.createSwitchEnum(loc, optional.forward(getSGF()), defaultBlock,
-                               caseBlocks);
+                               caseBlocks, caseBlockCountsRef,
+                               defaultBlockCount);
     }
   }
 
diff --git a/lib/SILGen/SILGenBuilder.h b/lib/SILGen/SILGenBuilder.h
index a6d6291..c455835 100644
--- a/lib/SILGen/SILGenBuilder.h
+++ b/lib/SILGen/SILGenBuilder.h
@@ -26,6 +26,7 @@
 #include "JumpDest.h"
 #include "ManagedValue.h"
 #include "RValue.h"
+#include "swift/Basic/ProfileCounter.h"
 #include "swift/SIL/SILBuilder.h"
 
 namespace swift {
@@ -257,7 +258,9 @@
   void createCheckedCastBranch(SILLocation loc, bool isExact,
                                ManagedValue operand, SILType type,
                                SILBasicBlock *trueBlock,
-                               SILBasicBlock *falseBlock);
+                               SILBasicBlock *falseBlock,
+                               ProfileCounter Target1Count,
+                               ProfileCounter Target2Count);
 
   using SILBuilder::createCheckedCastValueBranch;
   void createCheckedCastValueBranch(SILLocation loc, ManagedValue operand,
@@ -334,11 +337,13 @@
     SILBasicBlock *block;
     NullablePtr<SILBasicBlock> contBlock;
     NormalCaseHandler handler;
+    ProfileCounter count;
 
     NormalCaseData(EnumElementDecl *decl, SILBasicBlock *block,
                    NullablePtr<SILBasicBlock> contBlock,
-                   NormalCaseHandler handler)
-        : decl(decl), block(block), contBlock(contBlock), handler(handler) {}
+                   NormalCaseHandler handler, ProfileCounter count)
+        : decl(decl), block(block), contBlock(contBlock), handler(handler),
+          count(count) {}
     ~NormalCaseData() = default;
   };
 
@@ -347,12 +352,13 @@
     NullablePtr<SILBasicBlock> contBlock;
     DefaultCaseHandler handler;
     DefaultDispatchTime dispatchTime;
+    ProfileCounter count;
 
     DefaultCaseData(SILBasicBlock *block, NullablePtr<SILBasicBlock> contBlock,
                     DefaultCaseHandler handler,
-                    DefaultDispatchTime dispatchTime)
+                    DefaultDispatchTime dispatchTime, ProfileCounter count)
         : block(block), contBlock(contBlock), handler(handler),
-          dispatchTime(dispatchTime) {}
+          dispatchTime(dispatchTime), count(count) {}
     ~DefaultCaseData() = default;
   };
 
@@ -367,17 +373,19 @@
                     ManagedValue optional)
       : builder(builder), loc(loc), optional(optional) {}
 
-  void addDefaultCase(SILBasicBlock *defaultBlock,
-                      NullablePtr<SILBasicBlock> contBlock,
-                      DefaultCaseHandler handle,
-                      DefaultDispatchTime dispatchTime =
-                          DefaultDispatchTime::AfterNormalCases) {
-    defaultBlockData.emplace(defaultBlock, contBlock, handle, dispatchTime);
+  void addDefaultCase(
+      SILBasicBlock *defaultBlock, NullablePtr<SILBasicBlock> contBlock,
+      DefaultCaseHandler handle,
+      DefaultDispatchTime dispatchTime = DefaultDispatchTime::AfterNormalCases,
+      ProfileCounter count = ProfileCounter()) {
+    defaultBlockData.emplace(defaultBlock, contBlock, handle, dispatchTime,
+                             count);
   }
 
   void addCase(EnumElementDecl *decl, SILBasicBlock *caseBlock,
-               NullablePtr<SILBasicBlock> contBlock, NormalCaseHandler handle) {
-    caseDataArray.emplace_back(decl, caseBlock, contBlock, handle);
+               NullablePtr<SILBasicBlock> contBlock, NormalCaseHandler handle,
+               ProfileCounter count = ProfileCounter()) {
+    caseDataArray.emplace_back(decl, caseBlock, contBlock, handle, count);
   }
 
   void emit() &&;
diff --git a/lib/SILGen/SILGenDecl.cpp b/lib/SILGen/SILGenDecl.cpp
index 83c3554..ffe41f8 100644
--- a/lib/SILGen/SILGenDecl.cpp
+++ b/lib/SILGen/SILGenDecl.cpp
@@ -10,9 +10,9 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "SILGen.h"
 #include "Initialization.h"
 #include "RValue.h"
+#include "SILGen.h"
 #include "SILGenDynamicCast.h"
 #include "Scope.h"
 #include "SwitchCaseFullExpr.h"
@@ -21,6 +21,7 @@
 #include "swift/AST/Module.h"
 #include "swift/AST/NameLookup.h"
 #include "swift/AST/ProtocolConformance.h"
+#include "swift/Basic/ProfileCounter.h"
 #include "swift/SIL/FormalLinkage.h"
 #include "swift/SIL/PrettyStackTrace.h"
 #include "swift/SIL/SILArgument.h"
@@ -386,7 +387,7 @@
 
     // The variable may have its lifetime extended by a closure, heap-allocate
     // it using a box.
-    SILInstruction *allocBox =
+    SILValue allocBox =
         SGF.B.createAllocBox(decl, boxType, {decl->isLet(), ArgNo});
 
     // Mark the memory as uninitialized, so DI will track it for us.
@@ -908,12 +909,13 @@
   // Try to perform the cast to the destination type, producing an optional that
   // indicates whether we succeeded.
   auto destType = OptionalType::get(pattern->getCastTypeLoc().getType());
-  
-  value = emitConditionalCheckedCast(SGF, loc, value, pattern->getType(),
-                                     destType, pattern->getCastKind(),
-                                     SGFContext())
-            .getAsSingleValue(SGF, loc);
-  
+
+  value =
+      emitConditionalCheckedCast(SGF, loc, value, pattern->getType(), destType,
+                                 pattern->getCastKind(), SGFContext(),
+                                 ProfileCounter(), ProfileCounter())
+          .getAsSingleValue(SGF, loc);
+
   // Now that we have our result as an optional, we can use an enum projection
   // to do all the work.
   EnumElementPatternInitialization::
@@ -1184,8 +1186,10 @@
 /// specified JumpDest.  The insertion point is left in the block where the
 /// condition has matched and any bound variables are in scope.
 ///
-void SILGenFunction::emitStmtCondition(StmtCondition Cond,
-                                       JumpDest FailDest, SILLocation loc) {
+void SILGenFunction::emitStmtCondition(StmtCondition Cond, JumpDest FailDest,
+                                       SILLocation loc,
+                                       ProfileCounter NumTrueTaken,
+                                       ProfileCounter NumFalseTaken) {
 
   assert(B.hasValidInsertionPoint() &&
          "emitting condition at unreachable point");
@@ -1240,8 +1244,9 @@
     // on success we fall through to a new block.
     SILBasicBlock *ContBB = createBasicBlock();
     auto FailBB = Cleanups.emitBlockForCleanups(FailDest, loc);
-    B.createCondBranch(booleanTestLoc, booleanTestValue, ContBB, FailBB);
-    
+    B.createCondBranch(booleanTestLoc, booleanTestValue, ContBB, FailBB,
+                       NumTrueTaken, NumFalseTaken);
+
     // Finally, emit the continue block and keep emitting the rest of the
     // condition.
     B.emitBlock(ContBB);
diff --git a/lib/SILGen/SILGenDynamicCast.cpp b/lib/SILGen/SILGenDynamicCast.cpp
index 226a8e2..b63a3b4 100644
--- a/lib/SILGen/SILGenDynamicCast.cpp
+++ b/lib/SILGen/SILGenDynamicCast.cpp
@@ -117,7 +117,9 @@
     void emitConditional(
         ManagedValue operand, CastConsumptionKind consumption, SGFContext ctx,
         const std::function<void(ManagedValue)> &handleTrue,
-        const std::function<void(Optional<ManagedValue>)> &handleFalse) {
+        const std::function<void(Optional<ManagedValue>)> &handleFalse,
+        ProfileCounter TrueCount = ProfileCounter(),
+        ProfileCounter FalseCount = ProfileCounter()) {
       // The cast instructions don't know how to work with anything
       // but the most general possible abstraction level.
       AbstractionPattern abstraction =
@@ -140,7 +142,7 @@
             createAbstractResultBuffer(hasAbstraction, origTargetTL, ctx);
         SGF.B.createCheckedCastAddrBranch(
             Loc, consumption, operand.forward(SGF), SourceType, resultBuffer,
-            TargetType, trueBB, falseBB);
+            TargetType, trueBB, falseBB, TrueCount, FalseCount);
       } else if (Strategy == CastStrategy::Address) {
         // Opaque value mode
         operandValue = std::move(operand);
@@ -155,7 +157,7 @@
         }
         SGF.B.createCheckedCastBranch(Loc, /*exact*/ false, operandValue,
                                       origTargetTL.getLoweredType(), trueBB,
-                                      falseBB);
+                                      falseBB, TrueCount, FalseCount);
       }
 
       // Emit the success block.
@@ -285,22 +287,23 @@
 void SILGenFunction::emitCheckedCastBranch(
     SILLocation loc, Expr *source, Type targetType, SGFContext ctx,
     std::function<void(ManagedValue)> handleTrue,
-    std::function<void(Optional<ManagedValue>)> handleFalse) {
+    std::function<void(Optional<ManagedValue>)> handleFalse,
+    ProfileCounter TrueCount, ProfileCounter FalseCount) {
   CheckedCastEmitter emitter(*this, loc, source->getType(), targetType);
   ManagedValue operand = emitter.emitOperand(source);
   emitter.emitConditional(operand, CastConsumptionKind::TakeAlways, ctx,
-                          handleTrue, handleFalse);
+                          handleTrue, handleFalse, TrueCount, FalseCount);
 }
 
 void SILGenFunction::emitCheckedCastBranch(
     SILLocation loc, ConsumableManagedValue src, Type sourceType,
     CanType targetType, SGFContext ctx,
     std::function<void(ManagedValue)> handleTrue,
-    std::function<void(Optional<ManagedValue>)> handleFalse) {
+    std::function<void(Optional<ManagedValue>)> handleFalse,
+    ProfileCounter TrueCount, ProfileCounter FalseCount) {
   CheckedCastEmitter emitter(*this, loc, sourceType, targetType);
-  emitter.emitConditional(src.getFinalManagedValue(),
-                          src.getFinalConsumption(), ctx, handleTrue,
-                          handleFalse);
+  emitter.emitConditional(src.getFinalManagedValue(), src.getFinalConsumption(),
+                          ctx, handleTrue, handleFalse, TrueCount, FalseCount);
 }
 
 namespace {
@@ -395,7 +398,9 @@
     void emitConditional(ManagedValue operand, CastConsumptionKind consumption,
                          SGFContext ctx,
                          const std::function<void(ManagedValue)> &handleTrue,
-                         const std::function<void()> &handleFalse) {
+                         const std::function<void()> &handleFalse,
+                         ProfileCounter TrueCount = ProfileCounter(),
+                         ProfileCounter FalseCount = ProfileCounter()) {
       // The cast instructions don't know how to work with anything
       // but the most general possible abstraction level.
       AbstractionPattern abstraction = SGF.SGM.Types.getMostGeneralAbstraction();
@@ -414,10 +419,9 @@
         assert(operand.getType().isAddress());
         resultBuffer =
           createAbstractResultBuffer(hasAbstraction, origTargetTL, ctx);
-        SGF.B.createCheckedCastAddrBranch(Loc, consumption,
-                                          operand.forward(SGF), SourceType,
-                                          resultBuffer, TargetType,
-                                          trueBB, falseBB);
+        SGF.B.createCheckedCastAddrBranch(
+            Loc, consumption, operand.forward(SGF), SourceType, resultBuffer,
+            TargetType, trueBB, falseBB, TrueCount, FalseCount);
       } else {
         // Tolerate being passed an address here.  It comes up during switch
         //emission.
@@ -427,8 +431,8 @@
               Loc, scalarOperandValue, LoadOwnershipQualifier::Take);
         }
         SGF.B.createCheckedCastBranch(Loc, /*exact*/ false, scalarOperandValue,
-                                      origTargetTL.getLoweredType(),
-                                      trueBB, falseBB);
+                                      origTargetTL.getLoweredType(), trueBB,
+                                      falseBB, TrueCount, FalseCount);
       }
 
       // Emit the success block.
@@ -541,21 +545,23 @@
 void SILGenFunction::emitCheckedCastBranchOld(
     SILLocation loc, Expr *source, Type targetType, SGFContext ctx,
     std::function<void(ManagedValue)> handleTrue,
-    std::function<void()> handleFalse) {
+    std::function<void()> handleFalse, ProfileCounter TrueCount,
+    ProfileCounter FalseCount) {
   CheckedCastEmitterOld emitter(*this, loc, source->getType(), targetType);
   ManagedValue operand = emitter.emitOperand(source);
   emitter.emitConditional(operand, CastConsumptionKind::TakeAlways, ctx,
-                          handleTrue, handleFalse);
+                          handleTrue, handleFalse, TrueCount, FalseCount);
 }
 
 void SILGenFunction::emitCheckedCastBranchOld(
     SILLocation loc, ConsumableManagedValue src, Type sourceType,
     CanType targetType, SGFContext ctx,
     std::function<void(ManagedValue)> handleTrue,
-    std::function<void()> handleFalse) {
+    std::function<void()> handleFalse, ProfileCounter TrueCount,
+    ProfileCounter FalseCount) {
   CheckedCastEmitterOld emitter(*this, loc, sourceType, targetType);
   emitter.emitConditional(src.getFinalManagedValue(), src.getFinalConsumption(),
-                          ctx, handleTrue, handleFalse);
+                          ctx, handleTrue, handleFalse, TrueCount, FalseCount);
 }
 
 /// Emit a collection downcast expression.
@@ -664,13 +670,10 @@
   return emitter.emitUnconditionalCast(operandValue, C);
 }
 
-RValue Lowering::emitConditionalCheckedCast(SILGenFunction &SGF,
-                                            SILLocation loc,
-                                            ManagedValue operand,
-                                            Type operandType,
-                                            Type optTargetType,
-                                            CheckedCastKind castKind,
-                                            SGFContext C) {
+RValue Lowering::emitConditionalCheckedCast(
+    SILGenFunction &SGF, SILLocation loc, ManagedValue operand,
+    Type operandType, Type optTargetType, CheckedCastKind castKind,
+    SGFContext C, ProfileCounter TrueCount, ProfileCounter FalseCount) {
   // Drill into the result type.
   CanType resultObjectType =
     optTargetType->getCanonicalType().getAnyOptionalObjectType();
@@ -755,7 +758,8 @@
           SGF.B.createInjectEnumAddr(loc, resultBuffer, noneDecl);
           SGF.Cleanups.emitBranchAndCleanups(scope.getExitDest(), loc);
         }
-      });
+      },
+      TrueCount, FalseCount);
 
   // Enter the continuation block.
   SILBasicBlock *contBlock = scope.exit();
diff --git a/lib/SILGen/SILGenDynamicCast.h b/lib/SILGen/SILGenDynamicCast.h
index 45133a6..490c20b 100644
--- a/lib/SILGen/SILGenDynamicCast.h
+++ b/lib/SILGen/SILGenDynamicCast.h
@@ -25,13 +25,11 @@
                                     CheckedCastKind castKind,
                                     SGFContext C);
 
-RValue emitConditionalCheckedCast(SILGenFunction &SGF,
-                                  SILLocation loc,
-                                  ManagedValue operand,
-                                  Type operandType,
-                                  Type targetType,
-                                  CheckedCastKind castKind,
-                                  SGFContext C);
+RValue emitConditionalCheckedCast(SILGenFunction &SGF, SILLocation loc,
+                                  ManagedValue operand, Type operandType,
+                                  Type targetType, CheckedCastKind castKind,
+                                  SGFContext C, ProfileCounter TrueCount,
+                                  ProfileCounter FalseCount);
 
 SILValue emitIsa(SILGenFunction &SGF, SILLocation loc,
                  Expr *operand, Type targetType,
diff --git a/lib/SILGen/SILGenExpr.cpp b/lib/SILGen/SILGenExpr.cpp
index 6c8723f..5a5143d 100644
--- a/lib/SILGen/SILGenExpr.cpp
+++ b/lib/SILGen/SILGenExpr.cpp
@@ -2170,9 +2170,23 @@
 RValue RValueEmitter::
 visitConditionalCheckedCastExpr(ConditionalCheckedCastExpr *E,
                                 SGFContext C) {
+  ProfileCounter trueCount = ProfileCounter();
+  ProfileCounter falseCount = ProfileCounter();
+  auto parent = SGF.SGM.getPGOParent(E);
+  if (parent) {
+    auto &Node = parent.getValue();
+    auto *NodeS = Node.get<Stmt *>();
+    if (auto *IS = dyn_cast<IfStmt>(NodeS)) {
+      trueCount = SGF.SGM.loadProfilerCount(IS->getThenStmt());
+      if (auto *ElseStmt = IS->getElseStmt()) {
+        falseCount = SGF.SGM.loadProfilerCount(ElseStmt);
+      }
+    }
+  }
   ManagedValue operand = SGF.emitRValueAsSingleValue(E->getSubExpr());
   return emitConditionalCheckedCast(SGF, E, operand, E->getSubExpr()->getType(),
-                                    E->getType(), E->getCastKind(), C);
+                                    E->getType(), E->getCastKind(), C,
+                                    trueCount, falseCount);
 }
 
 RValue RValueEmitter::visitIsExpr(IsExpr *E, SGFContext C) {
@@ -3027,12 +3041,9 @@
   auto name = Mangle::ASTMangler()
     .mangleKeyPathGetterThunkHelper(property, genericSig, baseType,
                                     interfaceSubs);
-  auto thunk = SGF.SGM.M.getOrCreateSharedFunction(loc, name,
-                                                   signature,
-                                                   IsBare,
-                                                   IsNotTransparent,
-                                                   IsNotSerialized,
-                                                   IsThunk);
+  auto thunk = SGF.SGM.M.getOrCreateSharedFunction(
+      loc, name, signature, IsBare, IsNotTransparent, IsNotSerialized,
+      ProfileCounter(), IsThunk);
   if (!thunk->empty())
     return thunk;
   
@@ -3152,12 +3163,9 @@
                                                                 genericSig,
                                                                 baseType,
                                                                 interfaceSubs);
-  auto thunk = SGF.SGM.M.getOrCreateSharedFunction(loc, name,
-                                                   signature,
-                                                   IsBare,
-                                                   IsNotTransparent,
-                                                   IsNotSerialized,
-                                                   IsThunk);
+  auto thunk = SGF.SGM.M.getOrCreateSharedFunction(
+      loc, name, signature, IsBare, IsNotTransparent, IsNotSerialized,
+      ProfileCounter(), IsThunk);
   if (!thunk->empty())
     return thunk;
   
@@ -3314,12 +3322,9 @@
     
     auto name = Mangle::ASTMangler().mangleKeyPathEqualsHelper(indexTypes,
                                                                genericSig);
-    equals = SGM.M.getOrCreateSharedFunction(loc, name,
-                                             signature,
-                                             IsBare,
-                                             IsNotTransparent,
-                                             IsNotSerialized,
-                                             IsThunk);
+    equals = SGM.M.getOrCreateSharedFunction(loc, name, signature, IsBare,
+                                             IsNotTransparent, IsNotSerialized,
+                                             ProfileCounter(), IsThunk);
     if (!equals->empty()) {
       return;
     }
@@ -3482,12 +3487,9 @@
     
     auto name = Mangle::ASTMangler().mangleKeyPathHashHelper(indexTypes,
                                                              genericSig);
-    hash = SGM.M.getOrCreateSharedFunction(loc, name,
-                                           signature,
-                                           IsBare,
-                                           IsNotTransparent,
-                                           IsNotSerialized,
-                                           IsThunk);
+    hash = SGM.M.getOrCreateSharedFunction(loc, name, signature, IsBare,
+                                           IsNotTransparent, IsNotSerialized,
+                                           ProfileCounter(), IsThunk);
     if (!hash->empty()) {
       return;
     }
@@ -4421,6 +4423,9 @@
 RValue RValueEmitter::visitIfExpr(IfExpr *E, SGFContext C) {
   auto &lowering = SGF.getTypeLowering(E->getType());
 
+  auto NumTrueTaken = SGF.SGM.loadProfilerCount(E->getThenExpr());
+  auto NumFalseTaken = SGF.SGM.loadProfilerCount(E->getElseExpr());
+
   if (lowering.isLoadable() || !SGF.silConv.useLoweredAddresses()) {
     // If the result is loadable, emit each branch and forward its result
     // into the destination block argument.
@@ -4429,7 +4434,8 @@
     Condition cond = SGF.emitCondition(E->getCondExpr(),
                                        /*hasFalse*/ true,
                                        /*invertCondition*/ false,
-                                       SGF.getLoweredType(E->getType()));
+                                       SGF.getLoweredType(E->getType()),
+                                       NumTrueTaken, NumFalseTaken);
     
     cond.enterTrue(SGF);
     SGF.emitProfilerIncrement(E->getThenExpr());
@@ -4464,7 +4470,9 @@
     
     Condition cond = SGF.emitCondition(E->getCondExpr(),
                                        /*hasFalse*/ true,
-                                       /*invertCondition*/ false);
+                                       /*invertCondition*/ false,
+                                       /*contArgs*/ {},
+                                       NumTrueTaken, NumFalseTaken);
     cond.enterTrue(SGF);
     SGF.emitProfilerIncrement(E->getThenExpr());
     {
diff --git a/lib/SILGen/SILGenFunction.h b/lib/SILGen/SILGenFunction.h
index 1c93cef..13f6c2c 100644
--- a/lib/SILGen/SILGenFunction.h
+++ b/lib/SILGen/SILGenFunction.h
@@ -21,6 +21,7 @@
 #include "SILGen.h"
 #include "SILGenBuilder.h"
 #include "swift/AST/AnyFunctionRef.h"
+#include "swift/Basic/ProfileCounter.h"
 #include "swift/SIL/SILBuilder.h"
 #include "llvm/ADT/PointerIntPair.h"
 
@@ -370,10 +371,11 @@
 
   /// Emit code to increment a counter for profiling.
   void emitProfilerIncrement(ASTNode N) {
-    if (SGM.Profiler && SGM.Profiler->hasRegionCounters())
+    if (SGM.Profiler && SGM.Profiler->hasRegionCounters() &&
+        SGM.M.getOptions().UseProfile.empty())
       SGM.Profiler->emitCounterIncrement(B, N);
   }
-  
+
   SILGenFunction(SILGenModule &SGM, SILFunction &F);
   ~SILGenFunction();
   
@@ -592,13 +594,20 @@
   /// \param contArgs - the types of the arguments to the continuation BB.
   ///        Matching argument values must be passed to exitTrue and exitFalse
   ///        of the resulting Condition object.
-  Condition emitCondition(Expr *E,
-                          bool hasFalseCode = true, bool invertValue = false,
-                          ArrayRef<SILType> contArgs = {});
+  /// \param NumTrueTaken - The number of times the condition evaluates to true.
+  /// \param NumFalseTaken - The number of times the condition evaluates to
+  /// false.
+  Condition emitCondition(Expr *E, bool hasFalseCode = true,
+                          bool invertValue = false,
+                          ArrayRef<SILType> contArgs = {},
+                          ProfileCounter NumTrueTaken = ProfileCounter(),
+                          ProfileCounter NumFalseTaken = ProfileCounter());
 
-  Condition emitCondition(SILValue V, SILLocation Loc,
-                          bool hasFalseCode = true, bool invertValue = false,
-                          ArrayRef<SILType> contArgs = {});
+  Condition emitCondition(SILValue V, SILLocation Loc, bool hasFalseCode = true,
+                          bool invertValue = false,
+                          ArrayRef<SILType> contArgs = {},
+                          ProfileCounter NumTrueTaken = ProfileCounter(),
+                          ProfileCounter NumFalseTaken = ProfileCounter());
 
   /// Create a new basic block.
   ///
@@ -923,8 +932,9 @@
   //===--------------------------------------------------------------------===//
 
   SILValue emitOSVersionRangeCheck(SILLocation loc, const VersionRange &range);
-  void emitStmtCondition(StmtCondition Cond, JumpDest FailDest,
-                         SILLocation loc);
+  void emitStmtCondition(StmtCondition Cond, JumpDest FailDest, SILLocation loc,
+                         ProfileCounter NumTrueTaken = ProfileCounter(),
+                         ProfileCounter NumFalseTaken = ProfileCounter());
 
   void emitConditionalPBD(PatternBindingDecl *PBD, SILBasicBlock *FailBB);
 
@@ -1440,11 +1450,13 @@
   ///                     terminated.
   /// \param handleFalse  A callback to invoke in the failure path.  The
   ///                     current BB should be terminated.
-  void emitCheckedCastBranch(
-      SILLocation loc, ConsumableManagedValue src, Type sourceType,
-      CanType targetType, SGFContext C,
-      std::function<void(ManagedValue)> handleTrue,
-      std::function<void(Optional<ManagedValue>)> handleFalse);
+  void
+  emitCheckedCastBranch(SILLocation loc, ConsumableManagedValue src,
+                        Type sourceType, CanType targetType, SGFContext C,
+                        std::function<void(ManagedValue)> handleTrue,
+                        std::function<void(Optional<ManagedValue>)> handleFalse,
+                        ProfileCounter TrueCount = ProfileCounter(),
+                        ProfileCounter FalseCount = ProfileCounter());
 
   /// A form of checked cast branch that uses the old non-ownership preserving
   /// semantics.
@@ -1455,7 +1467,9 @@
   void emitCheckedCastBranchOld(SILLocation loc, Expr *source, Type targetType,
                                 SGFContext ctx,
                                 std::function<void(ManagedValue)> handleTrue,
-                                std::function<void()> handleFalse);
+                                std::function<void()> handleFalse,
+                                ProfileCounter TrueCount = ProfileCounter(),
+                                ProfileCounter FalseCount = ProfileCounter());
 
   /// \brief Emit a conditional checked cast branch, starting from an
   /// expression.  Terminates the current BB.
@@ -1469,10 +1483,13 @@
   ///                     terminated.
   /// \param handleFalse  A callback to invoke in the failure path.  The
   ///                     current BB should be terminated.
-  void emitCheckedCastBranch(
-      SILLocation loc, Expr *src, Type targetType, SGFContext C,
-      std::function<void(ManagedValue)> handleTrue,
-      std::function<void(Optional<ManagedValue>)> handleFalse);
+  void
+  emitCheckedCastBranch(SILLocation loc, Expr *src, Type targetType,
+                        SGFContext C,
+                        std::function<void(ManagedValue)> handleTrue,
+                        std::function<void(Optional<ManagedValue>)> handleFalse,
+                        ProfileCounter TrueCount = ProfileCounter(),
+                        ProfileCounter FalseCount = ProfileCounter());
 
   /// A form of checked cast branch that uses the old non-ownership preserving
   /// semantics.
@@ -1484,7 +1501,9 @@
                                 Type sourceType, CanType targetType,
                                 SGFContext ctx,
                                 std::function<void(ManagedValue)> handleTrue,
-                                std::function<void()> handleFalse);
+                                std::function<void()> handleFalse,
+                                ProfileCounter TrueCount = ProfileCounter(),
+                                ProfileCounter FalseCount = ProfileCounter());
 
   /// Emit the control flow for an optional 'bind' operation, branching to the
   /// active failure destination if the optional value addressed by optionalAddr
diff --git a/lib/SILGen/SILGenMaterializeForSet.cpp b/lib/SILGen/SILGenMaterializeForSet.cpp
index 4ca810e..8597760 100644
--- a/lib/SILGen/SILGenMaterializeForSet.cpp
+++ b/lib/SILGen/SILGenMaterializeForSet.cpp
@@ -700,10 +700,9 @@
 
   auto callback = SGM.M.createFunction(
       callbackLinkage, CallbackName, callbackType, genericEnv,
-      SILLocation(Witness), IsBare, F.isTransparent(), F.isSerialized(), IsNotThunk,
-      SubclassScope::NotApplicable,
-      /*inlineStrategy=*/InlineDefault,
-      /*EK=*/EffectsKind::Unspecified,
+      SILLocation(Witness), IsBare, F.isTransparent(), F.isSerialized(),
+      F.getEntryCount(), IsNotThunk, SubclassScope::NotApplicable,
+      /*inlineStrategy=*/InlineDefault, /*EK=*/EffectsKind::Unspecified,
       /*InsertBefore=*/&F);
 
   callback->setDebugScope(new (SGM.M) SILDebugScope(Witness, callback));
diff --git a/lib/SILGen/SILGenPattern.cpp b/lib/SILGen/SILGenPattern.cpp
index 391d0d0..8c3e142 100644
--- a/lib/SILGen/SILGenPattern.cpp
+++ b/lib/SILGen/SILGenPattern.cpp
@@ -11,26 +11,27 @@
 //===----------------------------------------------------------------------===//
 
 #define DEBUG_TYPE "patternmatch-silgen"
-#include "SILGen.h"
-#include "Scope.h"
 #include "Cleanup.h"
 #include "ExitableFullExpr.h"
 #include "Initialization.h"
 #include "RValue.h"
-#include "llvm/ADT/MapVector.h"
-#include "llvm/Support/Debug.h"
-#include "llvm/Support/FormattedStream.h"
+#include "SILGen.h"
+#include "Scope.h"
 #include "swift/AST/ASTWalker.h"
 #include "swift/AST/DiagnosticsSIL.h"
 #include "swift/AST/Pattern.h"
 #include "swift/AST/SILOptions.h"
 #include "swift/AST/Types.h"
+#include "swift/Basic/ProfileCounter.h"
 #include "swift/Basic/STLExtras.h"
 #include "swift/SIL/DynamicCasts.h"
 #include "swift/SIL/SILArgument.h"
 #include "swift/SIL/SILUndef.h"
 #include "swift/SIL/TypeLowering.h"
+#include "llvm/ADT/MapVector.h"
 #include "llvm/Support/Compiler.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/FormattedStream.h"
 
 using namespace swift;
 using namespace Lowering;
@@ -314,6 +315,9 @@
 
   /// Whether the row will be irrefutable after this specialization.
   bool Irrefutable;
+
+  /// Profile Count of hte row we intend to specialize.
+  ProfileCounter Count;
 };
 
 /// Changes that we wish to apply to a row which we have specialized.
@@ -470,7 +474,8 @@
   void emitEnumElementDispatch(ArrayRef<RowToSpecialize> rows,
                                ConsumableManagedValue src,
                                const SpecializationHandler &handleSpec,
-                               const FailureHandler &failure);
+                               const FailureHandler &failure,
+                               ProfileCounter defaultCaseCount);
   void emitBoolDispatch(ArrayRef<RowToSpecialize> rows,
                         ConsumableManagedValue src,
                         const SpecializationHandler &handleSpec,
@@ -1324,9 +1329,15 @@
   auto addRowToSpecialize = [&](Pattern *pattern, unsigned rowIndex) {
     assert(getSpecializingPattern(clauses[rowIndex][column]) == pattern);
     bool irrefutable = clauses[rowIndex].isIrrefutableAfterSpecializing(column);
-    rowsToSpecialize.push_back({pattern, rowIndex, irrefutable});
+    auto caseBlock = clauses[rowIndex].getClientData<CaseStmt>();
+    ProfileCounter count = ProfileCounter();
+    if (caseBlock) {
+      count = SGF.SGM.loadProfilerCount(caseBlock);
+    }
+    rowsToSpecialize.push_back({pattern, rowIndex, irrefutable, count});
   };
 
+  ProfileCounter defaultCaseCount = ProfileCounter();
   Pattern *firstSpecializer = getSpecializingPattern(clauses[firstRow][column]);
   assert(firstSpecializer && "specializing unspecializable row?");
   addRowToSpecialize(firstSpecializer, firstRow);
@@ -1335,7 +1346,13 @@
   for (++lastRow; lastRow != clauses.rows(); ++lastRow) {
     Pattern *specializer =
       getSimilarSpecializingPattern(clauses[lastRow][column], firstSpecializer);
-    if (!specializer) break;
+    if (!specializer) {
+      auto caseBlock = clauses[lastRow].getClientData<CaseStmt>();
+      if (caseBlock) {
+        defaultCaseCount = SGF.SGM.loadProfilerCount(caseBlock);
+      }
+      break;
+    }
     addRowToSpecialize(specializer, lastRow);
   }
   assert(lastRow - firstRow == rowsToSpecialize.size());
@@ -1380,7 +1397,8 @@
     return emitIsDispatch(rowsToSpecialize, arg, handler, failure);
   case PatternKind::EnumElement:
   case PatternKind::OptionalSome:
-    return emitEnumElementDispatch(rowsToSpecialize, arg, handler, failure);
+    return emitEnumElementDispatch(rowsToSpecialize, arg, handler, failure,
+                                   defaultCaseCount);
   case PatternKind::Bool:
     return emitBoolDispatch(rowsToSpecialize, arg, handler, failure);
   }
@@ -1648,7 +1666,7 @@
         assert(!SGF.B.hasValidInsertionPoint() && "did not end block");
       },
       // Failure block: branch out to the continuation block.
-      [&] { (*innerFailure)(loc); });
+      [&] { (*innerFailure)(loc); }, rows[0].Count);
 }
 
 /// Perform specialized dispatch for a sequence of EnumElementPattern or an
@@ -1878,8 +1896,8 @@
 /// OptionalSomePattern.
 void PatternMatchEmission::emitEnumElementDispatch(
     ArrayRef<RowToSpecialize> rows, ConsumableManagedValue src,
-    const SpecializationHandler &handleCase,
-    const FailureHandler &outerFailure) {
+    const SpecializationHandler &handleCase, const FailureHandler &outerFailure,
+    ProfileCounter defaultCaseCount) {
   // If sil ownership is enabled and we have that our source type is an object,
   // use the dispatch code path.
   if (SGF.getOptions().EnableSILOwnership && src.getType().isObject()) {
@@ -1904,6 +1922,7 @@
   // instructions want only the first information, so we split them up.
   SmallVector<std::pair<EnumElementDecl*, SILBasicBlock*>, 4> caseBBs;
   SmallVector<CaseInfo, 4> caseInfos;
+  SmallVector<ProfileCounter, 4> caseCounts;
   SILBasicBlock *defaultBB = nullptr;
 
   caseBBs.reserve(rows.size());
@@ -1935,6 +1954,7 @@
         caseInfos.resize(caseInfos.size() + 1);
         caseInfos.back().FormalElement = formalElt;
         caseInfos.back().FirstMatcher = row.Pattern;
+        caseCounts.push_back(row.Count);
       }
       assert(caseToIndex[elt] == index);
       assert(caseBBs[index].first == elt);
@@ -2019,10 +2039,13 @@
   SILValue srcValue = src.getFinalManagedValue().forward(SGF);
   SILLocation loc = PatternMatchStmt;
   loc.setDebugLoc(rows[0].Pattern);
+  ArrayRef<ProfileCounter> caseCountsArrayRef = caseCounts;
   if (addressOnlyEnum) {
-    SGF.B.createSwitchEnumAddr(loc, srcValue, defaultBB, caseBBs);
+    SGF.B.createSwitchEnumAddr(loc, srcValue, defaultBB, caseBBs,
+                               caseCountsArrayRef, defaultCaseCount);
   } else {
-    SGF.B.createSwitchEnum(loc, srcValue, defaultBB, caseBBs);
+    SGF.B.createSwitchEnum(loc, srcValue, defaultBB, caseBBs,
+                           caseCountsArrayRef, defaultCaseCount);
   }
 
   // Okay, now emit all the cases.
diff --git a/lib/SILGen/SILGenProfiling.cpp b/lib/SILGen/SILGenProfiling.cpp
index f564dfd..32f9175 100644
--- a/lib/SILGen/SILGenProfiling.cpp
+++ b/lib/SILGen/SILGenProfiling.cpp
@@ -82,7 +82,7 @@
   assert(isa<AbstractFunctionDecl>(D) ||
          isa<TopLevelCodeDecl>(D) && "Cannot create profiler for this decl");
   const auto &Opts = SGM.M.getOptions();
-  if (!Opts.GenerateProfile || isUnmappedDecl(D))
+  if ((!Opts.GenerateProfile && Opts.UseProfile.empty()) || isUnmappedDecl(D))
     return;
   SGM.Profiler =
       llvm::make_unique<SILGenProfiling>(SGM, Opts.EmitProfileCoverageMapping);
@@ -139,10 +139,11 @@
   }
 
   std::pair<bool, Expr *> walkToExprPre(Expr *E) override {
-    if (auto *IE = dyn_cast<IfExpr>(E))
+    if (auto *IE = dyn_cast<IfExpr>(E)) {
       CounterMap[IE->getThenExpr()] = NextCounter++;
-    else if (isa<AutoClosureExpr>(E) || isa<ClosureExpr>(E))
+    } else if (isa<AutoClosureExpr>(E) || isa<ClosureExpr>(E)) {
       CounterMap[E] = NextCounter++;
+    }
     return {true, E};
   }
 };
@@ -271,6 +272,195 @@
   }
 };
 
+/// An ASTWalker that maps ASTNodes to profiling counters.
+struct PGOMapping : public ASTWalker {
+  /// The next counter value to assign.
+  unsigned NextCounter;
+
+  /// The map of statements to counters.
+  llvm::DenseMap<ASTNode, ProfileCounter> &LoadedCounterMap;
+  llvm::Expected<llvm::InstrProfRecord> &LoadedCounts;
+  llvm::DenseMap<ASTNode, ASTNode> &CondToParentMap;
+  llvm::DenseMap<ASTNode, unsigned> CounterMap;
+
+  PGOMapping(llvm::DenseMap<ASTNode, ProfileCounter> &LoadedCounterMap,
+             llvm::Expected<llvm::InstrProfRecord> &LoadedCounts,
+             llvm::DenseMap<ASTNode, ASTNode> &PGORegionCondToParentMap)
+      : NextCounter(0), LoadedCounterMap(LoadedCounterMap),
+        LoadedCounts(LoadedCounts), CondToParentMap(PGORegionCondToParentMap) {}
+
+  unsigned getParentCounter() const {
+    if (Parent.isNull())
+      return 0;
+    else if (Parent.getKind() == ASTWalker::ParentKind::Decl) {
+      auto it = CounterMap.find(Parent.getAsDecl());
+      return (it != CounterMap.end()) ? it->getSecond() : 0;
+    } else if (Parent.getKind() == ASTWalker::ParentKind::Stmt) {
+      auto it = CounterMap.find(Parent.getAsStmt());
+      return (it != CounterMap.end()) ? it->getSecond() : 0;
+    } else if (Parent.getKind() == ASTWalker::ParentKind::Expr) {
+      auto it = CounterMap.find(Parent.getAsExpr());
+      return (it != CounterMap.end()) ? it->getSecond() : 0;
+    }
+    return 0;
+  }
+
+  ProfileCounter subtract(ProfileCounter L, ProfileCounter R) {
+    if (!L.hasValue() || !R.hasValue()) {
+      return L;
+    }
+    uint64_t LV = L.getValue();
+    uint64_t RV = R.getValue();
+    assert(LV >= RV && "Invalid counter subtraction");
+    return LV - RV;
+  }
+
+  /// Load the execution count corresponding to \p Node from a profile, if one
+  /// is available.
+  ProfileCounter loadExecutionCount(ASTNode Node) {
+    if (!Node)
+      return ProfileCounter();
+
+    auto CounterIt = CounterMap.find(Node);
+    assert(CounterIt != CounterMap.end() &&
+           "region does not have an associated counter");
+
+    unsigned CounterIndexForFunc = CounterIt->second;
+    return LoadedCounts->Counts[CounterIndexForFunc];
+  }
+
+  bool walkToDeclPre(Decl *D) override {
+    if (isUnmappedDecl(D))
+      return false;
+    if (auto *AFD = dyn_cast<AbstractFunctionDecl>(D)) {
+      auto node = AFD->getBody();
+      CounterMap[node] = NextCounter++;
+      auto count = loadExecutionCount(node);
+      LoadedCounterMap[node] = count;
+    }
+    if (auto *TLCD = dyn_cast<TopLevelCodeDecl>(D)) {
+      auto node = TLCD->getBody();
+      CounterMap[node] = NextCounter++;
+      auto count = loadExecutionCount(node);
+      LoadedCounterMap[node] = count;
+    }
+    return true;
+  }
+
+  std::pair<bool, Stmt *> walkToStmtPre(Stmt *S) override {
+    unsigned parent = getParentCounter();
+    if (auto *IS = dyn_cast<IfStmt>(S)) {
+      auto thenStmt = IS->getThenStmt();
+      CounterMap[thenStmt] = NextCounter++;
+      auto thenCount = loadExecutionCount(thenStmt);
+      LoadedCounterMap[thenStmt] = thenCount;
+      if (auto elseStmt = IS->getElseStmt()) {
+        CounterMap[elseStmt] = parent;
+        auto count = loadExecutionCount(elseStmt);
+        if (!parent) {
+          auto thenVal = thenCount.getValue();
+          for (auto pCount = NextCounter - 1; pCount > 0; --pCount) {
+            auto cCount = LoadedCounts->Counts[pCount];
+            if (cCount > thenVal) {
+              count = cCount;
+              break;
+            }
+          }
+        }
+        LoadedCounterMap[elseStmt] = subtract(count, thenCount);
+        auto Cond = IS->getCond();
+        for (const auto &elt : Cond) {
+          if (elt.getKind() ==
+              StmtConditionElement::ConditionKind::CK_PatternBinding) {
+            CondToParentMap[elt.getInitializer()] = IS;
+          }
+        }
+      }
+    } else if (auto *US = dyn_cast<GuardStmt>(S)) {
+      auto guardBody = US->getBody();
+      CounterMap[guardBody] = NextCounter++;
+      auto guardCount = loadExecutionCount(guardBody);
+      LoadedCounterMap[guardBody] = guardCount;
+      CounterMap[US] = parent;
+      auto count = loadExecutionCount(US);
+      LoadedCounterMap[US] = subtract(count, guardCount);
+    } else if (auto *WS = dyn_cast<WhileStmt>(S)) {
+      auto whileBody = WS->getBody();
+      CounterMap[whileBody] = NextCounter++;
+      auto whileCount = loadExecutionCount(whileBody);
+      LoadedCounterMap[whileBody] = whileCount;
+      CounterMap[WS] = parent;
+      auto count = loadExecutionCount(WS);
+      LoadedCounterMap[WS] = count;
+    } else if (auto *RWS = dyn_cast<RepeatWhileStmt>(S)) {
+      auto rwsBody = RWS->getBody();
+      CounterMap[rwsBody] = NextCounter++;
+      auto rwsBodyCount = loadExecutionCount(rwsBody);
+      LoadedCounterMap[rwsBody] = rwsBodyCount;
+      CounterMap[RWS] = parent;
+      auto count = loadExecutionCount(RWS);
+      LoadedCounterMap[RWS] = count;
+    } else if (auto *FES = dyn_cast<ForEachStmt>(S)) {
+      auto fesBody = FES->getBody();
+      CounterMap[fesBody] = NextCounter++;
+      auto fesCount = loadExecutionCount(fesBody);
+      LoadedCounterMap[fesBody] = fesCount;
+      CounterMap[FES] = parent;
+      auto count = loadExecutionCount(FES);
+      LoadedCounterMap[FES] = count;
+      walkPatternForProfiling(FES->getIterator(), *this);
+    } else if (auto *SS = dyn_cast<SwitchStmt>(S)) {
+      CounterMap[SS] = NextCounter++;
+      auto ssCount = loadExecutionCount(SS);
+      LoadedCounterMap[SS] = ssCount;
+    } else if (auto *CS = dyn_cast<CaseStmt>(S)) {
+      CounterMap[CS] = NextCounter++;
+      auto csCount = loadExecutionCount(CS);
+      LoadedCounterMap[CS] = csCount;
+    } else if (auto *DCS = dyn_cast<DoCatchStmt>(S)) {
+      CounterMap[DCS] = NextCounter++;
+      auto dcsCount = loadExecutionCount(DCS);
+      LoadedCounterMap[DCS] = dcsCount;
+    } else if (auto *CS = dyn_cast<CatchStmt>(S)) {
+      auto csBody = CS->getBody();
+      CounterMap[csBody] = NextCounter++;
+      auto csBodyCount = loadExecutionCount(csBody);
+      LoadedCounterMap[csBody] = csBodyCount;
+    }
+    return {true, S};
+  }
+
+  std::pair<bool, Expr *> walkToExprPre(Expr *E) override {
+    unsigned parent = getParentCounter();
+    if (auto *IE = dyn_cast<IfExpr>(E)) {
+      auto thenExpr = IE->getThenExpr();
+      CounterMap[thenExpr] = NextCounter++;
+      auto thenCount = loadExecutionCount(thenExpr);
+      LoadedCounterMap[thenExpr] = thenCount;
+      if (auto elseExpr = IE->getElseExpr()) {
+        CounterMap[elseExpr] = parent;
+        auto count = loadExecutionCount(elseExpr);
+        if (!parent) {
+          auto thenVal = thenCount.getValue();
+          for (auto pCount = NextCounter - 1; pCount > 0; --pCount) {
+            auto cCount = LoadedCounts->Counts[pCount];
+            if (cCount > thenVal) {
+              count = cCount;
+              break;
+            }
+          }
+        }
+        LoadedCounterMap[elseExpr] = subtract(count, thenCount);
+      }
+    } else if (isa<AutoClosureExpr>(E) || isa<ClosureExpr>(E)) {
+      CounterMap[E] = NextCounter++;
+      auto eCount = loadExecutionCount(E);
+      LoadedCounterMap[E] = eCount;
+    }
+    return {true, E};
+  }
+};
+
 struct CoverageMapping : public ASTWalker {
 private:
   const SourceManager &SM;
@@ -698,6 +888,10 @@
     CurrentFuncLinkage = FormalLinkage::HiddenUnique;
   }
 
+  PGOFuncName = llvm::getPGOFuncName(
+      CurrentFuncName, getEquivalentPGOLinkage(CurrentFuncLinkage),
+      CurrentFileName);
+
   walkForProfiling(Root, Mapper);
 
   NumRegionCounters = Mapper.NextCounter;
@@ -712,6 +906,45 @@
                                    getEquivalentPGOLinkage(CurrentFuncLinkage)),
                                FunctionHash, RegionCounterMap, CurrentFileName);
   }
+
+  if (SGM.PGOReader) {
+    auto LoadedCounts =
+        SGM.PGOReader->getInstrProfRecord(PGOFuncName, FunctionHash);
+    if (auto E = LoadedCounts.takeError()) {
+      llvm::handleAllErrors(std::move(E),
+                            [&E](const llvm::InstrProfError &Err) {
+                              Err.log(llvm::dbgs());
+                              return;
+                            });
+      llvm::dbgs() << PGOFuncName << "\n";
+      return;
+    }
+    PGOMapping pgoMapper(PGORegionLoadedCounterMap, LoadedCounts,
+                         PGORegionCondToParentMap);
+    walkForProfiling(Root, pgoMapper);
+  }
+}
+
+ProfileCounter SILGenProfiling::getExecutionCount(ASTNode Node) {
+  if (!Node) {
+    return ProfileCounter();
+  }
+  auto it = PGORegionLoadedCounterMap.find(Node);
+  if (it == PGORegionLoadedCounterMap.end()) {
+    return ProfileCounter();
+  }
+  return it->getSecond();
+}
+
+Optional<ASTNode> SILGenProfiling::getPGOParent(ASTNode Node) {
+  if (!Node) {
+    return None;
+  }
+  auto it = PGORegionCondToParentMap.find(Node);
+  if (it == PGORegionCondToParentMap.end()) {
+    return None;
+  }
+  return it->getSecond();
 }
 
 static SILLocation getLocation(ASTNode Node) {
diff --git a/lib/SILGen/SILGenProfiling.h b/lib/SILGen/SILGenProfiling.h
index 45e2cb7..562fb21 100644
--- a/lib/SILGen/SILGenProfiling.h
+++ b/lib/SILGen/SILGenProfiling.h
@@ -13,10 +13,12 @@
 #ifndef SWIFT_SILGEN_PROFILING_H
 #define SWIFT_SILGEN_PROFILING_H
 
-#include "llvm/ADT/DenseMap.h"
 #include "swift/AST/ASTNode.h"
 #include "swift/AST/Stmt.h"
+#include "swift/Basic/ProfileCounter.h"
 #include "swift/SIL/FormalLinkage.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ProfileData/InstrProf.h"
 
 namespace swift {
 
@@ -41,7 +43,10 @@
   FormalLinkage CurrentFuncLinkage;
   unsigned NumRegionCounters;
   uint64_t FunctionHash;
+  std::string PGOFuncName;
   llvm::DenseMap<ASTNode, unsigned> RegionCounterMap;
+  llvm::DenseMap<ASTNode, ProfileCounter> PGORegionLoadedCounterMap;
+  llvm::DenseMap<ASTNode, ASTNode> PGORegionCondToParentMap;
 
   std::vector<std::tuple<std::string, uint64_t, std::string>> CoverageData;
 
@@ -55,6 +60,14 @@
   /// Emit SIL to increment the counter for \c Node.
   void emitCounterIncrement(SILGenBuilder &Builder, ASTNode Node);
 
+  /// Get previously Loaded the execution count corresponding to \p Node
+  /// from a profile, if one is available.
+  ProfileCounter getExecutionCount(ASTNode Node);
+
+  /// Get PGORegion's parent ASTNode
+  /// used to get a condition's parent IfStmt or IfCond
+  Optional<ASTNode> getPGOParent(ASTNode Node);
+
 private:
   /// Map counters to ASTNodes and set them up for profiling the given function.
   void assignRegionCounters(Decl *Root);
@@ -72,6 +85,7 @@
 };
 
 } // end namespace Lowering
+
 } // end namespace swift
 
 #endif // SWIFT_SILGEN_PROFILING
diff --git a/lib/SILGen/SILGenStmt.cpp b/lib/SILGen/SILGenStmt.cpp
index 1a44a62..fd1e468 100644
--- a/lib/SILGen/SILGenStmt.cpp
+++ b/lib/SILGen/SILGenStmt.cpp
@@ -10,14 +10,15 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "SILGen.h"
 #include "Condition.h"
 #include "Initialization.h"
 #include "LValue.h"
 #include "RValue.h"
+#include "SILGen.h"
 #include "Scope.h"
 #include "SwitchCaseFullExpr.h"
 #include "swift/AST/DiagnosticsSIL.h"
+#include "swift/Basic/ProfileCounter.h"
 #include "swift/SIL/SILArgument.h"
 #include "llvm/Support/SaveAndRestore.h"
 
@@ -138,9 +139,11 @@
     SGF.B.emitBlock(BB, BranchLoc);
 }
 
-Condition SILGenFunction::emitCondition(Expr *E,
-                                        bool hasFalseCode, bool invertValue,
-                                        ArrayRef<SILType> contArgs) {
+Condition SILGenFunction::emitCondition(Expr *E, bool hasFalseCode,
+                                        bool invertValue,
+                                        ArrayRef<SILType> contArgs,
+                                        ProfileCounter NumTrueTaken,
+                                        ProfileCounter NumFalseTaken) {
   assert(B.hasValidInsertionPoint() &&
          "emitting condition at unreachable point");
 
@@ -152,14 +155,15 @@
   }
   assert(V->getType().castTo<BuiltinIntegerType>()->isFixedWidth(1));
 
-  return emitCondition(V, E, hasFalseCode, invertValue, contArgs);
+  return emitCondition(V, E, hasFalseCode, invertValue, contArgs, NumTrueTaken,
+                       NumFalseTaken);
 }
 
-
-
 Condition SILGenFunction::emitCondition(SILValue V, SILLocation Loc,
                                         bool hasFalseCode, bool invertValue,
-                                        ArrayRef<SILType> contArgs) {
+                                        ArrayRef<SILType> contArgs,
+                                        ProfileCounter NumTrueTaken,
+                                        ProfileCounter NumFalseTaken) {
   assert(B.hasValidInsertionPoint() &&
          "emitting condition at unreachable point");
 
@@ -180,10 +184,12 @@
   SILBasicBlock *TrueBB = createBasicBlock();
 
   if (invertValue)
-    B.createCondBranch(Loc, V, FalseDestBB, TrueBB);
+    B.createCondBranch(Loc, V, FalseDestBB, TrueBB, NumFalseTaken,
+                       NumTrueTaken);
   else
-    B.createCondBranch(Loc, V, TrueBB, FalseDestBB);
-  
+    B.createCondBranch(Loc, V, TrueBB, FalseDestBB, NumTrueTaken,
+                       NumFalseTaken);
+
   return Condition(TrueBB, FalseBB, ContBB, Loc);
 }
 
@@ -484,7 +490,7 @@
   JumpDest falseDest = contDest;
   if (S->getElseStmt())
     falseDest = createJumpDest(S);
-  
+
   // Emit the condition, along with the "then" part of the if properly guarded
   // by the condition and a jump to ContBB.  If the condition fails, jump to
   // the CondFalseBB.
@@ -492,8 +498,12 @@
     // Enter a scope for any bound pattern variables.
     LexicalScope trueScope(SGF, S);
 
-    SGF.emitStmtCondition(S->getCond(), falseDest, S);
-    
+    auto NumTrueTaken = SGF.SGM.loadProfilerCount(S->getThenStmt());
+    auto NumFalseTaken = SGF.SGM.loadProfilerCount(S->getElseStmt());
+
+    SGF.emitStmtCondition(S->getCond(), falseDest, S, NumTrueTaken,
+                          NumFalseTaken);
+
     // In the success path, emit the 'then' part if the if.
     SGF.emitProfilerIncrement(S->getThenStmt());
     SGF.emitStmt(S->getThenStmt());
@@ -553,7 +563,9 @@
 
   // Emit the condition bindings, branching to the bodyBB if they fail.  Since
   // we didn't push a scope, the bound variables are live after this statement.
-  SGF.emitStmtCondition(S->getCond(), bodyBB, S);
+  auto NumFalseTaken = SGF.SGM.loadProfilerCount(S->getBody());
+  auto NumNonTaken = SGF.SGM.loadProfilerCount(S);
+  SGF.emitStmtCondition(S->getCond(), bodyBB, S, NumNonTaken, NumFalseTaken);
 }
 
 void StmtEmitter::visitWhileStmt(WhileStmt *S) {
@@ -576,8 +588,10 @@
   {
     // Enter a scope for any bound pattern variables.
     Scope conditionScope(SGF.Cleanups, S);
-    
-    SGF.emitStmtCondition(S->getCond(), breakDest, S);
+
+    auto NumTrueTaken = SGF.SGM.loadProfilerCount(S->getBody());
+    auto NumFalseTaken = SGF.SGM.loadProfilerCount(S);
+    SGF.emitStmtCondition(S->getCond(), breakDest, S, NumTrueTaken, NumFalseTaken);
     
     // In the success path, emit the body of the while.
     SGF.emitProfilerIncrement(S->getBody());
@@ -729,8 +743,12 @@
   if (SGF.B.hasValidInsertionPoint()) {
     // Evaluate the condition with the false edge leading directly
     // to the continuation block.
-    Condition Cond = SGF.emitCondition(S->getCond(), /*hasFalseCode*/ false);
-    
+    auto NumTrueTaken = SGF.SGM.loadProfilerCount(S->getBody());
+    auto NumFalseTaken = SGF.SGM.loadProfilerCount(S);
+    Condition Cond = SGF.emitCondition(S->getCond(), /*hasFalseCode*/ false,
+                                       /*invertValue*/ false, /*contArgs*/ {},
+                                       NumTrueTaken, NumFalseTaken);
+
     Cond.enterTrue(SGF);
     if (SGF.B.hasValidInsertionPoint()) {
       SGF.B.createBranch(S->getCond(), loopBB);
@@ -866,7 +884,8 @@
         RegularLocation L(S->getBody());
         L.pointToEnd();
         scope.exitAndBranch(L);
-      });
+      },
+      SGF.SGM.loadProfilerCount(S->getBody()));
 
   // We add loop fail block, just to be defensive about intermediate
   // transformations performing cleanups at scope.exit(). We still jump to the
@@ -877,7 +896,8 @@
       [&](ManagedValue inputValue, SwitchCaseFullExpr &scope) {
         assert(!inputValue && "None should not be passed an argument!");
         scope.exitAndBranch(S);
-      });
+      },
+      SGF.SGM.loadProfilerCount(S));
 
   std::move(switchEnumBuilder).emit();
 
diff --git a/lib/SILGen/SILGenThunk.cpp b/lib/SILGen/SILGenThunk.cpp
index ea598d3..f1139a8 100644
--- a/lib/SILGen/SILGenThunk.cpp
+++ b/lib/SILGen/SILGenThunk.cpp
@@ -42,7 +42,7 @@
 
   auto F = M.getOrCreateFunction(constant.getDecl(), name, SILLinkage::Shared,
                                  constantInfo.SILFnType, IsBare, IsTransparent,
-                                 IsSerializable, IsThunk);
+                                 IsSerializable, ProfileCounter(), IsThunk);
 
   if (F->empty()) {
     // Emit the thunk if we haven't yet.
@@ -166,7 +166,7 @@
     SILGenBuilder::getPartialApplyResultType(toFn->getType(), /*appliedParams=*/1,
                                              SGM.M, subs,
                                              ParameterConvention::Direct_Owned);
-  SILInstruction *toClosure =
+  SILValue toClosure =
     B.createPartialApply(vd, toFn, substTy, subs, {selfArg}, closureTy);
   if (resultTy != closureTy)
     toClosure = B.createConvertFunction(vd, toClosure, resultTy);
@@ -270,7 +270,8 @@
                        fromInterfaceType, toInterfaceType, M.getSwiftModule());
   
   auto loc = RegularLocation::getAutoGeneratedLocation();
+
   return M.getOrCreateSharedFunction(loc, name, thunkType, IsBare,
                                      IsTransparent, IsSerializable,
-                                     IsReabstractionThunk);
+                                     ProfileCounter(), IsReabstractionThunk);
 }
diff --git a/lib/SILGen/SILGenType.cpp b/lib/SILGen/SILGenType.cpp
index d42bbdb..5fbf293 100644
--- a/lib/SILGen/SILGenType.cpp
+++ b/lib/SILGen/SILGenType.cpp
@@ -690,10 +690,9 @@
     InlineStrategy = AlwaysInline;
 
   auto *f = M.createFunction(
-      linkage, nameBuffer, witnessSILFnType,
-      genericEnv, SILLocation(witnessRef.getDecl()),
-      IsNotBare, IsTransparent, isSerialized, IsThunk,
-      SubclassScope::NotApplicable, InlineStrategy);
+      linkage, nameBuffer, witnessSILFnType, genericEnv,
+      SILLocation(witnessRef.getDecl()), IsNotBare, IsTransparent, isSerialized,
+      ProfileCounter(), IsThunk, SubclassScope::NotApplicable, InlineStrategy);
 
   f->setDebugScope(new (M)
                    SILDebugScope(RegularLocation(witnessRef.getDecl()), f));
diff --git a/lib/SILOptimizer/ARC/ARCRegionState.cpp b/lib/SILOptimizer/ARC/ARCRegionState.cpp
index 13c1d99..e4c2eed 100644
--- a/lib/SILOptimizer/ARC/ARCRegionState.cpp
+++ b/lib/SILOptimizer/ARC/ARCRegionState.cpp
@@ -516,9 +516,9 @@
 
 static bool isStrongEntranceInstruction(const SILInstruction &I) {
   switch (I.getKind()) {
-  case ValueKind::AllocRefInst:
-  case ValueKind::AllocRefDynamicInst:
-  case ValueKind::AllocBoxInst:
+  case SILInstructionKind::AllocRefInst:
+  case SILInstructionKind::AllocRefDynamicInst:
+  case SILInstructionKind::AllocBoxInst:
     return true;
   default:
     return false;
diff --git a/lib/SILOptimizer/ARC/RCStateTransition.cpp b/lib/SILOptimizer/ARC/RCStateTransition.cpp
index c74532a..23a2c1d 100644
--- a/lib/SILOptimizer/ARC/RCStateTransition.cpp
+++ b/lib/SILOptimizer/ARC/RCStateTransition.cpp
@@ -42,25 +42,25 @@
 //                           RCStateTransitionKind
 //===----------------------------------------------------------------------===//
 
-RCStateTransitionKind swift::getRCStateTransitionKind(ValueBase *V) {
-  switch (V->getKind()) {
-  case ValueKind::StrongRetainInst:
-  case ValueKind::RetainValueInst:
+RCStateTransitionKind swift::getRCStateTransitionKind(SILNode *N) {
+  switch (N->getKind()) {
+  case SILNodeKind::StrongRetainInst:
+  case SILNodeKind::RetainValueInst:
     return RCStateTransitionKind::StrongIncrement;
 
-  case ValueKind::StrongReleaseInst:
-  case ValueKind::ReleaseValueInst:
+  case SILNodeKind::StrongReleaseInst:
+  case SILNodeKind::ReleaseValueInst:
     return RCStateTransitionKind::StrongDecrement;
 
-  case ValueKind::SILFunctionArgument: {
-    auto *Arg = cast<SILFunctionArgument>(V);
+  case SILNodeKind::SILFunctionArgument: {
+    auto *Arg = cast<SILFunctionArgument>(N);
     if (Arg->hasConvention(SILArgumentConvention::Direct_Owned))
       return RCStateTransitionKind::StrongEntrance;
     return RCStateTransitionKind::Unknown;
   }
 
-  case ValueKind::ApplyInst: {
-    auto *AI = cast<ApplyInst>(V);
+  case SILNodeKind::ApplyInst: {
+    auto *AI = cast<ApplyInst>(N);
     if (isAutoreleasePoolCall(AI))
       return RCStateTransitionKind::AutoreleasePoolCall;
 
@@ -78,13 +78,13 @@
     return RCStateTransitionKind::Unknown;
   }
 
-  case ValueKind::AllocRefInst:
-  case ValueKind::AllocRefDynamicInst:
+  case SILNodeKind::AllocRefInst:
+  case SILNodeKind::AllocRefDynamicInst:
     // AllocRef* are always allocating new classes so they are introducing new
     // values at +1.
     return RCStateTransitionKind::StrongEntrance;
 
-  case ValueKind::AllocBoxInst:
+  case SILNodeKind::AllocBoxInst:
     // AllocBox introduce their container result at +1.
     return RCStateTransitionKind::StrongEntrance;
 
diff --git a/lib/SILOptimizer/ARC/RCStateTransition.h b/lib/SILOptimizer/ARC/RCStateTransition.h
index 4772b2d..65829ff 100644
--- a/lib/SILOptimizer/ARC/RCStateTransition.h
+++ b/lib/SILOptimizer/ARC/RCStateTransition.h
@@ -41,18 +41,18 @@
 #include "RCStateTransition.def"
 };
 
-/// \returns the RCStateTransitionKind corresponding to \p V.
-RCStateTransitionKind getRCStateTransitionKind(ValueBase *V);
+/// \returns the RCStateTransitionKind corresponding to \p N.
+RCStateTransitionKind getRCStateTransitionKind(SILNode *N);
 
 /// Define predicates to test for RCStateTransition abstract value kinds.
 #define ABSTRACT_VALUE(Name, Start, End)                              \
   bool isRCStateTransition ## Name(RCStateTransitionKind Kind);       \
-  static inline bool isRCStateTransition ## Name(ValueBase *V) {      \
-    return isRCStateTransition ## Name(getRCStateTransitionKind(V));  \
+  static inline bool isRCStateTransition ## Name(SILNode *N) {        \
+    return isRCStateTransition ## Name(getRCStateTransitionKind(N));  \
   }
 #define KIND(Name)                                                      \
-  static inline bool isRCStateTransition ## Name(ValueBase *V) {        \
-    return RCStateTransitionKind::Name == getRCStateTransitionKind(V);  \
+  static inline bool isRCStateTransition ## Name(SILNode *N) {          \
+    return RCStateTransitionKind::Name == getRCStateTransitionKind(N);  \
   }
 #include "RCStateTransition.def"
 
@@ -72,7 +72,7 @@
 
   /// An RCStateTransition can represent either an RC end point (i.e. an initial
   /// or terminal RC transition) or a ptr set of Mutators.
-  ValueBase *EndPoint;
+  SILNode *EndPoint;
   ImmutablePointerSet<SILInstruction> *Mutators =
       ImmutablePointerSetFactory<SILInstruction>::getEmptySet();
   RCStateTransitionKind Kind;
diff --git a/lib/SILOptimizer/ARC/RCStateTransitionVisitors.cpp b/lib/SILOptimizer/ARC/RCStateTransitionVisitors.cpp
index 9f71f14..ee79d35 100644
--- a/lib/SILOptimizer/ARC/RCStateTransitionVisitors.cpp
+++ b/lib/SILOptimizer/ARC/RCStateTransitionVisitors.cpp
@@ -65,7 +65,7 @@
 template <class ARCState>
 typename BottomUpDataflowRCStateVisitor<ARCState>::DataflowResult
 BottomUpDataflowRCStateVisitor<ARCState>::
-visitAutoreleasePoolCall(ValueBase *V) {
+visitAutoreleasePoolCall(SILNode *N) {
   DataflowState.clear();
 
   // We just cleared our BB State so we have no more possible effects.
@@ -107,8 +107,8 @@
 
 template <class ARCState>
 typename BottomUpDataflowRCStateVisitor<ARCState>::DataflowResult
-BottomUpDataflowRCStateVisitor<ARCState>::visitStrongDecrement(ValueBase *V) {
-  auto *I = dyn_cast<SILInstruction>(V);
+BottomUpDataflowRCStateVisitor<ARCState>::visitStrongDecrement(SILNode *N) {
+  auto *I = dyn_cast<SILInstruction>(N);
   if (!I)
     return DataflowResult();
 
@@ -137,8 +137,8 @@
 
 template <class ARCState>
 typename BottomUpDataflowRCStateVisitor<ARCState>::DataflowResult
-BottomUpDataflowRCStateVisitor<ARCState>::visitStrongIncrement(ValueBase *V) {
-  auto *I = dyn_cast<SILInstruction>(V);
+BottomUpDataflowRCStateVisitor<ARCState>::visitStrongIncrement(SILNode *N) {
+  auto *I = dyn_cast<SILInstruction>(N);
   if (!I)
     return DataflowResult();
 
@@ -191,7 +191,7 @@
 template <class ARCState>
 typename TopDownDataflowRCStateVisitor<ARCState>::DataflowResult
 TopDownDataflowRCStateVisitor<ARCState>::
-visitAutoreleasePoolCall(ValueBase *V) {
+visitAutoreleasePoolCall(SILNode *N) {
   DataflowState.clear();
   // We just cleared our BB State so we have no more possible effects.
   return DataflowResult(RCStateTransitionDataflowResultKind::NoEffects);
@@ -199,8 +199,8 @@
 
 template <class ARCState>
 typename TopDownDataflowRCStateVisitor<ARCState>::DataflowResult
-TopDownDataflowRCStateVisitor<ARCState>::visitStrongDecrement(ValueBase *V) {
-  auto *I = dyn_cast<SILInstruction>(V);
+TopDownDataflowRCStateVisitor<ARCState>::visitStrongDecrement(SILNode *N) {
+  auto *I = dyn_cast<SILInstruction>(N);
   if (!I)
     return DataflowResult();
 
@@ -241,8 +241,8 @@
 
 template <class ARCState>
 typename TopDownDataflowRCStateVisitor<ARCState>::DataflowResult
-TopDownDataflowRCStateVisitor<ARCState>::visitStrongIncrement(ValueBase *V) {
-  auto *I = dyn_cast<SILInstruction>(V);
+TopDownDataflowRCStateVisitor<ARCState>::visitStrongIncrement(SILNode *N) {
+  auto *I = dyn_cast<SILInstruction>(N);
   if (!I)
     return DataflowResult();
 
@@ -340,20 +340,20 @@
 template <class ARCState>
 typename TopDownDataflowRCStateVisitor<ARCState>::DataflowResult
 TopDownDataflowRCStateVisitor<ARCState>::
-visitStrongEntrance(ValueBase *V) {
-  if (auto *Arg = dyn_cast<SILFunctionArgument>(V))
+visitStrongEntrance(SILNode *N) {
+  if (auto *Arg = dyn_cast<SILFunctionArgument>(N))
     return visitStrongEntranceArgument(Arg);
 
-  if (auto *AI = dyn_cast<ApplyInst>(V))
+  if (auto *AI = dyn_cast<ApplyInst>(N))
     return visitStrongEntranceApply(AI);
 
-  if (auto *ARI = dyn_cast<AllocRefInst>(V))
+  if (auto *ARI = dyn_cast<AllocRefInst>(N))
     return visitStrongEntranceAllocRef(ARI);
 
-  if (auto *ARI = dyn_cast<AllocRefDynamicInst>(V))
+  if (auto *ARI = dyn_cast<AllocRefDynamicInst>(N))
     return visitStrongEntranceAllocRefDynamic(ARI);
 
-  if (auto *ABI = dyn_cast<AllocBoxInst>(V))
+  if (auto *ABI = dyn_cast<AllocBoxInst>(N))
     return visitStrongAllocBox(ABI);
 
   return DataflowResult();
diff --git a/lib/SILOptimizer/ARC/RCStateTransitionVisitors.h b/lib/SILOptimizer/ARC/RCStateTransitionVisitors.h
index 9a71d64..f51f518 100644
--- a/lib/SILOptimizer/ARC/RCStateTransitionVisitors.h
+++ b/lib/SILOptimizer/ARC/RCStateTransitionVisitors.h
@@ -38,14 +38,14 @@
   ImplTy &asImpl() { return *reinterpret_cast<ImplTy *>(this); }
 
 public:
-#define KIND(K) ResultTy visit ## K(ValueBase *) { return ResultTy(); }
+#define KIND(K) ResultTy visit ## K(SILNode *) { return ResultTy(); }
 #include "RCStateTransition.def"
 
-  ResultTy visit(ValueBase *V) {
-    switch (getRCStateTransitionKind(V)) {
+  ResultTy visit(SILNode *N) {
+    switch (getRCStateTransitionKind(N)) {
 #define KIND(K)                                 \
   case RCStateTransitionKind::K:                \
-    return asImpl().visit ## K(V);
+    return asImpl().visit ## K(N);
 #include "RCStateTransition.def"
     }
     llvm_unreachable("Covered switch isn't covered?!");
@@ -128,9 +128,9 @@
       ARCState &DataflowState, bool FreezeOwnedArgEpilogueReleases,
       IncToDecStateMapTy &IncToDecStateMap,
       ImmutablePointerSetFactory<SILInstruction> &SetFactory);
-  DataflowResult visitAutoreleasePoolCall(ValueBase *V);
-  DataflowResult visitStrongDecrement(ValueBase *V);
-  DataflowResult visitStrongIncrement(ValueBase *V);
+  DataflowResult visitAutoreleasePoolCall(SILNode *N);
+  DataflowResult visitStrongDecrement(SILNode *N);
+  DataflowResult visitStrongIncrement(SILNode *N);
 };
 
 } // end swift namespace
@@ -163,10 +163,10 @@
       RCIdentityFunctionInfo *RCFI, ARCState &State,
       DecToIncStateMapTy &DecToIncStateMap,
       ImmutablePointerSetFactory<SILInstruction> &SetFactory);
-  DataflowResult visitAutoreleasePoolCall(ValueBase *V);
-  DataflowResult visitStrongDecrement(ValueBase *V);
-  DataflowResult visitStrongIncrement(ValueBase *V);
-  DataflowResult visitStrongEntrance(ValueBase *V);
+  DataflowResult visitAutoreleasePoolCall(SILNode *N);
+  DataflowResult visitStrongDecrement(SILNode *N);
+  DataflowResult visitStrongIncrement(SILNode *N);
+  DataflowResult visitStrongEntrance(SILNode *N);
 
 private:
   DataflowResult visitStrongEntranceApply(ApplyInst *AI);
diff --git a/lib/SILOptimizer/Analysis/ARCAnalysis.cpp b/lib/SILOptimizer/Analysis/ARCAnalysis.cpp
index e48dbb9..2c2feb6 100644
--- a/lib/SILOptimizer/Analysis/ARCAnalysis.cpp
+++ b/lib/SILOptimizer/Analysis/ARCAnalysis.cpp
@@ -116,42 +116,42 @@
 bool swift::canNeverUseValues(SILInstruction *Inst) {
   switch (Inst->getKind()) {
   // These instructions do not use other values.
-  case ValueKind::FunctionRefInst:
-  case ValueKind::IntegerLiteralInst:
-  case ValueKind::FloatLiteralInst:
-  case ValueKind::StringLiteralInst:
-  case ValueKind::AllocStackInst:
-  case ValueKind::AllocRefInst:
-  case ValueKind::AllocRefDynamicInst:
-  case ValueKind::AllocBoxInst:
-  case ValueKind::MetatypeInst:
-  case ValueKind::WitnessMethodInst:
+  case SILInstructionKind::FunctionRefInst:
+  case SILInstructionKind::IntegerLiteralInst:
+  case SILInstructionKind::FloatLiteralInst:
+  case SILInstructionKind::StringLiteralInst:
+  case SILInstructionKind::AllocStackInst:
+  case SILInstructionKind::AllocRefInst:
+  case SILInstructionKind::AllocRefDynamicInst:
+  case SILInstructionKind::AllocBoxInst:
+  case SILInstructionKind::MetatypeInst:
+  case SILInstructionKind::WitnessMethodInst:
     return true;
 
   // DeallocStackInst do not use reference counted values.
-  case ValueKind::DeallocStackInst:
+  case SILInstructionKind::DeallocStackInst:
     return true;
 
   // Debug values do not use referenced counted values in a manner we care
   // about.
-  case ValueKind::DebugValueInst:
-  case ValueKind::DebugValueAddrInst:
+  case SILInstructionKind::DebugValueInst:
+  case SILInstructionKind::DebugValueAddrInst:
     return true;
 
   // Casts do not use pointers in a manner that we care about since we strip
   // them during our analysis. The reason for this is if the cast is not dead
   // then there must be some other use after the cast that we will protect if a
   // release is not in between the cast and the use.
-  case ValueKind::UpcastInst:
-  case ValueKind::AddressToPointerInst:
-  case ValueKind::PointerToAddressInst:
-  case ValueKind::UncheckedRefCastInst:
-  case ValueKind::UncheckedRefCastAddrInst:
-  case ValueKind::UncheckedAddrCastInst:
-  case ValueKind::RefToRawPointerInst:
-  case ValueKind::RawPointerToRefInst:
-  case ValueKind::UnconditionalCheckedCastInst:
-  case ValueKind::UncheckedBitwiseCastInst:
+  case SILInstructionKind::UpcastInst:
+  case SILInstructionKind::AddressToPointerInst:
+  case SILInstructionKind::PointerToAddressInst:
+  case SILInstructionKind::UncheckedRefCastInst:
+  case SILInstructionKind::UncheckedRefCastAddrInst:
+  case SILInstructionKind::UncheckedAddrCastInst:
+  case SILInstructionKind::RefToRawPointerInst:
+  case SILInstructionKind::RawPointerToRefInst:
+  case SILInstructionKind::UnconditionalCheckedCastInst:
+  case SILInstructionKind::UncheckedBitwiseCastInst:
     return true;
 
   // If we have a trivial bit cast between trivial types, it is not something
@@ -165,37 +165,37 @@
   // trivial value though could be used as a trivial value in ways that ARC
   // dataflow will not understand implying we need to treat it as a use to be
   // safe.
-  case ValueKind::UncheckedTrivialBitCastInst: {
+  case SILInstructionKind::UncheckedTrivialBitCastInst: {
     SILValue Op = cast<UncheckedTrivialBitCastInst>(Inst)->getOperand();
     return Op->getType().isTrivial(Inst->getModule());
   }
 
   // Typed GEPs do not use pointers. The user of the typed GEP may but we will
   // catch that via the dataflow.
-  case ValueKind::StructExtractInst:
-  case ValueKind::TupleExtractInst:
-  case ValueKind::StructElementAddrInst:
-  case ValueKind::TupleElementAddrInst:
-  case ValueKind::UncheckedTakeEnumDataAddrInst:
-  case ValueKind::RefElementAddrInst:
-  case ValueKind::RefTailAddrInst:
-  case ValueKind::UncheckedEnumDataInst:
-  case ValueKind::IndexAddrInst:
-  case ValueKind::IndexRawPointerInst:
+  case SILInstructionKind::StructExtractInst:
+  case SILInstructionKind::TupleExtractInst:
+  case SILInstructionKind::StructElementAddrInst:
+  case SILInstructionKind::TupleElementAddrInst:
+  case SILInstructionKind::UncheckedTakeEnumDataAddrInst:
+  case SILInstructionKind::RefElementAddrInst:
+  case SILInstructionKind::RefTailAddrInst:
+  case SILInstructionKind::UncheckedEnumDataInst:
+  case SILInstructionKind::IndexAddrInst:
+  case SILInstructionKind::IndexRawPointerInst:
       return true;
 
   // Aggregate formation by themselves do not create new uses since it is their
   // users that would create the appropriate uses.
-  case ValueKind::EnumInst:
-  case ValueKind::StructInst:
-  case ValueKind::TupleInst:
+  case SILInstructionKind::EnumInst:
+  case SILInstructionKind::StructInst:
+  case SILInstructionKind::TupleInst:
     return true;
 
   // Only uses non reference counted values.
-  case ValueKind::CondFailInst:
+  case SILInstructionKind::CondFailInst:
     return true;
 
-  case ValueKind::BuiltinInst: {
+  case SILInstructionKind::BuiltinInst: {
     auto *BI = cast<BuiltinInst>(Inst);
 
     // Certain builtin function refs we know can never use non-trivial values.
@@ -203,8 +203,8 @@
   }
   // We do not care about branch inst, since if the branch inst's argument is
   // dead, LLVM will clean it up.
-  case ValueKind::BranchInst:
-  case ValueKind::CondBranchInst:
+  case SILInstructionKind::BranchInst:
+  case SILInstructionKind::CondBranchInst:
     return true;
   default:
     return false;
@@ -1116,14 +1116,14 @@
 //===----------------------------------------------------------------------===//
 //             Analysis of builtin "unsafeGuaranteed" instructions
 //===----------------------------------------------------------------------===//
-std::pair<SILInstruction *, SILInstruction *>
+std::pair<SingleValueInstruction *, SingleValueInstruction *>
 swift::getSingleUnsafeGuaranteedValueResult(BuiltinInst *BI) {
   assert(BI->getBuiltinKind() &&
          *BI->getBuiltinKind() == BuiltinValueKind::UnsafeGuaranteed &&
          "Expecting a unsafeGuaranteed builtin");
 
-  SILInstruction *GuaranteedValue = nullptr;
-  SILInstruction *Token = nullptr;
+  SingleValueInstruction *GuaranteedValue = nullptr;
+  SingleValueInstruction *Token = nullptr;
 
   auto Failed = std::make_pair(nullptr, nullptr);
 
@@ -1153,7 +1153,7 @@
   return std::make_pair(GuaranteedValue, Token);
 }
 
-BuiltinInst *swift::getUnsafeGuaranteedEndUser(SILInstruction *UnsafeGuaranteedToken) {
+BuiltinInst *swift::getUnsafeGuaranteedEndUser(SILValue UnsafeGuaranteedToken) {
   BuiltinInst *UnsafeGuaranteedEndI = nullptr;
 
   for (auto *Operand : getNonDebugUses(UnsafeGuaranteedToken)) {
diff --git a/lib/SILOptimizer/Analysis/AccessSummaryAnalysis.cpp b/lib/SILOptimizer/Analysis/AccessSummaryAnalysis.cpp
index 59b00de..bcb328b 100644
--- a/lib/SILOptimizer/Analysis/AccessSummaryAnalysis.cpp
+++ b/lib/SILOptimizer/Analysis/AccessSummaryAnalysis.cpp
@@ -64,7 +64,7 @@
     SILInstruction *user = operand->getUser();
 
     switch (user->getKind()) {
-    case ValueKind::BeginAccessInst: {
+    case SILInstructionKind::BeginAccessInst: {
       auto *BAI = cast<BeginAccessInst>(user);
       const IndexTrieNode *subPath = findSubPathAccessed(BAI);
       summary.mergeWith(BAI->getAccessKind(), BAI->getLoc(), subPath);
@@ -75,31 +75,33 @@
       // elsewhere.
       break;
     }
-    case ValueKind::EndUnpairedAccessInst:
+    case SILInstructionKind::EndUnpairedAccessInst:
       // Don't diagnose unpaired access statically.
       assert(cast<EndUnpairedAccessInst>(user)->getEnforcement() ==
              SILAccessEnforcement::Dynamic);
       break;
-    case ValueKind::StructElementAddrInst:
-    case ValueKind::TupleElementAddrInst:
+    case SILInstructionKind::StructElementAddrInst:
+    case SILInstructionKind::TupleElementAddrInst: {
       // Eventually we'll summarize individual struct elements separately.
       // For now an access to a part of the struct is treated as an access
       // to the whole struct.
-      worklist.append(user->use_begin(), user->use_end());
+      auto inst = cast<SingleValueInstruction>(user);
+      worklist.append(inst->use_begin(), inst->use_end());
       break;
-    case ValueKind::DebugValueAddrInst:
-    case ValueKind::AddressToPointerInst:
+    }
+    case SILInstructionKind::DebugValueAddrInst:
+    case SILInstructionKind::AddressToPointerInst:
       // Ignore these uses, they don't affect formal accesses.
       break;
-    case ValueKind::PartialApplyInst:
+    case SILInstructionKind::PartialApplyInst:
       processPartialApply(info, argumentIndex, cast<PartialApplyInst>(user),
                           operand, order);
       break;
-    case ValueKind::ApplyInst:
+    case SILInstructionKind::ApplyInst:
       processFullApply(info, argumentIndex, cast<ApplyInst>(user), operand,
                        order);
       break;
-    case ValueKind::TryApplyInst:
+    case SILInstructionKind::TryApplyInst:
       processFullApply(info, argumentIndex, cast<TryApplyInst>(user), operand,
                        order);
       break;
@@ -128,19 +130,19 @@
 
   // It is fine to call the partial apply
   switch (user->getKind()) {
-  case ValueKind::ApplyInst:
-  case ValueKind::TryApplyInst:
+  case SILInstructionKind::ApplyInst:
+  case SILInstructionKind::TryApplyInst:
     return true;
 
-  case ValueKind::ConvertFunctionInst:
-    return llvm::all_of(user->getUses(),
+  case SILInstructionKind::ConvertFunctionInst:
+    return llvm::all_of(cast<ConvertFunctionInst>(user)->getUses(),
                         hasExpectedUsesOfNoEscapePartialApply);
 
-  case ValueKind::PartialApplyInst:
+  case SILInstructionKind::PartialApplyInst:
     return partialApplyUse->get() != cast<PartialApplyInst>(user)->getCallee();
 
-  case ValueKind::StoreInst:
-  case ValueKind::DestroyValueInst:
+  case SILInstructionKind::StoreInst:
+  case SILInstructionKind::DestroyValueInst:
     // @block_storage is passed by storing it to the stack. We know this is
     // still nonescaping simply because our original argument convention is
     // @inout_aliasable. In this SIL, both store and destroy_value are users
@@ -432,9 +434,9 @@
 /// user return a pair of the single user and the projection index.
 /// Otherwise, return a pair with the component nullptr and the second
 /// unspecified.
-static std::pair<SILInstruction *, unsigned>
-getSingleAddressProjectionUser(SILInstruction *I) {
-  SILInstruction *SingleUser = nullptr;
+static std::pair<SingleValueInstruction *, unsigned>
+getSingleAddressProjectionUser(SingleValueInstruction *I) {
+  SingleValueInstruction *SingleUser = nullptr;
   unsigned ProjectionIndex = 0;
 
   for (Operand *Use : I->getUses()) {
@@ -447,14 +449,18 @@
       return std::make_pair(nullptr, 0);
 
     switch (User->getKind()) {
-    case ValueKind::StructElementAddrInst:
-      ProjectionIndex = cast<StructElementAddrInst>(User)->getFieldNo();
-      SingleUser = User;
+    case SILInstructionKind::StructElementAddrInst: {
+      auto inst = cast<StructElementAddrInst>(User);
+      ProjectionIndex = inst->getFieldNo();
+      SingleUser = inst;
       break;
-    case ValueKind::TupleElementAddrInst:
-      ProjectionIndex = cast<TupleElementAddrInst>(User)->getFieldNo();
-      SingleUser = User;
+    }
+    case SILInstructionKind::TupleElementAddrInst: {
+      auto inst = cast<TupleElementAddrInst>(User);
+      ProjectionIndex = inst->getFieldNo();
+      SingleUser = inst;
       break;
+    }
     default:
       return std::make_pair(nullptr, 0);
     }
@@ -470,9 +476,9 @@
   // For each single-user projection of BAI, construct or get a node
   // from the trie representing the index of the field or tuple element
   // accessed by that projection.
-  SILInstruction *Iter = BAI;
+  SingleValueInstruction *Iter = BAI;
   while (true) {
-    std::pair<SILInstruction *, unsigned> ProjectionUser =
+    std::pair<SingleValueInstruction *, unsigned> ProjectionUser =
         getSingleAddressProjectionUser(Iter);
     if (!ProjectionUser.first)
       break;
diff --git a/lib/SILOptimizer/Analysis/AliasAnalysis.cpp b/lib/SILOptimizer/Analysis/AliasAnalysis.cpp
index 3cb3435..5b2d77f 100644
--- a/lib/SILOptimizer/Analysis/AliasAnalysis.cpp
+++ b/lib/SILOptimizer/Analysis/AliasAnalysis.cpp
@@ -302,18 +302,18 @@
 /// TBAA to know what the real types associated with the SILInstruction are.
 static bool isTypedAccessOracle(SILInstruction *I) {
   switch (I->getKind()) {
-  case ValueKind::RefElementAddrInst:
-  case ValueKind::RefTailAddrInst:
-  case ValueKind::StructElementAddrInst:
-  case ValueKind::TupleElementAddrInst:
-  case ValueKind::UncheckedTakeEnumDataAddrInst:
-  case ValueKind::LoadInst:
-  case ValueKind::StoreInst:
-  case ValueKind::AllocStackInst:
-  case ValueKind::AllocBoxInst:
-  case ValueKind::ProjectBoxInst:
-  case ValueKind::DeallocStackInst:
-  case ValueKind::DeallocBoxInst:
+  case SILInstructionKind::RefElementAddrInst:
+  case SILInstructionKind::RefTailAddrInst:
+  case SILInstructionKind::StructElementAddrInst:
+  case SILInstructionKind::TupleElementAddrInst:
+  case SILInstructionKind::UncheckedTakeEnumDataAddrInst:
+  case SILInstructionKind::LoadInst:
+  case SILInstructionKind::StoreInst:
+  case SILInstructionKind::AllocStackInst:
+  case SILInstructionKind::AllocBoxInst:
+  case SILInstructionKind::ProjectBoxInst:
+  case SILInstructionKind::DeallocStackInst:
+  case SILInstructionKind::DeallocBoxInst:
     return true;
   default:
     return false;
@@ -352,7 +352,8 @@
 static SILType findTypedAccessType(SILValue V) {
   // First look at the origin of V and see if we have any instruction that is a
   // typed oracle.
-  if (auto *I = dyn_cast<SILInstruction>(V))
+  // TODO: MultiValueInstruction
+  if (auto *I = dyn_cast<SingleValueInstruction>(V))
     if (isTypedAccessOracle(I))
       return V->getType();
 
diff --git a/lib/SILOptimizer/Analysis/ArraySemantic.cpp b/lib/SILOptimizer/Analysis/ArraySemantic.cpp
index 85a4e09..24cc25a 100644
--- a/lib/SILOptimizer/Analysis/ArraySemantic.cpp
+++ b/lib/SILOptimizer/Analysis/ArraySemantic.cpp
@@ -112,27 +112,52 @@
 }
 
 /// Match array semantic calls.
-swift::ArraySemanticsCall::ArraySemanticsCall(ValueBase *V,
-                                              StringRef SemanticStr,
-                                              bool MatchPartialName) {
-  if (auto *AI = dyn_cast<ApplyInst>(V))
-    if (auto *Fn = AI->getReferencedFunction())
-      if ((MatchPartialName &&
-           Fn->hasSemanticsAttrThatStartsWith(SemanticStr)) ||
-          (!MatchPartialName && Fn->hasSemanticsAttr(SemanticStr))) {
-        SemanticsCall = AI;
-        // Need a 'self' argument otherwise this is not a semantic call that
-        // we recognize.
-        if (getKind() < ArrayCallKind::kArrayInit && !hasSelf())
-          SemanticsCall = nullptr;
+swift::ArraySemanticsCall::ArraySemanticsCall(SILValue V,
+                                              StringRef semanticName,
+                                              bool matchPartialName)
+    : SemanticsCall(nullptr) {
+  if (auto AI = dyn_cast<ApplyInst>(V))
+    initialize(AI, semanticName, matchPartialName);
+}
 
-        // A arguments must be passed reference count neutral except for self.
-        if (SemanticsCall && !isValidSignature())
-          SemanticsCall = nullptr;
-        return;
-      }
-  // Otherwise, this is not the semantic call we are looking for.
-  SemanticsCall = nullptr;
+/// Match array semantic calls.
+swift::ArraySemanticsCall::ArraySemanticsCall(SILInstruction *I,
+                                              StringRef semanticName,
+                                              bool matchPartialName)
+    : SemanticsCall(nullptr) {
+  if (auto AI = dyn_cast<ApplyInst>(I))
+    initialize(AI, semanticName, matchPartialName);
+}
+
+/// Match array semantic calls.
+swift::ArraySemanticsCall::ArraySemanticsCall(ApplyInst *AI,
+                                              StringRef semanticName,
+                                              bool matchPartialName)
+    : SemanticsCall(nullptr) {
+  initialize(AI, semanticName, matchPartialName);
+}
+
+void ArraySemanticsCall::initialize(ApplyInst *AI, StringRef semanticName,
+                                    bool matchPartialName) {
+  auto *fn = AI->getReferencedFunction();
+  if (!fn)
+    return;
+
+  if (!(matchPartialName
+          ? fn->hasSemanticsAttrThatStartsWith(semanticName)
+          : fn->hasSemanticsAttr(semanticName)))
+    return;
+
+  SemanticsCall = AI;
+
+  // Need a 'self' argument otherwise this is not a semantic call that
+  // we recognize.
+  if (getKind() < ArrayCallKind::kArrayInit && !hasSelf())
+    SemanticsCall = nullptr;
+
+  // A arguments must be passed reference count neutral except for self.
+  if (SemanticsCall && !isValidSignature())
+    SemanticsCall = nullptr;
 }
 
 /// Determine which kind of array semantics call this is.
@@ -347,7 +372,7 @@
     InsertPt = Inst;
   }
 
-  return LI->clone(InsertBefore);
+  return cast<LoadInst>(LI->clone(InsertBefore));
 }
 
 static ApplyInst *hoistOrCopyCall(ApplyInst *AI, SILInstruction *InsertBefore,
diff --git a/lib/SILOptimizer/Analysis/EscapeAnalysis.cpp b/lib/SILOptimizer/Analysis/EscapeAnalysis.cpp
index 417678f..8aca566 100644
--- a/lib/SILOptimizer/Analysis/EscapeAnalysis.cpp
+++ b/lib/SILOptimizer/Analysis/EscapeAnalysis.cpp
@@ -24,60 +24,70 @@
 
 using namespace swift;
 
-static bool isProjection(ValueBase *V) {
-  switch (V->getKind()) {
-    case ValueKind::IndexAddrInst:
-    case ValueKind::IndexRawPointerInst:
-    case ValueKind::StructElementAddrInst:
-    case ValueKind::TupleElementAddrInst:
-    case ValueKind::UncheckedTakeEnumDataAddrInst:
-    case ValueKind::StructExtractInst:
-    case ValueKind::UncheckedEnumDataInst:
-    case ValueKind::MarkDependenceInst:
-    case ValueKind::PointerToAddressInst:
-    case ValueKind::AddressToPointerInst:
-    case ValueKind::InitEnumDataAddrInst:
-      return true;
-    case ValueKind::TupleExtractInst: {
-      auto *TEI = cast<TupleExtractInst>(V);
-      // Special handling for extracting the pointer-result from an
-      // array construction. We handle this like a ref_element_addr
-      // rather than a projection. See the handling of tuple_extract
-      // in analyzeInstruction().
-      if (TEI->getFieldNo() == 1 &&
-          ArraySemanticsCall(TEI->getOperand(), "array.uninitialized", false))
-        return false;
-      return true;
-    }
-    default:
-      return false;
+static bool isExtractOfArrayUninitializedPointer(TupleExtractInst *TEI) {
+  if (TEI->getFieldNo() == 1) {
+    if (auto apply = dyn_cast<ApplyInst>(TEI->getOperand()))
+      if (ArraySemanticsCall(apply, "array.uninitialized", false))
+        return true;
+  }
+  return false;
+}
+
+static SingleValueInstruction *isProjection(SILNode *node) {
+  switch (node->getKind()) {
+  case SILNodeKind::IndexAddrInst:
+  case SILNodeKind::IndexRawPointerInst:
+  case SILNodeKind::StructElementAddrInst:
+  case SILNodeKind::TupleElementAddrInst:
+  case SILNodeKind::UncheckedTakeEnumDataAddrInst:
+  case SILNodeKind::StructExtractInst:
+  case SILNodeKind::UncheckedEnumDataInst:
+  case SILNodeKind::MarkDependenceInst:
+  case SILNodeKind::PointerToAddressInst:
+  case SILNodeKind::AddressToPointerInst:
+  case SILNodeKind::InitEnumDataAddrInst:
+    return cast<SingleValueInstruction>(node);
+  case SILNodeKind::TupleExtractInst: {
+    auto *TEI = cast<TupleExtractInst>(node);
+    // Special handling for extracting the pointer-result from an
+    // array construction. We handle this like a ref_element_addr
+    // rather than a projection. See the handling of tuple_extract
+    // in analyzeInstruction().
+    if (isExtractOfArrayUninitializedPointer(TEI))
+      return nullptr;
+    return TEI;
+  }
+  default:
+    return nullptr;
   }
 }
 
-static bool isNonWritableMemoryAddress(ValueBase *V) {
+static bool isNonWritableMemoryAddress(SILNode *V) {
   switch (V->getKind()) {
-    case ValueKind::FunctionRefInst:
-    case ValueKind::WitnessMethodInst:
-    case ValueKind::ClassMethodInst:
-    case ValueKind::SuperMethodInst:
-    case ValueKind::DynamicMethodInst:
-    case ValueKind::StringLiteralInst:
-    case ValueKind::ThinToThickFunctionInst:
-    case ValueKind::ThinFunctionToPointerInst:
-    case ValueKind::PointerToThinFunctionInst:
-      // These instructions return pointers to memory which can't be a
-      // destination of a store.
-      return true;
-    default:
-      return false;
+  case SILNodeKind::FunctionRefInst:
+  case SILNodeKind::WitnessMethodInst:
+  case SILNodeKind::ClassMethodInst:
+  case SILNodeKind::SuperMethodInst:
+  case SILNodeKind::DynamicMethodInst:
+  case SILNodeKind::StringLiteralInst:
+  case SILNodeKind::ThinToThickFunctionInst:
+  case SILNodeKind::ThinFunctionToPointerInst:
+  case SILNodeKind::PointerToThinFunctionInst:
+    // These instructions return pointers to memory which can't be a
+    // destination of a store.
+    return true;
+  default:
+    return false;
   }
 }
 
 static ValueBase *skipProjections(ValueBase *V) {
   for (;;) {
-    if (!isProjection(V))
+    if (auto SVI = isProjection(V)) {
+      V = SVI->getOperand(0);
+    } else {
       return V;
-    V = cast<SILInstruction>(V)->getOperand(0);
+    }
   }
   llvm_unreachable("there is no escape from an infinite loop");
 }
@@ -97,9 +107,6 @@
   if (isa<FunctionRefInst>(V))
     return nullptr;
   
-  if (!V->hasValue())
-    return nullptr;
-  
   if (!EA->isPointer(V))
     return nullptr;
   
@@ -394,11 +401,11 @@
 
     for (auto &I : BB) {
       switch (I.getKind()) {
-        case ValueKind::StrongReleaseInst:
-        case ValueKind::ReleaseValueInst:
-        case ValueKind::UnownedReleaseInst:
-        case ValueKind::ApplyInst:
-        case ValueKind::TryApplyInst: {
+        case SILInstructionKind::StrongReleaseInst:
+        case SILInstructionKind::ReleaseValueInst:
+        case SILInstructionKind::UnownedReleaseInst:
+        case SILInstructionKind::ApplyInst:
+        case SILInstructionKind::TryApplyInst: {
           /// Actually we only add instructions which may release a reference.
           /// We need the use points only for getting the end of a reference's
           /// liferange. And that must be a releasing instruction.
@@ -536,10 +543,12 @@
 /// somehow refer to the Node's value.
 /// Use-points are only values which are relevant for lifeness computation,
 /// e.g. release or apply instructions.
-bool EscapeAnalysis::ConnectionGraph::isUsePoint(ValueBase *V, CGNode *Node) {
+bool EscapeAnalysis::ConnectionGraph::isUsePoint(SILNode *UsePoint,
+                                                 CGNode *Node) {
   assert(Node->getEscapeState() < EscapeState::Global &&
          "Use points are only valid for non-escaping nodes");
-  auto Iter = UsePoints.find(V);
+  UsePoint = UsePoint->getCanonicalSILNodeInObject();
+  auto Iter = UsePoints.find(UsePoint);
   if (Iter == UsePoints.end())
     return false;
   int Idx = Iter->second;
@@ -549,7 +558,7 @@
 }
 
 void EscapeAnalysis::ConnectionGraph::
-getUsePoints(CGNode *Node, llvm::SmallVectorImpl<ValueBase *> &UsePoints) {
+getUsePoints(CGNode *Node, llvm::SmallVectorImpl<SILNode *> &UsePoints) {
   assert(Node->getEscapeState() < EscapeState::Global &&
          "Use points are only valid for non-escaping nodes");
   for (int Idx = Node->UsePoints.find_first(); Idx >= 0;
@@ -620,7 +629,7 @@
   const EscapeAnalysis::ConnectionGraph *OrigGraph;
 
   // The same IDs as the SILPrinter uses.
-  llvm::DenseMap<const ValueBase *, unsigned> InstToIDMap;
+  llvm::DenseMap<const SILNode *, unsigned> InstToIDMap;
 
   typedef std::vector<Node>::iterator iterator;
   typedef SmallVectorImpl<Node *>::iterator child_iterator;
@@ -846,7 +855,7 @@
   OS << "CG of " << F->getName() << '\n';
 
   // Assign the same IDs to SILValues as the SILPrinter does.
-  llvm::DenseMap<const ValueBase *, unsigned> InstToIDMap;
+  llvm::DenseMap<const SILNode *, unsigned> InstToIDMap;
   InstToIDMap[nullptr] = (unsigned)-1;
   F->numberValues(InstToIDMap);
 
@@ -897,8 +906,8 @@
         const char *Separator = "";
         for (unsigned VIdx = Nd->UsePoints.find_first(); VIdx != -1u;
              VIdx = Nd->UsePoints.find_next(VIdx)) {
-          ValueBase *V = UsePointTable[VIdx];
-          OS << Separator << '%' << InstToIDMap[V];
+          auto node = UsePointTable[VIdx];
+          OS << Separator << '%' << InstToIDMap[node];
           Separator = ",";
         }
         break;
@@ -1039,7 +1048,6 @@
 }
 
 bool EscapeAnalysis::isPointer(ValueBase *V) {
-  assert(V->hasValue());
   SILType Ty = V->getType();
   auto Iter = isPointerCache.find(Ty);
   if (Iter != isPointerCache.end())
@@ -1119,8 +1127,8 @@
 }
 
 /// Returns true if all uses of \p I are tuple_extract instructions.
-static bool onlyUsedInTupleExtract(SILInstruction *I) {
-  for (Operand *Use : getNonDebugUses(I)) {
+static bool onlyUsedInTupleExtract(SILValue V) {
+  for (Operand *Use : getNonDebugUses(V)) {
     if (!isa<TupleExtractInst>(Use->getUser()))
       return false;
   }
@@ -1203,12 +1211,12 @@
       case ArrayCallKind::kArrayUninitialized:
         // Check if the result is used in the usual way: extracting the
         // array and the element pointer with tuple_extract.
-        if (onlyUsedInTupleExtract(I)) {
+        if (onlyUsedInTupleExtract(ASC.getCallResult())) {
           // array.uninitialized may have a first argument which is the
           // allocated array buffer. The call is like a struct(buffer)
           // instruction.
           if (CGNode *BufferNode = ConGraph->getNode(FAS.getArgument(0), this)) {
-            CGNode *ArrayNode = ConGraph->getNode(I, this);
+            CGNode *ArrayNode = ConGraph->getNode(ASC.getCallResult(), this);
             CGNode *ArrayContent = ConGraph->getContentNode(ArrayNode);
             ConGraph->defer(ArrayContent, BufferNode);
           }
@@ -1217,7 +1225,8 @@
         break;
       case ArrayCallKind::kGetArrayOwner:
         if (CGNode *BufferNode = ConGraph->getNode(ASC.getSelf(), this)) {
-          ConGraph->defer(ConGraph->getNode(I, this), BufferNode);
+          ConGraph->defer(ConGraph->getNode(ASC.getCallResult(), this),
+                          BufferNode);
         }
         return;
       case ArrayCallKind::kGetElement:
@@ -1225,7 +1234,7 @@
           CGNode *DestNode = nullptr;
           // This is like a load from a ref_element_addr.
           if (ASC.hasGetElementDirectResult()) {
-            DestNode = ConGraph->getNode(FAS.getInstruction(), this);
+            DestNode = ConGraph->getNode(ASC.getCallResult(), this);
           } else {
             CGNode *DestAddrNode = ConGraph->getNode(FAS.getArgument(0), this);
             assert(DestAddrNode && "indirect result must have node");
@@ -1246,7 +1255,7 @@
       case ArrayCallKind::kGetElementAddress:
         // This is like a ref_element_addr.
         if (CGNode *SelfNode = ConGraph->getNode(ASC.getSelf(), this)) {
-          ConGraph->defer(ConGraph->getNode(I, this),
+          ConGraph->defer(ConGraph->getNode(ASC.getCallResult(), this),
                           ConGraph->getContentNode(SelfNode));
         }
         return;
@@ -1338,35 +1347,35 @@
     return;
 
   switch (I->getKind()) {
-    case ValueKind::AllocStackInst:
-    case ValueKind::AllocRefInst:
-    case ValueKind::AllocBoxInst:
-      ConGraph->getNode(I, this);
+    case SILInstructionKind::AllocStackInst:
+    case SILInstructionKind::AllocRefInst:
+    case SILInstructionKind::AllocBoxInst:
+      ConGraph->getNode(cast<SingleValueInstruction>(I), this);
       return;
 
-    case ValueKind::DeallocStackInst:
-    case ValueKind::StrongRetainInst:
-    case ValueKind::StrongRetainUnownedInst:
-    case ValueKind::RetainValueInst:
-    case ValueKind::UnownedRetainInst:
-    case ValueKind::BranchInst:
-    case ValueKind::CondBranchInst:
-    case ValueKind::SwitchEnumInst:
-    case ValueKind::DebugValueInst:
-    case ValueKind::DebugValueAddrInst:
-    case ValueKind::ValueMetatypeInst:
-    case ValueKind::InitExistentialMetatypeInst:
-    case ValueKind::OpenExistentialMetatypeInst:
-    case ValueKind::ExistentialMetatypeInst:
-    case ValueKind::DeallocRefInst:
-    case ValueKind::SetDeallocatingInst:
-    case ValueKind::FixLifetimeInst:
+    case SILInstructionKind::DeallocStackInst:
+    case SILInstructionKind::StrongRetainInst:
+    case SILInstructionKind::StrongRetainUnownedInst:
+    case SILInstructionKind::RetainValueInst:
+    case SILInstructionKind::UnownedRetainInst:
+    case SILInstructionKind::BranchInst:
+    case SILInstructionKind::CondBranchInst:
+    case SILInstructionKind::SwitchEnumInst:
+    case SILInstructionKind::DebugValueInst:
+    case SILInstructionKind::DebugValueAddrInst:
+    case SILInstructionKind::ValueMetatypeInst:
+    case SILInstructionKind::InitExistentialMetatypeInst:
+    case SILInstructionKind::OpenExistentialMetatypeInst:
+    case SILInstructionKind::ExistentialMetatypeInst:
+    case SILInstructionKind::DeallocRefInst:
+    case SILInstructionKind::SetDeallocatingInst:
+    case SILInstructionKind::FixLifetimeInst:
       // These instructions don't have any effect on escaping.
       return;
-    case ValueKind::StrongReleaseInst:
-    case ValueKind::ReleaseValueInst:
-    case ValueKind::StrongUnpinInst:
-    case ValueKind::UnownedReleaseInst: {
+    case SILInstructionKind::StrongReleaseInst:
+    case SILInstructionKind::ReleaseValueInst:
+    case SILInstructionKind::StrongUnpinInst:
+    case SILInstructionKind::UnownedReleaseInst: {
       SILValue OpV = I->getOperand(0);
       if (CGNode *AddrNode = ConGraph->getNode(OpV, this)) {
         // A release instruction may deallocate the pointer operand. This may
@@ -1382,29 +1391,31 @@
       }
       return;
     }
-    case ValueKind::LoadInst:
-    case ValueKind::LoadWeakInst:
+    case SILInstructionKind::LoadInst:
+    case SILInstructionKind::LoadWeakInst:
     // We treat ref_element_addr like a load (see NodeType::Content).
-    case ValueKind::RefElementAddrInst:
-    case ValueKind::RefTailAddrInst:
-    case ValueKind::ProjectBoxInst:
-    case ValueKind::InitExistentialAddrInst:
-    case ValueKind::OpenExistentialAddrInst:
-      if (isPointer(I)) {
-        CGNode *AddrNode = ConGraph->getNode(I->getOperand(0), this);
+    case SILInstructionKind::RefElementAddrInst:
+    case SILInstructionKind::RefTailAddrInst:
+    case SILInstructionKind::ProjectBoxInst:
+    case SILInstructionKind::InitExistentialAddrInst:
+    case SILInstructionKind::OpenExistentialAddrInst: {
+      auto SVI = cast<SingleValueInstruction>(I);
+      if (isPointer(SVI)) {
+        CGNode *AddrNode = ConGraph->getNode(SVI->getOperand(0), this);
         if (!AddrNode) {
           // A load from an address we don't handle -> be conservative.
-          CGNode *ValueNode = ConGraph->getNode(I, this);
+          CGNode *ValueNode = ConGraph->getNode(SVI, this);
           ConGraph->setEscapesGlobal(ValueNode);
           return;
         }
         CGNode *PointsTo = ConGraph->getContentNode(AddrNode);
         // No need for a separate node for the load instruction:
         // just reuse the content node.
-        ConGraph->setNode(I, PointsTo);
+        ConGraph->setNode(SVI, PointsTo);
       }
       return;
-    case ValueKind::CopyAddrInst: {
+    }
+    case SILInstructionKind::CopyAddrInst: {
       // Be conservative if the dest may be the final release.
       if (!cast<CopyAddrInst>(I)->isInitializationOfDest()) {
         setAllEscaping(I, ConGraph);
@@ -1433,8 +1444,8 @@
       return;
     }
     break;
-    case ValueKind::StoreInst:
-    case ValueKind::StoreWeakInst:
+    case SILInstructionKind::StoreInst:
+    case SILInstructionKind::StoreWeakInst:
       if (CGNode *ValueNode = ConGraph->getNode(I->getOperand(StoreInst::Src),
                                                 this)) {
         CGNode *AddrNode = ConGraph->getNode(I->getOperand(StoreInst::Dest),
@@ -1449,40 +1460,42 @@
         }
       }
       return;
-    case ValueKind::PartialApplyInst: {
+    case SILInstructionKind::PartialApplyInst: {
       // The result of a partial_apply is a thick function which stores the
       // boxed partial applied arguments. We create defer-edges from the
       // partial_apply values to the arguments.
-      CGNode *ResultNode = ConGraph->getNode(I, this);
+      auto PAI = cast<PartialApplyInst>(I);
+      CGNode *ResultNode = ConGraph->getNode(PAI, this);
       assert(ResultNode && "thick functions must have a CG node");
-      for (const Operand &Op : I->getAllOperands()) {
+      for (const Operand &Op : PAI->getAllOperands()) {
         if (CGNode *ArgNode = ConGraph->getNode(Op.get(), this)) {
           ResultNode = ConGraph->defer(ResultNode, ArgNode);
         }
       }
       return;
     }
-    case ValueKind::SelectEnumInst:
-    case ValueKind::SelectEnumAddrInst:
+    case SILInstructionKind::SelectEnumInst:
+    case SILInstructionKind::SelectEnumAddrInst:
       analyzeSelectInst(cast<SelectEnumInstBase>(I), ConGraph);
       return;
-    case ValueKind::SelectValueInst:
+    case SILInstructionKind::SelectValueInst:
       analyzeSelectInst(cast<SelectValueInst>(I), ConGraph);
       return;
-    case ValueKind::StructInst:
-    case ValueKind::TupleInst:
-    case ValueKind::EnumInst: {
+    case SILInstructionKind::StructInst:
+    case SILInstructionKind::TupleInst:
+    case SILInstructionKind::EnumInst: {
       // Aggregate composition is like assigning the aggregate fields to the
       // resulting aggregate value.
+      auto SVI = cast<SingleValueInstruction>(I);
       CGNode *ResultNode = nullptr;
-      for (const Operand &Op : I->getAllOperands()) {
+      for (const Operand &Op : SVI->getAllOperands()) {
         if (CGNode *FieldNode = ConGraph->getNode(Op.get(), this)) {
           if (!ResultNode) {
             // A small optimization to reduce the graph size: we re-use the
             // first field node as result node.
-            ConGraph->setNode(I, FieldNode);
+            ConGraph->setNode(SVI, FieldNode);
             ResultNode = FieldNode;
-            assert(isPointer(I));
+            assert(isPointer(SVI));
           } else {
             ResultNode = ConGraph->defer(ResultNode, FieldNode);
           }
@@ -1490,41 +1503,40 @@
       }
       return;
     }
-    case ValueKind::TupleExtractInst: {
+    case SILInstructionKind::TupleExtractInst: {
       // This is a tuple_extract which extracts the second result of an
       // array.uninitialized call. The first result is the array itself.
       // The second result (which is a pointer to the array elements) must be
       // the content node of the first result. It's just like a ref_element_addr
       // instruction.
       auto *TEI = cast<TupleExtractInst>(I);
-      assert(TEI->getFieldNo() == 1 &&
-          ArraySemanticsCall(TEI->getOperand(), "array.uninitialized", false)
+      assert(isExtractOfArrayUninitializedPointer(TEI)
              && "tuple_extract should be handled as projection");
       CGNode *ArrayNode = ConGraph->getNode(TEI->getOperand(), this);
       CGNode *ArrayElements = ConGraph->getContentNode(ArrayNode);
-      ConGraph->setNode(I, ArrayElements);
+      ConGraph->setNode(TEI, ArrayElements);
       return;
     }
-    case ValueKind::UncheckedRefCastInst:
-    case ValueKind::ConvertFunctionInst:
-    case ValueKind::UpcastInst:
-    case ValueKind::InitExistentialRefInst:
-    case ValueKind::OpenExistentialRefInst:
-    case ValueKind::UnownedToRefInst:
-    case ValueKind::RefToUnownedInst:
-    case ValueKind::RawPointerToRefInst:
-    case ValueKind::RefToRawPointerInst:
-    case ValueKind::RefToBridgeObjectInst:
-    case ValueKind::BridgeObjectToRefInst:
-    case ValueKind::UncheckedAddrCastInst:
-    case ValueKind::UnconditionalCheckedCastInst:
-    case ValueKind::StrongPinInst:
+    case SILInstructionKind::UncheckedRefCastInst:
+    case SILInstructionKind::ConvertFunctionInst:
+    case SILInstructionKind::UpcastInst:
+    case SILInstructionKind::InitExistentialRefInst:
+    case SILInstructionKind::OpenExistentialRefInst:
+    case SILInstructionKind::UnownedToRefInst:
+    case SILInstructionKind::RefToUnownedInst:
+    case SILInstructionKind::RawPointerToRefInst:
+    case SILInstructionKind::RefToRawPointerInst:
+    case SILInstructionKind::RefToBridgeObjectInst:
+    case SILInstructionKind::BridgeObjectToRefInst:
+    case SILInstructionKind::UncheckedAddrCastInst:
+    case SILInstructionKind::UnconditionalCheckedCastInst:
+    case SILInstructionKind::StrongPinInst:
       // A cast is almost like a projection.
       if (CGNode *OpNode = ConGraph->getNode(I->getOperand(0), this)) {
-        ConGraph->setNode(I, OpNode);
+        ConGraph->setNode(cast<SingleValueInstruction>(I), OpNode);
       }
       break;
-    case ValueKind::UncheckedRefCastAddrInst: {
+    case SILInstructionKind::UncheckedRefCastAddrInst: {
       auto *URCAI = cast<UncheckedRefCastAddrInst>(I);
       CGNode *SrcNode = ConGraph->getNode(URCAI->getSrc(), this);
       CGNode *DestNode = ConGraph->getNode(URCAI->getDest(), this);
@@ -1532,7 +1544,7 @@
       ConGraph->defer(DestNode, SrcNode);
       return;
     }
-    case ValueKind::ReturnInst:
+    case SILInstructionKind::ReturnInst:
       if (CGNode *ValueNd = ConGraph->getNode(cast<ReturnInst>(I)->getOperand(),
                                               this)) {
         ConGraph->defer(ConGraph->getReturnNode(), ValueNd);
@@ -1586,8 +1598,8 @@
       }
       return true;
     }
-    if (isProjection(V)) {
-      V = dyn_cast<SILInstruction>(V)->getOperand(0);
+    if (auto SVI = isProjection(V)) {
+      V = SVI->getOperand(0);
       continue;
     }
     return false;
@@ -1611,7 +1623,8 @@
   }
   // Even if the instruction does not write memory it could e.g. return the
   // address of global memory. Therefore we have to define it as escaping.
-  setEscapesGlobal(ConGraph, I);
+  for (auto result : I->getResults())
+    setEscapesGlobal(ConGraph, result);
 }
 
 void EscapeAnalysis::recompute(FunctionInfo *Initial) {
@@ -1744,11 +1757,14 @@
 
   // Map the return value.
   if (CGNode *RetNd = CalleeGraph->getReturnNodeOrNull()) {
+    // The non-ApplySite instructions that cause calls are to things like
+    // destructors that don't have return values.
+    assert(FAS);
     ValueBase *CallerReturnVal = nullptr;
     if (auto *TAI = dyn_cast<TryApplyInst>(AS)) {
       CallerReturnVal = TAI->getNormalBB()->getArgument(0);
     } else {
-      CallerReturnVal = AS;
+      CallerReturnVal = cast<ApplyInst>(AS);
     }
     CGNode *CallerRetNd = CallerGraph->getNode(CallerReturnVal, this);
     Callee2CallerMapping.add(RetNd, CallerRetNd);
@@ -1773,7 +1789,7 @@
   return SummaryGraph->mergeFrom(Graph, Mapping);
 }
 
-bool EscapeAnalysis::canEscapeToUsePoint(SILValue V, ValueBase *UsePoint,
+bool EscapeAnalysis::canEscapeToUsePoint(SILValue V, SILNode *UsePoint,
                                          ConnectionGraph *ConGraph) {
 
   assert((FullApplySite::isa(UsePoint) || isa<RefCountingInst>(UsePoint)) &&
@@ -1980,13 +1996,16 @@
   }
 }
 
-void EscapeAnalysis::handleDeleteNotification(ValueBase *I) {
-  if (SILBasicBlock *Parent = I->getParentBlock()) {
+void EscapeAnalysis::handleDeleteNotification(SILNode *node) {
+  auto value = dyn_cast<ValueBase>(node);
+  if (!value) return;
+
+  if (SILBasicBlock *Parent = node->getParentBlock()) {
     SILFunction *F = Parent->getParent();
     if (FunctionInfo *FInfo = Function2Info.lookup(F)) {
       if (FInfo->isValid()) {
-        FInfo->Graph.removeFromGraph(I);
-        FInfo->SummaryGraph.removeFromGraph(I);
+        FInfo->Graph.removeFromGraph(value);
+        FInfo->SummaryGraph.removeFromGraph(value);
       }
     }
   }
diff --git a/lib/SILOptimizer/Analysis/IVAnalysis.cpp b/lib/SILOptimizer/Analysis/IVAnalysis.cpp
index 5a8dfe3..7033efe 100644
--- a/lib/SILOptimizer/Analysis/IVAnalysis.cpp
+++ b/lib/SILOptimizer/Analysis/IVAnalysis.cpp
@@ -19,8 +19,13 @@
 using namespace swift::PatternMatch;
 
 #if !defined(NDEBUG)
-static bool inSCC(ValueBase *Value, IVInfo::SCCType &SCC) {
-  return std::find(SCC.begin(), SCC.end(), Value) != SCC.end();
+static bool inSCC(ValueBase *value, IVInfo::SCCType &SCC) {
+  SILNode *valueNode = value->getCanonicalSILNodeInObject();
+  for (SILNode *node : SCC) {
+    if (node->getCanonicalSILNodeInObject() == valueNode)
+      return true;
+  }
+  return false;
 }
 #endif
 
@@ -48,9 +53,11 @@
       continue;
     }
 
+    // TODO: MultiValueInstruction
+
     auto *I = cast<SILInstruction>(SCC[i]);
     switch (I->getKind()) {
-    case ValueKind::BuiltinInst: {
+    case SILInstructionKind::BuiltinInst: {
       if (FoundBuiltin)
         return nullptr;
 
@@ -69,7 +76,7 @@
       break;
     }
 
-    case ValueKind::TupleExtractInst: {
+    case SILInstructionKind::TupleExtractInst: {
       assert(inSCC(cast<TupleExtractInst>(I)->getOperand(), SCC) &&
              "TupleExtract operand not an induction var");
       break;
@@ -93,6 +100,8 @@
   if (!(IV = isInductionSequence(SCC)))
     return;
 
-  for (auto V : SCC)
-    InductionVariableMap[V] = IV;
+  for (auto node : SCC) {
+    if (auto value = dyn_cast<ValueBase>(node))
+      InductionVariableMap[value] = IV;
+  }
 }
diff --git a/lib/SILOptimizer/Analysis/MemoryBehavior.cpp b/lib/SILOptimizer/Analysis/MemoryBehavior.cpp
index c8ca544..c3beacf 100644
--- a/lib/SILOptimizer/Analysis/MemoryBehavior.cpp
+++ b/lib/SILOptimizer/Analysis/MemoryBehavior.cpp
@@ -322,8 +322,7 @@
 MemBehavior
 AliasAnalysis::computeMemoryBehavior(SILInstruction *Inst, SILValue V,
                                      RetainObserveKind InspectionMode) {
-  MemBehaviorKeyTy Key = toMemoryBehaviorKey(SILValue(Inst), V,
-                                             InspectionMode);
+  MemBehaviorKeyTy Key = toMemoryBehaviorKey(Inst, V, InspectionMode);
   // Check if we've already computed this result.
   auto It = MemoryBehaviorCache.find(Key);
   if (It != MemoryBehaviorCache.end()) {
@@ -333,10 +332,10 @@
   // Flush the cache if the size of the cache is too large.
   if (MemoryBehaviorCache.size() > MemoryBehaviorAnalysisMaxCacheSize) {
     MemoryBehaviorCache.clear();
-    MemoryBehaviorValueBaseToIndex.clear();
+    MemoryBehaviorNodeToIndex.clear();
 
-    // Key is no longer valid as we cleared the MemoryBehaviorValueBaseToIndex.
-    Key = toMemoryBehaviorKey(SILValue(Inst), V, InspectionMode);
+    // Key is no longer valid as we cleared the MemoryBehaviorNodeToIndex.
+    Key = toMemoryBehaviorKey(Inst, V, InspectionMode);
   }
 
   // Calculate the aliasing result and store it in the cache.
@@ -354,12 +353,15 @@
   return MemoryBehaviorVisitor(this, SEA, EA, V, InspectionMode).visit(Inst);
 }
 
-MemBehaviorKeyTy AliasAnalysis::toMemoryBehaviorKey(SILValue V1, SILValue V2,
+MemBehaviorKeyTy AliasAnalysis::toMemoryBehaviorKey(SILInstruction *V1,
+                                                    SILValue V2,
                                                     RetainObserveKind M) {
-  size_t idx1 = MemoryBehaviorValueBaseToIndex.getIndex(V1);
+  size_t idx1 =
+    MemoryBehaviorNodeToIndex.getIndex(V1->getCanonicalSILNodeInObject());
   assert(idx1 != std::numeric_limits<size_t>::max() &&
          "~0 index reserved for empty/tombstone keys");
-  size_t idx2 = MemoryBehaviorValueBaseToIndex.getIndex(V2);
+  size_t idx2 =
+    MemoryBehaviorNodeToIndex.getIndex(V2->getCanonicalSILNodeInObject());
   assert(idx2 != std::numeric_limits<size_t>::max() &&
          "~0 index reserved for empty/tombstone keys");
   return {idx1, idx2, M};
diff --git a/lib/SILOptimizer/Analysis/RCIdentityAnalysis.cpp b/lib/SILOptimizer/Analysis/RCIdentityAnalysis.cpp
index 4b21759..978d163 100644
--- a/lib/SILOptimizer/Analysis/RCIdentityAnalysis.cpp
+++ b/lib/SILOptimizer/Analysis/RCIdentityAnalysis.cpp
@@ -65,7 +65,7 @@
 static SILValue stripRCIdentityPreservingInsts(SILValue V) {
   // First strip off RC identity preserving casts.
   if (isRCIdentityPreservingCast(V->getKind()))
-    return cast<SILInstruction>(V)->getOperand(0);
+    return cast<SingleValueInstruction>(V)->getOperand(0);
 
   // Then if we have a struct_extract that is extracting a non-trivial member
   // from a struct with no other non-trivial members, a ref count operation on
@@ -481,14 +481,14 @@
 /// means that from an RC use perspective, the object can be ignored since it is
 /// up to the frontend to communicate via fix_lifetime and mark_dependence these
 /// dependencies.
-static bool isNonOverlappingTrivialAccess(SILInstruction *User) {
-  if (auto *TEI = dyn_cast<TupleExtractInst>(User)) {
+static bool isNonOverlappingTrivialAccess(SILValue value) {
+  if (auto *TEI = dyn_cast<TupleExtractInst>(value)) {
     // If the tuple we are extracting from only has one non trivial element and
     // we are not extracting from that element, this is an ARC escape.
     return TEI->isTrivialEltOfOneRCIDTuple();
   }
 
-  if (auto *SEI = dyn_cast<StructExtractInst>(User)) {
+  if (auto *SEI = dyn_cast<StructExtractInst>(value)) {
     // If the struct we are extracting from only has one non trivial element and
     // we are not extracting from that element, this is an ARC escape.
     return SEI->isTrivialFieldOfOneRCIDStruct();
@@ -524,26 +524,28 @@
       if (!VisitedInsts.insert(User).second)
         continue;
 
-      // Otherwise attempt to strip off one layer of RC identical instructions
-      // from User.
-      SILValue StrippedRCID = stripRCIdentityPreservingInsts(User);
+      for (auto value : User->getResults()) {
+        // Otherwise attempt to strip off one layer of RC identical instructions
+        // from User.
+        SILValue StrippedRCID = stripRCIdentityPreservingInsts(value);
 
-      // If StrippedRCID is not V, then we know that User's result is
-      // conservatively not RCIdentical to V.
-      if (StrippedRCID != V) {
-        // If the user is extracting a trivial field of an aggregate structure
-        // that does not overlap with the ref counted part of the aggregate, we
-        // can ignore it.
-        if (isNonOverlappingTrivialAccess(User))
+        // If StrippedRCID is not V, then we know that User's result is
+        // conservatively not RCIdentical to V.
+        if (StrippedRCID != V) {
+          // If the user is extracting a trivial field of an aggregate structure
+          // that does not overlap with the ref counted part of the aggregate, we
+          // can ignore it.
+          if (isNonOverlappingTrivialAccess(value))
+            continue;
+
+          // Otherwise, it is an RC user that our user wants.
+          Users.push_back(User);
           continue;
+        }
 
-        // Otherwise, it is an RC user that our user wants.
-        Users.push_back(User);
-        continue;
+        // Otherwise, add the result to our list to continue searching.
+        Worklist.push_back(value);
       }
-
-      // Otherwise, add all of User's uses to our list to continue searching.
-      Worklist.push_back(User);
     }
   }
 }
diff --git a/lib/SILOptimizer/Analysis/SideEffectAnalysis.cpp b/lib/SILOptimizer/Analysis/SideEffectAnalysis.cpp
index 46cee51..bda9abb 100644
--- a/lib/SILOptimizer/Analysis/SideEffectAnalysis.cpp
+++ b/lib/SILOptimizer/Analysis/SideEffectAnalysis.cpp
@@ -104,7 +104,7 @@
       case ValueKind::ProjectBoxInst:
       case ValueKind::UncheckedTakeEnumDataAddrInst:
       case ValueKind::PointerToAddressInst:
-        V = cast<SILInstruction>(V)->getOperand(0);
+        V = cast<SingleValueInstruction>(V)->getOperand(0);
         break;
       default:
         return V;
@@ -120,7 +120,7 @@
       case ValueKind::TupleExtractInst:
       case ValueKind::UncheckedEnumDataInst:
       case ValueKind::UncheckedTrivialBitCastInst:
-        V = cast<SILInstruction>(V)->getOperand(0);
+        V = cast<SingleValueInstruction>(V)->getOperand(0);
         break;
       default:
         return V;
@@ -285,12 +285,14 @@
                                             int RecursionDepth) {
   if (FullApplySite FAS = FullApplySite::isa(I)) {
     // Is this a call to a semantics function?
-    ArraySemanticsCall ASC(I);
-    if (ASC && ASC.hasSelf()) {
-      FunctionEffects ApplyEffects(FAS.getNumArguments());
-      if (getSemanticEffects(ApplyEffects, ASC)) {
-        FInfo->FE.mergeFromApply(ApplyEffects, FAS);
-        return;
+    if (auto apply = dyn_cast<ApplyInst>(FAS.getInstruction())) {
+      ArraySemanticsCall ASC(apply);
+      if (ASC && ASC.hasSelf()) {
+        FunctionEffects ApplyEffects(FAS.getNumArguments());
+        if (getSemanticEffects(ApplyEffects, ASC)) {
+          FInfo->FE.mergeFromApply(ApplyEffects, FAS);
+          return;
+        }
       }
     }
 
@@ -326,43 +328,43 @@
   }
   // Handle some kind of instructions specially.
   switch (I->getKind()) {
-    case ValueKind::FixLifetimeInst:
+    case SILInstructionKind::FixLifetimeInst:
       // A fix_lifetime instruction acts like a read on the operand. Retains can move after it
       // but the last release can't move before it.
       FInfo->FE.getEffectsOn(I->getOperand(0))->Reads = true;
       return;
-    case ValueKind::AllocStackInst:
-    case ValueKind::DeallocStackInst:
+    case SILInstructionKind::AllocStackInst:
+    case SILInstructionKind::DeallocStackInst:
       return;
-    case ValueKind::StrongRetainInst:
-    case ValueKind::StrongRetainUnownedInst:
-    case ValueKind::RetainValueInst:
-    case ValueKind::UnownedRetainInst:
+    case SILInstructionKind::StrongRetainInst:
+    case SILInstructionKind::StrongRetainUnownedInst:
+    case SILInstructionKind::RetainValueInst:
+    case SILInstructionKind::UnownedRetainInst:
       FInfo->FE.getEffectsOn(I->getOperand(0))->Retains = true;
       return;
-    case ValueKind::StrongReleaseInst:
-    case ValueKind::ReleaseValueInst:
-    case ValueKind::UnownedReleaseInst:
+    case SILInstructionKind::StrongReleaseInst:
+    case SILInstructionKind::ReleaseValueInst:
+    case SILInstructionKind::UnownedReleaseInst:
       FInfo->FE.getEffectsOn(I->getOperand(0))->Releases = true;
       
       // TODO: Check the call graph to be less conservative about what
       // destructors might be called.
       FInfo->FE.setWorstEffects();
       return;
-    case ValueKind::UnconditionalCheckedCastInst:
+    case SILInstructionKind::UnconditionalCheckedCastInst:
       FInfo->FE.getEffectsOn(cast<UnconditionalCheckedCastInst>(I)->getOperand())->Reads = true;
       FInfo->FE.Traps = true;
       return;
-    case ValueKind::LoadInst:
+    case SILInstructionKind::LoadInst:
       FInfo->FE.getEffectsOn(cast<LoadInst>(I)->getOperand())->Reads = true;
       return;
-    case ValueKind::StoreInst:
+    case SILInstructionKind::StoreInst:
       FInfo->FE.getEffectsOn(cast<StoreInst>(I)->getDest())->Writes = true;
       return;
-    case ValueKind::CondFailInst:
+    case SILInstructionKind::CondFailInst:
       FInfo->FE.Traps = true;
       return;
-    case ValueKind::PartialApplyInst: {
+    case SILInstructionKind::PartialApplyInst: {
       FInfo->FE.AllocsObjects = true;
       auto *PAI = cast<PartialApplyInst>(I);
       auto Args = PAI->getArguments();
@@ -374,7 +376,7 @@
       }
       return;
     }
-    case ValueKind::BuiltinInst: {
+    case SILInstructionKind::BuiltinInst: {
       auto *BInst = cast<BuiltinInst>(I);
       auto &BI = BInst->getBuiltinInfo();
       switch (BI.ID) {
@@ -489,10 +491,12 @@
   ApplyEffects.ParamEffects.resize(FAS.getNumArguments());
 
   // Is this a call to a semantics function?
-  ArraySemanticsCall ASC(FAS.getInstruction());
-  if (ASC && ASC.hasSelf()) {
-    if (getSemanticEffects(ApplyEffects, ASC))
-      return;
+  if (auto apply = dyn_cast<ApplyInst>(FAS.getInstruction())) {
+    ArraySemanticsCall ASC(apply);
+    if (ASC && ASC.hasSelf()) {
+      if (getSemanticEffects(ApplyEffects, ASC))
+        return;
+    }
   }
 
   if (SILFunction *SingleCallee = FAS.getReferencedFunction()) {
diff --git a/lib/SILOptimizer/Analysis/ValueTracking.cpp b/lib/SILOptimizer/Analysis/ValueTracking.cpp
index c914f5e..afe73ec 100644
--- a/lib/SILOptimizer/Analysis/ValueTracking.cpp
+++ b/lib/SILOptimizer/Analysis/ValueTracking.cpp
@@ -53,20 +53,18 @@
     Processed.insert(V);
     // It should be a local object.
     V = getUnderlyingObject(V);
-    if (auto I = dyn_cast<SILInstruction>(V)) {
-      if (isa<AllocationInst>(V))
-        continue;
-      if (isa<StrongPinInst>(I)) {
-        WorkList.push_back(I->getOperand(0));
-        continue;
+    if (isa<AllocationInst>(V))
+      continue;
+    if (auto I = dyn_cast<StrongPinInst>(V)) {
+      WorkList.push_back(I->getOperand());
+      continue;
+    }
+    if (isa<StructInst>(V) || isa<TupleInst>(V) || isa<EnumInst>(V)) {
+      // A compound value is local, if all of its components are local.
+      for (auto &Op : cast<SingleValueInstruction>(V)->getAllOperands()) {
+        WorkList.push_back(Op.get());
       }
-      if (isa<StructInst>(I) || isa<TupleInst>(I) || isa<EnumInst>(I)) {
-        // A compound value is local, if all of its components are local.
-        for (auto &Op : I->getAllOperands()) {
-          WorkList.push_back(Op.get());
-        }
-        continue;
-      }
+      continue;
     }
 
     if (auto *Arg = dyn_cast<SILPHIArgument>(V)) {
@@ -108,7 +106,7 @@
     case ValueKind::UncheckedTrivialBitCastInst:
     // Extracting from a zero class returns a zero.
     case ValueKind::StructExtractInst:
-      return isZeroValue(cast<SILInstruction>(Value)->getOperand(0));
+      return isZeroValue(cast<SingleValueInstruction>(Value)->getOperand(0));
     default:
       break;
   }
@@ -180,7 +178,7 @@
     switch (Def->getKind()) {
     // Bitcast of non-negative is non-negative
     case ValueKind::UncheckedTrivialBitCastInst:
-      Value = cast<SILInstruction>(Def)->getOperand(0);
+      Value = cast<UncheckedTrivialBitCastInst>(Def)->getOperand();
       continue;
     default:
       break;
diff --git a/lib/SILOptimizer/IPO/CapturePromotion.cpp b/lib/SILOptimizer/IPO/CapturePromotion.cpp
index c82273e..333ae6e 100644
--- a/lib/SILOptimizer/IPO/CapturePromotion.cpp
+++ b/lib/SILOptimizer/IPO/CapturePromotion.cpp
@@ -193,7 +193,7 @@
 /// one or more captures from 'inout' (by-reference) to by-value.
 class ClosureCloner : public SILClonerWithScopes<ClosureCloner> {
 public:
-  friend class SILVisitor<ClosureCloner>;
+  friend class SILInstructionVisitor<ClosureCloner>;
   friend class SILCloner<ClosureCloner>;
 
   ClosureCloner(SILFunction *Orig, IsSerialized_t Serialized,
@@ -428,8 +428,9 @@
   auto *Fn = M.createFunction(
       Orig->getLinkage(), ClonedName, ClonedTy, Orig->getGenericEnvironment(),
       Orig->getLocation(), Orig->isBare(), IsNotTransparent, Serialized,
-      Orig->isThunk(), Orig->getClassSubclassScope(), Orig->getInlineStrategy(),
-      Orig->getEffectsKind(), Orig, Orig->getDebugScope());
+      Orig->getEntryCount(), Orig->isThunk(), Orig->getClassSubclassScope(),
+      Orig->getInlineStrategy(), Orig->getEffectsKind(), Orig,
+      Orig->getDebugScope());
   for (auto &Attr : Orig->getSemanticsAttrs())
     Fn->addSemanticsAttr(Attr);
   if (Orig->hasUnqualifiedOwnership()) {
@@ -677,11 +678,10 @@
     // Loads of a struct_element_addr of an argument get replaced with a
     // struct_extract of the new passed in value. The value should be borrowed
     // already, so we can just extract the value.
-    SILBuilderWithPostProcess<ClosureCloner, 1> B(this, LI);
-    assert(B.getFunction().hasUnqualifiedOwnership() ||
+    assert(getBuilder().getFunction().hasUnqualifiedOwnership() ||
            Val.getOwnershipKind().isTrivialOr(ValueOwnershipKind::Guaranteed));
-    Val =
-        B.emitStructExtract(LI->getLoc(), Val, SEAI->getField(), LI->getType());
+    Val = getBuilder().emitStructExtract(LI->getLoc(), Val, SEAI->getField(),
+                                         LI->getType());
 
     // If we were performing a load [copy], then we need to a perform a copy
     // here since when cloning, we do not eliminate the destroy on the copied
@@ -814,8 +814,8 @@
   /// Visit a random value base.
   ///
   /// These are considered to be escapes.
-  bool visitValueBase(ValueBase *V) {
-    DEBUG(llvm::dbgs() << "    FAIL! Have unknown escaping user: " << *V);
+  bool visitSILInstruction(SILInstruction *I) {
+    DEBUG(llvm::dbgs() << "    FAIL! Have unknown escaping user: " << *I);
     return false;
   }
 
@@ -850,7 +850,7 @@
   }
 
   /// Add the Operands of a transitive use instruction to the worklist.
-  void addUserOperandsToWorklist(SILInstruction *I) {
+  void addUserOperandsToWorklist(SingleValueInstruction *I) {
     for (auto *User : I->getUses()) {
       Worklist.push_back(User);
     }
@@ -1046,7 +1046,8 @@
   // derived from a projection like instruction). In fact such a thing may not
   // even make any sense!
   if (isa<CopyValueInst>(User) || isa<MarkUninitializedInst>(User)) {
-    return all_of(User->getUses(), [&State](Operand *UserOp) -> bool {
+    return all_of(cast<SingleValueInstruction>(User)->getUses(),
+                  [&State](Operand *UserOp) -> bool {
       return scanUsesForEscapesAndMutations(UserOp, State);
     });
   }
@@ -1178,7 +1179,7 @@
 
   // Otherwise, handle the alloc_box case. If we have a mark_uninitialized on
   // the box, we create the project value through that.
-  SILInstruction *Box = cast<AllocBoxInst>(PartialOperand);
+  SingleValueInstruction *Box = cast<AllocBoxInst>(PartialOperand);
   if (auto *Op = Box->getSingleUse()) {
     if (auto *MUI = dyn_cast<MarkUninitializedInst>(Op->getUser())) {
       Box = MUI;
diff --git a/lib/SILOptimizer/IPO/CapturePropagation.cpp b/lib/SILOptimizer/IPO/CapturePropagation.cpp
index 489dc85..5a0496e 100644
--- a/lib/SILOptimizer/IPO/CapturePropagation.cpp
+++ b/lib/SILOptimizer/IPO/CapturePropagation.cpp
@@ -94,7 +94,7 @@
 class CapturePropagationCloner
   : public TypeSubstCloner<CapturePropagationCloner> {
   using SuperTy = TypeSubstCloner<CapturePropagationCloner>;
-  friend class SILVisitor<CapturePropagationCloner>;
+  friend class SILInstructionVisitor<CapturePropagationCloner>;
   friend class SILCloner<CapturePropagationCloner>;
 
   SILFunction *OrigF;
@@ -141,12 +141,12 @@
 void CapturePropagationCloner::cloneConstValue(SILValue Val) {
   assert(IsCloningConstant && "incorrect mode");
 
-  auto Inst = dyn_cast<SILInstruction>(Val);
-  if (!Inst)
+  if (ValueMap.find(Val) != ValueMap.end())
     return;
 
-  auto II = InstructionMap.find(Inst);
-  if (II != InstructionMap.end())
+  // TODO: MultiValueInstruction?
+  auto Inst = dyn_cast<SingleValueInstruction>(Val);
+  if (!Inst)
     return;
 
   if (Inst->getNumOperands() > 0) {
@@ -258,11 +258,10 @@
   if (NewFTy->getGenericSignature())
     GenericEnv = OrigF->getGenericEnvironment();
   SILFunction *NewF = OrigF->getModule().createFunction(
-      SILLinkage::Shared, Name, NewFTy,
-      GenericEnv, OrigF->getLocation(), OrigF->isBare(),
-      OrigF->isTransparent(), Serialized, OrigF->isThunk(),
-      OrigF->getClassSubclassScope(), OrigF->getInlineStrategy(),
-      OrigF->getEffectsKind(),
+      SILLinkage::Shared, Name, NewFTy, GenericEnv, OrigF->getLocation(),
+      OrigF->isBare(), OrigF->isTransparent(), Serialized,
+      OrigF->getEntryCount(), OrigF->isThunk(), OrigF->getClassSubclassScope(),
+      OrigF->getInlineStrategy(), OrigF->getEffectsKind(),
       /*InsertBefore*/ OrigF, OrigF->getDebugScope());
   if (OrigF->hasUnqualifiedOwnership()) {
     NewF->setUnqualifiedOwnership();
@@ -387,7 +386,7 @@
         return nullptr;
       }
       assert(isa<ApplyInst>(&I) && "unknown FullApplySite instruction");
-      RetValue = &I;
+      RetValue = cast<ApplyInst>(&I);
       continue;
     }
     if (auto *RI = dyn_cast<ReturnInst>(&I)) {
diff --git a/lib/SILOptimizer/IPO/ClosureSpecializer.cpp b/lib/SILOptimizer/IPO/ClosureSpecializer.cpp
index 802c014..32e151c 100644
--- a/lib/SILOptimizer/IPO/ClosureSpecializer.cpp
+++ b/lib/SILOptimizer/IPO/ClosureSpecializer.cpp
@@ -112,7 +112,7 @@
 class ClosureSpecCloner : public SILClonerWithScopes<ClosureSpecCloner> {
 public:
   using SuperTy = SILClonerWithScopes<ClosureSpecCloner>;
-  friend class SILVisitor<ClosureSpecCloner>;
+  friend class SILInstructionVisitor<ClosureSpecCloner>;
   friend class SILCloner<ClosureSpecCloner>;
 
   ClosureSpecCloner(const CallSiteDescriptor &CallSiteDesc,
@@ -187,7 +187,7 @@
 
   SILParameterInfo getClosureParameterInfo() const { return ClosureParamInfo; }
 
-  SILInstruction *
+  SingleValueInstruction *
   createNewClosure(SILBuilder &B, SILValue V,
                    llvm::SmallVectorImpl<SILValue> &Args) const {
     if (isa<PartialApplyInst>(getClosure()))
@@ -219,7 +219,7 @@
     return OperandValueArrayRef(ArrayRef<Operand>());
   }
 
-  inline SILInstruction *getClosure() const;
+  inline SingleValueInstruction *getClosure() const;
 
   unsigned getNumArguments() const {
     if (auto *PAI = dyn_cast<PartialApplyInst>(getClosure()))
@@ -255,18 +255,18 @@
 
 namespace {
 struct ClosureInfo {
-  SILInstruction *Closure;
+  SingleValueInstruction *Closure;
   ValueLifetimeAnalysis::Frontier LifetimeFrontier;
   llvm::SmallVector<CallSiteDescriptor, 8> CallSites;
 
-  ClosureInfo(SILInstruction *Closure): Closure(Closure) {}
+  ClosureInfo(SingleValueInstruction *Closure): Closure(Closure) {}
 
   ClosureInfo(ClosureInfo &&) =default;
   ClosureInfo &operator=(ClosureInfo &&) =default;
 };
 } // end anonymous namespace
 
-SILInstruction *CallSiteDescriptor::getClosure() const {
+SingleValueInstruction *CallSiteDescriptor::getClosure() const {
   return CInfo->Closure;
 }
 
@@ -281,7 +281,7 @@
 static void rewriteApplyInst(const CallSiteDescriptor &CSDesc,
                              SILFunction *NewF) {
   FullApplySite AI = CSDesc.getApplyInst();
-  SILInstruction *Closure = CSDesc.getClosure();
+  SingleValueInstruction *Closure = CSDesc.getClosure();
   SILBuilderWithScope Builder(Closure);
   FunctionRefInst *FRI = Builder.createFunctionRef(AI.getLoc(), NewF);
 
@@ -403,19 +403,21 @@
       Builder.setInsertionPoint(AI.getInstruction());
     }
   } else {
-    NewAI = Builder.createApply(AI.getLoc(), FRI,
-                                SubstitutionList(),
-                                NewArgs, cast<ApplyInst>(AI)->isNonThrowing());
+    auto oldApply = cast<ApplyInst>(AI);
+    auto newApply = Builder.createApply(oldApply->getLoc(), FRI,
+                                        SubstitutionList(),
+                                        NewArgs, oldApply->isNonThrowing());
     // If we passed in the original closure as @owned, then insert a release
     // right after NewAI. This is to balance the +1 from being an @owned
     // argument to AI.
     if (CSDesc.isClosureConsumed() && CSDesc.closureHasRefSemanticContext())
-      Builder.createReleaseValue(Closure->getLoc(), Closure, Builder.getDefaultAtomicity());
-  }
+      Builder.createReleaseValue(Closure->getLoc(), Closure,
+                                 Builder.getDefaultAtomicity());
 
-  // Replace all uses of the old apply with the new apply.
-  if (isa<ApplyInst>(AI))
-    AI.getInstruction()->replaceAllUsesWith(NewAI.getInstruction());
+    // Replace all uses of the old apply with the new apply.
+    oldApply->replaceAllUsesWith(newApply);
+  }
+    
   // Erase the old apply.
   AI.getInstruction()->eraseFromParent();
 
@@ -614,10 +616,10 @@
       // and not the original linkage.
       // Otherwise the new function could have an external linkage (in case the
       // original function was de-serialized) and would not be code-gen'd.
-      getSpecializedLinkage(ClosureUser, ClosureUser->getLinkage()),
-      ClonedName, ClonedTy,
-      ClosureUser->getGenericEnvironment(), ClosureUser->getLocation(),
-      IsBare, ClosureUser->isTransparent(), CallSiteDesc.isSerialized(),
+      getSpecializedLinkage(ClosureUser, ClosureUser->getLinkage()), ClonedName,
+      ClonedTy, ClosureUser->getGenericEnvironment(),
+      ClosureUser->getLocation(), IsBare, ClosureUser->isTransparent(),
+      CallSiteDesc.isSerialized(), ClosureUser->getEntryCount(),
       ClosureUser->isThunk(), ClosureUser->getClassSubclassScope(),
       ClosureUser->getInlineStrategy(), ClosureUser->getEffectsKind(),
       ClosureUser, ClosureUser->getDebugScope());
@@ -741,7 +743,7 @@
                        llvm::SmallVectorImpl<ClosureInfo*> &ClosureCandidates,
                        llvm::DenseSet<FullApplySite> &MultipleClosureAI);
   bool specialize(SILFunction *Caller,
-                  std::vector<SILInstruction *> &PropagatedClosures);
+                  std::vector<SingleValueInstruction *> &PropagatedClosures);
 
 public:
   SILClosureSpecializerTransform() {}
@@ -762,7 +764,7 @@
   if (F->isExternalDeclaration())
     return;
 
-  std::vector<SILInstruction *> PropagatedClosures;
+  std::vector<SingleValueInstruction *> PropagatedClosures;
 
   if (!specialize(F, PropagatedClosures))
     return;
@@ -774,7 +776,7 @@
     // specialized all of their uses.
     DEBUG(llvm::dbgs() << "Trying to remove dead closures!\n");
     sortUnique(PropagatedClosures);
-    for (SILInstruction *Closure : PropagatedClosures) {
+    for (auto *Closure : PropagatedClosures) {
       DEBUG(llvm::dbgs() << "    Visiting: " << *Closure);
       if (!tryDeleteDeadClosure(Closure)) {
         DEBUG(llvm::dbgs() << "        Failed to delete closure!\n");
@@ -809,11 +811,12 @@
       // If II is not a closure that we support specializing, skip it...
       if (!isSupportedClosure(&II))
         continue;
+      auto ClosureInst = cast<SingleValueInstruction>(&II);
 
       ClosureInfo *CInfo = nullptr;
 
       // Go through all uses of our closure.
-      for (auto *Use : II.getUses()) {
+      for (auto *Use : ClosureInst->getUses()) {
         // If this use is not an apply inst or an apply inst with
         // substitutions, there is nothing interesting for us to do, so
         // continue...
@@ -856,7 +859,7 @@
         // corresponding to our partial apply.
         Optional<unsigned> ClosureIndex;
         for (unsigned i = 0, e = AI.getNumArguments(); i != e; ++i) {
-          if (AI.getArgument(i) != SILValue(&II))
+          if (AI.getArgument(i) != ClosureInst)
             continue;
           ClosureIndex = i;
           DEBUG(llvm::dbgs() << "    Found callsite with closure argument at "
@@ -902,7 +905,7 @@
         // don't need to be released.
         llvm::TinyPtrVector<SILBasicBlock *> NonFailureExitBBs;
         if (ClosureParamInfo.isGuaranteed() &&
-            !isa<ThinToThickFunctionInst>(&II) &&
+            !isa<ThinToThickFunctionInst>(ClosureInst) &&
             !findAllNonFailureExitBBs(ApplyCallee, NonFailureExitBBs)) {
           continue;
         }
@@ -910,7 +913,7 @@
         // Compute the final release points of the closure. We will insert
         // release of the captured arguments here.
         if (!CInfo) {
-          CInfo = new ClosureInfo(&II);
+          CInfo = new ClosureInfo(ClosureInst);
           ValueLifetimeAnalysis VLA(CInfo->Closure);
           VLA.computeFrontier(CInfo->LifetimeFrontier,
                               ValueLifetimeAnalysis::AllowToModifyCFG);
@@ -929,7 +932,7 @@
 }
 
 bool SILClosureSpecializerTransform::specialize(SILFunction *Caller,
-                            std::vector<SILInstruction *> &PropagatedClosures) {
+                    std::vector<SingleValueInstruction *> &PropagatedClosures) {
   DEBUG(llvm::dbgs() << "Optimizing callsites that take closure argument in "
                      << Caller->getName() << '\n');
 
diff --git a/lib/SILOptimizer/IPO/EagerSpecializer.cpp b/lib/SILOptimizer/IPO/EagerSpecializer.cpp
index 9df86d7..e569dd7 100644
--- a/lib/SILOptimizer/IPO/EagerSpecializer.cpp
+++ b/lib/SILOptimizer/IPO/EagerSpecializer.cpp
@@ -100,11 +100,12 @@
     if (NewRetVal->getType().isVoid()) {
       // Canonicalize Void return type into something that isTrivialReturnBlock
       // expects.
-      auto *TupleI = cast<SILInstruction>(RetInst->getOperand(0));
-      if (TupleI->hasOneUse()) {
+      auto *TupleI = dyn_cast<TupleInst>(RetInst->getOperand(0));
+      if (TupleI && TupleI->hasOneUse()) {
         TupleI->moveBefore(RetInst);
       } else {
-        TupleI = TupleI->clone(RetInst);
+        Builder.setInsertionPoint(RetInst);
+        TupleI = Builder.createTuple(RetInst->getLoc(), {});
         RetInst->setOperand(0, TupleI);
       }
       MergedBB = RetBB->split(TupleI->getIterator());
diff --git a/lib/SILOptimizer/IPO/GlobalOpt.cpp b/lib/SILOptimizer/IPO/GlobalOpt.cpp
index 09aca85..d55d583 100644
--- a/lib/SILOptimizer/IPO/GlobalOpt.cpp
+++ b/lib/SILOptimizer/IPO/GlobalOpt.cpp
@@ -127,14 +127,14 @@
                                 SILFunction *AddrF,
                                 SILFunction *InitF,
                                 SILGlobalVariable *SILG,
-                                SILInstruction *InitVal,
+                                SingleValueInstruction *InitVal,
                                 GlobalInitCalls &Calls);
 };
 
 /// Helper class to copy only a set of SIL instructions providing in the
 /// constructor.
 class InstructionsCloner : public SILClonerWithScopes<InstructionsCloner> {
-  friend class SILVisitor<InstructionsCloner>;
+  friend class SILInstructionVisitor<InstructionsCloner>;
   friend class SILCloner<InstructionsCloner>;
 
   ArrayRef<SILInstruction *> Insns;
@@ -162,7 +162,10 @@
   void postProcess(SILInstruction *Orig, SILInstruction *Cloned) {
     DestBB->push_back(Cloned);
     SILClonerWithScopes<InstructionsCloner>::postProcess(Orig, Cloned);
-    AvailVals.push_back(std::make_pair(Orig, Cloned));
+    auto origResults = Orig->getResults(), clonedResults = Cloned->getResults();
+    assert(origResults.size() == clonedResults.size());
+    for (auto i : indices(origResults))
+      AvailVals.push_back(std::make_pair(origResults[i], clonedResults[i]));
   }
 
   // Clone all instructions from Insns into DestBB
@@ -239,7 +242,7 @@
   SmallVector<SILInstruction *, 8> ReverseInsns;
   SmallVector<SILInstruction *, 8> Insns;
   ReverseInsns.push_back(Store);
-  ReverseInsns.push_back(dyn_cast<SILInstruction>(Store->getDest()));
+  ReverseInsns.push_back(dyn_cast<SingleValueInstruction>(Store->getDest()));
   if (!analyzeStaticInitializer(V, ReverseInsns))
     return nullptr;
 
@@ -599,33 +602,30 @@
 /// a chain of struct_element_addr followed by a load.
 /// The sequence is traversed starting from the load
 /// instruction.
-static SILInstruction *convertLoadSequence(SILInstruction *I,
-                                SILInstruction *Value,
-                                SILBuilder &B) {
+static SILValue convertLoadSequence(SILValue oldSequence,
+                                    SILValue newRootValue,
+                                    SILBuilder &B) {
 
-  if (isa<GlobalAddrInst>(I))
-    return Value;
+  if (isa<GlobalAddrInst>(oldSequence))
+    return newRootValue;
 
-  if (auto *LI = dyn_cast<LoadInst>(I)) {
-    Value =
-        convertLoadSequence(cast<SILInstruction>(LI->getOperand()), Value, B);
-    LI->replaceAllUsesWith(Value);
-    return Value;
+  if (auto *LI = dyn_cast<LoadInst>(oldSequence)) {
+    auto newValue = convertLoadSequence(LI->getOperand(), newRootValue, B);
+    LI->replaceAllUsesWith(newValue);
+    return newValue;
   }
 
   // It is a series of struct_element_addr followed by load.
-  if (auto *SEAI = dyn_cast<StructElementAddrInst>(I)) {
-    Value =
-        convertLoadSequence(cast<SILInstruction>(SEAI->getOperand()), Value, B);
-    auto *SEI = B.createStructExtract(SEAI->getLoc(), Value, SEAI->getField());
-    return SEI;
+  if (auto *SEAI = dyn_cast<StructElementAddrInst>(oldSequence)) {
+    auto newValue = convertLoadSequence(SEAI->getOperand(), newRootValue, B);
+    newValue = B.createStructExtract(SEAI->getLoc(), newValue, SEAI->getField());
+    return newValue;
   }
 
-  if (auto *TEAI = dyn_cast<TupleElementAddrInst>(I)) {
-    Value =
-        convertLoadSequence(cast<SILInstruction>(TEAI->getOperand()), Value, B);
-    auto *TEI = B.createTupleExtract(TEAI->getLoc(), Value, TEAI->getFieldNo());
-    return TEI;
+  if (auto *TEAI = dyn_cast<TupleElementAddrInst>(oldSequence)) {
+    auto newValue = convertLoadSequence(TEAI->getOperand(), newRootValue, B);
+    newValue = B.createTupleExtract(TEAI->getLoc(), newValue, TEAI->getFieldNo());
+    return newValue;
   }
 
   llvm_unreachable("Unknown instruction sequence for reading from a global");
@@ -633,7 +633,7 @@
 }
 
 static SILGlobalVariable *getVariableOfStaticInitializer(SILFunction *InitFunc,
-                                                   SILInstruction *&InitVal) {
+                                             SingleValueInstruction *&InitVal) {
   InitVal = nullptr;
   SILGlobalVariable *GVar = nullptr;
   // We only handle a single SILBasicBlock for now.
@@ -658,12 +658,13 @@
       if (HasStore || SI->getDest() != SGA)
         return nullptr;
       HasStore = true;
-      InitVal = dyn_cast<SILInstruction>(SI->getSrc());
+      SILValue value = SI->getSrc();
 
       // We only handle StructInst and TupleInst being stored to a
       // global variable for now.
-      if (!isa<StructInst>(InitVal) && !isa<TupleInst>(InitVal))
+      if (!isa<StructInst>(value) && !isa<TupleInst>(value))
         return nullptr;
+      InitVal = cast<SingleValueInstruction>(value);
     } else if (!SILGlobalVariable::isValidStaticInitializerInst(&I,
                                                              I.getModule())) {
       return nullptr;
@@ -679,7 +680,7 @@
 /// Utility class for cloning init values into the static initializer of a
 /// SILGlobalVariable.
 class StaticInitCloner : public SILCloner<StaticInitCloner> {
-  friend class SILVisitor<StaticInitCloner>;
+  friend class SILInstructionVisitor<StaticInitCloner>;
   friend class SILCloner<StaticInitCloner>;
 
   /// The number of not yet cloned operands for each instruction.
@@ -702,11 +703,11 @@
   /// SILGlobalVariable.
   ///
   /// \return Returns the cloned instruction in the SILGlobalVariable.
-  SILInstruction *clone(SILInstruction *InitVal);
+  SingleValueInstruction *clone(SingleValueInstruction *InitVal);
 
   /// Convenience function to clone a single \p InitVal.
   static void appendToInitializer(SILGlobalVariable *GVar,
-                                  SILInstruction *InitVal) {
+                                  SingleValueInstruction *InitVal) {
     StaticInitCloner Cloner(GVar);
     Cloner.add(InitVal);
     Cloner.clone(InitVal);
@@ -732,12 +733,13 @@
   } else {
     // Recursively add all operands.
     for (const Operand &Op : Ops) {
-      add(cast<SILInstruction>(Op.get()));
+      add(cast<SingleValueInstruction>(Op.get()));
     }
   }
 }
 
-SILInstruction *StaticInitCloner::clone(SILInstruction *InitVal) {
+SingleValueInstruction *
+StaticInitCloner::clone(SingleValueInstruction *InitVal) {
   assert(NumOpsToClone.count(InitVal) != 0 && "InitVal was not added");
   // Find the right order to clone: all operands of an instruction must be
   // cloned before the instruction itself.
@@ -748,15 +750,17 @@
     visit(I);
 
     // Check if users of I can now be cloned.
-    for (Operand *Use : I->getUses()) {
-      SILInstruction *User = Use->getUser();
-      if (NumOpsToClone.count(User) != 0 && --NumOpsToClone[User] == 0)
-        ReadyToClone.push_back(User);
+    for (SILValue result : I->getResults()) {
+      for (Operand *Use : result->getUses()) {
+        SILInstruction *User = Use->getUser();
+        if (NumOpsToClone.count(User) != 0 && --NumOpsToClone[User] == 0)
+          ReadyToClone.push_back(User);
+      }
     }
   }
-  assert(InstructionMap.count(InitVal) != 0 &&
+  assert(ValueMap.count(InitVal) != 0 &&
          "Could not schedule all instructions for cloning");
-  return InstructionMap[InitVal];
+  return cast<SingleValueInstruction>(ValueMap[InitVal]);
 }
 
 } // end anonymous namespace
@@ -765,7 +769,7 @@
 void SILGlobalOpt::
 replaceLoadsByKnownValue(BuiltinInst *CallToOnce, SILFunction *AddrF,
                          SILFunction *InitF, SILGlobalVariable *SILG,
-                         SILInstruction *InitVal,
+                         SingleValueInstruction *InitVal,
                          GlobalInitCalls &Calls) {
   assert(isAssignedOnlyOnceInInitializer(SILG) &&
          "The value of the initializer should be known at compile-time");
@@ -850,7 +854,7 @@
     return;
 
   // If the globalinit_func is trivial, continue; otherwise bail.
-  SILInstruction *InitVal;
+  SingleValueInstruction *InitVal;
   SILGlobalVariable *SILG = getVariableOfStaticInitializer(InitF, InitVal);
   if (!SILG)
     return;
@@ -884,7 +888,7 @@
       return nullptr;
 
     // If the globalinit_func is trivial, continue; otherwise bail.
-    SILInstruction *dummyInitVal;
+    SingleValueInstruction *dummyInitVal;
     auto *SILG = getVariableOfStaticInitializer(InitF, dummyInitVal);
     if (!SILG || !SILG->isDefinition())
       return nullptr;
@@ -929,7 +933,7 @@
 /// Check if instruction I is a load from instruction V or
 /// or a struct_element_addr from instruction V.
 /// returns instruction I if this condition holds, or nullptr otherwise.
-static LoadInst *getValidLoad(SILInstruction *I, SILInstruction *V) {
+static LoadInst *getValidLoad(SILInstruction *I, SILValue V) {
   if (auto *LI = dyn_cast<LoadInst>(I)) {
     if (LI->getOperand() == V)
       return LI;
@@ -1010,9 +1014,9 @@
 }
 
 /// Check if \p V is a valid instruction for a static initializer, including
-/// all it's operands.
+/// all its operands.
 static bool isValidInitVal(SILValue V) {
-  if (SILInstruction *I = dyn_cast<SILInstruction>(V)) {
+  if (auto I = dyn_cast<SingleValueInstruction>(V)) {
     if (!SILGlobalVariable::isValidStaticInitializerInst(I, I->getModule()))
       return false;
 
@@ -1031,7 +1035,7 @@
     return false;
 
   // If any of the operands is not empty, the whole struct/tuple is not empty.
-  for (Operand &Op : cast<SILInstruction>(V)->getAllOperands()) {
+  for (Operand &Op : cast<SingleValueInstruction>(V)->getAllOperands()) {
     if (!isEmptyInitVal(Op.get()))
       return false;
   }
@@ -1047,73 +1051,74 @@
 bool SILGlobalOpt::isValidUseOfObject(SILInstruction *I, bool isCOWObject,
                                       ApplyInst **FindStringCall) {
   switch (I->getKind()) {
-    case ValueKind::DebugValueAddrInst:
-    case ValueKind::DebugValueInst:
-    case ValueKind::LoadInst:
-    case ValueKind::DeallocRefInst:
-    case ValueKind::StrongRetainInst:
-    case ValueKind::StrongReleaseInst:
-      return true;
+  case SILInstructionKind::DebugValueAddrInst:
+  case SILInstructionKind::DebugValueInst:
+  case SILInstructionKind::LoadInst:
+  case SILInstructionKind::DeallocRefInst:
+  case SILInstructionKind::StrongRetainInst:
+  case SILInstructionKind::StrongReleaseInst:
+    return true;
 
-    case ValueKind::ReturnInst:
-    case ValueKind::TryApplyInst:
-    case ValueKind::PartialApplyInst:
-    case ValueKind::StoreInst:
-      /// We don't have a representation for COW objects in SIL, so we do some
-      /// ad-hoc testing: We can ignore uses of a COW object if any use after
-      /// this will do a uniqueness checking before the object is modified.
-      return isCOWObject;
+  case SILInstructionKind::ReturnInst:
+  case SILInstructionKind::TryApplyInst:
+  case SILInstructionKind::PartialApplyInst:
+  case SILInstructionKind::StoreInst:
+    /// We don't have a representation for COW objects in SIL, so we do some
+    /// ad-hoc testing: We can ignore uses of a COW object if any use after
+    /// this will do a uniqueness checking before the object is modified.
+    return isCOWObject;
 
-    case ValueKind::ApplyInst:
-      if (!isCOWObject)
-        return false;
-      // There should only be a single call to findStringSwitchCase. But even
-      // if there are multiple calls, it's not problem - we'll just optimize the
-      // last one we find.
-      if (cast<ApplyInst>(I)->hasSemantics("findStringSwitchCase"))
-        *FindStringCall = cast<ApplyInst>(I);
-      return true;
-
-    case ValueKind::StructInst:
-      if (isCOWType(I->getType())) {
-        // The object is wrapped into a COW container.
-        isCOWObject = true;
-      }
-      break;
-
-    case ValueKind::UncheckedRefCastInst:
-    case ValueKind::StructElementAddrInst:
-    case ValueKind::AddressToPointerInst:
-      assert(!isCOWObject && "instruction cannot have a COW object as operand");
-      break;
-
-    case ValueKind::TupleInst:
-    case ValueKind::TupleExtractInst:
-    case ValueKind::EnumInst:
-      break;
-
-    case ValueKind::StructExtractInst:
-      // To be on the safe side we don't consider the object as COW if it is
-      // extracted again from the COW container: the uniqueness check may be
-      // optimized away in this case.
-      isCOWObject = false;
-      break;
-
-    case ValueKind::BuiltinInst: {
-      // Handle the case for comparing addresses. This occurs when the Array
-      // comparison function is inlined.
-      auto *BI = cast<BuiltinInst>(I);
-      BuiltinValueKind K = BI->getBuiltinInfo().ID;
-      if (K == BuiltinValueKind::ICMP_EQ || K == BuiltinValueKind::ICMP_NE)
-        return true;
+  case SILInstructionKind::ApplyInst:
+    if (!isCOWObject)
       return false;
+    // There should only be a single call to findStringSwitchCase. But even
+    // if there are multiple calls, it's not problem - we'll just optimize the
+    // last one we find.
+    if (cast<ApplyInst>(I)->hasSemantics("findStringSwitchCase"))
+      *FindStringCall = cast<ApplyInst>(I);
+    return true;
+
+  case SILInstructionKind::StructInst:
+    if (isCOWType(cast<StructInst>(I)->getType())) {
+      // The object is wrapped into a COW container.
+      isCOWObject = true;
     }
+    break;
 
-    default:
-      return false;
+  case SILInstructionKind::UncheckedRefCastInst:
+  case SILInstructionKind::StructElementAddrInst:
+  case SILInstructionKind::AddressToPointerInst:
+    assert(!isCOWObject && "instruction cannot have a COW object as operand");
+    break;
+
+  case SILInstructionKind::TupleInst:
+  case SILInstructionKind::TupleExtractInst:
+  case SILInstructionKind::EnumInst:
+    break;
+
+  case SILInstructionKind::StructExtractInst:
+    // To be on the safe side we don't consider the object as COW if it is
+    // extracted again from the COW container: the uniqueness check may be
+    // optimized away in this case.
+    isCOWObject = false;
+    break;
+
+  case SILInstructionKind::BuiltinInst: {
+    // Handle the case for comparing addresses. This occurs when the Array
+    // comparison function is inlined.
+    auto *BI = cast<BuiltinInst>(I);
+    BuiltinValueKind K = BI->getBuiltinInfo().ID;
+    if (K == BuiltinValueKind::ICMP_EQ || K == BuiltinValueKind::ICMP_NE)
+      return true;
+    return false;
   }
 
-  for (Operand *Use : getNonDebugUses(I)) {
+  default:
+    return false;
+  }
+
+  auto SVI = cast<SingleValueInstruction>(I);
+  for (Operand *Use : getNonDebugUses(SVI)) {
     if (!isValidUseOfObject(Use->getUser(), isCOWObject, FindStringCall))
       return false;
   }
@@ -1257,7 +1262,7 @@
     return;
 
   // Is there a store for all tail allocated elements?
-  for (SILValue V : TailStores) {
+  for (auto V : TailStores) {
     if (!V)
       return;
   }
@@ -1278,10 +1283,10 @@
   StaticInitCloner Cloner(Glob);
   for (VarDecl *Field : Fields) {
     StoreInst *MemberStore = MemberStores[Field];
-    Cloner.add(cast<SILInstruction>(MemberStore->getSrc()));
+    Cloner.add(cast<SingleValueInstruction>(MemberStore->getSrc()));
   }
   for (StoreInst *TailStore : TailStores) {
-    Cloner.add(cast<SILInstruction>(TailStore->getSrc()));
+    Cloner.add(cast<SingleValueInstruction>(TailStore->getSrc()));
   }
 
   // Create the class property initializers
@@ -1290,14 +1295,14 @@
     StoreInst *MemberStore = MemberStores[Field];
     assert(MemberStore);
     ObjectArgs.push_back(Cloner.clone(
-                                 cast<SILInstruction>(MemberStore->getSrc())));
+                           cast<SingleValueInstruction>(MemberStore->getSrc())));
     MemberStore->eraseFromParent();
   }
   // Create the initializers for the tail elements.
   unsigned NumBaseElements = ObjectArgs.size();
   for (StoreInst *TailStore : TailStores) {
     ObjectArgs.push_back(Cloner.clone(
-                                   cast<SILInstruction>(TailStore->getSrc())));
+                           cast<SingleValueInstruction>(TailStore->getSrc())));
     TailStore->eraseFromParent();
   }
   // Create the initializer for the object itself.
@@ -1313,7 +1318,7 @@
     Operand *Use = *ARI->use_begin();
     SILInstruction *User = Use->getUser();
     switch (User->getKind()) {
-      case ValueKind::DeallocRefInst:
+      case SILInstructionKind::DeallocRefInst:
         User->eraseFromParent();
         break;
       default:
diff --git a/lib/SILOptimizer/IPO/GlobalPropertyOpt.cpp b/lib/SILOptimizer/IPO/GlobalPropertyOpt.cpp
index b455452..6b86ad1 100644
--- a/lib/SILOptimizer/IPO/GlobalPropertyOpt.cpp
+++ b/lib/SILOptimizer/IPO/GlobalPropertyOpt.cpp
@@ -72,7 +72,7 @@
         return os << "field " << entry.Field->getName() << '\n';
       if (!entry.Value)
         return os << "unknown-address\n";
-      if (auto *Inst = dyn_cast<SILInstruction>(entry.Value))
+      if (auto *Inst = entry.Value->getDefiningInstruction())
         return os << Inst->getFunction()->getName() << ": " << entry.Value;
       if (auto *Arg = dyn_cast<SILArgument>(entry.Value))
         return os << Arg->getFunction()->getName() << ": " << entry.Value;
@@ -260,13 +260,14 @@
       // We don't handle these instructions if we see them in store addresses.
       // So going through them lets stores be as bad as if the address would
       // escape.
-      if (canAddressEscape(User, false))
+      auto value = cast<SingleValueInstruction>(User);
+      if (canAddressEscape(value, false))
         return true;
       continue;
     }
-    if (isa<MarkDependenceInst>(User)) {
+    if (auto markDependence = dyn_cast<MarkDependenceInst>(User)) {
       unsigned opNum = UI->getOperandNumber();
-      if (opNum == 0 && canAddressEscape(User, acceptStore))
+      if (opNum == 0 && canAddressEscape(markDependence, acceptStore))
         return true;
       continue;
     }
@@ -321,11 +322,12 @@
       return;
     }
   } else if (isa<RefElementAddrInst>(Inst) || isa<StructElementAddrInst>(Inst)) {
-    if (isArrayAddressType(Inst->getType())) {
+    auto projection = cast<SingleValueInstruction>(Inst);
+    if (isArrayAddressType(projection->getType())) {
       // If the address of an array-field escapes, we give up for that field.
-      if (canAddressEscape(Inst, true)) {
-        setAddressEscapes(getAddrEntry(Inst));
-        DEBUG(llvm::dbgs() << "      field address escapes: " << *Inst);
+      if (canAddressEscape(projection, true)) {
+        setAddressEscapes(getAddrEntry(projection));
+        DEBUG(llvm::dbgs() << "      field address escapes: " << *projection);
       }
       return;
     }
@@ -375,10 +377,12 @@
 
   // For everything else which we didn't handle above: we set the property of
   // the instruction value to false.
-  if (SILType Type = Inst->getType()) {
+  for (auto result : Inst->getResults()) {
+    SILType Type = result->getType();
     if (isArrayType(Type) || isTupleWithArray(Type.getSwiftRValueType())) {
-      DEBUG(llvm::dbgs() << "      value could be non-native array: " << *Inst);
-      setNotNative(getValueEntry(Inst));
+      DEBUG(llvm::dbgs() << "      value could be non-native array: "
+                         << *result);
+      setNotNative(getValueEntry(result));
     }
   }
 }
diff --git a/lib/SILOptimizer/IPO/LetPropertiesOpts.cpp b/lib/SILOptimizer/IPO/LetPropertiesOpts.cpp
index b9d026d..775fbcb 100644
--- a/lib/SILOptimizer/IPO/LetPropertiesOpts.cpp
+++ b/lib/SILOptimizer/IPO/LetPropertiesOpts.cpp
@@ -32,6 +32,18 @@
 using namespace swift;
 
 namespace {
+
+using InstructionList = SmallVector<SILInstruction *, 8>;
+
+struct InitSequence {
+  InstructionList Instructions;
+  SILValue Result;
+
+  bool isValid() const {
+    return (bool) Result;
+  }
+};
+
 /// Promote values of non-static let properties initialized by means
 /// of constant values of simple types into their uses.
 ///
@@ -44,15 +56,14 @@
 class LetPropertiesOpt {
   SILModule *Module;
 
-  typedef SmallVector<SILInstruction *, 8> Instructions;
   typedef SmallVector<VarDecl *, 4> Properties;
 
   llvm::SetVector<SILFunction *> ChangedFunctions;
 
   // Map each let property to a set of instructions accessing it.
-  llvm::MapVector<VarDecl *, Instructions> AccessMap;
+  llvm::MapVector<VarDecl *, InstructionList> AccessMap;
   // Map each let property to the instruction sequence which initializes it.
-  llvm::MapVector<VarDecl *, Instructions> InitMap;
+  llvm::MapVector<VarDecl *, InitSequence> InitMap;
   // Properties in this set should not be processed by this pass
   // anymore.
   llvm::SmallPtrSet<VarDecl *, 16> SkipProcessing;
@@ -76,51 +87,44 @@
   bool isConstantLetProperty(VarDecl *Property);
   void collectPropertyAccess(SILInstruction *I, VarDecl *Property, bool NonRemovable);
   void collectStructPropertiesAccess(StructInst *SI, bool NonRemovable);
-  void optimizeLetPropertyAccess(VarDecl *SILG,
-                                 SmallVectorImpl<SILInstruction *> &Init);
+  void optimizeLetPropertyAccess(VarDecl *SILG, const InitSequence &Init);
   bool analyzeInitValue(SILInstruction *I, VarDecl *Prop);
 };
 
 /// Helper class to copy only a set of SIL instructions providing in the
 /// constructor.
-class InstructionsCloner : public SILClonerWithScopes<InstructionsCloner> {
-  friend class SILVisitor<InstructionsCloner>;
-  friend class SILCloner<InstructionsCloner>;
+class InitSequenceCloner : public SILClonerWithScopes<InitSequenceCloner> {
+  friend class SILInstructionVisitor<InitSequenceCloner>;
+  friend class SILCloner<InitSequenceCloner>;
 
-  ArrayRef<SILInstruction *> Insns;
+  const InitSequence &Init;
+  SILInstruction *DestIP;
 
-  protected:
-  SILBasicBlock *FromBB;
-  SILInstruction *Dest;
-
-  public:
-  // A map of old to new available values.
-  SmallVector<std::pair<ValueBase *, SILValue>, 16> AvailVals;
-
-  InstructionsCloner(SILFunction &F, ArrayRef<SILInstruction *> Insns,
-                     SILInstruction *Dest = nullptr)
-      : SILClonerWithScopes(Dest ? *Dest->getFunction() : F), Insns(Insns),
-        FromBB(nullptr), Dest(Dest) {}
+public:
+  InitSequenceCloner(const InitSequence &init, SILInstruction *destIP)
+    : SILClonerWithScopes(*destIP->getFunction()), Init(init), DestIP(destIP) {}
 
   void process(SILInstruction *I) { visit(I); }
 
   SILBasicBlock *remapBasicBlock(SILBasicBlock *BB) { return BB; }
 
   SILValue remapValue(SILValue Value) {
-    return SILCloner<InstructionsCloner>::remapValue(Value);
+    return SILCloner<InitSequenceCloner>::remapValue(Value);
   }
 
-  void postProcess(SILInstruction *Orig, SILInstruction *Cloned) {
-    Dest->getParent()->push_front(Cloned);
-    Cloned->moveBefore(Dest);
-    SILClonerWithScopes<InstructionsCloner>::postProcess(Orig, Cloned);
-    AvailVals.push_back(std::make_pair(Orig, Cloned));
+  void postProcess(SILInstruction *orig, SILInstruction *cloned) {
+    DestIP->getParent()->push_front(cloned);
+    cloned->moveBefore(DestIP);
+    SILClonerWithScopes<InitSequenceCloner>::postProcess(orig, cloned);
   }
 
-  // Clone all instructions from Insns into DestBB
-  void clone() {
-    for (auto I : Insns)
+  /// Clone all the instructions from Insns into the destination function,
+  /// immediately before the destination block, and return the value of
+  /// the result.
+  SILValue clone() {
+    for (auto I : Init.Instructions)
       process(I);
+    return remapValue(Init.Result);
   }
 };
 
@@ -141,14 +145,12 @@
 /// to have a constant value. Replace all loads from the
 /// property by its constant value.
 void LetPropertiesOpt::optimizeLetPropertyAccess(VarDecl *Property,
-    SmallVectorImpl<SILInstruction *> &Init) {
+                                                 const InitSequence &init) {
+  assert(init.isValid());
 
   if (SkipProcessing.count(Property))
     return;
 
-  if (Init.empty())
-    return;
-
   auto *Ty = dyn_cast<NominalTypeDecl>(Property->getDeclContext());
   if (SkipTypeProcessing.count(Ty))
     return;
@@ -191,55 +193,56 @@
   for (auto Load: Loads) {
     SILFunction *F = Load->getFunction();
 
+    // A helper function to copy the initializer into the target function
+    // at the target insertion point.
+    auto cloneInitAt = [&](SILInstruction *insertionPoint) -> SILValue {
+      InitSequenceCloner cloner(init, insertionPoint);
+      return cloner.clone();
+    };
+
     // Look for any instructions accessing let properties.
-    if (isa<RefElementAddrInst>(Load)) {
+    if (auto proj = dyn_cast<RefElementAddrInst>(Load)) {
       // Copy the initializer into the function
       // Replace the access to a let property by the value
       // computed by this initializer.
-      InstructionsCloner Cloner(*F, Init, Load);
-      Cloner.clone();
-      SILInstruction *I = &*std::prev(Load->getIterator());
-      SILBuilderWithScope B(Load);
-      for (auto UI = Load->use_begin(), E = Load->use_end(); UI != E;) {
+      SILValue clonedInit = cloneInitAt(proj);
+      SILBuilderWithScope B(proj);
+      for (auto UI = proj->use_begin(), E = proj->use_end(); UI != E;) {
         auto *User = UI->getUser();
         ++UI;
         if (isa<StoreInst>(User))
           continue;
 
-        replaceLoadSequence(User, I, B);
+        replaceLoadSequence(User, clonedInit, B);
         eraseUsesOfInstruction(User);
         User->eraseFromParent();
         ++NumReplaced;
       }
       ChangedFunctions.insert(F);
-    } else if (isa<StructExtractInst>(Load)) {
+    } else if (auto proj = dyn_cast<StructExtractInst>(Load)) {
       // Copy the initializer into the function
       // Replace the access to a let property by the value
       // computed by this initializer.
-      InstructionsCloner Cloner(*F, Init, Load);
-      Cloner.clone();
-      SILInstruction *I = &*std::prev(Load->getIterator());
-      Load->replaceAllUsesWith(I);
+      SILValue clonedInit = cloneInitAt(proj);
+      proj->replaceAllUsesWith(clonedInit);
       DEBUG(llvm::dbgs() << "Access to " << *Property << " was replaced:\n";
-            I->dumpInContext());
+            clonedInit->dumpInContext());
 
-      Load->eraseFromParent();
+      proj->eraseFromParent();
       ++NumReplaced;
       ChangedFunctions.insert(F);
-    }  else if (isa<StructElementAddrInst>(Load)) {
+    }  else if (auto proj = dyn_cast<StructElementAddrInst>(Load)) {
       // Copy the initializer into the function
       // Replace the access to a let property by the value
       // computed by this initializer.
-      InstructionsCloner Cloner(*F, Init, Load);
-      Cloner.clone();
-      SILInstruction *I = &*std::prev(Load->getIterator());
-      SILBuilderWithScope B(Load);
-      for (auto UI = Load->use_begin(), E = Load->use_end(); UI != E;) {
+      SILValue clonedInit = cloneInitAt(proj);
+      SILBuilderWithScope B(proj);
+      for (auto UI = proj->use_begin(), E = proj->use_end(); UI != E;) {
         auto *User = UI->getUser();
         ++UI;
         if (isa<StoreInst>(User))
           continue;
-        replaceLoadSequence(User, I, B);
+        replaceLoadSequence(User, clonedInit, B);
         eraseUsesOfInstruction(User);
         User->eraseFromParent();
         ++NumReplaced;
@@ -256,25 +259,32 @@
   }
 }
 
-/// Compare to SILValues structurally.
-static bool CmpSILValues(SILValue LHS, SILValue RHS) {
+/// Compare two SILValues structurally.
+static bool isStructurallyIdentical(SILValue LHS, SILValue RHS) {
+  if (LHS == RHS)
+    return true;
+
   if (LHS->getType() != RHS->getType())
     return false;
 
-  auto L = dyn_cast<SILInstruction>(LHS);
-  return L->isIdenticalTo(dyn_cast<SILInstruction>(RHS), CmpSILValues);
+  auto lResult = LHS->getDefiningInstructionResult();
+  auto rResult = RHS->getDefiningInstructionResult();
+  assert(lResult && rResult &&
+         "operands of instructions approved by analyzeStaticInitializer "
+         "should always be defined by instructions");
+  return (lResult->ResultIndex == rResult->ResultIndex &&
+          lResult->Instruction->isIdenticalTo(rResult->Instruction,
+                                              isStructurallyIdentical));
 };
 
-/// Compare two sequences of SIL instructions. They should be structurally equivalent.
-static bool compareInsnSequences(SmallVectorImpl<SILInstruction *> &LHS,
-                                 SmallVectorImpl<SILInstruction *> &RHS) {
-  if (LHS.size() != RHS.size())
-    return false;
-
-  for (int i=0, e=LHS.size(); i < e; ++i)
-    if (!LHS[i]->isIdenticalTo(RHS[i], CmpSILValues))
-      return false;
-  return true;
+/// Compare two sequences of SIL instructions. They should be structurally
+/// equivalent.
+static bool isSameInitSequence(const InitSequence &LHS,
+                               const InitSequence &RHS) {
+  assert(LHS.isValid() && RHS.isValid());
+  // This will recursively check all the instructions.  It's possible
+  // that they'll be composed slightly differently, but it shouldn't matter.
+  return isStructurallyIdentical(LHS.Result, RHS.Result);
 }
 
 /// Check if a given let property can be assigned externally.
@@ -407,11 +417,10 @@
 // Analyze the init value being stored by the instruction into a property.
 bool
 LetPropertiesOpt::analyzeInitValue(SILInstruction *I, VarDecl *Property) {
-  SmallVector<SILInstruction *, 8> Insns;
   SmallVector<SILInstruction *, 8> ReverseInsns;
-  SILValue ValueOfProperty;
+  SILValue value;
   if (auto SI = dyn_cast<StructInst>(I)) {
-    ValueOfProperty = SI->getFieldValue(Property);
+    value = SI->getFieldValue(Property);
   } else if (auto SI = dyn_cast<StoreInst>(I)) {
     auto Dest = SI->getDest();
 
@@ -421,27 +430,31 @@
              cast<StructElementAddrInst>(Dest)->getField() == Property)) &&
            "Store instruction should store into a proper let property");
     (void) Dest;
-    ValueOfProperty = SI->getSrc();
+    value = SI->getSrc();
   }
 
   // Bail if a value of a property is not a statically known constant init.
-  if (!analyzeStaticInitializer(ValueOfProperty, ReverseInsns))
+  if (!analyzeStaticInitializer(value, ReverseInsns))
     return false;
 
-  // Produce a correct order of instructions.
+  // Fill in the InitSequence by reversing the instructions and
+  // setting the result index.
+  InitSequence sequence;
   while (!ReverseInsns.empty()) {
-    Insns.push_back(ReverseInsns.pop_back_val());
+    sequence.Instructions.push_back(ReverseInsns.pop_back_val());
   }
+  sequence.Result = value;
 
-  auto &InitInsns = InitMap[Property];
-  if (!InitInsns.empty() && !compareInsnSequences(InitInsns, Insns)) {
+  auto &cachedSequence = InitMap[Property];
+  if (cachedSequence.isValid() &&
+      !isSameInitSequence(cachedSequence, sequence)) {
     // The found init value is different from the already seen init value.
     return false;
   } else {
     DEBUG(llvm::dbgs() << "The value of property '" << *Property
                        << "' is statically known so far\n");
     // Remember the statically known value.
-    InitInsns = Insns;
+    cachedSequence = std::move(sequence);
     return true;
   }
 }
@@ -510,7 +523,8 @@
     return true;
 
   if (isa<StructElementAddrInst>(I) || isa<TupleElementAddrInst>(I)) {
-    for (auto Use : getNonDebugUses(I))
+    auto projection = cast<SingleValueInstruction>(I);
+    for (auto Use : getNonDebugUses(projection))
       if (!isValidPropertyLoad(Use->getUser()))
         return false;
     return true;
@@ -533,14 +547,15 @@
 
   if (isa<RefElementAddrInst>(I) || isa<StructElementAddrInst>(I)) {
     // Check if there is a store to this property.
-    for (auto Use : getNonDebugUses(I)) {
+    auto projection = cast<SingleValueInstruction>(I);
+    for (auto Use : getNonDebugUses(projection)) {
       auto *User = Use->getUser();
 
       if (auto *SI = dyn_cast<StoreInst>(User)) {
         // There is a store into this property.
         // Analyze the assigned value and check if it is a constant
         // statically known initializer.
-        if (SI->getDest() != I || !analyzeInitValue(SI, Property)) {
+        if (SI->getDest() != projection || !analyzeInitValue(SI, Property)) {
           SkipProcessing.insert(Property);
           return;
         }
diff --git a/lib/SILOptimizer/IPO/UsePrespecialized.cpp b/lib/SILOptimizer/IPO/UsePrespecialized.cpp
index c766e15..b9d6b30 100644
--- a/lib/SILOptimizer/IPO/UsePrespecialized.cpp
+++ b/lib/SILOptimizer/IPO/UsePrespecialized.cpp
@@ -140,7 +140,13 @@
                        << " : " << NewF->getName() << "\n");
 
     auto NewAI = replaceWithSpecializedFunction(AI, NewF, ReInfo);
-    AI.getInstruction()->replaceAllUsesWith(NewAI.getInstruction());
+    if (auto oldApply = dyn_cast<ApplyInst>(AI)) {
+      oldApply->replaceAllUsesWith(cast<ApplyInst>(NewAI));
+    } else if (auto oldPApply = dyn_cast<PartialApplyInst>(AI)) {
+      oldPApply->replaceAllUsesWith(cast<PartialApplyInst>(NewAI));
+    } else {
+      assert(isa<TryApplyInst>(NewAI));
+    }
     recursivelyDeleteTriviallyDeadInstructions(AI.getInstruction(), true);
     Changed = true;
   }
diff --git a/lib/SILOptimizer/LoopTransforms/ArrayBoundsCheckOpts.cpp b/lib/SILOptimizer/LoopTransforms/ArrayBoundsCheckOpts.cpp
index a53289c..e927083 100644
--- a/lib/SILOptimizer/LoopTransforms/ArrayBoundsCheckOpts.cpp
+++ b/lib/SILOptimizer/LoopTransforms/ArrayBoundsCheckOpts.cpp
@@ -483,8 +483,8 @@
   return Changed;
 }
 
-static CondFailInst *hasCondFailUse(SILInstruction *I) {
-    for (auto *Op : I->getUses())
+static CondFailInst *hasCondFailUse(SILValue V) {
+    for (auto *Op : V->getUses())
       if (auto C = dyn_cast<CondFailInst>(Op->getUser()))
         return C;
     return nullptr;
@@ -935,7 +935,7 @@
     // Get the first induction value.
     auto FirstVal = Ind->getFirstValue();
     // Clone the struct for the start index.
-    auto Start = cast<SILInstruction>(CheckToHoist.getIndex())
+    auto Start = cast<SingleValueInstruction>(CheckToHoist.getIndex())
                      ->clone(Preheader->getTerminator());
     // Set the new start index to the first value of the induction.
     Start->setOperand(0, FirstVal);
@@ -947,7 +947,7 @@
     // Get the last induction value.
     auto LastVal = Ind->getLastValue(Loc, Builder);
     // Clone the struct for the end index.
-    auto End = cast<SILInstruction>(CheckToHoist.getIndex())
+    auto End = cast<SingleValueInstruction>(CheckToHoist.getIndex())
                    ->clone(Preheader->getTerminator());
     // Set the new end index to the last value of the induction.
     End->setOperand(0, LastVal);
@@ -1073,7 +1073,7 @@
 /// A dominating cond_fail on the same value ensures that this value is false.
 static bool isValueKnownFalseAt(SILValue Val, SILInstruction *At,
                                 DominanceInfo *DT) {
-  auto *Inst = dyn_cast<SILInstruction>(Val);
+  auto *Inst = Val->getDefiningInstruction();
   if (!Inst ||
       std::next(SILBasicBlock::iterator(Inst)) == Inst->getParent()->end())
     return false;
diff --git a/lib/SILOptimizer/LoopTransforms/COWArrayOpt.cpp b/lib/SILOptimizer/LoopTransforms/COWArrayOpt.cpp
index 359dec8..b7267e7 100644
--- a/lib/SILOptimizer/LoopTransforms/COWArrayOpt.cpp
+++ b/lib/SILOptimizer/LoopTransforms/COWArrayOpt.cpp
@@ -53,7 +53,7 @@
 static SILValue getAccessPath(SILValue V, SmallVectorImpl<unsigned>& Path) {
   V = stripCasts(V);
   ProjectionIndex PI(V);
-  if (!PI.isValid() || V->getKind() == ValueKind::IndexAddrInst)
+  if (!PI.isValid() || isa<IndexAddrInst>(V))
     return V;
 
   SILValue UnderlyingObject = getAccessPath(PI.Aggregate, Path);
@@ -100,10 +100,10 @@
 
   UserList AggregateAddressUsers;
   UserList StructAddressUsers;
-  UserList StructLoads;
+  SmallVector<LoadInst*, 16> StructLoads;
   UserList StructValueUsers;
   UserOperList ElementAddressUsers;
-  UserOperList ElementLoads;
+  SmallVector<std::pair<LoadInst*, Operand*>, 16> ElementLoads;
   UserOperList ElementValueUsers;
   VisitedSet Visited;
 
@@ -140,11 +140,7 @@
 protected:
 
   static bool definesSingleObjectType(ValueBase *V) {
-    if (auto *Arg = dyn_cast<SILArgument>(V))
-      return Arg->getType().isObject();
-    if (auto *Inst = dyn_cast<SILInstruction>(V))
-      return Inst->hasValue() && Inst->getType().isObject();
-    return false;
+    return V->getType().isObject();
   }
 
   /// If AccessPathSuffix is non-empty, then the value is the address of an
@@ -170,8 +166,8 @@
           continue;
         }
 
-        if (isa<StructElementAddrInst>(UseInst)) {
-          collectAddressUses(UseInst, AccessPathSuffix, StructVal);
+        if (auto proj = dyn_cast<StructElementAddrInst>(UseInst)) {
+          collectAddressUses(proj, AccessPathSuffix, StructVal);
           continue;
         }
 
@@ -186,8 +182,8 @@
           continue;
         }
 
-        if (isa<StructElementAddrInst>(UseInst)) {
-          collectAddressUses(UseInst, AccessPathSuffix, &*UI);
+        if (auto proj = dyn_cast<StructElementAddrInst>(UseInst)) {
+          collectAddressUses(proj, AccessPathSuffix, &*UI);
           continue;
         }
 
@@ -201,10 +197,18 @@
         continue;
       }
 
-      ProjectionIndex PI(UseInst);
+      // Check for uses of projections.
+
+      // These are all single-value instructions.
+      auto ProjInst = dyn_cast<SingleValueInstruction>(UseInst);
+      if (!ProjInst) {
+        AggregateAddressUsers.push_back(UseInst);
+        continue;
+      }
+      ProjectionIndex PI(ProjInst);
       // Do not form a path from an IndexAddrInst without otherwise
       // distinguishing it from subelement addressing.
-      if (!PI.isValid() || V->getKind() == ValueKind::IndexAddrInst) {
+      if (!PI.isValid() || isa<IndexAddrInst>(V)) {
         // Found a use of an aggregate containing the given element.
         AggregateAddressUsers.push_back(UseInst);
         continue;
@@ -220,7 +224,7 @@
 
       // Recursively check for users after stripping this component from the
       // access path.
-      collectAddressUses(UseInst, AccessPathSuffix.slice(1), nullptr);
+      collectAddressUses(ProjInst, AccessPathSuffix.slice(1), nullptr);
     }
   }
 };
@@ -631,20 +635,19 @@
 
 /// Returns true if this instruction is a safe array use if all of its users are
 /// also safe array users.
-static bool isTransitiveSafeUser(SILInstruction *I) {
+static SILValue isTransitiveSafeUser(SILInstruction *I) {
   switch (I->getKind()) {
-  case ValueKind::StructExtractInst:
-  case ValueKind::TupleExtractInst:
-  case ValueKind::UncheckedEnumDataInst:
-  case ValueKind::StructInst:
-  case ValueKind::TupleInst:
-  case ValueKind::EnumInst:
-  case ValueKind::UncheckedRefCastInst:
-  case ValueKind::UncheckedBitwiseCastInst:
-    assert(I->hasValue() && "We assume these are unary");
-    return true;
+  case SILInstructionKind::StructExtractInst:
+  case SILInstructionKind::TupleExtractInst:
+  case SILInstructionKind::UncheckedEnumDataInst:
+  case SILInstructionKind::StructInst:
+  case SILInstructionKind::TupleInst:
+  case SILInstructionKind::EnumInst:
+  case SILInstructionKind::UncheckedRefCastInst:
+  case SILInstructionKind::UncheckedBitwiseCastInst:
+    return cast<SingleValueInstruction>(I);
   default:
-    return false;
+    return nullptr;
   }
 }
 
@@ -667,8 +670,8 @@
     /// Is this a unary transitive safe user instruction. This means that the
     /// instruction is safe only if all of its users are safe. Check this
     /// recursively.
-    if (isTransitiveSafeUser(UseInst)) {
-      if (std::all_of(UseInst->use_begin(), UseInst->use_end(),
+    if (auto inst = isTransitiveSafeUser(UseInst)) {
+      if (std::all_of(inst->use_begin(), inst->use_end(),
                       [this](Operand *Op) -> bool {
                         return checkSafeArrayElementUse(Op->getUser(),
                                                         Op->get());
@@ -765,8 +768,8 @@
   // all of its users are safe array element uses, recursively check its uses
   // and return false if any of them are not transitive escape array element
   // uses.
-  if (isTransitiveSafeUser(UseInst)) {
-    return std::all_of(UseInst->use_begin(), UseInst->use_end(),
+  if (auto result = isTransitiveSafeUser(UseInst)) {
+    return std::all_of(result->use_begin(), result->use_end(),
                        [this, &ArrayVal](Operand *UI) -> bool {
                          return checkSafeArrayElementUse(UI->getUser(),
                                                          ArrayVal);
@@ -874,7 +877,8 @@
       return false;
     StartInst = ASI;
   } else {
-    StartInst = cast<SILInstruction>(V);
+    // True because of the caller.
+    StartInst = V->getDefiningInstruction();
   }
   for (auto II = std::next(SILBasicBlock::iterator(StartInst)),
             IE = StartInst->getParent()->end();
@@ -936,9 +940,9 @@
 static SILValue
 stripValueProjections(SILValue V,
                       SmallVectorImpl<SILInstruction *> &ValuePrjs) {
-  while (V->getKind() == ValueKind::StructExtractInst) {
-    ValuePrjs.push_back(cast<SILInstruction>(V));
-    V = cast<SILInstruction>(V)->getOperand(0);
+  while (auto SEI = dyn_cast<StructExtractInst>(V)) {
+    ValuePrjs.push_back(SEI);
+    V = SEI->getOperand();
   }
   return V;
 }
@@ -1232,8 +1236,9 @@
         // are release before we hit a make_unique instruction.
         ApplyInst *SemCall = Sem;
         if (Sem.getKind() == ArrayCallKind::kGetElement) {
-          SILValue Elem = (Sem.hasGetElementDirectResult() ? Inst :
-                           SemCall->getArgument(0));
+          SILValue Elem = (Sem.hasGetElementDirectResult()
+                            ? Sem.getCallResult()
+                            : SemCall->getArgument(0));
           if (!Elem->getType().isTrivial(Module))
             CreatedNonTrivialValues.insert(Elem);
         } else if (Sem.getKind() == ArrayCallKind::kMakeMutable) {
@@ -1933,7 +1938,7 @@
   SILBasicBlock *StartBB;
   SmallPtrSet<SILBasicBlock *, 16> OutsideBBs;
 
-  friend class SILVisitor<RegionCloner>;
+  friend class SILInstructionVisitor<RegionCloner>;
   friend class SILCloner<RegionCloner>;
 
 public:
@@ -2086,7 +2091,8 @@
 
       // Update outside used instruction values.
       for (auto &Inst : *OrigBB) {
-        updateSSAForValue(OrigBB, &Inst, SSAUp);
+        for (auto result : Inst.getResults())
+          updateSSAForValue(OrigBB, result, SSAUp);
       }
     }
   }
@@ -2213,6 +2219,24 @@
   C.removeCall();
 }
 
+/// Collects all loop dominated blocks outside the loop that are immediately
+/// dominated by the loop.
+static void
+collectImmediateLoopDominatedBlocks(const SILLoop *Lp, DominanceInfoNode *Node,
+                                    SmallVectorImpl<SILBasicBlock *> &Blocks) {
+  SILBasicBlock *BB = Node->getBlock();
+
+  // Base case: First loop dominated block outside of loop.
+  if (!Lp->contains(BB)) {
+    Blocks.push_back(BB);
+    return;
+  }
+
+  // Loop contains the basic block. Look at immediately dominated nodes.
+  for (auto *Child : *Node)
+    collectImmediateLoopDominatedBlocks(Lp, Child, Blocks);
+}
+
 void ArrayPropertiesSpecializer::specializeLoopNest() {
   auto *Lp = getLoop();
   assert(Lp);
@@ -2225,22 +2249,19 @@
   auto *CheckBlock = splitBasicBlockAndBranch(B,
       HoistableLoopPreheader->getTerminator(), DomTree, nullptr);
 
-  // Get the exit blocks of the original loop.
   auto *Header = CheckBlock->getSingleSuccessorBlock();
   assert(Header);
 
-  // Our loop info is not really completely valid anymore since the cloner does
-  // not update it. However, exit blocks of the original loop are still valid.
+  // Collect all loop dominated blocks (e.g exit blocks could be among them). We
+  // need to update their dominator.
+  SmallVector<SILBasicBlock *, 16> LoopDominatedBlocks;
+  collectImmediateLoopDominatedBlocks(Lp, DomTree->getNode(Header),
+                                      LoopDominatedBlocks);
+
+  // Collect all exit blocks.
   SmallVector<SILBasicBlock *, 16> ExitBlocks;
   Lp->getExitBlocks(ExitBlocks);
 
-  // Collect the exit blocks dominated by the loop - they will be dominated by
-  // the check block.
-  SmallVector<SILBasicBlock *, 16> ExitBlocksDominatedByPreheader;
-  for (auto *ExitBlock: ExitBlocks)
-    if (DomTree->dominates(CheckBlock, ExitBlock))
-      ExitBlocksDominatedByPreheader.push_back(ExitBlock);
-
   // Split the preheader before the first instruction.
   SILBasicBlock *NewPreheader =
     splitBasicBlockAndBranch(B, &*CheckBlock->begin(), DomTree, nullptr);
@@ -2269,8 +2290,8 @@
                      IsFastNativeArray, ClonedPreheader, NewPreheader);
   CheckBlock->getTerminator()->eraseFromParent();
 
-  // Fixup the exit blocks. They are now dominated by the check block.
-  for (auto *BB : ExitBlocksDominatedByPreheader)
+  // Fixup the loop dominated blocks. They are now dominated by the check block.
+  for (auto *BB : LoopDominatedBlocks)
     DomTree->changeImmediateDominator(DomTree->getNode(BB),
                                       DomTree->getNode(CheckBlock));
 
diff --git a/lib/SILOptimizer/LoopTransforms/LICM.cpp b/lib/SILOptimizer/LoopTransforms/LICM.cpp
index 29bbf18..9820f24 100644
--- a/lib/SILOptimizer/LoopTransforms/LICM.cpp
+++ b/lib/SILOptimizer/LoopTransforms/LICM.cpp
@@ -115,7 +115,7 @@
     ValueBase *Def = Op.get();
 
     // Operand is defined outside the loop.
-    if (auto *Inst = dyn_cast<SILInstruction>(Def))
+    if (auto *Inst = Def->getDefiningInstruction())
       return !L->contains(Inst->getParent());
     if (auto *Arg = dyn_cast<SILArgument>(Def))
       return !L->contains(Arg->getParent());
diff --git a/lib/SILOptimizer/LoopTransforms/LoopRotate.cpp b/lib/SILOptimizer/LoopTransforms/LoopRotate.cpp
index 8723cc4..aca1f15 100644
--- a/lib/SILOptimizer/LoopTransforms/LoopRotate.cpp
+++ b/lib/SILOptimizer/LoopTransforms/LoopRotate.cpp
@@ -42,7 +42,7 @@
 
     ValueBase *Def = Op.get();
     // Operand is outside the loop or marked invariant.
-    if (auto *Inst = dyn_cast<SILInstruction>(Def))
+    if (auto *Inst = Def->getDefiningInstruction())
       return !L->contains(Inst->getParent()) || Inv.count(Inst);
     if (auto *Arg = dyn_cast<SILArgument>(Def))
       return !L->contains(Arg->getParent());
@@ -101,61 +101,64 @@
   }
 }
 
+static void updateSSAForUseOfValue(
+    SILSSAUpdater &Updater, SmallVectorImpl<SILPHIArgument *> &InsertedPHIs,
+    const llvm::DenseMap<ValueBase *, SILValue> &ValueMap,
+    SILBasicBlock *Header, SILBasicBlock *EntryCheckBlock,
+    SILValue Res) {
+  // Find the mapped instruction.
+  assert(ValueMap.count(Res) && "Expected to find value in map!");
+  SILValue MappedValue = ValueMap.find(Res)->second;
+  assert(MappedValue);
+  assert(Res->getType() == MappedValue->getType() && "The types must match");
+
+  InsertedPHIs.clear();
+  Updater.Initialize(Res->getType());
+  Updater.AddAvailableValue(Header, Res);
+  Updater.AddAvailableValue(EntryCheckBlock, MappedValue);
+
+
+  // Because of the way that phi nodes are represented we have to collect all
+  // uses before we update SSA. Modifying one phi node can invalidate another
+  // unrelated phi nodes operands through the common branch instruction (that
+  // has to be modified). This would invalidate a plain ValueUseIterator.
+  // Instead we collect uses wrapping uses in branches specially so that we
+  // can reconstruct the use even after the branch has been modified.
+  SmallVector<UseWrapper, 8> StoredUses;
+  for (auto *U : Res->getUses())
+    StoredUses.push_back(UseWrapper(U));
+  for (auto U : StoredUses) {
+    Operand *Use = U;
+    SILInstruction *User = Use->getUser();
+    assert(User && "Missing user");
+
+    // Ignore uses in the same basic block.
+    if (User->getParent() == Header)
+      continue;
+
+    assert(User->getParent() != EntryCheckBlock &&
+           "The entry check block should dominate the header");
+    Updater.RewriteUse(*Use);
+  }
+  // Canonicalize inserted phis to avoid extra BB Args.
+  for (SILPHIArgument *Arg : InsertedPHIs) {
+    if (SILValue Inst = replaceBBArgWithCast(Arg)) {
+      Arg->replaceAllUsesWith(Inst);
+      // DCE+SimplifyCFG runs as a post-pass cleanup.
+      // DCE replaces dead arg values with undef.
+      // SimplifyCFG deletes the dead BB arg.
+    }
+  }
+}
+
 static void updateSSAForUseOfInst(
     SILSSAUpdater &Updater, SmallVectorImpl<SILPHIArgument *> &InsertedPHIs,
     const llvm::DenseMap<ValueBase *, SILValue> &ValueMap,
-    SILBasicBlock *Header, SILBasicBlock *EntryCheckBlock, ValueBase *Inst) {
-  if (Inst->use_empty())
-    return;
-
-  // Find the mapped instruction.
-  assert(ValueMap.count(Inst) && "Expected to find value in map!");
-  SILValue MappedValue = ValueMap.find(Inst)->second;
-  assert(MappedValue);
-
-  // For each use of a specific result value of the instruction.
-  if (Inst->hasValue()) {
-    SILValue Res(Inst);
-    assert(Res->getType() == MappedValue->getType() && "The types must match");
-
-    InsertedPHIs.clear();
-    Updater.Initialize(Res->getType());
-    Updater.AddAvailableValue(Header, Res);
-    Updater.AddAvailableValue(EntryCheckBlock, MappedValue);
-
-
-    // Because of the way that phi nodes are represented we have to collect all
-    // uses before we update SSA. Modifying one phi node can invalidate another
-    // unrelated phi nodes operands through the common branch instruction (that
-    // has to be modified). This would invalidate a plain ValueUseIterator.
-    // Instead we collect uses wrapping uses in branches specially so that we
-    // can reconstruct the use even after the branch has been modified.
-    SmallVector<UseWrapper, 8> StoredUses;
-    for (auto *U : Res->getUses())
-      StoredUses.push_back(UseWrapper(U));
-    for (auto U : StoredUses) {
-      Operand *Use = U;
-      SILInstruction *User = Use->getUser();
-      assert(User && "Missing user");
-
-      // Ignore uses in the same basic block.
-      if (User->getParent() == Header)
-        continue;
-
-      assert(User->getParent() != EntryCheckBlock &&
-             "The entry check block should dominate the header");
-      Updater.RewriteUse(*Use);
-    }
-    // Canonicalize inserted phis to avoid extra BB Args.
-    for (SILPHIArgument *Arg : InsertedPHIs) {
-      if (SILInstruction *Inst = replaceBBArgWithCast(Arg)) {
-        Arg->replaceAllUsesWith(Inst);
-        // DCE+SimplifyCFG runs as a post-pass cleanup.
-        // DCE replaces dead arg values with undef.
-        // SimplifyCFG deletes the dead BB arg.
-      }
-    }
-  }
+    SILBasicBlock *Header, SILBasicBlock *EntryCheckBlock,
+    SILInstruction *Inst) {
+  for (auto result : Inst->getResults())
+    updateSSAForUseOfValue(Updater, InsertedPHIs, ValueMap, Header,
+                           EntryCheckBlock, result);
 }
 
 /// Rewrite the code we just created in the preheader and update SSA form.
@@ -167,9 +170,9 @@
   SILSSAUpdater Updater(&InsertedPHIs);
 
   // Fix PHIs (incoming arguments).
-  for (auto *Inst : Header->getArguments())
-    updateSSAForUseOfInst(Updater, InsertedPHIs, ValueMap, Header,
-                          EntryCheckBlock, Inst);
+  for (auto *Arg : Header->getArguments())
+    updateSSAForUseOfValue(Updater, InsertedPHIs, ValueMap, Header,
+                           EntryCheckBlock, Arg);
 
   auto InstIter = Header->begin();
 
@@ -345,11 +348,15 @@
   // The other instructions are just cloned to the preheader.
   TermInst *PreheaderBranch = Preheader->getTerminator();
   for (auto &Inst : *Header) {
-    if (SILInstruction *I = Inst.clone(PreheaderBranch)) {
-      mapOperands(I, ValueMap);
+    if (SILInstruction *cloned = Inst.clone(PreheaderBranch)) {
+      mapOperands(cloned, ValueMap);
 
       // The actual operand will sort out which result idx to use.
-      ValueMap[&Inst] = I;
+      auto instResults = Inst.getResults();
+      auto clonedResults = cloned->getResults();
+      assert(instResults.size() == clonedResults.size());
+      for (auto i : indices(instResults))
+        ValueMap[instResults[i]] = clonedResults[i];
     }
   }
 
diff --git a/lib/SILOptimizer/LoopTransforms/LoopUnroll.cpp b/lib/SILOptimizer/LoopTransforms/LoopUnroll.cpp
index fc93029..dd43738 100644
--- a/lib/SILOptimizer/LoopTransforms/LoopUnroll.cpp
+++ b/lib/SILOptimizer/LoopTransforms/LoopUnroll.cpp
@@ -37,7 +37,7 @@
 class LoopCloner : public SILCloner<LoopCloner> {
   SILLoop *Loop;
 
-  friend class SILVisitor<LoopCloner>;
+  friend class SILInstructionVisitor<LoopCloner>;
   friend class SILCloner<LoopCloner>;
 
 public:
@@ -51,9 +51,6 @@
   MapVector<SILBasicBlock *, SILBasicBlock *> &getBBMap() { return BBMap; }
 
   DenseMap<SILValue, SILValue> &getValueMap() { return ValueMap; }
-  DenseMap<SILInstruction *, SILInstruction *> &getInstMap() {
-    return InstructionMap;
-  }
 
 protected:
   SILValue remapValue(SILValue V) {
@@ -293,8 +290,7 @@
 /// value to live out value in the cloned loop.
 static void collectLoopLiveOutValues(
     DenseMap<SILValue, SmallVector<SILValue, 8>> &LoopLiveOutValues,
-    SILLoop *Loop, DenseMap<SILValue, SILValue> &ClonedValues,
-    DenseMap<SILInstruction *, SILInstruction *> &ClonedInstructions) {
+    SILLoop *Loop, DenseMap<SILValue, SILValue> &ClonedValues) {
   for (auto *Block : Loop->getBlocks()) {
     // Look at block arguments.
     for (auto *Arg : Block->getArguments()) {
@@ -312,15 +308,17 @@
     }
     // And the instructions.
     for (auto &Inst : *Block) {
-      for (auto *Op : Inst.getUses()) {
-        // Is this use outside the loop.
-        if (!Loop->contains(Op->getUser())) {
+      for (SILValue result : Inst.getResults()) {
+        for (auto *Op : result->getUses()) {
+          // Ignore uses inside the loop.
+          if (Loop->contains(Op->getUser()))
+            continue;
+
           auto UsedValue = Op->get();
-          assert(UsedValue == &Inst && "Instructions must match");
-          assert(ClonedInstructions.count(&Inst) && "Unmapped instruction!");
+          assert(UsedValue == result && "Instructions must match");
 
           if (!LoopLiveOutValues.count(UsedValue))
-            LoopLiveOutValues[UsedValue].push_back(ClonedInstructions[&Inst]);
+            LoopLiveOutValues[UsedValue].push_back(ClonedValues[result]);
         }
       }
     }
@@ -405,18 +403,11 @@
     // subsequent iterations we only need to update this map with the values
     // from the new iteration's clone.
     if (Cnt == 1)
-      collectLoopLiveOutValues(LoopLiveOutValues, Loop, Cloner.getValueMap(),
-                               Cloner.getInstMap());
+      collectLoopLiveOutValues(LoopLiveOutValues, Loop, Cloner.getValueMap());
     else {
       for (auto &MapEntry : LoopLiveOutValues) {
-        // If this is an argument look up the value in the value map.
-        SILValue MappedValue;
-        if (isa<SILArgument>(MapEntry.first))
-          MappedValue = Cloner.getValueMap()[MapEntry.first];
-        // Otherwise, consult the instruction map.
-        else
-          MappedValue = Cloner
-                  .getInstMap()[cast<SILInstruction>(MapEntry.first)];
+        // Look it up in the value map.
+        SILValue MappedValue = Cloner.getValueMap()[MapEntry.first];
         MapEntry.second.push_back(MappedValue);
         assert(MapEntry.second.size() == Cnt);
       }
diff --git a/lib/SILOptimizer/Mandatory/AccessEnforcementSelection.cpp b/lib/SILOptimizer/Mandatory/AccessEnforcementSelection.cpp
index 21ecd6f..2be7614 100644
--- a/lib/SILOptimizer/Mandatory/AccessEnforcementSelection.cpp
+++ b/lib/SILOptimizer/Mandatory/AccessEnforcementSelection.cpp
@@ -175,7 +175,7 @@
   void run();
 
 private:
-  void analyzeUsesOfBox(SILInstruction *source);
+  void analyzeUsesOfBox(SingleValueInstruction *source);
   void analyzeProjection(ProjectBoxInst *projection);
 
   /// Note that the given instruction is a use of the box (or a use of
@@ -214,7 +214,7 @@
 
 // FIXME: This should cover a superset of AllocBoxToStack's findUnexpectedBoxUse
 // to avoid perturbing codegen. They should be sharing the same analysis.
-void SelectEnforcement::analyzeUsesOfBox(SILInstruction *source) {
+void SelectEnforcement::analyzeUsesOfBox(SingleValueInstruction *source) {
   // Collect accesses rooted off of projections.
   for (auto use : source->getUses()) {
     auto user = use->getUser();
diff --git a/lib/SILOptimizer/Mandatory/AccessMarkerElimination.cpp b/lib/SILOptimizer/Mandatory/AccessMarkerElimination.cpp
index 456a23d..44d360f 100644
--- a/lib/SILOptimizer/Mandatory/AccessMarkerElimination.cpp
+++ b/lib/SILOptimizer/Mandatory/AccessMarkerElimination.cpp
@@ -77,7 +77,6 @@
 
     // Delete any associated end_access instructions.
     if (auto endAccess = dyn_cast<EndAccessInst>(op->getUser())) {
-      assert(endAccess->use_empty() && "found use of end_access");
       endAccess->eraseFromParent();
 
       // Forward all other uses to the original address.
@@ -123,7 +122,6 @@
     if (shouldPreserveAccess(BUA->getEnforcement()))
       return false;
 
-    BUA->replaceAllUsesWith(BUA->getSource());
     return true;
   }
   // end_unpaired_access instructions will be directly removed and
@@ -132,7 +130,6 @@
     if (shouldPreserveAccess(EUA->getEnforcement()))
       return false;
 
-    assert(EUA->use_empty() && "use of end_unpaired_access");
     return true;
   }
   return false;
diff --git a/lib/SILOptimizer/Mandatory/AddressLowering.cpp b/lib/SILOptimizer/Mandatory/AddressLowering.cpp
index 1b19f09..531bea9 100644
--- a/lib/SILOptimizer/Mandatory/AddressLowering.cpp
+++ b/lib/SILOptimizer/Mandatory/AddressLowering.cpp
@@ -112,15 +112,19 @@
 
 // Visit all call results.
 // Stop when the visitor returns `false`.
-void visitCallResults(ApplySite apply,
-                      std::function<bool(SILInstruction *)> visitor) {
-  if (apply.getType().is<TupleType>()) {
-    for (auto *operand : apply.getInstruction()->getUses()) {
-      if (!visitor(operand->getUser()))
-        break;
+static void visitCallResults(ApplySite apply,
+                             llvm::function_ref<bool(SILValue)> visitor) {
+  // FIXME: this entire implementation only really works for ApplyInst.
+  auto applyInst = cast<ApplyInst>(apply);
+  if (applyInst->getType().is<TupleType>()) {
+    // TODO: MultiValueInstruction
+    for (auto *operand : applyInst->getUses()) {
+      if (auto extract = dyn_cast<TupleExtractInst>(operand->getUser()))
+        if (!visitor(extract))
+          break;
     }
   } else
-    visitor(apply.getInstruction());
+    visitor(applyInst);
 }
 
 //===----------------------------------------------------------------------===//
@@ -233,7 +237,7 @@
   ValueStorageMap valueStorageMap;
   // All call sites with formally indirect SILArgument or SILResult conventions.
   // Calls are removed from the set when rewritten.
-  SmallSetVector<SILInstruction *, 16> indirectApplies;
+  SmallSetVector<ApplySite, 16> indirectApplies;
   // All function-exiting terminators (return or throw instructions).
   SmallVector<TermInst *, 8> returnInsts;
   // Delete these instructions after performing transformations.
@@ -250,8 +254,9 @@
 
   void markDead(SILInstruction *inst) {
 #ifndef NDEBUG
-    for (Operand *use : inst->getUses())
-      assert(instsToDelete.count(use->getUser()));
+    for (auto result : inst->getResults())
+      for (Operand *use : result->getUses())
+        assert(instsToDelete.count(use->getUser()));
 #endif
     instsToDelete.insert(inst);
   }
@@ -305,11 +310,11 @@
       }
     }
     for (auto &II : *BB) {
-      if (ApplySite::isa(&II))
-        visitApply(ApplySite(&II));
+      if (auto apply = ApplySite::isa(&II))
+        visitApply(apply);
 
-      if (II.hasValue())
-        visitValue(SILValue(&II));
+      for (auto result : II.getResults())
+        visitValue(result);
     }
   }
 }
@@ -323,16 +328,16 @@
     if (operand.get()->getType().isObject()) {
       auto argConv = calleeConv.getSILArgumentConvention(calleeArgIdx);
       if (argConv.isIndirectConvention()) {
-        pass.indirectApplies.insert(applySite.getInstruction());
+        pass.indirectApplies.insert(applySite);
       }
     }
     ++calleeArgIdx;
   }
 
   if (applySite.getSubstCalleeType()->hasIndirectFormalResults()) {
-    pass.indirectApplies.insert(applySite.getInstruction());
+    pass.indirectApplies.insert(applySite);
     if (!applySite.getType().is<TupleType>())
-      pass.valueStorageMap.insertValue(applySite.getInstruction());
+      pass.valueStorageMap.insertValue(cast<ApplyInst>(applySite));
 
     return;
   }
@@ -375,7 +380,8 @@
 protected:
   void convertIndirectFunctionArgs();
   unsigned insertIndirectReturnArgs();
-  bool canProjectFrom(SILInstruction *innerVal, SILInstruction *composingUse);
+  bool canProjectFrom(SingleValueInstruction *innerVal,
+                      SILInstruction *composingUse);
   void allocateForValue(SILValue value, ValueStorage &storage);
 };
 } // end anonymous namespace
@@ -472,7 +478,7 @@
 /// 
 /// TODO: This should be a common utility.
 static SILLocation getLocForValue(SILValue value) {
-  if (auto *instr = dyn_cast<SILInstruction>(value)) {
+  if (auto *instr = value->getDefiningInstruction()) {
     return instr->getLoc();
   }
   if (auto *arg = dyn_cast<SILArgument>(value)) {
@@ -488,22 +494,24 @@
 ///
 /// TODO: Handle struct.
 /// TODO: Make this a visitor.
-bool OpaqueStorageAllocation::canProjectFrom(SILInstruction *innerVal,
+bool OpaqueStorageAllocation::canProjectFrom(SingleValueInstruction *innerVal,
                                              SILInstruction *composingUse) {
   if (!OptimizeOpaqueAddressLowering)
     return false;
 
+  SILValue composingValue;
   switch (composingUse->getKind()) {
   default:
     return false;
-  case ValueKind::ApplyInst:
+  case SILInstructionKind::ApplyInst:
     // @in operands never need their own storage since they are non-mutating
     // uses. They simply reuse the storage allocated for their operand. So it
     // wouldn't make sense to "project" out of the apply argument.
     return false;
-  case ValueKind::EnumInst:
+  case SILInstructionKind::EnumInst:
+    composingValue = cast<EnumInst>(composingUse);
     break;
-  case ValueKind::InitExistentialValueInst: {
+  case SILInstructionKind::InitExistentialValueInst: {
     // Ensure that all opened archetypes are available at the inner value's
     // definition.
     auto *initExistential = cast<InitExistentialValueInst>(composingUse);
@@ -511,21 +519,23 @@
       if (!pass.domInfo->properlyDominates(operand.get(), innerVal))
         return false;
     }
+    composingValue = initExistential;
     break;
   }
-  case ValueKind::ReturnInst:
+  case SILInstructionKind::ReturnInst:
     return true;
-  case ValueKind::StoreInst: {
+  case SILInstructionKind::StoreInst: {
     if (cast<StoreInst>(composingUse)->getSrc() == innerVal
         && isa<CopyValueInst>(innerVal)) {
       return true;
     }
     return false;
   }
-  case ValueKind::TupleInst:
+  case SILInstructionKind::TupleInst:
+    composingValue = cast<TupleInst>(composingUse);
     break;
   }
-  ValueStorage &storage = pass.valueStorageMap.getStorage(composingUse);
+  ValueStorage &storage = pass.valueStorageMap.getStorage(composingValue);
   if (SILValue addr = storage.storageAddress) {
     if (auto *stackInst = dyn_cast<AllocStackInst>(addr)) {
       assert(pass.domInfo->properlyDominates(stackInst, innerVal));
@@ -545,11 +555,11 @@
                                                ValueStorage &storage) {
   assert(!isa<SILFunctionArgument>(value));
 
-  if (ApplySite::isa(value)) {
+  if (auto apply = ApplySite::isa(value)) {
     // Result tuples will be canonicalized during apply rewriting so the tuple
     // itself is unused.
     if (value->getType().is<TupleType>()) {
-      assert(ApplySite(value).getSubstCalleeType()->getNumResults() > 1);
+      assert(apply.getSubstCalleeType()->getNumResults() > 1);
       return;
     }
   }
@@ -564,7 +574,7 @@
     // TODO: Handle block arguments.
     // TODO: Handle subobjects with a single composition, and other non-mutating
     // uses such as @in arguments.
-    if (auto *def = dyn_cast<SILInstruction>(value)) {
+    if (auto *def = dyn_cast<SingleValueInstruction>(value)) {
       Operand *useOper = *value->use_begin();
       if (canProjectFrom(def, useOper->getUser())) {
         storage.setComposedOperand(useOper);
@@ -662,14 +672,14 @@
   default:
     DEBUG(user->dump());
     llvm_unreachable("Unexpected subobject composition.");
-  case ValueKind::EnumInst: {
+  case SILInstructionKind::EnumInst: {
     auto *enumInst = cast<EnumInst>(user);
     SILValue enumAddr = materializeAddress(enumInst);
     return B.createInitEnumDataAddr(enumInst->getLoc(), enumAddr,
                                     enumInst->getElement(),
                                     operand->get()->getType().getAddressType());
   }
-  case ValueKind::InitExistentialValueInst: {
+  case SILInstructionKind::InitExistentialValueInst: {
     auto *initExistentialValue = cast<InitExistentialValueInst>(user);
     SILValue containerAddr = materializeAddress(initExistentialValue);
     auto canTy = initExistentialValue->getFormalConcreteType();
@@ -679,11 +689,11 @@
         initExistentialValue->getLoc(), containerAddr, canTy,
         concreteTL.getLoweredType(), initExistentialValue->getConformances());
   }
-  case ValueKind::ReturnInst: {
+  case SILInstructionKind::ReturnInst: {
     assert(pass.loweredFnConv.hasIndirectSILResults());
     return pass.F->getArguments()[0];
   }
-  case ValueKind::TupleInst: {
+  case SILInstructionKind::TupleInst: {
     auto *tupleInst = cast<TupleInst>(user);
     // Function return values.
     if (tupleInst->hasOneUse()
@@ -717,9 +727,12 @@
   ApplySite apply;
   SILBuilder argBuilder;
 
+  /// For now, we assume that the apply site is a normal apply.
+  ApplyInst *getApplyInst() const { return cast<ApplyInst>(apply); }
+
 public:
-  ApplyRewriter(SILInstruction *origCall, AddressLoweringState &pass)
-      : pass(pass), apply(origCall), argBuilder(origCall) {
+  ApplyRewriter(ApplySite origCall, AddressLoweringState &pass)
+      : pass(pass), apply(origCall), argBuilder(origCall.getInstruction()) {
     argBuilder.setSILConventions(
         SILModuleConventions::getLoweredAddressConventions());
   }
@@ -731,9 +744,10 @@
 
 protected:
   void
-  canonicalizeResults(SmallVectorImpl<SILInstruction *> &directResultValues,
+  canonicalizeResults(MutableArrayRef<SingleValueInstruction *> directResultValues,
                       ArrayRef<Operand *> nonCanonicalUses);
-  SILValue materializeIndirectResultAddress(SILInstruction *origDirectResultVal,
+  SILValue materializeIndirectResultAddress(
+                                    SingleValueInstruction *origDirectResultVal,
                                             SILType argTy);
 };
 } // end anonymous namespace
@@ -762,17 +776,17 @@
   SILInstruction *lastUse = argLoad ? argLoad : applyInst;
 
   switch (applyInst->getKind()) {
-  case ValueKind::ApplyInst: {
+  case SILInstructionKind::ApplyInst: {
     SILBuilder deallocBuilder(&*std::next(lastUse->getIterator()));
     deallocBuilder.setSILConventions(
         SILModuleConventions::getLoweredAddressConventions());
     deallocBuilder.createDeallocStack(allocInst->getLoc(), allocInst);
     break;
   }
-  case ValueKind::TryApplyInst:
+  case SILInstructionKind::TryApplyInst:
     // TODO!!!: insert dealloc in the catch block.
     llvm_unreachable("not implemented for this instruction!");
-  case ValueKind::PartialApplyInst:
+  case SILInstructionKind::PartialApplyInst:
     llvm_unreachable("partial apply cannot have indirect results.");
   default:
     llvm_unreachable("not implemented for this instruction!");
@@ -820,19 +834,18 @@
 // that result if one exists. This function will add an entry to
 // directResultValues whenever it needs to materialize a TupleExtractInst.
 void ApplyRewriter::canonicalizeResults(
-    SmallVectorImpl<SILInstruction *> &directResultValues,
+    MutableArrayRef<SingleValueInstruction *> directResultValues,
     ArrayRef<Operand *> nonCanonicalUses) {
 
-  auto *applyInst = apply.getInstruction();
+  auto *applyInst = getApplyInst();
 
   for (Operand *operand : nonCanonicalUses) {
     auto *destroyInst = dyn_cast<DestroyValueInst>(operand->getUser());
     if (!destroyInst)
       llvm::report_fatal_error("Simultaneous use of multiple call results.");
 
-    for (unsigned resultIdx = 0, endIdx = directResultValues.size();
-         resultIdx < endIdx; ++resultIdx) {
-      SILInstruction *result = directResultValues[resultIdx];
+    for (unsigned resultIdx : indices(directResultValues)) {
+      SingleValueInstruction *result = directResultValues[resultIdx];
       if (!result) {
         SILBuilder resultBuilder(std::next(SILBasicBlock::iterator(applyInst)));
         resultBuilder.setSILConventions(
@@ -856,7 +869,7 @@
 ///
 /// origDirectResultVal may be nullptr for unused results.
 SILValue ApplyRewriter::materializeIndirectResultAddress(
-    SILInstruction *origDirectResultVal, SILType argTy) {
+    SingleValueInstruction *origDirectResultVal, SILType argTy) {
 
   if (origDirectResultVal
       && origDirectResultVal->getType().isAddressOnly(pass.F->getModule())) {
@@ -891,12 +904,12 @@
 void ApplyRewriter::convertApplyWithIndirectResults() {
   assert(apply.getSubstCalleeType()->hasIndirectFormalResults());
 
-  SILInstruction *origCallInst = apply.getInstruction();
+  auto *origCallInst = getApplyInst();
   SILFunctionConventions origFnConv = apply.getSubstCalleeConv();
 
   // Gather the original direct return values.
   // Canonicalize results so no user uses more than one result.
-  SmallVector<SILInstruction *, 8> origDirectResultValues(
+  SmallVector<SingleValueInstruction *, 8> origDirectResultValues(
     origFnConv.getNumDirectSILResults());
   SmallVector<Operand *, 4> nonCanonicalUses;
   if (origCallInst->getType().is<TupleType>()) {
@@ -950,7 +963,7 @@
   for_each(
     apply.getSubstCalleeType()->getResults(),
     origDirectResultValues, 
-    [&](SILResultInfo resultInfo, SILInstruction *origDirectResultVal) {
+    [&](SILResultInfo resultInfo, SingleValueInstruction *origDirectResultVal) {
       // Assume that all original results are direct in SIL.
       assert(!origFnConv.isSILIndirect(resultInfo));
 
@@ -979,17 +992,17 @@
   }
 
   // Create a new apply with indirect result operands.
-  SILInstruction *newCallInst;
+  ApplyInst *newCallInst;
   switch (origCallInst->getKind()) {
-  case ValueKind::ApplyInst:
+  case SILInstructionKind::ApplyInst:
     newCallInst = callBuilder.createApply(
         loc, apply.getCallee(), apply.getSubstitutions(), newCallArgs,
         cast<ApplyInst>(origCallInst)->isNonThrowing(), nullptr);
     break;
-  case ValueKind::TryApplyInst:
+  case SILInstructionKind::TryApplyInst:
     // TODO: insert dealloc in the catch block.
     llvm_unreachable("not implemented for this instruction!");
-  case ValueKind::PartialApplyInst:
+  case SILInstructionKind::PartialApplyInst:
   // Partial apply does not have formally indirect results.
   default:
     llvm_unreachable("not implemented for this instruction!");
@@ -1030,11 +1043,11 @@
     }
     // Either the new call instruction has only a single direct result, or we
     // map the original tuple field to the new tuple field.
-    SILInstruction *newValue = newCallInst;
+    SILValue newValue = newCallInst;
     if (loweredCalleeConv.getNumDirectSILResults() > 1) {
-      assert(newCallInst->getType().is<TupleType>());
+      assert(newValue->getType().is<TupleType>());
       newValue = resultBuilder.createTupleExtract(
-        extractInst->getLoc(), newCallInst,
+        extractInst->getLoc(), newValue,
         newDirectResultIndices[origResultIdx]);
     }
     extractInst->replaceAllUsesWith(newValue);
@@ -1148,8 +1161,8 @@
   }
   SILValue origFullResult = returnInst->getOperand();
   returnInst->setOperand(newReturnVal);
-  if (auto *fullResultInst = dyn_cast<SILInstruction>(origFullResult)) {
-    if (fullResultInst->use_empty())
+  if (auto *fullResultInst = origFullResult->getDefiningInstruction()) {
+    if (!fullResultInst->hasUsesOfAnyResult())
       pass.markDead(fullResultInst);
   }
 }
@@ -1160,8 +1173,9 @@
 
 namespace {
 class AddressOnlyUseRewriter
-    : SILInstructionVisitor<AddressOnlyUseRewriter, void> {
-  friend SILVisitor<AddressOnlyUseRewriter, void>;
+    : SILInstructionVisitor<AddressOnlyUseRewriter> {
+  friend SILVisitorBase<AddressOnlyUseRewriter>;
+  friend SILInstructionVisitor<AddressOnlyUseRewriter>;
 
   AddressLoweringState &pass;
 
@@ -1182,22 +1196,21 @@
   }
 
 protected:
-  void markRewritten(SILValue addr) {
-    auto &storage = pass.valueStorageMap.getStorage(currOper->getUser());
+  void markRewritten(SILValue oldValue, SILValue addr) {
+    auto &storage = pass.valueStorageMap.getStorage(oldValue);
     storage.storageAddress = addr;
     storage.markRewritten();
   }
 
-  void beforeVisit(ValueBase *V) {
-    DEBUG(llvm::dbgs() << "  REWRITE USE "; V->dump());
+  void beforeVisit(SILInstruction *I) {
+    DEBUG(llvm::dbgs() << "  REWRITE USE "; I->dump());
 
-    auto *I = cast<SILInstruction>(V);
     B.setInsertionPoint(I);
     B.setCurrentDebugScope(I->getDebugScope());
   }
 
-  void visitValueBase(ValueBase *V) {
-    DEBUG(V->dump());
+  void visitSILInstruction(SILInstruction *I) {
+    DEBUG(I->dump());
     llvm_unreachable("Unimplemented?!");
   }
 
@@ -1217,7 +1230,7 @@
     SILValue destAddr = addrMat.materializeAddress(copyInst);
     B.createCopyAddr(copyInst->getLoc(), srcAddr, destAddr, IsNotTake,
                      IsInitialization);
-    markRewritten(destAddr);
+    markRewritten(copyInst, destAddr);
   }
   
   void visitDebugValueInst(DebugValueInst *debugInst) {
@@ -1298,8 +1311,9 @@
 
 namespace {
 class AddressOnlyDefRewriter
-    : SILInstructionVisitor<AddressOnlyDefRewriter, void> {
-  friend SILVisitor<AddressOnlyDefRewriter, void>;
+    : SILInstructionVisitor<AddressOnlyDefRewriter> {
+  friend SILVisitorBase<AddressOnlyDefRewriter>;
+  friend SILInstructionVisitor<AddressOnlyDefRewriter>;
 
   AddressLoweringState &pass;
 
@@ -1317,24 +1331,27 @@
   void visitInst(SILInstruction *inst) { visit(inst); }
 
 protected:
-  void beforeVisit(ValueBase *V) {
-    storage = &pass.valueStorageMap.getStorage(V);
+  void beforeVisit(SILInstruction *I) {
+    // This cast succeeds beecause only specific instructions get added to
+    // the value storage map.
+    storage = &pass.valueStorageMap.getStorage(cast<SingleValueInstruction>(I));
 
-    DEBUG(llvm::dbgs() << "REWRITE DEF "; V->dump());
+    DEBUG(llvm::dbgs() << "REWRITE DEF "; I->dump());
     if (storage->storageAddress)
       DEBUG(llvm::dbgs() << "  STORAGE "; storage->storageAddress->dump());
 
-    auto *I = cast<SILInstruction>(V);
     B.setInsertionPoint(I);
     B.setCurrentDebugScope(I->getDebugScope());
   }
 
-  void visitValueBase(ValueBase *V) {
-    DEBUG(V->dump());
+  void visitSILInstruction(SILInstruction *I) {
+    DEBUG(I->dump());
     llvm_unreachable("Unimplemented?!");
   }
 
   void visitApplyInst(ApplyInst *applyInst) {
+    assert(isa<SingleValueInstruction>(applyInst) &&
+           "beforeVisit assumes that ApplyInst is an SVI");
     assert(!storage->isRewritten());
     // Completely rewrite the apply instruction, handling any remaining
     // (loadable) indirect parameters, allocating memory for indirect
@@ -1420,8 +1437,7 @@
     // This must be an indirect result for an apply that has not yet been
     // rewritten. Rewrite the apply.
     SILValue srcVal = extractInst->getOperand();
-    assert(ApplySite::isa(srcVal));
-    ApplyRewriter(cast<SILInstruction>(srcVal), pass)
+    ApplyRewriter(cast<ApplyInst>(srcVal), pass)
         .convertApplyWithIndirectResults();
 
     assert(storage->storageAddress);
@@ -1436,7 +1452,8 @@
   for (auto &valueStorageI : pass.valueStorageMap) {
     SILValue valueDef = valueStorageI.first;
 
-    if (auto *defInst = dyn_cast<SILInstruction>(valueDef))
+    // TODO: MultiValueInstruction: ApplyInst
+    if (auto *defInst = dyn_cast<SingleValueInstruction>(valueDef))
       defVisitor.visitInst(defInst);
 
     SmallVector<Operand *, 8> uses(valueDef->getUses());
@@ -1445,12 +1462,11 @@
   }
 
   // Rewrite any remaining (loadable) indirect parameters.
-  for (SILInstruction *applyInst : pass.indirectApplies) {
-    ApplySite apply(applyInst);
+  for (ApplySite apply : pass.indirectApplies) {
     // Calls with indirect formal results have already been rewritten.
     if (apply.getSubstCalleeType()->hasIndirectFormalResults()) {
       bool isRewritten = false;
-      visitCallResults(apply, [&](SILInstruction *result) {
+      visitCallResults(apply, [&](SILValue result) {
         if (result->getType().isAddressOnly(pass.F->getModule())) {
           assert(pass.valueStorageMap.getStorage(result).isRewritten());
           isRewritten = true;
@@ -1459,13 +1475,13 @@
         return true;
       });
       if (!isRewritten) {
-        ApplyRewriter rewriter(applyInst, pass);
+        ApplyRewriter rewriter(apply, pass);
         rewriter.rewriteParameters();
         rewriter.convertApplyWithIndirectResults();
         continue;
       }
     }
-    ApplyRewriter(applyInst, pass).rewriteParameters();
+    ApplyRewriter(apply, pass).rewriteParameters();
   }
   if (pass.F->getLoweredFunctionType()->hasIndirectFormalResults())
     ReturnRewriter(pass).rewriteReturns();
@@ -1506,14 +1522,16 @@
   // Add the rest of the instructions to the dead list in post order.
   // FIXME: make sure we cleaned up address-only BB arguments.
   for (auto &valueStorageI : reversed(pass.valueStorageMap)) {
-    auto *deadInst = dyn_cast<SILInstruction>(valueStorageI.first);
+    // TODO: MultiValueInstruction: ApplyInst
+    auto *deadInst = dyn_cast<SingleValueInstruction>(valueStorageI.first);
     if (!deadInst)
       continue;
 
     DEBUG(llvm::dbgs() << "DEAD "; deadInst->dump());
 #ifndef NDEBUG
-    for (Operand *operand : deadInst->getUses())
-      assert(pass.instsToDelete.count(operand->getUser()));
+    for (auto result : deadInst->getResults())
+      for (Operand *operand : result->getUses())
+        assert(pass.instsToDelete.count(operand->getUser()));
 #endif
     pass.instsToDelete.insert(deadInst);
   }
diff --git a/lib/SILOptimizer/Mandatory/ConstantPropagation.cpp b/lib/SILOptimizer/Mandatory/ConstantPropagation.cpp
index 71157e4..8202e9e 100644
--- a/lib/SILOptimizer/Mandatory/ConstantPropagation.cpp
+++ b/lib/SILOptimizer/Mandatory/ConstantPropagation.cpp
@@ -36,9 +36,8 @@
 }
 
 /// \brief Construct (int, overflow) result tuple.
-static SILInstruction *constructResultWithOverflowTuple(BuiltinInst *BI,
-                                                        APInt Res,
-                                                        bool Overflow) {
+static SILValue constructResultWithOverflowTuple(BuiltinInst *BI,
+                                                 APInt Res, bool Overflow) {
   // Get the SIL subtypes of the returned tuple type.
   SILType FuncResType = BI->getType();
   assert(FuncResType.castTo<TupleType>()->getNumElements() == 2);
@@ -57,7 +56,7 @@
 }
 
 /// \brief Fold arithmetic intrinsics with overflow.
-static SILInstruction *
+static SILValue
 constantFoldBinaryWithOverflow(BuiltinInst *BI, llvm::Intrinsic::ID ID,
                                bool ReportOverflow,
                                Optional<bool> &ResultsInError) {
@@ -159,7 +158,7 @@
   return constructResultWithOverflowTuple(BI, Res, Overflow);
 }
 
-static SILInstruction *
+static SILValue
 constantFoldBinaryWithOverflow(BuiltinInst *BI, BuiltinValueKind ID,
                                Optional<bool> &ResultsInError) {
   OperandValueArrayRef Args = BI->getArguments();
@@ -170,9 +169,8 @@
            ResultsInError);
 }
 
-static SILInstruction *constantFoldIntrinsic(BuiltinInst *BI,
-                                             llvm::Intrinsic::ID ID,
-                                             Optional<bool> &ResultsInError) {
+static SILValue constantFoldIntrinsic(BuiltinInst *BI, llvm::Intrinsic::ID ID,
+                                      Optional<bool> &ResultsInError) {
   switch (ID) {
   default: break;
   case llvm::Intrinsic::expect: {
@@ -224,8 +222,7 @@
   return nullptr;
 }
 
-static SILInstruction *constantFoldCompare(BuiltinInst *BI,
-                                           BuiltinValueKind ID) {
+static SILValue constantFoldCompare(BuiltinInst *BI, BuiltinValueKind ID) {
   OperandValueArrayRef Args = BI->getArguments();
 
   // Fold for integer constant arguments.
@@ -394,7 +391,7 @@
   return nullptr;
 }
 
-static SILInstruction *
+static SILValue
 constantFoldAndCheckDivision(BuiltinInst *BI, BuiltinValueKind ID,
                              Optional<bool> &ResultsInError) {
   assert(ID == BuiltinValueKind::SDiv ||
@@ -462,9 +459,9 @@
 ///
 /// The list of operations we constant fold might not be complete. Start with
 /// folding the operations used by the standard library.
-static SILInstruction *constantFoldBinary(BuiltinInst *BI,
-                                          BuiltinValueKind ID,
-                                          Optional<bool> &ResultsInError) {
+static SILValue constantFoldBinary(BuiltinInst *BI,
+                                   BuiltinValueKind ID,
+                                   Optional<bool> &ResultsInError) {
   switch (ID) {
   default:
     llvm_unreachable("Not all BUILTIN_BINARY_OPERATIONs are covered!");
@@ -573,7 +570,7 @@
   return std::pair<bool, bool>(SrcTySigned, DstTySigned);
 }
 
-static SILInstruction *
+static SILValue
 constantFoldAndCheckIntegerConversions(BuiltinInst *BI,
                                        const BuiltinInfo &Builtin,
                                        Optional<bool> &ResultsInError) {
@@ -753,8 +750,8 @@
 
 }
 
-static SILInstruction *constantFoldBuiltin(BuiltinInst *BI,
-                                           Optional<bool> &ResultsInError) {
+static SILValue constantFoldBuiltin(BuiltinInst *BI,
+                                    Optional<bool> &ResultsInError) {
   const IntrinsicInfo &Intrinsic = BI->getIntrinsicInfo();
   SILModule &M = BI->getModule();
 
@@ -971,7 +968,8 @@
     SILValue Val = Op.get();
     Op.drop();
     if (Val->use_empty()) {
-      auto *DeadI = dyn_cast<SILInstruction>(Val);
+      auto *DeadI = Val->getDefiningInstruction();
+      assert(DeadI);
       recursivelyDeleteTriviallyDeadInstructions(DeadI, /*force*/ true,
                                                  RemoveCallback);
       WorkList.remove(DeadI);
@@ -996,7 +994,7 @@
                                llvm::SetVector<SILInstruction *> &WorkList) {
   for (auto &BB : F) {
     for (auto &I : BB) {
-      if (isFoldable(&I) && !I.use_empty()) {
+      if (isFoldable(&I) && I.hasUsesOfAnyResult()) {
         WorkList.insert(&I);
         continue;
       }
@@ -1051,7 +1049,7 @@
 
   llvm::SetVector<SILInstruction *> FoldedUsers;
   CastOptimizer CastOpt(
-      [&](SILInstruction *I, ValueBase *V) { /* ReplaceInstUsesAction */
+      [&](SingleValueInstruction *I, ValueBase *V) { /* ReplaceInstUsesAction */
 
         InvalidateInstructions = true;
         I->replaceAllUsesWith(V);
@@ -1122,20 +1120,23 @@
         isa<UnconditionalCheckedCastAddrInst>(I)) {
       // Try to perform cast optimizations. Invalidation is handled by a
       // callback inside the cast optimizer.
-      ValueBase *Result = nullptr;
+      SILInstruction *Result = nullptr;
       switch(I->getKind()) {
       default:
         llvm_unreachable("Unexpected instruction for cast optimizations");
-      case ValueKind::CheckedCastBranchInst:
+      case SILInstructionKind::CheckedCastBranchInst:
         Result = CastOpt.simplifyCheckedCastBranchInst(cast<CheckedCastBranchInst>(I));
         break;
-      case ValueKind::CheckedCastAddrBranchInst:
+      case SILInstructionKind::CheckedCastAddrBranchInst:
         Result = CastOpt.simplifyCheckedCastAddrBranchInst(cast<CheckedCastAddrBranchInst>(I));
         break;
-      case ValueKind::UnconditionalCheckedCastInst:
-        Result = CastOpt.optimizeUnconditionalCheckedCastInst(cast<UnconditionalCheckedCastInst>(I));
+      case SILInstructionKind::UnconditionalCheckedCastInst: {
+        auto Value =
+          CastOpt.optimizeUnconditionalCheckedCastInst(cast<UnconditionalCheckedCastInst>(I));
+        if (Value) Result = Value->getDefiningInstruction();
         break;
-      case ValueKind::UnconditionalCheckedCastAddrInst:
+      }
+      case SILInstructionKind::UnconditionalCheckedCastAddrInst:
         Result = CastOpt.optimizeUnconditionalCheckedCastAddrInst(cast<UnconditionalCheckedCastAddrInst>(I));
         break;
       }
@@ -1145,15 +1146,16 @@
             isa<CheckedCastAddrBranchInst>(Result) ||
             isa<UnconditionalCheckedCastInst>(Result) ||
             isa<UnconditionalCheckedCastAddrInst>(Result))
-          WorkList.insert(cast<SILInstruction>(Result));
+          WorkList.insert(Result);
       }
       continue;
     }
 
 
     // Go through all users of the constant and try to fold them.
+    // TODO: MultiValueInstruction
     FoldedUsers.clear();
-    for (auto Use : I->getUses()) {
+    for (auto Use : cast<SingleValueInstruction>(I)->getUses()) {
       SILInstruction *User = Use->getUser();
       DEBUG(llvm::dbgs() << "    User: " << *User);
 
@@ -1200,6 +1202,10 @@
       if (!C)
         continue;
 
+      // We can currently only do this constant-folding of single-value
+      // instructions.
+      auto UserV = cast<SingleValueInstruction>(User);
+
       // Ok, we have succeeded. Add user to the FoldedUsers list and perform the
       // necessary cleanups, RAUWs, etc.
       FoldedUsers.insert(User);
@@ -1211,7 +1217,7 @@
       // any tuple_extract instructions using the apply.  This is a common case
       // for functions returning multiple values.
       if (auto *TI = dyn_cast<TupleInst>(C)) {
-        for (auto UI = User->use_begin(), E = User->use_end(); UI != E;) {
+        for (auto UI = UserV->use_begin(), E = UserV->use_end(); UI != E;) {
           Operand *O = *UI++;
 
           // If the user is a tuple_extract, just substitute the right value in.
@@ -1220,21 +1226,21 @@
             TEI->replaceAllUsesWith(NewVal);
             TEI->dropAllReferences();
             FoldedUsers.insert(TEI);
-            if (auto *Inst = dyn_cast<SILInstruction>(NewVal))
+            if (auto *Inst = NewVal->getDefiningInstruction())
               WorkList.insert(Inst);
           }
         }
 
-        if (User->use_empty())
+        if (UserV->use_empty())
           FoldedUsers.insert(TI);
       }
 
 
       // We were able to fold, so all users should use the new folded value.
-      User->replaceAllUsesWith(C);
+      UserV->replaceAllUsesWith(C);
 
       // The new constant could be further folded now, add it to the worklist.
-      if (auto *Inst = dyn_cast<SILInstruction>(C))
+      if (auto *Inst = C->getDefiningInstruction())
         WorkList.insert(Inst);
     }
 
diff --git a/lib/SILOptimizer/Mandatory/DIMemoryUseCollector.cpp b/lib/SILOptimizer/Mandatory/DIMemoryUseCollector.cpp
index 42dc987..f0f6248 100644
--- a/lib/SILOptimizer/Mandatory/DIMemoryUseCollector.cpp
+++ b/lib/SILOptimizer/Mandatory/DIMemoryUseCollector.cpp
@@ -43,7 +43,7 @@
 }
 
 
-DIMemoryObjectInfo::DIMemoryObjectInfo(SILInstruction *MI) {
+DIMemoryObjectInfo::DIMemoryObjectInfo(SingleValueInstruction *MI) {
   auto &Module = MI->getModule();
 
   MemoryInst = MI;
@@ -338,7 +338,7 @@
       continue;
 
     if (auto project = dyn_cast<ProjectBoxInst>(User)) {
-      collectUses(User, project->getFieldIndex());
+      collectUses(project, project->getFieldIndex());
       continue;
     }
 
@@ -392,8 +392,8 @@
     }
 
     // Look through begin_access.
-    if (isa<BeginAccessInst>(User)) {
-      collectUses(User, BaseEltNo);
+    if (auto I = dyn_cast<BeginAccessInst>(User)) {
+      collectUses(I, BaseEltNo);
       continue;
     }
 
@@ -550,14 +550,14 @@
     // that is looking into the memory object (i.e., the memory object needs to
     // be explicitly initialized by a copy_addr or some other use of the
     // projected address).
-    if (isa<InitEnumDataAddrInst>(User)) {
+    if (auto I = dyn_cast<InitEnumDataAddrInst>(User)) {
       assert(!InStructSubElement &&
              "init_enum_data_addr shouldn't apply to struct subelements");
       // Keep track of the fact that we're inside of an enum.  This informs our
       // recursion that tuple stores are not scalarized outside, and that stores
       // should not be treated as partial stores.
       llvm::SaveAndRestore<bool> X(InEnumSubElement, true);
-      collectUses(User, BaseEltNo);
+      collectUses(I, BaseEltNo);
       continue;
     }
 
@@ -609,7 +609,7 @@
   // Now that we've walked all of the immediate uses, scalarize any operations
   // working on tuples if we need to for canonicalization or analysis reasons.
   if (!UsesToScalarize.empty()) {
-    SILInstruction *PointerInst = cast<SILInstruction>(Pointer);
+    SILInstruction *PointerInst = Pointer->getDefiningInstruction();
     SmallVector<SILValue, 4> ElementAddrs;
     SILBuilderWithScope AddrBuilder(++SILBasicBlock::iterator(PointerInst),
                                     PointerInst);
diff --git a/lib/SILOptimizer/Mandatory/DIMemoryUseCollector.h b/lib/SILOptimizer/Mandatory/DIMemoryUseCollector.h
index 43bb692..1a3021a 100644
--- a/lib/SILOptimizer/Mandatory/DIMemoryUseCollector.h
+++ b/lib/SILOptimizer/Mandatory/DIMemoryUseCollector.h
@@ -49,7 +49,7 @@
 public:
   /// This is the instruction that represents the memory.  It is either an
   /// allocation (alloc_box, alloc_stack) or a mark_uninitialized.
-  SILInstruction *MemoryInst;
+  SingleValueInstruction *MemoryInst;
 
   /// This is the base type of the memory allocation.
   SILType MemorySILType;
@@ -64,7 +64,7 @@
   unsigned NumElements;
 public:
 
-  DIMemoryObjectInfo(SILInstruction *MemoryInst);
+  DIMemoryObjectInfo(SingleValueInstruction *MemoryInst);
 
   SILLocation getLoc() const { return MemoryInst->getLoc(); }
   SILFunction &getFunction() const { return *MemoryInst->getFunction(); }
@@ -76,7 +76,7 @@
     return MemorySILType.getSwiftRValueType();
   }
 
-  SILInstruction *getAddress() const {
+  SingleValueInstruction *getAddress() const {
     if (isa<AllocStackInst>(MemoryInst))
       return MemoryInst;
     assert(false);
diff --git a/lib/SILOptimizer/Mandatory/DIMemoryUseCollectorOwnership.cpp b/lib/SILOptimizer/Mandatory/DIMemoryUseCollectorOwnership.cpp
index 7415453..80a5fe0 100644
--- a/lib/SILOptimizer/Mandatory/DIMemoryUseCollectorOwnership.cpp
+++ b/lib/SILOptimizer/Mandatory/DIMemoryUseCollectorOwnership.cpp
@@ -90,7 +90,8 @@
   return {MemorySILType, VDecl->isLet()};
 }
 
-DIMemoryObjectInfo::DIMemoryObjectInfo(SILInstruction *MI) : MemoryInst(MI) {
+DIMemoryObjectInfo::DIMemoryObjectInfo(SingleValueInstruction *MI)
+    : MemoryInst(MI) {
   auto &Module = MI->getModule();
 
   std::tie(MemorySILType, IsLet) = computeMemorySILType(MemoryInst);
@@ -418,10 +419,12 @@
       if (!isa<SelectEnumInst>(User) && !isa<SelectEnumAddrInst>(User))
         continue;
 
-      if (!User->hasOneUse())
+      auto value = cast<SingleValueInstruction>(User);
+
+      if (!value->hasOneUse())
         continue;
 
-      User = User->use_begin()->getUser();
+      User = value->use_begin()->getUser();
       if (auto *CBI = dyn_cast<CondBranchInst>(User)) {
         trackFailureBlock(MemoryInfo, CBI, CBI->getTrueBB());
         return;
@@ -668,7 +671,7 @@
       continue;
 
     if (auto *PBI = dyn_cast<ProjectBoxInst>(User)) {
-      collectUses(User, PBI->getFieldIndex());
+      collectUses(PBI, PBI->getFieldIndex());
       continue;
     }
 
@@ -736,7 +739,8 @@
 
     // Look through begin_access and begin_borrow
     if (isa<BeginAccessInst>(User) || isa<BeginBorrowInst>(User)) {
-      collectUses(User, BaseEltNo);
+      auto begin = cast<SingleValueInstruction>(User);
+      collectUses(begin, BaseEltNo);
       continue;
     }
 
@@ -917,14 +921,14 @@
     // that is looking into the memory object (i.e., the memory object needs to
     // be explicitly initialized by a copy_addr or some other use of the
     // projected address).
-    if (isa<InitEnumDataAddrInst>(User)) {
+    if (auto init = dyn_cast<InitEnumDataAddrInst>(User)) {
       assert(!InStructSubElement &&
              "init_enum_data_addr shouldn't apply to struct subelements");
       // Keep track of the fact that we're inside of an enum.  This informs our
       // recursion that tuple stores are not scalarized outside, and that stores
       // should not be treated as partial stores.
       llvm::SaveAndRestore<bool> X(InEnumSubElement, true);
-      collectUses(User, BaseEltNo);
+      collectUses(init, BaseEltNo);
       continue;
     }
 
@@ -974,7 +978,7 @@
   // Now that we've walked all of the immediate uses, scalarize any operations
   // working on tuples if we need to for canonicalization or analysis reasons.
   if (!UsesToScalarize.empty()) {
-    SILInstruction *PointerInst = cast<SILInstruction>(Pointer);
+    SILInstruction *PointerInst = Pointer->getDefiningInstruction();
     SmallVector<SILValue, 4> ElementAddrs;
     SILBuilderWithScope AddrBuilder(++SILBasicBlock::iterator(PointerInst),
                                     PointerInst);
@@ -1103,7 +1107,8 @@
 
     // Loads of the box produce self, so collect uses from them.
     if (isa<LoadInst>(User) || isa<LoadBorrowInst>(User)) {
-      collectClassSelfUses(User, TheMemory.MemorySILType, EltNumbering);
+      auto load = cast<SingleValueInstruction>(User);
+      collectClassSelfUses(load, TheMemory.MemorySILType, EltNumbering);
       continue;
     }
 
@@ -1385,7 +1390,8 @@
     // Look through begin_borrow and unchecked_ref_cast.
     if (isa<BeginBorrowInst>(UCIOpUser) ||
         isa<UncheckedRefCastInst>(UCIOpUser)) {
-      copy(UCIOpUser->getUses(), std::back_inserter(Worklist));
+      auto I = cast<SingleValueInstruction>(UCIOpUser);
+      copy(I->getUses(), std::back_inserter(Worklist));
       continue;
     }
 
@@ -1474,14 +1480,15 @@
       }
 
       // Otherwise, look through the upcast and continue.
-      std::copy(User->use_begin(), User->use_end(),
+      std::copy(UCI->use_begin(), UCI->use_end(),
                 std::back_inserter(Worklist));
       continue;
     }
 
     // Look through begin_borrow and copy_value.
     if (isa<BeginBorrowInst>(User) || isa<CopyValueInst>(User)) {
-      std::copy(User->use_begin(), User->use_end(),
+      auto value = cast<SingleValueInstruction>(User);
+      std::copy(value->use_begin(), value->use_end(),
                 std::back_inserter(Worklist));
       continue;
     }
@@ -1527,7 +1534,7 @@
   // *NOTE* Even though this takes a SILInstruction it actually only accepts
   // load_borrow and load instructions. This is enforced via an assert.
   void collectDelegatingClassInitSelfLoadUses(MarkUninitializedInst *MUI,
-                                              SILInstruction *LI);
+                                              SingleValueInstruction *LI);
 };
 
 } // end anonymous namespace
@@ -1583,7 +1590,7 @@
     // Stores *to* the allocation are writes.  If the value being stored is a
     // call to self.init()... then we have a self.init call.
     if (auto *AI = dyn_cast<AssignInst>(User)) {
-      if (auto *AssignSource = dyn_cast<SILInstruction>(AI->getOperand(0))) {
+      if (auto *AssignSource = AI->getOperand(0)->getDefiningInstruction()) {
         if (isSelfInitUse(AssignSource)) {
           UseInfo.trackUse(DIMemoryUse(User, DIUseKind::SelfInit, 0, 1));
           continue;
@@ -1607,7 +1614,8 @@
 
     // Loads of the box produce self, so collect uses from them.
     if (isa<LoadInst>(User) || isa<LoadBorrowInst>(User)) {
-      collectDelegatingClassInitSelfLoadUses(MUI, User);
+      collectDelegatingClassInitSelfLoadUses(MUI,
+                                        cast<SingleValueInstruction>(User));
       continue;
     }
 
@@ -1667,7 +1675,7 @@
     // Stores *to* the allocation are writes.  If the value being stored is a
     // call to self.init()... then we have a self.init call.
     if (auto *AI = dyn_cast<AssignInst>(User)) {
-      if (auto *AssignSource = dyn_cast<SILInstruction>(AI->getOperand(0)))
+      if (auto *AssignSource = AI->getOperand(0)->getDefiningInstruction())
         if (isSelfInitUse(AssignSource))
           Kind = DIUseKind::SelfInit;
       if (auto *AssignSource = dyn_cast<SILArgument>(AI->getOperand(0))) {
@@ -1692,7 +1700,7 @@
 }
 
 void DelegatingInitElementUseCollector::collectDelegatingClassInitSelfLoadUses(
-    MarkUninitializedInst *MUI, SILInstruction *LI) {
+    MarkUninitializedInst *MUI, SingleValueInstruction *LI) {
   assert(isa<LoadBorrowInst>(LI) || isa<LoadInst>(LI));
 
   // If we have a load, then this is a use of the box.  Look at the uses of
@@ -1712,8 +1720,8 @@
       continue;
 
     // Look through begin_borrow.
-    if (isa<BeginBorrowInst>(User)) {
-      std::copy(User->use_begin(), User->use_end(),
+    if (auto borrow = dyn_cast<BeginBorrowInst>(User)) {
+      std::copy(borrow->use_begin(), borrow->use_end(),
                 std::back_inserter(Worklist));
       continue;
     }
diff --git a/lib/SILOptimizer/Mandatory/DIMemoryUseCollectorOwnership.h b/lib/SILOptimizer/Mandatory/DIMemoryUseCollectorOwnership.h
index da3800d..bc07e9e 100644
--- a/lib/SILOptimizer/Mandatory/DIMemoryUseCollectorOwnership.h
+++ b/lib/SILOptimizer/Mandatory/DIMemoryUseCollectorOwnership.h
@@ -55,7 +55,7 @@
 public:
   /// This is the instruction that represents the memory.  It is either an
   /// allocation (alloc_box, alloc_stack) or a mark_uninitialized.
-  SILInstruction *MemoryInst;
+  SingleValueInstruction *MemoryInst;
 
   /// This is the base type of the memory allocation.
   SILType MemorySILType;
@@ -70,7 +70,7 @@
   unsigned NumElements;
 
 public:
-  DIMemoryObjectInfo(SILInstruction *MemoryInst);
+  DIMemoryObjectInfo(SingleValueInstruction *MemoryInst);
 
   SILLocation getLoc() const { return MemoryInst->getLoc(); }
   SILFunction &getFunction() const { return *MemoryInst->getFunction(); }
@@ -80,7 +80,7 @@
 
   CanType getType() const { return MemorySILType.getSwiftRValueType(); }
 
-  SILInstruction *getAddress() const {
+  SingleValueInstruction *getAddress() const {
     if (isa<MarkUninitializedInst>(MemoryInst) ||
         isa<AllocStackInst>(MemoryInst))
       return MemoryInst;
diff --git a/lib/SILOptimizer/Mandatory/DefiniteInitialization.cpp b/lib/SILOptimizer/Mandatory/DefiniteInitialization.cpp
index f6fe944..3142757 100644
--- a/lib/SILOptimizer/Mandatory/DefiniteInitialization.cpp
+++ b/lib/SILOptimizer/Mandatory/DefiniteInitialization.cpp
@@ -1327,15 +1327,15 @@
         continue;
 
       // Look through upcasts.
-      if (isa<UpcastInst>(BBIOpUser)) {
-        std::copy(BBIOpUser->use_begin(), BBIOpUser->use_end(),
+      if (auto upcast = dyn_cast<UpcastInst>(BBIOpUser)) {
+        std::copy(upcast->use_begin(), upcast->use_end(),
                   std::back_inserter(Worklist));
         continue;
       }
 
       // Look through unchecked_ref_cast.
-      if (isa<UncheckedRefCastInst>(BBIOpUser)) {
-        std::copy(BBIOpUser->use_begin(), BBIOpUser->use_end(),
+      if (auto cast = dyn_cast<UncheckedRefCastInst>(BBIOpUser)) {
+        std::copy(cast->use_begin(), cast->use_end(),
                   std::back_inserter(Worklist));
         continue;
       }
@@ -1496,7 +1496,7 @@
     auto *LI = Inst;
     bool hasReturnUse = false, hasUnknownUses = false;
     
-    for (auto LoadUse : LI->getUses()) {
+    for (auto LoadUse : cast<SingleValueInstruction>(LI)->getUses()) {
       auto *User = LoadUse->getUser();
       
       // Ignore retains of the struct/enum before the return.
@@ -1892,7 +1892,7 @@
   SILInstruction *Release = Destroys[ReleaseID];
   if (isa<DestroyAddrInst>(Release)) {
     SILValue Addr = Release->getOperand(0);
-    if (auto *AddrI = dyn_cast<SILInstruction>(Addr))
+    if (auto *AddrI = Addr->getDefiningInstruction())
       recursivelyDeleteTriviallyDeadInstructions(AddrI);
   }
   Release->eraseFromParent();
diff --git a/lib/SILOptimizer/Mandatory/DiagnoseStaticExclusivity.cpp b/lib/SILOptimizer/Mandatory/DiagnoseStaticExclusivity.cpp
index 184a953..dd776f8 100644
--- a/lib/SILOptimizer/Mandatory/DiagnoseStaticExclusivity.cpp
+++ b/lib/SILOptimizer/Mandatory/DiagnoseStaticExclusivity.cpp
@@ -790,7 +790,7 @@
     case ValueKind::RefTailAddrInst:
     case ValueKind::TailAddrInst:
     case ValueKind::IndexAddrInst:
-      Iter = cast<SILInstruction>(Iter)->getOperand(0);
+      Iter = cast<SingleValueInstruction>(Iter)->getOperand(0);
       continue;
 
     // Base address producers.
diff --git a/lib/SILOptimizer/Mandatory/DiagnoseUnreachable.cpp b/lib/SILOptimizer/Mandatory/DiagnoseUnreachable.cpp
index f3301a6..5f914d3 100644
--- a/lib/SILOptimizer/Mandatory/DiagnoseUnreachable.cpp
+++ b/lib/SILOptimizer/Mandatory/DiagnoseUnreachable.cpp
@@ -192,11 +192,10 @@
   // Process conditional branches with constant conditions.
   if (auto *CBI = dyn_cast<CondBranchInst>(TI)) {
     SILValue V = CBI->getCondition();
-    auto *CondI = dyn_cast<SILInstruction>(V);
     SILLocation Loc = CBI->getLoc();
 
     if (IntegerLiteralInst *ConstCond =
-          dyn_cast_or_null<IntegerLiteralInst>(CondI)) {
+          dyn_cast_or_null<IntegerLiteralInst>(V)) {
       SILBuilderWithScope B(&BB, CBI);
 
       // Determine which of the successors is unreachable and create a new
@@ -399,18 +398,20 @@
 }
 
 static void setOutsideBlockUsesToUndef(SILInstruction *I) {
-  if (I->use_empty())
-      return;
+  if (!I->hasUsesOfAnyResult())
+    return;
 
   SILBasicBlock *BB = I->getParent();
   SILModule &Mod = BB->getModule();
 
   // Replace all uses outside of I's basic block by undef.
-  llvm::SmallVector<Operand *, 16> Uses(I->use_begin(), I->use_end());
+  llvm::SmallVector<Operand *, 16> Uses;
+  for (auto result : I->getResults())
+    Uses.append(result->use_begin(), result->use_end());
+
   for (auto *Use : Uses)
-    if (auto *User = dyn_cast<SILInstruction>(Use->getUser()))
-      if (User->getParent() != BB)
-        Use->set(SILUndef::get(Use->get()->getType(), Mod));
+    if (Use->getUser()->getParent() != BB)
+      Use->set(SILUndef::get(Use->get()->getType(), Mod));
 }
 
 static SILInstruction *getAsCallToNoReturn(SILInstruction *I) {
diff --git a/lib/SILOptimizer/Mandatory/GuaranteedARCOpts.cpp b/lib/SILOptimizer/Mandatory/GuaranteedARCOpts.cpp
index 94d6cdf..4b1f57d 100644
--- a/lib/SILOptimizer/Mandatory/GuaranteedARCOpts.cpp
+++ b/lib/SILOptimizer/Mandatory/GuaranteedARCOpts.cpp
@@ -24,7 +24,7 @@
 
 struct GuaranteedARCOptsVisitor
     : SILInstructionVisitor<GuaranteedARCOptsVisitor, bool> {
-  bool visitValueBase(ValueBase *V) { return false; }
+  bool visitSILInstruction(SILInstruction *I) { return false; }
   bool visitDestroyAddrInst(DestroyAddrInst *DAI);
   bool visitStrongReleaseInst(StrongReleaseInst *SRI);
   bool visitDestroyValueInst(DestroyValueInst *DVI);
diff --git a/lib/SILOptimizer/Mandatory/MandatoryInlining.cpp b/lib/SILOptimizer/Mandatory/MandatoryInlining.cpp
index 0c603bf..9e56867 100644
--- a/lib/SILOptimizer/Mandatory/MandatoryInlining.cpp
+++ b/lib/SILOptimizer/Mandatory/MandatoryInlining.cpp
@@ -62,8 +62,8 @@
   bool needsNotifications() override { return true; }
 
   // Handle notifications about removals of instructions.
-  void handleDeleteNotification(swift::ValueBase *Value) override {
-    if (auto DeletedI = dyn_cast<SILInstruction>(Value)) {
+  void handleDeleteNotification(SILNode *node) override {
+    if (auto DeletedI = dyn_cast<SILInstruction>(node)) {
       if (CurrentI == SILBasicBlock::iterator(DeletedI)) {
         if (CurrentI != CurrentI->getParent()->begin()) {
           --CurrentI;
@@ -164,10 +164,10 @@
                    ArrayRef<SILValue> FullArgs) {
   SmallVector<SILInstruction*, 16> InstsToDelete;
   for (SILValue V : FullArgs) {
-    if (auto *I = dyn_cast<SILInstruction>(V))
-      if (I != CalleeValue &&
-          isInstructionTriviallyDead(I))
-        InstsToDelete.push_back(I);
+    if (V != CalleeValue)
+      if (auto *I = V->getDefiningInstruction())
+        if (isInstructionTriviallyDead(I))
+          InstsToDelete.push_back(I);
   }
   recursivelyDeleteTriviallyDeadInstructions(InstsToDelete, true);
 
@@ -337,11 +337,11 @@
     return std::make_tuple(InnerAI, I);
 
   replaceDeadApply(InnerAI, NewInst);
-  if (auto *II = dyn_cast<SILInstruction>(NewInst))
-    I = II->getIterator();
-  else
-    I = NewInst->getParentBlock()->begin();
-  auto NewAI = FullApplySite::isa(NewInstPair.second.getInstruction());
+
+  auto newApplyAI = NewInstPair.second.getInstruction();
+  assert(newApplyAI && "devirtualized but removed apply site?");
+  I = newApplyAI->getIterator();
+  auto NewAI = FullApplySite::isa(newApplyAI);
   // *NOTE*, it is important that we return I here since we may have
   // devirtualized but not have a full apply site anymore.
   if (!NewAI)
diff --git a/lib/SILOptimizer/Mandatory/PredictableMemOpt.cpp b/lib/SILOptimizer/Mandatory/PredictableMemOpt.cpp
index ae811e4..0eba2c4 100644
--- a/lib/SILOptimizer/Mandatory/PredictableMemOpt.cpp
+++ b/lib/SILOptimizer/Mandatory/PredictableMemOpt.cpp
@@ -72,8 +72,6 @@
       Pointer = SEAI->getOperand();
     else if (auto BAI = dyn_cast<BeginAccessInst>(Pointer))
       Pointer = BAI->getSource();
-    else if (auto BUAI = dyn_cast<BeginUnpairedAccessInst>(Pointer))
-      Pointer = BUAI->getSource();
     else
       return Pointer;
   }
@@ -92,7 +90,8 @@
 ///
 /// If this pointer is to within an existential projection, it returns ~0U.
 ///
-static unsigned computeSubelement(SILValue Pointer, SILInstruction *RootInst) {
+static unsigned computeSubelement(SILValue Pointer,
+                                  SingleValueInstruction *RootInst) {
   unsigned SubEltNumber = 0;
   SILModule &M = RootInst->getModule();
   
@@ -101,22 +100,17 @@
     if (RootInst == Pointer)
       return SubEltNumber;
     
-    auto *Inst = cast<SILInstruction>(Pointer);
-    if (auto *PBI = dyn_cast<ProjectBoxInst>(Inst)) {
+    if (auto *PBI = dyn_cast<ProjectBoxInst>(Pointer)) {
       Pointer = PBI->getOperand();
       continue;
     }
 
-    if (auto *BAI = dyn_cast<BeginAccessInst>(Inst)) {
+    if (auto *BAI = dyn_cast<BeginAccessInst>(Pointer)) {
       Pointer = BAI->getSource();
       continue;
     }
-    if (auto *BUAI = dyn_cast<BeginUnpairedAccessInst>(Inst)) {
-      Pointer = BUAI->getSource();
-      continue;
-    }
 
-    if (auto *TEAI = dyn_cast<TupleElementAddrInst>(Inst)) {
+    if (auto *TEAI = dyn_cast<TupleElementAddrInst>(Pointer)) {
       SILType TT = TEAI->getOperand()->getType();
       
       // Keep track of what subelement is being referenced.
@@ -127,7 +121,7 @@
       continue;
     }
 
-    if (auto *SEAI = dyn_cast<StructElementAddrInst>(Inst)) {
+    if (auto *SEAI = dyn_cast<StructElementAddrInst>(Pointer)) {
       SILType ST = SEAI->getOperand()->getType();
       
       // Keep track of what subelement is being referenced.
@@ -142,7 +136,7 @@
     }
 
     
-    assert((isa<InitExistentialAddrInst>(Inst) || isa<InjectEnumAddrInst>(Inst))&&
+    assert(isa<InitExistentialAddrInst>(Pointer) &&
            "Unknown access path instruction");
     // Cannot promote loads and stores from within an existential projection.
     return ~0U;
@@ -207,7 +201,7 @@
     SILModule &Module;
     
     /// TheMemory - This is either an alloc_box or alloc_stack instruction.
-    SILInstruction *TheMemory;
+    AllocationInst *TheMemory;
     
     /// This is the SILType of the memory object.
     SILType MemoryType;
@@ -229,7 +223,7 @@
     bool HasAnyEscape = false;
     
   public:
-    AllocOptimize(SILInstruction *TheMemory,
+    AllocOptimize(AllocationInst *TheMemory,
                   SmallVectorImpl<DIMemoryUse> &Uses,
                   SmallVectorImpl<SILInstruction*> &Releases);
     
@@ -263,7 +257,7 @@
 } // end anonymous namespace
 
 
-AllocOptimize::AllocOptimize(SILInstruction *TheMemory,
+AllocOptimize::AllocOptimize(AllocationInst *TheMemory,
                              SmallVectorImpl<DIMemoryUse> &Uses,
                              SmallVectorImpl<SILInstruction*> &Releases)
 : Module(TheMemory->getModule()), TheMemory(TheMemory), Uses(Uses),
@@ -626,25 +620,30 @@
   // diagnostics pass this like one.
   
   // We only handle load and copy_addr right now.
+  SILValue src;
   if (auto CAI = dyn_cast<CopyAddrInst>(Inst)) {
     // If this is a CopyAddr, verify that the element type is loadable.  If not,
     // we can't explode to a load.
-    if (!CAI->getSrc()->getType().isLoadable(Module))
+    src = CAI->getSrc();
+    if (!src->getType().isLoadable(Module))
       return false;
-  } else if (!isa<LoadInst>(Inst))
+  } else if (auto load = dyn_cast<LoadInst>(Inst)) {
+    src = load->getOperand();
+  } else {
     return false;
-  
+  }
+
   // If the box has escaped at this instruction, we can't safely promote the
   // load.
   if (hasEscapedAt(Inst))
     return false;
   
-  SILType LoadTy = Inst->getOperand(0)->getType().getObjectType();
+  SILType LoadTy = src->getType().getObjectType();
   
   // If this is a load/copy_addr from a struct field that we want to promote,
   // compute the access path down to the field so we can determine precise
   // def/use behavior.
-  unsigned FirstElt = computeSubelement(Inst->getOperand(0), TheMemory);
+  unsigned FirstElt = computeSubelement(src, TheMemory);
   
   // If this is a load from within an enum projection, we can't promote it since
   // we don't track subelements in a type that could be changing.
@@ -692,20 +691,20 @@
   // Aggregate together all of the subelements into something that has the same
   // type as the load did, and emit smaller) loads for any subelements that were
   // not available.
-  auto NewVal = AggregateAvailableValues(Inst, LoadTy, Inst->getOperand(0),
+  auto Load = cast<LoadInst>(Inst);
+  auto NewVal = AggregateAvailableValues(Load, LoadTy, Load->getOperand(),
                                          AvailableValues, FirstElt);
   
   ++NumLoadPromoted;
   
   // Simply replace the load.
-  assert(isa<LoadInst>(Inst));
-  DEBUG(llvm::dbgs() << "  *** Promoting load: " << *Inst << "\n");
+  DEBUG(llvm::dbgs() << "  *** Promoting load: " << *Load << "\n");
   DEBUG(llvm::dbgs() << "      To value: " << *NewVal << "\n");
   
-  Inst->replaceAllUsesWith(NewVal);
-  SILValue Addr = Inst->getOperand(0);
-  Inst->eraseFromParent();
-  if (auto *AddrI = dyn_cast<SILInstruction>(Addr))
+  Load->replaceAllUsesWith(NewVal);
+  SILValue Addr = Load->getOperand();
+  Load->eraseFromParent();
+  if (auto *AddrI = Addr->getDefiningInstruction())
     recursivelyDeleteTriviallyDeadInstructions(AddrI);
   return true;
 }
@@ -833,7 +832,7 @@
       NewInst->dump();
       llvm_unreachable("Unknown instruction generated by copy_addr lowering");
       
-    case ValueKind::StoreInst:
+    case SILInstructionKind::StoreInst:
       // If it is a store to the memory object (as oppose to a store to
       // something else), track it as an access.
       if (StoreUse.isValid()) {
@@ -843,7 +842,7 @@
       }
       continue;
       
-    case ValueKind::LoadInst:
+    case SILInstructionKind::LoadInst:
       // If it is a load from the memory object (as oppose to a load from
       // something else), track it as an access.  We need to explicitly check to
       // see if the load accesses "TheMemory" because it could either be a load
@@ -856,12 +855,12 @@
       }
       continue;
       
-    case ValueKind::RetainValueInst:
-    case ValueKind::StrongRetainInst:
-    case ValueKind::StrongReleaseInst:
-    case ValueKind::UnownedRetainInst:
-    case ValueKind::UnownedReleaseInst:
-    case ValueKind::ReleaseValueInst:   // Destroy overwritten value
+    case SILInstructionKind::RetainValueInst:
+    case SILInstructionKind::StrongRetainInst:
+    case SILInstructionKind::StrongReleaseInst:
+    case SILInstructionKind::UnownedRetainInst:
+    case SILInstructionKind::UnownedReleaseInst:
+    case SILInstructionKind::ReleaseValueInst:   // Destroy overwritten value
       // These are ignored.
       continue;
     }
@@ -994,9 +993,10 @@
         ++I;
         continue;
       }
+      auto Alloc = cast<AllocationInst>(Inst);
 
-      DEBUG(llvm::dbgs() << "*** DI Optimize looking at: " << *Inst << "\n");
-      DIMemoryObjectInfo MemInfo(Inst);
+      DEBUG(llvm::dbgs() << "*** DI Optimize looking at: " << *Alloc << "\n");
+      DIMemoryObjectInfo MemInfo(Alloc);
 
       // Set up the datastructure used to collect the uses of the allocation.
       SmallVector<DIMemoryUse, 16> Uses;
@@ -1005,12 +1005,12 @@
       // Walk the use list of the pointer, collecting them.
       collectDIElementUsesFrom(MemInfo, Uses, Releases);
 
-      Changed |= AllocOptimize(Inst, Uses, Releases).doIt();
+      Changed |= AllocOptimize(Alloc, Uses, Releases).doIt();
       
       // Carefully move iterator to avoid invalidation problems.
       ++I;
-      if (Inst->use_empty()) {
-        Inst->eraseFromParent();
+      if (Alloc->use_empty()) {
+        Alloc->eraseFromParent();
         ++NumAllocRemoved;
         Changed = true;
       }
diff --git a/lib/SILOptimizer/PassManager/PassManager.cpp b/lib/SILOptimizer/PassManager/PassManager.cpp
index 5aa0f81..736ca54 100644
--- a/lib/SILOptimizer/PassManager/PassManager.cpp
+++ b/lib/SILOptimizer/PassManager/PassManager.cpp
@@ -291,12 +291,12 @@
 
   assert(analysesUnlocked() && "Expected all analyses to be unlocked!");
 
-  PrettyStackTraceSILFunctionTransform X(SFT, NumPassesRun);
-  DebugPrintEnabler DebugPrint(NumPassesRun);
-
   SFT->injectPassManager(this);
   SFT->injectFunction(F);
 
+  PrettyStackTraceSILFunctionTransform X(SFT, NumPassesRun);
+  DebugPrintEnabler DebugPrint(NumPassesRun);
+
   // If nothing changed since the last run of this pass, we can skip this
   // pass.
   CompletedPasses &completedPasses = CompletedPassesMap[F];
@@ -440,12 +440,12 @@
 
   const SILOptions &Options = getOptions();
 
-  PrettyStackTraceSILModuleTransform X(SMT, NumPassesRun);
-  DebugPrintEnabler DebugPrint(NumPassesRun);
-
   SMT->injectPassManager(this);
   SMT->injectModule(Mod);
 
+  PrettyStackTraceSILModuleTransform X(SMT, NumPassesRun);
+  DebugPrintEnabler DebugPrint(NumPassesRun);
+
   updateSILModuleStatsBeforeTransform(*Mod, SMT, *this, NumPassesRun);
 
   CurrentPassHasInvalidated = false;
@@ -719,7 +719,7 @@
     std::vector<Node> Nodes;
 
     /// The SILValue IDs which are printed as edge source labels.
-    llvm::DenseMap<const ValueBase *, unsigned> InstToIDMap;
+    llvm::DenseMap<const SILNode *, unsigned> InstToIDMap;
 
     typedef std::vector<Node>::iterator iterator;
   };
diff --git a/lib/SILOptimizer/SILCombiner/SILCombine.cpp b/lib/SILOptimizer/SILCombiner/SILCombine.cpp
index 0df5c69..53a653d 100644
--- a/lib/SILOptimizer/SILCombiner/SILCombine.cpp
+++ b/lib/SILOptimizer/SILCombiner/SILCombine.cpp
@@ -150,7 +150,7 @@
                          << "    New = " << *Result << '\n');
 
       // Everything uses the new instruction now.
-      replaceInstUsesWith(*I, Result);
+      replaceInstUsesWith(*cast<SingleValueInstruction>(I), Result);
 
       // Push the new instruction and any users onto the worklist.
       Worklist.addUsersToWorklist(Result);
@@ -181,12 +181,11 @@
                            << "    New = " << *Result << '\n');
 
         // Everything uses the new instruction now.
-        replaceInstUsesWith(*I, Result);
+        replaceInstUsesPairwiseWith(I, Result);
 
         // Push the new instruction and any users onto the worklist.
         Worklist.add(Result);
-        Worklist.addUsersToWorklist(Result);
-
+        Worklist.addUsersOfAllResultsToWorklist(Result);
 
         eraseInstFromFunction(*I);
       } else {
@@ -199,7 +198,7 @@
           eraseInstFromFunction(*I);
         } else {
           Worklist.add(I);
-          Worklist.addUsersToWorklist(I);
+          Worklist.addUsersOfAllResultsToWorklist(I);
         }
       }
       MadeChange = true;
@@ -266,16 +265,31 @@
 // replaceable with another preexisting expression. Here we add all uses of I
 // to the worklist, replace all uses of I with the new value, then return I,
 // so that the combiner will know that I was modified.
-SILInstruction *SILCombiner::replaceInstUsesWith(SILInstruction &I,
-                                                 ValueBase *V) {
+void SILCombiner::replaceInstUsesWith(SingleValueInstruction &I, ValueBase *V) {
   Worklist.addUsersToWorklist(&I);   // Add all modified instrs to worklist.
 
   DEBUG(llvm::dbgs() << "SC: Replacing " << I << "\n"
         "    with " << *V << '\n');
 
   I.replaceAllUsesWith(V);
+}
 
-  return &I;
+/// Replace all of the results of the old instruction with the
+/// corresponding results of the new instruction.
+void SILCombiner::replaceInstUsesPairwiseWith(SILInstruction *oldI,
+                                              SILInstruction *newI) {
+  DEBUG(llvm::dbgs() << "SC: Replacing " << *oldI << "\n"
+        "    with " << *newI << '\n');
+
+  auto oldResults = oldI->getResults();
+  auto newResults = newI->getResults();
+  assert(oldResults.size() == newResults.size());
+  for (auto i : indices(oldResults)) {
+    // Add all modified instrs to worklist.
+    Worklist.addUsersToWorklist(oldResults[i]);
+
+    oldResults[i]->replaceAllUsesWith(newResults[i]);
+  }
 }
 
 // Some instructions can never be "trivially dead" due to side effects or
@@ -289,12 +303,14 @@
                                             bool AddOperandsToWorklist) {
   DEBUG(llvm::dbgs() << "SC: ERASE " << I << '\n');
 
-  assert(onlyHaveDebugUses(&I) && "Cannot erase instruction that is used!");
+  assert(onlyHaveDebugUsesOfAllResults(&I) &&
+         "Cannot erase instruction that is used!");
+
   // Make sure that we reprocess all operands now that we reduced their
   // use counts.
   if (I.getNumOperands() < 8 && AddOperandsToWorklist) {
     for (auto &OpI : I.getAllOperands()) {
-      if (auto *Op = llvm::dyn_cast<SILInstruction>(&*OpI.get())) {
+      if (auto *Op = OpI.get()->getDefiningInstruction()) {
         DEBUG(llvm::dbgs() << "SC: add op " << *Op <<
               " from erased inst to worklist\n");
         Worklist.add(Op);
@@ -302,8 +318,9 @@
     }
   }
 
-  for (Operand *DU : getDebugUses(&I))
-    Worklist.remove(DU->getUser());
+  for (auto result : I.getResults())
+    for (Operand *DU : getDebugUses(result))
+      Worklist.remove(DU->getUser());
 
   Worklist.remove(&I);
   eraseFromParentWithDebugInsts(&I, InstIter);
@@ -339,7 +356,10 @@
     }
   }
   
-  void handleDeleteNotification(ValueBase *I) override {
+  void handleDeleteNotification(SILNode *node) override {
+    auto I = dyn_cast<SILInstruction>(node);
+    if (!I) return;
+
     // Linear searching the tracking list doesn't hurt because usually it only
     // contains a few elements.
     auto Iter = std::find(TrackingList.begin(), TrackingList.end(), I);
diff --git a/lib/SILOptimizer/SILCombiner/SILCombiner.h b/lib/SILOptimizer/SILCombiner/SILCombiner.h
index c5786b2..9fd6333 100644
--- a/lib/SILOptimizer/SILCombiner/SILCombiner.h
+++ b/lib/SILOptimizer/SILCombiner/SILCombiner.h
@@ -51,10 +51,8 @@
 
   /// If the given ValueBase is a SILInstruction add it to the worklist.
   void addValue(ValueBase *V) {
-    auto *I = dyn_cast<SILInstruction>(V);
-    if (!I)
-      return;
-    add(I);
+    if (auto *I = V->getDefiningInstruction())
+      add(I);
   }
 
   /// Add the given list of instructions in reverse order to the worklist. This
@@ -82,13 +80,22 @@
   }
 
   /// When an instruction has been simplified, add all of its users to the
-  /// worklist since additional simplifications of its users may have been
+  /// worklist, since additional simplifications of its users may have been
   /// exposed.
   void addUsersToWorklist(ValueBase *I) {
     for (auto UI : I->getUses())
       add(UI->getUser());
   }
 
+  /// When an instruction has been simplified, add all of its users to the
+  /// worklist, since additional simplifications of its users may have been
+  /// exposed.
+  void addUsersOfAllResultsToWorklist(SILInstruction *I) {
+    for (auto result : I->getResults()) {
+      addUsersToWorklist(result);
+    }
+  }
+
   /// Check that the worklist is empty and nuke the backing store for the map if
   /// it is large.
   void zap() {
@@ -130,7 +137,7 @@
       : AA(AA), Worklist(), MadeChange(false), RemoveCondFails(removeCondFails),
         Iteration(0), Builder(B),
         CastOpt(/* ReplaceInstUsesAction */
-                [&](SILInstruction *I, ValueBase * V) {
+                [&](SingleValueInstruction *I, ValueBase * V) {
                   replaceInstUsesWith(*I, V);
                 },
                 /* EraseAction */
@@ -152,7 +159,9 @@
   // replaceable with another preexisting expression. Here we add all uses of I
   // to the worklist, replace all uses of I with the new value, then return I,
   // so that the combiner will know that I was modified.
-  SILInstruction *replaceInstUsesWith(SILInstruction &I, ValueBase *V);
+  void replaceInstUsesWith(SingleValueInstruction &I, ValueBase *V);
+
+  void replaceInstUsesPairwiseWith(SILInstruction *oldI, SILInstruction *newI);
 
   // Some instructions can never be "trivially dead" due to side effects or
   // producing a void value. In those cases, since we cannot rely on
@@ -175,7 +184,7 @@
   }
 
   /// Base visitor that does not do anything.
-  SILInstruction *visitValueBase(ValueBase *V) { return nullptr; }
+  SILInstruction *visitSILInstruction(SILInstruction *I) { return nullptr; }
 
   /// Instruction visitors.
   SILInstruction *visitReleaseValueInst(ReleaseValueInst *DI);
diff --git a/lib/SILOptimizer/SILCombiner/SILCombinerApplyVisitors.cpp b/lib/SILOptimizer/SILCombiner/SILCombinerApplyVisitors.cpp
index d57ad29..16a7ba2 100644
--- a/lib/SILOptimizer/SILCombiner/SILCombinerApplyVisitors.cpp
+++ b/lib/SILOptimizer/SILCombiner/SILCombinerApplyVisitors.cpp
@@ -342,7 +342,9 @@
     Builder.createStrongRelease(AI.getLoc(), PAI, Builder.getDefaultAtomicity());
   }
 
-  SilCombiner->replaceInstUsesWith(*AI.getInstruction(), NAI.getInstruction());
+  if (auto apply = dyn_cast<ApplyInst>(AI))
+    SilCombiner->replaceInstUsesWith(*apply,
+                                     cast<ApplyInst>(NAI.getInstruction()));
   SilCombiner->eraseInstFromFunction(*AI.getInstruction());
   return true;
 }
@@ -477,6 +479,7 @@
   for (auto *Use : Value->getUses()) {
     SILInstruction *Inst = Use->getUser();
     if (isa<RefCountingInst>(Inst) ||
+        isa<StrongPinInst>(Inst) ||
         isa<DebugValueInst>(Inst)) {
       Uses.push_back(Inst);
       continue;
@@ -485,7 +488,7 @@
         isa<StructExtractInst>(Inst) ||
         isa<PointerToAddressInst>(Inst)) {
       Uses.push_back(Inst);
-      if (recursivelyCollectARCUsers(Uses, Inst))
+      if (recursivelyCollectARCUsers(Uses, cast<SingleValueInstruction>(Inst)))
         continue;
     }
     return false;
@@ -616,7 +619,7 @@
       return getAddressOfStackInit(ASI, CAI);
     return CAISrc;
   }
-  return SingleWrite;
+  return cast<InitExistentialAddrInst>(SingleWrite);
 }
 
 /// Find the init_existential, which could be used to determine a concrete
@@ -744,8 +747,8 @@
     NewAI = Builder.createApply(AI.getLoc(), AI.getCallee(), Substitutions,
                                 Args, cast<ApplyInst>(AI)->isNonThrowing());
 
-  if (isa<ApplyInst>(NewAI))
-    replaceInstUsesWith(*AI.getInstruction(), NewAI.getInstruction());
+  if (auto apply = dyn_cast<ApplyInst>(NewAI))
+    replaceInstUsesWith(*cast<ApplyInst>(AI.getInstruction()), apply);
   eraseInstFromFunction(*AI.getInstruction());
 
   return NewAI.getInstruction();
@@ -753,7 +756,8 @@
 
 /// Derive a concrete type of self and conformance from the init_existential
 /// instruction.
-static Optional<std::tuple<ProtocolConformanceRef, CanType, SILValue, SILValue>>
+static Optional<std::tuple<ProtocolConformanceRef, CanType,
+                           SingleValueInstruction*, SILValue>>
 getConformanceAndConcreteType(ASTContext &Ctx,
                               FullApplySite AI,
                               SILInstruction *InitExistential,
@@ -763,7 +767,7 @@
   CanType ConcreteType;
   // The existential type result of the found init_existential.
   CanType ExistentialType;
-  SILValue ConcreteTypeDef;
+  SingleValueInstruction *ConcreteTypeDef = nullptr;
   SILValue NewSelf;
 
   // FIXME: Factor this out. All we really need here is the ExistentialSig
@@ -812,7 +816,8 @@
   if (ConcreteType->isOpenedExistential()) {
     assert(!InitExistential->getTypeDependentOperands().empty() &&
            "init_existential is supposed to have a typedef operand");
-    ConcreteTypeDef = InitExistential->getTypeDependentOperands()[0].get();
+    ConcreteTypeDef = cast<SingleValueInstruction>(
+      InitExistential->getTypeDependentOperands()[0].get());
   }
 
   return std::make_tuple(*ExactConformance, ConcreteType,
@@ -863,7 +868,7 @@
 
   ProtocolConformanceRef Conformance = std::get<0>(*ConformanceAndConcreteType);
   CanType ConcreteType = std::get<1>(*ConformanceAndConcreteType);
-  SILValue ConcreteTypeDef = std::get<2>(*ConformanceAndConcreteType);
+  auto ConcreteTypeDef = std::get<2>(*ConformanceAndConcreteType);
   SILValue NewSelf = std::get<3>(*ConformanceAndConcreteType);
 
   SILOpenedArchetypesTracker *OldOpenedArchetypesTracker =
diff --git a/lib/SILOptimizer/SILCombiner/SILCombinerBuiltinVisitors.cpp b/lib/SILOptimizer/SILCombiner/SILCombinerBuiltinVisitors.cpp
index ab63eed..81f2492 100644
--- a/lib/SILOptimizer/SILCombiner/SILCombinerBuiltinVisitors.cpp
+++ b/lib/SILOptimizer/SILCombiner/SILCombinerBuiltinVisitors.cpp
@@ -287,12 +287,12 @@
 /// Given an index_raw_pointer Ptr, size_of(Metatype) * Distance create an
 /// address_to_pointer (index_addr ptr, Distance : $*Metatype) : $RawPointer
 /// instruction.
-static SILInstruction *createIndexAddrFrom(IndexRawPointerInst *I,
-                                           MetatypeInst *Metatype,
-                                           BuiltinInst *TruncOrBitCast,
-                                           SILValue Ptr, SILValue Distance,
-                                           SILType RawPointerTy,
-                                           SILBuilder &Builder) {
+static SILValue createIndexAddrFrom(IndexRawPointerInst *I,
+                                    MetatypeInst *Metatype,
+                                    BuiltinInst *TruncOrBitCast,
+                                    SILValue Ptr, SILValue Distance,
+                                    SILType RawPointerTy,
+                                    SILBuilder &Builder) {
   Builder.setCurrentDebugScope(I->getDebugScope());
   SILType InstanceType =
     Metatype->getType().getMetatypeInstanceType(I->getModule());
@@ -408,9 +408,11 @@
          getBitOpArgs(Prev, op, prevBits)) {
     combine(bits, prevBits);
   }
-  if (isNeutral(bits))
+  if (isNeutral(bits)) {
     // The bit operation has no effect, e.g. x | 0 -> x
-    return C->replaceInstUsesWith(*BI, op);
+    C->replaceInstUsesWith(*BI, op);
+    return BI;
+  }
 
   if (isZero(bits))
     // The bit operation yields to a constant, e.g. x & 0 -> 0
diff --git a/lib/SILOptimizer/SILCombiner/SILCombinerCastVisitors.cpp b/lib/SILOptimizer/SILCombiner/SILCombinerCastVisitors.cpp
index 84f9934..3072069 100644
--- a/lib/SILOptimizer/SILCombiner/SILCombinerCastVisitors.cpp
+++ b/lib/SILOptimizer/SILCombiner/SILCombinerCastVisitors.cpp
@@ -524,7 +524,8 @@
   auto Converted = CFI->getConverted();
   while (!CFI->use_empty()) {
     auto *Use = *(CFI->use_begin());
-    assert(!Use->getUser()->hasValue() && "Did not expect user with a result!");
+    assert(Use->getUser()->getResults().empty() &&
+           "Did not expect user with a result!");
     Use->set(Converted);
   }
 
diff --git a/lib/SILOptimizer/SILCombiner/SILCombinerMiscVisitors.cpp b/lib/SILOptimizer/SILCombiner/SILCombinerMiscVisitors.cpp
index 0bf6a53..7f6c5eb 100644
--- a/lib/SILOptimizer/SILCombiner/SILCombinerMiscVisitors.cpp
+++ b/lib/SILOptimizer/SILCombiner/SILCombinerMiscVisitors.cpp
@@ -431,7 +431,7 @@
 
   // Erase the 'live-range'
   for (auto *Inst : ToDelete) {
-    Inst->replaceAllUsesWithUndef();
+    Inst->replaceAllUsesOfAllResultsWithUndef();
     eraseInstFromFunction(*Inst);
   }
   return eraseInstFromFunction(*AS);
@@ -477,7 +477,7 @@
   // Given a load with multiple struct_extracts/tuple_extracts and no other
   // uses, canonicalize the load into several (struct_element_addr (load))
   // pairs.
-  using ProjInstPairTy = std::pair<Projection, SILInstruction *>;
+  using ProjInstPairTy = std::pair<Projection, SingleValueInstruction *>;
 
   // Go through the loads uses and add any users that are projections to the
   // projection list.
@@ -489,7 +489,8 @@
     if (!isa<StructExtractInst>(User) && !isa<TupleExtractInst>(User))
       return nullptr;
 
-    Projections.push_back({Projection(User), User});
+    auto extract = cast<SingleValueInstruction>(User);
+    Projections.push_back({Projection(extract), extract});
   }
 
   // The reason why we sort the list is so that we will process projections with
@@ -667,7 +668,7 @@
 
   for (auto *Inst : ToRemove) {
     // Replace any still-remaining uses with undef and erase.
-    Inst->replaceAllUsesWithUndef();
+    Inst->replaceAllUsesOfAllResultsWithUndef();
     eraseInstFromFunction(*Inst);
   }
 
@@ -1055,7 +1056,7 @@
 
   for (auto *Inst : ToRemove) {
     // Replace any still-remaining uses with undef values and erase.
-    Inst->replaceAllUsesWithUndef();
+    Inst->replaceAllUsesOfAllResultsWithUndef();
     eraseInstFromFunction(*Inst);
   }
 
@@ -1358,7 +1359,7 @@
   if (auto *UC = dyn_cast<UpcastInst>(MDVal))
     MDVal = UC->getOperand();
 
-  SILInstruction *NewInst = nullptr;
+  SingleValueInstruction *NewInst = nullptr;
   if (auto *MI = dyn_cast<MetatypeInst>(MDVal)) {
     auto &Mod = ARDI->getModule();
     auto SILInstanceTy = MI->getType().getMetatypeInstanceType(Mod);
diff --git a/lib/SILOptimizer/Transforms/ARCCodeMotion.cpp b/lib/SILOptimizer/Transforms/ARCCodeMotion.cpp
index e5f8d10..f8642e2 100644
--- a/lib/SILOptimizer/Transforms/ARCCodeMotion.cpp
+++ b/lib/SILOptimizer/Transforms/ARCCodeMotion.cpp
@@ -653,7 +653,7 @@
     //
     // We can not move a release above the instruction that defines the
     // released value.
-    if (II == Ptr)
+    if (II == Ptr->getDefiningInstruction())
       return true;
     // Identical RC root blocks code motion, we will be able to move this release
     // further once we move the blocking release.
diff --git a/lib/SILOptimizer/Transforms/AllocBoxToStack.cpp b/lib/SILOptimizer/Transforms/AllocBoxToStack.cpp
index dee5158..b457d15 100644
--- a/lib/SILOptimizer/Transforms/AllocBoxToStack.cpp
+++ b/lib/SILOptimizer/Transforms/AllocBoxToStack.cpp
@@ -141,7 +141,8 @@
     // If we have a copy value or a mark_uninitialized, add its uses to the work
     // list and continue.
     if (isa<MarkUninitializedInst>(User) || isa<CopyValueInst>(User)) {
-      copy(User->getUses(), std::back_inserter(Worklist));
+      copy(cast<SingleValueInstruction>(User)->getUses(),
+           std::back_inserter(Worklist));
       continue;
     }
 
@@ -212,8 +213,8 @@
     // If we have a copy_value, the copy value does not cause an escape, but its
     // uses might do so... so add the copy_value's uses to the worklist and
     // continue.
-    if (isa<CopyValueInst>(User)) {
-      copy(User->getUses(), std::back_inserter(Worklist));
+    if (auto CVI = dyn_cast<CopyValueInst>(User)) {
+      copy(CVI->getUses(), std::back_inserter(Worklist));
       continue;
     }
 
@@ -385,7 +386,8 @@
     // If our user instruction is a copy_value or a marked_uninitialized, visit
     // the users recursively.
     if (isa<MarkUninitializedInst>(User) || isa<CopyValueInst>(User)) {
-      copy(User->getUses(), std::back_inserter(Worklist));
+      copy(cast<SingleValueInstruction>(User)->getUses(),
+           std::back_inserter(Worklist));
       continue;
     }
 
@@ -514,11 +516,11 @@
 
     // Look through any mark_uninitialized, copy_values.
     if (isa<MarkUninitializedInst>(User) || isa<CopyValueInst>(User)) {
-      transform(User->getUses(), std::back_inserter(Worklist),
+      auto Inst = cast<SingleValueInstruction>(User);
+      transform(Inst->getUses(), std::back_inserter(Worklist),
                 [](Operand *Op) -> SILInstruction * { return Op->getUser(); });
-      User->replaceAllUsesWith(
-          SILUndef::get(User->getType(), User->getModule()));
-      User->eraseFromParent();
+      Inst->replaceAllUsesWithUndef();
+      Inst->eraseFromParent();
       continue;
     }
 
@@ -538,7 +540,7 @@
 /// promoting some of its box parameters to stack addresses.
 class PromotedParamCloner : public SILClonerWithScopes<PromotedParamCloner> {
 public:
-  friend class SILVisitor<PromotedParamCloner>;
+  friend class SILInstructionVisitor<PromotedParamCloner>;
   friend class SILCloner<PromotedParamCloner>;
 
   PromotedParamCloner(SILFunction *Orig, IsSerialized_t Serialized,
@@ -639,8 +641,9 @@
   auto *Fn = M.createFunction(
       SILLinkage::Shared, ClonedName, ClonedTy, Orig->getGenericEnvironment(),
       Orig->getLocation(), Orig->isBare(), IsNotTransparent, Serialized,
-      Orig->isThunk(), Orig->getClassSubclassScope(), Orig->getInlineStrategy(),
-      Orig->getEffectsKind(), Orig, Orig->getDebugScope());
+      Orig->getEntryCount(), Orig->isThunk(), Orig->getClassSubclassScope(),
+      Orig->getInlineStrategy(), Orig->getEffectsKind(), Orig,
+      Orig->getDebugScope());
   for (auto &Attr : Orig->getSemanticsAttrs()) {
     Fn->addSemanticsAttr(Attr);
   }
@@ -811,7 +814,7 @@
     // address because we've proven we can keep this value on the stack. The
     // partial_apply had ownership of this box so we must now release it
     // explicitly when the partial_apply is released.
-    SILInstruction *Box = cast<SILInstruction>(O.get());
+    auto *Box = cast<SingleValueInstruction>(O.get());
     assert((isa<AllocBoxInst>(Box) || isa<CopyValueInst>(Box)) &&
            "Expected either an alloc box or a copy of an alloc box");
     SILBuilder B(Box);
diff --git a/lib/SILOptimizer/Transforms/ArrayCountPropagation.cpp b/lib/SILOptimizer/Transforms/ArrayCountPropagation.cpp
index e82a519..87e44b8 100644
--- a/lib/SILOptimizer/Transforms/ArrayCountPropagation.cpp
+++ b/lib/SILOptimizer/Transforms/ArrayCountPropagation.cpp
@@ -123,7 +123,9 @@
   for (auto *Opd : Def->getUses()) {
     auto *User = Opd->getUser();
     // Ignore reference counting and debug instructions.
-    if (isa<RefCountingInst>(User) || isa<DebugValueInst>(User))
+    if (isa<RefCountingInst>(User) ||
+        isa<StrongPinInst>(User) ||
+        isa<DebugValueInst>(User))
       continue;
 
     // Array value projection.
@@ -134,11 +136,13 @@
     }
 
     // Check array semantic calls.
-    ArraySemanticsCall ArrayOp(User);
-    if (ArrayOp && ArrayOp.doesNotChangeArray()) {
-      if (ArrayOp.getKind() == ArrayCallKind::kGetCount)
-        CountCalls.insert(ArrayOp);
-      continue;
+    if (auto apply = dyn_cast<ApplyInst>(User)) {
+      ArraySemanticsCall ArrayOp(apply);
+      if (ArrayOp && ArrayOp.doesNotChangeArray()) {
+        if (ArrayOp.getKind() == ArrayCallKind::kGetCount)
+          CountCalls.insert(ArrayOp);
+        continue;
+      }
     }
 
     // An operation that escapes or modifies the array value.
diff --git a/lib/SILOptimizer/Transforms/ArrayElementValuePropagation.cpp b/lib/SILOptimizer/Transforms/ArrayElementValuePropagation.cpp
index 522d673..be7f376 100644
--- a/lib/SILOptimizer/Transforms/ArrayElementValuePropagation.cpp
+++ b/lib/SILOptimizer/Transforms/ArrayElementValuePropagation.cpp
@@ -190,7 +190,9 @@
   for (auto *Opd : Def->getUses()) {
     auto *User = Opd->getUser();
     // Ignore reference counting and debug instructions.
-    if (isa<RefCountingInst>(User) || isa<DebugValueInst>(User))
+    if (isa<RefCountingInst>(User) ||
+        isa<StrongPinInst>(User) ||
+        isa<DebugValueInst>(User))
       continue;
 
     // Array value projection.
diff --git a/lib/SILOptimizer/Transforms/AssumeSingleThreaded.cpp b/lib/SILOptimizer/Transforms/AssumeSingleThreaded.cpp
index 5587520..ca3c528 100644
--- a/lib/SILOptimizer/Transforms/AssumeSingleThreaded.cpp
+++ b/lib/SILOptimizer/Transforms/AssumeSingleThreaded.cpp
@@ -45,6 +45,8 @@
       for (auto &I : BB) {
         if (auto RCInst = dyn_cast<RefCountingInst>(&I))
           RCInst->setNonAtomic();
+        if (auto RCInst = dyn_cast<StrongPinInst>(&I))
+          RCInst->setNonAtomic();
       }
     }
     invalidateAnalysis(SILAnalysis::InvalidationKind::Instructions);
diff --git a/lib/SILOptimizer/Transforms/CSE.cpp b/lib/SILOptimizer/Transforms/CSE.cpp
index 5684342..38aa71e 100644
--- a/lib/SILOptimizer/Transforms/CSE.cpp
+++ b/lib/SILOptimizer/Transforms/CSE.cpp
@@ -82,7 +82,7 @@
   using hash_code = llvm::hash_code;
 
 public:
-  hash_code visitValueBase(ValueBase *) {
+  hash_code visitSILInstruction(SILInstruction *) {
     llvm_unreachable("No hash implemented for the given type");
   }
 
@@ -395,20 +395,18 @@
   if (LHS.isSentinel() || RHS.isSentinel())
     return LHSI == RHSI;
 
-  if (isa<OpenExistentialRefInst>(LHSI) && isa<OpenExistentialRefInst>(RHSI)) {
-    if (LHSI->getNumOperands() != RHSI->getNumOperands())
-      return false;
-
+  auto LOpen = dyn_cast<OpenExistentialRefInst>(LHSI);
+  auto ROpen = dyn_cast<OpenExistentialRefInst>(RHSI);
+  if (LOpen && ROpen) {
     // Check operands.
-    for (unsigned i = 0, e = LHSI->getNumOperands(); i != e; ++i)
-      if (LHSI->getOperand(i) !=  RHSI->getOperand(i))
-        return false;
+    if (LOpen->getOperand() != ROpen->getOperand())
+      return false;
 
     // Consider the types of two open_existential_ref instructions to be equal,
     // if the sets of protocols they conform to are equal.
-    auto LHSArchetypeTy = LHSI->getType().castTo<ArchetypeType>();
+    auto LHSArchetypeTy = LOpen->getType().castTo<ArchetypeType>();
     auto LHSConformsTo = LHSArchetypeTy->getConformsTo();
-    auto RHSArchetypeTy = RHSI->getType().castTo<ArchetypeType>();
+    auto RHSArchetypeTy = ROpen->getType().castTo<ArchetypeType>();
     auto RHSConformsTo = RHSArchetypeTy->getConformsTo();
     return LHSConformsTo == RHSConformsTo;
   }
@@ -430,7 +428,7 @@
   typedef llvm::ScopedHashTableVal<SimpleValue, ValueBase *> SimpleValueHTType;
   typedef llvm::RecyclingAllocator<llvm::BumpPtrAllocator, SimpleValueHTType>
   AllocatorTy;
-  typedef llvm::ScopedHashTable<SimpleValue, ValueBase *,
+  typedef llvm::ScopedHashTable<SimpleValue, SILInstruction *,
                                 llvm::DenseMapInfo<SimpleValue>,
                                 AllocatorTy> ScopedHTType;
 
@@ -507,7 +505,7 @@
   };
 
   bool processNode(DominanceInfoNode *Node);
-  bool processOpenExistentialRef(SILInstruction *Inst, ValueBase *V,
+  bool processOpenExistentialRef(OpenExistentialRefInst *Inst, ValueBase *V,
                                  SILBasicBlock::iterator &I);
 };
 } // namespace swift
@@ -564,7 +562,7 @@
   // is remapping the archetypes when it is required.
   class InstructionCloner : public SILCloner<InstructionCloner> {
     friend class SILCloner<InstructionCloner>;
-    friend class SILVisitor<InstructionCloner>;
+    friend class SILInstructionVisitor<InstructionCloner>;
     SILInstruction *Result = nullptr;
   public:
     InstructionCloner(SILFunction *F) : SILCloner(*F) {}
@@ -644,12 +642,15 @@
 /// \Inst is the open_existential_ref instruction
 /// \V is the dominating open_existential_ref instruction
 /// \I is the iterator referring to the current instruction.
-bool CSE::processOpenExistentialRef(SILInstruction *Inst, ValueBase *V,
+bool CSE::processOpenExistentialRef(OpenExistentialRefInst *Inst, ValueBase *V,
                                     SILBasicBlock::iterator &I) {
-  assert(isa<OpenExistentialRefInst>(Inst));
+  // All the open instructions are single-value instructions.
+  auto VI = dyn_cast<SingleValueInstruction>(V);
+  if (!VI) return false;
+
   llvm::SmallSetVector<SILInstruction *, 16> Candidates;
   auto OldOpenedArchetype = getOpenedArchetypeOf(Inst);
-  auto NewOpenedArchetype = getOpenedArchetypeOf(dyn_cast<SILInstruction>(V));
+  auto NewOpenedArchetype = getOpenedArchetypeOf(VI);
 
   // Collect all candidates that may contain opened archetypes
   // that need to be replaced.
@@ -684,7 +685,7 @@
   // TODO: Move it to CSE instance to avoid recreating it every time?
   SILOpenedArchetypesTracker OpenedArchetypesTracker(Inst->getFunction());
   // Register the new archetype to be used.
-  OpenedArchetypesTracker.registerOpenedArchetypes(dyn_cast<SILInstruction>(V));
+  OpenedArchetypesTracker.registerOpenedArchetypes(VI);
   // Use a cloner. It makes copying the instruction and remapping of
   // opened archetypes trivial.
   InstructionCloner Cloner(I->getFunction());
@@ -700,22 +701,31 @@
     auto Candidate = Candidates.pop_back_val();
     if (Processed.count(Candidate))
       continue;
-    // True if a candidate depends on the old opened archetype.
-    bool DependsOnOldOpenedArchetype = !Candidate->getTypeDependentOperands().empty();
-    if (!Candidate->use_empty() &&
-        Candidate->getType().hasOpenedExistential()) {
-      // Check if the result type of the candidate depends on the opened
-      // existential in question.
+
+    // Compute if a candidate depends on the old opened archetype.
+    // It always does if it has any type-dependent operands.
+    bool DependsOnOldOpenedArchetype =
+      !Candidate->getTypeDependentOperands().empty();
+
+    // Look for dependencies propagated via the candidate's results.
+    for (auto CandidateResult : Candidate->getResults()) {
+      if (CandidateResult->use_empty() ||
+          !CandidateResult->getType().hasOpenedExistential())
+        continue;
+
+      // Check if the result type depends on this specific opened existential.
       auto ResultDependsOnOldOpenedArchetype =
-          Candidate->getType().getSwiftRValueType().findIf(
+          CandidateResult->getType().getSwiftRValueType().findIf(
               [&OldOpenedArchetype](Type t) -> bool {
                 return (CanType(t) == OldOpenedArchetype);
               });
+
+      // If it does, the candidate depends on the opened existential.
       if (ResultDependsOnOldOpenedArchetype) {
         DependsOnOldOpenedArchetype |= ResultDependsOnOldOpenedArchetype;
-        // We need to update uses of this candidate, because their types
-        // may be affected.
-        for (auto Use : Candidate->getUses()) {
+
+        // The users of this candidate are new candidates.
+        for (auto Use : CandidateResult->getUses()) {
           Candidates.insert(Use->getUser());
         }
       }
@@ -733,7 +743,7 @@
     auto NewI = Cloner.clone(Candidate);
     // Result types of candidate's uses instructions may be using this archetype.
     // Thus, we need to try to replace it there.
-    Candidate->replaceAllUsesWith(NewI);
+    Candidate->replaceAllUsesPairwiseWith(NewI);
     if (I == Candidate->getIterator())
       I = NewI->getIterator();
     eraseFromParentWithDebugInsts(Candidate, I);
@@ -767,7 +777,7 @@
     if (SILValue V = simplifyInstruction(Inst)) {
       DEBUG(llvm::dbgs() << "SILCSE SIMPLIFY: " << *Inst << "  to: " << *V
             << '\n');
-      Inst->replaceAllUsesWith(V);
+      cast<SingleValueInstruction>(Inst)->replaceAllUsesWith(V);
       Inst->eraseFromParent();
       Changed = true;
       ++NumSimplify;
@@ -786,14 +796,17 @@
 
     // Now that we know we have an instruction we understand see if the
     // instruction has an available value.  If so, use it.
-    if (ValueBase *V = AvailableValues->lookup(Inst)) {
-      DEBUG(llvm::dbgs() << "SILCSE CSE: " << *Inst << "  to: " << *V << '\n');
+    if (SILInstruction *AvailInst = AvailableValues->lookup(Inst)) {
+      DEBUG(llvm::dbgs() << "SILCSE CSE: " << *Inst << "  to: " << *AvailInst
+                         << '\n');
       // Instructions producing a new opened archetype need a special handling,
       // because replacing these instructions may require a replacement
       // of the opened archetype type operands in some of the uses.
       if (!isa<OpenExistentialRefInst>(Inst) ||
-          processOpenExistentialRef(Inst, V, I)) {
-        Inst->replaceAllUsesWith(V);
+          processOpenExistentialRef(cast<OpenExistentialRefInst>(Inst),
+                                    cast<OpenExistentialRefInst>(AvailInst),
+                                    I)) {
+        Inst->replaceAllUsesPairwiseWith(AvailInst);
         Inst->eraseFromParent();
         Changed = true;
         ++NumCSE;
@@ -859,58 +872,58 @@
     return !EMI->getOperand()->getType().isAddress();
   }
   switch (Inst->getKind()) {
-    case ValueKind::FunctionRefInst:
-    case ValueKind::GlobalAddrInst:
-    case ValueKind::IntegerLiteralInst:
-    case ValueKind::FloatLiteralInst:
-    case ValueKind::StringLiteralInst:
-    case ValueKind::StructInst:
-    case ValueKind::StructExtractInst:
-    case ValueKind::StructElementAddrInst:
-    case ValueKind::TupleInst:
-    case ValueKind::TupleExtractInst:
-    case ValueKind::TupleElementAddrInst:
-    case ValueKind::MetatypeInst:
-    case ValueKind::ValueMetatypeInst:
-    case ValueKind::ObjCProtocolInst:
-    case ValueKind::RefElementAddrInst:
-    case ValueKind::RefTailAddrInst:
-    case ValueKind::ProjectBoxInst:
-    case ValueKind::IndexRawPointerInst:
-    case ValueKind::IndexAddrInst:
-    case ValueKind::PointerToAddressInst:
-    case ValueKind::AddressToPointerInst:
-    case ValueKind::CondFailInst:
-    case ValueKind::EnumInst:
-    case ValueKind::UncheckedEnumDataInst:
-    case ValueKind::IsNonnullInst:
-    case ValueKind::UncheckedTrivialBitCastInst:
-    case ValueKind::UncheckedBitwiseCastInst:
-    case ValueKind::RefToRawPointerInst:
-    case ValueKind::RawPointerToRefInst:
-    case ValueKind::RefToUnownedInst:
-    case ValueKind::UnownedToRefInst:
-    case ValueKind::RefToUnmanagedInst:
-    case ValueKind::UnmanagedToRefInst:
-    case ValueKind::UpcastInst:
-    case ValueKind::ThickToObjCMetatypeInst:
-    case ValueKind::ObjCToThickMetatypeInst:
-    case ValueKind::UncheckedRefCastInst:
-    case ValueKind::UncheckedAddrCastInst:
-    case ValueKind::ObjCMetatypeToObjectInst:
-    case ValueKind::ObjCExistentialMetatypeToObjectInst:
-    case ValueKind::SelectEnumInst:
-    case ValueKind::SelectValueInst:
-    case ValueKind::RefToBridgeObjectInst:
-    case ValueKind::BridgeObjectToRefInst:
-    case ValueKind::BridgeObjectToWordInst:
-    case ValueKind::ThinFunctionToPointerInst:
-    case ValueKind::PointerToThinFunctionInst:
-    case ValueKind::MarkDependenceInst:
-    case ValueKind::OpenExistentialRefInst:
-      return true;
-    default:
-      return false;
+  case SILInstructionKind::FunctionRefInst:
+  case SILInstructionKind::GlobalAddrInst:
+  case SILInstructionKind::IntegerLiteralInst:
+  case SILInstructionKind::FloatLiteralInst:
+  case SILInstructionKind::StringLiteralInst:
+  case SILInstructionKind::StructInst:
+  case SILInstructionKind::StructExtractInst:
+  case SILInstructionKind::StructElementAddrInst:
+  case SILInstructionKind::TupleInst:
+  case SILInstructionKind::TupleExtractInst:
+  case SILInstructionKind::TupleElementAddrInst:
+  case SILInstructionKind::MetatypeInst:
+  case SILInstructionKind::ValueMetatypeInst:
+  case SILInstructionKind::ObjCProtocolInst:
+  case SILInstructionKind::RefElementAddrInst:
+  case SILInstructionKind::RefTailAddrInst:
+  case SILInstructionKind::ProjectBoxInst:
+  case SILInstructionKind::IndexRawPointerInst:
+  case SILInstructionKind::IndexAddrInst:
+  case SILInstructionKind::PointerToAddressInst:
+  case SILInstructionKind::AddressToPointerInst:
+  case SILInstructionKind::CondFailInst:
+  case SILInstructionKind::EnumInst:
+  case SILInstructionKind::UncheckedEnumDataInst:
+  case SILInstructionKind::IsNonnullInst:
+  case SILInstructionKind::UncheckedTrivialBitCastInst:
+  case SILInstructionKind::UncheckedBitwiseCastInst:
+  case SILInstructionKind::RefToRawPointerInst:
+  case SILInstructionKind::RawPointerToRefInst:
+  case SILInstructionKind::RefToUnownedInst:
+  case SILInstructionKind::UnownedToRefInst:
+  case SILInstructionKind::RefToUnmanagedInst:
+  case SILInstructionKind::UnmanagedToRefInst:
+  case SILInstructionKind::UpcastInst:
+  case SILInstructionKind::ThickToObjCMetatypeInst:
+  case SILInstructionKind::ObjCToThickMetatypeInst:
+  case SILInstructionKind::UncheckedRefCastInst:
+  case SILInstructionKind::UncheckedAddrCastInst:
+  case SILInstructionKind::ObjCMetatypeToObjectInst:
+  case SILInstructionKind::ObjCExistentialMetatypeToObjectInst:
+  case SILInstructionKind::SelectEnumInst:
+  case SILInstructionKind::SelectValueInst:
+  case SILInstructionKind::RefToBridgeObjectInst:
+  case SILInstructionKind::BridgeObjectToRefInst:
+  case SILInstructionKind::BridgeObjectToWordInst:
+  case SILInstructionKind::ThinFunctionToPointerInst:
+  case SILInstructionKind::PointerToThinFunctionInst:
+  case SILInstructionKind::MarkDependenceInst:
+  case SILInstructionKind::OpenExistentialRefInst:
+    return true;
+  default:
+    return false;
   }
 }
 
diff --git a/lib/SILOptimizer/Transforms/CopyForwarding.cpp b/lib/SILOptimizer/Transforms/CopyForwarding.cpp
index 0221cb1..ec8ce27 100644
--- a/lib/SILOptimizer/Transforms/CopyForwarding.cpp
+++ b/lib/SILOptimizer/Transforms/CopyForwarding.cpp
@@ -481,19 +481,19 @@
       continue;
     }
     switch (UserInst->getKind()) {
-    case ValueKind::LoadInst:
+    case SILInstructionKind::LoadInst:
       IsLoadedFrom = true;
       SrcUserInsts.insert(UserInst);
       break;
-    case ValueKind::ExistentialMetatypeInst:
-    case ValueKind::InjectEnumAddrInst:
-    case ValueKind::StoreInst:
+    case SILInstructionKind::ExistentialMetatypeInst:
+    case SILInstructionKind::InjectEnumAddrInst:
+    case SILInstructionKind::StoreInst:
       SrcUserInsts.insert(UserInst);
       break;
-    case ValueKind::DebugValueAddrInst:
+    case SILInstructionKind::DebugValueAddrInst:
       SrcDebugValueInsts.insert(cast<DebugValueAddrInst>(UserInst));
       break;
-    case ValueKind::DeallocStackInst:
+    case SILInstructionKind::DeallocStackInst:
       break;
     default:
       // Most likely one of:
@@ -914,10 +914,11 @@
 findAddressRootAndUsers(ValueBase *Def,
                         SmallPtrSetImpl<SILInstruction*> &RootUserInsts) {
   if (isa<InitEnumDataAddrInst>(Def) || isa<InitExistentialAddrInst>(Def)) {
-    SILValue InitRoot = cast<SILInstruction>(Def)->getOperand(0);
+    auto InitInst = cast<SingleValueInstruction>(Def);
+    SILValue InitRoot = InitInst->getOperand(0);
     for (auto *Use : InitRoot->getUses()) {
       auto *UserInst = Use->getUser();
-      if (UserInst == Def)
+      if (UserInst == InitInst)
         continue;
       RootUserInsts.insert(UserInst);
     }
@@ -954,12 +955,13 @@
   while (SI != SE) {
     --SI;
     SILInstruction *UserInst = &*SI;
-    if (UserInst == CopyDestDef)
+    if (UserInst == CopyDestDef->getDefiningInstruction())
       seenCopyDestDef = true;
 
     // If we see another use of Dest, then Dest is live after the Src location
     // is initialized, so we really need the copy.
-    if (UserInst == CopyDestRoot || DestUserInsts.count(UserInst)
+    if (UserInst == CopyDestRoot->getDefiningInstruction()
+        || DestUserInsts.count(UserInst)
         || RootUserInsts.count(UserInst)) {
       if (auto *DVAI = dyn_cast<DebugValueAddrInst>(UserInst)) {
         DebugValueInstsToDelete.push_back(DVAI);
@@ -1004,7 +1006,7 @@
   }
   // Rematerialize the projection if needed by simply moving it.
   if (seenCopyDestDef) {
-    cast<SILInstruction>(CopyDestDef)->moveBefore(&*SI);
+    CopyDestDef->getDefiningInstruction()->moveBefore(&*SI);
   }
   // Now that an init was found, it is safe to substitute all recorded uses
   // with the copy's dest.
@@ -1349,7 +1351,8 @@
 {
   AliasAnalysis *AA = nullptr;
 
-  static bool collectLoads(SILInstruction *CurrentInst, SILInstruction *addr,
+  static bool collectLoads(SILInstruction *CurrentInst,
+                           SingleValueInstruction *addr,
                            llvm::SmallPtrSetImpl<SILInstruction *> &loadInsts);
 
   bool checkNoSourceModification(CopyAddrInst *copyInst,
@@ -1407,7 +1410,7 @@
 /// Transitively explore all data flow uses of the given \p address until
 /// reaching a load or returning false.
 bool TempRValueOptPass::
-collectLoads(SILInstruction *user, SILInstruction *address,
+collectLoads(SILInstruction *user, SingleValueInstruction *address,
              llvm::SmallPtrSetImpl<SILInstruction *> &loadInsts) {
   // All normal uses (loads) must be in the initialization block.
   // (The destroy and dealloc are commonly in a different block though.)
@@ -1428,23 +1431,26 @@
       DEBUG(llvm::dbgs() << "  Temp use may write/destroy its source" << *user);
       return false;
 
-    case ValueKind::StructElementAddrInst:
-    case ValueKind::TupleElementAddrInst:
+    case SILInstructionKind::StructElementAddrInst:
+    case SILInstructionKind::TupleElementAddrInst: {
       // Transitively look through projections on stack addresses.
-      for (auto *useOper : user->getUses()) {
-        if (!collectLoads(useOper->getUser(), user, loadInsts))
+      auto proj = cast<SingleValueInstruction>(user);
+      for (auto *useOper : proj->getUses()) {
+        if (!collectLoads(useOper->getUser(), proj, loadInsts))
           return false;
       }
       return true;
+    }
 
-    case ValueKind::LoadInst:
-    case ValueKind::LoadBorrowInst:
+    case SILInstructionKind::LoadInst:
+    case SILInstructionKind::LoadBorrowInst: {
       // Loads are the end of the data flow chain. The users of the load can't
       // access the temporary storage.
       loadInsts.insert(user);
       return true;
+    }
 
-    case ValueKind::CopyAddrInst: {
+    case SILInstructionKind::CopyAddrInst: {
       // copy_addr which read from the temporary are like loads.
       // TODO: Handle copy_addr [take]. But this doesn't seem to be important.
       auto *copyFromTmp = cast<CopyAddrInst>(user);
@@ -1452,7 +1458,7 @@
         DEBUG(llvm::dbgs() << "  Temp written or taken" << *user);
         return false;
       }
-      loadInsts.insert(user);
+      loadInsts.insert(copyFromTmp);
       return true;
     }
   }
@@ -1538,20 +1544,20 @@
     Operand *use = *tempObj->use_begin();
     SILInstruction *user = use->getUser();
     switch (user->getKind()) {
-      case ValueKind::DestroyAddrInst:
-      case ValueKind::DeallocStackInst:
-        user->eraseFromParent();
-        break;
-      case ValueKind::CopyAddrInst:
-      case ValueKind::StructElementAddrInst:
-      case ValueKind::TupleElementAddrInst:
-      case ValueKind::LoadInst:
-      case ValueKind::LoadBorrowInst:
-        use->set(copyInst->getSrc());
-        break;
+    case SILInstructionKind::DestroyAddrInst:
+    case SILInstructionKind::DeallocStackInst:
+      user->eraseFromParent();
+      break;
+    case SILInstructionKind::CopyAddrInst:
+    case SILInstructionKind::StructElementAddrInst:
+    case SILInstructionKind::TupleElementAddrInst:
+    case SILInstructionKind::LoadInst:
+    case SILInstructionKind::LoadBorrowInst:
+      use->set(copyInst->getSrc());
+      break;
 
-      default:
-        llvm_unreachable("unhandled instruction");
+    default:
+      llvm_unreachable("unhandled instruction");
     }
   }
   tempObj->eraseFromParent();
diff --git a/lib/SILOptimizer/Transforms/DeadCodeElimination.cpp b/lib/SILOptimizer/Transforms/DeadCodeElimination.cpp
index 767dd6a..df77071 100644
--- a/lib/SILOptimizer/Transforms/DeadCodeElimination.cpp
+++ b/lib/SILOptimizer/Transforms/DeadCodeElimination.cpp
@@ -73,7 +73,7 @@
 class DCE : public SILFunctionTransform {
   typedef llvm::DomTreeNodeBase<SILBasicBlock> PostDomTreeNode;
 
-  llvm::SmallPtrSet<ValueBase *, 16> LiveValues;
+  llvm::SmallPtrSet<SILNode *, 16> LiveValues;
   llvm::SmallPtrSet<SILBasicBlock *, 16> LiveBlocks;
   llvm::SmallVector<SILInstruction *, 64> Worklist;
   PostDominanceInfo *PDT;
@@ -160,7 +160,7 @@
   unsigned computeMinPredecessorLevels(PostDomTreeNode *Node);
   void insertControllingInfo(SILBasicBlock *Block, unsigned Level);
 
-  void markValueLive(ValueBase *V);
+  void markValueLive(SILNode *V);
   void markTerminatorArgsLive(SILBasicBlock *Pred, SILBasicBlock *Succ,
                               size_t ArgIndex);
   void markControllingTerminatorsLive(SILBasicBlock *Block);
@@ -178,7 +178,8 @@
 
 // Keep track of the fact that V is live and add it to our worklist
 // so that we can process the values it depends on.
-void DCE::markValueLive(ValueBase *V) {
+void DCE::markValueLive(SILNode *V) {
+  V = V->getCanonicalSILNodeInObject();
   if (LiveValues.count(V) || isa<SILUndef>(V))
     return;
 
@@ -193,6 +194,8 @@
     return;
   }
 
+  // TODO: MultiValueInstruction
+
   assert(isa<SILArgument>(V) &&
          "Only expected instructions and arguments!");
 
@@ -239,7 +242,7 @@
         // A fix_lifetime (with a non-address type) is only alive if it's
         // definition is alive.
         SILValue Op = FLI->getOperand();
-        auto *OpInst = dyn_cast<SILInstruction>(Op);
+        auto *OpInst = Op->getDefiningInstruction();
         if (OpInst && !Op->getType().isAddress()) {
           addReverseDependency(OpInst, FLI);
         } else {
@@ -363,8 +366,9 @@
     // Conceptually, the dependency from a debug instruction to its definition
     // is in reverse direction: Only if its definition is alive, also the
     // debug_value instruction is alive.
-    for (Operand *DU : getDebugUses(I))
-      markValueLive(DU->getUser());
+    for (auto result : I->getResults())
+      for (Operand *DU : getDebugUses(result))
+        markValueLive(DU->getUser());
 
     // Handle all other reverse-dependency instructions, like cond_fail and
     // fix_lifetime. Only if the definition is alive, the user itself is alive.
@@ -374,7 +378,7 @@
     return;
   }
 
-  switch (ValueKindAsTermKind(I->getKind())) {
+  switch (cast<TermInst>(I)->getTermKind()) {
   case TermKind::BranchInst:
   case TermKind::UnreachableInst:
     return;
@@ -459,10 +463,7 @@
       DEBUG(llvm::dbgs() << "Removing dead argument:\n");
       DEBUG(Inst->dump());
 
-      if (Inst->hasValue()) {
-        auto *Undef = SILUndef::get(Inst->getType(), Inst->getModule());
-        Inst->replaceAllUsesWith(Undef);
-      }
+      Inst->replaceAllUsesWithUndef();
 
       Changed = true;
     }
@@ -489,11 +490,7 @@
       DEBUG(llvm::dbgs() << "Removing dead instruction:\n");
       DEBUG(Inst->dump());
 
-      if (Inst->hasValue()) {
-        auto *Undef = SILUndef::get(Inst->getType(), Inst->getModule());
-        Inst->replaceAllUsesWith(Undef);
-      }
-
+      Inst->replaceAllUsesOfAllResultsWithUndef();
 
       if (isa<ApplyInst>(Inst))
         CallsChanged = true;
diff --git a/lib/SILOptimizer/Transforms/DeadObjectElimination.cpp b/lib/SILOptimizer/Transforms/DeadObjectElimination.cpp
index 10b7199..a33bfee 100644
--- a/lib/SILOptimizer/Transforms/DeadObjectElimination.cpp
+++ b/lib/SILOptimizer/Transforms/DeadObjectElimination.cpp
@@ -181,8 +181,7 @@
 void static
 removeInstructions(ArrayRef<SILInstruction*> UsersToRemove) {
   for (auto *I : UsersToRemove) {
-    if (!I->use_empty())
-      I->replaceAllUsesWith(SILUndef::get(I->getType(), I->getModule()));
+    I->replaceAllUsesOfAllResultsWithUndef();
     // Now we know that I should not have any uses... erase it from its parent.
     I->eraseFromParent();
   }
@@ -197,7 +196,7 @@
 static bool canZapInstruction(SILInstruction *Inst) {
   // It is ok to eliminate various retains/releases. We are either removing
   // everything or nothing.
-  if (isa<RefCountingInst>(Inst))
+  if (isa<RefCountingInst>(Inst) || isa<StrongPinInst>(Inst))
     return true;
 
   // If we see a store here, we have already checked that we are storing into
@@ -255,20 +254,22 @@
     // At this point, we can remove the instruction as long as all of its users
     // can be removed as well. Scan its users and add them to the worklist for
     // recursive processing.
-    for (auto *Op : I->getUses()) {
-      auto *User = Op->getUser();
+    for (auto result : I->getResults()) {
+      for (auto *Op : result->getUses()) {
+        auto *User = Op->getUser();
 
-      // Make sure that we are only storing into our users, not storing our
-      // users which would be an escape.
-      if (auto *SI = dyn_cast<StoreInst>(User))
-        if (Op->get() == SI->getSrc()) {
-          DEBUG(llvm::dbgs() << "        Found store of pointer. Failure: " <<
-                *SI);
-          return true;
-        }
+        // Make sure that we are only storing into our users, not storing our
+        // users which would be an escape.
+        if (auto *SI = dyn_cast<StoreInst>(User))
+          if (Op->get() == SI->getSrc()) {
+            DEBUG(llvm::dbgs() << "        Found store of pointer. Failure: " <<
+                  *SI);
+            return true;
+          }
 
-      // Otherwise, add normal instructions to the worklist for processing.
-      Worklist.push_back(User);
+        // Otherwise, add normal instructions to the worklist for processing.
+        Worklist.push_back(User);
+      }
     }
   }
 
@@ -388,7 +389,9 @@
     auto User = Op->getUser();
 
     // Lifetime endpoints that don't allow the address to escape.
-    if (isa<RefCountingInst>(User) || isa<DebugValueInst>(User)) {
+    if (isa<RefCountingInst>(User) ||
+        isa<StrongPinInst>(User) ||
+        isa<DebugValueInst>(User)) {
       AllUsers.insert(User);
       continue;
     }
@@ -409,44 +412,46 @@
       AllUsers.insert(User);
       continue;
     }
-    if (isa<PointerToAddressInst>(User)) {
+    if (auto PTAI = dyn_cast<PointerToAddressInst>(User)) {
       // Only one pointer-to-address is allowed for safety.
       if (SeenPtrToAddr)
         return false;
 
       SeenPtrToAddr = true;
-      if (!recursivelyCollectInteriorUses(User, AddressNode, IsInteriorAddress))
+      if (!recursivelyCollectInteriorUses(PTAI, AddressNode, IsInteriorAddress))
         return false;
 
       continue;
     }
     // Recursively follow projections.
-    ProjectionIndex PI(User);
-    if (PI.isValid()) {
-      IndexTrieNode *ProjAddrNode = AddressNode;
-      bool ProjInteriorAddr = IsInteriorAddress;
-      if (Projection::isAddressProjection(User)) {
-        if (User->getKind() == ValueKind::IndexAddrInst) {
-          // Don't support indexing within an interior address.
-          if (IsInteriorAddress)
-            return false;
+    if (auto ProjInst = dyn_cast<SingleValueInstruction>(User)) {
+      ProjectionIndex PI(ProjInst);
+      if (PI.isValid()) {
+        IndexTrieNode *ProjAddrNode = AddressNode;
+        bool ProjInteriorAddr = IsInteriorAddress;
+        if (Projection::isAddressProjection(ProjInst)) {
+          if (isa<IndexAddrInst>(ProjInst)) {
+            // Don't support indexing within an interior address.
+            if (IsInteriorAddress)
+              return false;
+          }
+          else if (!IsInteriorAddress) {
+            // Push an extra zero index node for the first interior address.
+            ProjAddrNode = AddressNode->getChild(0);
+            ProjInteriorAddr = true;
+          }
         }
-        else if (!IsInteriorAddress) {
-          // Push an extra zero index node for the first interior address.
-          ProjAddrNode = AddressNode->getChild(0);
-          ProjInteriorAddr = true;
+        else if (IsInteriorAddress) {
+          // Don't expect to extract values once we've taken an address.
+          return false;
         }
+        if (!recursivelyCollectInteriorUses(ProjInst,
+                                            ProjAddrNode->getChild(PI.Index),
+                                            ProjInteriorAddr)) {
+          return false;
+        }
+        continue;
       }
-      else if (IsInteriorAddress) {
-        // Don't expect to extract values once we've taken an address.
-        return false;
-      }
-      if (!recursivelyCollectInteriorUses(User,
-                                          ProjAddrNode->getChild(PI.Index),
-                                          ProjInteriorAddr)) {
-        return false;
-      }
-      continue;
     }
     // Otherwise bail.
     DEBUG(llvm::dbgs() << "        Found an escaping use: " << *User);
@@ -532,7 +537,7 @@
 // TODO: This relies on the lowest level array.uninitialized not being
 // inlined. To do better we could either run this pass before semantic inlining,
 // or we could also handle calls to array.init.
-static bool removeAndReleaseArray(SILInstruction *NewArrayValue,
+static bool removeAndReleaseArray(SingleValueInstruction *NewArrayValue,
                                   DeadEndBlocks &DEBlocks) {
   TupleExtractInst *ArrayDef = nullptr;
   TupleExtractInst *StorageAddress = nullptr;
diff --git a/lib/SILOptimizer/Transforms/DeadStoreElimination.cpp b/lib/SILOptimizer/Transforms/DeadStoreElimination.cpp
index 337ae48..c59d7bf 100644
--- a/lib/SILOptimizer/Transforms/DeadStoreElimination.cpp
+++ b/lib/SILOptimizer/Transforms/DeadStoreElimination.cpp
@@ -147,14 +147,14 @@
 /// general sense but are inert from a load store perspective.
 static bool isDeadStoreInertInstruction(SILInstruction *Inst) {
   switch (Inst->getKind()) {
-  case ValueKind::StrongRetainInst:
-  case ValueKind::StrongRetainUnownedInst:
-  case ValueKind::UnownedRetainInst:
-  case ValueKind::RetainValueInst:
-  case ValueKind::DeallocStackInst:
-  case ValueKind::DeallocRefInst:
-  case ValueKind::CondFailInst:
-  case ValueKind::FixLifetimeInst:
+  case SILInstructionKind::StrongRetainInst:
+  case SILInstructionKind::StrongRetainUnownedInst:
+  case SILInstructionKind::UnownedRetainInst:
+  case SILInstructionKind::RetainValueInst:
+  case SILInstructionKind::DeallocStackInst:
+  case SILInstructionKind::DeallocRefInst:
+  case SILInstructionKind::CondFailInst:
+  case SILInstructionKind::FixLifetimeInst:
     return true;
   default:
     return false;
@@ -1109,7 +1109,8 @@
   }  
 
   // Check whether this instruction will invalidate any other locations.
-  invalidateBase(I, getBlockState(I), Kind);
+  for (auto result : I->getResults())
+    invalidateBase(result, getBlockState(I), Kind);
 }
 
 void DSEContext::runIterativeDSE() {
@@ -1214,10 +1215,10 @@
     for (auto &X : S->LiveAddr) {
       Changed = true;
       auto I = S->LiveStores.find(X);
-      SILInstruction *Inst = cast<SILInstruction>(I->first);
+      SILInstruction *Inst = I->first->getDefiningInstruction();
       auto *IT = &*std::next(Inst->getIterator());
       SILBuilderWithScope Builder(IT);
-      Builder.createStore(Inst->getLoc(), I->second, Inst,
+      Builder.createStore(Inst->getLoc(), I->second, I->first,
                           StoreOwnershipQualifier::Unqualified);
     }
     // Delete the dead stores.
diff --git a/lib/SILOptimizer/Transforms/Devirtualizer.cpp b/lib/SILOptimizer/Transforms/Devirtualizer.cpp
index 935d178..922969a 100644
--- a/lib/SILOptimizer/Transforms/Devirtualizer.cpp
+++ b/lib/SILOptimizer/Transforms/Devirtualizer.cpp
@@ -76,7 +76,7 @@
 
     auto *AI = Apply.getInstruction();
     if (!isa<TryApplyInst>(AI))
-      AI->replaceAllUsesWith(NewInstPair.first);
+      cast<SingleValueInstruction>(AI)->replaceAllUsesWith(NewInstPair.first);
 
     DeadApplies.push_back(AI);
     NewApplies.push_back(NewInstPair.second);
diff --git a/lib/SILOptimizer/Transforms/FunctionSignatureOpts.cpp b/lib/SILOptimizer/Transforms/FunctionSignatureOpts.cpp
index 70ba575..d3270a0 100644
--- a/lib/SILOptimizer/Transforms/FunctionSignatureOpts.cpp
+++ b/lib/SILOptimizer/Transforms/FunctionSignatureOpts.cpp
@@ -499,8 +499,8 @@
       }
 
       // Scan the result type of the instruction.
-      if (I.getType()) {
-        I.getType().getSwiftRValueType().visit(FindArchetypesAndGenericTypes);
+      for (auto V : I.getResults()) {
+        V->getType().getSwiftRValueType().visit(FindArchetypesAndGenericTypes);
       }
 
       if (UsesGenerics)
@@ -649,11 +649,11 @@
     NewFGenericEnv = nullptr;
   }
 
-  NewF = M.createFunction(
-      linkage, Name, NewFTy, NewFGenericEnv, F->getLocation(), F->isBare(),
-      F->isTransparent(), F->isSerialized(), F->isThunk(),
-      F->getClassSubclassScope(), F->getInlineStrategy(), F->getEffectsKind(),
-      nullptr, F->getDebugScope());
+  NewF = M.createFunction(linkage, Name, NewFTy, NewFGenericEnv,
+                          F->getLocation(), F->isBare(), F->isTransparent(),
+                          F->isSerialized(), F->getEntryCount(), F->isThunk(),
+                          F->getClassSubclassScope(), F->getInlineStrategy(),
+                          F->getEffectsKind(), nullptr, F->getDebugScope());
   if (F->hasUnqualifiedOwnership()) {
     NewF->setUnqualifiedOwnership();
   }
@@ -948,8 +948,8 @@
         continue;
       }
       // Create a release to balance it out.
-      assert(isa<ApplyInst>(X) && "Unknown epilogue retain");
-      createDecrementBefore(X, dyn_cast<ApplyInst>(X)->getParent()->getTerminator());
+      auto AI = cast<ApplyInst>(X);
+      createDecrementBefore(AI, AI->getParent()->getTerminator());
     }
   }
 }
@@ -1018,12 +1018,12 @@
   }
 
   SILInstruction *Call = findOnlyApply(F);
-  if (isa<ApplyInst>(Call)) {
-    Builder.setInsertionPoint(&*std::next(SILBasicBlock::iterator(Call)));
-    Builder.createRetainValue(RegularLocation(SourceLoc()), Call,
+  if (auto AI = dyn_cast<ApplyInst>(Call)) {
+    Builder.setInsertionPoint(&*std::next(SILBasicBlock::iterator(AI)));
+    Builder.createRetainValue(RegularLocation(SourceLoc()), AI,
                               Builder.getDefaultAtomicity());
   } else {
-    SILBasicBlock *NormalBB = dyn_cast<TryApplyInst>(Call)->getNormalBB();
+    SILBasicBlock *NormalBB = cast<TryApplyInst>(Call)->getNormalBB();
     Builder.setInsertionPoint(&*NormalBB->begin());
     Builder.createRetainValue(RegularLocation(SourceLoc()),
                               NormalBB->getArgument(0), Builder.getDefaultAtomicity());
diff --git a/lib/SILOptimizer/Transforms/MarkUninitializedFixup.cpp b/lib/SILOptimizer/Transforms/MarkUninitializedFixup.cpp
index 981ef7c..5613b0b 100644
--- a/lib/SILOptimizer/Transforms/MarkUninitializedFixup.cpp
+++ b/lib/SILOptimizer/Transforms/MarkUninitializedFixup.cpp
@@ -22,7 +22,7 @@
 //                           Top Level Entry Point
 //===----------------------------------------------------------------------===//
 
-static SILInstruction *
+static ProjectBoxInst *
 getInitialProjectBox(MarkUninitializedInst *MUI,
                      ArrayRef<ProjectBoxInst *> Projections) {
   assert(!Projections.empty());
@@ -113,7 +113,7 @@
 
           // That means now our project box now has the alloc_box as its
           // operand. Grab that project_box.
-          SILInstruction *PBI = getInitialProjectBox(MUI, Projections);
+          auto *PBI = getInitialProjectBox(MUI, Projections);
 
           // Then create the new mark_uninitialized and force all uses of the
           // project_box to go through the new mark_uninitialized.
diff --git a/lib/SILOptimizer/Transforms/Outliner.cpp b/lib/SILOptimizer/Transforms/Outliner.cpp
index 12bc9d7..add7ab7 100644
--- a/lib/SILOptimizer/Transforms/Outliner.cpp
+++ b/lib/SILOptimizer/Transforms/Outliner.cpp
@@ -207,7 +207,7 @@
 ///  bb10(%45 : $Optional<String>):
 class BridgedProperty : public OutlinePattern {
   std::string OutlinedName;
-  SILInstruction *FirstInst;
+  SingleValueInstruction *FirstInst; // A load or class_method
   SILBasicBlock *StartBB;
   SILBasicBlock *SomeBB;
   SILBasicBlock *NoneBB;
diff --git a/lib/SILOptimizer/Transforms/OwnershipModelEliminator.cpp b/lib/SILOptimizer/Transforms/OwnershipModelEliminator.cpp
index f59c614..55e41a1 100644
--- a/lib/SILOptimizer/Transforms/OwnershipModelEliminator.cpp
+++ b/lib/SILOptimizer/Transforms/OwnershipModelEliminator.cpp
@@ -46,13 +46,12 @@
     B.setOpenedArchetypesTracker(&OpenedArchetypesTracker);
   }
 
-  void beforeVisit(ValueBase *V) {
-    auto *I = cast<SILInstruction>(V);
+  void beforeVisit(SILInstruction *I) {
     B.setInsertionPoint(I);
     B.setCurrentDebugScope(I->getDebugScope());
   }
 
-  bool visitValueBase(ValueBase *V) { return false; }
+  bool visitSILInstruction(SILInstruction *I) { return false; }
   bool visitLoadInst(LoadInst *LI);
   bool visitStoreInst(StoreInst *SI);
   bool visitStoreBorrowInst(StoreBorrowInst *SI);
@@ -176,7 +175,6 @@
   // Now that we have set the unqualified ownership flag, destroy value
   // operation will delegate to the appropriate strong_release, etc.
   B.emitCopyValueOperation(URVI->getLoc(), URVI->getOperand());
-  URVI->replaceAllUsesWith(URVI->getOperand());
   URVI->eraseFromParent();
   return true;
 }
diff --git a/lib/SILOptimizer/Transforms/PerformanceInliner.cpp b/lib/SILOptimizer/Transforms/PerformanceInliner.cpp
index 2fd9c1e..6f5d22d 100644
--- a/lib/SILOptimizer/Transforms/PerformanceInliner.cpp
+++ b/lib/SILOptimizer/Transforms/PerformanceInliner.cpp
@@ -128,15 +128,24 @@
     return SPA;
   }
 
-  bool isProfitableToInline(FullApplySite AI,
-                            Weight CallerWeight,
-                            ConstantTracker &callerTracker,
-                            int &NumCallerBlocks);
+  bool profileBasedDecision(
+      const FullApplySite &AI, int Benefit, SILFunction *Callee, int CalleeCost,
+      int &NumCallerBlocks,
+      const llvm::DenseMapIterator<
+          swift::SILBasicBlock *, uint64_t,
+          llvm::DenseMapInfo<swift::SILBasicBlock *>,
+          llvm::detail::DenseMapPair<swift::SILBasicBlock *, uint64_t>, true>
+          &bbIt);
 
-  bool decideInWarmBlock(FullApplySite AI,
-                         Weight CallerWeight,
-                         ConstantTracker &callerTracker,
-                         int &NumCallerBlocks);
+  bool isProfitableToInline(
+      FullApplySite AI, Weight CallerWeight, ConstantTracker &callerTracker,
+      int &NumCallerBlocks,
+      const llvm::DenseMap<SILBasicBlock *, uint64_t> &BBToWeightMap);
+
+  bool decideInWarmBlock(
+      FullApplySite AI, Weight CallerWeight, ConstantTracker &callerTracker,
+      int &NumCallerBlocks,
+      const llvm::DenseMap<SILBasicBlock *, uint64_t> &BBToWeightMap);
 
   bool decideInColdBlock(FullApplySite AI, SILFunction *Callee);
 
@@ -165,10 +174,63 @@
   return ReabstractionInfo::canBeSpecialized(AI, F, Subs);
 }
 
-bool SILPerformanceInliner::isProfitableToInline(FullApplySite AI,
-                                                 Weight CallerWeight,
-                                                 ConstantTracker &callerTracker,
-                                                 int &NumCallerBlocks) {
+bool SILPerformanceInliner::profileBasedDecision(
+    const FullApplySite &AI, int Benefit, SILFunction *Callee, int CalleeCost,
+    int &NumCallerBlocks,
+    const llvm::DenseMapIterator<
+        swift::SILBasicBlock *, uint64_t,
+        llvm::DenseMapInfo<swift::SILBasicBlock *>,
+        llvm::detail::DenseMapPair<swift::SILBasicBlock *, uint64_t>, true>
+        &bbIt) {
+  if (CalleeCost < TrivialFunctionThreshold) {
+    // We do not increase code size below this threshold
+    return true;
+  }
+  auto callerCount = bbIt->getSecond();
+  if (callerCount < 1) {
+    // Never called - do not inline
+    DEBUG(dumpCaller(AI.getFunction()); llvm::dbgs()
+                                        << "profiled decision: NO"
+                                        << ", reason= Never Called." << '\n';);
+    return false;
+  }
+  auto calleeCount = Callee->getEntryCount();
+  if (calleeCount) {
+    // If we have Callee count - use SI heuristic:
+    auto calleCountVal = calleeCount.getValue();
+    auto percent = (long double)callerCount / (long double)calleCountVal;
+    if (percent < 0.8) {
+      DEBUG(dumpCaller(AI.getFunction());
+            llvm::dbgs() << "profiled decision: NO"
+                         << ", reason=SI " << std::to_string(percent) << "%"
+                         << '\n';);
+      return false;
+    }
+    DEBUG(dumpCaller(AI.getFunction()); llvm::dbgs() << "profiled decision: YES"
+                                                     << ", reason=SI "
+                                                     << std::to_string(percent)
+                                                     << "%" << '\n';);
+  } else {
+    // No callee count - use a "modified" aggressive IHF for now
+    if (CalleeCost > Benefit && callerCount < 100) {
+      DEBUG(dumpCaller(AI.getFunction());
+            llvm::dbgs() << "profiled decision: NO"
+                         << ", reason=IHF " << callerCount << '\n';);
+      return false;
+    }
+    DEBUG(dumpCaller(AI.getFunction()); llvm::dbgs() << "profiled decision: YES"
+                                                     << ", reason=IHF "
+                                                     << callerCount << '\n';);
+  }
+  // We're gonna inline!
+  NumCallerBlocks += Callee->size();
+  return true;
+}
+
+bool SILPerformanceInliner::isProfitableToInline(
+    FullApplySite AI, Weight CallerWeight, ConstantTracker &callerTracker,
+    int &NumCallerBlocks,
+    const llvm::DenseMap<SILBasicBlock *, uint64_t> &BBToWeightMap) {
   SILFunction *Callee = AI.getReferencedFunction();
   bool IsGeneric = !AI.getSubstitutions().empty();
 
@@ -253,7 +315,7 @@
         // Check if inlining the callee would allow for further
         // optimizations like devirtualization or generic specialization. 
         if (!def)
-          def = dyn_cast_or_null<SILInstruction>(FAI.getCallee());
+          def = dyn_cast_or_null<SingleValueInstruction>(FAI.getCallee());
 
         if (!def)
           continue;
@@ -362,6 +424,14 @@
                         NumCallerBlocks / BlockLimitDenominator;
   Benefit -= blockMinus;
 
+  // If we have profile info - use it for final inlining decision.
+  auto *bb = AI.getInstruction()->getParent();
+  auto bbIt = BBToWeightMap.find(bb);
+  if (bbIt != BBToWeightMap.end()) {
+    return profileBasedDecision(AI, Benefit, Callee, CalleeCost,
+                                NumCallerBlocks, bbIt);
+  }
+
   // This is the final inlining decision.
   if (CalleeCost > Benefit) {
     return false;
@@ -423,11 +493,10 @@
   return None;
 }
 
-bool SILPerformanceInliner::
-decideInWarmBlock(FullApplySite AI,
-                  Weight CallerWeight,
-                  ConstantTracker &callerTracker,
-                  int &NumCallerBlocks) {
+bool SILPerformanceInliner::decideInWarmBlock(
+    FullApplySite AI, Weight CallerWeight, ConstantTracker &callerTracker,
+    int &NumCallerBlocks,
+    const llvm::DenseMap<SILBasicBlock *, uint64_t> &BBToWeightMap) {
   if (!AI.getSubstitutions().empty()) {
     // Only inline generics if definitively clear that it should be done.
     auto ShouldInlineGeneric = shouldInlineGeneric(AI);
@@ -445,7 +514,8 @@
     return true;
   }
 
-  return isProfitableToInline(AI, CallerWeight, callerTracker, NumCallerBlocks);
+  return isProfitableToInline(AI, CallerWeight, callerTracker, NumCallerBlocks,
+                              BBToWeightMap);
 }
 
 /// Return true if inlining this call site into a cold block is profitable.
@@ -505,6 +575,94 @@
   }
 }
 
+static bool containsWeight(TermInst *inst) {
+  for (auto &succ : inst->getSuccessors()) {
+    if (succ.getCount()) {
+      return true;
+    }
+  }
+  return false;
+}
+
+static void
+addToBBCounts(llvm::DenseMap<SILBasicBlock *, uint64_t> &BBToWeightMap,
+              uint64_t numToAdd, swift::TermInst *termInst) {
+  for (auto &succ : termInst->getSuccessors()) {
+    auto *currBB = succ.getBB();
+    assert(BBToWeightMap.find(currBB) != BBToWeightMap.end() &&
+           "Expected to find block in map");
+    BBToWeightMap[currBB] += numToAdd;
+  }
+}
+
+static void
+calculateBBWeights(SILFunction *Caller, DominanceInfo *DT,
+                   llvm::DenseMap<SILBasicBlock *, uint64_t> &BBToWeightMap) {
+  auto entryCount = Caller->getEntryCount();
+  if (!entryCount) {
+    // No profile for function - return
+    return;
+  }
+  // Add all blocks to BBToWeightMap without count 0
+  for (auto &block : Caller->getBlocks()) {
+    BBToWeightMap[&block] = 0;
+  }
+  BBToWeightMap[Caller->getEntryBlock()] = entryCount.getValue();
+  DominanceOrder domOrder(&Caller->front(), DT, Caller->size());
+  while (SILBasicBlock *block = domOrder.getNext()) {
+    auto bbIt = BBToWeightMap.find(block);
+    assert(bbIt != BBToWeightMap.end() && "Expected to find block in map");
+    auto bbCount = bbIt->getSecond();
+    auto *termInst = block->getTerminator();
+    if (containsWeight(termInst)) {
+      // Instruction already contains accurate counters - use them as-is
+      uint64_t countSum = 0;
+      uint64_t blocksWithoutCount = 0;
+      for (auto &succ : termInst->getSuccessors()) {
+        auto *currBB = succ.getBB();
+        assert(BBToWeightMap.find(currBB) != BBToWeightMap.end() &&
+               "Expected to find block in map");
+        auto currCount = succ.getCount();
+        if (!currCount) {
+          ++blocksWithoutCount;
+          continue;
+        }
+        auto currCountVal = currCount.getValue();
+        countSum += currCountVal;
+        BBToWeightMap[currBB] += currCountVal;
+      }
+      if (countSum < bbCount) {
+        // inaccurate profile - fill in the gaps for BBs without a count:
+        if (blocksWithoutCount > 0) {
+          auto numToAdd = (bbCount - countSum) / blocksWithoutCount;
+          for (auto &succ : termInst->getSuccessors()) {
+            auto *currBB = succ.getBB();
+            auto currCount = succ.getCount();
+            if (!currCount) {
+              BBToWeightMap[currBB] += numToAdd;
+            }
+          }
+        }
+      } else {
+        auto numOfSucc = termInst->getSuccessors().size();
+        assert(numOfSucc > 0 && "Expected successors > 0");
+        auto numToAdd = (countSum - bbCount) / numOfSucc;
+        addToBBCounts(BBToWeightMap, numToAdd, termInst);
+      }
+    } else {
+      // Fill counters speculatively
+      auto numOfSucc = termInst->getSuccessors().size();
+      if (numOfSucc == 0) {
+        // No successors to fill
+        continue;
+      }
+      auto numToAdd = bbCount / numOfSucc;
+      addToBBCounts(BBToWeightMap, numToAdd, termInst);
+    }
+    domOrder.pushChildrenIf(block, [&](SILBasicBlock *child) { return true; });
+  }
+}
+
 void SILPerformanceInliner::collectAppliesToInline(
     SILFunction *Caller, SmallVectorImpl<FullApplySite> &Applies) {
   DominanceInfo *DT = DA->get(Caller);
@@ -552,6 +710,9 @@
   DominanceOrder domOrder(&Caller->front(), DT, Caller->size());
   int NumCallerBlocks = (int)Caller->size();
 
+  llvm::DenseMap<SILBasicBlock *, uint64_t> BBToWeightMap;
+  calculateBBWeights(Caller, DT, BBToWeightMap);
+
   // Go through all instructions and find candidates for inlining.
   // We do this in dominance order for the constTracker.
   SmallVector<FullApplySite, 8> InitialCandidates;
@@ -575,7 +736,8 @@
         // The actual weight including a possible weight correction.
         Weight W(BlockWeight, WeightCorrections.lookup(AI));
 
-        if (decideInWarmBlock(AI, W, constTracker, NumCallerBlocks))
+        if (decideInWarmBlock(AI, W, constTracker, NumCallerBlocks,
+                              BBToWeightMap))
           InitialCandidates.push_back(AI);
       }
     }
@@ -607,8 +769,9 @@
     assert(Callee && "apply_inst does not have a direct callee anymore");
 
     const unsigned CallsToCalleeThreshold = 1024;
-    if (CalleeCount[Callee] <= CallsToCalleeThreshold)
+    if (CalleeCount[Callee] <= CallsToCalleeThreshold) {
       Applies.push_back(AI);
+    }
   }
 }
 
diff --git a/lib/SILOptimizer/Transforms/RedundantLoadElimination.cpp b/lib/SILOptimizer/Transforms/RedundantLoadElimination.cpp
index 76ad412..f8fdc04 100644
--- a/lib/SILOptimizer/Transforms/RedundantLoadElimination.cpp
+++ b/lib/SILOptimizer/Transforms/RedundantLoadElimination.cpp
@@ -98,12 +98,9 @@
 
 STATISTIC(NumForwardedLoads, "Number of loads forwarded");
 
-/// Return the deallocate stack instructions corresponding to the given
-/// AllocStackInst.
-static SILInstruction *findAllocStackInst(SILInstruction *I) {
-  if (auto *DSI = dyn_cast<DeallocStackInst>(I))
-    return dyn_cast<SILInstruction>(DSI->getOperand());
-  return nullptr;
+static AllocStackInst *findAllocStackInst(DeallocStackInst *I) {
+  // It's allowed to be undef in unreachable code.
+  return dyn_cast<AllocStackInst>(I->getOperand());
 }
 
 /// ComputeAvailSetMax - If we ignore all unknown writes, what is the max
@@ -149,15 +146,15 @@
 /// general sense but are inert from a load store perspective.
 static bool isRLEInertInstruction(SILInstruction *Inst) {
   switch (Inst->getKind()) {
-  case ValueKind::StrongRetainInst:
-  case ValueKind::StrongRetainUnownedInst:
-  case ValueKind::UnownedRetainInst:
-  case ValueKind::RetainValueInst:
-  case ValueKind::DeallocStackInst:
-  case ValueKind::CondFailInst:
-  case ValueKind::IsUniqueInst:
-  case ValueKind::IsUniqueOrPinnedInst:
-  case ValueKind::FixLifetimeInst:
+  case SILInstructionKind::StrongRetainInst:
+  case SILInstructionKind::StrongRetainUnownedInst:
+  case SILInstructionKind::UnownedRetainInst:
+  case SILInstructionKind::RetainValueInst:
+  case SILInstructionKind::DeallocStackInst:
+  case SILInstructionKind::CondFailInst:
+  case SILInstructionKind::IsUniqueInst:
+  case SILInstructionKind::IsUniqueOrPinnedInst:
+  case SILInstructionKind::FixLifetimeInst:
     return true;
   default:
     return false;
@@ -237,7 +234,7 @@
 
   /// Keeps a list of replaceable instructions in the current basic block as
   /// well as their SILValue replacement.
-  llvm::DenseMap<SILInstruction *, SILValue> RedundantLoads;
+  llvm::DenseMap<SingleValueInstruction *, SILValue> RedundantLoads;
 
   /// LSLocation read or written has been extracted, expanded and mapped to the
   /// bit position in the bitvector. Update it in the ForwardSetIn of the
@@ -352,7 +349,9 @@
 
   /// Returns the redundant loads and their replacement in the currently basic
   /// block.
-  llvm::DenseMap<SILInstruction *, SILValue> &getRL() { return RedundantLoads; }
+  llvm::DenseMap<SingleValueInstruction *, SILValue> &getRL() {
+    return RedundantLoads;
+  }
 
   /// Look into the value for the given LSLocation at end of the basic block,
   /// return one of the three ValueState type.
@@ -386,10 +385,10 @@
   void processUnknownWriteInstForRLE(RLEContext &Ctx, SILInstruction *I);
 
 
-  void processDeallocStackInst(RLEContext &Ctx, SILInstruction *I,
+  void processDeallocStackInst(RLEContext &Ctx, DeallocStackInst *I,
                                RLEKind Kind);
-  void processDeallocStackInstForGenKillSet(RLEContext &Ctx, SILInstruction *I);
-  void processDeallocStackInstForRLE(RLEContext &Ctx, SILInstruction *I);
+  void processDeallocStackInstForGenKillSet(RLEContext &Ctx, DeallocStackInst *I);
+  void processDeallocStackInstForRLE(RLEContext &Ctx, DeallocStackInst *I);
 
   /// Process LoadInst. Extract LSLocations from LoadInst.
   void processLoadInst(RLEContext &Ctx, LoadInst *LI, RLEKind Kind);
@@ -723,7 +722,7 @@
   // replace it with, we can record it for now and forwarded it after all the
   // forwardable values are recorded in the function.
   //
-  RedundantLoads[I] = TheForwardingValue;
+  RedundantLoads[cast<SingleValueInstruction>(I)] = TheForwardingValue;
 
   DEBUG(llvm::dbgs() << "FORWARD " << TheForwardingValue << "  to" << *I);
   return true;
@@ -1000,7 +999,7 @@
 }
 
 void BlockState::
-processDeallocStackInstForGenKillSet(RLEContext &Ctx, SILInstruction *I) {
+processDeallocStackInstForGenKillSet(RLEContext &Ctx, DeallocStackInst *I) {
   SILValue ASI = findAllocStackInst(I);
   for (unsigned i = 0; i < LocationNum; ++i) {
     LSLocation &R = Ctx.getLocation(i);
@@ -1013,7 +1012,7 @@
 }
 
 void BlockState::
-processDeallocStackInstForRLE(RLEContext &Ctx, SILInstruction *I) {
+processDeallocStackInstForRLE(RLEContext &Ctx, DeallocStackInst *I) {
   SILValue ASI = findAllocStackInst(I);
   for (unsigned i = 0; i < LocationNum; ++i) {
     LSLocation &R = Ctx.getLocation(i);
@@ -1026,7 +1025,7 @@
 }
 
 void BlockState::
-processDeallocStackInst(RLEContext &Ctx, SILInstruction *I, RLEKind Kind) {
+processDeallocStackInst(RLEContext &Ctx, DeallocStackInst *I, RLEKind Kind) {
   // Are we computing the genset and killset ?
   if (isComputeAvailGenKillSet(Kind)) {
     processDeallocStackInstForGenKillSet(Ctx, I);
@@ -1574,7 +1573,10 @@
     // NOTE: we could end up with different SIL depending on the ordering load
     // forwarding is performed.
     for (auto I = B.rbegin(), E = B.rend(); I != E; ++I) {
-      auto Iter = Loads.find(&*I);
+      auto V = dyn_cast<SingleValueInstruction>(&*I);
+      if (!V)
+        continue;
+      auto Iter = Loads.find(V);
       if (Iter == Loads.end())
         continue;
       DEBUG(llvm::dbgs() << "Replacing  " << SILValue(Iter->first) << "With "
@@ -1593,7 +1595,7 @@
     // used as the replacement Value, i.e. F.second, for some other RLE pairs.
     //
     // TODO: we should fix this, otherwise we are missing RLE opportunities.
-    if (!X->use_empty())
+    if (X->hasUsesOfAnyResult())
       continue;
     recursivelyDeleteTriviallyDeadInstructions(X, true);
   }
diff --git a/lib/SILOptimizer/Transforms/RemovePin.cpp b/lib/SILOptimizer/Transforms/RemovePin.cpp
index 2c03c17..86492f7 100644
--- a/lib/SILOptimizer/Transforms/RemovePin.cpp
+++ b/lib/SILOptimizer/Transforms/RemovePin.cpp
@@ -40,10 +40,9 @@
 /// \brief Can this instruction read the pinned bit of the reference count.
 /// Reading the pinned prevents us from moving the pin instructions across it.
 static bool mayReadPinFlag(SILInstruction *I) {
-  auto Kind = I->getKind();
-  if (Kind == ValueKind::IsUniqueOrPinnedInst)
+  if (isa<IsUniqueOrPinnedInst>(I))
     return true;
-  if (Kind != ValueKind::ApplyInst)
+  if (!isa<ApplyInst>(I))
     return false;
   if (!I->mayReadFromMemory())
     return false;
@@ -58,7 +57,7 @@
 
   /// The set of currently available pins that have not been invalidate by an
   /// instruction that mayRelease memory.
-  llvm::SmallPtrSet<SILInstruction *, 16> AvailablePins;
+  llvm::SmallPtrSet<StrongPinInst *, 16> AvailablePins;
 
   AliasAnalysis *AA;
 
@@ -89,9 +88,9 @@
         DEBUG(llvm::dbgs() << "    Visiting: " << *CurInst);
 
         // Add StrongPinInst to available pins.
-        if (isa<StrongPinInst>(CurInst)) {
+        if (auto pin = dyn_cast<StrongPinInst>(CurInst)) {
           DEBUG(llvm::dbgs() << "        Found pin!\n");
-          AvailablePins.insert(CurInst);
+          AvailablePins.insert(pin);
           continue;
         }
 
@@ -181,11 +180,19 @@
 
     for (auto *U : Users) {
       // A mark_dependence is safe if it is marking a dependence on a base that
-      // is the strong_pinned value.
+      // is the strong_pinned value:
+      //    %0 = strong_pin ...
+      //    %1 = mark_dependence ... on %0
+      // or
+      //    %0 = strong_pin ...
+      //    %1 = foo ... %0 ...
+      //    %2 = mark_dependence ... on %1
       if (auto *MD = dyn_cast<MarkDependenceInst>(U))
         if (Pin == MD->getBase() ||
-            std::find(Users.begin(), Users.end(), MD->getBase()) !=
-                Users.end()) {
+            std::find_if(Users.begin(), Users.end(),
+                         [&](SILInstruction *I) {
+                           return MD->getBase()->getDefiningInstruction() == I;
+                         }) != Users.end()) {
           MarkDeps.push_back(MD);
           continue;
         }
@@ -236,7 +243,7 @@
     // TODO: We already created an ArraySemanticsCall in
     // isSafeArraySemanticFunction. I wonder if we can refactor into a third
     // method that takes an array semantic call. Then we can reuse the work.
-    ArraySemanticsCall Call(I);
+    ArraySemanticsCall Call(cast<ApplyInst>(I));
 
     // If our call does not have guaranteed self, bail.
     if (!Call.hasGuaranteedSelf())
@@ -249,7 +256,7 @@
   /// Removes available pins that could be released by executing of 'I'.
   void invalidateAvailablePins(SILInstruction *I) {
     // Collect pins that we have to clear because they might have been released.
-    SmallVector<SILInstruction *, 16> RemovePin;
+    SmallVector<StrongPinInst *, 16> RemovePin;
     for (auto *P : AvailablePins) {
       if (!isSafeArraySemanticFunction(I) &&
           (mayDecrementRefCount(I, P, AA) ||
diff --git a/lib/SILOptimizer/Transforms/SILCodeMotion.cpp b/lib/SILOptimizer/Transforms/SILCodeMotion.cpp
index 2452ff8..bdb57cb 100644
--- a/lib/SILOptimizer/Transforms/SILCodeMotion.cpp
+++ b/lib/SILOptimizer/Transforms/SILCodeMotion.cpp
@@ -73,10 +73,8 @@
 
   ++NumRefCountOpsSimplified;
 
-  auto *RCI = cast<RefCountingInst>(I);
-
   // If we have a retain value...
-  if (isa<RetainValueInst>(I)) {
+  if (auto RCI = dyn_cast<RetainValueInst>(I)) {
     // And our payload is refcounted, insert a strong_retain onto the
     // payload.
     if (UEDITy.isReferenceCounted(Mod)) {
@@ -93,6 +91,7 @@
   // payload.
   assert(isa<ReleaseValueInst>(I) && "If I is not a retain value here, it must "
          "be a release value since enums do not have reference semantics.");
+  auto *RCI = cast<ReleaseValueInst>(I);
 
   // If our payload has reference semantics, insert the strong release.
   if (UEDITy.isReferenceCounted(Mod)) {
@@ -154,7 +153,7 @@
 
 /// \brief Returns True if we can sink this instruction to another basic block.
 static bool canSinkInstruction(SILInstruction *Inst) {
-  return Inst->use_empty() && !isa<TermInst>(Inst);
+  return !Inst->hasUsesOfAnyResult() && !isa<TermInst>(Inst);
 }
 
 /// \brief Returns true if this instruction is a skip barrier, which means that
@@ -322,15 +321,15 @@
   if (!FirstStruct || !SecondStruct)
     return None;
 
-  assert(First->getNumOperands() == Second->getNumOperands() &&
-         First->getType() == Second->getType() &&
+  assert(FirstStruct->getNumOperands() == SecondStruct->getNumOperands() &&
+         FirstStruct->getType() == SecondStruct->getType() &&
          "Types should be identical");
 
   llvm::Optional<unsigned> DifferentOperandIndex;
 
   // Check operands.
   for (unsigned i = 0, e = First->getNumOperands(); i != e; ++i) {
-    if (First->getOperand(i) != Second->getOperand(i)) {
+    if (FirstStruct->getOperand(i) != SecondStruct->getOperand(i)) {
       // Only track one different operand for now
       if (DifferentOperandIndex)
         return None;
@@ -344,7 +343,7 @@
   // Found a different operand, now check to see if its type is something
   // cheap enough to sink.
   // TODO: Sink more than just integers.
-  const auto &ArgTy = First->getOperand(*DifferentOperandIndex)->getType();
+  SILType ArgTy = FirstStruct->getOperand(*DifferentOperandIndex)->getType();
   if (!ArgTy.is<BuiltinIntegerType>())
     return None;
 
@@ -408,16 +407,17 @@
   SILBasicBlock *FirstPred = *BB->pred_begin();
   TermInst *FirstTerm = FirstPred->getTerminator();
   auto FirstPredArg = FirstTerm->getOperand(ArgNum);
-  auto *FSI = dyn_cast<SILInstruction>(FirstPredArg);
-
-  // The list of identical instructions.
-  SmallVector<SILValue, 8> Clones;
-  Clones.push_back(FirstPredArg);
+  auto *FSI = dyn_cast<SingleValueInstruction>(FirstPredArg);
+  // TODO: MultiValueInstruction?
 
   // We only move instructions with a single use.
   if (!FSI || !hasOneNonDebugUse(FSI))
     return false;
 
+  // The list of identical instructions.
+  SmallVector<SingleValueInstruction*, 8> Clones;
+  Clones.push_back(FSI);
+
   // Don't move instructions that are sensitive to their location.
   //
   // If this instruction can read memory, we try to be conservatively not to
@@ -443,9 +443,18 @@
 
     // Find the Nth argument passed to BB.
     SILValue Arg = TI->getOperand(ArgNum);
-    auto *SI = dyn_cast<SILInstruction>(Arg);
-    if (!SI || !hasOneNonDebugUse(SI))
+
+    // If it's not the same basic kind of node, neither isIdenticalTo nor
+    // cheaperToPassOperandsAsArguments will return true.
+    if (Arg->getKind() != FSI->getValueKind())
       return false;
+
+    // Since it's the same kind, Arg must also be a single-value instruction.
+    auto *SI = cast<SingleValueInstruction>(Arg);
+
+    if (!hasOneNonDebugUse(SI))
+      return false;
+
     if (SI->isIdenticalTo(FSI)) {
       Clones.push_back(SI);
       continue;
@@ -466,10 +475,7 @@
     Clones.push_back(SI);
   }
 
-  if (!FSI)
-    return false;
-
-  auto *Undef = SILUndef::get(FirstPredArg->getType(), BB->getModule());
+  auto *Undef = SILUndef::get(FSI->getType(), BB->getModule());
 
   // Delete the debug info of the instruction that we are about to sink.
   deleteAllDebugUses(FSI);
@@ -495,7 +501,8 @@
       assert((isa<BranchInst>(TI) || isa<CondBranchInst>(TI)) &&
              "Branch instruction required");
 
-      auto *CloneInst = dyn_cast<SILInstruction>(*CloneIt);
+      // TODO: MultiValueInstruction
+      auto *CloneInst = *CloneIt;
       TI->setOperand(ArgNum, CloneInst->getOperand(*DifferentOperandIndex));
       // Now delete the clone as we only needed it operand.
       if (CloneInst != FSI)
@@ -511,9 +518,9 @@
   }
 
   // Sink one of the copies of the instruction.
-  FirstPredArg->replaceAllUsesWith(Undef);
+  FSI->replaceAllUsesWithUndef();
   FSI->moveBefore(&*BB->begin());
-  BB->getArgument(ArgNum)->replaceAllUsesWith(FirstPredArg);
+  BB->getArgument(ArgNum)->replaceAllUsesWith(FSI);
 
   // The argument is no longer in use. Replace all incoming inputs with undef
   // and try to delete the instruction.
@@ -673,7 +680,7 @@
         }
         Changed = true;
         for (auto I : Dups) {
-          I->replaceAllUsesWith(&*InstToSink);
+          I->replaceAllUsesPairwiseWith(&*InstToSink);
           I->eraseFromParent();
           NumSunk++;
         }
@@ -970,7 +977,7 @@
 
   void clear() { ValueToCaseMap.clear(); }
 
-  bool visitValueBase(ValueBase *V) { return false; }
+  bool visitSILInstruction(SILInstruction *I) { return false; }
 
   bool visitEnumInst(EnumInst *EI) {
     DEBUG(llvm::dbgs() << "    Storing enum into map: " << *EI);
diff --git a/lib/SILOptimizer/Transforms/SILMem2Reg.cpp b/lib/SILOptimizer/Transforms/SILMem2Reg.cpp
index 9955915..1dfc54d 100644
--- a/lib/SILOptimizer/Transforms/SILMem2Reg.cpp
+++ b/lib/SILOptimizer/Transforms/SILMem2Reg.cpp
@@ -187,7 +187,7 @@
     return false;
   
   // Recursively search for other (non-)loads in the instruction's uses.
-  for (auto UI : I->getUses()) {
+  for (auto UI : cast<SingleValueInstruction>(I)->getUses()) {
     SILInstruction *II = UI->getUser();
     if (II->getParent() != singleBlock)
       singleBlock = nullptr;
@@ -290,7 +290,7 @@
     if (!isa<StructElementAddrInst>(op) && !isa<TupleElementAddrInst>(op))
       return false;
     
-    op = cast<SILInstruction>(op)->getOperand(0);
+    op = cast<SingleValueInstruction>(op)->getOperand(0);
   }
   return true;
 }
@@ -305,7 +305,7 @@
     return;
   
   // Recursively search for other loads in the instruction's uses.
-  for (auto UI : I->getUses()) {
+  for (auto UI : cast<SingleValueInstruction>(I)->getUses()) {
     collectLoads(UI->getUser(), Loads);
   }
 }
@@ -316,7 +316,7 @@
   SILValue op = LI->getOperand();
   while (op != ASI) {
     assert(isa<StructElementAddrInst>(op) || isa<TupleElementAddrInst>(op));
-    SILInstruction *Inst = cast<SILInstruction>(op);
+    auto *Inst = cast<SingleValueInstruction>(op);
     projections.push_back(Projection(Inst));
     op = Inst->getOperand(0);
   }
@@ -330,7 +330,7 @@
   LI->eraseFromParent();
   while (op != ASI && op->use_empty()) {
     assert(isa<StructElementAddrInst>(op) || isa<TupleElementAddrInst>(op));
-    SILInstruction *Inst = cast<SILInstruction>(op);
+    auto *Inst = cast<SingleValueInstruction>(op);
     SILValue next = Inst->getOperand(0);
     Inst->eraseFromParent();
     op = next;
@@ -370,18 +370,19 @@
     ++BBI;
 
     if (isLoadFromStack(Inst, ASI)) {
+      auto Load = cast<LoadInst>(Inst);
       if (RunningVal) {
         // If we are loading from the AllocStackInst and we already know the
         // content of the Alloca then use it.
-        DEBUG(llvm::dbgs() << "*** Promoting load: " << *Inst);
+        DEBUG(llvm::dbgs() << "*** Promoting load: " << *Load);
         
-        replaceLoad(cast<LoadInst>(Inst), RunningVal, ASI);
+        replaceLoad(Load, RunningVal, ASI);
         NumInstRemoved++;
-      } else if (Inst->getOperand(0) == ASI) {
+      } else if (Load->getOperand() == ASI) {
         // If we don't know the content of the AllocStack then the loaded
         // value *is* the new value;
-        DEBUG(llvm::dbgs() << "*** First load: " << *Inst);
-        RunningVal = Inst;
+        DEBUG(llvm::dbgs() << "*** First load: " << *Load);
+        RunningVal = Load;
       }
       continue;
     }
@@ -509,13 +510,13 @@
       }
     }
 
-    SILValue InstVal = Inst;
-    
     // Remove dead address instructions that may be uses of the allocation.
-    while (InstVal->use_empty() && (isa<StructElementAddrInst>(InstVal) ||
-                                    isa<TupleElementAddrInst>(InstVal))) {
-      SILInstruction *I = cast<SILInstruction>(InstVal);
-      InstVal = I->getOperand(0);
+    SILNode *Node = Inst;
+    while (isa<StructElementAddrInst>(Node) ||
+           isa<TupleElementAddrInst>(Node)) {
+      auto *I = cast<SingleValueInstruction>(Node);
+      if (!I->use_empty()) break;
+      Node = I->getOperand(0);
       I->eraseFromParent();
       NumInstRemoved++;
     }
diff --git a/lib/SILOptimizer/Transforms/SILSROA.cpp b/lib/SILOptimizer/Transforms/SILSROA.cpp
index 350fc22..5393655 100644
--- a/lib/SILOptimizer/Transforms/SILSROA.cpp
+++ b/lib/SILOptimizer/Transforms/SILSROA.cpp
@@ -50,7 +50,7 @@
   // Stores to AI.
   llvm::SmallVector<StoreInst *, 4> Stores;
   // Instructions which extract from aggregates.
-  llvm::SmallVector<SILInstruction *, 4> ExtractInsts;
+  llvm::SmallVector<SingleValueInstruction *, 4> ExtractInsts;
 
   // TupleType if we are visiting a tuple.
   TupleType *TT = nullptr;
@@ -65,17 +65,17 @@
   void chopUpAlloca(std::vector<AllocStackInst *> &Worklist);
 
 private:
-  SILInstruction *createAgg(SILBuilder &B, SILLocation Loc, SILType Ty,
-                                  ArrayRef<SILValue> Elements);
-  SILInstruction *createAggProjection(SILBuilder &B, SILLocation Loc,
-                                      SILValue Operand, unsigned EltNo);
+  SILValue createAgg(SILBuilder &B, SILLocation Loc, SILType Ty,
+                     ArrayRef<SILValue> Elements);
+  SILValue createAggProjection(SILBuilder &B, SILLocation Loc,
+                               SILValue Operand, unsigned EltNo);
   unsigned getEltNoForProjection(SILInstruction *Inst);
   void createAllocas(llvm::SmallVector<AllocStackInst *, 4> &NewAllocations);
 };
 
 } // end anonymous namespace
 
-SILInstruction *
+SILValue 
 SROAMemoryUseAnalyzer::createAgg(SILBuilder &B, SILLocation Loc,
                                  SILType Ty,
                                  ArrayRef<SILValue> Elements) {
@@ -87,7 +87,7 @@
   return B.createStruct(Loc, Ty, Elements);
 }
 
-SILInstruction *
+SILValue
 SROAMemoryUseAnalyzer::createAggProjection(SILBuilder &B, SILLocation Loc,
                                            SILValue Operand,
                                            unsigned EltNo) {
@@ -237,8 +237,8 @@
     for (auto *NewAI : NewAllocations)
       Elements.push_back(B.createLoad(LI->getLoc(), NewAI,
                                       LoadOwnershipQualifier::Unqualified));
-    auto *Agg = createAgg(B, LI->getLoc(), LI->getType().getObjectType(),
-                          Elements);
+    SILValue Agg = createAgg(B, LI->getLoc(), LI->getType().getObjectType(),
+                             Elements);
     LI->replaceAllUsesWith(Agg);
     LI->eraseFromParent();
   }
diff --git a/lib/SILOptimizer/Transforms/SimplifyCFG.cpp b/lib/SILOptimizer/Transforms/SimplifyCFG.cpp
index 940f2fd..fe6da5e 100644
--- a/lib/SILOptimizer/Transforms/SimplifyCFG.cpp
+++ b/lib/SILOptimizer/Transforms/SimplifyCFG.cpp
@@ -211,33 +211,31 @@
     if (Inst->use_empty())
       continue;
 
-    if (Inst->hasValue()) {
-      SILValue NewRes(AvailValPair.second);
+    SILValue NewRes(AvailValPair.second);
 
-      SmallVector<UseWrapper, 16> UseList;
-      // Collect the uses of the value.
-      for (auto Use : Inst->getUses())
-        UseList.push_back(UseWrapper(Use));
+    SmallVector<UseWrapper, 16> UseList;
+    // Collect the uses of the value.
+    for (auto Use : Inst->getUses())
+      UseList.push_back(UseWrapper(Use));
 
-      SSAUp.Initialize(Inst->getType());
-      SSAUp.AddAvailableValue(DestBB, Inst);
-      SSAUp.AddAvailableValue(SrcBB, NewRes);
+    SSAUp.Initialize(Inst->getType());
+    SSAUp.AddAvailableValue(DestBB, Inst);
+    SSAUp.AddAvailableValue(SrcBB, NewRes);
 
-      if (UseList.empty())
+    if (UseList.empty())
+      continue;
+
+    // Update all the uses.
+    for (auto U : UseList) {
+      Operand *Use = U;
+      SILInstruction *User = Use->getUser();
+      assert(User && "Missing user");
+
+      // Ignore uses in the same basic block.
+      if (User->getParent() == DestBB)
         continue;
 
-      // Update all the uses.
-      for (auto U : UseList) {
-        Operand *Use = U;
-        SILInstruction *User = Use->getUser();
-        assert(User && "Missing user");
-
-        // Ignore uses in the same basic block.
-        if (User->getParent() == DestBB)
-          continue;
-
-        SSAUp.RewriteUse(*Use);
-      }
+      SSAUp.RewriteUse(*Use);
     }
   }
 }
@@ -394,9 +392,9 @@
 }
 
 /// Create an enum element by extracting the operand of a switch_enum.
-static SILInstruction *createEnumElement(SILBuilder &Builder,
-                                         SwitchEnumInst *SEI,
-                                         EnumElementDecl *EnumElement) {
+static SILValue createEnumElement(SILBuilder &Builder,
+                                  SwitchEnumInst *SEI,
+                                  EnumElementDecl *EnumElement) {
   auto EnumVal = SEI->getOperand();
   // Do we have a payload.
   auto EnumTy = EnumVal->getType();
@@ -411,9 +409,9 @@
 
 /// Create a value for the condition of the terminator that flows along the edge
 /// with 'EdgeIdx'. Insert it before the 'UserInst'.
-static SILInstruction *createValueForEdge(SILInstruction *UserInst,
-                                          SILInstruction *DominatingTerminator,
-                                          unsigned EdgeIdx) {
+static SILValue createValueForEdge(SILInstruction *UserInst,
+                                   SILInstruction *DominatingTerminator,
+                                   unsigned EdgeIdx) {
   SILBuilderWithScope Builder(UserInst);
 
   if (auto *CBI = dyn_cast<CondBranchInst>(DominatingTerminator))
@@ -557,7 +555,7 @@
 
     // Replace dominated user instructions.
     for (auto *UserInst : UsersToReplace) {
-      SILInstruction *EdgeValue = nullptr;
+      SILValue EdgeValue;
       for (auto &Op : UserInst->getAllOperands()) {
         if (stripExpectIntrinsic(Op.get()) == DominatingCondition) {
           if (!EdgeValue)
@@ -1031,8 +1029,14 @@
       return false;
 
     // We need to update ssa if a value is used outside the duplicated block.
-    if (!NeedToUpdateSSA)
-      NeedToUpdateSSA |= isUsedOutsideOfBlock(&Inst, DestBB);
+    if (!NeedToUpdateSSA) {
+      for (auto result : Inst.getResults()) {
+        if (isUsedOutsideOfBlock(result, DestBB)) {
+          NeedToUpdateSSA = true;
+          break;
+        }
+      }
+    }
   }
 
   // Don't jump thread through a potential header - this can produce irreducible
@@ -1087,7 +1091,9 @@
 bool SimplifyCFG::simplifyBranchOperands(OperandValueArrayRef Operands) {
   bool Simplified = false;
   for (auto O = Operands.begin(), E = Operands.end(); O != E; ++O)
-    if (auto *I = dyn_cast<SILInstruction>(*O))
+    // All of our interesting simplifications are on single-value instructions
+    // for now.
+    if (auto *I = dyn_cast<SingleValueInstruction>(*O))
       if (SILValue Result = simplifyInstruction(I)) {
         DEBUG(llvm::dbgs() << "simplify branch operand " << *I);
         I->replaceAllUsesWith(Result);
@@ -1454,7 +1460,8 @@
           Builder.createCondBranch(
               BI->getLoc(),
               invertExpectAndApplyTo(Builder, BI->getCondition(), Cond),
-              FalseSide, FalseArgs, TrueSide, TrueArgs);
+              FalseSide, FalseArgs, TrueSide, TrueArgs, BI->getFalseBBCount(),
+              BI->getTrueBBCount());
           BI->eraseFromParent();
           addToWorklist(ThisBB);
           return true;
@@ -1469,10 +1476,9 @@
   if (TrueTrampolineDest && TrueTrampolineDest != FalseSide) {
     DEBUG(llvm::dbgs() << "true-trampoline from bb" << ThisBB->getDebugID() <<
           " to bb" << TrueTrampolineDest->getDebugID() << '\n');
-    SILBuilderWithScope(BI)
-      .createCondBranch(BI->getLoc(), BI->getCondition(),
-                        TrueTrampolineDest, TrueArgs,
-                        FalseSide, FalseArgs);
+    SILBuilderWithScope(BI).createCondBranch(
+        BI->getLoc(), BI->getCondition(), TrueTrampolineDest, TrueArgs,
+        FalseSide, FalseArgs, BI->getTrueBBCount(), BI->getFalseBBCount());
     BI->eraseFromParent();
 
     if (LoopHeaders.count(TrueSide))
@@ -1486,10 +1492,10 @@
   if (FalseTrampolineDest && FalseTrampolineDest != TrueSide) {
     DEBUG(llvm::dbgs() << "false-trampoline from bb" << ThisBB->getDebugID() <<
           " to bb" << FalseTrampolineDest->getDebugID() << '\n');
-    SILBuilderWithScope(BI)
-      .createCondBranch(BI->getLoc(), BI->getCondition(),
-                        TrueSide, TrueArgs,
-                        FalseTrampolineDest, FalseArgs);
+    SILBuilderWithScope(BI).createCondBranch(
+        BI->getLoc(), BI->getCondition(), TrueSide, TrueArgs,
+        FalseTrampolineDest, FalseArgs, BI->getTrueBBCount(),
+        BI->getFalseBBCount());
     BI->eraseFromParent();
     if (LoopHeaders.count(FalseSide))
       LoopHeaders.insert(ThisBB);
@@ -1518,9 +1524,9 @@
     DEBUG(llvm::dbgs() << "true-trampoline from bb" << ThisBB->getDebugID() <<
           " to bb" << TrueTrampolineBr->getDestBB()->getDebugID() << '\n');
     SILBuilderWithScope(BI).createCondBranch(
-        BI->getLoc(), BI->getCondition(),
-        TrueTrampolineBr->getDestBB(), TrueTrampolineBr->getArgs(),
-        FalseSide, FalseArgs);
+        BI->getLoc(), BI->getCondition(), TrueTrampolineBr->getDestBB(),
+        TrueTrampolineBr->getArgs(), FalseSide, FalseArgs, BI->getTrueBBCount(),
+        BI->getFalseBBCount());
     BI->eraseFromParent();
 
     if (LoopHeaders.count(TrueSide))
@@ -1536,9 +1542,9 @@
     DEBUG(llvm::dbgs() << "false-trampoline from bb" << ThisBB->getDebugID() <<
           " to bb" << FalseTrampolineBr->getDestBB()->getDebugID() << '\n');
     SILBuilderWithScope(BI).createCondBranch(
-        BI->getLoc(), BI->getCondition(),
-        TrueSide, TrueArgs,
-        FalseTrampolineBr->getDestBB(), FalseTrampolineBr->getArgs());
+        BI->getLoc(), BI->getCondition(), TrueSide, TrueArgs,
+        FalseTrampolineBr->getDestBB(), FalseTrampolineBr->getArgs(),
+        BI->getTrueBBCount(), BI->getFalseBBCount());
     BI->eraseFromParent();
     if (LoopHeaders.count(FalseSide))
       LoopHeaders.insert(ThisBB);
@@ -1844,10 +1850,10 @@
     switch (MaybeDead->getKind()) {
       // These technically have side effects, but not ones that matter
       // in a block that we shouldn't really reach...
-    case ValueKind::StrongRetainInst:
-    case ValueKind::StrongReleaseInst:
-    case ValueKind::RetainValueInst:
-    case ValueKind::ReleaseValueInst:
+    case SILInstructionKind::StrongRetainInst:
+    case SILInstructionKind::StrongReleaseInst:
+    case SILInstructionKind::RetainValueInst:
+    case SILInstructionKind::ReleaseValueInst:
       break;
 
     default:
@@ -1859,11 +1865,7 @@
       }
     }
 
-    if (!MaybeDead->use_empty()) {
-      auto Undef = SILUndef::get(MaybeDead->getType(), BB->getModule());
-      MaybeDead->replaceAllUsesWith(Undef);
-    }
-
+    MaybeDead->replaceAllUsesOfAllResultsWithUndef();
     DeadInstrs.push_back(&*MaybeDead);
     Changed = true;
   }
@@ -2341,11 +2343,11 @@
     // Add the default-entry of the original instruction as case-entry.
     CaseBBs.push_back(std::make_pair(elementDecl.get(), SWI->getDefaultBB()));
 
-    if (SWI->getKind() == ValueKind::SwitchEnumInst) {
+    if (isa<SwitchEnumInst>(SWI)) {
       SILBuilderWithScope(SWI)
           .createSwitchEnum(SWI->getLoc(), SWI->getOperand(), nullptr, CaseBBs);
     } else {
-      assert(SWI->getKind() == ValueKind::SwitchEnumAddrInst &&
+      assert(isa<SwitchEnumAddrInst>(SWI) &&
              "unknown switch_enum instruction");
       SILBuilderWithScope(SWI).createSwitchEnumAddr(
           SWI->getLoc(), SWI->getOperand(), nullptr, CaseBBs);
@@ -2447,7 +2449,7 @@
 deleteTriviallyDeadOperandsOfDeadArgument(MutableArrayRef<Operand> TermOperands,
                                           unsigned DeadArgIndex, SILModule &M) {
   Operand &Op = TermOperands[DeadArgIndex];
-  auto *I = dyn_cast<SILInstruction>(Op.get());
+  auto *I = Op.get()->getDefiningInstruction();
   if (!I)
     return;
   Op.set(SILUndef::get(Op.get()->getType(), M));
@@ -2484,7 +2486,8 @@
 
     Builder.createCondBranch(CBI->getLoc(), CBI->getCondition(),
                              CBI->getTrueBB(), TrueArgs, CBI->getFalseBB(),
-                             FalseArgs);
+                             FalseArgs, CBI->getTrueBBCount(),
+                             CBI->getFalseBBCount());
     Branch->eraseFromParent();
     return;
   }
@@ -2603,7 +2606,8 @@
   }
 
   B.createCondBranch(CBI->getLoc(), CBI->getCondition(), CBI->getTrueBB(),
-                     NewTrueValues, CBI->getFalseBB(), NewFalseValues);
+                     NewTrueValues, CBI->getFalseBB(), NewFalseValues,
+                     CBI->getTrueBBCount(), CBI->getFalseBBCount());
 }
 
 bool ArgumentSplitter::createNewArguments() {
@@ -2651,7 +2655,7 @@
     NewArgumentValues.push_back(NewArg);
   }
 
-  SILInstruction *Agg = nullptr;
+  SingleValueInstruction *Agg;
 
   {
     SILBuilder B(ParentBB->begin());
@@ -2663,7 +2667,6 @@
     auto Loc = RegularLocation::getAutoGeneratedLocation();
     Agg = Projection::createAggFromFirstLevelProjections(
               B, Loc, Arg->getType(), NewArgumentValues).get();
-    assert(Agg->hasValue() && "Expected a result");
   }
 
   Arg->replaceAllUsesWith(Agg);
@@ -3141,7 +3144,7 @@
   IntegerLiteralInst *Literal = nullptr;
   
   /// The result value.
-  SILInstruction *Result = nullptr;
+  SingleValueInstruction *Result = nullptr;
 
   /// The block which contains the cond_br of the input value comparison
   /// or the block which assigns the default value.
@@ -3390,11 +3393,14 @@
     return false;
 
   auto *Use = *A->use_begin();
-  auto *User = cast<SILInstruction>(Use->getUser());
+  auto *User = Use->getUser();
+
+  // Handle projections.
   if (!isa<StructExtractInst>(User) &&
       !isa<TupleExtractInst>(User) &&
       !isa<UncheckedEnumDataInst>(User))
     return false;
+  auto proj = cast<SingleValueInstruction>(User);
 
   // For now, just handle the case where all predecessors are
   // unconditional branches.
@@ -3408,7 +3414,7 @@
     if (isa<TupleInst>(BranchArg))
       continue;
     if (auto *EI = dyn_cast<EnumInst>(BranchArg)) {
-      if (EI->getElement() == cast<UncheckedEnumDataInst>(User)->getElement())
+      if (EI->getElement() == cast<UncheckedEnumDataInst>(proj)->getElement())
         continue;
     }
     return false;
@@ -3419,20 +3425,20 @@
   DEBUG(llvm::dbgs() << "unwrap argument:" << *A);
   A->replaceAllUsesWith(SILUndef::get(A->getType(), BB->getModule()));
   auto *NewArg =
-      BB->replacePHIArgument(i, User->getType(), ValueOwnershipKind::Owned);
-  User->replaceAllUsesWith(NewArg);
+      BB->replacePHIArgument(i, proj->getType(), ValueOwnershipKind::Owned);
+  proj->replaceAllUsesWith(NewArg);
 
   // Rewrite the branch operand for each incoming branch.
   for (auto *Pred : BB->getPredecessorBlocks()) {
     if (auto *Branch = cast<BranchInst>(Pred->getTerminator())) {
-      auto V = getInsertedValue(cast<SILInstruction>(Branch->getArg(i)),
-                                User);
+      auto V = getInsertedValue(cast<SingleValueInstruction>(Branch->getArg(i)),
+                                proj);
       Branch->setOperand(i, V);
       addToWorklist(Pred);
     }
   }
 
-  User->eraseFromParent();
+  proj->eraseFromParent();
 
   return true;
 }
diff --git a/lib/SILOptimizer/Transforms/Sink.cpp b/lib/SILOptimizer/Transforms/Sink.cpp
index 427e511..40bb7ee 100644
--- a/lib/SILOptimizer/Transforms/Sink.cpp
+++ b/lib/SILOptimizer/Transforms/Sink.cpp
@@ -73,25 +73,27 @@
 
     // TODO: We may want to delete debug instructions to allow us to sink more
     // instructions.
-    for (auto *Operand : II->getUses()) {
-      SILInstruction *User = Operand->getUser();
+    for (auto result : II->getResults()) {
+      for (auto *Operand : result->getUses()) {
+        SILInstruction *User = Operand->getUser();
 
-      // Check if the instruction is already in the user's block.
-      if (User->getParent() == CurrentBlock) return false;
+        // Check if the instruction is already in the user's block.
+        if (User->getParent() == CurrentBlock) return false;
 
-      // Record the block of the first user and move on to
-      // other users.
-      if (!Dest) {
-        Dest = User->getParent();
-        continue;
+        // Record the block of the first user and move on to
+        // other users.
+        if (!Dest) {
+          Dest = User->getParent();
+          continue;
+        }
+
+        // Find a location that dominates all users. If we did not find such
+        // a block or if it is the current block then bail out.
+        Dest = DT->findNearestCommonDominator(Dest, User->getParent());
+
+        if (!Dest || Dest == CurrentBlock)
+          return false;
       }
-
-      // Find a location that dominates all users. If we did not find such
-      // a block or if it is the current block then bail out.
-      Dest = DT->findNearestCommonDominator(Dest, User->getParent());
-
-      if (!Dest || Dest == CurrentBlock)
-        return false;
     }
 
     if (!Dest) return false;
diff --git a/lib/SILOptimizer/Transforms/SpeculativeDevirtualizer.cpp b/lib/SILOptimizer/Transforms/SpeculativeDevirtualizer.cpp
index 5ca42e6..2c96bcf 100644
--- a/lib/SILOptimizer/Transforms/SpeculativeDevirtualizer.cpp
+++ b/lib/SILOptimizer/Transforms/SpeculativeDevirtualizer.cpp
@@ -59,13 +59,13 @@
   FullApplySite NAI;
 
   switch (AI.getInstruction()->getKind()) {
-  case ValueKind::ApplyInst:
+  case SILInstructionKind::ApplyInst:
     NAI = Builder.createApply(AI.getLoc(), AI.getCallee(),
                                    AI.getSubstitutions(),
                                    Ret,
                                    cast<ApplyInst>(AI)->isNonThrowing());
     break;
-  case ValueKind::TryApplyInst: {
+  case SILInstructionKind::TryApplyInst: {
     auto *TryApplyI = cast<TryApplyInst>(AI.getInstruction());
     NAI = Builder.createTryApply(AI.getLoc(), AI.getCallee(),
                                       AI.getSubstitutions(),
@@ -155,25 +155,26 @@
       VirtBuilder.createUnreachable(AI.getLoc());
     } else {
       IdenBuilder.createBranch(AI.getLoc(), Continue,
-                               ArrayRef<SILValue>(IdenAI.getInstruction()));
+                               { cast<ApplyInst>(IdenAI) });
       VirtBuilder.createBranch(AI.getLoc(), Continue,
-                               ArrayRef<SILValue>(VirtAI.getInstruction()));
+                               { cast<ApplyInst>(VirtAI) });
     }
   }
 
   // Remove the old Apply instruction.
   assert(AI.getInstruction() == &Continue->front() &&
          "AI should be the first instruction in the split Continue block");
-  if (!isa<TryApplyInst>(AI)) {
-    AI.getInstruction()->replaceAllUsesWith(Arg);
-    AI.getInstruction()->eraseFromParent();
-    assert(!Continue->empty() &&
-           "There should be at least a terminator after AI");
-  } else {
+  if (isa<TryApplyInst>(AI)) {
     AI.getInstruction()->eraseFromParent();
     assert(Continue->empty() &&
            "There should not be an instruction after try_apply");
     Continue->eraseFromParent();
+  } else {
+    auto apply = cast<ApplyInst>(AI);
+    apply->replaceAllUsesWith(Arg);
+    apply->eraseFromParent();
+    assert(!Continue->empty() &&
+           "There should be at least a terminator after AI");
   }
 
   // Update the stats.
diff --git a/lib/SILOptimizer/Transforms/StackPromotion.cpp b/lib/SILOptimizer/Transforms/StackPromotion.cpp
index 07e9bbe..5c1d0c4 100644
--- a/lib/SILOptimizer/Transforms/StackPromotion.cpp
+++ b/lib/SILOptimizer/Transforms/StackPromotion.cpp
@@ -115,10 +115,10 @@
 
   // Collect all use-points of the allocation. These are refcount instructions
   // and apply instructions.
-  llvm::SmallVector<ValueBase *, 8> BaseUsePoints;
+  llvm::SmallVector<SILNode *, 8> BaseUsePoints;
   llvm::SmallVector<SILInstruction *, 8> UsePoints;
   ConGraph->getUsePoints(Node, BaseUsePoints);
-  for (ValueBase *UsePoint : BaseUsePoints) {
+  for (SILNode *UsePoint : BaseUsePoints) {
     if (SILInstruction *I = dyn_cast<SILInstruction>(UsePoint)) {
       UsePoints.push_back(I);
     } else {
diff --git a/lib/SILOptimizer/Transforms/UnsafeGuaranteedPeephole.cpp b/lib/SILOptimizer/Transforms/UnsafeGuaranteedPeephole.cpp
index b17b337..dce03e0 100644
--- a/lib/SILOptimizer/Transforms/UnsafeGuaranteedPeephole.cpp
+++ b/lib/SILOptimizer/Transforms/UnsafeGuaranteedPeephole.cpp
@@ -64,8 +64,8 @@
     auto *CurInst = &*It++;
     if (CurInst != Retain &&
         (isa<StrongRetainInst>(CurInst) || isa<RetainValueInst>(CurInst)) &&
-        RCFI.getRCIdentityRoot(CurInst->getOperand(0)) ==
-            SILValue(UnsafeGuaranteedI)) {
+        RCFI.getRCIdentityRoot(CurInst->getOperand(0))
+          ->getDefiningInstruction() == UnsafeGuaranteedI) {
       CandidateRetain = CurInst;
       continue;
     }
@@ -80,8 +80,8 @@
 
     if (CandidateRetain != nullptr && CurInst != Release &&
         (isa<StrongReleaseInst>(CurInst) || isa<ReleaseValueInst>(CurInst)) &&
-        RCFI.getRCIdentityRoot(CurInst->getOperand(0)) ==
-            SILValue(UnsafeGuaranteedI)) {
+        RCFI.getRCIdentityRoot(CurInst->getOperand(0))
+          ->getDefiningInstruction() == UnsafeGuaranteedI) {
       // Delete the retain/release pair.
       InstsToDelete.push_back(CandidateRetain);
       InstsToDelete.push_back(CurInst);
@@ -155,8 +155,8 @@
       //  %4 = builtin "unsafeGuaranteed"<Foo>(%0 : $Foo)
       //  %5 = tuple_extract %4 : $(Foo, Builtin.Int8), 0
       //  %6 = tuple_extract %4 : $(Foo, Builtin.Int8), 1
-      SILInstruction *UnsafeGuaranteedValue;
-      SILInstruction *UnsafeGuaranteedToken;
+      SingleValueInstruction *UnsafeGuaranteedValue;
+      SingleValueInstruction *UnsafeGuaranteedToken;
       std::tie(UnsafeGuaranteedValue, UnsafeGuaranteedToken) =
           getSingleUnsafeGuaranteedValueResult(UnsafeGuaranteedI);
 
diff --git a/lib/SILOptimizer/UtilityPasses/AADumper.cpp b/lib/SILOptimizer/UtilityPasses/AADumper.cpp
index 31e83c0..6da3331 100644
--- a/lib/SILOptimizer/UtilityPasses/AADumper.cpp
+++ b/lib/SILOptimizer/UtilityPasses/AADumper.cpp
@@ -41,8 +41,8 @@
     for (auto *Arg : BB.getArguments())
       Values.push_back(SILValue(Arg));
     for (auto &II : BB)
-      if (II.hasValue())
-        Values.push_back(&II);
+      for (auto result : II.getResults())
+        Values.push_back(result);
   }
   return Values.size() > 1;
 }
diff --git a/lib/SILOptimizer/UtilityPasses/BasicCalleePrinter.cpp b/lib/SILOptimizer/UtilityPasses/BasicCalleePrinter.cpp
index e59965f..cce51c8 100644
--- a/lib/SILOptimizer/UtilityPasses/BasicCalleePrinter.cpp
+++ b/lib/SILOptimizer/UtilityPasses/BasicCalleePrinter.cpp
@@ -35,7 +35,7 @@
 
   void printCallees(FullApplySite FAS) {
     llvm::outs() << "Function call site:\n";
-    if (auto *Callee = dyn_cast<SILInstruction>(FAS.getCallee()))
+    if (auto *Callee = FAS.getCallee()->getDefiningInstruction())
       llvm::outs() << *Callee;
     llvm::outs() << *FAS.getInstruction();
 
diff --git a/lib/SILOptimizer/UtilityPasses/BugReducerTester.cpp b/lib/SILOptimizer/UtilityPasses/BugReducerTester.cpp
index ae03632..d03573d 100644
--- a/lib/SILOptimizer/UtilityPasses/BugReducerTester.cpp
+++ b/lib/SILOptimizer/UtilityPasses/BugReducerTester.cpp
@@ -88,7 +88,8 @@
 
     SILFunction *F = getFunction()->getModule().getOrCreateSharedFunction(
         RegularLocation::getAutoGeneratedLocation(), RuntimeCrasherFunctionName,
-        FuncType, IsBare, IsNotTransparent, IsSerialized, IsNotThunk);
+        FuncType, IsBare, IsNotTransparent, IsSerialized, ProfileCounter(),
+        IsNotThunk);
     if (F->isDefinition())
       return F;
 
diff --git a/lib/SILOptimizer/UtilityPasses/IVInfoPrinter.cpp b/lib/SILOptimizer/UtilityPasses/IVInfoPrinter.cpp
index 725964c..b6ccb65 100644
--- a/lib/SILOptimizer/UtilityPasses/IVInfoPrinter.cpp
+++ b/lib/SILOptimizer/UtilityPasses/IVInfoPrinter.cpp
@@ -55,15 +55,17 @@
             dumpIV(Info.getInductionVariableHeader(A), A);
           }
 
-        for (auto &I : BB)
-          if (Info.isInductionVariable(&I)) {
-            if (!FoundIV)
-              llvm::errs() << "Induction variables for function: " <<
-              F.getName() << "\n";
+        for (auto &I : BB) {
+          auto value = dyn_cast<SingleValueInstruction>(&I);
+          if (!value) continue;
+          if (!Info.isInductionVariable(value)) continue;
+          if (!FoundIV)
+            llvm::errs() << "Induction variables for function: " <<
+            F.getName() << "\n";
 
-            FoundIV = true;
-            dumpIV(Info.getInductionVariableHeader(&I), &I);
-          }
+          FoundIV = true;
+          dumpIV(Info.getInductionVariableHeader(value), value);
+        }
       }
       
       if (FoundIV)
diff --git a/lib/SILOptimizer/UtilityPasses/InstCount.cpp b/lib/SILOptimizer/UtilityPasses/InstCount.cpp
index a63b9cf..9501a3f 100644
--- a/lib/SILOptimizer/UtilityPasses/InstCount.cpp
+++ b/lib/SILOptimizer/UtilityPasses/InstCount.cpp
@@ -53,13 +53,13 @@
 STATISTIC(TotalSharedExternalFuncs, "Number of shared external funcs");
 
 // Individual instruction statistics
-#define INST(Id, Parent, TextualName, MemBehavior, ReleasingBehavior)          \
+#define INST(Id, Parent) \
   STATISTIC(Num##Id, "Number of " #Id);
 #include "swift/SIL/SILNodes.def"
 
 namespace {
 
-struct InstCountVisitor : SILVisitor<InstCountVisitor> {
+struct InstCountVisitor : SILInstructionVisitor<InstCountVisitor> {
   // We store these locally so that we do not continually check if the function
   // is external or not. Instead, we just check once at the end and accumulate.
   unsigned InstCount = 0;
@@ -67,16 +67,16 @@
 
   void visitSILBasicBlock(SILBasicBlock *BB) {
     BlockCount++;
-    SILVisitor<InstCountVisitor>::visitSILBasicBlock(BB);
+    SILInstructionVisitor<InstCountVisitor>::visitSILBasicBlock(BB);
   }
 
   void visitSILFunction(SILFunction *F) {
-    SILVisitor<InstCountVisitor>::visitSILFunction(F);
+    SILInstructionVisitor<InstCountVisitor>::visitSILFunction(F);
   }
 
   void visitValueBase(ValueBase *V) { }
 
-#define INST(Id, Parent, TextualName, MemBehavior, ReleasingBehavior)          \
+#define INST(Id, Parent)                                                       \
   void visit##Id(Id *I) {                                                      \
     ++Num##Id;                                                                 \
     ++InstCount;                                                               \
diff --git a/lib/SILOptimizer/UtilityPasses/MemBehaviorDumper.cpp b/lib/SILOptimizer/UtilityPasses/MemBehaviorDumper.cpp
index dc41e52..a1d0eaa 100644
--- a/lib/SILOptimizer/UtilityPasses/MemBehaviorDumper.cpp
+++ b/lib/SILOptimizer/UtilityPasses/MemBehaviorDumper.cpp
@@ -33,9 +33,10 @@
   for (auto &BB : Fn) {
     for (auto *Arg : BB.getArguments())
       Values.push_back(SILValue(Arg));
-    for (auto &II : BB)
-      if (II.hasValue())
-        Values.push_back(&II);
+    for (auto &II : BB) {
+      for (auto result : II.getResults())
+        Values.push_back(result);
+    }
   }
   return Values.size() > 1;
 }
@@ -81,7 +82,7 @@
               bool Write = AA->mayWriteToMemory(&I, V);
               bool SideEffects = AA->mayHaveSideEffects(&I, V);
               llvm::outs() << "PAIR #" << PairCount++ << ".\n"
-                           << "  " << SILValue(&I) << "  " << V
+                           << "  " << I << "  " << V
                            << "  r=" << Read << ",w=" << Write
                            << ",se=" << SideEffects << "\n";
             }
diff --git a/lib/SILOptimizer/UtilityPasses/RCIdentityDumper.cpp b/lib/SILOptimizer/UtilityPasses/RCIdentityDumper.cpp
index f04abf8..fa1a132 100644
--- a/lib/SILOptimizer/UtilityPasses/RCIdentityDumper.cpp
+++ b/lib/SILOptimizer/UtilityPasses/RCIdentityDumper.cpp
@@ -50,8 +50,7 @@
         Results.push_back({Arg, RCId->getRCIdentityRoot(Arg)});
       }
       for (auto &II : BB) {
-        if (II.hasValue()) {
-          SILValue V(&II);
+        for (auto V : II.getResults()) {
           ValueToValueIDMap[V] = ValueCount++;
           Results.push_back({V, RCId->getRCIdentityRoot(V)});
         }
diff --git a/lib/SILOptimizer/UtilityPasses/SimplifyUnreachableContainingBlocks.cpp b/lib/SILOptimizer/UtilityPasses/SimplifyUnreachableContainingBlocks.cpp
index f1ad790..c208b93 100644
--- a/lib/SILOptimizer/UtilityPasses/SimplifyUnreachableContainingBlocks.cpp
+++ b/lib/SILOptimizer/UtilityPasses/SimplifyUnreachableContainingBlocks.cpp
@@ -43,7 +43,7 @@
         auto *I = &*II;
         ++II;
 
-        I->replaceAllUsesWithUndef();
+        I->replaceAllUsesOfAllResultsWithUndef();
         I->eraseFromParent();
       }
     }
diff --git a/lib/SILOptimizer/UtilityPasses/ValueOwnershipKindDumper.cpp b/lib/SILOptimizer/UtilityPasses/ValueOwnershipKindDumper.cpp
index 900abe9..67e5573 100644
--- a/lib/SILOptimizer/UtilityPasses/ValueOwnershipKindDumper.cpp
+++ b/lib/SILOptimizer/UtilityPasses/ValueOwnershipKindDumper.cpp
@@ -43,29 +43,33 @@
     for (auto &BB : *F) {
       // We only verify instructions right now.
       for (auto &II : BB) {
-        // If the instruction doesn't have a value, bail.
-        if (!II.hasValue())
-          continue;
-        SILValue V(&II);
-        llvm::outs() << "Visiting: " << II;
-        auto Kind = V.getOwnershipKind();
-        llvm::outs() << "    " << Kind << "\n";
-        if (Kind == ValueOwnershipKind::Any)
+        // If the instruction doesn't have any results, bail.
+        auto results = II.getResults();
+        if (results.empty())
           continue;
 
-        if (Kind == ValueOwnershipKind::Trivial) {
-          if (auto *EI = dyn_cast<EnumInst>(V)) {
-            checkEnumInstIsTrivial(EI);
+        llvm::outs() << "Visiting: " << II;
+
+        for (auto V : results) {
+          auto Kind = V.getOwnershipKind();
+          llvm::outs() << "    " << Kind << "\n";
+          if (Kind == ValueOwnershipKind::Any)
             continue;
-          }
-          SILType Ty = V->getType();
-          if (!Ty.isTrivial(M) && !Ty.isAddress()) {
-            llvm_unreachable("Error! Trivial ownership without trivial type\n");
-          }
-        } else {
-          if (V->getType().isTrivial(M)) {
-            llvm_unreachable(
-                "Error! Non Trivial ownership with trivial type\n");
+
+          if (Kind == ValueOwnershipKind::Trivial) {
+            if (auto *EI = dyn_cast<EnumInst>(V)) {
+              checkEnumInstIsTrivial(EI);
+              continue;
+            }
+            SILType Ty = V->getType();
+            if (!Ty.isTrivial(M) && !Ty.isAddress()) {
+              llvm_unreachable("Error! Trivial ownership without trivial type\n");
+            }
+          } else {
+            if (V->getType().isTrivial(M)) {
+              llvm_unreachable(
+                  "Error! Non Trivial ownership with trivial type\n");
+            }
           }
         }
       }
diff --git a/lib/SILOptimizer/Utils/CFG.cpp b/lib/SILOptimizer/Utils/CFG.cpp
index 9632f61..452e58d 100644
--- a/lib/SILOptimizer/Utils/CFG.cpp
+++ b/lib/SILOptimizer/Utils/CFG.cpp
@@ -50,9 +50,10 @@
       assert(FalseArgs.size() == Dest->getNumArguments());
     }
 
-    NewBr = Builder.createCondBranch(CBI->getLoc(), CBI->getCondition(),
-                                    CBI->getTrueBB(), TrueArgs,
-                                    CBI->getFalseBB(), FalseArgs);
+    NewBr = Builder.createCondBranch(
+        CBI->getLoc(), CBI->getCondition(), CBI->getTrueBB(), TrueArgs,
+        CBI->getFalseBB(), FalseArgs, CBI->getTrueBBCount(),
+        CBI->getFalseBBCount());
   } else if (auto *BI = dyn_cast<BranchInst>(Branch)) {
     SmallVector<SILValue, 8> Args;
 
@@ -120,9 +121,10 @@
     assert(FalseArgs.size() == CBI->getFalseBB()->getNumArguments() &&
            "Destination block's number of arguments must match");
 
-    CBI = Builder.createCondBranch(CBI->getLoc(), CBI->getCondition(),
-                                    CBI->getTrueBB(), TrueArgs,
-                                    CBI->getFalseBB(), FalseArgs);
+    CBI = Builder.createCondBranch(
+        CBI->getLoc(), CBI->getCondition(), CBI->getTrueBB(), TrueArgs,
+        CBI->getFalseBB(), FalseArgs, CBI->getTrueBBCount(),
+        CBI->getFalseBBCount());
     Branch->dropAllReferences();
     Branch->eraseFromParent();
     return CBI;
@@ -205,8 +207,9 @@
     else
       FalseDest = NewDest;
 
-    B.createCondBranch(CondBr->getLoc(), CondBr->getCondition(),
-                       TrueDest, TrueArgs, FalseDest, FalseArgs);
+    B.createCondBranch(CondBr->getLoc(), CondBr->getCondition(), TrueDest,
+                       TrueArgs, FalseDest, FalseArgs, CondBr->getTrueBBCount(),
+                       CondBr->getFalseBBCount());
     CondBr->dropAllReferences();
     CondBr->eraseFromParent();
     return;
@@ -256,7 +259,8 @@
     auto SuccessBB = !EdgeIdx ? NewDest : CBI->getSuccessBB();
     auto FailureBB = EdgeIdx ? NewDest : CBI->getFailureBB();
     B.createCheckedCastBranch(CBI->getLoc(), CBI->isExact(), CBI->getOperand(),
-                              CBI->getCastType(), SuccessBB, FailureBB);
+                              CBI->getCastType(), SuccessBB, FailureBB,
+                              CBI->getTrueBBCount(), CBI->getFalseBBCount());
     CBI->eraseFromParent();
     return;
   }
@@ -277,10 +281,12 @@
     assert(EdgeIdx == 0 || EdgeIdx == 1 && "Invalid edge index");
     auto SuccessBB = !EdgeIdx ? NewDest : CBI->getSuccessBB();
     auto FailureBB = EdgeIdx ? NewDest : CBI->getFailureBB();
+    auto TrueCount = CBI->getTrueBBCount();
+    auto FalseCount = CBI->getFalseBBCount();
     B.createCheckedCastAddrBranch(CBI->getLoc(), CBI->getConsumptionKind(),
                                   CBI->getSrc(), CBI->getSourceType(),
                                   CBI->getDest(), CBI->getTargetType(),
-                                  SuccessBB, FailureBB);
+                                  SuccessBB, FailureBB, TrueCount, FalseCount);
     CBI->eraseFromParent();
     return;
   }
@@ -372,8 +378,9 @@
       FalseDest = NewDest;
     }
 
-    B.createCondBranch(CondBr->getLoc(), CondBr->getCondition(),
-        TrueDest, TrueArgs, FalseDest, FalseArgs);
+    B.createCondBranch(CondBr->getLoc(), CondBr->getCondition(), TrueDest,
+                       TrueArgs, FalseDest, FalseArgs, CondBr->getTrueBBCount(),
+                       CondBr->getFalseBBCount());
     CondBr->dropAllReferences();
     CondBr->eraseFromParent();
     return;
@@ -423,7 +430,8 @@
     auto SuccessBB = OldDest == CBI->getSuccessBB() ? NewDest : CBI->getSuccessBB();
     auto FailureBB = OldDest == CBI->getFailureBB() ? NewDest : CBI->getFailureBB();
     B.createCheckedCastBranch(CBI->getLoc(), CBI->isExact(), CBI->getOperand(),
-        CBI->getCastType(), SuccessBB, FailureBB);
+                              CBI->getCastType(), SuccessBB, FailureBB,
+                              CBI->getTrueBBCount(), CBI->getFalseBBCount());
     CBI->eraseFromParent();
     return;
   }
@@ -447,10 +455,12 @@
     assert(OldDest == CBI->getSuccessBB() || OldDest == CBI->getFailureBB() && "Invalid edge index");
     auto SuccessBB = OldDest == CBI->getSuccessBB() ? NewDest : CBI->getSuccessBB();
     auto FailureBB = OldDest == CBI->getFailureBB() ? NewDest : CBI->getFailureBB();
+    auto TrueCount = CBI->getTrueBBCount();
+    auto FalseCount = CBI->getFalseBBCount();
     B.createCheckedCastAddrBranch(CBI->getLoc(), CBI->getConsumptionKind(),
-        CBI->getSrc(), CBI->getSourceType(),
-        CBI->getDest(), CBI->getTargetType(),
-        SuccessBB, FailureBB);
+                                  CBI->getSrc(), CBI->getSourceType(),
+                                  CBI->getDest(), CBI->getTargetType(),
+                                  SuccessBB, FailureBB, TrueCount, FalseCount);
     CBI->eraseFromParent();
     return;
   }
diff --git a/lib/SILOptimizer/Utils/Devirtualize.cpp b/lib/SILOptimizer/Utils/Devirtualize.cpp
index 0af9509..b5f3410 100644
--- a/lib/SILOptimizer/Utils/Devirtualize.cpp
+++ b/lib/SILOptimizer/Utils/Devirtualize.cpp
@@ -329,8 +329,8 @@
         continue;
       }
       // Look through strong_pin instructions.
-      if (isa<StrongPinInst>(V)) {
-        WorkList.push_back(cast<SILInstruction>(V)->getOperand(0));
+      if (auto pin = dyn_cast<StrongPinInst>(V)) {
+        WorkList.push_back(pin->getOperand());
         continue;
       }
     }
@@ -621,9 +621,10 @@
   SmallVector<Operand *, 4> OriginalResultUses;
 
   if (!isa<TryApplyInst>(AI)) {
-    NewAI = B.createApply(AI.getLoc(), FRI, Subs, NewArgs,
-                          cast<ApplyInst>(AI)->isNonThrowing());
-    ResultValue = NewAI.getInstruction();
+    auto apply = B.createApply(AI.getLoc(), FRI, Subs, NewArgs,
+                               cast<ApplyInst>(AI)->isNonThrowing());
+    NewAI = apply;
+    ResultValue = apply;
   } else {
     auto *TAI = cast<TryApplyInst>(AI);
     // Create new normal and error BBs only if:
@@ -693,7 +694,6 @@
         Use->set(ResultValue);
       }
     }
-    return std::make_pair(NewAI.getInstruction(), NewAI);
   }
 
   // We need to return a pair of values here:
@@ -890,7 +890,7 @@
     // Check if any casting is required for the return value.
     ResultValue = castValueToABICompatibleType(&Builder, Loc, NewAI,
                                                NewAI->getType(), AI.getType());
-    SAI = ApplySite::isa(NewAI);
+    SAI = NewAI;
   }
   if (auto *TAI = dyn_cast<TryApplyInst>(AI))
     SAI = Builder.createTryApply(Loc, FRI, NewSubs, Arguments,
@@ -905,7 +905,7 @@
     // Check if any casting is required for the return value.
     ResultValue = castValueToABICompatibleType(
         &Builder, Loc, NewPAI, NewPAI->getType(), PAI->getType());
-    SAI = ApplySite::isa(NewPAI);
+    SAI = NewPAI;
   }
 
   NumWitnessDevirt++;
diff --git a/lib/SILOptimizer/Utils/FunctionSignatureOptUtils.cpp b/lib/SILOptimizer/Utils/FunctionSignatureOptUtils.cpp
index e088889..d6b8661 100644
--- a/lib/SILOptimizer/Utils/FunctionSignatureOptUtils.cpp
+++ b/lib/SILOptimizer/Utils/FunctionSignatureOptUtils.cpp
@@ -49,8 +49,10 @@
       return true;
 
     // Otherwise add all non-debug uses of I to the worklist.
-    for (Operand *I : getNonDebugUses(SILValue(U)))
-      Worklist.push_back(I->getUser());
+    for (auto result : U->getResults()) {
+      for (Operand *I : getNonDebugUses(result))
+        Worklist.push_back(I->getUser());
+    }
   }
   return false;
 }
diff --git a/lib/SILOptimizer/Utils/GenericCloner.cpp b/lib/SILOptimizer/Utils/GenericCloner.cpp
index ca214a7..1b825bc 100644
--- a/lib/SILOptimizer/Utils/GenericCloner.cpp
+++ b/lib/SILOptimizer/Utils/GenericCloner.cpp
@@ -41,8 +41,8 @@
   SILFunction *NewF = Orig->getModule().createFunction(
       getSpecializedLinkage(Orig, Orig->getLinkage()), NewName,
       ReInfo.getSpecializedType(), ReInfo.getSpecializedGenericEnvironment(),
-      Orig->getLocation(), Orig->isBare(), Orig->isTransparent(),
-      Serialized, Orig->isThunk(), Orig->getClassSubclassScope(),
+      Orig->getLocation(), Orig->isBare(), Orig->isTransparent(), Serialized,
+      Orig->getEntryCount(), Orig->isThunk(), Orig->getClassSubclassScope(),
       Orig->getInlineStrategy(), Orig->getEffectsKind(), Orig,
       Orig->getDebugScope());
   for (auto &Attr : Orig->getSemanticsAttrs()) {
diff --git a/lib/SILOptimizer/Utils/Generics.cpp b/lib/SILOptimizer/Utils/Generics.cpp
index 1bf8554..d3a2592 100644
--- a/lib/SILOptimizer/Utils/Generics.cpp
+++ b/lib/SILOptimizer/Utils/Generics.cpp
@@ -2078,9 +2078,9 @@
 } // anonymous namespace
 
 SILFunction *ReabstractionThunkGenerator::createThunk() {
-  SILFunction *Thunk =
-      M.getOrCreateSharedFunction(Loc, ThunkName, ReInfo.getSubstitutedType(),
-                                  IsBare, IsTransparent, Serialized, IsThunk);
+  SILFunction *Thunk = M.getOrCreateSharedFunction(
+      Loc, ThunkName, ReInfo.getSubstitutedType(), IsBare, IsTransparent,
+      Serialized, ProfileCounter(), IsThunk);
   // Re-use an existing thunk.
   if (!Thunk->empty())
     return Thunk;
@@ -2300,7 +2300,7 @@
         continue;
 
       auto FAS = FullApplySite::isa(User);
-      if (FAS && FAS.getCallee() == Apply.getInstruction())
+      if (FAS && FAS.getCallee() == PAI)
         continue;
 
       auto *PAIUser = dyn_cast<PartialApplyInst>(User);
diff --git a/lib/SILOptimizer/Utils/LoadStoreOptUtils.cpp b/lib/SILOptimizer/Utils/LoadStoreOptUtils.cpp
index b8775da..4c26167 100644
--- a/lib/SILOptimizer/Utils/LoadStoreOptUtils.cpp
+++ b/lib/SILOptimizer/Utils/LoadStoreOptUtils.cpp
@@ -114,7 +114,7 @@
   Builder.setCurrentDebugScope(InsertPt->getFunction()->getDebugScope());
   
   // We use an auto-generated SILLocation for now.
-  NullablePtr<swift::SILInstruction> AI =
+  NullablePtr<swift::SingleValueInstruction> AI =
       Projection::createAggFromFirstLevelProjections(
           Builder, RegularLocation::getAutoGeneratedLocation(),
           Base.getType(M).getObjectType(),
diff --git a/lib/SILOptimizer/Utils/Local.cpp b/lib/SILOptimizer/Utils/Local.cpp
index fdcb153..00e2707 100644
--- a/lib/SILOptimizer/Utils/Local.cpp
+++ b/lib/SILOptimizer/Utils/Local.cpp
@@ -87,11 +87,11 @@
 swift::isInstructionTriviallyDead(SILInstruction *I) {
   // At Onone, consider all uses, including the debug_info.
   // This way, debug_info is preserved at Onone.
-  if (!I->use_empty() &&
+  if (I->hasUsesOfAnyResult() &&
       I->getModule().getOptions().Optimization <= SILOptions::SILOptMode::None)
     return false;
 
-  if (!onlyHaveDebugUses(I) || isa<TermInst>(I))
+  if (!onlyHaveDebugUsesOfAllResults(I) || isa<TermInst>(I))
     return false;
 
   if (auto *BI = dyn_cast<BuiltinInst>(I)) {
@@ -192,7 +192,7 @@
 
         // If the operand is an instruction that is only used by the instruction
         // being deleted, delete it.
-        if (auto *OpValInst = dyn_cast<SILInstruction>(OpVal))
+        if (auto *OpValInst = OpVal->getDefiningInstruction())
           if (!DeadInsts.count(OpValInst) &&
               isInstructionTriviallyDead(OpValInst))
             NextInsts.insert(OpValInst);
@@ -232,29 +232,32 @@
 
 void swift::eraseUsesOfInstruction(SILInstruction *Inst,
                                    CallbackTy Callback) {
-  while (!Inst->use_empty()) {
-    auto UI = Inst->use_begin();
-    auto *User = UI->getUser();
-    assert(User && "User should never be NULL!");
+  for (auto result : Inst->getResults()) {
+    while (!result->use_empty()) {
+      auto UI = result->use_begin();
+      auto *User = UI->getUser();
+      assert(User && "User should never be NULL!");
 
-    // If the instruction itself has any uses, recursively zap them so that
-    // nothing uses this instruction.
-    eraseUsesOfInstruction(User, Callback);
+      // If the instruction itself has any uses, recursively zap them so that
+      // nothing uses this instruction.
+      eraseUsesOfInstruction(User, Callback);
 
-    // Walk through the operand list and delete any random instructions that
-    // will become trivially dead when this instruction is removed.
+      // Walk through the operand list and delete any random instructions that
+      // will become trivially dead when this instruction is removed.
 
-    for (auto &Op : User->getAllOperands()) {
-      if (auto *OpI = dyn_cast<SILInstruction>(Op.get())) {
-        // Don't recursively delete the pointer we're getting in.
-        if (OpI != Inst) {
-          Op.drop();
-          recursivelyDeleteTriviallyDeadInstructions(OpI, false, Callback);
+      for (auto &Op : User->getAllOperands()) {
+        if (auto *OpI = Op.get()->getDefiningInstruction()) {
+          // Don't recursively delete the instruction we're working on.
+          // FIXME: what if we're being recursively invoked?
+          if (OpI != Inst) {
+            Op.drop();
+            recursivelyDeleteTriviallyDeadInstructions(OpI, false, Callback);
+          }
         }
       }
+      Callback(User);
+      User->eraseFromParent();
     }
-    Callback(User);
-    User->eraseFromParent();
   }
 }
 
@@ -267,7 +270,8 @@
       continue;
 
     // Collect the users of this instruction.
-    collectUsesOfValue(User, Insts);
+    for (auto result : User->getResults())
+      collectUsesOfValue(result, Insts);
   }
 }
 
@@ -280,7 +284,7 @@
   // Its not safe to do recursively delete here as some of the SILInstruction
   // maybe tracked by this set.
   for (auto I : Insts) {
-    I->replaceAllUsesWithUndef();
+    I->replaceAllUsesOfAllResultsWithUndef();
     I->eraseFromParent();
   }
 }
@@ -288,19 +292,13 @@
 // Devirtualization of functions with covariant return types produces
 // a result that is not an apply, but takes an apply as an
 // argument. Attempt to dig the apply out from this result.
-FullApplySite swift::findApplyFromDevirtualizedResult(SILInstruction *I) {
-  if (!I)
-    return FullApplySite();
-
-  if (auto Apply = FullApplySite::isa(I))
+FullApplySite swift::findApplyFromDevirtualizedResult(SILValue V) {
+  if (auto Apply = FullApplySite::isa(V))
     return Apply;
 
-  if (!I->getNumOperands())
-    return FullApplySite();
-
-  if (isa<UpcastInst>(I) || isa<EnumInst>(I) || isa<UncheckedRefCastInst>(I))
+  if (isa<UpcastInst>(V) || isa<EnumInst>(V) || isa<UncheckedRefCastInst>(V))
     return findApplyFromDevirtualizedResult(
-        dyn_cast<SILInstruction>(I->getOperand(0)));
+             cast<SingleValueInstruction>(V)->getOperand(0));
 
   return FullApplySite();
 }
@@ -332,7 +330,7 @@
 void swift::replaceDeadApply(ApplySite Old, ValueBase *New) {
   auto *OldApply = Old.getInstruction();
   if (!isa<TryApplyInst>(OldApply))
-    OldApply->replaceAllUsesWith(New);
+    cast<SingleValueInstruction>(OldApply)->replaceAllUsesWith(New);
   recursivelyDeleteTriviallyDeadInstructions(OldApply, true);
 }
 
@@ -399,9 +397,7 @@
       assert(FalseArgs.size() == Dest->getNumArguments());
     }
 
-    return Builder.createCondBranch(CBI->getLoc(), CBI->getCondition(),
-                                    CBI->getTrueBB(), TrueArgs,
-                                    CBI->getFalseBB(), FalseArgs);
+    return Builder.createCondBranch(CBI->getLoc(), CBI->getCondition(), CBI->getTrueBB(), TrueArgs, CBI->getFalseBB(), FalseArgs, CBI->getTrueBBCount(), CBI->getFalseBBCount());
   }
 
   if (auto *BI = dyn_cast<BranchInst>(Branch)) {
@@ -444,7 +440,7 @@
     auto *Inst = &BB->back();
 
     // Replace any still-remaining uses with undef values and erase.
-    Inst->replaceAllUsesWithUndef();
+    Inst->replaceAllUsesOfAllResultsWithUndef();
     Inst->eraseFromParent();
   }
 }
@@ -673,7 +669,7 @@
   /// concatenation of string literals.
   ///
   /// Returns a new instruction if optimization was possible.
-  SILInstruction *optimize();
+  SingleValueInstruction *optimize();
 };
 
 } // end anonymous namespace
@@ -834,7 +830,7 @@
   return IsAsciiLeft && IsAsciiRight;
 }
 
-SILInstruction *StringConcatenationOptimizer::optimize() {
+SingleValueInstruction *StringConcatenationOptimizer::optimize() {
   // Bail out if string literals concatenation optimization is
   // not possible.
   if (!extractStringConcatOperands())
@@ -880,7 +876,8 @@
 }
 
 /// Top level entry point
-SILInstruction *swift::tryToConcatenateStrings(ApplyInst *AI, SILBuilder &B) {
+SingleValueInstruction *
+swift::tryToConcatenateStrings(ApplyInst *AI, SILBuilder &B) {
   return StringConcatenationOptimizer(AI, B).optimize();
 }
 
@@ -890,13 +887,13 @@
 
 static bool useDoesNotKeepClosureAlive(const SILInstruction *I) {
   switch (I->getKind()) {
-  case ValueKind::StrongRetainInst:
-  case ValueKind::StrongReleaseInst:
-  case ValueKind::CopyValueInst:
-  case ValueKind::DestroyValueInst:
-  case ValueKind::RetainValueInst:
-  case ValueKind::ReleaseValueInst:
-  case ValueKind::DebugValueInst:
+  case SILInstructionKind::StrongRetainInst:
+  case SILInstructionKind::StrongReleaseInst:
+  case SILInstructionKind::CopyValueInst:
+  case SILInstructionKind::DestroyValueInst:
+  case SILInstructionKind::RetainValueInst:
+  case SILInstructionKind::ReleaseValueInst:
+  case SILInstructionKind::DebugValueInst:
     return true;
   default:
     return false;
@@ -1078,7 +1075,7 @@
 }
 
 /// TODO: Generalize this to general objects.
-bool swift::tryDeleteDeadClosure(SILInstruction *Closure,
+bool swift::tryDeleteDeadClosure(SingleValueInstruction *Closure,
                                  InstModCallbacks Callbacks) {
   // We currently only handle locally identified values that do not escape. We
   // also assume that the partial apply does not capture any addresses.
@@ -1108,9 +1105,10 @@
 
   // Then delete all user instructions.
   for (auto *User : Tracker.getTrackedUsers()) {
-    assert(!User->hasValue() && "We expect only ARC operations without "
-                                "results. This is true b/c of "
-                                "isARCOperationRemovableIfObjectIsDead");
+    assert(User->getResults().empty()
+           && "We expect only ARC operations without "
+              "results. This is true b/c of "
+              "isARCOperationRemovableIfObjectIsDead");
     Callbacks.DeleteInst(User);
   }
 
@@ -1452,9 +1450,10 @@
       Builder.setInsertionPoint(CastSuccessBB);
       SrcOp = CastSuccessBB->getArgument(0);
     } else {
-      NewI = Builder.createUnconditionalCheckedCast(Loc, Load,
-                                                    SILBridgedTy);
-      SrcOp = NewI;
+      auto cast = Builder.createUnconditionalCheckedCast(Loc, Load,
+                                                         SILBridgedTy);
+      NewI = cast;
+      SrcOp = cast;
     }
   } else {
     SrcOp = Src;
@@ -1745,8 +1744,8 @@
              && "unsupported convention for bridging conversion");
       // Need to make a copy of the source, can be changed in ObjC
       auto BridgeStack = Builder.createAllocStack(Loc, Src->getType());
-      Src = Builder.createCopyAddr(Loc, Src, BridgeStack, IsNotTake,
-                                   IsInitialization);
+      Builder.createCopyAddr(Loc, Src, BridgeStack, IsNotTake,
+                             IsInitialization);
       break;
     }
     case ParameterConvention::Indirect_Inout:
@@ -1778,15 +1777,16 @@
     auto ConvTy = NewAI->getType();
     auto DestTy = Dest->getType().getObjectType();
     SILValue CastedValue;
-    if ((ConvTy == DestTy || DestTy.isExactSuperclassOf(ConvTy))) {
-      CastedValue = SILValue(
-          (ConvTy == DestTy) ? NewI : Builder.createUpcast(Loc, NewAI, DestTy));
+    if (ConvTy == DestTy) {
+      CastedValue = NewAI;
+    } else if (DestTy.isExactSuperclassOf(ConvTy)) {
+      CastedValue = Builder.createUpcast(Loc, NewAI, DestTy);
     } else if (ConvTy.isExactSuperclassOf(DestTy)) {
       // The downcast from a base class to derived class may fail.
       if (isConditional) {
         // In case of a conditional cast, we should handle it gracefully.
         auto CondBrSuccessBB =
-            NewAI->getFunction()->createBasicBlock(NewAI->getParentBlock());
+            NewAI->getFunction()->createBasicBlock(NewAI->getParent());
         CondBrSuccessBB->createPHIArgument(DestTy, ValueOwnershipKind::Owned,
                                            nullptr);
         Builder.createCheckedCastBranch(Loc, /* isExact*/ false, NewAI, DestTy,
@@ -1813,7 +1813,7 @@
     }
     NewI = Builder.createStore(Loc, CastedValue, Dest,
                                StoreOwnershipQualifier::Unqualified);
-    if (isConditional && NewI->getParentBlock() != NewAI->getParentBlock()) {
+    if (isConditional && NewI->getParent() != NewAI->getParent()) {
       Builder.createBranch(Loc, SuccessBB);
     }
   }
@@ -2106,7 +2106,6 @@
         Src, Dest, SourceType, TargetType, nullptr, nullptr);
 
     if (BridgedI) {
-      CastedValue = BridgedI;
       llvm_unreachable(
         "Bridged casts cannot be expressed by checked_cast_br yet");
     } else {
@@ -2195,7 +2194,6 @@
         Src, Dest, SourceType, TargetType, nullptr, nullptr);
 
     if (BridgedI) {
-      CastedValue = BridgedI;
       llvm_unreachable(
           "Bridged casts cannot be expressed by checked_cast_value_br yet");
     } else {
@@ -2294,8 +2292,9 @@
                 Inst->getTargetType())) {
           SILBuilderWithScope B(Inst);
           auto NewI = B.createCheckedCastBranch(
-              Loc, false /*isExact*/, MI,
-              Dest->getType().getObjectType(), SuccessBB, FailureBB);
+              Loc, false /*isExact*/, MI, Dest->getType().getObjectType(),
+              SuccessBB, FailureBB, Inst->getTrueBBCount(),
+              Inst->getFalseBBCount());
           SuccessBB->createPHIArgument(Dest->getType().getObjectType(),
                                        ValueOwnershipKind::Owned);
           B.setInsertionPoint(SuccessBB->begin());
@@ -2341,10 +2340,9 @@
   if (auto *IEMI = dyn_cast<InitExistentialMetatypeInst>(Op)) {
     if (auto *MI = dyn_cast<MetatypeInst>(IEMI->getOperand())) {
       SILBuilderWithScope B(Inst);
-      auto *NewI = B.createCheckedCastBranch(Loc, /* isExact */ false, MI,
-                                LoweredTargetType,
-                                SuccessBB,
-                                FailureBB);
+      auto *NewI = B.createCheckedCastBranch(
+          Loc, /* isExact */ false, MI, LoweredTargetType, SuccessBB, FailureBB,
+          Inst->getTrueBBCount(), Inst->getFalseBBCount());
       EraseInstAction(Inst);
       return NewI;
     }
@@ -2410,10 +2408,9 @@
             FoundIEI->getTypeDependentOperands());
         auto *MI = B.createMetatype(FoundIEI->getLoc(), SILMetaTy);
 
-        auto *NewI = B.createCheckedCastBranch(Loc, /* isExact */ false, MI,
-                                  LoweredTargetType,
-                                  SuccessBB,
-                                  FailureBB);
+        auto *NewI = B.createCheckedCastBranch(
+            Loc, /* isExact */ false, MI, LoweredTargetType, SuccessBB,
+            FailureBB, Inst->getTrueBBCount(), Inst->getFalseBBCount());
         EraseInstAction(Inst);
         return NewI;
       }
@@ -2470,10 +2467,9 @@
             FoundIERI->getTypeDependentOperands());
         auto *MI = B.createMetatype(FoundIERI->getLoc(), SILMetaTy);
 
-        auto *NewI = B.createCheckedCastBranch(Loc, /* isExact */ false, MI,
-                                  LoweredTargetType,
-                                  SuccessBB,
-                                  FailureBB);
+        auto *NewI = B.createCheckedCastBranch(
+            Loc, /* isExact */ false, MI, LoweredTargetType, SuccessBB,
+            FailureBB, Inst->getTrueBBCount(), Inst->getFalseBBCount());
         EraseInstAction(Inst);
         return NewI;
       }
@@ -2538,10 +2534,12 @@
                                    false, Src, SILValue(), SourceType,
                                    TargetType, nullptr, nullptr);
   if (NewI) {
-    ReplaceInstUsesAction(Inst, NewI);
+    // FIXME: I'm not sure why this is true!
+    auto newValue = cast<SingleValueInstruction>(NewI);
+    ReplaceInstUsesAction(Inst, newValue);
     EraseInstAction(Inst);
     WillSucceedAction();
-    return NewI;
+    return newValue;
   }
 
   // If the cast may succeed or fail and can't be optimized into a bridging
@@ -2571,8 +2569,6 @@
   EraseInstAction(Inst);
   WillSucceedAction();
   return Result;
-
-  return nullptr;
 }
 
 /// Deletes all instructions after \p UnreachableInst except dealloc_stack
@@ -2590,7 +2586,7 @@
         DeallocStack->moveBefore(TrapInst);
         continue;
       }
-    CurInst->replaceAllUsesWithUndef();
+    CurInst->replaceAllUsesOfAllResultsWithUndef();
     EraseInstAction(CurInst);
   }
 }
@@ -2679,7 +2675,6 @@
         }
         };
 
-        Inst->replaceAllUsesWithUndef();
         return true;
       }
     }
@@ -2725,7 +2720,6 @@
                           StoreOwnershipQualifier::Unqualified);
     }
     auto *TrapI = Builder.createBuiltinTrap(Loc);
-    Inst->replaceAllUsesWithUndef();
     EraseInstAction(Inst);
     Builder.setInsertionPoint(std::next(SILBasicBlock::iterator(TrapI)));
     auto *UnreachableInst =
@@ -2802,7 +2796,6 @@
       return nullptr;
     }
 
-    Inst->replaceAllUsesWithUndef();
     EraseInstAction(Inst);
     WillSucceedAction();
   }
@@ -2810,21 +2803,22 @@
   return nullptr;
 }
 
-bool swift::simplifyUsers(SILInstruction *I) {
+bool swift::simplifyUsers(SingleValueInstruction *I) {
   bool Changed = false;
 
   for (auto UI = I->use_begin(), UE = I->use_end(); UI != UE; ) {
     SILInstruction *User = UI->getUser();
     ++UI;
 
-    if (!User->hasValue())
-      continue;
-    SILValue S = simplifyInstruction(User);
+    auto SVI = dyn_cast<SingleValueInstruction>(User);
+    if (!SVI) continue;
+
+    SILValue S = simplifyInstruction(SVI);
     if (!S)
       continue;
 
-    User->replaceAllUsesWith(S);
-    User->eraseFromParent();
+    SVI->replaceAllUsesWith(S);
+    SVI->eraseFromParent();
     Changed = true;
   }
 
@@ -2874,57 +2868,50 @@
 bool
 swift::analyzeStaticInitializer(SILValue V,
                                 SmallVectorImpl<SILInstruction *> &Insns) {
-  auto I = dyn_cast<SILInstruction>(V);
-  if (!I)
-    return false;
+  // Save every instruction we see.
+  // TODO: MultiValueInstruction?
+  if (auto I = dyn_cast<SingleValueInstruction>(V))
+    Insns.push_back(I);
 
-  while (true) {
-    if (!isa<AllocGlobalInst>(I))
-      Insns.push_back(I);
-    if (auto *SI = dyn_cast<StructInst>(I)) {
-      // If it is not a struct which is a simple type, bail.
-      if (!isSimpleType(SI->getType(), I->getModule()))
+  if (auto *SI = dyn_cast<StructInst>(V)) {
+    // If it is not a struct which is a simple type, bail.
+    if (!isSimpleType(SI->getType(), SI->getModule()))
+      return false;
+    for (auto &Op: SI->getAllOperands()) {
+      // If one of the struct instruction operands is not
+      // a simple initializer, bail.
+      if (!analyzeStaticInitializer(Op.get(), Insns))
         return false;
-      for (auto &Op: SI->getAllOperands()) {
-        // If one of the struct instruction operands is not
-        // a simple initializer, bail.
-        if (!analyzeStaticInitializer(Op.get(), Insns))
-          return false;
-      }
-      return true;
-    } if (auto *TI = dyn_cast<TupleInst>(I)) {
-      // If it is not a tuple which is a simple type, bail.
-      if (!isSimpleType(TI->getType(), I->getModule()))
+    }
+    return true;
+  } else if (auto *TI = dyn_cast<TupleInst>(V)) {
+    // If it is not a tuple which is a simple type, bail.
+    if (!isSimpleType(TI->getType(), TI->getModule()))
+      return false;
+    for (auto &Op: TI->getAllOperands()) {
+      // If one of the struct instruction operands is not
+      // a simple initializer, bail.
+      if (!analyzeStaticInitializer(Op.get(), Insns))
         return false;
-      for (auto &Op: TI->getAllOperands()) {
-        // If one of the struct instruction operands is not
-        // a simple initializer, bail.
-        if (!analyzeStaticInitializer(Op.get(), Insns))
-          return false;
+    }
+    return true;
+  } else if (auto *bi = dyn_cast<BuiltinInst>(V)) {
+    switch (bi->getBuiltinInfo().ID) {
+    case BuiltinValueKind::FPTrunc:
+      if (auto *LI = dyn_cast<LiteralInst>(bi->getArguments()[0])) {
+        return analyzeStaticInitializer(LI, Insns);
       }
-      return true;
-    } else {
-      if (auto *bi = dyn_cast<BuiltinInst>(I)) {
-        switch (bi->getBuiltinInfo().ID) {
-        case BuiltinValueKind::FPTrunc:
-          if (auto *LI = dyn_cast<LiteralInst>(bi->getArguments()[0])) {
-            I = LI;
-            continue;
-          }
-          break;
-        default:
-          return false;
-        }
-      }
-
-      if (I->getKind() == ValueKind::IntegerLiteralInst
-          || I->getKind() == ValueKind::FloatLiteralInst
-          || I->getKind() == ValueKind::StringLiteralInst)
-        return true;
+      return false;
+    default:
       return false;
     }
+  } else if (isa<IntegerLiteralInst>(V)
+             || isa<FloatLiteralInst>(V)
+             || isa<StringLiteralInst>(V)) {
+    return true;
+  } else {
+    return false;
   }
-  return false;
 }
 
 /// Replace load sequence which may contain
@@ -2933,7 +2920,7 @@
 /// starting with the innermost struct_element_addr
 /// Move into utils.
 void swift::replaceLoadSequence(SILInstruction *I,
-                                SILInstruction *Value,
+                                SILValue Value,
                                 SILBuilder &B) {
   if (auto *LI = dyn_cast<LoadInst>(I)) {
     LI->replaceAllUsesWith(Value);
@@ -3038,7 +3025,7 @@
       case ValueKind::RefElementAddrInst:
       case ValueKind::RefTailAddrInst:
       case ValueKind::UncheckedTakeEnumDataAddrInst: {
-        auto *Inst = cast<SILInstruction>(V);
+        auto *Inst = cast<SingleValueInstruction>(V);
         // We are done once the current projection dominates the insert point.
         if (DomTree->dominates(Inst->getParent(), InsertBefore->getParent()))
           return;
diff --git a/lib/SILOptimizer/Utils/OptimizerStatsUtils.cpp b/lib/SILOptimizer/Utils/OptimizerStatsUtils.cpp
index bce9658..c702246 100644
--- a/lib/SILOptimizer/Utils/OptimizerStatsUtils.cpp
+++ b/lib/SILOptimizer/Utils/OptimizerStatsUtils.cpp
@@ -79,51 +79,79 @@
 namespace {
 
 /// The total number of different kinds of SILInstructions.
-constexpr unsigned SILInstructionsNum = int(ValueKind::Last_SILInstruction) + 1;
+constexpr unsigned NumSILInstructions =
+    unsigned(SILNodeKind::Last_SILInstruction)
+  - unsigned(SILNodeKind::First_SILInstruction)
+  + 1;
+
+static unsigned getIndexForKind(SILInstructionKind kind) {
+  return unsigned(kind) - unsigned(SILNodeKind::First_SILInstruction);
+}
 
 /// A set of counters, one per SILInstruction kind.
-using InstructionCounts = SmallVector<int, SILInstructionsNum>;
+class InstructionCounts {
+  unsigned Counts[NumSILInstructions] = {};
+
+public:
+  constexpr InstructionCounts() {}
+
+  unsigned &operator[](SILInstructionKind kind) {
+    return Counts[getIndexForKind(kind)];
+  }
+
+  void addAll(const InstructionCounts &other) {
+    for (unsigned i = 0; i != NumSILInstructions; ++i) {
+      Counts[i] += other.Counts[i];
+    }
+  }
+
+  void subAll(const InstructionCounts &other) {
+    for (unsigned i = 0; i != NumSILInstructions; ++i) {
+      Counts[i] -= other.Counts[i];
+    }
+  }
+};
 
 /// A helper type to parse a comma separated list of SIL instruction names
 /// provided as argument of the -sil-stats-only-instructions options.
 class StatsOnlyInstructionsOpt {
-  /// If ComputeInstCounts[i] is non-zero, this kind of SILInstruction should be
-  /// tracked.
-  InstructionCounts ComputeInstCounts;
+  bool ShouldComputeInstCounts[NumSILInstructions] = {};
+
   /// The number of different kinds of SILInstructions to be tracked.
-  int InstCountsNum = 0;
+  unsigned NumInstCounts = 0;
 
 public:
-  StatsOnlyInstructionsOpt() : ComputeInstCounts(SILInstructionsNum) {}
+  constexpr StatsOnlyInstructionsOpt() {}
 
-  void operator=(const std::string &Val) {
-    if (Val.empty())
+  void operator=(StringRef val) {
+    if (val.empty())
       return;
-    if (Val == "all") {
-      for (auto &Inst : ComputeInstCounts) {
-        Inst = 1;
+    if (val == "all") {
+      for (auto &inst : ShouldComputeInstCounts) {
+        inst = true;
       }
-      InstCountsNum = ComputeInstCounts.size();
+      NumInstCounts = NumSILInstructions;
       return;
     }
     SmallVector<StringRef, 8> statsInstNames;
-    StringRef(Val).split(statsInstNames, ',', -1, false);
+    val.split(statsInstNames, ',', -1, false);
     for (auto instName : statsInstNames) {
       // Check if it is a known instruction.
-      auto Kind = getSILInstructionKind(instName);
-      if (!ComputeInstCounts[int(Kind)] ){
-          ComputeInstCounts[int(Kind)] = 1;
-          InstCountsNum++;
+      auto kind = getSILInstructionKind(instName);
+      unsigned index = getIndexForKind(kind);
+      if (!ShouldComputeInstCounts[index]) {
+        ShouldComputeInstCounts[index] = true;
+        NumInstCounts++;
       }
     }
   }
 
-  bool shouldComputeInstCount(SILInstructionKind Kind) const {
-    return ComputeInstCounts[int(Kind)] != 0;
+  bool shouldComputeInstCount(SILInstructionKind kind) const {
+    return ShouldComputeInstCounts[getIndexForKind(kind)];
   }
 
   int getInstCountsNum() const {
-    return InstCountsNum;
+    return NumInstCounts;
   }
 };
 
@@ -245,7 +273,7 @@
   InstructionCounts InstCounts;
 
   FunctionStat(SILFunction *F);
-  FunctionStat() : InstCounts(SILInstructionsNum) {}
+  FunctionStat() {}
 
   void print(llvm::raw_ostream &stream) const {
     stream << "FunctionStat("
@@ -280,7 +308,7 @@
   /// Instruction counts per SILInstruction kind.
   InstructionCounts InstCounts;
 
-  ModuleStat() : InstCounts(SILInstructionsNum) {}
+  ModuleStat() {}
 
   /// Add the stats for a given function to the total module stats.
   void addFunctionStat(FunctionStat &Stat) {
@@ -289,9 +317,7 @@
     ++FunctionCount;
     if (!StatsOnlyInstructionsOptLoc.getInstCountsNum())
       return;
-    for (unsigned i : indices(InstCounts)) {
-      InstCounts[i] += Stat.InstCounts[i];
-    }
+    InstCounts.addAll(Stat.InstCounts);
   }
 
   /// Subtract the stats for a given function from total module stats.
@@ -301,9 +327,7 @@
     --FunctionCount;
     if (!StatsOnlyInstructionsOptLoc.getInstCountsNum())
       return;
-    for (unsigned i : indices(InstCounts)) {
-      InstCounts[i] -= Stat.InstCounts[i];
-    }
+    InstCounts.subAll(Stat.InstCounts);
   }
 
   /// Add the stats about current memory usage.
@@ -338,7 +362,7 @@
 
 // A helper type to collect the stats about the number of instructions and basic
 // blocks.
-struct InstCountVisitor : SILVisitor<InstCountVisitor> {
+struct InstCountVisitor : SILInstructionVisitor<InstCountVisitor> {
   int BlockCount = 0;
   int InstCount = 0;
   InstructionCounts &InstCounts;
@@ -355,21 +379,13 @@
 
   void visitSILBasicBlock(SILBasicBlock *BB) {
     ++BlockCount;
-    SILVisitor<InstCountVisitor>::visitSILBasicBlock(BB);
+    SILInstructionVisitor<InstCountVisitor>::visitSILBasicBlock(BB);
   }
 
-  void visitSILFunction(SILFunction *F) {
-    SILVisitor<InstCountVisitor>::visitSILFunction(F);
+  void visit(SILInstruction *I) {
+    ++InstCount;
+    ++InstCounts[I->getKind()];
   }
-
-  void visitValueBase(ValueBase *V) {}
-
-#define INST(Id, Parent, TextualName, MemBehavior, ReleasingBehavior)          \
-  void visit##Id(Id *I) {                                                      \
-    ++InstCount;                                                               \
-    ++InstCounts[int(I->getKind())];                                           \
-  }
-#include "swift/SIL/SILNodes.def"
 };
 
 /// A helper type to store different parameters related to the current transform.
@@ -673,15 +689,14 @@
   if (!StatsOnlyInstructionsOptLoc.getInstCountsNum())
     return;
 
-  for (int i = 0, e = SILInstructionsNum; i < e; ++i) {
-    if (!Stat.InstCounts[i])
+  for (auto kind : allSILInstructionKinds()) {
+    if (!Stat.InstCounts[kind])
       continue;
-    SILInstructionKind Kind = SILInstructionKind(i);
-    if (!StatsOnlyInstructionsOptLoc.shouldComputeInstCount(Kind))
+    if (!StatsOnlyInstructionsOptLoc.shouldComputeInstCount(kind))
       continue;
     std::string CounterName = "inst_";
-    CounterName += getSILInstructionName(Kind);
-    printCounterValue("function_history", CounterName, Stat.InstCounts[i],
+    CounterName += getSILInstructionName(kind);
+    printCounterValue("function_history", CounterName, Stat.InstCounts[kind],
                       F->getName(), Ctx);
   }
 }
@@ -822,19 +837,18 @@
   if (!StatsOnlyInstructionsOptLoc.getInstCountsNum())
     return;
 
-  for (int i = 0, e = SILInstructionsNum; i < e; ++i) {
+  for (auto kind : allSILInstructionKinds()) {
     // Do not print anything, if there is no change.
-    if (OldStat.InstCounts[i] == NewStat.InstCounts[i])
+    if (OldStat.InstCounts[kind] == NewStat.InstCounts[kind])
       continue;
-    SILInstructionKind Kind = SILInstructionKind(i);
-    if (!StatsOnlyInstructionsOptLoc.shouldComputeInstCount(Kind))
+    if (!StatsOnlyInstructionsOptLoc.shouldComputeInstCount(kind))
       continue;
     SmallString<64> CounterName("inst_");
-    CounterName += getSILInstructionName(Kind);
+    CounterName += getSILInstructionName(kind);
     auto DeltaCounterKindCount =
-        computeDelta(OldStat.InstCounts[i], NewStat.InstCounts[i]);
+        computeDelta(OldStat.InstCounts[kind], NewStat.InstCounts[kind]);
     printCounterChange("module", CounterName, DeltaCounterKindCount,
-                       OldStat.InstCounts[i], NewStat.InstCounts[i], Ctx);
+                       OldStat.InstCounts[kind], NewStat.InstCounts[kind], Ctx);
   }
 }
 
@@ -925,7 +939,7 @@
   ModStat = NewModStat;
 }
 
-FunctionStat::FunctionStat(SILFunction *F) : InstCounts(SILInstructionsNum) {
+FunctionStat::FunctionStat(SILFunction *F) {
   InstCountVisitor V(InstCounts);
   V.visitSILFunction(F);
   BlockCount = V.getBlockCount();
diff --git a/lib/SILOptimizer/Utils/PerformanceInlinerUtils.cpp b/lib/SILOptimizer/Utils/PerformanceInlinerUtils.cpp
index bb78605..810f970 100644
--- a/lib/SILOptimizer/Utils/PerformanceInlinerUtils.cpp
+++ b/lib/SILOptimizer/Utils/PerformanceInlinerUtils.cpp
@@ -41,8 +41,7 @@
 SILValue ConstantTracker::scanProjections(SILValue addr,
                                           SmallVectorImpl<Projection> *Result) {
   for (;;) {
-    if (Projection::isAddressProjection(addr)) {
-      SILInstruction *I = cast<SILInstruction>(addr);
+    if (auto *I = Projection::isAddressProjection(addr)) {
       if (Result) {
         Result->push_back(Projection(I));
       }
@@ -110,11 +109,11 @@
 
   // Track the value up the dominator tree.
   for (;;) {
-    if (auto *inst = dyn_cast<SILInstruction>(val)) {
-      if (Projection::isObjectProjection(inst)) {
+    if (auto *inst = dyn_cast<SingleValueInstruction>(val)) {
+      if (auto pi = Projection::isObjectProjection(val)) {
         // Extract a member from a struct/tuple/enum.
-        projStack.push_back(Projection(inst));
-        val = inst->getOperand(0);
+        projStack.push_back(Projection(pi));
+        val = pi->getOperand(0);
         continue;
       } else if (SILValue member = getMember(inst, projStack)) {
         // The opposite of a projection instruction: composing a struct/tuple.
@@ -125,8 +124,8 @@
         // A value loaded from memory.
         val = loadedVal;
         continue;
-      } else if (isa<ThinToThickFunctionInst>(inst)) {
-        val = inst->getOperand(0);
+      } else if (auto ti = dyn_cast<ThinToThickFunctionInst>(inst)) {
+        val = ti->getOperand();
         continue;
       }
       return inst;
diff --git a/lib/SILOptimizer/Utils/SILInliner.cpp b/lib/SILOptimizer/Utils/SILInliner.cpp
index ba5db27..997ba40 100644
--- a/lib/SILOptimizer/Utils/SILInliner.cpp
+++ b/lib/SILOptimizer/Utils/SILInliner.cpp
@@ -98,7 +98,6 @@
   for (auto AI = Args.begin(), AE = Args.end(); AI != AE; ++AI, ++BAI)
     ValueMap.insert(std::make_pair(*BAI, *AI));
 
-  InstructionMap.clear();
   BBMap.clear();
   // Do not allow the entry block to be cloned again
   SILBasicBlock::iterator InsertPoint =
@@ -140,10 +139,11 @@
                            SILFunction::iterator(ReturnToBB));
 
     // Create an argument on the return-to BB representing the returned value.
-    auto *RetArg = ReturnToBB->createPHIArgument(AI.getInstruction()->getType(),
+    auto apply = cast<ApplyInst>(AI.getInstruction());
+    auto *RetArg = ReturnToBB->createPHIArgument(apply->getType(),
                                                  ValueOwnershipKind::Owned);
     // Replace all uses of the ApplyInst with the new argument.
-    AI.getInstruction()->replaceAllUsesWith(RetArg);
+    apply->replaceAllUsesWith(RetArg);
   }
 
   // Now iterate over the callee BBs and fix up the terminators.
@@ -236,235 +236,230 @@
 /// instruction. This is of course very much so not true.
 InlineCost swift::instructionInlineCost(SILInstruction &I) {
   switch (I.getKind()) {
-    case ValueKind::IntegerLiteralInst:
-    case ValueKind::FloatLiteralInst:
-    case ValueKind::DebugValueInst:
-    case ValueKind::DebugValueAddrInst:
-    case ValueKind::StringLiteralInst:
-    case ValueKind::ConstStringLiteralInst:
-    case ValueKind::FixLifetimeInst:
-    case ValueKind::EndBorrowInst:
-    case ValueKind::EndBorrowArgumentInst:
-    case ValueKind::BeginBorrowInst:
-    case ValueKind::MarkDependenceInst:
-    case ValueKind::FunctionRefInst:
-    case ValueKind::AllocGlobalInst:
-    case ValueKind::GlobalAddrInst:
-    case ValueKind::EndLifetimeInst:
-    case ValueKind::UncheckedOwnershipConversionInst:
+  case SILInstructionKind::IntegerLiteralInst:
+  case SILInstructionKind::FloatLiteralInst:
+  case SILInstructionKind::DebugValueInst:
+  case SILInstructionKind::DebugValueAddrInst:
+  case SILInstructionKind::StringLiteralInst:
+  case SILInstructionKind::ConstStringLiteralInst:
+  case SILInstructionKind::FixLifetimeInst:
+  case SILInstructionKind::EndBorrowInst:
+  case SILInstructionKind::EndBorrowArgumentInst:
+  case SILInstructionKind::BeginBorrowInst:
+  case SILInstructionKind::MarkDependenceInst:
+  case SILInstructionKind::FunctionRefInst:
+  case SILInstructionKind::AllocGlobalInst:
+  case SILInstructionKind::GlobalAddrInst:
+  case SILInstructionKind::EndLifetimeInst:
+  case SILInstructionKind::UncheckedOwnershipConversionInst:
+    return InlineCost::Free;
+
+  // Typed GEPs are free.
+  case SILInstructionKind::TupleElementAddrInst:
+  case SILInstructionKind::StructElementAddrInst:
+  case SILInstructionKind::ProjectBlockStorageInst:
+    return InlineCost::Free;
+
+  // Aggregates are exploded at the IR level; these are effectively no-ops.
+  case SILInstructionKind::TupleInst:
+  case SILInstructionKind::StructInst:
+  case SILInstructionKind::StructExtractInst:
+  case SILInstructionKind::TupleExtractInst:
+    return InlineCost::Free;
+
+  // Unchecked casts are free.
+  case SILInstructionKind::AddressToPointerInst:
+  case SILInstructionKind::PointerToAddressInst:
+
+  case SILInstructionKind::UncheckedRefCastInst:
+  case SILInstructionKind::UncheckedRefCastAddrInst:
+  case SILInstructionKind::UncheckedAddrCastInst:
+  case SILInstructionKind::UncheckedTrivialBitCastInst:
+  case SILInstructionKind::UncheckedBitwiseCastInst:
+
+  case SILInstructionKind::RawPointerToRefInst:
+  case SILInstructionKind::RefToRawPointerInst:
+
+  case SILInstructionKind::UpcastInst:
+
+  case SILInstructionKind::ThinToThickFunctionInst:
+  case SILInstructionKind::ThinFunctionToPointerInst:
+  case SILInstructionKind::PointerToThinFunctionInst:
+  case SILInstructionKind::ConvertFunctionInst:
+
+  case SILInstructionKind::BridgeObjectToWordInst:
+    return InlineCost::Free;
+
+  // Access instructions are free unless we're dynamically enforcing them.
+  case SILInstructionKind::BeginAccessInst:
+    return getEnforcementCost(cast<BeginAccessInst>(I).getEnforcement());
+  case SILInstructionKind::EndAccessInst:
+    return getEnforcementCost(cast<EndAccessInst>(I).getBeginAccess()
+                                                   ->getEnforcement());
+  case SILInstructionKind::BeginUnpairedAccessInst:
+    return getEnforcementCost(cast<BeginUnpairedAccessInst>(I)
+                                .getEnforcement());
+  case SILInstructionKind::EndUnpairedAccessInst:
+    return getEnforcementCost(cast<EndUnpairedAccessInst>(I)
+                                .getEnforcement());
+
+  // TODO: These are free if the metatype is for a Swift class.
+  case SILInstructionKind::ThickToObjCMetatypeInst:
+  case SILInstructionKind::ObjCToThickMetatypeInst:
+    return InlineCost::Expensive;
+    
+  // TODO: Bridge object conversions imply a masking operation that should be
+  // "hella cheap" but not really expensive
+  case SILInstructionKind::BridgeObjectToRefInst:
+  case SILInstructionKind::RefToBridgeObjectInst:
+    return InlineCost::Expensive;
+
+  case SILInstructionKind::MetatypeInst:
+    // Thin metatypes are always free.
+    if (cast<MetatypeInst>(I).getType().castTo<MetatypeType>()
+          ->getRepresentation() == MetatypeRepresentation::Thin)
+      return InlineCost::Free;
+    // TODO: Thick metatypes are free if they don't require generic or lazy
+    // instantiation.
+    return InlineCost::Expensive;
+
+  // Protocol descriptor references are free.
+  case SILInstructionKind::ObjCProtocolInst:
+    return InlineCost::Free;
+
+  // Metatype-to-object conversions are free.
+  case SILInstructionKind::ObjCExistentialMetatypeToObjectInst:
+  case SILInstructionKind::ObjCMetatypeToObjectInst:
+    return InlineCost::Free;
+
+  // Return and unreachable are free.
+  case SILInstructionKind::UnreachableInst:
+  case SILInstructionKind::ReturnInst:
+  case SILInstructionKind::ThrowInst:
+    return InlineCost::Free;
+
+  case SILInstructionKind::ApplyInst:
+  case SILInstructionKind::TryApplyInst:
+  case SILInstructionKind::AllocBoxInst:
+  case SILInstructionKind::AllocExistentialBoxInst:
+  case SILInstructionKind::AllocRefInst:
+  case SILInstructionKind::AllocRefDynamicInst:
+  case SILInstructionKind::AllocStackInst:
+  case SILInstructionKind::AllocValueBufferInst:
+  case SILInstructionKind::BindMemoryInst:
+  case SILInstructionKind::ValueMetatypeInst:
+  case SILInstructionKind::WitnessMethodInst:
+  case SILInstructionKind::AssignInst:
+  case SILInstructionKind::BranchInst:
+  case SILInstructionKind::CheckedCastBranchInst:
+  case SILInstructionKind::CheckedCastValueBranchInst:
+  case SILInstructionKind::CheckedCastAddrBranchInst:
+  case SILInstructionKind::ClassMethodInst:
+  case SILInstructionKind::CondBranchInst:
+  case SILInstructionKind::CondFailInst:
+  case SILInstructionKind::CopyBlockInst:
+  case SILInstructionKind::CopyAddrInst:
+  case SILInstructionKind::RetainValueInst:
+  case SILInstructionKind::RetainValueAddrInst:
+  case SILInstructionKind::UnmanagedRetainValueInst:
+  case SILInstructionKind::CopyValueInst:
+  case SILInstructionKind::CopyUnownedValueInst:
+  case SILInstructionKind::DeallocBoxInst:
+  case SILInstructionKind::DeallocExistentialBoxInst:
+  case SILInstructionKind::DeallocRefInst:
+  case SILInstructionKind::DeallocPartialRefInst:
+  case SILInstructionKind::DeallocStackInst:
+  case SILInstructionKind::DeallocValueBufferInst:
+  case SILInstructionKind::DeinitExistentialAddrInst:
+  case SILInstructionKind::DeinitExistentialValueInst:
+  case SILInstructionKind::DestroyAddrInst:
+  case SILInstructionKind::ProjectValueBufferInst:
+  case SILInstructionKind::ProjectBoxInst:
+  case SILInstructionKind::ProjectExistentialBoxInst:
+  case SILInstructionKind::ReleaseValueInst:
+  case SILInstructionKind::ReleaseValueAddrInst:
+  case SILInstructionKind::UnmanagedReleaseValueInst:
+  case SILInstructionKind::DestroyValueInst:
+  case SILInstructionKind::AutoreleaseValueInst:
+  case SILInstructionKind::UnmanagedAutoreleaseValueInst:
+  case SILInstructionKind::DynamicMethodBranchInst:
+  case SILInstructionKind::DynamicMethodInst:
+  case SILInstructionKind::EnumInst:
+  case SILInstructionKind::IndexAddrInst:
+  case SILInstructionKind::TailAddrInst:
+  case SILInstructionKind::IndexRawPointerInst:
+  case SILInstructionKind::InitEnumDataAddrInst:
+  case SILInstructionKind::InitExistentialAddrInst:
+  case SILInstructionKind::InitExistentialValueInst:
+  case SILInstructionKind::InitExistentialMetatypeInst:
+  case SILInstructionKind::InitExistentialRefInst:
+  case SILInstructionKind::InjectEnumAddrInst:
+  case SILInstructionKind::IsNonnullInst:
+  case SILInstructionKind::LoadInst:
+  case SILInstructionKind::LoadBorrowInst:
+  case SILInstructionKind::LoadUnownedInst:
+  case SILInstructionKind::LoadWeakInst:
+  case SILInstructionKind::OpenExistentialAddrInst:
+  case SILInstructionKind::OpenExistentialBoxInst:
+  case SILInstructionKind::OpenExistentialBoxValueInst:
+  case SILInstructionKind::OpenExistentialMetatypeInst:
+  case SILInstructionKind::OpenExistentialRefInst:
+  case SILInstructionKind::OpenExistentialValueInst:
+  case SILInstructionKind::PartialApplyInst:
+  case SILInstructionKind::ExistentialMetatypeInst:
+  case SILInstructionKind::RefElementAddrInst:
+  case SILInstructionKind::RefTailAddrInst:
+  case SILInstructionKind::RefToUnmanagedInst:
+  case SILInstructionKind::RefToUnownedInst:
+  case SILInstructionKind::StoreInst:
+  case SILInstructionKind::StoreBorrowInst:
+  case SILInstructionKind::StoreUnownedInst:
+  case SILInstructionKind::StoreWeakInst:
+  case SILInstructionKind::StrongPinInst:
+  case SILInstructionKind::StrongReleaseInst:
+  case SILInstructionKind::SetDeallocatingInst:
+  case SILInstructionKind::StrongRetainInst:
+  case SILInstructionKind::StrongRetainUnownedInst:
+  case SILInstructionKind::StrongUnpinInst:
+  case SILInstructionKind::SuperMethodInst:
+  case SILInstructionKind::SwitchEnumAddrInst:
+  case SILInstructionKind::SwitchEnumInst:
+  case SILInstructionKind::SwitchValueInst:
+  case SILInstructionKind::UncheckedEnumDataInst:
+  case SILInstructionKind::UncheckedTakeEnumDataAddrInst:
+  case SILInstructionKind::UnconditionalCheckedCastInst:
+  case SILInstructionKind::UnconditionalCheckedCastAddrInst:
+  case SILInstructionKind::UnconditionalCheckedCastValueInst:
+  case SILInstructionKind::UnmanagedToRefInst:
+  case SILInstructionKind::UnownedReleaseInst:
+  case SILInstructionKind::UnownedRetainInst:
+  case SILInstructionKind::IsUniqueInst:
+  case SILInstructionKind::IsUniqueOrPinnedInst:
+  case SILInstructionKind::UnownedToRefInst:
+  case SILInstructionKind::InitBlockStorageHeaderInst:
+  case SILInstructionKind::SelectEnumAddrInst:
+  case SILInstructionKind::SelectEnumInst:
+  case SILInstructionKind::SelectValueInst:
+  case SILInstructionKind::KeyPathInst:
+  case SILInstructionKind::GlobalValueInst:
+    return InlineCost::Expensive;
+
+  case SILInstructionKind::BuiltinInst: {
+    auto *BI = cast<BuiltinInst>(&I);
+    // Expect intrinsics are 'free' instructions.
+    if (BI->getIntrinsicInfo().ID == llvm::Intrinsic::expect)
+      return InlineCost::Free;
+    if (BI->getBuiltinInfo().ID == BuiltinValueKind::OnFastPath)
       return InlineCost::Free;
 
-    // Typed GEPs are free.
-    case ValueKind::TupleElementAddrInst:
-    case ValueKind::StructElementAddrInst:
-    case ValueKind::ProjectBlockStorageInst:
-      return InlineCost::Free;
-
-    // Aggregates are exploded at the IR level; these are effectively no-ops.
-    case ValueKind::TupleInst:
-    case ValueKind::StructInst:
-    case ValueKind::StructExtractInst:
-    case ValueKind::TupleExtractInst:
-      return InlineCost::Free;
-
-    // Unchecked casts are free.
-    case ValueKind::AddressToPointerInst:
-    case ValueKind::PointerToAddressInst:
-
-    case ValueKind::UncheckedRefCastInst:
-    case ValueKind::UncheckedRefCastAddrInst:
-    case ValueKind::UncheckedAddrCastInst:
-    case ValueKind::UncheckedTrivialBitCastInst:
-    case ValueKind::UncheckedBitwiseCastInst:
-
-    case ValueKind::RawPointerToRefInst:
-    case ValueKind::RefToRawPointerInst:
-
-    case ValueKind::UpcastInst:
-
-    case ValueKind::ThinToThickFunctionInst:
-    case ValueKind::ThinFunctionToPointerInst:
-    case ValueKind::PointerToThinFunctionInst:
-    case ValueKind::ConvertFunctionInst:
-
-    case ValueKind::BridgeObjectToWordInst:
-      return InlineCost::Free;
-
-    // Access instructions are free unless we're dynamically enforcing them.
-    case ValueKind::BeginAccessInst:
-      return getEnforcementCost(cast<BeginAccessInst>(I).getEnforcement());
-    case ValueKind::EndAccessInst:
-      return getEnforcementCost(cast<EndAccessInst>(I).getBeginAccess()
-                                                     ->getEnforcement());
-    case ValueKind::BeginUnpairedAccessInst:
-      return getEnforcementCost(cast<BeginUnpairedAccessInst>(I)
-                                  .getEnforcement());
-    case ValueKind::EndUnpairedAccessInst:
-      return getEnforcementCost(cast<EndUnpairedAccessInst>(I)
-                                  .getEnforcement());
-
-    // TODO: These are free if the metatype is for a Swift class.
-    case ValueKind::ThickToObjCMetatypeInst:
-    case ValueKind::ObjCToThickMetatypeInst:
-      return InlineCost::Expensive;
-      
-    // TODO: Bridge object conversions imply a masking operation that should be
-    // "hella cheap" but not really expensive
-    case ValueKind::BridgeObjectToRefInst:
-    case ValueKind::RefToBridgeObjectInst:
-      return InlineCost::Expensive;
-
-    case ValueKind::MetatypeInst:
-      // Thin metatypes are always free.
-      if (I.getType().castTo<MetatypeType>()->getRepresentation()
-            == MetatypeRepresentation::Thin)
-        return InlineCost::Free;
-      // TODO: Thick metatypes are free if they don't require generic or lazy
-      // instantiation.
-      return InlineCost::Expensive;
-
-    // Protocol descriptor references are free.
-    case ValueKind::ObjCProtocolInst:
-      return InlineCost::Free;
-
-    // Metatype-to-object conversions are free.
-    case ValueKind::ObjCExistentialMetatypeToObjectInst:
-    case ValueKind::ObjCMetatypeToObjectInst:
-      return InlineCost::Free;
-
-    // Return and unreachable are free.
-    case ValueKind::UnreachableInst:
-    case ValueKind::ReturnInst:
-    case ValueKind::ThrowInst:
-      return InlineCost::Free;
-
-    case ValueKind::ApplyInst:
-    case ValueKind::TryApplyInst:
-    case ValueKind::AllocBoxInst:
-    case ValueKind::AllocExistentialBoxInst:
-    case ValueKind::AllocRefInst:
-    case ValueKind::AllocRefDynamicInst:
-    case ValueKind::AllocStackInst:
-    case ValueKind::AllocValueBufferInst:
-    case ValueKind::BindMemoryInst:
-    case ValueKind::ValueMetatypeInst:
-    case ValueKind::WitnessMethodInst:
-    case ValueKind::AssignInst:
-    case ValueKind::BranchInst:
-    case ValueKind::CheckedCastBranchInst:
-    case ValueKind::CheckedCastValueBranchInst:
-    case ValueKind::CheckedCastAddrBranchInst:
-    case ValueKind::ClassMethodInst:
-    case ValueKind::CondBranchInst:
-    case ValueKind::CondFailInst:
-    case ValueKind::CopyBlockInst:
-    case ValueKind::CopyAddrInst:
-    case ValueKind::RetainValueInst:
-    case ValueKind::RetainValueAddrInst:
-    case ValueKind::UnmanagedRetainValueInst:
-    case ValueKind::CopyValueInst:
-    case ValueKind::CopyUnownedValueInst:
-    case ValueKind::DeallocBoxInst:
-    case ValueKind::DeallocExistentialBoxInst:
-    case ValueKind::DeallocRefInst:
-    case ValueKind::DeallocPartialRefInst:
-    case ValueKind::DeallocStackInst:
-    case ValueKind::DeallocValueBufferInst:
-    case ValueKind::DeinitExistentialAddrInst:
-    case ValueKind::DeinitExistentialValueInst:
-    case ValueKind::DestroyAddrInst:
-    case ValueKind::ProjectValueBufferInst:
-    case ValueKind::ProjectBoxInst:
-    case ValueKind::ProjectExistentialBoxInst:
-    case ValueKind::ReleaseValueInst:
-    case ValueKind::ReleaseValueAddrInst:
-    case ValueKind::UnmanagedReleaseValueInst:
-    case ValueKind::DestroyValueInst:
-    case ValueKind::AutoreleaseValueInst:
-    case ValueKind::UnmanagedAutoreleaseValueInst:
-    case ValueKind::DynamicMethodBranchInst:
-    case ValueKind::DynamicMethodInst:
-    case ValueKind::EnumInst:
-    case ValueKind::IndexAddrInst:
-    case ValueKind::TailAddrInst:
-    case ValueKind::IndexRawPointerInst:
-    case ValueKind::InitEnumDataAddrInst:
-    case ValueKind::InitExistentialAddrInst:
-    case ValueKind::InitExistentialValueInst:
-    case ValueKind::InitExistentialMetatypeInst:
-    case ValueKind::InitExistentialRefInst:
-    case ValueKind::InjectEnumAddrInst:
-    case ValueKind::IsNonnullInst:
-    case ValueKind::LoadInst:
-    case ValueKind::LoadBorrowInst:
-    case ValueKind::LoadUnownedInst:
-    case ValueKind::LoadWeakInst:
-    case ValueKind::OpenExistentialAddrInst:
-    case ValueKind::OpenExistentialBoxInst:
-    case ValueKind::OpenExistentialBoxValueInst:
-    case ValueKind::OpenExistentialMetatypeInst:
-    case ValueKind::OpenExistentialRefInst:
-    case ValueKind::OpenExistentialValueInst:
-    case ValueKind::PartialApplyInst:
-    case ValueKind::ExistentialMetatypeInst:
-    case ValueKind::RefElementAddrInst:
-    case ValueKind::RefTailAddrInst:
-    case ValueKind::RefToUnmanagedInst:
-    case ValueKind::RefToUnownedInst:
-    case ValueKind::StoreInst:
-    case ValueKind::StoreBorrowInst:
-    case ValueKind::StoreUnownedInst:
-    case ValueKind::StoreWeakInst:
-    case ValueKind::StrongPinInst:
-    case ValueKind::StrongReleaseInst:
-    case ValueKind::SetDeallocatingInst:
-    case ValueKind::StrongRetainInst:
-    case ValueKind::StrongRetainUnownedInst:
-    case ValueKind::StrongUnpinInst:
-    case ValueKind::SuperMethodInst:
-    case ValueKind::SwitchEnumAddrInst:
-    case ValueKind::SwitchEnumInst:
-    case ValueKind::SwitchValueInst:
-    case ValueKind::UncheckedEnumDataInst:
-    case ValueKind::UncheckedTakeEnumDataAddrInst:
-    case ValueKind::UnconditionalCheckedCastInst:
-    case ValueKind::UnconditionalCheckedCastAddrInst:
-    case ValueKind::UnconditionalCheckedCastValueInst:
-    case ValueKind::UnmanagedToRefInst:
-    case ValueKind::UnownedReleaseInst:
-    case ValueKind::UnownedRetainInst:
-    case ValueKind::IsUniqueInst:
-    case ValueKind::IsUniqueOrPinnedInst:
-    case ValueKind::UnownedToRefInst:
-    case ValueKind::InitBlockStorageHeaderInst:
-    case ValueKind::SelectEnumAddrInst:
-    case ValueKind::SelectEnumInst:
-    case ValueKind::SelectValueInst:
-    case ValueKind::KeyPathInst:
-    case ValueKind::GlobalValueInst:
-      return InlineCost::Expensive;
-
-    case ValueKind::BuiltinInst: {
-      auto *BI = cast<BuiltinInst>(&I);
-      // Expect intrinsics are 'free' instructions.
-      if (BI->getIntrinsicInfo().ID == llvm::Intrinsic::expect)
-        return InlineCost::Free;
-      if (BI->getBuiltinInfo().ID == BuiltinValueKind::OnFastPath)
-        return InlineCost::Free;
-
-      return InlineCost::Expensive;
-    }
-    case ValueKind::SILPHIArgument:
-    case ValueKind::SILFunctionArgument:
-    case ValueKind::SILUndef:
-      llvm_unreachable("Only instructions should be passed into this "
-                       "function.");
-    case ValueKind::MarkFunctionEscapeInst:
-    case ValueKind::MarkUninitializedInst:
-    case ValueKind::MarkUninitializedBehaviorInst:
-      llvm_unreachable("not valid in canonical sil");
-    case ValueKind::ObjectInst:
-      llvm_unreachable("not valid in a function");
+    return InlineCost::Expensive;
+  }
+  case SILInstructionKind::MarkFunctionEscapeInst:
+  case SILInstructionKind::MarkUninitializedInst:
+  case SILInstructionKind::MarkUninitializedBehaviorInst:
+    llvm_unreachable("not valid in canonical sil");
+  case SILInstructionKind::ObjectInst:
+    llvm_unreachable("not valid in a function");
   }
 
   llvm_unreachable("Unhandled ValueKind in switch.");
diff --git a/lib/SILOptimizer/Utils/SILSSAUpdater.cpp b/lib/SILOptimizer/Utils/SILSSAUpdater.cpp
index 4cbcc34..75fe849 100644
--- a/lib/SILOptimizer/Utils/SILSSAUpdater.cpp
+++ b/lib/SILOptimizer/Utils/SILSSAUpdater.cpp
@@ -78,11 +78,12 @@
 
 /// Are all available values identicalTo each other.
 bool areIdentical(AvailableValsTy &Avails) {
-  auto *First = dyn_cast<SILInstruction>(Avails.begin()->second);
+  // TODO: MultiValueInstruction
+  auto *First = dyn_cast<SingleValueInstruction>(Avails.begin()->second);
   if (!First)
     return false;
   for (auto Avail : Avails) {
-    auto *Inst = dyn_cast<SILInstruction>(Avail.second);
+    auto *Inst = dyn_cast<SingleValueInstruction>(Avail.second);
     if (!Inst)
       return false;
     if (!Inst->isIdenticalTo(First))
@@ -100,7 +101,7 @@
     assert(areIdentical(getAvailVals(AV)) &&
            "The function_refs need to have the same value");
     SILInstruction *User = Op.getUser();
-    auto *NewFR = FR->clone(User);
+    auto *NewFR = cast<FunctionRefInst>(FR->clone(User));
     Op.set(NewFR);
     return;
   } else if (auto *IL = dyn_cast<IntegerLiteralInst>(Op.get()))
@@ -108,7 +109,7 @@
       // Some llvm intrinsics don't like phi nodes as their constant inputs (e.g
       // ctlz).
       SILInstruction *User = Op.getUser();
-      auto *NewIL = IL->clone(User);
+      auto *NewIL = cast<IntegerLiteralInst>(IL->clone(User));
       Op.set(NewIL);
       return;
     }
@@ -531,7 +532,7 @@
 /// detection like induction variable analysis to succeed.
 ///
 /// If Arg is replaced, return the cast instruction. Otherwise return nullptr.
-SILInstruction *swift::replaceBBArgWithCast(SILPHIArgument *Arg) {
+SILValue swift::replaceBBArgWithCast(SILPHIArgument *Arg) {
   SmallVector<SILValue, 4> ArgValues;
   Arg->getIncomingValues(ArgValues);
   if (isa<StructInst>(ArgValues[0]))
diff --git a/lib/SILOptimizer/Utils/SpecializationMangler.cpp b/lib/SILOptimizer/Utils/SpecializationMangler.cpp
index 7134e4b..8dc7219 100644
--- a/lib/SILOptimizer/Utils/SpecializationMangler.cpp
+++ b/lib/SILOptimizer/Utils/SpecializationMangler.cpp
@@ -183,29 +183,29 @@
   switch (LI->getKind()) {
   default:
     llvm_unreachable("unknown literal");
-  case ValueKind::FunctionRefInst: {
+  case SILInstructionKind::FunctionRefInst: {
     SILFunction *F = cast<FunctionRefInst>(LI)->getReferencedFunction();
     ArgOpBuffer << 'f';
     appendIdentifier(F->getName());
     break;
   }
-  case ValueKind::GlobalAddrInst: {
+  case SILInstructionKind::GlobalAddrInst: {
     SILGlobalVariable *G = cast<GlobalAddrInst>(LI)->getReferencedGlobal();
     ArgOpBuffer << 'g';
     appendIdentifier(G->getName());
     break;
   }
-  case ValueKind::IntegerLiteralInst: {
+  case SILInstructionKind::IntegerLiteralInst: {
     APInt apint = cast<IntegerLiteralInst>(LI)->getValue();
     ArgOpBuffer << 'i' << apint;
     break;
   }
-  case ValueKind::FloatLiteralInst: {
+  case SILInstructionKind::FloatLiteralInst: {
     APInt apint = cast<FloatLiteralInst>(LI)->getBits();
     ArgOpBuffer << 'd' << apint;
     break;
   }
-  case ValueKind::StringLiteralInst: {
+  case SILInstructionKind::StringLiteralInst: {
     StringLiteralInst *SLI = cast<StringLiteralInst>(LI);
     StringRef V = SLI->getValue();
     assert(V.size() <= 32 && "Cannot encode string of length > 32");
diff --git a/lib/SILOptimizer/Utils/StackNesting.cpp b/lib/SILOptimizer/Utils/StackNesting.cpp
index 143bc3d..56a38f7 100644
--- a/lib/SILOptimizer/Utils/StackNesting.cpp
+++ b/lib/SILOptimizer/Utils/StackNesting.cpp
@@ -41,15 +41,16 @@
     BlockInfo *BI = WorkList.pop_back_val();
     for (SILInstruction &I : *BI->Block) {
       if (I.isAllocatingStack()) {
+        auto Alloc = cast<AllocationInst>(&I);
         // Register this stack location.
         unsigned CurrentBitNumber = StackLocs.size();
-        StackLoc2BitNumbers[&I] = CurrentBitNumber;
-        StackLocs.push_back(StackLoc(&I));
+        StackLoc2BitNumbers[Alloc] = CurrentBitNumber;
+        StackLocs.push_back(StackLoc(Alloc));
 
-        BI->StackInsts.push_back(&I);
+        BI->StackInsts.push_back(Alloc);
 
       } else if (I.isDeallocatingStack()) {
-        auto *AllocInst = cast<SILInstruction>(I.getOperand(0));
+        auto *AllocInst = cast<SingleValueInstruction>(I.getOperand(0));
         if (!BI->StackInsts.empty() && BI->StackInsts.back() == AllocInst) {
           // As an optimization, we ignore perfectly nested alloc-dealloc pairs
           // inside a basic block.
@@ -114,7 +115,8 @@
       }
       for (SILInstruction *StackInst : reversed(BI.StackInsts)) {
         if (StackInst->isAllocatingStack()) {
-          int BitNr = StackLoc2BitNumbers[StackInst];
+          auto AllocInst = cast<SingleValueInstruction>(StackInst);
+          int BitNr = StackLoc2BitNumbers[AllocInst];
           if (Bits != StackLocs[BitNr].AliveLocs) {
             // More locations are alive around the StackInst's location.
             // Update the AlivaLocs bitset, which contains all those alive
@@ -132,7 +134,8 @@
           // A stack deallocation begins the lifetime of its location (in
           // reverse order). And it also begins the lifetime of all other
           // locations which are alive at the allocation point.
-          auto *AllocInst = cast<SILInstruction>(StackInst->getOperand(0));
+          auto *AllocInst =
+            cast<SingleValueInstruction>(StackInst->getOperand(0));
           int BitNr = StackLoc2BitNumbers[AllocInst];
           Bits |= StackLocs[BitNr].AliveLocs;
         }
@@ -147,14 +150,14 @@
   return isNested;
 }
 
-static SILInstruction *createDealloc(SILInstruction *Alloc,
+static SILInstruction *createDealloc(AllocationInst *Alloc,
                                      SILInstruction *InsertionPoint,
                                      SILLocation Location) {
   SILBuilder B(InsertionPoint);
   switch (Alloc->getKind()) {
-    case ValueKind::AllocStackInst:
+    case SILInstructionKind::AllocStackInst:
       return B.createDeallocStack(Location, Alloc);
-    case ValueKind::AllocRefInst:
+    case SILInstructionKind::AllocRefInst:
       assert(cast<AllocRefInst>(Alloc)->canAllocOnStack());
       return B.createDeallocRef(Location, Alloc, /*canBeOnStack*/true);
     default:
@@ -176,7 +179,7 @@
   for (int LocNr = AliveBefore.find_first(); LocNr >= 0;
        LocNr = AliveBefore.find_next(LocNr)) {
     if (!AliveAfter.test(LocNr)) {
-      SILInstruction *Alloc = StackLocs[LocNr].Alloc;
+      AllocationInst *Alloc = StackLocs[LocNr].Alloc;
       InsertionPoint = createDealloc(Alloc, InsertionPoint,
                    Location.hasValue() ? Location.getValue() : Alloc->getLoc());
       changesMade = true;
@@ -244,13 +247,14 @@
     for (SILInstruction *StackInst : reversed(BI.StackInsts)) {
       if (StackInst->isAllocatingStack()) {
         // For allocations we just update the bit-set.
-        int BitNr = StackLoc2BitNumbers.lookup(StackInst);
+        auto AllocInst = cast<SingleValueInstruction>(StackInst);
+        int BitNr = StackLoc2BitNumbers.lookup(AllocInst);
         assert(Bits == StackLocs[BitNr].AliveLocs &&
                "dataflow didn't converge");
         Bits.reset(BitNr);
       } else if (StackInst->isDeallocatingStack()) {
         // Handle deallocations.
-        auto *AllocInst = cast<SILInstruction>(StackInst->getOperand(0));
+        auto *AllocInst = cast<SingleValueInstruction>(StackInst->getOperand(0));
         SILLocation Loc = StackInst->getLoc();
         int BitNr = StackLoc2BitNumbers.lookup(AllocInst);
         SILInstruction *InsertionPoint = &*std::next(StackInst->getIterator());
@@ -301,12 +305,13 @@
     dumpBits(BI.AliveStackLocsAtEntry);
     for (SILInstruction *StackInst : BI.StackInsts) {
       if (StackInst->isAllocatingStack()) {
-        int BitNr = StackLoc2BitNumbers.lookup(StackInst);
+        auto AllocInst = cast<AllocationInst>(StackInst);
+        int BitNr = StackLoc2BitNumbers.lookup(AllocInst);
         llvm::dbgs() << "  alloc #" << BitNr << ": alive=";
         dumpBits(StackLocs[BitNr].AliveLocs);
         llvm::dbgs() << "    " << *StackInst;
       } else if (StackInst->isDeallocatingStack()) {
-        auto *AllocInst = cast<SILInstruction>(StackInst->getOperand(0));
+        auto *AllocInst = cast<AllocationInst>(StackInst->getOperand(0));
         int BitNr = StackLoc2BitNumbers.lookup(AllocInst);
         llvm::dbgs() << "  dealloc for #" << BitNr << "\n"
                         "    " << *StackInst;
diff --git a/lib/Sema/CSBindings.cpp b/lib/Sema/CSBindings.cpp
index a175413..3ca3f74 100644
--- a/lib/Sema/CSBindings.cpp
+++ b/lib/Sema/CSBindings.cpp
@@ -123,6 +123,40 @@
   llvm_unreachable("Unhandled ConstraintKind in switch.");
 }
 
+void ConstraintSystem::PotentialBindings::addPotentialBinding(
+    PotentialBinding binding, bool allowJoinMeet) {
+  assert(!binding.BindingType->is<ErrorType>());
+
+  // If this is a non-defaulted supertype binding,
+  // check whether we can combine it with another
+  // supertype binding by computing the 'join' of the types.
+  if (binding.Kind == AllowedBindingKind::Supertypes &&
+      !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;
+        }
+      }
+    }
+
+    // Record this as the most recent supertype index.
+    lastSupertypeIndex = Bindings.size();
+  }
+
+  Bindings.push_back(std::move(binding));
+}
+
 /// \brief Retrieve the set of potential type bindings for the given
 /// representative type variable, along with flags indicating whether
 /// those types should be opened.
@@ -154,16 +188,9 @@
       continue;
 
     switch (constraint->getKind()) {
-    case ConstraintKind::BindParam:
-      if (simplifyType(constraint->getSecondType())
-              ->getAs<TypeVariableType>() == typeVar) {
-        result.IsRHSOfBindParam = true;
-      }
-
-      LLVM_FALLTHROUGH;
-
     case ConstraintKind::Bind:
     case ConstraintKind::Equal:
+    case ConstraintKind::BindParam:
     case ConstraintKind::BindToPointerType:
     case ConstraintKind::Subtype:
     case ConstraintKind::Conversion:
diff --git a/lib/Sema/CSDiag.cpp b/lib/Sema/CSDiag.cpp
index bea32ae..d2b84a8 100644
--- a/lib/Sema/CSDiag.cpp
+++ b/lib/Sema/CSDiag.cpp
@@ -3289,18 +3289,42 @@
           patternElt.first->setType(patternElt.second);
       
       for (auto paramDeclElt : ParamDeclTypes)
-        if (!paramDeclElt.first->hasType())
-          paramDeclElt.first->setType(paramDeclElt.second);
+        if (!paramDeclElt.first->hasType()) {
+          paramDeclElt.first->setType(getParamBaseType(paramDeclElt));
+        }
 
       for (auto paramDeclIfaceElt : ParamDeclInterfaceTypes)
-        if (!paramDeclIfaceElt.first->hasInterfaceType())
-          paramDeclIfaceElt.first->setInterfaceType(paramDeclIfaceElt.second);
+        if (!paramDeclIfaceElt.first->hasInterfaceType()) {
+          paramDeclIfaceElt.first->setInterfaceType(
+              getParamBaseType(paramDeclIfaceElt));
+        }
 
       if (!PossiblyInvalidDecls.empty())
         for (auto D : PossiblyInvalidDecls)
           if (D->hasInterfaceType())
             D->setInvalid(D->getInterfaceType()->hasError());
     }
+
+  private:
+    static Type getParamBaseType(std::pair<ParamDecl *, Type> &storedParam) {
+      ParamDecl *param;
+      Type storedType;
+
+      std::tie(param, storedType) = storedParam;
+
+      // FIXME: We are currently in process of removing `InOutType`
+      //        so `VarDecl::get{Interface}Type` is going to wrap base
+      //        type into `InOutType` if its flag indicates that it's
+      //        an `inout` parameter declaration. But such type can't
+      //        be restored directly using `VarDecl::set{Interface}Type`
+      //        caller needs additional logic to extract base type.
+      if (auto *IOT = storedType->getAs<InOutType>()) {
+        assert(param->isInOut());
+        return IOT->getObjectType();
+      }
+
+      return storedType;
+    }
   };
 } // end anonymous namespace
 
diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp
index 68813f8..1d97b74 100644
--- a/lib/Sema/CSSimplify.cpp
+++ b/lib/Sema/CSSimplify.cpp
@@ -1681,11 +1681,27 @@
         if (!isBindable(typeVar1, type2))
           return formUnsolvedResult();
 
+        // If the right-hand side of the BindParam constraint
+        // is `lvalue` type, we'll have to make sure that
+        // left-hand side is bound to type variable which
+        // is wrapped in `inout` type to preserve inout/lvalue pairing.
         if (auto *lvt = type2->getAs<LValueType>()) {
-          assignFixedType(typeVar1, InOutType::get(lvt->getObjectType()));
-        } else {
-          assignFixedType(typeVar1, type2);
+          auto *tv = createTypeVariable(typeVar1->getImpl().getLocator(),
+                                        /*options=*/0);
+          assignFixedType(typeVar1, InOutType::get(tv));
+
+          typeVar1 = tv;
+          type2 = lvt->getObjectType();
         }
+
+        // If we have a binding for the right-hand side
+        // (argument type) don't try to bind it to the left-hand
+        // side (parameter type) directly, because their
+        // relationship is contravariant and the actual
+        // binding can only come from the left-hand side.
+        addUnsolvedConstraint(
+            Constraint::create(*this, ConstraintKind::ArgumentConversion, type2,
+                               typeVar1, getConstraintLocator(locator)));
         return SolutionKind::Solved;
       }
 
diff --git a/lib/Sema/CSSolver.cpp b/lib/Sema/CSSolver.cpp
index a01baec..2055c66 100644
--- a/lib/Sema/CSSolver.cpp
+++ b/lib/Sema/CSSolver.cpp
@@ -75,6 +75,17 @@
   if (count(referencedTypeVars, typeVar))
     return None;
 
+  // If type variable is not allowed to bind to `lvalue`,
+  // let's check if type of potential binding has any
+  // type variables, which are allowed to bind to `lvalue`,
+  // and postpone such type from consideration.
+  if (!typeVar->getImpl().canBindToLValue()) {
+    for (auto *typeVar : referencedTypeVars) {
+      if (typeVar->getImpl().canBindToLValue())
+        return None;
+    }
+  }
+
   // If the type is a type variable itself, don't permit the binding.
   if (auto bindingTypeVar = type->getRValueType()->getAs<TypeVariableType>()) {
     if (isNilLiteral) {
diff --git a/lib/Sema/CodeSynthesis.cpp b/lib/Sema/CodeSynthesis.cpp
index 727f365..24c5854 100644
--- a/lib/Sema/CodeSynthesis.cpp
+++ b/lib/Sema/CodeSynthesis.cpp
@@ -2118,6 +2118,12 @@
     ctor->getAttrs().add(clonedAttr);
   }
 
+  // Inherit the @_inlineable attribute.
+  if (superclassCtor->getAttrs().hasAttribute<InlineableAttr>()) {
+    auto *clonedAttr = new (ctx) InlineableAttr(/*implicit=*/true);
+    ctor->getAttrs().add(clonedAttr);
+  }
+
   // Make sure the constructor is only as available as its superclass's
   // constructor.
   AvailabilityInference::applyInferredAvailableAttrs(ctor, superclassCtor, ctx);
diff --git a/lib/Sema/ConstraintGraph.cpp b/lib/Sema/ConstraintGraph.cpp
index 789f640..3698f76 100644
--- a/lib/Sema/ConstraintGraph.cpp
+++ b/lib/Sema/ConstraintGraph.cpp
@@ -648,25 +648,6 @@
   }
 }
 
-/// We use this function to determine if a subtype constraint is set
-/// between two (possibly sugared) type variables, one of which is wrapped
-/// in an inout type.
-static bool isStrictInoutSubtypeConstraint(Constraint *constraint) {
-  if (constraint->getKind() != ConstraintKind::Subtype)
-    return false;
-
-  auto t1 = constraint->getFirstType()->getDesugaredType();
-
-  if (auto tt = t1->getAs<TupleType>()) {
-    if (tt->getNumElements() != 1)
-      return false;
-
-    t1 = tt->getElementType(0).getPointer();
-  }
-
-  return t1->is<InOutType>();
-}
-
 bool ConstraintGraph::contractEdges() {
   llvm::SetVector<std::pair<TypeVariableType *,
                             TypeVariableType *>> contractions;
@@ -694,20 +675,13 @@
 
         auto isParamBindingConstraint = kind == ConstraintKind::BindParam;
 
-        // We need to take special care not to directly contract parameter
-        // binding constraints if there is an inout subtype constraint on the
-        // type variable. The constraint solver depends on multiple constraints
-        // being present in this case, so it can generate the appropriate lvalue
-        // wrapper for the argument type.
-        if (isParamBindingConstraint) {
-          auto *node = tyvar1->getImpl().getGraphNode();
-          auto constraints = node->getConstraints();
-          if (llvm::any_of(constraints, [](Constraint *constraint) {
-                            return isStrictInoutSubtypeConstraint(constraint);
-                          })) {
-            continue;
-          }
-        }
+        // If the parameter is allowed to bind to `inout` let's not
+        // try to contract the edge connecting parameter declaration to
+        // it's use in the body. If parameter declaration is bound to
+        // `inout` it's use has to be bound to `l-value`, which can't
+        // happen once equivalence classes of parameter and argument are merged.
+        if (isParamBindingConstraint && tyvar1->getImpl().canBindToInOut())
+          continue;
 
         auto rep1 = CS.getRepresentative(tyvar1);
         auto rep2 = CS.getRepresentative(tyvar2);
@@ -740,10 +714,12 @@
 }
 
 void ConstraintGraph::removeEdge(Constraint *constraint) {
+  bool isExistingConstraint = false;
 
   for (auto &active : CS.ActiveConstraints) {
     if (&active == constraint) {
       CS.ActiveConstraints.erase(constraint);
+      isExistingConstraint = true;
       break;
     }
   }
@@ -751,12 +727,17 @@
   for (auto &inactive : CS.InactiveConstraints) {
     if (&inactive == constraint) {
       CS.InactiveConstraints.erase(constraint);
+      isExistingConstraint = true;
       break;
     }
   }
 
-  if (CS.solverState)
-    CS.solverState->removeGeneratedConstraint(constraint);
+  if (CS.solverState) {
+    if (isExistingConstraint)
+      CS.solverState->retireConstraint(constraint);
+    else
+      CS.solverState->removeGeneratedConstraint(constraint);
+  }
 
   removeConstraint(constraint);
 }
diff --git a/lib/Sema/ConstraintSystem.h b/lib/Sema/ConstraintSystem.h
index c106aa4..296a099 100644
--- a/lib/Sema/ConstraintSystem.h
+++ b/lib/Sema/ConstraintSystem.h
@@ -2551,8 +2551,8 @@
   };
 
   struct PotentialBindings {
-    typedef std::tuple<bool, bool, bool, bool, bool,
-                       unsigned char, unsigned int> BindingScore;
+    typedef std::tuple<bool, bool, bool, bool, unsigned char, unsigned int>
+        BindingScore;
 
     TypeVariableType *TypeVar;
 
@@ -2574,9 +2574,6 @@
     /// The number of defaultable bindings.
     unsigned NumDefaultableBindings = 0;
 
-    /// Is this type variable on the RHS of a BindParam constraint?
-    bool IsRHSOfBindParam = false;
-
     /// Tracks the position of the last known supertype in the group.
     Optional<unsigned> lastSupertypeIndex;
 
@@ -2593,7 +2590,6 @@
     static BindingScore formBindingScore(const PotentialBindings &b) {
       return std::make_tuple(!b.hasNonDefaultableBindings(),
                              b.FullyBound,
-                             b.IsRHSOfBindParam,
                              b.SubtypeOfExistentialType,
                              b.InvolvesTypeVariables,
                              static_cast<unsigned char>(b.LiteralBinding),
@@ -2629,39 +2625,7 @@
     /// \brief Add a potential binding to the list of bindings,
     /// coalescing supertype bounds when we are able to compute the meet.
     void addPotentialBinding(PotentialBinding binding,
-                             bool allowJoinMeet = true) {
-      assert(!binding.BindingType->is<ErrorType>());
-
-      // If this is a non-defaulted supertype binding,
-      // check whether we can combine it with another
-      // supertype binding by computing the 'join' of the types.
-      if (binding.Kind == AllowedBindingKind::Supertypes &&
-          !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;
-            }
-          }
-        }
-
-        // Record this as the most recent supertype index.
-        lastSupertypeIndex = Bindings.size();
-      }
-
-      Bindings.push_back(std::move(binding));
-    }
+                             bool allowJoinMeet = true);
 
     void dump(llvm::raw_ostream &out,
               unsigned indent = 0) const LLVM_ATTRIBUTE_USED {
diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp
index a9db914..afa22bd 100644
--- a/lib/Sema/TypeCheckDecl.cpp
+++ b/lib/Sema/TypeCheckDecl.cpp
@@ -7117,8 +7117,11 @@
   }
 
   void visitDestructorDecl(DestructorDecl *DD) {
-    if (DD->isInvalid()) {
+    auto enclosingClass = dyn_cast<ClassDecl>(DD->getDeclContext());
+    if (DD->isInvalid() ||
+        enclosingClass == nullptr) {
       DD->setInterfaceType(ErrorType::get(TC.Context));
+      DD->setInvalid();
       return;
     }
 
@@ -7140,10 +7143,13 @@
 
     TC.checkDeclAttributesEarly(DD);
     if (!DD->hasAccess()) {
-      auto enclosingClass = cast<ClassDecl>(DD->getParent());
       DD->setAccess(enclosingClass->getFormalAccess());
     }
 
+    if (enclosingClass->getAttrs().hasAttribute<VersionedAttr>()) {
+      DD->getAttrs().add(new (TC.Context) VersionedAttr(/*implicit=*/true));
+    }
+
     configureImplicitSelf(TC, DD);
 
     if (DD->getDeclContext()->getGenericSignatureOfContext()) {
@@ -7664,25 +7670,13 @@
 
     break;
   }
-      
-  case DeclKind::Func: {
-    typeCheckDecl(D, true);
-    break;
-  }
 
+  case DeclKind::Func:
   case DeclKind::Subscript:
   case DeclKind::Constructor:
-    typeCheckDecl(D, true);
-    break;
-
   case DeclKind::Destructor:
   case DeclKind::EnumElement: {
-    if (auto container = dyn_cast<NominalTypeDecl>(D->getDeclContext())) {
-      validateDecl(container);
-      typeCheckDecl(D, true);
-    } else {
-      D->setInterfaceType(ErrorType::get(Context));
-    }
+    typeCheckDecl(D, true);
     break;
   }
   }
@@ -8036,8 +8030,7 @@
   // Local function used to infer requirements from the extended type.
   auto inferExtendedTypeReqs = [&](GenericSignatureBuilder &builder) {
     auto source =
-      GenericSignatureBuilder::FloatingRequirementSource::forInferred(
-                                          nullptr, /*quietly=*/false);
+      GenericSignatureBuilder::FloatingRequirementSource::forInferred(nullptr);
 
     builder.inferRequirements(*ext->getModuleContext(),
                               TypeLoc::withoutLoc(extInterfaceType),
diff --git a/lib/Sema/TypeCheckGeneric.cpp b/lib/Sema/TypeCheckGeneric.cpp
index 949f618..c81fb27 100644
--- a/lib/Sema/TypeCheckGeneric.cpp
+++ b/lib/Sema/TypeCheckGeneric.cpp
@@ -480,8 +480,7 @@
           fn->getBodyResultTypeLoc().getTypeRepr()) {
         auto source =
           GenericSignatureBuilder::FloatingRequirementSource::forInferred(
-              fn->getBodyResultTypeLoc().getTypeRepr(),
-              /*quietly=*/true);
+              fn->getBodyResultTypeLoc().getTypeRepr());
         builder->inferRequirements(*func->getParentModule(),
                                    fn->getBodyResultTypeLoc(),
                                    source);
@@ -497,8 +496,7 @@
         if (auto *subscriptDecl = dyn_cast<SubscriptDecl>(storage)) {
           auto source =
             GenericSignatureBuilder::FloatingRequirementSource::forInferred(
-                subscriptDecl->getElementTypeLoc().getTypeRepr(),
-                /*quietly=*/true);
+                subscriptDecl->getElementTypeLoc().getTypeRepr());
 
           TypeLoc type(nullptr, subscriptDecl->getElementInterfaceType());
           assert(type.getType());
@@ -945,8 +943,7 @@
   if (genericParams && builder) {
     auto source =
       GenericSignatureBuilder::FloatingRequirementSource::forInferred(
-          subscript->getElementTypeLoc().getTypeRepr(),
-          /*quietly=*/true);
+          subscript->getElementTypeLoc().getTypeRepr());
 
     builder->inferRequirements(*subscript->getParentModule(),
                                subscript->getElementTypeLoc(),
diff --git a/lib/Serialization/DeserializeSIL.cpp b/lib/Serialization/DeserializeSIL.cpp
index 4000929..19c5080 100644
--- a/lib/Serialization/DeserializeSIL.cpp
+++ b/lib/Serialization/DeserializeSIL.cpp
@@ -318,7 +318,7 @@
   return M.createFunction(
       SILLinkage::Private, name, type.castTo<SILFunctionType>(), nullptr,
       RegularLocation(loc), IsNotBare, IsNotTransparent, IsNotSerialized,
-      IsNotThunk, SubclassScope::NotApplicable);
+      ProfileCounter(), IsNotThunk, SubclassScope::NotApplicable);
 }
 
 /// Helper function to find a SILFunction, given its name and type.
@@ -470,7 +470,7 @@
     fn = SILMod.createFunction(
         linkage.getValue(), name, ty.castTo<SILFunctionType>(), nullptr, loc,
         IsNotBare, IsTransparent_t(isTransparent == 1),
-        IsSerialized_t(isSerialized), IsThunk_t(isThunk),
+        IsSerialized_t(isSerialized), ProfileCounter(), IsThunk_t(isThunk),
         SubclassScope::NotApplicable, (Inline_t)inlineStrategy);
     fn->setGlobalInit(isGlobal == 1);
     fn->setEffectsKind((EffectsKind)effect);
@@ -725,7 +725,7 @@
 
   Builder.setInsertionPoint(BB);
   Builder.setCurrentDebugScope(Fn->getDebugScope());
-  unsigned OpCode = 0, TyCategory = 0, TyCategory2 = 0, TyCategory3 = 0,
+  unsigned RawOpCode = 0, TyCategory = 0, TyCategory2 = 0, TyCategory3 = 0,
            Attr = 0, NumSubs = 0, NumConformances = 0, IsNonThrowingApply = 0;
   ValueID ValID, ValID2, ValID3;
   TypeID TyID, TyID2, TyID3;
@@ -739,25 +739,25 @@
   default:
     llvm_unreachable("Record kind for a SIL instruction is not supported.");
   case SIL_ONE_VALUE_ONE_OPERAND:
-    SILOneValueOneOperandLayout::readRecord(scratch, OpCode, Attr,
+    SILOneValueOneOperandLayout::readRecord(scratch, RawOpCode, Attr,
                                             ValID, TyID, TyCategory,
                                             ValID2);
     break;
   case SIL_ONE_TYPE:
-    SILOneTypeLayout::readRecord(scratch, OpCode, TyID, TyCategory);
+    SILOneTypeLayout::readRecord(scratch, RawOpCode, TyID, TyCategory);
     break;
   case SIL_ONE_OPERAND:
-    SILOneOperandLayout::readRecord(scratch, OpCode, Attr,
+    SILOneOperandLayout::readRecord(scratch, RawOpCode, Attr,
                                     TyID, TyCategory, ValID);
     break;
   case SIL_ONE_TYPE_ONE_OPERAND:
-    SILOneTypeOneOperandLayout::readRecord(scratch, OpCode, Attr,
+    SILOneTypeOneOperandLayout::readRecord(scratch, RawOpCode, Attr,
                                            TyID, TyCategory,
                                            TyID2, TyCategory2,
                                            ValID);
     break;
   case SIL_INIT_EXISTENTIAL:
-    SILInitExistentialLayout::readRecord(scratch, OpCode,
+    SILInitExistentialLayout::readRecord(scratch, RawOpCode,
                                          TyID, TyCategory,
                                          TyID2, TyCategory2,
                                          ValID,
@@ -765,22 +765,22 @@
                                          NumConformances);
     break;
   case SIL_INST_CAST:
-    SILInstCastLayout::readRecord(scratch, OpCode, Attr,
+    SILInstCastLayout::readRecord(scratch, RawOpCode, Attr,
                                   TyID, TyCategory,
                                   TyID2, TyCategory2,
                                   ValID);
     break;
   case SIL_ONE_TYPE_VALUES:
-    SILOneTypeValuesLayout::readRecord(scratch, OpCode, TyID, TyCategory,
+    SILOneTypeValuesLayout::readRecord(scratch, RawOpCode, TyID, TyCategory,
                                        ListOfValues);
     break;
   case SIL_TWO_OPERANDS:
-    SILTwoOperandsLayout::readRecord(scratch, OpCode, Attr,
+    SILTwoOperandsLayout::readRecord(scratch, RawOpCode, Attr,
                                      TyID, TyCategory, ValID,
                                      TyID2, TyCategory2, ValID2);
     break;
   case SIL_TAIL_ADDR:
-    SILTailAddrLayout::readRecord(scratch, OpCode,
+    SILTailAddrLayout::readRecord(scratch, RawOpCode,
                                   TyID, ValID,
                                   TyID2, ValID2,
                                   TyID3);
@@ -791,19 +791,19 @@
                                    TyID, TyID2, ValID, ListOfValues);
     switch (IsPartial) {
     case SIL_APPLY:
-      OpCode = (unsigned)ValueKind::ApplyInst;
+      RawOpCode = (unsigned)SILInstructionKind::ApplyInst;
       break;
     case SIL_PARTIAL_APPLY:
-      OpCode = (unsigned)ValueKind::PartialApplyInst;
+      RawOpCode = (unsigned)SILInstructionKind::PartialApplyInst;
       break;
     case SIL_BUILTIN:
-      OpCode = (unsigned)ValueKind::BuiltinInst;
+      RawOpCode = (unsigned)SILInstructionKind::BuiltinInst;
       break;
     case SIL_TRY_APPLY:
-      OpCode = (unsigned)ValueKind::TryApplyInst;
+      RawOpCode = (unsigned)SILInstructionKind::TryApplyInst;
       break;
     case SIL_NON_THROWING_APPLY:
-      OpCode = (unsigned)ValueKind::ApplyInst;
+      RawOpCode = (unsigned)SILInstructionKind::ApplyInst;
       IsNonThrowingApply = true;
       break;
         
@@ -813,35 +813,33 @@
     break;
   }
   case SIL_INST_NO_OPERAND:
-    SILInstNoOperandLayout::readRecord(scratch, OpCode);
+    SILInstNoOperandLayout::readRecord(scratch, RawOpCode);
     break;
   case SIL_INST_WITNESS_METHOD:
     SILInstWitnessMethodLayout::readRecord(
         scratch, TyID, TyCategory, Attr, TyID2, TyCategory2, TyID3,
         TyCategory3, ValID3, ListOfValues);
-    OpCode = (unsigned)ValueKind::WitnessMethodInst;
+    RawOpCode = (unsigned)SILInstructionKind::WitnessMethodInst;
     break;
   }
 
-  SILInstruction *ResultVal;
-  switch ((ValueKind)OpCode) {
-  case ValueKind::SILPHIArgument:
-  case ValueKind::SILFunctionArgument:
-  case ValueKind::SILUndef:
-    llvm_unreachable("not an instruction");
+  // FIXME: validate
+  SILInstructionKind OpCode = (SILInstructionKind) RawOpCode;
 
-  case ValueKind::DebugValueInst:
-  case ValueKind::DebugValueAddrInst:
+  SILInstruction *ResultVal;
+  switch (OpCode) {
+  case SILInstructionKind::DebugValueInst:
+  case SILInstructionKind::DebugValueAddrInst:
     llvm_unreachable("not supported");
 
-  case ValueKind::AllocBoxInst:
+  case SILInstructionKind::AllocBoxInst:
     assert(RecordKind == SIL_ONE_TYPE && "Layout should be OneType.");
     ResultVal = Builder.createAllocBox(Loc,
                        cast<SILBoxType>(MF->getType(TyID)->getCanonicalType()));
     break;
   
 #define ONETYPE_INST(ID)                      \
-  case ValueKind::ID##Inst:                   \
+  case SILInstructionKind::ID##Inst:                   \
     assert(RecordKind == SIL_ONE_TYPE && "Layout should be OneType.");         \
     ResultVal = Builder.create##ID(Loc,                                        \
                   getSILType(MF->getType(TyID), (SILValueCategory)TyCategory));\
@@ -850,7 +848,7 @@
   ONETYPE_INST(Metatype)
 #undef ONETYPE_INST
 #define ONETYPE_ONEOPERAND_INST(ID)           \
-  case ValueKind::ID##Inst:                   \
+  case SILInstructionKind::ID##Inst:                   \
     assert(RecordKind == SIL_ONE_TYPE_ONE_OPERAND &&       \
            "Layout should be OneTypeOneOperand.");         \
     ResultVal = Builder.create##ID(Loc,                    \
@@ -866,7 +864,7 @@
   ONETYPE_ONEOPERAND_INST(ProjectExistentialBox)
   ONETYPE_ONEOPERAND_INST(DeallocValueBuffer)
 #undef ONETYPE_ONEOPERAND_INST
-  case ValueKind::DeallocBoxInst:
+  case SILInstructionKind::DeallocBoxInst:
     assert(RecordKind == SIL_ONE_TYPE_ONE_OPERAND &&
            "Layout should be OneTypeOneOperand.");
     ResultVal = Builder.createDeallocBox(Loc,
@@ -874,7 +872,7 @@
                     getSILType(MF->getType(TyID2),
                                (SILValueCategory)TyCategory2)));
     break;
-  case ValueKind::OpenExistentialAddrInst:
+  case SILInstructionKind::OpenExistentialAddrInst:
     assert(RecordKind == SIL_ONE_TYPE_ONE_OPERAND &&
            "Layout should be OneTypeOneOperand.");
     ResultVal = Builder.createOpenExistentialAddr(
@@ -886,7 +884,7 @@
     break;
 
 #define ONEOPERAND_ONETYPE_INST(ID)           \
-  case ValueKind::ID##Inst:                   \
+  case SILInstructionKind::ID##Inst:                   \
     assert(RecordKind == SIL_ONE_TYPE_ONE_OPERAND &&       \
            "Layout should be OneTypeOneOperand.");         \
     ResultVal = Builder.create##ID(Loc,                    \
@@ -926,7 +924,7 @@
   ONEOPERAND_ONETYPE_INST(ProjectBlockStorage)
 #undef ONEOPERAND_ONETYPE_INST
 
-  case ValueKind::ProjectBoxInst: {
+  case SILInstructionKind::ProjectBoxInst: {
     assert(RecordKind == SIL_ONE_TYPE_ONE_OPERAND &&
            "Layout should be OneTypeOneOperand.");
     ResultVal = Builder.createProjectBox(Loc,
@@ -937,7 +935,7 @@
     break;
   }
 
-  case ValueKind::PointerToAddressInst: {
+  case SILInstructionKind::PointerToAddressInst: {
     assert(RecordKind == SIL_ONE_TYPE_ONE_OPERAND &&
            "Layout should be OneTypeOneOperand.");
     bool isStrict = Attr & 0x01;
@@ -950,7 +948,7 @@
       isStrict, isInvariant);
     break;
   }
-  case ValueKind::DeallocExistentialBoxInst: {
+  case SILInstructionKind::DeallocExistentialBoxInst: {
     assert(RecordKind == SIL_ONE_TYPE_ONE_OPERAND &&
            "Layout should be OneTypeOneOperand.");
     ResultVal = Builder.createDeallocExistentialBox(Loc,
@@ -962,7 +960,7 @@
 
   }
   
-  case ValueKind::RefToBridgeObjectInst: {
+  case SILInstructionKind::RefToBridgeObjectInst: {
     auto RefTy = getSILType(MF->getType(TyID), (SILValueCategory)TyCategory);
     auto Ref = getLocalValue(ValID, RefTy);
     auto BitsTy = getSILType(MF->getType(TyID2), (SILValueCategory)TyCategory2);
@@ -972,26 +970,26 @@
     break;
   }
 
-  case ValueKind::ObjCProtocolInst: {
+  case SILInstructionKind::ObjCProtocolInst: {
     auto Ty = getSILType(MF->getType(TyID), (SILValueCategory)TyCategory);
     auto Proto = MF->getDecl(ValID);
     ResultVal = Builder.createObjCProtocol(Loc, cast<ProtocolDecl>(Proto), Ty);
     break;
   }
 
-  case ValueKind::InitExistentialAddrInst:
-  case ValueKind::InitExistentialValueInst:
-  case ValueKind::InitExistentialMetatypeInst:
-  case ValueKind::InitExistentialRefInst:
-  case ValueKind::AllocExistentialBoxInst: {
+  case SILInstructionKind::InitExistentialAddrInst:
+  case SILInstructionKind::InitExistentialValueInst:
+  case SILInstructionKind::InitExistentialMetatypeInst:
+  case SILInstructionKind::InitExistentialRefInst:
+  case SILInstructionKind::AllocExistentialBoxInst: {
 
     auto Ty = getSILType(MF->getType(TyID), (SILValueCategory)TyCategory);
     auto Ty2 = MF->getType(TyID2);
     CanType ConcreteTy;
-    if ((ValueKind) OpCode != ValueKind::InitExistentialMetatypeInst)
+    if (OpCode != SILInstructionKind::InitExistentialMetatypeInst)
       ConcreteTy = MF->getType(ConcreteTyID)->getCanonicalType();
     SILValue operand;
-    if ((ValueKind) OpCode != ValueKind::AllocExistentialBoxInst)
+    if (OpCode != SILInstructionKind::AllocExistentialBoxInst)
       operand = getLocalValue(ValID,
                          getSILType(Ty2, (SILValueCategory)TyCategory2));
 
@@ -1003,37 +1001,37 @@
 
     auto ctxConformances = MF->getContext().AllocateCopy(conformances);
 
-    switch ((ValueKind)OpCode) {
+    switch (OpCode) {
     default: llvm_unreachable("Out of sync with parent switch");
-    case ValueKind::InitExistentialAddrInst:
+    case SILInstructionKind::InitExistentialAddrInst:
       ResultVal = Builder.createInitExistentialAddr(Loc, operand,
                                                 ConcreteTy,
                                                 Ty,
                                                 ctxConformances);
       break;
-    case ValueKind::InitExistentialValueInst:
+    case SILInstructionKind::InitExistentialValueInst:
       ResultVal = Builder.createInitExistentialValue(Loc, Ty, ConcreteTy,
                                                       operand, ctxConformances);
       break;
-    case ValueKind::InitExistentialMetatypeInst:
+    case SILInstructionKind::InitExistentialMetatypeInst:
       ResultVal = Builder.createInitExistentialMetatype(Loc, operand, Ty,
                                                         ctxConformances);
       break;
-    case ValueKind::InitExistentialRefInst:
+    case SILInstructionKind::InitExistentialRefInst:
       ResultVal = Builder.createInitExistentialRef(Loc, Ty,
                                          ConcreteTy,
                                          operand,
                                          ctxConformances);
       break;
-    case ValueKind::AllocExistentialBoxInst:
+    case SILInstructionKind::AllocExistentialBoxInst:
       ResultVal = Builder.createAllocExistentialBox(Loc, Ty, ConcreteTy,
                                   ctxConformances);
       break;
     }
     break;
   }
-  case ValueKind::AllocRefInst:
-  case ValueKind::AllocRefDynamicInst: {
+  case SILInstructionKind::AllocRefInst:
+  case SILInstructionKind::AllocRefDynamicInst: {
     assert(RecordKind == SIL_ONE_TYPE_VALUES &&
            "Layout should be OneTypeValues.");
     unsigned NumVals = ListOfValues.size();
@@ -1054,7 +1052,7 @@
       SILValue CountVal = getLocalValue(ListOfValues[i+1], CountType);
       Counts.push_back(CountVal);
     }
-    if ((ValueKind)OpCode == ValueKind::AllocRefDynamicInst) {
+    if (OpCode == SILInstructionKind::AllocRefDynamicInst) {
       assert(i + 2 == NumVals);
       assert(!canAllocOnStack);
       SILType MetadataType = getSILType(MF->getType(ListOfValues[i+1]),
@@ -1069,7 +1067,7 @@
     }
     break;
   }
-  case ValueKind::ApplyInst: {
+  case SILInstructionKind::ApplyInst: {
     // Format: attributes such as transparent, the callee's type, a value for
     // the callee and a list of values for the arguments. Each value in the list
     // is represented with 2 IDs: ValueID and ValueResultNumber.
@@ -1099,7 +1097,7 @@
                                     IsNonThrowingApply != 0);
     break;
   }
-  case ValueKind::TryApplyInst: {
+  case SILInstructionKind::TryApplyInst: {
     // Format: attributes such as transparent, the callee's type, a value for
     // the callee and a list of values for the arguments. Each value in the list
     // is represented with 2 IDs: ValueID and ValueResultNumber.  The final
@@ -1135,7 +1133,7 @@
                                        Substitutions, Args, normalBB, errorBB);
     break;
   }
-  case ValueKind::PartialApplyInst: {
+  case SILInstructionKind::PartialApplyInst: {
     auto Ty = MF->getType(TyID);
     auto Ty2 = MF->getType(TyID2);
     SILType FnTy = getSILType(Ty, SILValueCategory::Object);
@@ -1172,7 +1170,7 @@
         closureTy.getAs<SILFunctionType>()->getCalleeConvention());
     break;
   }
-  case ValueKind::BuiltinInst: {
+  case SILInstructionKind::BuiltinInst: {
     auto ASTTy = MF->getType(TyID);
     auto ResultTy = getSILType(ASTTy, (SILValueCategory)(unsigned)TyID2);
     SmallVector<SILValue, 4> Args;
@@ -1195,7 +1193,7 @@
                                       Args);
     break;
   }
-  case ValueKind::AllocGlobalInst: {
+  case SILInstructionKind::AllocGlobalInst: {
     // Format: Name and type. Use SILOneOperandLayout.
     Identifier Name = MF->getIdentifier(ValID);
 
@@ -1206,8 +1204,8 @@
     ResultVal = Builder.createAllocGlobal(Loc, g);
     break;
   }
-  case ValueKind::GlobalAddrInst:
-  case ValueKind::GlobalValueInst: {
+  case SILInstructionKind::GlobalAddrInst:
+  case SILInstructionKind::GlobalValueInst: {
     // Format: Name and type. Use SILOneOperandLayout.
     auto Ty = MF->getType(TyID);
     Identifier Name = MF->getIdentifier(ValID);
@@ -1215,27 +1213,27 @@
     // Find the global variable.
     SILGlobalVariable *g = getGlobalForReference(Name.str());
     assert(g && "Can't deserialize global variable");
-    SILType expectedType = ((ValueKind)OpCode == ValueKind::GlobalAddrInst ?
+    SILType expectedType = (OpCode == SILInstructionKind::GlobalAddrInst ?
                             g->getLoweredType().getAddressType() :
                             g->getLoweredType());
     assert(expectedType == getSILType(Ty, (SILValueCategory)TyCategory) &&
            "Type of a global variable does not match GlobalAddr.");
     (void)Ty;
-    if ((ValueKind)OpCode == ValueKind::GlobalAddrInst) {
+    if (OpCode == SILInstructionKind::GlobalAddrInst) {
       ResultVal = Builder.createGlobalAddr(Loc, g);
     } else {
       ResultVal = Builder.createGlobalValue(Loc, g);
     }
     break;
   }
-  case ValueKind::DeallocStackInst: {
+  case SILInstructionKind::DeallocStackInst: {
     auto Ty = MF->getType(TyID);
     ResultVal = Builder.createDeallocStack(Loc,
         getLocalValue(ValID,
                       getSILType(Ty, (SILValueCategory)TyCategory)));
     break;
   }
-  case ValueKind::DeallocRefInst: {
+  case SILInstructionKind::DeallocRefInst: {
     auto Ty = MF->getType(TyID);
     bool OnStack = (bool)Attr;
     ResultVal = Builder.createDeallocRef(Loc,
@@ -1243,7 +1241,7 @@
                       getSILType(Ty, (SILValueCategory)TyCategory)), OnStack);
     break;
   }
-  case ValueKind::DeallocPartialRefInst: {
+  case SILInstructionKind::DeallocPartialRefInst: {
     auto Ty = MF->getType(TyID);
     auto Ty2 = MF->getType(TyID2);
     ResultVal = Builder.createDeallocPartialRef(Loc,
@@ -1253,7 +1251,7 @@
                       getSILType(Ty2,  (SILValueCategory)TyCategory2)));
     break;
   }
-  case ValueKind::FunctionRefInst: {
+  case SILInstructionKind::FunctionRefInst: {
     auto Ty = MF->getType(TyID);
     Identifier FuncName = MF->getIdentifier(ValID);
     ResultVal = Builder.createFunctionRef(Loc,
@@ -1261,7 +1259,7 @@
                             getSILType(Ty, (SILValueCategory)TyCategory)));
     break;
   }
-  case ValueKind::MarkDependenceInst: {
+  case SILInstructionKind::MarkDependenceInst: {
     auto Ty = MF->getType(TyID);
     auto Ty2 = MF->getType(TyID2);
     ResultVal = Builder.createMarkDependence(Loc,
@@ -1271,7 +1269,7 @@
                       getSILType(Ty2,  (SILValueCategory)TyCategory2)));
     break;
   }
-  case ValueKind::IndexAddrInst: {
+  case SILInstructionKind::IndexAddrInst: {
     auto Ty = MF->getType(TyID);
     auto Ty2 = MF->getType(TyID2);
     ResultVal = Builder.createIndexAddr(Loc,
@@ -1281,7 +1279,7 @@
                       getSILType(Ty2,  (SILValueCategory)TyCategory2)));
     break;
   }
-  case ValueKind::TailAddrInst: {
+  case SILInstructionKind::TailAddrInst: {
     auto Ty = MF->getType(TyID);
     auto Ty2 = MF->getType(TyID2);
     auto ResultTy = MF->getType(TyID3);
@@ -1291,7 +1289,7 @@
         getSILType(ResultTy, SILValueCategory::Address));
     break;
   }
-  case ValueKind::IndexRawPointerInst: {
+  case SILInstructionKind::IndexRawPointerInst: {
     auto Ty = MF->getType(TyID);
     auto Ty2 = MF->getType(TyID2);
     ResultVal = Builder.createIndexRawPointer(Loc,
@@ -1301,7 +1299,7 @@
                       getSILType(Ty2,  (SILValueCategory)TyCategory2)));
     break;
   }
-  case ValueKind::IntegerLiteralInst: {
+  case SILInstructionKind::IntegerLiteralInst: {
     auto Ty = MF->getType(TyID);
     auto intTy = Ty->getAs<BuiltinIntegerType>();
     Identifier StringVal = MF->getIdentifier(ValID);
@@ -1312,7 +1310,7 @@
         value);
     break;
   }
-  case ValueKind::FloatLiteralInst: {
+  case SILInstructionKind::FloatLiteralInst: {
     auto Ty = MF->getType(TyID);
     auto floatTy = Ty->getAs<BuiltinFloatType>();
     Identifier StringVal = MF->getIdentifier(ValID);
@@ -1328,7 +1326,7 @@
         value);
     break;
   }
-  case ValueKind::StringLiteralInst: {
+  case SILInstructionKind::StringLiteralInst: {
     Identifier StringVal = MF->getIdentifier(ValID);
     auto encoding = fromStableStringEncoding(Attr);
     if (!encoding) return true;
@@ -1336,7 +1334,7 @@
                                             encoding.getValue());
     break;
   }
-  case ValueKind::ConstStringLiteralInst: {
+  case SILInstructionKind::ConstStringLiteralInst: {
     Identifier StringVal = MF->getIdentifier(ValID);
     auto encoding = fromStableConstStringEncoding(Attr);
     if (!encoding)
@@ -1345,7 +1343,7 @@
                                                  encoding.getValue());
     break;
   }
-  case ValueKind::MarkFunctionEscapeInst: {
+  case SILInstructionKind::MarkFunctionEscapeInst: {
     // Format: a list of typed values. A typed value is expressed by 4 IDs:
     // TypeID, TypeCategory, ValueID, ValueResultNumber.
     SmallVector<SILValue, 4> OpList;
@@ -1359,7 +1357,7 @@
     break;
   }
   // Checked Conversion instructions.
-  case ValueKind::UnconditionalCheckedCastInst: {
+  case SILInstructionKind::UnconditionalCheckedCastInst: {
     SILValue Val = getLocalValue(ValID,
                  getSILType(MF->getType(TyID2), (SILValueCategory)TyCategory2));
     SILType Ty = getSILType(MF->getType(TyID), (SILValueCategory)TyCategory);
@@ -1368,7 +1366,7 @@
   }
 
 #define UNARY_INSTRUCTION(ID) \
-  case ValueKind::ID##Inst:                   \
+  case SILInstructionKind::ID##Inst:                   \
     assert(RecordKind == SIL_ONE_OPERAND &&            \
            "Layout should be OneOperand.");            \
     ResultVal = Builder.create##ID(Loc, getLocalValue(ValID,  \
@@ -1377,7 +1375,7 @@
    break;
 
 #define REFCOUNTING_INSTRUCTION(ID) \
-  case ValueKind::ID##Inst:                   \
+  case SILInstructionKind::ID##Inst:                   \
     assert(RecordKind == SIL_ONE_OPERAND &&            \
            "Layout should be OneOperand.");            \
     ResultVal = Builder.create##ID(Loc, getLocalValue(ValID,  \
@@ -1423,7 +1421,7 @@
 #undef UNARY_INSTRUCTION
 #undef REFCOUNTING_INSTRUCTION
 
-  case ValueKind::UncheckedOwnershipConversionInst: {
+  case SILInstructionKind::UncheckedOwnershipConversionInst: {
     auto Ty = MF->getType(TyID);
     auto ResultKind = ValueOwnershipKind(Attr);
     ResultVal = Builder.createUncheckedOwnershipConversion(
@@ -1432,7 +1430,7 @@
     break;
   }
 
-  case ValueKind::LoadInst: {
+  case SILInstructionKind::LoadInst: {
     auto Ty = MF->getType(TyID);
     auto Qualifier = LoadOwnershipQualifier(Attr);
     ResultVal = Builder.createLoad(
@@ -1441,7 +1439,7 @@
     break;
   }
 
-  case ValueKind::LoadUnownedInst: {
+  case SILInstructionKind::LoadUnownedInst: {
     auto Ty = MF->getType(TyID);
     bool isTake = (Attr > 0);
     ResultVal = Builder.createLoadUnowned(Loc,
@@ -1450,7 +1448,7 @@
         IsTake_t(isTake));
     break;
   }
-  case ValueKind::LoadWeakInst: {
+  case SILInstructionKind::LoadWeakInst: {
     auto Ty = MF->getType(TyID);
     bool isTake = (Attr > 0);
     ResultVal = Builder.createLoadWeak(Loc,
@@ -1459,14 +1457,14 @@
         IsTake_t(isTake));
     break;
   }
-  case ValueKind::MarkUninitializedInst: {
+  case SILInstructionKind::MarkUninitializedInst: {
     auto Ty = getSILType(MF->getType(TyID), (SILValueCategory)TyCategory);
     auto Kind = (MarkUninitializedInst::Kind)Attr;
     auto Val = getLocalValue(ValID, Ty);
     ResultVal = Builder.createMarkUninitialized(Loc, Val, Kind);
     break;
   }
-  case ValueKind::StoreInst: {
+  case SILInstructionKind::StoreInst: {
     auto Ty = MF->getType(TyID);
     SILType addrType = getSILType(Ty, (SILValueCategory)TyCategory);
     SILType ValType = addrType.getObjectType();
@@ -1475,7 +1473,7 @@
                                     getLocalValue(ValID2, addrType), Qualifier);
     break;
   }
-  case ValueKind::StoreBorrowInst: {
+  case SILInstructionKind::StoreBorrowInst: {
     auto Ty = MF->getType(TyID);
     SILType addrType = getSILType(Ty, (SILValueCategory)TyCategory);
     SILType ValType = addrType.getObjectType();
@@ -1483,7 +1481,7 @@
                                           getLocalValue(ValID2, addrType));
     break;
   }
-  case ValueKind::EndBorrowInst: {
+  case SILInstructionKind::EndBorrowInst: {
     SILValue BorrowSource, BorrowDest;
     BorrowSource = getLocalValue(
         ValID, getSILType(MF->getType(TyID), (SILValueCategory)TyCategory));
@@ -1492,7 +1490,7 @@
     ResultVal = Builder.createEndBorrow(Loc, BorrowSource, BorrowDest);
     break;
   }
-  case ValueKind::BeginAccessInst: {
+  case SILInstructionKind::BeginAccessInst: {
     SILValue op = getLocalValue(
         ValID, getSILType(MF->getType(TyID), (SILValueCategory)TyCategory));
     auto accessKind = SILAccessKind(Attr & 0x3);
@@ -1500,14 +1498,14 @@
     ResultVal = Builder.createBeginAccess(Loc, op, accessKind, enforcement);
     break;
   }
-  case ValueKind::EndAccessInst: {
+  case SILInstructionKind::EndAccessInst: {
     SILValue op = getLocalValue(
         ValID, getSILType(MF->getType(TyID), (SILValueCategory)TyCategory));
     bool aborted = Attr & 0x1;
     ResultVal = Builder.createEndAccess(Loc, op, aborted);
     break;
   }
-  case ValueKind::BeginUnpairedAccessInst: {
+  case SILInstructionKind::BeginUnpairedAccessInst: {
     SILValue source = getLocalValue(
         ValID, getSILType(MF->getType(TyID), (SILValueCategory)TyCategory));
     SILValue buffer = getLocalValue(
@@ -1518,7 +1516,7 @@
                                                   accessKind, enforcement);
     break;
   }
-  case ValueKind::EndUnpairedAccessInst: {
+  case SILInstructionKind::EndUnpairedAccessInst: {
     SILValue op = getLocalValue(
         ValID, getSILType(MF->getType(TyID), (SILValueCategory)TyCategory));
     bool aborted = Attr & 0x1;
@@ -1526,7 +1524,7 @@
     ResultVal = Builder.createEndUnpairedAccess(Loc, op, enforcement, aborted);
     break;
   }
-  case ValueKind::StoreUnownedInst: {
+  case SILInstructionKind::StoreUnownedInst: {
     auto Ty = MF->getType(TyID);
     SILType addrType = getSILType(Ty, (SILValueCategory)TyCategory);
     auto refType = addrType.getAs<WeakStorageType>();
@@ -1538,7 +1536,7 @@
                     IsInitialization_t(isInit));
     break;
   }
-  case ValueKind::StoreWeakInst: {
+  case SILInstructionKind::StoreWeakInst: {
     auto Ty = MF->getType(TyID);
     SILType addrType = getSILType(Ty, (SILValueCategory)TyCategory);
     auto refType = addrType.getAs<WeakStorageType>();
@@ -1550,7 +1548,7 @@
                     IsInitialization_t(isInit));
     break;
   }
-  case ValueKind::CopyAddrInst: {
+  case SILInstructionKind::CopyAddrInst: {
     auto Ty = MF->getType(TyID);
     SILType addrType = getSILType(Ty, (SILValueCategory)TyCategory);
     bool isInit = (Attr & 0x2) > 0;
@@ -1562,7 +1560,7 @@
                     IsInitialization_t(isInit));
     break;
   }
-  case ValueKind::AssignInst: {
+  case SILInstructionKind::AssignInst: {
     auto Ty = MF->getType(TyID);
     SILType addrType = getSILType(Ty, (SILValueCategory)TyCategory);
     SILType ValType = addrType.getObjectType();
@@ -1571,7 +1569,7 @@
                     getLocalValue(ValID2, addrType));
     break;
   }
-  case ValueKind::BindMemoryInst: {
+  case SILInstructionKind::BindMemoryInst: {
     assert(RecordKind == SIL_ONE_TYPE_VALUES &&
            "Layout should be OneTypeValues.");
     auto Ty = MF->getType(TyID);   // BoundTy
@@ -1586,15 +1584,15 @@
       getSILType(Ty, (SILValueCategory)TyCategory));
     break;
   }
-  case ValueKind::StructElementAddrInst:
-  case ValueKind::StructExtractInst: {
+  case SILInstructionKind::StructElementAddrInst:
+  case SILInstructionKind::StructExtractInst: {
     // Use SILOneValueOneOperandLayout.
     VarDecl *Field = cast<VarDecl>(MF->getDecl(ValID));
     auto Ty = MF->getType(TyID);
     auto Val = getLocalValue(ValID2,
                              getSILType(Ty, (SILValueCategory)TyCategory));
     auto ResultTy = Val->getType().getFieldType(Field, SILMod);
-    if ((ValueKind)OpCode == ValueKind::StructElementAddrInst)
+    if (OpCode == SILInstructionKind::StructElementAddrInst)
       ResultVal = Builder.createStructElementAddr(Loc, Val, Field,
                                                   ResultTy.getAddressType());
     else
@@ -1602,7 +1600,7 @@
                                               ResultTy.getObjectType());
     break;
   }
-  case ValueKind::StructInst: {
+  case SILInstructionKind::StructInst: {
     // Format: a type followed by a list of typed values. A typed value is
     // expressed by 4 IDs: TypeID, TypeCategory, ValueID, ValueResultNumber.
     auto Ty = MF->getType(TyID);
@@ -1618,22 +1616,22 @@
                     OpList);
     break;
   }
-  case ValueKind::TupleElementAddrInst:
-  case ValueKind::TupleExtractInst: {
+  case SILInstructionKind::TupleElementAddrInst:
+  case SILInstructionKind::TupleExtractInst: {
     // Use OneTypeOneOperand layout where the field number is stored in TypeID.
     auto Ty2 = MF->getType(TyID2);
     SILType ST = getSILType(Ty2, (SILValueCategory)TyCategory2);
     TupleType *TT = ST.getAs<TupleType>();
 
     auto ResultTy = TT->getElement(TyID).getType();
-    switch ((ValueKind)OpCode) {
+    switch (OpCode) {
     default: llvm_unreachable("Out of sync with parent switch");
-    case ValueKind::TupleElementAddrInst:
+    case SILInstructionKind::TupleElementAddrInst:
       ResultVal = Builder.createTupleElementAddr(Loc,
                       getLocalValue(ValID, ST),
                       TyID, getSILType(ResultTy, SILValueCategory::Address));
       break;
-    case ValueKind::TupleExtractInst:
+    case SILInstructionKind::TupleExtractInst:
       ResultVal = Builder.createTupleExtract(Loc,
                                              getLocalValue(ValID,ST),
                                              TyID,
@@ -1642,7 +1640,7 @@
     }
     break;
   }
-  case ValueKind::TupleInst: {
+  case SILInstructionKind::TupleInst: {
     // Format: a type followed by a list of values. A value is expressed by
     // 2 IDs: ValueID, ValueResultNumber.
     auto Ty = MF->getType(TyID);
@@ -1660,10 +1658,10 @@
                     OpList);
     break;
   }
-  case ValueKind::ObjectInst: {
+  case SILInstructionKind::ObjectInst: {
     llvm_unreachable("Serialization of global initializers not supported");
   }
-  case ValueKind::BranchInst: {
+  case SILInstructionKind::BranchInst: {
     SmallVector<SILValue, 4> Args;
     for (unsigned I = 0, E = ListOfValues.size(); I < E; I += 3)
       Args.push_back(
@@ -1675,7 +1673,7 @@
                     Args);
     break;
   }
-  case ValueKind::CondBranchInst: {
+  case SILInstructionKind::CondBranchInst: {
     // Format: condition, true basic block ID, a list of arguments, false basic
     // block ID, a list of arguments. Use SILOneTypeValuesLayout: the type is
     // for condition, the list has value for condition, true basic block ID,
@@ -1707,8 +1705,8 @@
                     getBBForReference(Fn, ListOfValues[2]), FalseArgs);
     break;
   }
-  case ValueKind::SwitchEnumInst:
-  case ValueKind::SwitchEnumAddrInst: {
+  case SILInstructionKind::SwitchEnumInst:
+  case SILInstructionKind::SwitchEnumAddrInst: {
     // Format: condition, a list of cases (EnumElementDecl + Basic Block ID),
     // default basic block ID. Use SILOneTypeValuesLayout: the type is
     // for condition, the list has value for condition, hasDefault, default
@@ -1726,15 +1724,15 @@
       CaseBBs.push_back( {cast<EnumElementDecl>(MF->getDecl(ListOfValues[I])),
                             getBBForReference(Fn, ListOfValues[I+1])} );
     }
-    if ((ValueKind)OpCode == ValueKind::SwitchEnumInst)
+    if (OpCode == SILInstructionKind::SwitchEnumInst)
       ResultVal = Builder.createSwitchEnum(Loc, Cond, DefaultBB, CaseBBs);
     else
       ResultVal = Builder.createSwitchEnumAddr(Loc, Cond,
                       DefaultBB, CaseBBs);
     break;
   }
-  case ValueKind::SelectEnumInst:
-  case ValueKind::SelectEnumAddrInst: {
+  case SILInstructionKind::SelectEnumInst:
+  case SILInstructionKind::SelectEnumAddrInst: {
     // Format: condition, a list of cases (EnumElementDecl + Value ID),
     // default value ID. Use SILOneTypeValuesLayout: the type is
     // for condition, the list has value for condition, result type,
@@ -1758,7 +1756,7 @@
       CaseVals.push_back({cast<EnumElementDecl>(MF->getDecl(ListOfValues[I])),
                          Value});
     }
-    if ((ValueKind)OpCode == ValueKind::SelectEnumInst)
+    if (OpCode == SILInstructionKind::SelectEnumInst)
       ResultVal = Builder.createSelectEnum(Loc, Cond, ResultTy,
                                            DefaultVal, CaseVals);
     else
@@ -1766,7 +1764,7 @@
                                                DefaultVal, CaseVals);
     break;
   }
-  case ValueKind::SwitchValueInst: {
+  case SILInstructionKind::SwitchValueInst: {
     // Format: condition, a list of cases (Value ID + Basic Block ID),
     // default basic block ID. Use SILOneTypeValuesLayout: the type is
     // for condition, the list contains value for condition, hasDefault, default
@@ -1788,7 +1786,7 @@
     ResultVal = Builder.createSwitchValue(Loc, Cond, DefaultBB, CaseBBs);
     break;
   }
-  case ValueKind::SelectValueInst: {
+  case SILInstructionKind::SelectValueInst: {
     // Format: condition, a list of cases (ValueID + Value ID),
     // default value ID. Use SILOneTypeValuesLayout: the type is
     // for condition, the list has value for condition, result type,
@@ -1816,7 +1814,7 @@
                                           DefaultVal, CaseValuesAndResults);
     break;
   }  
-  case ValueKind::EnumInst: {
+  case SILInstructionKind::EnumInst: {
     // Format: a type, an operand and a decl ID. Use SILTwoOperandsLayout: type,
     // (DeclID + hasOperand), and an operand.
     SILValue Operand;
@@ -1830,7 +1828,7 @@
                                                (SILValueCategory)TyCategory));
     break;
   }
-  case ValueKind::InitEnumDataAddrInst: {
+  case SILInstructionKind::InitEnumDataAddrInst: {
     // Use SILOneValueOneOperandLayout.
     EnumElementDecl *Elt = cast<EnumElementDecl>(MF->getDecl(ValID));
     SILType OperandTy = getSILType(MF->getType(TyID),
@@ -1841,7 +1839,7 @@
                     Elt, ResultTy);
     break;
   }
-  case ValueKind::UncheckedEnumDataInst: {
+  case SILInstructionKind::UncheckedEnumDataInst: {
     // Use SILOneValueOneOperandLayout.
     EnumElementDecl *Elt = cast<EnumElementDecl>(MF->getDecl(ValID));
     SILType OperandTy = getSILType(MF->getType(TyID),
@@ -1852,7 +1850,7 @@
                     Elt, ResultTy);
     break;
   }
-  case ValueKind::UncheckedTakeEnumDataAddrInst: {
+  case SILInstructionKind::UncheckedTakeEnumDataAddrInst: {
     // Use SILOneValueOneOperandLayout.
     EnumElementDecl *Elt = cast<EnumElementDecl>(MF->getDecl(ValID));
     SILType OperandTy = getSILType(MF->getType(TyID),
@@ -1863,7 +1861,7 @@
                     Elt, ResultTy);
     break;
   }
-  case ValueKind::InjectEnumAddrInst: {
+  case SILInstructionKind::InjectEnumAddrInst: {
     // Use SILOneValueOneOperandLayout.
     EnumElementDecl *Elt = cast<EnumElementDecl>(MF->getDecl(ValID));
     auto Ty = MF->getType(TyID);
@@ -1873,7 +1871,7 @@
                     Elt);
     break;
   }
-  case ValueKind::RefElementAddrInst: {
+  case SILInstructionKind::RefElementAddrInst: {
     // Use SILOneValueOneOperandLayout.
     VarDecl *Field = cast<VarDecl>(MF->getDecl(ValID));
     auto Ty = MF->getType(TyID);
@@ -1884,7 +1882,7 @@
                                              ResultTy);
     break;
   }
-  case ValueKind::RefTailAddrInst: {
+  case SILInstructionKind::RefTailAddrInst: {
     assert(RecordKind == SIL_ONE_TYPE_ONE_OPERAND &&
            "Layout should be OneTypeOneOperand.");
     assert(Attr == 0);
@@ -1896,9 +1894,9 @@
       getSILType(MF->getType(TyID), SILValueCategory::Address));
     break;
   }
-  case ValueKind::ClassMethodInst:
-  case ValueKind::SuperMethodInst:
-  case ValueKind::DynamicMethodInst: {
+  case SILInstructionKind::ClassMethodInst:
+  case SILInstructionKind::SuperMethodInst:
+  case SILInstructionKind::DynamicMethodInst: {
     // Format: a type, an operand and a SILDeclRef. Use SILOneTypeValuesLayout:
     // type, Attr, SILDeclRef (DeclID, Kind, uncurryLevel, IsObjC),
     // and an operand.
@@ -1912,19 +1910,19 @@
     NextValueIndex += 2;
     bool IsVolatile = ListOfValues[0] > 0;
 
-    switch ((ValueKind)OpCode) {
+    switch (OpCode) {
     default: llvm_unreachable("Out of sync with parent switch");
-    case ValueKind::ClassMethodInst:
+    case SILInstructionKind::ClassMethodInst:
       ResultVal = Builder.createClassMethod(Loc,
                     getLocalValue(ListOfValues[NextValueIndex], operandTy),
                     DRef, Ty, IsVolatile);
       break;
-    case ValueKind::SuperMethodInst:
+    case SILInstructionKind::SuperMethodInst:
       ResultVal = Builder.createSuperMethod(Loc,
                     getLocalValue(ListOfValues[NextValueIndex], operandTy),
                     DRef, Ty, IsVolatile);
       break;
-    case ValueKind::DynamicMethodInst:
+    case SILInstructionKind::DynamicMethodInst:
       ResultVal = Builder.createDynamicMethod(Loc,
                     getLocalValue(ListOfValues[NextValueIndex], operandTy),
                     DRef, Ty, IsVolatile);
@@ -1932,7 +1930,7 @@
     }
     break;
   }
-  case ValueKind::WitnessMethodInst: {
+  case SILInstructionKind::WitnessMethodInst: {
     unsigned NextValueIndex = 0;
     SILDeclRef DRef = getSILDeclRef(MF, ListOfValues, NextValueIndex);
     assert(ListOfValues.size() >= NextValueIndex &&
@@ -1955,7 +1953,7 @@
         Loc, Ty, Conformance, DRef, OperandTy, Attr);
     break;
   }
-  case ValueKind::DynamicMethodBranchInst: {
+  case SILInstructionKind::DynamicMethodBranchInst: {
     // Format: a typed value, a SILDeclRef, a BasicBlock ID for method,
     // a BasicBlock ID for no method. Use SILOneTypeValuesLayout.
     unsigned NextValueIndex = 1;
@@ -1969,7 +1967,7 @@
                     getBBForReference(Fn, ListOfValues[NextValueIndex+1]));
     break;
   }
-  case ValueKind::CheckedCastBranchInst: {
+  case SILInstructionKind::CheckedCastBranchInst: {
     // Format: the cast kind, a typed value, a BasicBlock ID for success,
     // a BasicBlock ID for failure. Uses SILOneTypeValuesLayout.
     assert(ListOfValues.size() == 6 &&
@@ -1987,7 +1985,7 @@
                                                 successBB, failureBB);
     break;
   }
-  case ValueKind::CheckedCastValueBranchInst: {
+  case SILInstructionKind::CheckedCastValueBranchInst: {
     // Format: the cast kind, a typed value, a BasicBlock ID for success,
     // a BasicBlock ID for failure. Uses SILOneTypeValuesLayout.
     assert(ListOfValues.size() == 5 &&
@@ -2004,14 +2002,14 @@
                                                      failureBB);
     break;
   }
-  case ValueKind::UnconditionalCheckedCastValueInst: {
+  case SILInstructionKind::UnconditionalCheckedCastValueInst: {
     SILValue Val = getLocalValue(
         ValID, getSILType(MF->getType(TyID2), (SILValueCategory)TyCategory2));
     SILType Ty = getSILType(MF->getType(TyID), (SILValueCategory)TyCategory);
     ResultVal = Builder.createUnconditionalCheckedCastValue(Loc, Val, Ty);
     break;
   }
-  case ValueKind::UnconditionalCheckedCastAddrInst: {
+  case SILInstructionKind::UnconditionalCheckedCastAddrInst: {
     // ignore attr.
     CanType sourceType = MF->getType(ListOfValues[0])->getCanonicalType();
     SILType srcAddrTy = getSILType(MF->getType(ListOfValues[2]),
@@ -2027,7 +2025,7 @@
                                                            dest, targetType);
     break;
   }
-  case ValueKind::CheckedCastAddrBranchInst: {
+  case SILInstructionKind::CheckedCastAddrBranchInst: {
     CastConsumptionKind consumption = getCastConsumptionKind(ListOfValues[0]);
 
     CanType sourceType = MF->getType(ListOfValues[1])->getCanonicalType();
@@ -2048,7 +2046,7 @@
                                                     successBB, failureBB);
     break;
   }
-  case ValueKind::UncheckedRefCastAddrInst: {
+  case SILInstructionKind::UncheckedRefCastAddrInst: {
     CanType sourceType = MF->getType(ListOfValues[0])->getCanonicalType();
     // ignore attr.
     SILType srcAddrTy = getSILType(MF->getType(ListOfValues[2]),
@@ -2064,7 +2062,7 @@
                                                    dest, targetType);
     break;
   }
-  case ValueKind::InitBlockStorageHeaderInst: {
+  case SILInstructionKind::InitBlockStorageHeaderInst: {
     assert(ListOfValues.size() == 5 &&
            "expected 5 values for InitBlockStorageHeader");
     SILType blockTy
@@ -2093,11 +2091,11 @@
                                                      blockTy, Substitutions);
     break;
   }
-  case ValueKind::UnreachableInst: {
+  case SILInstructionKind::UnreachableInst: {
     ResultVal = Builder.createUnreachable(Loc);
     break;
   }
-  case ValueKind::KeyPathInst: {
+  case SILInstructionKind::KeyPathInst: {
     unsigned nextValue = 0;
     SILType kpTy
       = getSILType(MF->getType(TyID), (SILValueCategory)TyCategory);
@@ -2250,13 +2248,13 @@
                                       substitutions, operands, kpTy);
     break;
   }
-  case ValueKind::MarkUninitializedBehaviorInst:
+  case SILInstructionKind::MarkUninitializedBehaviorInst:
     llvm_unreachable("todo");
   }
 
-  if (ResultVal->hasValue()) {
+  for (auto result : ResultVal->getResults()) {
     LastValueID = LastValueID + 1;
-    setLocalValue(ResultVal, LastValueID);
+    setLocalValue(result, LastValueID);
   }
 
   return false;
diff --git a/lib/Serialization/SerializeSIL.cpp b/lib/Serialization/SerializeSIL.cpp
index b759524..9f6a048 100644
--- a/lib/Serialization/SerializeSIL.cpp
+++ b/lib/Serialization/SerializeSIL.cpp
@@ -226,17 +226,17 @@
     void writeSILBlock(const SILModule *SILMod);
     void writeIndexTables();
 
-    void writeConversionLikeInstruction(const SILInstruction *I);
-    void writeOneTypeLayout(ValueKind valueKind, SILType type);
-    void writeOneTypeOneOperandLayout(ValueKind valueKind,
+    void writeConversionLikeInstruction(const SingleValueInstruction *I);
+    void writeOneTypeLayout(SILInstructionKind valueKind, SILType type);
+    void writeOneTypeOneOperandLayout(SILInstructionKind valueKind,
                                       unsigned attrs,
                                       SILType type,
                                       SILValue operand);
-    void writeOneTypeOneOperandLayout(ValueKind valueKind,
+    void writeOneTypeOneOperandLayout(SILInstructionKind valueKind,
                                       unsigned attrs,
                                       CanType type,
                                       SILValue operand);
-    void writeOneOperandLayout(ValueKind valueKind,
+    void writeOneOperandLayout(SILInstructionKind valueKind,
                                unsigned attrs,
                                SILValue operand);
 
@@ -415,8 +415,8 @@
       ValueIDs[static_cast<const ValueBase*>(*I)] = ++ValueID;
 
     for (const SILInstruction &SI : BB)
-      if (SI.hasValue())
-        ValueIDs[&SI] = ++ValueID;
+      for (auto result : SI.getResults())
+        ValueIDs[result] = ++ValueID;
   }
 
   // Write SIL basic blocks in the RPOT order
@@ -501,7 +501,7 @@
   ListOfValues.push_back(addValueRef(operand));
 }
 
-void SILSerializer::writeOneTypeLayout(ValueKind valueKind,
+void SILSerializer::writeOneTypeLayout(SILInstructionKind valueKind,
                                        SILType type) {
   unsigned abbrCode = SILAbbrCodes[SILOneTypeLayout::Code];
   SILOneTypeLayout::emitRecord(Out, ScratchRecord, abbrCode,
@@ -510,7 +510,7 @@
         (unsigned)type.getCategory());
 }
 
-void SILSerializer::writeOneOperandLayout(ValueKind valueKind,
+void SILSerializer::writeOneOperandLayout(SILInstructionKind valueKind,
                                           unsigned attrs,
                                           SILValue operand) {
 
@@ -525,7 +525,7 @@
         operandRef);
 }
 
-void SILSerializer::writeOneTypeOneOperandLayout(ValueKind valueKind,
+void SILSerializer::writeOneTypeOneOperandLayout(SILInstructionKind valueKind,
                                                  unsigned attrs,
                                                  SILType type,
                                                  SILValue operand) {
@@ -541,7 +541,7 @@
         operandTypeRef, unsigned(operandType.getCategory()),
         operandRef);
 }
-void SILSerializer::writeOneTypeOneOperandLayout(ValueKind valueKind,
+void SILSerializer::writeOneTypeOneOperandLayout(SILInstructionKind valueKind,
                                                  unsigned attrs,
                                                  CanType type,
                                                  SILValue operand) {
@@ -560,7 +560,7 @@
 
 /// Write an instruction that looks exactly like a conversion: all
 /// important information is encoded in the operand and the result type.
-void SILSerializer::writeConversionLikeInstruction(const SILInstruction *I) {
+void SILSerializer::writeConversionLikeInstruction(const SingleValueInstruction *I) {
   assert(I->getNumOperands() - I->getTypeDependentOperands().size() == 1);
   writeOneTypeOneOperandLayout(I->getKind(), 0, I->getType(),
                                I->getOperand(0));
@@ -568,32 +568,27 @@
 
 void SILSerializer::writeSILInstruction(const SILInstruction &SI) {
   switch (SI.getKind()) {
-  case ValueKind::SILPHIArgument:
-  case ValueKind::SILFunctionArgument:
-  case ValueKind::SILUndef:
-    llvm_unreachable("not an instruction");
-
-  case ValueKind::ObjectInst:
+  case SILInstructionKind::ObjectInst:
     llvm_unreachable("static initializers of sil_global are not serialized");
 
-  case ValueKind::DebugValueInst:
-  case ValueKind::DebugValueAddrInst:
+  case SILInstructionKind::DebugValueInst:
+  case SILInstructionKind::DebugValueAddrInst:
     // Currently we don't serialize debug variable infos, so it doesn't make
     // sense to write the instruction at all.
     // TODO: decide if we want to serialize those instructions.
     return;
       
-  case ValueKind::UnreachableInst: {
+  case SILInstructionKind::UnreachableInst: {
     unsigned abbrCode = SILAbbrCodes[SILInstNoOperandLayout::Code];
     SILInstNoOperandLayout::emitRecord(Out, ScratchRecord, abbrCode,
                                        (unsigned)SI.getKind());
     break;
   }
-  case ValueKind::AllocExistentialBoxInst:
-  case ValueKind::InitExistentialAddrInst:
-  case ValueKind::InitExistentialValueInst:
-  case ValueKind::InitExistentialMetatypeInst:
-  case ValueKind::InitExistentialRefInst: {
+  case SILInstructionKind::AllocExistentialBoxInst:
+  case SILInstructionKind::InitExistentialAddrInst:
+  case SILInstructionKind::InitExistentialValueInst:
+  case SILInstructionKind::InitExistentialMetatypeInst:
+  case SILInstructionKind::InitExistentialRefInst: {
     SILValue operand;
     SILType Ty;
     CanType FormalConcreteType;
@@ -601,7 +596,7 @@
 
     switch (SI.getKind()) {
     default: llvm_unreachable("out of sync with parent");
-    case ValueKind::InitExistentialAddrInst: {
+    case SILInstructionKind::InitExistentialAddrInst: {
       auto &IEI = cast<InitExistentialAddrInst>(SI);
       operand = IEI.getOperand();
       Ty = IEI.getLoweredConcreteType();
@@ -609,7 +604,7 @@
       conformances = IEI.getConformances();
       break;
     }
-    case ValueKind::InitExistentialValueInst: {
+    case SILInstructionKind::InitExistentialValueInst: {
       auto &IEOI = cast<InitExistentialValueInst>(SI);
       operand = IEOI.getOperand();
       Ty = IEOI.getType();
@@ -617,7 +612,7 @@
       conformances = IEOI.getConformances();
       break;
     }
-    case ValueKind::InitExistentialRefInst: {
+    case SILInstructionKind::InitExistentialRefInst: {
       auto &IERI = cast<InitExistentialRefInst>(SI);
       operand = IERI.getOperand();
       Ty = IERI.getType();
@@ -625,14 +620,14 @@
       conformances = IERI.getConformances();
       break;
     }
-    case ValueKind::InitExistentialMetatypeInst: {
+    case SILInstructionKind::InitExistentialMetatypeInst: {
       auto &IEMI = cast<InitExistentialMetatypeInst>(SI);
       operand = IEMI.getOperand();
       Ty = IEMI.getType();
       conformances = IEMI.getConformances();
       break;
     }
-    case ValueKind::AllocExistentialBoxInst: {
+    case SILInstructionKind::AllocExistentialBoxInst: {
       auto &AEBI = cast<AllocExistentialBoxInst>(SI);
       Ty = AEBI.getExistentialType();
       FormalConcreteType = AEBI.getFormalConcreteType();
@@ -666,55 +661,55 @@
     }
     break;
   }
-  case ValueKind::DeallocValueBufferInst: {
+  case SILInstructionKind::DeallocValueBufferInst: {
     auto DVBI = cast<DeallocValueBufferInst>(&SI);
     writeOneTypeOneOperandLayout(DVBI->getKind(), 0,
                                  DVBI->getValueType(),
                                  DVBI->getOperand());
     break;
   }
-  case ValueKind::DeallocBoxInst: {
+  case SILInstructionKind::DeallocBoxInst: {
     auto DBI = cast<DeallocBoxInst>(&SI);
     writeOneTypeOneOperandLayout(DBI->getKind(), 0,
                                  DBI->getOperand()->getType(),
                                  DBI->getOperand());
     break;
   }
-  case ValueKind::DeallocExistentialBoxInst: {
+  case SILInstructionKind::DeallocExistentialBoxInst: {
     auto DBI = cast<DeallocExistentialBoxInst>(&SI);
     writeOneTypeOneOperandLayout(DBI->getKind(), 0,
                                  DBI->getConcreteType(),
                                  DBI->getOperand());
     break;
   }
-  case ValueKind::ValueMetatypeInst: {
+  case SILInstructionKind::ValueMetatypeInst: {
     auto VMI = cast<ValueMetatypeInst>(&SI);
     writeOneTypeOneOperandLayout(VMI->getKind(), 0,
                                  VMI->getType(),
                                  VMI->getOperand());
     break;
   }
-  case ValueKind::ExistentialMetatypeInst: {
+  case SILInstructionKind::ExistentialMetatypeInst: {
     auto EMI = cast<ExistentialMetatypeInst>(&SI);
     writeOneTypeOneOperandLayout(EMI->getKind(), 0,
                                  EMI->getType(),
                                  EMI->getOperand());
     break;
   }
-  case ValueKind::AllocValueBufferInst: {
+  case SILInstructionKind::AllocValueBufferInst: {
     auto AVBI = cast<AllocValueBufferInst>(&SI);
     writeOneTypeOneOperandLayout(AVBI->getKind(), 0,
                                  AVBI->getValueType(),
                                  AVBI->getOperand());
     break;
   }
-  case ValueKind::AllocBoxInst: {
+  case SILInstructionKind::AllocBoxInst: {
     const AllocBoxInst *ABI = cast<AllocBoxInst>(&SI);
     writeOneTypeLayout(ABI->getKind(), ABI->getType());
     break;
   }
-  case ValueKind::AllocRefInst:
-  case ValueKind::AllocRefDynamicInst: {
+  case SILInstructionKind::AllocRefInst:
+  case SILInstructionKind::AllocRefDynamicInst: {
     const AllocRefInstBase *ARI = cast<AllocRefInstBase>(&SI);
     unsigned abbrCode = SILAbbrCodes[SILOneTypeValuesLayout::Code];
     SmallVector<ValueID, 4> Args;
@@ -724,7 +719,7 @@
     ArrayRef<Operand> AllOps = ARI->getAllOperands();
     unsigned NumTailAllocs = TailTypes.size();
     unsigned NumOpsToWrite = NumTailAllocs;
-    if (SI.getKind() == ValueKind::AllocRefDynamicInst)
+    if (SI.getKind() == SILInstructionKind::AllocRefDynamicInst)
       ++NumOpsToWrite;
     for (unsigned Idx = 0; Idx < NumOpsToWrite; ++Idx) {
       if (Idx < NumTailAllocs) {
@@ -745,19 +740,19 @@
                                        Args);
     break;
   }
-  case ValueKind::AllocStackInst: {
+  case SILInstructionKind::AllocStackInst: {
     const AllocStackInst *ASI = cast<AllocStackInst>(&SI);
     writeOneTypeLayout(ASI->getKind(), ASI->getElementType());
     break;
   }
-  case ValueKind::ProjectValueBufferInst: {
+  case SILInstructionKind::ProjectValueBufferInst: {
     auto PVBI = cast<ProjectValueBufferInst>(&SI);
     writeOneTypeOneOperandLayout(PVBI->getKind(), 0,
                                  PVBI->getType(),
                                  PVBI->getOperand());
     break;
   }
-  case ValueKind::ProjectBoxInst: {
+  case SILInstructionKind::ProjectBoxInst: {
     auto PBI = cast<ProjectBoxInst>(&SI);
     
     // Use SILOneTypeOneOperandLayout with the field index crammed in the TypeID
@@ -774,14 +769,14 @@
           boxRef);
     break;
   }
-  case ValueKind::ProjectExistentialBoxInst: {
+  case SILInstructionKind::ProjectExistentialBoxInst: {
     auto PEBI = cast<ProjectExistentialBoxInst>(&SI);
     writeOneTypeOneOperandLayout(PEBI->getKind(), 0,
                                  PEBI->getType(),
                                  PEBI->getOperand());
     break;
   }
-  case ValueKind::BuiltinInst: {
+  case SILInstructionKind::BuiltinInst: {
     // Format: number of substitutions, the builtin name, result type, and
     // a list of values for the arguments. Each value in the list
     // is represented with 4 IDs:
@@ -805,7 +800,7 @@
     S.writeSubstitutions(BI->getSubstitutions(), SILAbbrCodes);
     break;
   }
-  case ValueKind::ApplyInst: {
+  case SILInstructionKind::ApplyInst: {
     // Format: attributes such as transparent and number of substitutions,
     // the callee's substituted and unsubstituted types, a value for
     // the callee and a list of values for the arguments. Each value in the list
@@ -827,7 +822,7 @@
     S.writeSubstitutions(AI->getSubstitutions(), SILAbbrCodes);
     break;
   }
-  case ValueKind::TryApplyInst: {
+  case SILInstructionKind::TryApplyInst: {
     // Format: attributes such as transparent and number of substitutions,
     // the callee's substituted and unsubstituted types, a value for
     // the callee and a list of values for the arguments. Each value in the list
@@ -851,7 +846,7 @@
     S.writeSubstitutions(AI->getSubstitutions(), SILAbbrCodes);
     break;
   }
-  case ValueKind::PartialApplyInst: {
+  case SILInstructionKind::PartialApplyInst: {
     const PartialApplyInst *PAI = cast<PartialApplyInst>(&SI);
         SmallVector<ValueID, 4> Args;
     for (auto Arg: PAI->getArguments()) {
@@ -867,7 +862,7 @@
     S.writeSubstitutions(PAI->getSubstitutions(), SILAbbrCodes);
     break;
   }
-  case ValueKind::AllocGlobalInst: {
+  case SILInstructionKind::AllocGlobalInst: {
     // Format: Name and type. Use SILOneOperandLayout.
     const AllocGlobalInst *AGI = cast<AllocGlobalInst>(&SI);
     SILOneOperandLayout::emitRecord(Out, ScratchRecord,
@@ -877,8 +872,8 @@
             Ctx.getIdentifier(AGI->getReferencedGlobal()->getName())));
     break;
   }
-  case ValueKind::GlobalAddrInst:
-  case ValueKind::GlobalValueInst: {
+  case SILInstructionKind::GlobalAddrInst:
+  case SILInstructionKind::GlobalValueInst: {
     // Format: Name and type. Use SILOneOperandLayout.
     const GlobalAccessInst *GI = cast<GlobalAccessInst>(&SI);
     SILOneOperandLayout::emitRecord(Out, ScratchRecord,
@@ -890,7 +885,7 @@
             Ctx.getIdentifier(GI->getReferencedGlobal()->getName())));
     break;
   }
-  case ValueKind::BranchInst: {
+  case SILInstructionKind::BranchInst: {
     // Format: destination basic block ID, a list of arguments. Use
     // SILOneTypeValuesLayout.
     const BranchInst *BrI = cast<BranchInst>(&SI);
@@ -907,7 +902,7 @@
         BasicBlockMap[BrI->getDestBB()], 0, ListOfValues);
     break;
   }
-  case ValueKind::CondBranchInst: {
+  case SILInstructionKind::CondBranchInst: {
     // Format: condition, true basic block ID, a list of arguments, false basic
     // block ID, a list of arguments. Use SILOneTypeValuesLayout: the type is
     // for condition, the list has value for condition, true basic block ID,
@@ -938,8 +933,8 @@
         ListOfValues);
     break;
   }
-  case ValueKind::SwitchEnumInst:
-  case ValueKind::SwitchEnumAddrInst: {
+  case SILInstructionKind::SwitchEnumInst:
+  case SILInstructionKind::SwitchEnumAddrInst: {
     // Format: condition, a list of cases (EnumElementDecl + Basic Block ID),
     // default basic block ID. Use SILOneTypeValuesLayout: the type is
     // for condition, the list has value for condition, hasDefault, default
@@ -968,8 +963,8 @@
         ListOfValues);
     break;
   }
-  case ValueKind::SelectEnumInst:
-  case ValueKind::SelectEnumAddrInst: {
+  case SILInstructionKind::SelectEnumInst:
+  case SILInstructionKind::SelectEnumAddrInst: {
     // Format: condition, a list of cases (EnumElementDecl + Value ID),
     // default value ID. Use SILOneTypeValuesLayout: the type is
     // for condition, the list has value for condition, result type,
@@ -1001,7 +996,7 @@
         ListOfValues);
     break;
   }
-  case ValueKind::SwitchValueInst: {
+  case SILInstructionKind::SwitchValueInst: {
     // Format: condition, a list of cases (Value ID + Basic Block ID),
     // default basic block ID. Use SILOneTypeValuesLayout: the type is
     // for condition, the list contains value for condition, hasDefault, default
@@ -1030,7 +1025,7 @@
         ListOfValues);
     break;
   }
-  case ValueKind::SelectValueInst: {
+  case SILInstructionKind::SelectValueInst: {
     // Format: condition, a list of cases (Value ID + Value ID),
     // default value ID. Use SILOneTypeValuesLayout: the type is
     // for condition, the list has value for condition, result type,
@@ -1062,47 +1057,47 @@
         ListOfValues);
     break;
   }
-  case ValueKind::CondFailInst:
-  case ValueKind::RetainValueInst:
-  case ValueKind::RetainValueAddrInst:
-  case ValueKind::UnmanagedRetainValueInst:
-  case ValueKind::EndBorrowArgumentInst:
-  case ValueKind::CopyValueInst:
-  case ValueKind::CopyUnownedValueInst:
-  case ValueKind::DestroyValueInst:
-  case ValueKind::ReleaseValueInst:
-  case ValueKind::ReleaseValueAddrInst:
-  case ValueKind::UnmanagedReleaseValueInst:
-  case ValueKind::AutoreleaseValueInst:
-  case ValueKind::UnmanagedAutoreleaseValueInst:
-  case ValueKind::SetDeallocatingInst:
-  case ValueKind::DeallocStackInst:
-  case ValueKind::DeallocRefInst:
-  case ValueKind::DeinitExistentialAddrInst:
-  case ValueKind::DeinitExistentialValueInst:
-  case ValueKind::DestroyAddrInst:
-  case ValueKind::IsNonnullInst:
-  case ValueKind::LoadInst:
-  case ValueKind::LoadBorrowInst:
-  case ValueKind::BeginBorrowInst:
-  case ValueKind::LoadUnownedInst:
-  case ValueKind::LoadWeakInst:
-  case ValueKind::MarkUninitializedInst:
-  case ValueKind::FixLifetimeInst:
-  case ValueKind::EndLifetimeInst:
-  case ValueKind::CopyBlockInst:
-  case ValueKind::StrongPinInst:
-  case ValueKind::StrongReleaseInst:
-  case ValueKind::StrongRetainInst:
-  case ValueKind::StrongUnpinInst:
-  case ValueKind::StrongRetainUnownedInst:
-  case ValueKind::UnownedRetainInst:
-  case ValueKind::UnownedReleaseInst:
-  case ValueKind::IsUniqueInst:
-  case ValueKind::IsUniqueOrPinnedInst:
-  case ValueKind::ReturnInst:
-  case ValueKind::UncheckedOwnershipConversionInst:
-  case ValueKind::ThrowInst: {
+  case SILInstructionKind::CondFailInst:
+  case SILInstructionKind::RetainValueInst:
+  case SILInstructionKind::RetainValueAddrInst:
+  case SILInstructionKind::UnmanagedRetainValueInst:
+  case SILInstructionKind::EndBorrowArgumentInst:
+  case SILInstructionKind::CopyValueInst:
+  case SILInstructionKind::CopyUnownedValueInst:
+  case SILInstructionKind::DestroyValueInst:
+  case SILInstructionKind::ReleaseValueInst:
+  case SILInstructionKind::ReleaseValueAddrInst:
+  case SILInstructionKind::UnmanagedReleaseValueInst:
+  case SILInstructionKind::AutoreleaseValueInst:
+  case SILInstructionKind::UnmanagedAutoreleaseValueInst:
+  case SILInstructionKind::SetDeallocatingInst:
+  case SILInstructionKind::DeallocStackInst:
+  case SILInstructionKind::DeallocRefInst:
+  case SILInstructionKind::DeinitExistentialAddrInst:
+  case SILInstructionKind::DeinitExistentialValueInst:
+  case SILInstructionKind::DestroyAddrInst:
+  case SILInstructionKind::IsNonnullInst:
+  case SILInstructionKind::LoadInst:
+  case SILInstructionKind::LoadBorrowInst:
+  case SILInstructionKind::BeginBorrowInst:
+  case SILInstructionKind::LoadUnownedInst:
+  case SILInstructionKind::LoadWeakInst:
+  case SILInstructionKind::MarkUninitializedInst:
+  case SILInstructionKind::FixLifetimeInst:
+  case SILInstructionKind::EndLifetimeInst:
+  case SILInstructionKind::CopyBlockInst:
+  case SILInstructionKind::StrongPinInst:
+  case SILInstructionKind::StrongReleaseInst:
+  case SILInstructionKind::StrongRetainInst:
+  case SILInstructionKind::StrongUnpinInst:
+  case SILInstructionKind::StrongRetainUnownedInst:
+  case SILInstructionKind::UnownedRetainInst:
+  case SILInstructionKind::UnownedReleaseInst:
+  case SILInstructionKind::IsUniqueInst:
+  case SILInstructionKind::IsUniqueOrPinnedInst:
+  case SILInstructionKind::ReturnInst:
+  case SILInstructionKind::UncheckedOwnershipConversionInst:
+  case SILInstructionKind::ThrowInst: {
     unsigned Attr = 0;
     if (auto *LI = dyn_cast<LoadInst>(&SI))
       Attr = unsigned(LI->getOwnershipQualifier());
@@ -1116,13 +1111,15 @@
       Attr = (unsigned)DRI->canAllocOnStack();
     else if (auto *RCI = dyn_cast<RefCountingInst>(&SI))
       Attr = RCI->isNonAtomic();
+    else if (auto *RCI = dyn_cast<StrongPinInst>(&SI))
+      Attr = RCI->isNonAtomic();
     else if (auto *UOCI = dyn_cast<UncheckedOwnershipConversionInst>(&SI)) {
       Attr = unsigned(SILValue(UOCI).getOwnershipKind());
     }
     writeOneOperandLayout(SI.getKind(), Attr, SI.getOperand(0));
     break;
   }
-  case ValueKind::FunctionRefInst: {
+  case SILInstructionKind::FunctionRefInst: {
     // Use SILOneOperandLayout to specify the function type and the function
     // name (IdentifierID).
     const FunctionRefInst *FRI = cast<FunctionRefInst>(&SI);
@@ -1136,21 +1133,21 @@
 
     break;
   }
-  case ValueKind::DeallocPartialRefInst:
-  case ValueKind::MarkDependenceInst:
-  case ValueKind::IndexAddrInst:
-  case ValueKind::IndexRawPointerInst: {
+  case SILInstructionKind::DeallocPartialRefInst:
+  case SILInstructionKind::MarkDependenceInst:
+  case SILInstructionKind::IndexAddrInst:
+  case SILInstructionKind::IndexRawPointerInst: {
     SILValue operand, operand2;
     unsigned Attr = 0;
-    if (SI.getKind() == ValueKind::DeallocPartialRefInst) {
+    if (SI.getKind() == SILInstructionKind::DeallocPartialRefInst) {
       const DeallocPartialRefInst *DPRI = cast<DeallocPartialRefInst>(&SI);
       operand = DPRI->getInstance();
       operand2 = DPRI->getMetatype();
-    } else if (SI.getKind() == ValueKind::IndexRawPointerInst) {
+    } else if (SI.getKind() == SILInstructionKind::IndexRawPointerInst) {
       const IndexRawPointerInst *IRP = cast<IndexRawPointerInst>(&SI);
       operand = IRP->getBase();
       operand2 = IRP->getIndex();
-    } else if (SI.getKind() == ValueKind::MarkDependenceInst) {
+    } else if (SI.getKind() == SILInstructionKind::MarkDependenceInst) {
       const MarkDependenceInst *MDI = cast<MarkDependenceInst>(&SI);
       operand = MDI->getValue();
       operand2 = MDI->getBase();
@@ -1170,7 +1167,7 @@
         addValueRef(operand2));
     break;
   }
-  case ValueKind::TailAddrInst: {
+  case SILInstructionKind::TailAddrInst: {
     const TailAddrInst *TAI = cast<TailAddrInst>(&SI);
     SILTailAddrLayout::emitRecord(Out, ScratchRecord,
         SILAbbrCodes[SILTailAddrLayout::Code],
@@ -1182,7 +1179,7 @@
         S.addTypeRef(TAI->getTailType().getSwiftRValueType()));
     break;
   }
-  case ValueKind::StringLiteralInst: {
+  case SILInstructionKind::StringLiteralInst: {
     auto SLI = cast<StringLiteralInst>(&SI);
     StringRef Str = SLI->getValue();
     unsigned abbrCode = SILAbbrCodes[SILOneOperandLayout::Code];
@@ -1192,7 +1189,7 @@
                                     S.addDeclBaseNameRef(Ctx.getIdentifier(Str)));
     break;
   }
-  case ValueKind::ConstStringLiteralInst: {
+  case SILInstructionKind::ConstStringLiteralInst: {
     auto SLI = cast<ConstStringLiteralInst>(&SI);
     StringRef Str = SLI->getValue();
     unsigned abbrCode = SILAbbrCodes[SILOneOperandLayout::Code];
@@ -1202,18 +1199,18 @@
                                     S.addDeclBaseNameRef(Ctx.getIdentifier(Str)));
     break;
   }
-  case ValueKind::FloatLiteralInst:
-  case ValueKind::IntegerLiteralInst: {
+  case SILInstructionKind::FloatLiteralInst:
+  case SILInstructionKind::IntegerLiteralInst: {
     // Use SILOneOperandLayout to specify the type and the literal.
     std::string Str;
     SILType Ty;
     switch (SI.getKind()) {
     default: llvm_unreachable("Out of sync with parent switch");
-    case ValueKind::IntegerLiteralInst:
+    case SILInstructionKind::IntegerLiteralInst:
       Str = cast<IntegerLiteralInst>(&SI)->getValue().toString(10, true);
       Ty = cast<IntegerLiteralInst>(&SI)->getType();
       break;
-    case ValueKind::FloatLiteralInst:
+    case SILInstructionKind::FloatLiteralInst:
       Str = cast<FloatLiteralInst>(&SI)->getBits().toString(16,
                                                             /*Signed*/false);
       Ty = cast<FloatLiteralInst>(&SI)->getType();
@@ -1227,7 +1224,7 @@
         S.addDeclBaseNameRef(Ctx.getIdentifier(Str)));
     break;
   }
-  case ValueKind::MarkFunctionEscapeInst: {
+  case SILInstructionKind::MarkFunctionEscapeInst: {
     // Format: a list of typed values. A typed value is expressed by 4 IDs:
     // TypeID, TypeCategory, ValueID, ValueResultNumber.
     const MarkFunctionEscapeInst *MFE = cast<MarkFunctionEscapeInst>(&SI);
@@ -1243,10 +1240,12 @@
         (unsigned)SI.getKind(), 0, 0, ListOfValues);
     break;
   }
-  case ValueKind::MetatypeInst:
-    writeOneTypeLayout(SI.getKind(), SI.getType());
+  case SILInstructionKind::MetatypeInst: {
+    auto &MI = cast<MetatypeInst>(SI);
+    writeOneTypeLayout(MI.getKind(), MI.getType());
     break;
-  case ValueKind::ObjCProtocolInst: {
+  }
+  case SILInstructionKind::ObjCProtocolInst: {
     const ObjCProtocolInst *PI = cast<ObjCProtocolInst>(&SI);
     unsigned abbrCode = SILAbbrCodes[SILOneOperandLayout::Code];
     SILOneOperandLayout::emitRecord(Out, ScratchRecord, abbrCode,
@@ -1256,57 +1255,57 @@
                               S.addDeclRef(PI->getProtocol()));
     break;
   }
-  case ValueKind::OpenExistentialAddrInst: {
-    assert(SI.getNumOperands() - SI.getTypeDependentOperands().size() == 1);
-    unsigned attrs = cast<OpenExistentialAddrInst>(SI).getAccessKind() ==
-                             OpenedExistentialAccess::Immutable
+  case SILInstructionKind::OpenExistentialAddrInst: {
+    auto &open = cast<OpenExistentialAddrInst>(SI);
+    assert(open.getNumOperands() - open.getTypeDependentOperands().size() == 1);
+    unsigned attrs = open.getAccessKind() == OpenedExistentialAccess::Immutable
                          ? 0 : 1;
-    writeOneTypeOneOperandLayout(SI.getKind(), attrs, SI.getType(),
-                                 SI.getOperand(0));
+    writeOneTypeOneOperandLayout(open.getKind(), attrs, open.getType(),
+                                 open.getOperand());
     break;
   }
   // Conversion instructions (and others of similar form).
-  case ValueKind::OpenExistentialRefInst:
-  case ValueKind::OpenExistentialMetatypeInst:
-  case ValueKind::OpenExistentialBoxInst:
-  case ValueKind::OpenExistentialValueInst:
-  case ValueKind::OpenExistentialBoxValueInst:
-  case ValueKind::UncheckedRefCastInst:
-  case ValueKind::UncheckedAddrCastInst:
-  case ValueKind::UncheckedTrivialBitCastInst:
-  case ValueKind::UncheckedBitwiseCastInst:
-  case ValueKind::BridgeObjectToRefInst:
-  case ValueKind::BridgeObjectToWordInst:
-  case ValueKind::UpcastInst:
-  case ValueKind::AddressToPointerInst:
-  case ValueKind::RefToRawPointerInst:
-  case ValueKind::RawPointerToRefInst:
-  case ValueKind::RefToUnownedInst:
-  case ValueKind::UnownedToRefInst:
-  case ValueKind::RefToUnmanagedInst:
-  case ValueKind::UnmanagedToRefInst:
-  case ValueKind::ThinToThickFunctionInst:
-  case ValueKind::ThickToObjCMetatypeInst:
-  case ValueKind::ObjCToThickMetatypeInst:
-  case ValueKind::ConvertFunctionInst:
-  case ValueKind::ThinFunctionToPointerInst:
-  case ValueKind::PointerToThinFunctionInst:
-  case ValueKind::ObjCMetatypeToObjectInst:
-  case ValueKind::ObjCExistentialMetatypeToObjectInst:
-  case ValueKind::ProjectBlockStorageInst: {
-    writeConversionLikeInstruction(&SI);
+  case SILInstructionKind::OpenExistentialRefInst:
+  case SILInstructionKind::OpenExistentialMetatypeInst:
+  case SILInstructionKind::OpenExistentialBoxInst:
+  case SILInstructionKind::OpenExistentialValueInst:
+  case SILInstructionKind::OpenExistentialBoxValueInst:
+  case SILInstructionKind::UncheckedRefCastInst:
+  case SILInstructionKind::UncheckedAddrCastInst:
+  case SILInstructionKind::UncheckedTrivialBitCastInst:
+  case SILInstructionKind::UncheckedBitwiseCastInst:
+  case SILInstructionKind::BridgeObjectToRefInst:
+  case SILInstructionKind::BridgeObjectToWordInst:
+  case SILInstructionKind::UpcastInst:
+  case SILInstructionKind::AddressToPointerInst:
+  case SILInstructionKind::RefToRawPointerInst:
+  case SILInstructionKind::RawPointerToRefInst:
+  case SILInstructionKind::RefToUnownedInst:
+  case SILInstructionKind::UnownedToRefInst:
+  case SILInstructionKind::RefToUnmanagedInst:
+  case SILInstructionKind::UnmanagedToRefInst:
+  case SILInstructionKind::ThinToThickFunctionInst:
+  case SILInstructionKind::ThickToObjCMetatypeInst:
+  case SILInstructionKind::ObjCToThickMetatypeInst:
+  case SILInstructionKind::ConvertFunctionInst:
+  case SILInstructionKind::ThinFunctionToPointerInst:
+  case SILInstructionKind::PointerToThinFunctionInst:
+  case SILInstructionKind::ObjCMetatypeToObjectInst:
+  case SILInstructionKind::ObjCExistentialMetatypeToObjectInst:
+  case SILInstructionKind::ProjectBlockStorageInst: {
+    writeConversionLikeInstruction(cast<SingleValueInstruction>(&SI));
     break;
   }
-  case ValueKind::PointerToAddressInst: {
-    assert(SI.getNumOperands() - SI.getTypeDependentOperands().size() == 1);
+  case SILInstructionKind::PointerToAddressInst: {
     auto &PAI = cast<PointerToAddressInst>(SI);
+    assert(PAI.getNumOperands() - PAI.getTypeDependentOperands().size() == 1);
     unsigned attrs = (PAI.isStrict() ? 1 : 0)
                    | (PAI.isInvariant() ? 2 : 0);
-    writeOneTypeOneOperandLayout(SI.getKind(), attrs, SI.getType(),
-                                 SI.getOperand(0));
+    writeOneTypeOneOperandLayout(PAI.getKind(), attrs, PAI.getType(),
+                                 PAI.getOperand());
     break;
   }
-  case ValueKind::RefToBridgeObjectInst: {
+  case SILInstructionKind::RefToBridgeObjectInst: {
     auto RI = cast<RefToBridgeObjectInst>(&SI);
     SILTwoOperandsLayout::emitRecord(Out, ScratchRecord,
            SILAbbrCodes[SILTwoOperandsLayout::Code], (unsigned)SI.getKind(),
@@ -1320,7 +1319,7 @@
     break;
   }
   // Checked Conversion instructions.
-  case ValueKind::UnconditionalCheckedCastInst: {
+  case SILInstructionKind::UnconditionalCheckedCastInst: {
     auto CI = cast<UnconditionalCheckedCastInst>(&SI);
     SILInstCastLayout::emitRecord(Out, ScratchRecord,
         SILAbbrCodes[SILInstCastLayout::Code],
@@ -1332,7 +1331,7 @@
         addValueRef(CI->getOperand()));
     break;
   }
-  case ValueKind::UnconditionalCheckedCastAddrInst: {
+  case SILInstructionKind::UnconditionalCheckedCastAddrInst: {
     auto CI = cast<UnconditionalCheckedCastAddrInst>(&SI);
     ValueID listOfValues[] = {
       S.addTypeRef(CI->getSourceType()),
@@ -1349,7 +1348,7 @@
              llvm::makeArrayRef(listOfValues));
     break;
   }
-  case ValueKind::UnconditionalCheckedCastValueInst: {
+  case SILInstructionKind::UnconditionalCheckedCastValueInst: {
     auto CI = cast<UnconditionalCheckedCastValueInst>(&SI);
     SILInstCastLayout::emitRecord(
         Out, ScratchRecord, SILAbbrCodes[SILInstCastLayout::Code],
@@ -1362,7 +1361,7 @@
         addValueRef(CI->getOperand()));
     break;
   }
-  case ValueKind::UncheckedRefCastAddrInst: {
+  case SILInstructionKind::UncheckedRefCastAddrInst: {
     auto CI = cast<UncheckedRefCastAddrInst>(&SI);
     ValueID listOfValues[] = {
       S.addTypeRef(CI->getSourceType()),
@@ -1380,7 +1379,7 @@
     break;
   }
 
-  case ValueKind::EndBorrowInst: {
+  case SILInstructionKind::EndBorrowInst: {
     unsigned abbrCode = SILAbbrCodes[SILTwoOperandsLayout::Code];
     unsigned Attr = 0;
     auto *EBI = cast<EndBorrowInst>(&SI);
@@ -1398,7 +1397,7 @@
     break;
   }
 
-  case ValueKind::BeginAccessInst: {
+  case SILInstructionKind::BeginAccessInst: {
     unsigned abbrCode = SILAbbrCodes[SILOneOperandLayout::Code];
     auto *BAI = cast<BeginAccessInst>(&SI);
     unsigned attr =
@@ -1414,7 +1413,7 @@
     break;
   }
 
-  case ValueKind::EndAccessInst: {
+  case SILInstructionKind::EndAccessInst: {
     unsigned abbrCode = SILAbbrCodes[SILOneOperandLayout::Code];
     auto *EAI = cast<EndAccessInst>(&SI);
     unsigned attr = unsigned(EAI->isAborting());
@@ -1428,7 +1427,7 @@
     break;
   }
 
-  case ValueKind::BeginUnpairedAccessInst: {
+  case SILInstructionKind::BeginUnpairedAccessInst: {
     unsigned abbrCode = SILAbbrCodes[SILTwoOperandsLayout::Code];
     auto *BAI = cast<BeginUnpairedAccessInst>(&SI);
     unsigned attr =
@@ -1448,7 +1447,7 @@
     break;
   }
 
-  case ValueKind::EndUnpairedAccessInst: {
+  case SILInstructionKind::EndUnpairedAccessInst: {
     unsigned abbrCode = SILAbbrCodes[SILOneOperandLayout::Code];
     auto *EAI = cast<EndUnpairedAccessInst>(&SI);
     unsigned attr = unsigned(EAI->isAborting())
@@ -1463,30 +1462,30 @@
     break;
   }
 
-  case ValueKind::AssignInst:
-  case ValueKind::CopyAddrInst:
-  case ValueKind::StoreInst:
-  case ValueKind::StoreBorrowInst:
-  case ValueKind::StoreUnownedInst:
-  case ValueKind::StoreWeakInst: {
+  case SILInstructionKind::AssignInst:
+  case SILInstructionKind::CopyAddrInst:
+  case SILInstructionKind::StoreInst:
+  case SILInstructionKind::StoreBorrowInst:
+  case SILInstructionKind::StoreUnownedInst:
+  case SILInstructionKind::StoreWeakInst: {
     SILValue operand, value;
     unsigned Attr = 0;
-    if (SI.getKind() == ValueKind::StoreWeakInst) {
+    if (SI.getKind() == SILInstructionKind::StoreWeakInst) {
       Attr = cast<StoreWeakInst>(&SI)->isInitializationOfDest();
       operand = cast<StoreWeakInst>(&SI)->getDest();
       value = cast<StoreWeakInst>(&SI)->getSrc();
-    } else if (SI.getKind() == ValueKind::StoreUnownedInst) {
+    } else if (SI.getKind() == SILInstructionKind::StoreUnownedInst) {
       Attr = cast<StoreUnownedInst>(&SI)->isInitializationOfDest();
       operand = cast<StoreUnownedInst>(&SI)->getDest();
       value = cast<StoreUnownedInst>(&SI)->getSrc();
-    } else if (SI.getKind() == ValueKind::StoreInst) {
+    } else if (SI.getKind() == SILInstructionKind::StoreInst) {
       Attr = unsigned(cast<StoreInst>(&SI)->getOwnershipQualifier());
       operand = cast<StoreInst>(&SI)->getDest();
       value = cast<StoreInst>(&SI)->getSrc();
-    } else if (SI.getKind() == ValueKind::AssignInst) {
+    } else if (SI.getKind() == SILInstructionKind::AssignInst) {
       operand = cast<AssignInst>(&SI)->getDest();
       value = cast<AssignInst>(&SI)->getSrc();
-    } else if (SI.getKind() == ValueKind::CopyAddrInst) {
+    } else if (SI.getKind() == SILInstructionKind::CopyAddrInst) {
       const CopyAddrInst *CAI = cast<CopyAddrInst>(&SI);
       Attr = (CAI->isInitializationOfDest() << 1) | CAI->isTakeOfSrc();
       operand = cast<CopyAddrInst>(&SI)->getDest();
@@ -1506,7 +1505,7 @@
                   addValueRef(operand));
     break;
   }
-  case ValueKind::BindMemoryInst: {
+  case SILInstructionKind::BindMemoryInst: {
     auto *BI = cast<BindMemoryInst>(&SI);
     SILValue baseOperand = BI->getBase();
     SILValue indexOperand = BI->getIndex();
@@ -1531,44 +1530,44 @@
       ListOfValues);
     break;
   }
-  case ValueKind::RefElementAddrInst:
-  case ValueKind::StructElementAddrInst:
-  case ValueKind::StructExtractInst:
-  case ValueKind::InitEnumDataAddrInst:
-  case ValueKind::UncheckedEnumDataInst:
-  case ValueKind::UncheckedTakeEnumDataAddrInst:
-  case ValueKind::InjectEnumAddrInst: {
+  case SILInstructionKind::RefElementAddrInst:
+  case SILInstructionKind::StructElementAddrInst:
+  case SILInstructionKind::StructExtractInst:
+  case SILInstructionKind::InitEnumDataAddrInst:
+  case SILInstructionKind::UncheckedEnumDataInst:
+  case SILInstructionKind::UncheckedTakeEnumDataAddrInst:
+  case SILInstructionKind::InjectEnumAddrInst: {
     // Has a typed valueref and a field decl. We use SILOneValueOneOperandLayout
     // where the field decl is streamed as a ValueID.
     SILValue operand;
     Decl *tDecl;
     switch (SI.getKind()) {
     default: llvm_unreachable("Out of sync with parent switch");
-    case ValueKind::RefElementAddrInst:
+    case SILInstructionKind::RefElementAddrInst:
       operand = cast<RefElementAddrInst>(&SI)->getOperand();
       tDecl = cast<RefElementAddrInst>(&SI)->getField();
       break;
-    case ValueKind::StructElementAddrInst:
+    case SILInstructionKind::StructElementAddrInst:
       operand = cast<StructElementAddrInst>(&SI)->getOperand();
       tDecl = cast<StructElementAddrInst>(&SI)->getField();
       break;
-    case ValueKind::StructExtractInst:
+    case SILInstructionKind::StructExtractInst:
       operand = cast<StructExtractInst>(&SI)->getOperand();
       tDecl = cast<StructExtractInst>(&SI)->getField();
       break;
-    case ValueKind::InitEnumDataAddrInst:
+    case SILInstructionKind::InitEnumDataAddrInst:
       operand = cast<InitEnumDataAddrInst>(&SI)->getOperand();
       tDecl = cast<InitEnumDataAddrInst>(&SI)->getElement();
       break;
-    case ValueKind::UncheckedEnumDataInst:
+    case SILInstructionKind::UncheckedEnumDataInst:
       operand = cast<UncheckedEnumDataInst>(&SI)->getOperand();
       tDecl = cast<UncheckedEnumDataInst>(&SI)->getElement();
       break;
-    case ValueKind::UncheckedTakeEnumDataAddrInst:
+    case SILInstructionKind::UncheckedTakeEnumDataAddrInst:
       operand = cast<UncheckedTakeEnumDataAddrInst>(&SI)->getOperand();
       tDecl = cast<UncheckedTakeEnumDataAddrInst>(&SI)->getElement();
       break;
-    case ValueKind::InjectEnumAddrInst:
+    case SILInstructionKind::InjectEnumAddrInst:
       operand = cast<InjectEnumAddrInst>(&SI)->getOperand();
       tDecl = cast<InjectEnumAddrInst>(&SI)->getElement();
       break;
@@ -1581,14 +1580,14 @@
         addValueRef(operand));
     break;
   }
-  case ValueKind::RefTailAddrInst: {
+  case SILInstructionKind::RefTailAddrInst: {
     auto *RTAI = cast<RefTailAddrInst>(&SI);
     writeOneTypeOneOperandLayout(RTAI->getKind(), 0,
                                  RTAI->getType(),
                                  RTAI->getOperand());
     break;
   }
-  case ValueKind::StructInst: {
+  case SILInstructionKind::StructInst: {
     // Format: a type followed by a list of typed values. A typed value is
     // expressed by 4 IDs: TypeID, TypeCategory, ValueID, ValueResultNumber.
     const StructInst *StrI = cast<StructInst>(&SI);
@@ -1606,17 +1605,17 @@
         (unsigned)StrI->getType().getCategory(), ListOfValues);
     break;
   }
-  case ValueKind::TupleElementAddrInst:
-  case ValueKind::TupleExtractInst: {
+  case SILInstructionKind::TupleElementAddrInst:
+  case SILInstructionKind::TupleExtractInst: {
     SILValue operand;
     unsigned FieldNo;
     switch (SI.getKind()) {
     default: llvm_unreachable("Out of sync with parent switch");
-    case ValueKind::TupleElementAddrInst:
+    case SILInstructionKind::TupleElementAddrInst:
       operand = cast<TupleElementAddrInst>(&SI)->getOperand();
       FieldNo = cast<TupleElementAddrInst>(&SI)->getFieldNo();
       break;
-    case ValueKind::TupleExtractInst:
+    case SILInstructionKind::TupleExtractInst:
       operand = cast<TupleExtractInst>(&SI)->getOperand();
       FieldNo = cast<TupleExtractInst>(&SI)->getFieldNo();
       break;
@@ -1632,7 +1631,7 @@
         addValueRef(operand));
     break;
   }
-  case ValueKind::TupleInst: {
+  case SILInstructionKind::TupleInst: {
     // Format: a type followed by a list of values. A value is expressed by
     // 2 IDs: ValueID, ValueResultNumber.
     const TupleInst *TI = cast<TupleInst>(&SI);
@@ -1649,7 +1648,7 @@
         ListOfValues);
     break;
   }
-  case ValueKind::EnumInst: {
+  case SILInstructionKind::EnumInst: {
     // Format: a type, an operand and a decl ID. Use SILTwoOperandsLayout: type,
     // (DeclID + hasOperand), and an operand.
     const EnumInst *UI = cast<EnumInst>(&SI);
@@ -1667,7 +1666,7 @@
         UI->hasOperand() ? addValueRef(UI->getOperand()) : ValueID());
     break;
   }
-  case ValueKind::WitnessMethodInst: {
+  case SILInstructionKind::WitnessMethodInst: {
     // Format: a type, an operand and a SILDeclRef. Use SILOneTypeValuesLayout:
     // type, Attr, SILDeclRef (DeclID, Kind, uncurryLevel, IsObjC), and a type.
     const WitnessMethodInst *AMI = cast<WitnessMethodInst>(&SI);
@@ -1693,7 +1692,7 @@
 
     break;
   }
-  case ValueKind::ClassMethodInst: {
+  case SILInstructionKind::ClassMethodInst: {
     // Format: a type, an operand and a SILDeclRef. Use SILOneTypeValuesLayout:
     // type, Attr, SILDeclRef (DeclID, Kind, uncurryLevel, IsObjC),
     // and an operand.
@@ -1708,7 +1707,7 @@
         (unsigned)Ty.getCategory(), ListOfValues);
     break;
   }
-  case ValueKind::SuperMethodInst: {
+  case SILInstructionKind::SuperMethodInst: {
     // Format: a type, an operand and a SILDeclRef. Use SILOneTypeValuesLayout:
     // type, Attr, SILDeclRef (DeclID, Kind, uncurryLevel, IsObjC),
     // and an operand.
@@ -1723,7 +1722,7 @@
         (unsigned)Ty.getCategory(), ListOfValues);
     break;
   }
-  case ValueKind::DynamicMethodInst: {
+  case SILInstructionKind::DynamicMethodInst: {
     // Format: a type, an operand and a SILDeclRef. Use SILOneTypeValuesLayout:
     // type, Attr, SILDeclRef (DeclID, Kind, uncurryLevel, IsObjC),
     // and an operand.
@@ -1738,7 +1737,7 @@
         (unsigned)Ty.getCategory(), ListOfValues);
     break;
   }
-  case ValueKind::DynamicMethodBranchInst: {
+  case SILInstructionKind::DynamicMethodBranchInst: {
     // Format: a typed value, a SILDeclRef, a BasicBlock ID for method,
     // a BasicBlock ID for no method. Use SILOneTypeValuesLayout.
     const DynamicMethodBranchInst *DMB = cast<DynamicMethodBranchInst>(&SI);
@@ -1754,7 +1753,7 @@
         (unsigned)DMB->getOperand()->getType().getCategory(), ListOfValues);
     break;
   }
-  case ValueKind::CheckedCastBranchInst: {
+  case SILInstructionKind::CheckedCastBranchInst: {
     // Format: the cast kind, a typed value, a BasicBlock ID for success,
     // a BasicBlock ID for failure. Uses SILOneTypeValuesLayout.
     const CheckedCastBranchInst *CBI = cast<CheckedCastBranchInst>(&SI);
@@ -1774,7 +1773,7 @@
              ListOfValues);
     break;
   }
-  case ValueKind::CheckedCastValueBranchInst: {
+  case SILInstructionKind::CheckedCastValueBranchInst: {
     // Format: the cast kind, a typed value, a BasicBlock ID for success,
     // a BasicBlock ID for failure. Uses SILOneTypeValuesLayout.
     const CheckedCastValueBranchInst *CBI =
@@ -1795,7 +1794,7 @@
         (unsigned)CBI->getCastType().getCategory(), ListOfValues);
     break;
   }
-  case ValueKind::CheckedCastAddrBranchInst: {
+  case SILInstructionKind::CheckedCastAddrBranchInst: {
     // Format: the cast kind, two typed values, a BasicBlock ID for
     // success, a BasicBlock ID for failure.  Uses SILOneTypeValuesLayout;
     // the type is the type of the second (dest) operand.
@@ -1818,7 +1817,7 @@
              llvm::makeArrayRef(listOfValues));
     break;
   }
-  case ValueKind::InitBlockStorageHeaderInst: {
+  case SILInstructionKind::InitBlockStorageHeaderInst: {
     auto IBSHI = cast<InitBlockStorageHeaderInst>(&SI);
     SmallVector<ValueID, 6> ListOfValues;
     ListOfValues.push_back(addValueRef(IBSHI->getBlockStorage()));
@@ -1841,7 +1840,7 @@
 
     break;
   }
-  case ValueKind::KeyPathInst: {
+  case SILInstructionKind::KeyPathInst: {
     auto KPI = cast<KeyPathInst>(&SI);
     SmallVector<ValueID, 6> ListOfValues;
 
@@ -1964,12 +1963,12 @@
 
     break;
   }
-  case ValueKind::MarkUninitializedBehaviorInst:
+  case SILInstructionKind::MarkUninitializedBehaviorInst:
     llvm_unreachable("todo");
   }
   // Non-void values get registered in the value table.
-  if (SI.hasValue()) {
-    addValueRef(&SI);
+  for (auto result : SI.getResults()) {
+    addValueRef(result);
     ++InstID;
   }
 }
diff --git a/stdlib/public/Reflection/MetadataSource.cpp b/stdlib/public/Reflection/MetadataSource.cpp
index 59c989c..7278c53 100644
--- a/stdlib/public/Reflection/MetadataSource.cpp
+++ b/stdlib/public/Reflection/MetadataSource.cpp
@@ -87,13 +87,6 @@
     closeForm();
   }
 
-  void
-  visitParentMetadataSource(const ParentMetadataSource *P) {
-    printHeader("parent_of");
-    printRec(P->getChild());
-    closeForm();
-  }
-
   void visitSelfMetadataSource(const SelfMetadataSource *S) {
     printHeader("self");
     closeForm();
diff --git a/stdlib/public/core/Equatable.swift b/stdlib/public/core/Equatable.swift
index a72e3a2..a00c38d 100644
--- a/stdlib/public/core/Equatable.swift
+++ b/stdlib/public/core/Equatable.swift
@@ -236,10 +236,7 @@
 public func === (lhs: AnyObject?, rhs: AnyObject?) -> Bool {
   switch (lhs, rhs) {
   case let (l?, r?):
-    return Bool(Builtin.cmp_eq_RawPointer(
-        Builtin.bridgeToRawPointer(Builtin.castToUnknownObject(l)),
-        Builtin.bridgeToRawPointer(Builtin.castToUnknownObject(r))
-      ))
+    return ObjectIdentifier(l) == ObjectIdentifier(r)
   case (nil, nil):
     return true
   default:
diff --git a/stdlib/public/core/VarArgs.swift b/stdlib/public/core/VarArgs.swift
index b521f81..5a2adb8 100644
--- a/stdlib/public/core/VarArgs.swift
+++ b/stdlib/public/core/VarArgs.swift
@@ -168,6 +168,12 @@
   }
 }
 
+extension Bool : CVarArg {
+  public var _cVarArgEncoding: [Int] {
+    return _encodeBitsAsWords(Int32(self ? 1:0))
+  }
+}
+
 extension Int64 : CVarArg, _CVarArgAligned {
   /// Transform `self` into a series of machine words that can be
   /// appropriately interpreted by C varargs.
diff --git a/stdlib/public/runtime/Demangle.cpp b/stdlib/public/runtime/Demangle.cpp
index d36c04f..423b096 100644
--- a/stdlib/public/runtime/Demangle.cpp
+++ b/stdlib/public/runtime/Demangle.cpp
@@ -30,13 +30,107 @@
 swift::_swift_buildDemanglingForMetadata(const Metadata *type,
                                          Demangle::Demangler &Dem);
 
+static Demangle::NodePointer
+_applyGenericArguments(const Metadata * const *genericArgs,
+                       const NominalTypeDescriptor *description,
+                       Demangle::NodePointer node, unsigned depth,
+                       Demangle::Demangler &Dem) {
+  assert(depth > 0);
+
+  auto typeNode = node;
+  if (typeNode->getKind() == Node::Kind::Type)
+    typeNode = typeNode->getChild(0);
+
+  auto parentNode = typeNode->getChild(0);
+
+  // It might be more accurate to keep this sugar, but the old version
+  // of this function dropped it, and I want to keep things compatible.
+  if (parentNode->getKind() == Node::Kind::Extension) {
+    parentNode = parentNode->getChild(1);
+  }
+
+  switch (parentNode->getKind()) {
+  case Node::Kind::Class:
+  case Node::Kind::Structure:
+  case Node::Kind::Enum: {
+    // The parent type is a nominal type which may have its own generic
+    // arguments.
+    auto newParentNode = _applyGenericArguments(genericArgs, description,
+                                                parentNode, depth - 1,
+                                                Dem);
+    if (newParentNode == nullptr)
+      return nullptr;
+
+    auto newTypeNode = Dem.createNode(typeNode->getKind());
+    newTypeNode->addChild(newParentNode, Dem);
+    newTypeNode->addChild(typeNode->getChild(1), Dem);
+
+    typeNode = newTypeNode;
+    break;
+  }
+  default:
+    // Parent is a local context or module. Leave it as-is, and just apply
+    // generic arguments below.
+    break;
+  }
+
+  // See if we have any generic arguments at this depth.
+  unsigned numArgumentsAtDepth =
+      description->GenericParams.getContext(depth - 1).NumPrimaryParams;
+  if (numArgumentsAtDepth == 0) {
+    // No arguments here, just return the original node (except we may have
+    // replaced its parent type above).
+    return typeNode;
+  }
+
+  // Ok, we have generic arguments. Figure out where the arguments for this
+  // depth begin in the generic type metadata.
+  unsigned firstArgumentAtDepth = 0;
+  for (unsigned i = 0; i < depth - 1; i++) {
+    firstArgumentAtDepth +=
+        description->GenericParams.getContext(i).NumPrimaryParams;
+  }
+
+  // Demangle them.
+  auto typeParams = Dem.createNode(Node::Kind::TypeList);
+  for (unsigned i = firstArgumentAtDepth,
+                e = firstArgumentAtDepth + numArgumentsAtDepth;
+                i < e; ++i) {
+    auto demangling = _swift_buildDemanglingForMetadata(genericArgs[i], Dem);
+    if (demangling == nullptr)
+      return nullptr;
+    typeParams->addChild(demangling, Dem);
+  }
+
+  Node::Kind boundGenericKind;
+  switch (typeNode->getKind()) {
+  case Node::Kind::Class:
+    boundGenericKind = Node::Kind::BoundGenericClass;
+    break;
+  case Node::Kind::Structure:
+    boundGenericKind = Node::Kind::BoundGenericStructure;
+    break;
+  case Node::Kind::Enum:
+    boundGenericKind = Node::Kind::BoundGenericEnum;
+    break;
+  default:
+    return nullptr;
+  }
+
+  auto newNode = Dem.createNode(Node::Kind::Type);
+  newNode->addChild(typeNode, Dem);
+
+  auto genericNode = Dem.createNode(boundGenericKind);
+  genericNode->addChild(newNode, Dem);
+  genericNode->addChild(typeParams, Dem);
+  return genericNode;
+}
+
 // Build a demangled type tree for a nominal type.
 static Demangle::NodePointer
 _buildDemanglingForNominalType(const Metadata *type, Demangle::Demangler &Dem) {
   using namespace Demangle;
 
-  const Metadata *parent;
-  Node::Kind boundGenericKind;
   const NominalTypeDescriptor *description;
 
   // Demangle the parent type, if any.
@@ -48,23 +142,17 @@
     while (classType->isTypeMetadata() && classType->isArtificialSubclass())
       classType = classType->SuperClass;
 #endif
-    parent = classType->getParentType(classType->getDescription());
-    boundGenericKind = Node::Kind::BoundGenericClass;
     description = classType->getDescription();
     break;
   }
   case MetadataKind::Enum:
   case MetadataKind::Optional: {
     auto enumType = static_cast<const EnumMetadata *>(type);
-    parent = enumType->Parent;
-    boundGenericKind = Node::Kind::BoundGenericEnum;
     description = enumType->Description;
     break;
   }
   case MetadataKind::Struct: {
     auto structType = static_cast<const StructMetadata *>(type);
-    parent = structType->Parent;
-    boundGenericKind = Node::Kind::BoundGenericStructure;
     description = structType->Description;
     break;
   }
@@ -76,42 +164,13 @@
   auto node = Dem.demangleType(StringRef(description->Name));
   assert(node->getKind() == Node::Kind::Type);
 
-  // Demangle the parent.
-  if (parent) {
-    auto parentNode = _swift_buildDemanglingForMetadata(parent, Dem);
-    if (parentNode->getKind() == Node::Kind::Type)
-      parentNode = parentNode->getChild(0);
+  auto typeBytes = reinterpret_cast<const char *>(type);
+  auto genericArgs = reinterpret_cast<const Metadata * const *>(
+               typeBytes + sizeof(void*) * description->GenericParams.Offset);
 
-    auto typeNode = node->getChild(0);
-    auto newTypeNode = Dem.createNode(typeNode->getKind());
-    newTypeNode->addChild(parentNode, Dem);
-    newTypeNode->addChild(typeNode->getChild(1), Dem);
-
-    auto newNode = Dem.createNode(Node::Kind::Type);
-    newNode->addChild(newTypeNode, Dem);
-    node = newNode;
-  }
-
-  // If generic, demangle the type parameters.
-  if (description->GenericParams.NumPrimaryParams > 0) {
-    auto typeParams = Dem.createNode(Node::Kind::TypeList);
-    auto typeBytes = reinterpret_cast<const char *>(type);
-    auto genericParam = reinterpret_cast<const Metadata * const *>(
-                 typeBytes + sizeof(void*) * description->GenericParams.Offset);
-    for (unsigned i = 0, e = description->GenericParams.NumPrimaryParams;
-         i < e; ++i, ++genericParam) {
-      auto demangling = _swift_buildDemanglingForMetadata(*genericParam, Dem);
-      if (demangling == nullptr)
-        return nullptr;
-      typeParams->addChild(demangling, Dem);
-    }
-
-    auto genericNode = Dem.createNode(boundGenericKind);
-    genericNode->addChild(node, Dem);
-    genericNode->addChild(typeParams, Dem);
-    return genericNode;
-  }
-  return node;
+  return _applyGenericArguments(genericArgs, description, node,
+                                description->GenericParams.NestingDepth,
+                                Dem);
 }
 
 // Build a demangled type tree for a type.
diff --git a/stdlib/public/runtime/Metadata.cpp b/stdlib/public/runtime/Metadata.cpp
index d5875ac..fbfad19 100644
--- a/stdlib/public/runtime/Metadata.cpp
+++ b/stdlib/public/runtime/Metadata.cpp
@@ -221,8 +221,7 @@
     pattern->AddressPoint;
   auto patternMetadata = reinterpret_cast<const ValueMetadata*>(patternBytes);
   metadata->Description = patternMetadata->Description.get();
-  metadata->Parent = patternMetadata->Parent;
-  
+
   return metadata;
 }
 
@@ -1329,13 +1328,6 @@
     auto &description = ancestor->getDescription();
     auto &genericParams = description->GenericParams;
 
-    // Copy the parent type.
-    if (genericParams.Flags.hasParent()) {
-      memcpy(classWords + genericParams.Offset - 1,
-             superWords + genericParams.Offset - 1,
-             sizeof(uintptr_t));
-    }
-
     // Copy the generic requirements.
     if (genericParams.hasGenericRequirements()) {
       unsigned numParamWords = genericParams.NumGenericRequirements;
diff --git a/stdlib/public/stubs/LibcShims.cpp b/stdlib/public/stubs/LibcShims.cpp
index 6f558e5..86cc09a 100644
--- a/stdlib/public/stubs/LibcShims.cpp
+++ b/stdlib/public/stubs/LibcShims.cpp
@@ -109,7 +109,7 @@
 void _swift_stdlib_destroyTLS(void *);
 
 static void
-#if defined(_M_X86)
+#if defined(_M_IX86)
 __stdcall
 #endif
 _swift_stdlib_destroyTLS_CCAdjustmentThunk(void *ptr) {
diff --git a/stdlib/public/stubs/SwiftNativeNSXXXBase.mm.gyb b/stdlib/public/stubs/SwiftNativeNSXXXBase.mm.gyb
index d0c2675..ece3bbc 100644
--- a/stdlib/public/stubs/SwiftNativeNSXXXBase.mm.gyb
+++ b/stdlib/public/stubs/SwiftNativeNSXXXBase.mm.gyb
@@ -24,9 +24,9 @@
 // To trick Swift into using its fast refcounting and allocation
 // directly (rather than going through objc_msgSend to arrive at the
 // implementations defined here), we define subclasses on the Swift
-// side but hide the inheritance relationship from the Swift compiler
-// and only establish it dynamically, in the '+ load' method of each
-// class defined here.
+// side but we establish the inheritance relationship with
+// the special @_swift_native_objc_runtime_base attribute rather
+// than directly subclassing the classes defined here.
 //
 //===----------------------------------------------------------------------===//
 
@@ -72,6 +72,10 @@
 - (id)autorelease {
   return _objc_rootAutorelease(self);
 }
+- (NSUInteger)retainCount {
+  auto SELF = reinterpret_cast<HeapObject *>(self);
+  return swift_retainCount(SELF);
+}
 
 - (BOOL)_tryRetain {
   auto SELF = reinterpret_cast<HeapObject *>(self);
diff --git a/test/ClangImporter/Inputs/custom-modules/SubclassExistentialsExtra.h b/test/ClangImporter/Inputs/custom-modules/SubclassExistentialsExtra.h
new file mode 100644
index 0000000..0ff6e95
--- /dev/null
+++ b/test/ClangImporter/Inputs/custom-modules/SubclassExistentialsExtra.h
@@ -0,0 +1,12 @@
+@import Foundation;
+
+@interface SomeSpecificSubclass : NSObject
+@end
+
+typedef NSObject <NSCopying> CopyableNSObjectBase;
+typedef SomeSpecificSubclass <NSCopying> CopyableSpecificBase;
+
+@interface CompositionSubObject : CopyableNSObjectBase
+@end
+@interface CompositionSubSpecific : CopyableSpecificBase
+@end
diff --git a/test/ClangImporter/Inputs/custom-modules/module.map b/test/ClangImporter/Inputs/custom-modules/module.map
index 9177b5c..9b5c8c4 100644
--- a/test/ClangImporter/Inputs/custom-modules/module.map
+++ b/test/ClangImporter/Inputs/custom-modules/module.map
@@ -140,6 +140,11 @@
   export *
 }
 
+module SubclassExistentialsExtra {
+  header "SubclassExistentialsExtra.h"
+  export *
+}
+
 module SwiftPrivateAttr {
   header "SwiftPrivateAttr.h"
 }
diff --git a/test/ClangImporter/subclass_existentials.swift b/test/ClangImporter/subclass_existentials.swift
index 690d30c..15a085f 100644
--- a/test/ClangImporter/subclass_existentials.swift
+++ b/test/ClangImporter/subclass_existentials.swift
@@ -1,8 +1,9 @@
-// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck -verify -o - -primary-file %s -swift-version 4
+// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck -verify -o - -primary-file %s -swift-version 4 -I %S/Inputs/custom-modules/
 
 // REQUIRES: objc_interop
 
 import Foundation
+import SubclassExistentialsExtra
 
 class SwiftLaundryService : NSLaundry {
   var g: (Garment & Coat)? = nil
@@ -39,3 +40,12 @@
 // Make sure the method lookup is not ambiguous
 
 _ = Coat.fashionStatement.wear()
+
+
+func testInheritanceFromComposition(_ object: CompositionSubObject, _ specific: CompositionSubSpecific) {
+  let _: NSObject = object
+  let _: NSCopying = object
+
+  let _: SomeSpecificSubclass = specific
+  let _: NSCopying = specific
+}
diff --git a/test/ClangImporter/subclass_existentials_swift3.swift b/test/ClangImporter/subclass_existentials_swift3.swift
index 7b1c955..4e24b33 100644
--- a/test/ClangImporter/subclass_existentials_swift3.swift
+++ b/test/ClangImporter/subclass_existentials_swift3.swift
@@ -1,8 +1,9 @@
-// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck -verify -o - -primary-file %s -swift-version 3
+// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck -verify -o - -primary-file %s -swift-version 3 -I %S/Inputs/custom-modules/
 
 // REQUIRES: objc_interop
 
 import Foundation
+import SubclassExistentialsExtra
 
 // FIXME: Consider better diagnostics here.
 
@@ -34,3 +35,11 @@
     return g!
   }
 }
+
+func testInheritanceFromComposition(_ object: CompositionSubObject, _ specific: CompositionSubSpecific) {
+  let _: NSObject = object
+  let _: NSCopying = object
+
+  let _: SomeSpecificSubclass = specific
+  let _: NSCopying = specific
+}
diff --git a/test/Constraints/closures.swift b/test/Constraints/closures.swift
index 3c47f49..d19b9a2 100644
--- a/test/Constraints/closures.swift
+++ b/test/Constraints/closures.swift
@@ -603,3 +603,45 @@
 // SR-1976/SR-3073: Inference of inout
 func sr1976<T>(_ closure: (inout T) -> Void) {}
 sr1976({ $0 += 2 }) // ok
+
+// rdar://problem/33429010
+
+struct I_33429010 : IteratorProtocol {
+    func next() -> Int? {
+        fatalError()
+    }
+}
+
+extension Sequence {
+    public func rdar33429010<Result>(into initialResult: Result,
+                                     _ nextPartialResult: (_ partialResult: inout Result, Iterator.Element) throws -> ()
+        ) rethrows -> Result {
+        return initialResult
+    }
+}
+
+extension Int {
+   public mutating func rdar33429010_incr(_ inc: Int) {
+     self += inc
+   }
+}
+
+func rdar33429010_2() {
+  let iter = I_33429010()
+  var acc: Int = 0 // expected-warning {{}}
+  let _: Int = AnySequence { iter }.rdar33429010(into: acc, { $0 + $1 })
+  // expected-warning@-1 {{result of operator '+' is unused}}
+  let _: Int = AnySequence { iter }.rdar33429010(into: acc, { $0.rdar33429010_incr($1) })
+}
+
+class P_33429010 {
+  var name: String = "foo"
+}
+
+class C_33429010 : P_33429010 {
+}
+
+func rdar33429010_3() {
+ let arr = [C_33429010()]
+ let _ = arr.map({ ($0.name, $0 as P_33429010) }) // Ok
+}
diff --git a/test/Driver/profiling.swift b/test/Driver/profiling.swift
index ccf6aa0..0ef41d7 100644
--- a/test/Driver/profiling.swift
+++ b/test/Driver/profiling.swift
@@ -46,3 +46,13 @@
 // LINUX: clang++{{"? }}
 // LINUX: lib/swift/clang/lib/linux/libclang_rt.profile-x86_64.a
 // LINUX: -u__llvm_profile_runtime
+
+// RUN: not %swiftc_driver -driver-print-jobs -profile-generate -profile-use=/dev/null %s 2>&1 | %FileCheck -check-prefix=MIX_GEN_USE %s
+// MIX_GEN_USE: conflicting options '-profile-generate' and '-profile-use'
+
+// RUN: not %swiftc_driver -driver-print-jobs -profile-use=%t.does_not_exist %s 2>&1 | %FileCheck -check-prefix=USE_MISSING_FILE %s
+// USE_MISSING_FILE: no profdata file exists at '{{[^']+}}.does_not_exist'
+
+// RUN: %swiftc_driver -driver-print-jobs -profile-use=/dev/null %s | %FileCheck -check-prefix=USE_DEVNULL %s
+// USE_DEVNULL: swift
+// USE_DEVNULL: -profile-use=/dev/null
diff --git a/test/Generics/requirement_inference.swift b/test/Generics/requirement_inference.swift
index ac124ae..658e1e5 100644
--- a/test/Generics/requirement_inference.swift
+++ b/test/Generics/requirement_inference.swift
@@ -76,8 +76,6 @@
 // CHECK-NEXT:   τ_0_0 : Canidae
 func inferSuperclassRequirement1<T : Carnivora>(
 	_ v: V<T>) {}
-// expected-warning@-2{{redundant superclass constraint 'T' : 'Carnivora'}}
-// expected-note@-2{{superclass constraint 'T' : 'Canidae' inferred from type here}}
 
 // CHECK-LABEL: .inferSuperclassRequirement2@
 // CHECK-NEXT: Requirements:
@@ -307,8 +305,8 @@
 }
 
 struct X22<T, U> {
-  func g<V>(_: V) where T: P20, // expected-warning{{redundant conformance constraint 'T': 'P20'}}
-                  U == X20<T> { } // expected-note{{conformance constraint 'T': 'P20' inferred from type here}}
+  func g<V>(_: V) where T: P20,
+                  U == X20<T> { }
 }
 
 // CHECK: Generic signature: <Self where Self : P22>
@@ -330,8 +328,8 @@
 // CHECK-NEXT: Canonical requirement signature: <τ_0_0 where τ_0_0.B : P20, τ_0_0.A == X20<τ_0_0.B>>
 protocol P23 {
   associatedtype A
-  associatedtype B: P20 // expected-warning{{redundant conformance constraint 'Self.B': 'P20'}}
-    where A == X20<B> // expected-note{{conformance constraint 'Self.B': 'P20' inferred from type here}}
+  associatedtype B: P20
+    where A == X20<B>
 }
 
 protocol P24 {
diff --git a/test/Generics/same_type_constraints.swift b/test/Generics/same_type_constraints.swift
index c30e592..381edb1 100644
--- a/test/Generics/same_type_constraints.swift
+++ b/test/Generics/same_type_constraints.swift
@@ -363,8 +363,8 @@
 
 struct X11<T: P10> where T.A == T.B { }
 
-func intracomponentInferred<T>(_: X11<T>) // expected-note{{previous same-type constraint 'T.A' == 'T.B' inferred from type here}}
-  where T.A == T.B { } // expected-warning{{redundant same-type constraint 'T.A' == 'T.B'}}
+func intracomponentInferred<T>(_: X11<T>)
+  where T.A == T.B { }
 
 // Suppress redundant same-type constraint warnings from result types.
 struct StructTakingP1<T: P1> { }
diff --git a/test/IDE/structure.swift b/test/IDE/structure.swift
index 336610d..4274fd2 100644
--- a/test/IDE/structure.swift
+++ b/test/IDE/structure.swift
@@ -232,3 +232,21 @@
 
 a.b(c: d?.e?.f, g: h)
 // CHECK: <call><name>a.b</name>(<arg><name>c</name>: d?.e?.f</arg>, <arg><name>g</name>: h</arg>)</call>
+
+struct Tuples {
+  var foo: (Int, String) {
+    return (1, "test")
+    // CHECK: <tuple>(<elem-expr>1</elem-expr>, <elem-expr>"test"</elem-expr>)</tuple>
+  }
+  
+  func foo2() {
+    foo3(x: (1, 20))
+    // CHECK: <call><name>foo3</name>(<arg><name>x</name>: <tuple>(<elem-expr>1</elem-expr>, <elem-expr>20</elem-expr>)</tuple></arg>)</call>
+    let y = (x, foo4(a: 0))
+    // CHECK: <lvar>let <name>y</name> = <tuple>(<elem-expr>x</elem-expr>, <elem-expr><call><name>foo4</name>(<arg><name>a</name>: 0</arg>)</call></elem-expr>)</tuple></lvar>
+    
+    let z = (name1: 1, name2: 2)
+    // CHECK: <lvar>let <name>z</name> = <tuple>(name1: <elem-expr>1</elem-expr>, name2: <elem-expr>2</elem-expr>)</tuple></lvar>
+  }
+}
+
diff --git a/test/IRGen/access_markers.sil b/test/IRGen/access_markers.sil
index 068e44d..f6794ac 100644
--- a/test/IRGen/access_markers.sil
+++ b/test/IRGen/access_markers.sil
@@ -33,7 +33,7 @@
   // CHECK-NEXT: call void @swift_endAccess([[BUFFER]]* [[SCRATCH1]])
   // CHECK-NEXT: [[T0:%.*]] = bitcast [[BUFFER]]* [[SCRATCH1]] to i8*
   // CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 {{.*}}, i8* [[T0]])
-  %4 = end_access %3 : $*Int
+  end_access %3 : $*Int
 
   // CHECK-NEXT: [[T0:%.*]] = bitcast [[BUFFER]]* [[SCRATCH2]] to i8*
   // CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 {{.*}}, i8* [[T0]])
@@ -44,7 +44,7 @@
   // CHECK-NEXT: call void @swift_endAccess([[BUFFER]]* [[SCRATCH2]])
   // CHECK-NEXT: [[T0:%.*]] = bitcast [[BUFFER]]* [[SCRATCH2]] to i8*
   // CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 {{.*}}, i8* [[T0]])
-  %6 = end_access %5 : $*Int
+  end_access %5 : $*Int
 
   %20 = tuple ()
   return %20 : $()
@@ -61,17 +61,17 @@
 
   // CHECK-NEXT: [[T1:%.*]] = bitcast [[INT]]* [[PROPERTY]] to i8*
   // CHECK-NEXT: call void @swift_beginAccess(i8* [[T1]], [[BUFFER]]* [[SCRATCH]], [[SIZE]] 1, i8* null)
-  %3 = begin_unpaired_access [modify] [dynamic] %2 : $*Int, %1 : $*Builtin.UnsafeValueBuffer
+  begin_unpaired_access [modify] [dynamic] %2 : $*Int, %1 : $*Builtin.UnsafeValueBuffer
 
   // CHECK-NEXT: call void @swift_endAccess([[BUFFER]]* [[SCRATCH]])
-  %4 = end_unpaired_access [dynamic] %1 : $*Builtin.UnsafeValueBuffer
+  end_unpaired_access [dynamic] %1 : $*Builtin.UnsafeValueBuffer
 
   // CHECK-NEXT: [[T1:%.*]] = bitcast [[INT]]* [[PROPERTY]] to i8*
   // CHECK-NEXT: call void @swift_beginAccess(i8* [[T1]], [[BUFFER]]* [[SCRATCH]], [[SIZE]] 0, i8* null)
-  %5 = begin_unpaired_access [read] [dynamic] %2 : $*Int, %1 : $*Builtin.UnsafeValueBuffer
+  begin_unpaired_access [read] [dynamic] %2 : $*Int, %1 : $*Builtin.UnsafeValueBuffer
 
   // CHECK-NEXT: call void @swift_endAccess([[BUFFER]]* [[SCRATCH]])
-  %6 = end_unpaired_access [dynamic] %1 : $*Builtin.UnsafeValueBuffer
+  end_unpaired_access [dynamic] %1 : $*Builtin.UnsafeValueBuffer
 
   dealloc_stack %1 : $*Builtin.UnsafeValueBuffer
 
@@ -88,18 +88,18 @@
   // CHECK-NEXT: [[T1:%.*]] = bitcast [[INT]]* [[PROPERTY]] to i8*
   // CHECK-NEXT: [[PC:%.*]] = call i8* @llvm.returnaddress(i32 0)
   // CHECK-NEXT: call void @swift_beginAccess(i8* [[T1]], [[BUFFER]]* [[SCRATCH:%1]], [[SIZE]] 1, i8* [[PC]])
-  %3 = begin_unpaired_access [modify] [dynamic] %2 : $*Int, %1 : $*Builtin.UnsafeValueBuffer
+  begin_unpaired_access [modify] [dynamic] %2 : $*Int, %1 : $*Builtin.UnsafeValueBuffer
 
   // CHECK-NEXT: call void @swift_endAccess([[BUFFER]]* [[SCRATCH]])
-  %4 = end_unpaired_access [dynamic] %1 : $*Builtin.UnsafeValueBuffer
+  end_unpaired_access [dynamic] %1 : $*Builtin.UnsafeValueBuffer
 
   // CHECK-NEXT: [[T1:%.*]] = bitcast [[INT]]* [[PROPERTY]] to i8*
   // CHECK-NEXT: [[PC:%.*]] = call i8* @llvm.returnaddress(i32 0)
   // CHECK-NEXT: call void @swift_beginAccess(i8* [[T1]], [[BUFFER]]* [[SCRATCH]], [[SIZE]] 0, i8* [[PC]])
-  %5 = begin_unpaired_access [read] [dynamic] %2 : $*Int, %1 : $*Builtin.UnsafeValueBuffer
+  begin_unpaired_access [read] [dynamic] %2 : $*Int, %1 : $*Builtin.UnsafeValueBuffer
 
   // CHECK-NEXT: call void @swift_endAccess([[BUFFER]]* [[SCRATCH]])
-  %6 = end_unpaired_access [dynamic] %1 : $*Builtin.UnsafeValueBuffer
+  end_unpaired_access [dynamic] %1 : $*Builtin.UnsafeValueBuffer
 
   %20 = tuple ()
   return %20 : $()
@@ -118,13 +118,13 @@
   %3 = begin_access [modify] [dynamic] %2 : $*()
   %write_fn = function_ref @writeEmptyTuple : $@convention(thin) (@inout ()) -> ()
   apply %write_fn(%3) : $@convention(thin) (@inout ()) -> ()
-  %4 = end_access %3 : $*()
+  end_access %3 : $*()
 
   // CHECK-NEXT: call {{.*}}void @readEmptyTuple(%swift.opaque* noalias nocapture undef)
   %5 = begin_access [read] [dynamic] %2 : $*()
   %read_fn = function_ref @readEmptyTuple : $@convention(thin) (@in_guaranteed ()) -> ()
   apply %read_fn(%5) : $@convention(thin) (@in_guaranteed ()) -> ()
-  %6 = end_access %5 : $*()
+  end_access %5 : $*()
 
   // CHECK-NEXT: ret void
   %20 = tuple ()
diff --git a/test/IRGen/associated_type_witness.swift b/test/IRGen/associated_type_witness.swift
index 47e64cf..5b1f25e 100644
--- a/test/IRGen/associated_type_witness.swift
+++ b/test/IRGen/associated_type_witness.swift
@@ -51,21 +51,21 @@
 //   Associated type metadata access function for Fulfilled.Assoc.
 // CHECK-LABEL:  define internal %swift.type* @_T023associated_type_witness9FulfilledVyxGAA8AssockedA2A1PRzAA1QRzl5AssocWt(%swift.type* %"Fulfilled<T>", i8** %"Fulfilled<T>.Assocked")
 // CHECK:         [[T0:%.*]] = bitcast %swift.type* %"Fulfilled<T>" to %swift.type**
-// CHECK-NEXT:    [[T1:%.*]] = getelementptr inbounds %swift.type*, %swift.type** [[T0]], i64 3
+// CHECK-NEXT:    [[T1:%.*]] = getelementptr inbounds %swift.type*, %swift.type** [[T0]], i64 2
 // CHECK-NEXT:    [[T2:%.*]] = load %swift.type*, %swift.type** [[T1]], align 8, !invariant.load
 // CHECK-NEXT:    ret %swift.type* [[T2]]
 
 //   Associated type witness table access function for Fulfilled.Assoc : P.
 // CHECK-LABEL:  define internal i8** @_T023associated_type_witness9FulfilledVyxGAA8AssockedA2A1PRzAA1QRzl5AssocAaFPWT(%swift.type* %"Fulfilled<T>.Assoc", %swift.type* %"Fulfilled<T>", i8** %"Fulfilled<T>.Assocked")
 // CHECK:         [[T0:%.*]] = bitcast %swift.type* %"Fulfilled<T>" to i8***
-// CHECK-NEXT:    [[T1:%.*]] = getelementptr inbounds i8**, i8*** [[T0]], i64 4
+// CHECK-NEXT:    [[T1:%.*]] = getelementptr inbounds i8**, i8*** [[T0]], i64 3
 // CHECK-NEXT:    [[T2:%.*]] = load i8**, i8*** [[T1]], align 8, !invariant.load
 // CHECK-NEXT:    ret i8** [[T2]]
 
 //   Associated type witness table access function for Fulfilled.Assoc : Q.
 // CHECK-LABEL:  define internal i8** @_T023associated_type_witness9FulfilledVyxGAA8AssockedA2A1PRzAA1QRzl5AssocAaGPWT(%swift.type* %"Fulfilled<T>.Assoc", %swift.type* %"Fulfilled<T>", i8** %"Fulfilled<T>.Assocked")
 // CHECK:         [[T0:%.*]] = bitcast %swift.type* %"Fulfilled<T>" to i8***
-// CHECK-NEXT:    [[T1:%.*]] = getelementptr inbounds i8**, i8*** [[T0]], i64 5
+// CHECK-NEXT:    [[T1:%.*]] = getelementptr inbounds i8**, i8*** [[T0]], i64 4
 // CHECK-NEXT:    [[T2:%.*]] = load i8**, i8*** [[T1]], align 8, !invariant.load
 // CHECK-NEXT:    ret i8** [[T2]]
 
@@ -108,10 +108,10 @@
 // CHECK-NEXT:     ret %swift.type* [[T0]]
 // CHECK:        fetch:
 // CHECK-NEXT:    [[T0:%.*]] = bitcast %swift.type* %"Computed<T, U>" to %swift.type**
-// CHECK-NEXT:    [[T1:%.*]] = getelementptr inbounds %swift.type*, %swift.type** [[T0]], i64 3
+// CHECK-NEXT:    [[T1:%.*]] = getelementptr inbounds %swift.type*, %swift.type** [[T0]], i64 2
 // CHECK-NEXT:    [[T:%.*]] = load %swift.type*, %swift.type** [[T1]], align 8, !invariant.load
 // CHECK:         [[T0:%.*]] = bitcast %swift.type* %"Computed<T, U>" to %swift.type**
-// CHECK-NEXT:    [[T1:%.*]] = getelementptr inbounds %swift.type*, %swift.type** [[T0]], i64 4
+// CHECK-NEXT:    [[T1:%.*]] = getelementptr inbounds %swift.type*, %swift.type** [[T0]], i64 3
 // CHECK-NEXT:    [[U:%.*]] = load %swift.type*, %swift.type** [[T1]], align 8, !invariant.load
 // CHECK-NEXT:    [[FETCH_RESULT]] = call %swift.type* @_T023associated_type_witness4PairVMa(%swift.type* [[T]], %swift.type* [[U]])
 // CHECK-NEXT:    store atomic %swift.type* [[FETCH_RESULT]], %swift.type** [[CACHE]] release, align 8
diff --git a/test/IRGen/class_bounded_generics.swift b/test/IRGen/class_bounded_generics.swift
index 184f8ae..573a13b 100644
--- a/test/IRGen/class_bounded_generics.swift
+++ b/test/IRGen/class_bounded_generics.swift
@@ -1,4 +1,4 @@
-// RUN: %target-swift-frontend -assume-parsing-unqualified-ownership-sil -emit-ir -primary-file %s -disable-objc-attr-requires-foundation-module | %FileCheck %s
+// RUN: %target-swift-frontend -emit-ir -primary-file %s -disable-objc-attr-requires-foundation-module | %FileCheck %s
 
 // REQUIRES: CPU=x86_64
 // XFAIL: linux
@@ -9,7 +9,7 @@
 protocol ClassBound2 : class {
   func classBoundMethod2()
 }
-protocol ClassBoundBinary : class, ClassBound {
+protocol ClassBoundBinary : ClassBound {
   func classBoundBinaryMethod(_ x: Self)
 }
 @objc protocol ObjCClassBound {
@@ -214,7 +214,7 @@
 }
 
 // CHECK-LABEL: define hidden swiftcc { i64, %objc_object*, i64 } @_T022class_bounded_generics0A28_generic_field_struct_fields{{[_0-9a-zA-Z]*}}F(i64, %objc_object*, i64, %swift.type* %T, i8** %T.ClassBound)
-func class_generic_field_struct_fields<T : ClassBound>
+func class_generic_field_struct_fields<T>
 (_ x:ClassGenericFieldStruct<T>) -> (Int, T, Int) {
   return (x.x, x.y, x.z)
 }
@@ -226,7 +226,7 @@
 }
 
 // CHECK-LABEL: define hidden swiftcc { i64, %objc_object*, i64 } @_T022class_bounded_generics0a15_generic_field_A7_fields{{[_0-9a-zA-Z]*}}F(%T22class_bounded_generics017ClassGenericFieldD0C*)
-func class_generic_field_class_fields<T : ClassBound>
+func class_generic_field_class_fields<T>
 (_ x:ClassGenericFieldClass<T>) -> (Int, T, Int) {
   return (x.x, x.y, x.z)
   // CHECK: getelementptr inbounds %T22class_bounded_generics017ClassGenericFieldD0C, %T22class_bounded_generics017ClassGenericFieldD0C* %0, i32 0, i32 1
@@ -273,3 +273,36 @@
     s = S.init()
   }
 }
+
+// CHECK-LABEL: define hidden swiftcc void @_T022class_bounded_generics14takes_metatypeyxmlF(%swift.type*, %swift.type* %T)
+func takes_metatype<T>(_: T.Type) {}
+
+// CHECK-LABEL: define hidden swiftcc void @_T022class_bounded_generics023archetype_with_generic_A11_constraintyx1t_tAA1ACyq_GRbzr0_lF(%T22class_bounded_generics1AC.2*, %swift.type* %T)
+// CHECK:      [[ISA_ADDR:%.*]] = bitcast %T22class_bounded_generics1AC.2* %0 to %swift.type**
+// CHECK-NEXT: [[ISA:%.*]] = load %swift.type*, %swift.type** [[ISA_ADDR]]
+// CHECK-NEXT: call swiftcc void @_T022class_bounded_generics14takes_metatypeyxmlF(%swift.type* %T, %swift.type* %T)
+// CHECK-NEXT: [[ISA_PTR:%.*]] = bitcast %swift.type* [[ISA]] to %swift.type**
+// CHECK-NEXT: [[U_ADDR:%.*]] = getelementptr inbounds %swift.type*, %swift.type** [[ISA_PTR]], i64 10
+// CHECK-NEXT: [[U:%.*]] = load %swift.type*, %swift.type** [[U_ADDR]]
+// CHECK-NEXT: call swiftcc void @_T022class_bounded_generics14takes_metatypeyxmlF(%swift.type* %U, %swift.type* %U)
+// CHECK:      ret void
+
+func archetype_with_generic_class_constraint<T, U>(t: T) where T : A<U> {
+  takes_metatype(T.self)
+  takes_metatype(U.self)
+}
+
+// CHECK-LABEL: define hidden swiftcc void @_T022class_bounded_generics029calls_archetype_with_generic_A11_constraintyAA1ACyxG1a_tlF(%T22class_bounded_generics1AC*) #0 {
+// CHECK:      [[ISA_ADDR:%.*]] = getelementptr inbounds %T22class_bounded_generics1AC, %T22class_bounded_generics1AC* %0, i32 0, i32 0, i32 0
+// CHECK-NEXT: [[ISA:%.*]] = load %swift.type*, %swift.type** [[ISA_ADDR]]
+// CHECK:      [[SELF:%.*]] = bitcast %T22class_bounded_generics1AC* %0 to %T22class_bounded_generics1AC.2*
+// CHECK-NEXT: [[ISA_PTR:%.*]] = bitcast %swift.type* [[ISA]] to %swift.type**
+// CHECK-NEXT: [[T_ADDR:%.*]] = getelementptr inbounds %swift.type*, %swift.type** [[ISA_PTR]], i64 10
+// CHECK-NEXT: [[T:%.*]] = load %swift.type*, %swift.type** [[T_ADDR]]
+// CHECK-NEXT: [[A_OF_T:%.*]] = call %swift.type* @_T022class_bounded_generics1ACMa(%swift.type* [[T]])
+// CHECK-NEXT: call swiftcc void @_T022class_bounded_generics023archetype_with_generic_A11_constraintyx1t_tAA1ACyq_GRbzr0_lF(%T22class_bounded_generics1AC.2* [[SELF]], %swift.type* [[A_OF_T]])
+// CHECK:      ret void
+
+func calls_archetype_with_generic_class_constraint<T>(a: A<T>) {
+  archetype_with_generic_class_constraint(t: a)
+}
diff --git a/test/IRGen/enum.sil b/test/IRGen/enum.sil
index 6985832..e6d1f54 100644
--- a/test/IRGen/enum.sil
+++ b/test/IRGen/enum.sil
@@ -107,75 +107,86 @@
 // CHECK: [[DYNAMICSINGLETON_FIELD_NAMES:@.*]] = private constant [7 x i8] c"value\00\00"
 // CHECK: [[DYNAMICSINGLETON_NAME:@.*]] = private constant [25 x i8] c"4enum16DynamicSingletonO\00"
 // CHECK: @_T04enum16DynamicSingletonOMn = hidden constant <{ {{.*}} i32 }> <{
-// CHECK:   [25 x i8]* [[DYNAMICSINGLETON_NAME]]
+// CHECK-SAME:   [25 x i8]* [[DYNAMICSINGLETON_NAME]]
 // --       One payload
-// CHECK:   i32 1,
+// CHECK-SAME:   i32 1,
 // --       No empty cases
-// CHECK:   i32 0,
+// CHECK-SAME:   i32 0,
 // --       Case names
-// CHECK:   [[DYNAMICSINGLETON_FIELD_NAMES]]
+// CHECK-SAME:   [[DYNAMICSINGLETON_FIELD_NAMES]]
 // --       Case type accessor
-// CHECK:   @get_field_types_DynamicSingleton
+// CHECK-SAME:   @get_field_types_DynamicSingleton
 // --       generic parameter vector offset
-// CHECK:   i32 3,
+// CHECK-SAME:   i32 2,
 // --       generic parameter vector length; witness table counts
-// CHECK:   i32 1, i32 0
-// CHECK: }>
+// CHECK-SAME:   i32 1, i32 1
+// --       nesting depth
+// CHECK-SAME:   i16 1
+// --       flags
+// CHECK-SAME:   i16 0
+// --       generic parameters at depth 0
+// CHECK-SAME:   i32 1
+// CHECK-SAME: }>
 
 // CHECK: @_T04enum16DynamicSingletonOMP = internal global <{ {{.*}}, [16 x i8*] }> <{
-// CHECK:   %swift.type* (%swift.type_pattern*, i8**)* @create_generic_metadata_DynamicSingleton
-// CHECK:   @_T04enum16DynamicSingletonOMn
-// CHECK:   i8* null
-// CHECK:   i8* bitcast (void (%swift.opaque*, i32, %swift.type*)* @_T04enum16DynamicSingletonOwxs to i8*)
-// CHECK:   i8* bitcast (i32 (%swift.opaque*, %swift.type*)* @_T04enum16DynamicSingletonOwxg to i8*)
+// CHECK-SAME:   %swift.type* (%swift.type_pattern*, i8**)* @create_generic_metadata_DynamicSingleton
+// CHECK-SAME:   @_T04enum16DynamicSingletonOMn
+// CHECK-SAME:   i8* null
+// CHECK-SAME:   i8* bitcast (void (%swift.opaque*, i32, %swift.type*)* @_T04enum16DynamicSingletonOwxs to i8*)
+// CHECK-SAME:   i8* bitcast (i32 (%swift.opaque*, %swift.type*)* @_T04enum16DynamicSingletonOwxg to i8*)
 
 // -- No-payload enums have extra inhabitants in
 //    their value witness table.
 // CHECK: @_T04enum10NoPayloadsOWV = internal constant [16 x i8*] [
 // -- ...
 // -- size
-// CHECK:   i8* inttoptr ([[WORD:i32|i64]] 1 to i8*),
+// CHECK-SAME:   i8* inttoptr ([[WORD:i32|i64]] 1 to i8*),
 // -- flags                 0x24_0000 - alignment 1, has extra inhabitants and enum witnesses
-// CHECK:   i8* inttoptr ([[WORD]] 2359296 to i8*),
+// CHECK-SAME:   i8* inttoptr ([[WORD]] 2359296 to i8*),
 // -- stride
-// CHECK:   i8* inttoptr ([[WORD]] 1 to i8*),
+// CHECK-SAME:   i8* inttoptr ([[WORD]] 1 to i8*),
 // -- num extra inhabitants (256 - 3 valid states)
-// CHECK:   i8* inttoptr ([[WORD]] 253 to i8*)
+// CHECK-SAME:   i8* inttoptr ([[WORD]] 253 to i8*)
 // -- storeExtraInhabitant
-// CHECK:   i8* bitcast (void (%swift.opaque*, i32, %swift.type*)* @_T04enum10NoPayloadsOwxs to i8*)
+// CHECK-SAME:   i8* bitcast (void (%swift.opaque*, i32, %swift.type*)* @_T04enum10NoPayloadsOwxs to i8*)
 // -- getExtraInhabitantIndex
-// CHECK:   i8* bitcast (i32 (%swift.opaque*, %swift.type*)* @_T04enum10NoPayloadsOwxg to i8*)
-// CHECK: ]
+// CHECK-SAME:   i8* bitcast (i32 (%swift.opaque*, %swift.type*)* @_T04enum10NoPayloadsOwxg to i8*)
+// CHECK-SAME: ]
 
 // -- Single-payload enums take unused extra inhabitants from their payload
 //    as their own.
 // CHECK: @_T04enum19SinglePayloadNestedOWV = internal constant [16 x i8*] [
 // -- ...
 // -- size
-// CHECK:   i8* inttoptr ([[WORD]] 1 to i8*),
+// CHECK-SAME:   i8* inttoptr ([[WORD]] 1 to i8*),
 // -- flags                 0x4_0000 - alignment 1, has extra inhabitants
-// CHECK:   i8* inttoptr ([[WORD]] 2359296 to i8*),
+// CHECK-SAME:   i8* inttoptr ([[WORD]] 2359296 to i8*),
 // -- stride
-// CHECK:   i8* inttoptr ([[WORD]] 1 to i8*),
+// CHECK-SAME:   i8* inttoptr ([[WORD]] 1 to i8*),
 // -- num extra inhabitants (253 from payload - 3 empty cases)
-// CHECK:   i8* inttoptr ([[WORD]] 250 to i8*)
+// CHECK-SAME:   i8* inttoptr ([[WORD]] 250 to i8*)
 // -- storeExtraInhabitant
-// CHECK:   i8* bitcast (void (%swift.opaque*, i32, %swift.type*)* @_T04enum19SinglePayloadNestedOwxs to i8*)
+// CHECK-SAME:   i8* bitcast (void (%swift.opaque*, i32, %swift.type*)* @_T04enum19SinglePayloadNestedOwxs to i8*)
 // -- getExtraInhabitantIndex
-// CHECK:   i8* bitcast (i32 (%swift.opaque*, %swift.type*)* @_T04enum19SinglePayloadNestedOwxg to i8*)
-// CHECK: ]
+// CHECK-SAME:   i8* bitcast (i32 (%swift.opaque*, %swift.type*)* @_T04enum19SinglePayloadNestedOwxg to i8*)
+// CHECK-SAME: ]
 
 
 // CHECK: @_T04enum20DynamicSinglePayloadOMP = internal global <{ {{.*}}, [16 x i8*] }> <{
-// CHECK:   %swift.type* (%swift.type_pattern*, i8**)* @create_generic_metadata_DynamicSinglePayload
-// CHECK:   i8* null
-// CHECK:   i8* bitcast (void (%swift.opaque*, i32, %swift.type*)* @_T04enum20DynamicSinglePayloadOwxs to i8*)
-// CHECK:   i8* bitcast (i32 (%swift.opaque*, %swift.type*)* @_T04enum20DynamicSinglePayloadOwxg to i8*)
+// CHECK-SAME:   %swift.type* (%swift.type_pattern*, i8**)* @create_generic_metadata_DynamicSinglePayload
+// CHECK-SAME:   i8* null
+// CHECK-SAME:   i8* bitcast (void (%swift.opaque*, i32, %swift.type*)* @_T04enum20DynamicSinglePayloadOwxs to i8*)
+// CHECK-SAME:   i8* bitcast (i32 (%swift.opaque*, %swift.type*)* @_T04enum20DynamicSinglePayloadOwxg to i8*)
 
 // CHECK: @_T04enum18MultiPayloadNestedOWV = internal constant [16 x i8*] [
-// CHECK:   i8* inttoptr ([[WORD]] 9 to i8*),
-// CHECK:   i8* inttoptr ([[WORD]] 16 to i8*)
-// CHECK: ]
+// -- size
+// CHECK-32-SAME:   i8* inttoptr ([[WORD]] 5 to i8*),
+// CHECK-64-SAME:   i8* inttoptr ([[WORD]] 9 to i8*),
+// -- flags                 0x250003 - alignment 4
+// CHECK-32-SAME:   i8* inttoptr ([[WORD]] {{2424835|2097155}} to i8*)
+// -- flags                 0x200007 - alignment 8
+// CHECK-64-SAME:   i8* inttoptr ([[WORD]] 2097159 to i8*)
+// CHECK-SAME: ]
 
 enum Empty {}
 
@@ -2660,10 +2671,10 @@
 // CHECK:   [[T:%T]] = load %swift.type*, %swift.type** [[T0]],
 // CHECK:   [[METADATA:%.*]] = call %swift.type* @swift_allocateGenericValueMetadata(%swift.type_pattern* %0, i8** %1)
 // CHECK:   [[METADATA_ARRAY:%.*]] = bitcast %swift.type* [[METADATA]] to i8**
-// CHECK:   [[T1:%.*]] = getelementptr inbounds i8*, i8** [[METADATA_ARRAY]], i32 3
+// CHECK:   [[T1:%.*]] = getelementptr inbounds i8*, i8** [[METADATA_ARRAY]], i32 2
 // CHECK:   [[T0:%.*]] = bitcast %swift.type* [[T]] to i8*
 // CHECK:   store i8* [[T0]], i8** [[T1]]
-// CHECK:   [[VWT:%.*]] = getelementptr inbounds i8*, i8** [[METADATA_ARRAY]], i32 5
+// CHECK:   [[VWT:%.*]] = getelementptr inbounds i8*, i8** [[METADATA_ARRAY]], i32 4
 // CHECK:   [[T0:%.*]] = bitcast i8** [[VWT]] to i8*
 // CHECK:   [[T1:%.*]] = getelementptr inbounds i8*, i8** [[METADATA_ARRAY]], i32 -1
 // CHECK:   store i8* [[T0]], i8** [[T1]]
diff --git a/test/IRGen/enum_resilience.swift b/test/IRGen/enum_resilience.swift
index e58ee04..f2f4ece 100644
--- a/test/IRGen/enum_resilience.swift
+++ b/test/IRGen/enum_resilience.swift
@@ -254,7 +254,7 @@
 
 // CHECK-LABEL: define{{( protected)?}} swiftcc %swift.type* @_T014resilient_enum32ResilientMultiPayloadGenericEnumO0B11_resilienceE16getTypeParameterxmyF(%swift.type* %"ResilientMultiPayloadGenericEnum<T>", %swift.opaque* noalias nocapture swiftself)
 // CHECK: [[METADATA:%.*]] = bitcast %swift.type* %"ResilientMultiPayloadGenericEnum<T>" to %swift.type**
-// CHECK-NEXT: [[T_ADDR:%.*]] = getelementptr inbounds %swift.type*, %swift.type** [[METADATA]], [[INT]] 3
+// CHECK-NEXT: [[T_ADDR:%.*]] = getelementptr inbounds %swift.type*, %swift.type** [[METADATA]], [[INT]] 2
 // CHECK-NEXT: [[T:%.*]] = load %swift.type*, %swift.type** [[T_ADDR]]
   public func getTypeParameter() -> T.Type {
     return T.self
diff --git a/test/IRGen/enum_value_semantics.sil b/test/IRGen/enum_value_semantics.sil
index 734169d..1f1800c 100644
--- a/test/IRGen/enum_value_semantics.sil
+++ b/test/IRGen/enum_value_semantics.sil
@@ -119,7 +119,6 @@
 // CHECK-SAME:   i8** getelementptr inbounds ([16 x i8*], [16 x i8*]* @_T020enum_value_semantics20SinglePayloadTrivialOWV, i32 0, i32 0),
 // CHECK-SAME:   i64 2,
 // CHECK-SAME:   {{.*}}* @_T020enum_value_semantics20SinglePayloadTrivialOMn
-// CHECK-SAME:   %swift.type* null
 // CHECK-SAME: }>
 
 
@@ -150,13 +149,12 @@
 // CHECK-SAME:   i8** getelementptr inbounds ([16 x i8*], [16 x i8*]* @_T020enum_value_semantics23SinglePayloadNontrivialOWV, i32 0, i32 0),
 // CHECK-SAME:   i64 2,
 // CHECK-SAME:   {{.*}}* @_T020enum_value_semantics23SinglePayloadNontrivialOMn
-// CHECK-SAME:   %swift.type* null
 // CHECK-SAME: }>
 
 
 // CHECK-LABEL: @_T020enum_value_semantics18GenericFixedLayoutOMP = internal global <{{[{].*\* [}]}}> <{
 // CHECK:   %swift.type* (%swift.type_pattern*, i8**)* @create_generic_metadata_GenericFixedLayout
-// CHECK:   i32 48, i16 1, i16 8,
+// CHECK:   i32 40, i16 1, i16 8,
 // CHECK:   [16 x i8*] zeroinitializer,
 // CHECK:   i8** getelementptr inbounds ([16 x i8*], [16 x i8*]* @_T020enum_value_semantics18GenericFixedLayoutOWV, i32 0, i32 0),
 // CHECK:   i64 2,
diff --git a/test/IRGen/field_type_vectors.sil b/test/IRGen/field_type_vectors.sil
index 9908a8c..e526e07 100644
--- a/test/IRGen/field_type_vectors.sil
+++ b/test/IRGen/field_type_vectors.sil
@@ -13,9 +13,9 @@
 // CHECK-LABEL: @_T018field_type_vectors3BarVMn = hidden constant
 // CHECK:         %swift.type** (%swift.type*)* [[BAR_TYPES_ACCESSOR:@[A-Za-z0-9_]*]]
 // CHECK-LABEL: @_T018field_type_vectors3BarVMP = internal global
-// -- There should be 5 words between the address point and the field type
+// -- There should be 4 words between the address point and the field type
 //    vector slot, with type %swift.type**
-// CHECK:         i64, i64, i64, i64, %swift.type*, %swift.type**
+// CHECK:         i64, i64, i64, %swift.type*, %swift.type**
 struct Bar<T> {
   var y: Int
 }
@@ -23,9 +23,9 @@
 // CHECK-LABEL: @_T018field_type_vectors3BasVMn = hidden constant
 // CHECK:         %swift.type** (%swift.type*)* [[BAS_TYPES_ACCESSOR:@[A-Za-z0-9_]*]]
 // CHECK-LABEL: @_T018field_type_vectors3BasVMP = internal global
-// -- There should be 7 words between the address point and the field type
+// -- There should be 6 words between the address point and the field type
 //    vector slot, with type %swift.type**
-// CHECK:         i64, i64, i64, i64, i64, %swift.type*, %swift.type*, %swift.type**
+// CHECK:          i64, i64, i64, %swift.type*, %swift.type*, %swift.type**
 struct Bas<T, U> {
   var foo: Foo
   var bar: Bar<T>
@@ -83,8 +83,8 @@
 
 // CHECK: define{{( protected)?}} private %swift.type** [[BAR_TYPES_ACCESSOR]](%swift.type* %"Bar<T>")
 // CHECK:   [[T0:%.*]] = bitcast %swift.type* %"Bar<T>" to %swift.type***
-// -- 5 words between the address point and the slot
-// CHECK:   [[SLOT:%.*]] = getelementptr inbounds %swift.type**, %swift.type*** [[T0]], i32 5
+// -- 4 words between the address point and the slot
+// CHECK:   [[SLOT:%.*]] = getelementptr inbounds %swift.type**, %swift.type*** [[T0]], i32 4
 // CHECK:   load %swift.type**, %swift.type*** [[SLOT]], align 8
 // CHECK:   br
 // CHECK-NOT: load %swift.type*,
@@ -93,8 +93,8 @@
 
 // CHECK: define{{( protected)?}} private %swift.type** [[BAS_TYPES_ACCESSOR]](%swift.type* %"Bas<T, U>")
 // CHECK:   [[T0:%.*]] = bitcast %swift.type* %"Bas<T, U>" to %swift.type***
-// -- 7 words between the address point and the slot
-// CHECK:   [[SLOT:%.*]] = getelementptr inbounds %swift.type**, %swift.type*** [[T0]], i32 7
+// -- 6 words between the address point and the slot
+// CHECK:   [[SLOT:%.*]] = getelementptr inbounds %swift.type**, %swift.type*** [[T0]], i32 6
 // CHECK:   load %swift.type**, %swift.type*** [[SLOT]], align 8
 // CHECK:   br
 // CHECK:   store {{.*}} @_T018field_type_vectors3FooVMf
diff --git a/test/IRGen/foreign_types.sil b/test/IRGen/foreign_types.sil
index b52ce5b..ac6281d 100644
--- a/test/IRGen/foreign_types.sil
+++ b/test/IRGen/foreign_types.sil
@@ -4,14 +4,12 @@
 import c_layout
 
 // CHECK-LABEL: @_T0SC14HasNestedUnionV18__Unnamed_struct_sVN = linkonce_odr hidden global
-// CHECK-SAME:  void (%swift.type*)* @initialize_metadata___Unnamed_struct_s,
 // CHECK-SAME:  i8* getelementptr inbounds
 // CHECK-SAME:  %swift.type* null,
-// CHECK-SAME:  [[INT:i[0-9]+]] 1,
+// CHECK-SAME:  [[INT:i[0-9]+]] 0,
 // CHECK-SAME:  @_T0SC14HasNestedUnionV18__Unnamed_struct_sVWV
 // CHECK-SAME:  [[INT]] 1,
 // CHECK-SAME:  [[INT]] sub ({{.*}}),
-// CHECK-SAME:  %swift.type* null,
 // CHECK-SAME:  [[INT]] 0,
 // CHECK-SAME:  [[INT]] 4 }
 
@@ -22,10 +20,3 @@
   %ret = tuple ()
   return %ret : $()
 }
-
-// CHECK-LABEL: define private void @initialize_metadata___Unnamed_struct_s
-// CHECK:       [[PARENT:%.*]] = call %swift.type* @_T0SC14HasNestedUnionVMa()
-// CHECK-NEXT:  [[T0:%.]] = bitcast %swift.type* %0 to %swift.type**
-// CHECK-NEXT:  [[T1:%.]] = getelementptr inbounds %swift.type*, %swift.type** [[T0]], [[INT]] 2
-// CHECK-NEXT:  store %swift.type* [[PARENT]], %swift.type** [[T1]],
-// CHECK-NEXT:  ret void
diff --git a/test/IRGen/generic_classes.sil b/test/IRGen/generic_classes.sil
index e3f4c6f..62ab6c6 100644
--- a/test/IRGen/generic_classes.sil
+++ b/test/IRGen/generic_classes.sil
@@ -27,8 +27,12 @@
 // CHECK-SAME:   i32 10,
 // --       generic parameter count, primary count
 // CHECK-SAME:   i32 1, i32 1,
+// --       nesting depth
+// CHECK-SAME:   i16 1,
 // --       flags -- has vtable
-// CHECK-SAME:   i32 4,
+// CHECK-SAME:   i16 4,
+// --       generic parameters at depth 0
+// CHECK-SAME:   i32 1,
 // --       vtable offset
 // CHECK-SAME:   i32 11,
 // --       vtable size
diff --git a/test/IRGen/generic_structs.sil b/test/IRGen/generic_structs.sil
index 4d3ee50..1796e4b 100644
--- a/test/IRGen/generic_structs.sil
+++ b/test/IRGen/generic_structs.sil
@@ -12,39 +12,45 @@
 // CHECK: [[SINGLEDYNAMIC_FIELDS:@.*]] = private constant [3 x i8] c"x\00\00"
 // CHECK: @_T015generic_structs13SingleDynamicVMn = hidden constant <{ {{.*}} i32 }> <{
 // --       name
-// CHECK:   [34 x i8]* [[SINGLEDYNAMIC_NAME]]
+// CHECK-SAME:   [34 x i8]* [[SINGLEDYNAMIC_NAME]]
 // --       field count
-// CHECK:   i32 1,
+// CHECK-SAME:   i32 1,
 // --       field offset vector offset
-// CHECK:   i32 3,
+// CHECK-SAME:   i32 2,
 // --       field names
-// CHECK:   [3 x i8]* [[SINGLEDYNAMIC_FIELDS]]
+// CHECK-SAME:   [3 x i8]* [[SINGLEDYNAMIC_FIELDS]]
 // --       generic metadata pattern, kind 1 (struct)
-// CHECK:   i32 add ({{.*}}@_T015generic_structs13SingleDynamicVMP{{.*}}, i32 1)
+// CHECK-SAME:   i32 add ({{.*}}@_T015generic_structs13SingleDynamicVMP{{.*}}, i32 1)
 // --       generic parameter vector offset
-// CHECK:   i32 4,
-// --       generic parameter count, primary counts; generic parameter witness counts
-// CHECK:   i32 1, i32 1, i32 0
-// CHECK: }>
+// CHECK-SAME:   i32 3,
+// --       generic parameter count, primary count
+// CHECK-SAME:   i32 1, i32 1
+// --       nesting depth
+// CHECK-SAME: i16 1,
+// --       flags
+// CHECK-SAME: i16 0,
+// --       generic parameters at depth 0
+// CHECK-SAME: i32 1
+// CHECK-SAME: }>
 // CHECK: @_T015generic_structs13SingleDynamicVMP = internal global <{ {{.*}} }> <{
 // -- template header
-// CHECK:   %swift.type* (%swift.type_pattern*, i8**)* @create_generic_metadata_SingleDynamic,
-// CHECK:   i32 160, i16 1, i16 8, [{{[0-9]+}} x i8*] zeroinitializer,
+// CHECK-SAME:   %swift.type* (%swift.type_pattern*, i8**)* @create_generic_metadata_SingleDynamic,
+// CHECK-SAME:   i32 152, i16 1, i16 8, [{{[0-9]+}} x i8*] zeroinitializer,
 // -- placeholder for vwtable pointer
-// CHECK:   i8* null,
+// CHECK-SAME:   i8* null,
 // -- address point
-// CHECK:   i64 1, {{.*}}* @_T015generic_structs13SingleDynamicVMn
+// CHECK-SAME:   i64 1, {{.*}}* @_T015generic_structs13SingleDynamicVMn
 // -- field offset vector; generic parameter vector
-// CHECK:   i64 0, %swift.type* null,
+// CHECK-SAME:   i64 0, %swift.type* null,
 // -- tail-allocated vwtable pattern
-// CHECK:   i8* bitcast (%swift.opaque* ([24 x i8]*, [24 x i8]*, %swift.type*)* @_T015generic_structs13SingleDynamicVwCP to i8*),
+// CHECK-SAME:   i8* bitcast (%swift.opaque* ([24 x i8]*, [24 x i8]*, %swift.type*)* @_T015generic_structs13SingleDynamicVwCP to i8*),
 // -- ...
 // -- placeholder for size, flags, stride
-// CHECK:   i8* null, i8* null, i8* null
+// CHECK-SAME:   i8* null, i8* null, i8* null
 // -- extra inhabitants
-// CHECK:   i8* null,
-// CHECK:   i8* bitcast (void (%swift.opaque*, i32, %swift.type*)* @_T015generic_structs13SingleDynamicVwxs to i8*),
-// CHECK:   i8* bitcast (i32 (%swift.opaque*, %swift.type*)* @_T015generic_structs13SingleDynamicVwxg to i8*)] }>
+// CHECK-SAME:   i8* null,
+// CHECK-SAME:   i8* bitcast (void (%swift.opaque*, i32, %swift.type*)* @_T015generic_structs13SingleDynamicVwxs to i8*),
+// CHECK-SAME:   i8* bitcast (i32 (%swift.opaque*, %swift.type*)* @_T015generic_structs13SingleDynamicVwxg to i8*)] }>
 // CHECK-NOT: @_T015generic_structs13SingleDynamicVWV
 
 // -- Nominal type descriptor for generic struct with protocol requirements
@@ -57,15 +63,21 @@
 // --       field count
 // CHECK-SAME: i32 2,
 // --       field offset vector offset
-// CHECK-SAME: i32 3,
+// CHECK-SAME: i32 2,
 // --       field names
 // CHECK-SAME: [5 x i8]* [[DYNAMICWITHREQUIREMENTS_FIELDS]]
 // --       generic metadata pattern
 // CHECK-SAME: i32 add ({{.*}}@_T015generic_structs23DynamicWithRequirementsVMP{{.*}}, i32 1)
 // --       generic parameter vector offset
-// CHECK-SAME: i32 5,
-// --       generic requirements count; generic arguments count; flags; generic parameter witness counts
-// CHECK-SAME: i32 4, i32 2, i32 0
+// CHECK-SAME: i32 4,
+// --       generic requirements count; generic arguments count
+// CHECK-SAME: i32 4, i32 2
+// --       nesting depth
+// CHECK-SAME: i16 1,
+// --       flags
+// CHECK-SAME: i16 0,
+// --       generic parameters at depth 0
+// CHECK-SAME: i32 2
 // CHECK-SAME: }>
 
 // CHECK: @_T015generic_structs23DynamicWithRequirementsVMP = internal global <{ {{.*}} }> <{
@@ -75,14 +87,14 @@
 
 // -- Fixed-layout struct metadata contains fixed field offsets
 // CHECK: @_T015generic_structs6IntishVMf = internal constant <{ {{.*}} i64 }> <{
-// CHECK:   i64 0
-// CHECK: }>
+// CHECK-SAME:   i64 0
+// CHECK-SAME: }>
 // CHECK: @_T015generic_structs7CharethVMf = internal constant <{ {{.*}} i64 }> <{
-// CHECK:   i64 0
-// CHECK: }>
+// CHECK-SAME:   i64 0
+// CHECK-SAME: }>
 // CHECK: @_T015generic_structs8StringlyVMf = internal constant <{ {{.*}} i64, i64, i64 }> <{
-// CHECK:   i64 0, i64 8, i64 16
-// CHECK: }>
+// CHECK-SAME:   i64 0, i64 8, i64 16
+// CHECK-SAME: }>
 
 struct SingleDynamic<T> {
   var x : T
@@ -134,7 +146,7 @@
   %a = struct_element_addr %0 : $*ComplexDynamic<A, B>, #ComplexDynamic.a2
 
   // CHECK: [[METADATA:%.*]] = bitcast %swift.type* {{%.*}} to i64*
-  // CHECK: [[FIELD_OFFSET_VECTOR:%.*]] = getelementptr inbounds i64, i64* [[METADATA]], i64 3
+  // CHECK: [[FIELD_OFFSET_VECTOR:%.*]] = getelementptr inbounds i64, i64* [[METADATA]], i64 2
   // CHECK: [[FIELD_OFFSET_ADDR:%.*]] = getelementptr inbounds i64, i64* [[FIELD_OFFSET_VECTOR]], i32 2
   // CHECK: [[FIELD_OFFSET:%.*]] = load i64, i64* [[FIELD_OFFSET_ADDR]], align 8
   // CHECK: [[BYTES:%.*]] = bitcast %T15generic_structs14ComplexDynamicV* %0 to i8*
@@ -143,7 +155,7 @@
   %b = struct_element_addr %0 : $*ComplexDynamic<A, B>, #ComplexDynamic.b
 
   // CHECK: [[METADATA:%.*]] = bitcast %swift.type* {{%.*}} to i64*
-  // CHECK: [[FIELD_OFFSET_VECTOR:%.*]] = getelementptr inbounds i64, i64* [[METADATA]], i64 3
+  // CHECK: [[FIELD_OFFSET_VECTOR:%.*]] = getelementptr inbounds i64, i64* [[METADATA]], i64 2
   // CHECK: [[FIELD_OFFSET_ADDR:%.*]] = getelementptr inbounds i64, i64* [[FIELD_OFFSET_VECTOR]], i32 3
   // CHECK: [[FIELD_OFFSET:%.*]] = load i64, i64* [[FIELD_OFFSET_ADDR]], align 8
   // CHECK: [[BYTES:%.*]] = bitcast %T15generic_structs14ComplexDynamicV* %0 to i8*
@@ -153,7 +165,7 @@
   %c = struct_element_addr %5 : $*SingleDynamic<B>, #SingleDynamic.x
 
   // CHECK: [[METADATA:%.*]] = bitcast %swift.type* {{%.*}} to i64*
-  // CHECK: [[FIELD_OFFSET_VECTOR:%.*]] = getelementptr inbounds i64, i64* [[METADATA]], i64 3
+  // CHECK: [[FIELD_OFFSET_VECTOR:%.*]] = getelementptr inbounds i64, i64* [[METADATA]], i64 2
   // CHECK: [[FIELD_OFFSET_ADDR:%.*]] = getelementptr inbounds i64, i64* [[FIELD_OFFSET_VECTOR]], i32 4
   // CHECK: [[FIELD_OFFSET:%.*]] = load i64, i64* [[FIELD_OFFSET_ADDR]], align 8
   // CHECK: [[BYTES:%.*]] = bitcast %T15generic_structs14ComplexDynamicV* %0 to i8*
@@ -204,17 +216,17 @@
 // CHECK:   [[METADATA:%.*]] = call %swift.type* @swift_allocateGenericValueMetadata(%swift.type_pattern* %0, i8** %1)
 // CHECK:   [[SELF_ARRAY:%.*]] = bitcast %swift.type* [[METADATA]] to i8**
 //   Fill type argument.
-// CHECK:   [[T1:%.*]] = getelementptr inbounds i8*, i8** [[SELF_ARRAY]], i32 4
+// CHECK:   [[T1:%.*]] = getelementptr inbounds i8*, i8** [[SELF_ARRAY]], i32 3
 // CHECK:   [[T0:%.*]] = bitcast %swift.type* %T to i8*
 // CHECK:   store i8* [[T0]], i8** [[T1]], align 8
 //   Fill vwtable reference.
-// CHECK:   [[VWTABLE_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[SELF_ARRAY]], i32 6
+// CHECK:   [[VWTABLE_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[SELF_ARRAY]], i32 5
 // CHECK:   [[VWTABLE_VAL:%.*]] = bitcast i8** [[VWTABLE_ADDR]] to i8*
 // CHECK:   [[VWTABLE_SLOT_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[SELF_ARRAY]], i32 -1
 // CHECK:   store i8* [[VWTABLE_VAL]], i8** [[VWTABLE_SLOT_ADDR]], align 8
 //   Lay out fields.
 // CHECK:   [[T0:%.*]] = bitcast %swift.type* [[METADATA]] to i64*
-// CHECK:   [[T1:%.*]] = getelementptr inbounds i64, i64* [[T0]], i64 3
+// CHECK:   [[T1:%.*]] = getelementptr inbounds i64, i64* [[T0]], i64 2
 // CHECK:   [[T2:%.*]] = getelementptr inbounds i8**, i8*** [[TYPES:%.*]], i32 0
 // CHECK:   call void @swift_initStructMetadata_UniversalStrategy(i64 1, i8*** [[TYPES]], i64* [[T1]], i8** [[VWTABLE_ADDR]])
 // CHECK:   ret %swift.type* [[METADATA]]
diff --git a/test/IRGen/generic_vtable.swift b/test/IRGen/generic_vtable.swift
index 00c3cb8..bbba876 100644
--- a/test/IRGen/generic_vtable.swift
+++ b/test/IRGen/generic_vtable.swift
@@ -21,8 +21,12 @@
 //// Nominal type descriptor for 'Base' does not have any method descriptors.
 
 // CHECK-LABEL: @_T014generic_vtable4BaseCMn = {{(protected )?}}constant
+// -- nesting depth
+// CHECK-SAME: i16 1,
 // -- flags: has vtable
-// CHECK-SAME: i32 4,
+// CHECK-SAME: i16 4,
+// -- generic parameters at depth 0
+// CHECK-SAME: i32 0,
 // -- vtable offset
 // CHECK-SAME: i32 10,
 // -- vtable size
@@ -46,8 +50,12 @@
 //// Nominal type descriptor for 'Derived' has method descriptors.
 
 // CHECK-LABEL: @_T014generic_vtable7DerivedCMn = {{(protected )?}}constant
+// -- nesting depth
+// CHECK-SAME: i16 1,
 // -- flags: has vtable
-// CHECK-SAME: i32 4,
+// CHECK-SAME: i16 4,
+// -- generic parameters at depth 0
+// CHECK-SAME: i32 1,
 // -- vtable offset
 // CHECK-SAME: i32 14,
 // -- vtable size
@@ -76,8 +84,12 @@
 //// Nominal type descriptor for 'Concrete' has method descriptors.
 
 // CHECK-LABEL: @_T014generic_vtable8ConcreteCMn = {{(protected )?}}constant
+// -- nesting depth
+// CHECK-SAME: i16 1,
 // -- flags: has vtable
-// CHECK-SAME: i32 4,
+// CHECK-SAME: i16 4,
+// -- generic parameters at depth 0
+// CHECK-SAME: i32 0,
 // -- vtable offset
 // CHECK-SAME: i32 15,
 // -- vtable size
diff --git a/test/IRGen/keypaths.sil b/test/IRGen/keypaths.sil
index b7dbb0e..8e5d64e 100644
--- a/test/IRGen/keypaths.sil
+++ b/test/IRGen/keypaths.sil
@@ -200,8 +200,8 @@
 // CHECK-64-SAME: [4 x i8] zeroinitializer,
 //             -- struct with runtime-resolved offset
 // CHECK-SAME: <i32 0x1ffffffe>,
-// CHECK-32-SAME: i32 12 }>
-// CHECK-64-SAME: i32 24 }>
+// CHECK-32-SAME: i32 8 }>
+// CHECK-64-SAME: i32 16 }>
 
 // -- %j: Gen<A>.y
 // CHECK: [[KP_J:@keypath.*]] = private global <{ {{.*}} }> <{
@@ -213,8 +213,8 @@
 // CHECK-64-SAME: [4 x i8] zeroinitializer,
 //             -- struct with runtime-resolved offset
 // CHECK-SAME: <i32 0x1ffffffe>,
-// CHECK-32-SAME: i32 16 }>
-// CHECK-64-SAME: i32 32 }>
+// CHECK-32-SAME: i32 12 }>
+// CHECK-64-SAME: i32 24 }>
 
 // CHECK-LABEL: define{{( protected)?}} swiftcc void @stored_property_fixed_offsets()
 sil @stored_property_fixed_offsets : $@convention(thin) () -> () {
diff --git a/test/IRGen/nested_generics.swift b/test/IRGen/nested_generics.swift
new file mode 100644
index 0000000..13bf3e3
--- /dev/null
+++ b/test/IRGen/nested_generics.swift
@@ -0,0 +1,81 @@
+// RUN: %target-swift-frontend %s -emit-ir | %FileCheck %s --check-prefix=CHECK
+
+// REQUIRES: CPU=x86_64
+
+func blah<T>(_: T.Type) {}
+
+// CHECK-LABEL: define{{( protected)?}} swiftcc void @_T015nested_generics13makeAMetadatayyF()
+public func makeAMetadata() {
+  blah(OuterGenericStruct<Int>.InnerGenericStruct<String>.self)
+  blah(OuterGenericStruct<Int>.InnerConcreteStruct.self)
+
+  blah(OuterGenericClass<Int>.InnerGenericClass<String>.self)
+  blah(OuterGenericClass<Int>.InnerConcreteClass.self)
+}
+
+// Type constructor for OuterGenericStruct<Int>.InnerGenericStruct<String>
+// CHECK-LABEL: define linkonce_odr hidden %swift.type* @_T015nested_generics18OuterGenericStructV05InnerdE0VySi_SSGMa()
+// CHECK: call %swift.type* @_T015nested_generics18OuterGenericStructV05InnerdE0VMa(%swift.type* @_T0SiN, %swift.type* @_T0SSN)
+// CHECK: ret %swift.type
+
+// Type constructor for OuterGenericStruct<T>.InnerGenericStruct<U>
+// CHECK-LABEL: define{{( protected)?}} %swift.type* @_T015nested_generics18OuterGenericStructV05InnerdE0VMa(%swift.type*, %swift.type*)
+
+// Type constructor for OuterGenericStruct<Int>.InnerConcreteStruct
+// CHECK-LABEL: define linkonce_odr hidden %swift.type* @_T015nested_generics18OuterGenericStructV013InnerConcreteE0VySi_GMa()
+// CHECK: call %swift.type* @_T015nested_generics18OuterGenericStructV013InnerConcreteE0VMa(%swift.type* @_T0SiN)
+// CHECK: ret %swift.type
+
+// Type constructor for OuterGenericStruct<T>.InnerConcreteStruct
+// CHECK-LABEL: define{{( protected)?}} %swift.type* @_T015nested_generics18OuterGenericStructV013InnerConcreteE0VMa(%swift.type*)
+
+public struct OuterGenericStruct<T> {
+  public struct InnerGenericStruct<U> {
+    public func method() {
+      blah(T.self)
+      blah(U.self)
+    }
+  }
+
+  public struct InnerConcreteStruct {
+    public func method() {
+      blah(T.self)
+    }
+  }
+}
+
+// Type constructor for OuterGenericClass<Int>.InnerGenericClass<String>
+// CHECK-LABEL: define linkonce_odr hidden %swift.type* @_T015nested_generics17OuterGenericClassC05InnerdE0CySi_SSGMa()
+// CHECK: call %swift.type* @_T015nested_generics17OuterGenericClassC05InnerdE0CMa(%swift.type* @_T0SiN, %swift.type* @_T0SSN)
+
+// Type constructor for OuterGenericClass<T>.InnerGenericClass<U>
+// CHECK-LABEL: define{{( protected)?}} %swift.type* @_T015nested_generics17OuterGenericClassC05InnerdE0CMa(%swift.type*, %swift.type*)
+
+// Type constructor for OuterGenericClass<Int>.InnerConcreteClass
+// CHECK-LABEL: define linkonce_odr hidden %swift.type* @_T015nested_generics17OuterGenericClassC013InnerConcreteE0CySi_GMa()
+// CHECK: call %swift.type* @_T015nested_generics17OuterGenericClassC013InnerConcreteE0CMa(%swift.type* @_T0SiN)
+// CHECK: ret %swift.type
+
+// Type constructor for OuterGenericClass<T>.InnerConcreteClass
+// CHECK-LABEL: define{{( protected)?}} %swift.type* @_T015nested_generics17OuterGenericClassC013InnerConcreteE0CMa(%swift.type*)
+
+// Type constructor for OuterGenericStruct<T>
+// CHECK-LABEL: define{{( protected)?}} %swift.type* @_T015nested_generics18OuterGenericStructVMa(%swift.type*)
+
+// Type constructor for OuterGenericClass<T>
+// CHECK-LABEL: define{{( protected)?}} %swift.type* @_T015nested_generics17OuterGenericClassCMa(%swift.type*)
+
+public class OuterGenericClass<T> {
+  public class InnerGenericClass<U> {
+    public func method() {
+      blah(T.self)
+      blah(U.self)
+    }
+  }
+
+  public class InnerConcreteClass {
+    public func method() {
+      blah(T.self)
+    }
+  }
+}
diff --git a/test/IRGen/nested_types.sil b/test/IRGen/nested_types.sil
index 274a98b..f27fa25 100644
--- a/test/IRGen/nested_types.sil
+++ b/test/IRGen/nested_types.sil
@@ -32,7 +32,5 @@
 // CHECK-NEXT: ret %swift.type* [[T4]]
 
 // CHECK-LABEL: define private void @initialize_metadata_Inner
-// CHECK:      [[T0:%.*]] = call %swift.type* @_T012nested_types5OuterCMa()
-// CHECK-NEXT: store %swift.type* [[T0]], %swift.type** getelementptr inbounds (%swift.type*, %swift.type** bitcast ({{.*}} @_T012nested_types5OuterC5InnerVMf{{.*}}, [[INT:i[0-9]+]] 2), align
-// CHECK-NEXT: store atomic %swift.type* bitcast ({{.*}} @_T012nested_types5OuterC5InnerVMf{{.*}} to %swift.type*), %swift.type** @_T012nested_types5OuterC5InnerVML release, align
+// CHECK:      store atomic %swift.type* bitcast ({{.*}} @_T012nested_types5OuterC5InnerVMf{{.*}} to %swift.type*), %swift.type** @_T012nested_types5OuterC5InnerVML release, align
 // CHECK-NEXT: ret void
diff --git a/test/IRGen/nonatomic_reference_counting.sil b/test/IRGen/nonatomic_reference_counting.sil
index 92c29ea..a38ed30 100644
--- a/test/IRGen/nonatomic_reference_counting.sil
+++ b/test/IRGen/nonatomic_reference_counting.sil
@@ -133,7 +133,7 @@
   %r = apply %f () : $@convention(thin) () -> ()
   unowned_release [nonatomic] %1 : $@sil_unowned C
   %3 = tuple ()
-  %4 = return %3 : $()
+  return %3 : $()
 }
 
 // CHECK-LABEL: define {{.*}}@test_bridged_nonatomic_rr
@@ -150,7 +150,7 @@
   %r = apply %f () : $@convention(thin) () -> ()
   strong_release [nonatomic] %2 : $Builtin.BridgeObject
   %3 = tuple ()
-  %4 = return %3 : $()
+  return %3 : $()
 }
 
 // CHECK-LABEL: define {{.*}}@test_bridged_nonatomic_rr_n
@@ -171,7 +171,7 @@
   strong_release [nonatomic] %2 : $Builtin.BridgeObject
   strong_release [nonatomic] %2 : $Builtin.BridgeObject
   %3 = tuple ()
-  %4 = return %3 : $()
+  return %3 : $()
 }
 
 // CHECK-LABEL: define {{.*}}@test_bridged_mixed_rr_n
@@ -192,7 +192,7 @@
   strong_release %2 : $Builtin.BridgeObject
   strong_release [nonatomic] %2 : $Builtin.BridgeObject
   %3 = tuple ()
-  %4 = return %3 : $()
+  return %3 : $()
 }
 
 // CHECK-LABEL: define {{.*}}@test_nonatomic_pin_unpin
@@ -208,7 +208,7 @@
   %r = apply %f () : $@convention(thin) () -> ()
   strong_unpin [nonatomic] %2 : $Optional<Builtin.NativeObject>
   %3 = tuple ()
-  %4 = return %3 : $()
+  return %3 : $()
 }
 
 // C.__deallocating_deinit
diff --git a/test/IRGen/struct_resilience.swift b/test/IRGen/struct_resilience.swift
index 7458d97..eed6368 100644
--- a/test/IRGen/struct_resilience.swift
+++ b/test/IRGen/struct_resilience.swift
@@ -59,7 +59,7 @@
 
 // CHECK: [[METADATA:%.*]] = call %swift.type* @_T016resilient_struct9RectangleVMa()
 // CHECK-NEXT: [[METADATA_ADDR:%.*]] = bitcast %swift.type* [[METADATA]] to [[INT]]*
-// CHECK-NEXT: [[FIELD_OFFSET_VECTOR:%.*]] = getelementptr inbounds [[INT]], [[INT]]* [[METADATA_ADDR]], [[INT]] 3
+// CHECK-NEXT: [[FIELD_OFFSET_VECTOR:%.*]] = getelementptr inbounds [[INT]], [[INT]]* [[METADATA_ADDR]], [[INT]] 2
 // CHECK-NEXT: [[FIELD_OFFSET_PTR:%.*]] = getelementptr inbounds [[INT]], [[INT]]* [[FIELD_OFFSET_VECTOR]], i32 2
 // CHECK-NEXT: [[FIELD_OFFSET:%.*]] = load [[INT]], [[INT]]* [[FIELD_OFFSET_PTR]]
 // CHECK-NEXT: [[STRUCT_ADDR:%.*]] = bitcast %T16resilient_struct9RectangleV* %0 to i8*
@@ -116,7 +116,7 @@
 // CHECK-LABEL: define{{( protected)?}} swiftcc {{i32|i64}} @_T017struct_resilience26StructWithResilientStorageV1nSivg(%T17struct_resilience26StructWithResilientStorageV* {{.*}})
 // CHECK: [[METADATA:%.*]] = call %swift.type* @_T017struct_resilience26StructWithResilientStorageVMa()
 // CHECK-NEXT: [[METADATA_ADDR:%.*]] = bitcast %swift.type* [[METADATA]] to [[INT]]*
-// CHECK-NEXT: [[FIELD_OFFSET_VECTOR:%.*]] = getelementptr inbounds [[INT]], [[INT]]* [[METADATA_ADDR]], [[INT]] 3
+// CHECK-NEXT: [[FIELD_OFFSET_VECTOR:%.*]] = getelementptr inbounds [[INT]], [[INT]]* [[METADATA_ADDR]], [[INT]] 2
 // CHECK-NEXT: [[FIELD_OFFSET_PTR:%.*]] = getelementptr inbounds [[INT]], [[INT]]* [[FIELD_OFFSET_VECTOR]], i32 2
 // CHECK-NEXT: [[FIELD_OFFSET:%.*]] = load [[INT]], [[INT]]* [[FIELD_OFFSET_PTR]]
 // CHECK-NEXT: [[STRUCT_ADDR:%.*]] = bitcast %T17struct_resilience26StructWithResilientStorageV* %0 to i8*
diff --git a/test/IRGen/unowned.sil b/test/IRGen/unowned.sil
index bc12958..ab5a51a 100644
--- a/test/IRGen/unowned.sil
+++ b/test/IRGen/unowned.sil
@@ -25,10 +25,10 @@
 
 sil @test_weak_rr_class : $@convention(thin) (@sil_unowned C) -> () {
 bb0(%0 : $@sil_unowned C):
-  %1 = unowned_retain %0 : $@sil_unowned C
-  %2 = unowned_release %0 : $@sil_unowned C
+  unowned_retain %0 : $@sil_unowned C
+  unowned_release %0 : $@sil_unowned C
   %3 = tuple ()
-  %4 = return %3 : $()
+  return %3 : $()
 }
 // CHECK:    define{{( protected)?}} swiftcc void @test_weak_rr_class([[C]]*) {{.*}} {
 // CHECK:      call [[C]]* bitcast ([[REF]]* ([[REF]]*)* @swift_rt_swift_unownedRetain to [[C]]* ([[C]]*)*)([[C]]* returned %0)
@@ -37,10 +37,10 @@
 
 sil @test_weak_rr_proto : $@convention(thin) (@sil_unowned P) -> () {
 bb0(%0 : $@sil_unowned P):
-  %1 = unowned_retain %0 : $@sil_unowned P
-  %2 = unowned_release %0 : $@sil_unowned P
+  unowned_retain %0 : $@sil_unowned P
+  unowned_release %0 : $@sil_unowned P
   %3 = tuple ()
-  %4 = return %3 : $()
+  return %3 : $()
 }
 // CHECK:    define{{( protected)?}} swiftcc void @test_weak_rr_proto(%swift.refcounted*, i8**) {{.*}} {
 // CHECK:      call %swift.refcounted* @swift_rt_swift_unownedRetain(%swift.refcounted* returned %0)
diff --git a/test/IRGen/unowned_objc.sil b/test/IRGen/unowned_objc.sil
index 792b834..879d683 100644
--- a/test/IRGen/unowned_objc.sil
+++ b/test/IRGen/unowned_objc.sil
@@ -31,10 +31,10 @@
 
 sil @test_weak_rr_class : $@convention(thin) (@sil_unowned C) -> () {
 bb0(%0 : $@sil_unowned C):
-  %1 = unowned_retain %0 : $@sil_unowned C
-  %2 = unowned_release %0 : $@sil_unowned C
+  unowned_retain %0 : $@sil_unowned C
+  unowned_release %0 : $@sil_unowned C
   %3 = tuple ()
-  %4 = return %3 : $()
+  return %3 : $()
 }
 // CHECK:    define{{( protected)?}} swiftcc void @test_weak_rr_class([[C]]*) {{.*}} {
 // CHECK:      call [[C]]* bitcast ([[REF]]* ([[REF]]*)* @swift_rt_swift_unownedRetain to [[C]]* ([[C]]*)*)([[C]]* returned %0)
diff --git a/test/Parse/errors.swift b/test/Parse/errors.swift
index 472d598..8fb0ecf 100644
--- a/test/Parse/errors.swift
+++ b/test/Parse/errors.swift
@@ -104,8 +104,7 @@
     do {
       _ = try genError()
 
-    // TODO: this recovery is terrible
-    } catch MSV.CarriesInt(let i) where i == genError()) { // expected-error {{call can throw, but errors cannot be thrown out of a catch guard expression}} expected-error {{expected '{'}} expected-error {{closure expression is unused}} expected-note {{did you mean to use a 'do' statement?}} {{58-58=do }}
+    } catch MSV.CarriesInt(let i) where i == genError()) { // expected-error {{call can throw, but errors cannot be thrown out of a catch guard expression}} expected-error {{expected '{'}}
     }
 }
 
diff --git a/test/Parse/recovery.swift b/test/Parse/recovery.swift
index 9ab1aaa..bd78194 100644
--- a/test/Parse/recovery.swift
+++ b/test/Parse/recovery.swift
@@ -194,7 +194,7 @@
   // expected-error @+3 {{expected pattern}}
   // expected-error @+2 {{expected Sequence expression for for-each loop}}
   // expected-error @+1 {{expected '{' to start the body of for-each loop}}
-  for for in { // expected-error {{expected pattern}} expected-error {{expected Sequence expression for for-each loop}}
+  for for in {
   }
 
   for i in { // expected-error {{expected Sequence expression for for-each loop}}
@@ -215,6 +215,15 @@
     var x = 42
   }
 #endif
+  
+  // SR-5943
+  struct User { let name: String? }
+  let users = [User]()
+  for user in users whe { // expected-error {{expected '{' to start the body of for-each loop}}
+    if let name = user.name {
+      let key = "\(name)"
+    }
+  }
 }
 
 func missingControllingExprInSwitch() {
diff --git a/test/SIL/Parser/basic.sil b/test/SIL/Parser/basic.sil
index 68afa78..368f050 100644
--- a/test/SIL/Parser/basic.sil
+++ b/test/SIL/Parser/basic.sil
@@ -98,7 +98,7 @@
 sil @named_tuple : $() -> (Builtin.Word, Builtin.Word) {
   %0 = integer_literal $Builtin.Word, 42      // CHECK: integer_literal $Builtin.Word, 42
   %9 = tuple $(Builtin.Word, Builtin.Word) (%0, %0)
-  %10 = return %9 : $(Builtin.Word, Builtin.Word)
+  return %9 : $(Builtin.Word, Builtin.Word)
 }
 
 sil @return_int : $@convention(thin) (Int) -> Int { // CHECK: $@convention(thin) (Int) -> Int {
@@ -137,7 +137,7 @@
   // CHECK: apply
   %4 = apply %1(%3, %2) : $@convention(thin) (Builtin.Word, @thin Int.Type) -> Int
   // CHECK: return
-  %5 = return %4 : $Int
+  return %4 : $Int
 }
 
 sil @_TSi25convertFromIntegerLiteralfMSiFT3valBi64__Si : $@convention(thin) (Builtin.Word, @thin Int.Type) -> Int
@@ -154,13 +154,13 @@
   // CHECK: alloc_stack $Bool
   %1 = alloc_stack $Bool
   // CHECK: store
-  %2 = store %0 to %1 : $*Bool
+  store %0 to %1 : $*Bool
   // CHECK: function_ref @_TSb13getLogicValuefRSbFT_Bi1_ : $@convention(method) (@inout Bool) -> Builtin.Int1
   %3 = function_ref @_TSb13getLogicValuefRSbFT_Bi1_ : $@convention(method) (@inout Bool) -> Builtin.Int1
   // CHECK: apply
   %4 = apply %3(%1) : $@convention(method) (@inout Bool) -> Builtin.Int1
   // CHECK: cond_br
-  %5 = cond_br %4, bb1, bb2
+  cond_br %4, bb1, bb2
 
 // CHECK: bb1:
 bb1:
@@ -173,7 +173,7 @@
   // CHECK: apply
   %9 = apply %6(%8, %7) : $@convention(thin) (Builtin.Int128, @thin Int.Type) -> Int
   // CHECK: dealloc_stack
-  %10 = dealloc_stack %1 : $*Bool
+  dealloc_stack %1 : $*Bool
   // CHECK: br
   br bb3(%9 : $Int)
 
@@ -188,7 +188,7 @@
   // CHECK: apply
   %15 = apply %12(%14, %13) : $@convention(thin) (Builtin.Int128, @thin Int.Type) -> Int
   // CHECK: dealloc_stack
-  %16 = dealloc_stack %1 : $*Bool
+  dealloc_stack %1 : $*Bool
   // CHECK: br
   br bb3(%15 : $Int)
 
@@ -221,8 +221,8 @@
   %6 = witness_method $@opened("01234567-89ab-cdef-0123-000000000001") P, #P.doIt!1, %5 : $*@opened("01234567-89ab-cdef-0123-000000000001") P : $@convention(witness_method) <T: P> (@in_guaranteed T) -> ()
   %8 = apply %6<@opened("01234567-89ab-cdef-0123-000000000001") P>(%5) : $@convention(witness_method) <T: P> (@in_guaranteed T) -> ()
 
-  %9 = destroy_addr %0 : $*P          // CHECK: destroy_addr %0 : $*P
-  %10 = return %4 : $()                // CHECK: return
+  destroy_addr %0 : $*P          // CHECK: destroy_addr %0 : $*P
+  return %4 : $()                // CHECK: return
 }
 
 
@@ -258,7 +258,7 @@
 
   %5 = unconditional_checked_cast %C : $C to $D   // CHECK: unconditional_checked_cast
   %6 = tuple ()
-  %7 = return %6 : $()
+  return %6 : $()
 }
 
 sil @optional_upcasts : $@convention(thin) (Optional<D>) -> () {
@@ -266,7 +266,7 @@
   // CHECK: upcast {{.*}} : $Optional<D> to $Optional<C>
   %1 = upcast %0 : $Optional<D> to $Optional<C>
   %2 = tuple ()
-  %3 = return %2 : $()
+  return %2 : $()
 }
 
 
@@ -295,15 +295,15 @@
   // C/HECK: witness_method $*T, #Runcible.associated_method!1
   %4 = witness_method $*T, #Runcible.associated_method!1 : $@cc(method) (@inout T) -> @thick T.U.Type
   %5 = apply %4(%0) : $@cc(method) (@inout T) -> @thick T.U.Type
-  %6 = store %5 to %3 : $*@thick T.U.Type
+  store %5 to %3 : $*@thick T.U.Type
   %7 = metatype $@thick T.Type
   // C/HECK: witness_method [volatile] $*T, #Runcible.static_method!1
   %8 = witness_method [volatile] $*T, #Runcible.static_method!1 : $(@thick T.Type) -> ()
   %9 = apply %8(%7) : $(@thick T.Type) -> ()
-  %10 = dealloc_stack %3 : $*@thick T.U.Type
+  dealloc_stack %3 : $*@thick T.U.Type
   %11 = tuple ()
-  %12 = destroy_addr %0 : $*T
-  %13 = return %11 : $()
+  destroy_addr %0 : $*T
+  return %11 : $()
 }
 */
 
@@ -316,20 +316,20 @@
   %2 = alloc_box $<τ_0_0> { var τ_0_0 } <Bendable & Runcible>
   %2a = project_box %2 : $<τ_0_0> { var τ_0_0 } <Bendable & Runcible>, 0
   // CHECK: copy_addr [take] {{.*}} to [initialization] {{.*}} : $*Bendable & Runcible
-  %3 = copy_addr [take] %1 to [initialization] %2a : $*Bendable & Runcible
+  copy_addr [take] %1 to [initialization] %2a : $*Bendable & Runcible
   // CHECK: alloc_stack
   %4 = alloc_stack $Bendable & Runcible
   // CHECK: copy_addr {{.*}} to [initialization] {{.*}} : $*Bendable & Runcible
-  %5 = copy_addr %2a to [initialization] %4 : $*Bendable & Runcible
+  copy_addr %2a to [initialization] %4 : $*Bendable & Runcible
   %7 = tuple ()
   // CHECK: destroy_addr
-  %8 = destroy_addr %4 : $*Bendable & Runcible
+  destroy_addr %4 : $*Bendable & Runcible
   // CHECK: dealloc_stack
-  %9 = dealloc_stack %4 : $*Bendable & Runcible
+  dealloc_stack %4 : $*Bendable & Runcible
   // CHECK: release
-  %10 = strong_release %2 : $<τ_0_0> { var τ_0_0 } <Bendable & Runcible>
+  strong_release %2 : $<τ_0_0> { var τ_0_0 } <Bendable & Runcible>
   // CHECK: return
-  %11 = return %7 : $()
+  return %7 : $()
 }
 
 protocol ClassBound : class {
@@ -341,17 +341,17 @@
 bb0(%0 : $ClassBound):
   %1 = alloc_box $<τ_0_0> { var τ_0_0 } <ClassBound>                // CHECK: alloc_box
   %1a = project_box %1 : $<τ_0_0> { var τ_0_0 } <ClassBound>, 0
-  %2 = store %0 to %1a : $*ClassBound      // CHECK: store
+  store %0 to %1a : $*ClassBound      // CHECK: store
   %3 = load %1a : $*ClassBound             // CHECK: load
-  %4 = strong_retain %3 : $ClassBound              // CHECK: strong_retain
+  strong_retain %3 : $ClassBound              // CHECK: strong_retain
   // CHECK: open_existential_ref {{%.*}} : $ClassBound to $@opened({{.*}}) ClassBound
   %5 = open_existential_ref %3 : $ClassBound to $@opened("01234567-89ab-cdef-0123-111111111111") ClassBound
   // CHECK: witness_method
   %6 = witness_method $@opened("01234567-89ab-cdef-0123-111111111111") ClassBound, #ClassBound.classBoundMethod!1, %5 : $@opened("01234567-89ab-cdef-0123-111111111111") ClassBound : $@convention(witness_method) <T: ClassBound> (T) -> ()
   %7 = apply %6<@opened("01234567-89ab-cdef-0123-111111111111") ClassBound>(%5) : $@convention(witness_method) <T: ClassBound> (T) -> ()
   %8 = tuple ()
-  %9 = strong_release %1 : $<τ_0_0> { var τ_0_0 } <ClassBound>
-  %10 = return %8 : $()
+  strong_release %1 : $<τ_0_0> { var τ_0_0 } <ClassBound>
+  return %8 : $()
 }
 
 struct Val {
@@ -363,7 +363,7 @@
   %1 = alloc_stack $Val // CHECK: alloc_stack
   %3 = load %1 : $*Val
   dealloc_stack %1 : $*Val
-  %4 = return %3 : $Val
+  return %3 : $Val
 }
 
 class Ref {
@@ -378,7 +378,7 @@
 bb0(%0 : $Ref, %1 : $Val, %2 : $@thin Aleph.Type):
   // CHECK: struct $Aleph ({{%.*}} : $Ref, {{%.*}} : $Val)
   %3 = struct $Aleph (%0 : $Ref, %1 : $Val)
-  %4 = return %3 : $Aleph  // CHECK: return
+  return %3 : $Aleph  // CHECK: return
 }
 
 // CHECK: $@convention(thin) (@thin Aleph.Type) -> Aleph
@@ -390,13 +390,13 @@
   // CHECK: struct_element_addr {{.*}} : $*Aleph, #Aleph.a
   %5 = struct_element_addr %2a : $*Aleph, #Aleph.a
   %6 = load %5 : $*Ref
-  %8 = strong_release %6 : $Ref
+  strong_release %6 : $Ref
   %14 = load %2a : $*Aleph
   // CHECK: struct_extract {{%.*}} : $Aleph, #Aleph.a
   %15 = struct_extract %14 : $Aleph, #Aleph.a
-  %16 = strong_retain %15 : $Ref
-  %17 = strong_release %2 : $<τ_0_0> { var τ_0_0 } <Aleph>
-  %18 = return %14 : $Aleph
+  strong_retain %15 : $Ref
+  strong_release %2 : $<τ_0_0> { var τ_0_0 } <Aleph>
+  return %14 : $Aleph
 }
 
 enum Beth {
@@ -455,7 +455,7 @@
   %2a = project_box %2 : $<τ_0_0> { var τ_0_0 } <(Int, Float)>, 0
   // CHECK: tuple ({{%.*}} : $Int, {{%.*}} : $Float)
   %3 = tuple (%0 : $Int, %1 : $Float)
-  %4 = store %3 to %2a : $*(Int, Float)
+  store %3 to %2a : $*(Int, Float)
   // CHECK: tuple_element_addr {{%.*}} : $*(Int, Float), 0
   %6 = tuple_element_addr %2a : $*(Int, Float), 0
   // CHECK: load
@@ -475,8 +475,8 @@
   // CHECK: apply
   %24 = apply %19(%17) : $@convention(thin) (Float) -> ()
   %25 = tuple ()
-  %26 = strong_release %2 : $<τ_0_0> { var τ_0_0 } <(Int, Float)>
-  %27 = return %25 : $()
+  strong_release %2 : $<τ_0_0> { var τ_0_0 } <(Int, Float)>
+  return %25 : $()
 }
 
 class M {
@@ -489,21 +489,21 @@
 bb0(%0 : $Int, %1 : $M):
   %2 = alloc_box $<τ_0_0> { var τ_0_0 } <Int>     // CHECK: alloc_box $<τ_0_0> { var τ_0_0 } <Int>
   %2a = project_box %2 : $<τ_0_0> { var τ_0_0 } <Int>, 0
-  %3 = store %0 to %2a : $*Int
+  store %0 to %2a : $*Int
   %4 = alloc_box $<τ_0_0> { var τ_0_0 } <M>         // CHECK: alloc_box $<τ_0_0> { var τ_0_0 } <M>
   %4a = project_box %4 : $<τ_0_0> { var τ_0_0 } <M>, 0
-  %5 = store %1 to %4a : $*M
+  store %1 to %4a : $*M
   %6 = load %2a : $*Int  // CHECK: load {{.*}} : $*Int
   %7 = load %4a : $*M      // CHECK: load {{.*}} : $*M
-  %8 = strong_retain %7 : $M
+  strong_retain %7 : $M
   // CHECK: ref_element_addr {{%.*}} : $M, #M.member
   %9 = ref_element_addr %7 : $M, #M.member
-  %10 = store %6 to %9 : $*Int
-  %11 = strong_release %7 : $M
+  store %6 to %9 : $*Int
+  strong_release %7 : $M
   %12 = tuple ()
-  %13 = strong_release %4 : $<τ_0_0> { var τ_0_0 } <M>
-  %14 = strong_release %2 : $<τ_0_0> { var τ_0_0 } <Int>
-  %15 = return %12 : $()
+  strong_release %4 : $<τ_0_0> { var τ_0_0 } <M>
+  strong_release %2 : $<τ_0_0> { var τ_0_0 } <Int>
+  return %12 : $()
 }
 
 class GenericClass<Q> {
@@ -529,9 +529,9 @@
 bb0(%0 : $B):
   %1 = alloc_box $<τ_0_0> { var τ_0_0 } <B>                           // CHECK: alloc_box
   %1a = project_box %1 : $<τ_0_0> { var τ_0_0 } <B>, 0
-  %2 = store %0 to %1a : $*B
+  store %0 to %1a : $*B
   %3 = load %1a : $*B                        // CHECK: load
-  %4 = strong_retain %3 : $B
+  strong_retain %3 : $B
   checked_cast_br %3 : $B to $E, yes, no     // CHECK: checked_cast_br
 yes(%5 : $E):
   %y = integer_literal $Builtin.Int1, 1
@@ -540,9 +540,9 @@
   %n = integer_literal $Builtin.Int1, 0
   br isa(%n : $Builtin.Int1)
 isa(%6 : $Builtin.Int1):
-  %7 = strong_release %3 : $B
-  %8 = strong_release %1 : $<τ_0_0> { var τ_0_0 } <B>
-  %9 = return %6 : $Builtin.Int1
+  strong_release %3 : $B
+  strong_release %1 : $<τ_0_0> { var τ_0_0 } <B>
+  return %6 : $Builtin.Int1
 }
 
 sil @_TSd31_convertFromBuiltinFloatLiteralfMSdFT5valueBf64__Sd : $@convention(thin) (Builtin.FPIEEE64, @thin Float64.Type) -> Float64
@@ -555,15 +555,15 @@
   %2a = project_box %2 : $<τ_0_0> { var τ_0_0 } <Builtin.RawPointer>, 0
   %3 = alloc_box $<τ_0_0> { var τ_0_0 } <Builtin.Word>                   // CHECK: alloc_box
   %3a = project_box %3 : $<τ_0_0> { var τ_0_0 } <Builtin.Word>, 0
-  %4 = store %0 to %2a : $*Builtin.RawPointer
-  %5 = store %1 to %3a : $*Builtin.Word
+  store %0 to %2a : $*Builtin.RawPointer
+  store %1 to %3a : $*Builtin.Word
   %7 = load %2a : $*Builtin.RawPointer           // CHECK: load
   %8 = load %3a : $*Builtin.Word                // CHECK: load
   // CHECK: index_raw_pointer {{%.*}} : $Builtin.RawPointer, {{%.*}} : $Builtin.Word
   %9 = index_raw_pointer %7 : $Builtin.RawPointer, %8 : $Builtin.Word
-  %10 = strong_release %3 : $<τ_0_0> { var τ_0_0 } <Builtin.Word>
-  %11 = strong_release %2 : $<τ_0_0> { var τ_0_0 } <Builtin.RawPointer>
-  %12 = return %9 : $Builtin.RawPointer
+  strong_release %3 : $<τ_0_0> { var τ_0_0 } <Builtin.Word>
+  strong_release %2 : $<τ_0_0> { var τ_0_0 } <Builtin.RawPointer>
+  return %9 : $Builtin.RawPointer
 }
 
 sil_global @x : $Int
@@ -589,9 +589,9 @@
   %2 = metatype $@thin Int.Type
   %3 = integer_literal $Builtin.Int128, 0 // CHECK: integer_literal $Builtin.Int128, 0
   %4 = apply %1(%3, %2) : $@convention(thin) (Builtin.Int128, @thin Int.Type) -> Int
-  %5 = store %4 to %0 : $*Int
+  store %4 to %0 : $*Int
   %6 = tuple ()
-  %7 = return %6 : $()
+  return %6 : $()
 }
 
 protocol SomeProtocol {
@@ -606,55 +606,55 @@
   %2a = project_box %2 : $<τ_0_0> { var τ_0_0 } <SomeClass>, 0
   %3 = alloc_box $<τ_0_0> { var τ_0_0 } <SomeSubclass>                    // CHECK: alloc_box
   %3a = project_box %3 : $<τ_0_0> { var τ_0_0 } <SomeSubclass>, 0
-  %4 = store %0 to %2a : $*SomeClass
-  %5 = store %1 to %3a : $*SomeSubclass
+  store %0 to %2a : $*SomeClass
+  store %1 to %3a : $*SomeSubclass
   %7 = load %2a : $*SomeClass                    // CHECK: load
-  %8 = strong_retain %7 : $SomeClass
+  strong_retain %7 : $SomeClass
   // CHECK: value_metatype $@thick SomeClass.Type, {{%.*}} : $SomeClass
   %9 = value_metatype $@thick SomeClass.Type, %7 : $SomeClass
   %11 = load %3a : $*SomeSubclass                // CHECK: load
-  %12 = strong_retain %11 : $SomeSubclass
+  strong_retain %11 : $SomeSubclass
   // CHECK: value_metatype $@thick SomeSubclass.Type, {{%.*}} : $SomeSubclass
   %13 = value_metatype $@thick SomeSubclass.Type, %11 : $SomeSubclass
   %14 = upcast %13 : $@thick SomeSubclass.Type to $@thick SomeClass.Type  // CHECK: upcast
   %15 = tuple (%9 : $@thick SomeClass.Type, %14 : $@thick SomeClass.Type) // CHECK: tuple
-  %16 = strong_release %11 : $SomeSubclass
-  %17 = strong_release %7 : $SomeClass
-  %18 = strong_release %3 : $<τ_0_0> { var τ_0_0 } <SomeSubclass>
-  %19 = strong_release %2 : $<τ_0_0> { var τ_0_0 } <SomeClass>
-  %20 = return %15 : $(@thick SomeClass.Type, @thick SomeClass.Type)
+  strong_release %11 : $SomeSubclass
+  strong_release %7 : $SomeClass
+  strong_release %3 : $<τ_0_0> { var τ_0_0 } <SomeSubclass>
+  strong_release %2 : $<τ_0_0> { var τ_0_0 } <SomeClass>
+  return %15 : $(@thick SomeClass.Type, @thick SomeClass.Type)
 }
 
 sil @test_value_metatype : $@convention(thin) <T> (@in T) -> (@thick T.Type, @thick T.Type) {
 bb0(%0 : $*T):
   %1 = alloc_box $<τ_0_0> { var τ_0_0 } <T>                               // CHECK: alloc_box
   %1a = project_box %1 : $<τ_0_0> { var τ_0_0 } <T>, 0
-  %2 = copy_addr [take] %0 to [initialization] %1a : $*T
+  copy_addr [take] %0 to [initialization] %1a : $*T
   %3 = metatype $@thick T.Type                       // CHECK: metatype
   %5 = alloc_stack $T                               // CHECK: alloc_stack
-  %6 = copy_addr %1a to [initialization] %5 : $*T
+  copy_addr %1a to [initialization] %5 : $*T
   // CHECK: value_metatype $@thick T.Type, {{%.*}} : $*T
   %7 = value_metatype $@thick T.Type, %5 : $*T
   %8 = tuple (%3 : $@thick T.Type, %7 : $@thick T.Type) // CHECK: tuple
-  %9 = destroy_addr %5 : $*T
-  %10 = dealloc_stack %5 : $*T
-  %11 = strong_release %1 : $<τ_0_0> { var τ_0_0 } <T>
-  %12 = return %8 : $(@thick T.Type, @thick T.Type)
+  destroy_addr %5 : $*T
+  dealloc_stack %5 : $*T
+  strong_release %1 : $<τ_0_0> { var τ_0_0 } <T>
+  return %8 : $(@thick T.Type, @thick T.Type)
 }
 
 sil @test_existential_metatype : $@convention(thin) (@in SomeProtocol) -> @thick SomeProtocol.Type {
 bb0(%0 : $*SomeProtocol):
   %1 = alloc_box $<τ_0_0> { var τ_0_0 } <SomeProtocol>                    // CHECK: alloc_box
   %1a = project_box %1 : $<τ_0_0> { var τ_0_0 } <SomeProtocol>, 0
-  %2 = copy_addr [take] %0 to [initialization] %1a : $*SomeProtocol
+  copy_addr [take] %0 to [initialization] %1a : $*SomeProtocol
   %4 = alloc_stack $SomeProtocol                    // CHECK: alloc_stack
-  %5 = copy_addr %1a to [initialization] %4 : $*SomeProtocol
+  copy_addr %1a to [initialization] %4 : $*SomeProtocol
   // CHECK: existential_metatype $@thick SomeProtocol.Type, {{%.*}} : $*SomeProtocol
   %6 = existential_metatype $@thick SomeProtocol.Type, %4 : $*SomeProtocol
-  %7 = destroy_addr %4 : $*SomeProtocol
-  %8 = dealloc_stack %4 : $*SomeProtocol
-  %9 = strong_release %1 : $<τ_0_0> { var τ_0_0 } <SomeProtocol>
-  %10 = return %6 : $@thick SomeProtocol.Type
+  destroy_addr %4 : $*SomeProtocol
+  dealloc_stack %4 : $*SomeProtocol
+  strong_release %1 : $<τ_0_0> { var τ_0_0 } <SomeProtocol>
+  return %6 : $@thick SomeProtocol.Type
 }
 
 // CHECK-LABEL: sil @test_unreachable
@@ -668,14 +668,14 @@
 bb0(%0 : $SomeClass):
   %1 = ref_to_unowned %0 : $SomeClass to $@sil_unowned SomeClass
 // CHECK: ref_to_unowned %0 : $SomeClass to $@sil_unowned SomeClass
-  %2 = unowned_retain %1 : $@sil_unowned SomeClass
+  unowned_retain %1 : $@sil_unowned SomeClass
 // CHECK: unowned_retain %1 : $@sil_unowned SomeClass
-  %3 = unowned_release %1 : $@sil_unowned SomeClass
+  unowned_release %1 : $@sil_unowned SomeClass
 // CHECK: unowned_release %1 : $@sil_unowned SomeClass
   %4 = unowned_to_ref %1 : $@sil_unowned SomeClass to $SomeClass
 // CHECK: unowned_to_ref %1 : $@sil_unowned SomeClass to $SomeClass
   %5 = tuple ()
-  %6 = return %5 : $()
+  return %5 : $()
 }
 
 // CHECK-LABEL: sil @test_basic_block_arguments
@@ -1048,14 +1048,14 @@
   // CHECK: apply %{{.*}}() : $@convention(thin) () -> ()
   %1 = apply %0() : $@convention(thin) () -> ()
   %2 = tuple ()
-  %3 = return %2 : $()
+  return %2 : $()
 }
 
 // CHECK-LABEL: sil [thunk] @test_thunk : $@convention(thin) () -> () {
 sil [thunk] @test_thunk : $@convention(thin) () -> () {
 bb0:
   %0 = tuple ()
-  %1 = return %0 : $()
+  return %0 : $()
 }
 
 // CHECK-LABEL: sil @takes_unnamed_closure : $@convention(thin) (@callee_owned () -> Int) -> () -> () -> Int
@@ -1069,7 +1069,7 @@
   %1 = function_ref @takes_int64_float32 : $@convention(thin) (Int, Float) -> ()
   // CHECK: partial_apply %{{.*}}(%{{.*}}) : $@convention(thin) (Int, Float) -> ()
   %2 = partial_apply %1(%0) : $@convention(thin) (Int, Float) -> ()
-  %3 = return %2 : $@callee_owned Int -> ()
+  return %2 : $@callee_owned Int -> ()
 }
 
 class X {
diff --git a/test/SIL/Parser/errors.sil b/test/SIL/Parser/errors.sil
index da77db7..4875a1c 100644
--- a/test/SIL/Parser/errors.sil
+++ b/test/SIL/Parser/errors.sil
@@ -8,9 +8,9 @@
 sil @block_errors : $() -> () {
 bb0:
   %0 = tuple ()
-  %1 = return %0 : $()
+  return %0 : $()
 bb0:                      // expected-error {{redefinition of basic block 'bb0'}}
-  %3 = return %0 : $()
+  return %0 : $()
 }
 
 sil @local_value_errors : $() -> () {
@@ -27,7 +27,7 @@
   %0 = function_ref @global_value_errors : $ () -> ((), ()) // expected-error {{defined with mismatching type}}
   %1 = function_ref @not_defined : $ () -> () // expected-error {{use of undefined value 'not_defined'}}
   %2 = tuple ()
-  %3 = return %2 : $()
+  return %2 : $()
 }
 
 sil @global_value_errors : $() -> () {  // expected-error {{redefinition of value 'global_value_errors'}}
diff --git a/test/SIL/Parser/indirect_enum.sil b/test/SIL/Parser/indirect_enum.sil
index 26521b5..f550c84 100644
--- a/test/SIL/Parser/indirect_enum.sil
+++ b/test/SIL/Parser/indirect_enum.sil
@@ -35,7 +35,7 @@
 sil @indirect_enum_case_addr_only : $@convention(thin) <T> (@in TreeB<T>) -> () {
 entry(%e : $*TreeB<T>):
   %a = unchecked_take_enum_data_addr %e : $*TreeB<T>, #TreeB.Leaf!enumelt.1
-  %b = destroy_addr %a : $*T
+  destroy_addr %a : $*T
 
   %c = unchecked_take_enum_data_addr %e : $*TreeB<T>, #TreeB.Branch!enumelt.1
   %d = load [take] %c : $*<τ_0_0> { var τ_0_0 } <(left: TreeB<T>, right: TreeB<T>)>
diff --git a/test/SIL/Parser/nonatomic_reference_counting.sil b/test/SIL/Parser/nonatomic_reference_counting.sil
index 2a9f743..67a3f68 100644
--- a/test/SIL/Parser/nonatomic_reference_counting.sil
+++ b/test/SIL/Parser/nonatomic_reference_counting.sil
@@ -56,7 +56,7 @@
   %2 = strong_pin [nonatomic] %1 : $Builtin.NativeObject
   strong_unpin [nonatomic] %2 : $Optional<Builtin.NativeObject>
   %3 = tuple ()
-  %4 = return %3 : $()
+  return %3 : $()
 }
 
 // CHECK-LABEL: sil @test_unowned_nonatomic_rr
@@ -70,7 +70,7 @@
   unowned_retain [nonatomic] %1 : $@sil_unowned C
   unowned_release [nonatomic] %1 : $@sil_unowned C
   %3 = tuple ()
-  %4 = return %3 : $()
+  return %3 : $()
 }
 
 // CHECK-LABEL: sil @test_set_deallocating
diff --git a/test/SIL/Parser/opaque_values_parse.sil b/test/SIL/Parser/opaque_values_parse.sil
index bda7bda..5c9578a 100644
--- a/test/SIL/Parser/opaque_values_parse.sil
+++ b/test/SIL/Parser/opaque_values_parse.sil
@@ -31,7 +31,7 @@
 // CHECK-LABEL: } // end sil function 'condCastOpaque'
 sil @condCastOpaque : $@convention(thin) (Int) -> () {
 bb0(%0 : $Int):
-  %c = checked_cast_value_br %0 : $Int to $Int, bb2, bb1
+  checked_cast_value_br %0 : $Int to $Int, bb2, bb1
 
 bb1:
   br bb3
@@ -52,7 +52,7 @@
 sil @initDeinitExistentialValue : $@convention(thin) <T> (@in T) -> () {
 bb0(%0 : $T):
   %i = init_existential_value %0 : $T, $T, $Any
-  %d = deinit_existential_value %i : $Any
+  deinit_existential_value %i : $Any
   %t = tuple ()
   return %t : $()
 }
diff --git a/test/SIL/Serialization/opaque_values_serialize.sil b/test/SIL/Serialization/opaque_values_serialize.sil
index 6ce7f0dd..bb7ea3a 100644
--- a/test/SIL/Serialization/opaque_values_serialize.sil
+++ b/test/SIL/Serialization/opaque_values_serialize.sil
@@ -37,7 +37,7 @@
 // CHECK-LABEL: } // end sil function 'condCastOpaque'
 sil @condCastOpaque : $@convention(thin) (Int) -> () {
 bb0(%0 : $Int):
-  %c = checked_cast_value_br %0 : $Int to $Int, bb2, bb1
+  checked_cast_value_br %0 : $Int to $Int, bb2, bb1
 
 bb1:
   br bb3
@@ -58,7 +58,7 @@
 sil @initDeinitExistentialValue : $@convention(thin) <T> (@in T) -> () {
 bb0(%0 : $T):
   %i = init_existential_value %0 : $T, $T, $Any
-  %d = deinit_existential_value %i : $Any
+  deinit_existential_value %i : $Any
   %t = tuple ()
   return %t : $()
 }
diff --git a/test/SIL/ownership-verifier/definite_init.sil b/test/SIL/ownership-verifier/definite_init.sil
index 69fa754..e322f99 100644
--- a/test/SIL/ownership-verifier/definite_init.sil
+++ b/test/SIL/ownership-verifier/definite_init.sil
@@ -35,7 +35,7 @@
   %91 = alloc_box $<τ_0_0> { var τ_0_0 } <Builtin.Int32>
   %91a = project_box %91 : $<τ_0_0> { var τ_0_0 } <Builtin.Int32>, 0
   %1 = mark_uninitialized [var] %91a : $*Builtin.Int32
-  %2 = store %0 to [trivial] %1 : $*Builtin.Int32
+  store %0 to [trivial] %1 : $*Builtin.Int32
   %3 = load [trivial] %1 : $*Builtin.Int32
   %5 = function_ref @takes_Int_inout : $@convention(thin) (@inout Builtin.Int32) -> ()
   %6 = apply %5(%1) : $@convention(thin) (@inout Builtin.Int32) -> ()
diff --git a/test/SIL/ownership-verifier/use_verifier.sil b/test/SIL/ownership-verifier/use_verifier.sil
index 8429460..908afae 100644
--- a/test/SIL/ownership-verifier/use_verifier.sil
+++ b/test/SIL/ownership-verifier/use_verifier.sil
@@ -106,7 +106,7 @@
 sil @store_borrow_result : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () {
 bb0(%0 : @guaranteed $Builtin.NativeObject):
   %1 = alloc_stack $Builtin.NativeObject
-  %2 = store_borrow %0 to %1 : $*Builtin.NativeObject
+  store_borrow %0 to %1 : $*Builtin.NativeObject
   dealloc_stack %1 : $*Builtin.NativeObject
   %9999 = tuple()
   return %9999 : $()
@@ -324,10 +324,10 @@
   %011 = begin_borrow %01 : $RefWithInt
   %11 = alloc_stack $Builtin.UnsafeValueBuffer
   %21 = ref_element_addr %011 : $RefWithInt, #RefWithInt.value
-  %31 = begin_unpaired_access [modify] [dynamic] %21 : $*Builtin.Int32, %11 : $*Builtin.UnsafeValueBuffer
-  %41 = end_unpaired_access [dynamic] %11 : $*Builtin.UnsafeValueBuffer
-  %51 = begin_unpaired_access [read] [dynamic] %21 : $*Builtin.Int32, %11 : $*Builtin.UnsafeValueBuffer
-  %61 = end_unpaired_access [dynamic] %11 : $*Builtin.UnsafeValueBuffer
+  begin_unpaired_access [modify] [dynamic] %21 : $*Builtin.Int32, %11 : $*Builtin.UnsafeValueBuffer
+  end_unpaired_access [dynamic] %11 : $*Builtin.UnsafeValueBuffer
+  begin_unpaired_access [read] [dynamic] %21 : $*Builtin.Int32, %11 : $*Builtin.UnsafeValueBuffer
+  end_unpaired_access [dynamic] %11 : $*Builtin.UnsafeValueBuffer
   end_borrow %011 from %01 : $RefWithInt, $RefWithInt
   dealloc_stack %11 : $*Builtin.UnsafeValueBuffer
   destroy_value %01 : $RefWithInt
diff --git a/test/SILGen/inlineable_attribute.swift b/test/SILGen/inlineable_attribute.swift
index e747462..9150d51 100644
--- a/test/SILGen/inlineable_attribute.swift
+++ b/test/SILGen/inlineable_attribute.swift
@@ -74,3 +74,20 @@
 @_inlineable public func talkAboutAHorse(h: Horse) {
   _ = h.gallop
 }
+
+@_versioned class Base {
+  @_versioned
+  @_inlineable
+  init(horse: Horse) {}
+}
+
+// CHECK-LABEL: sil [serialized] @_T020inlineable_attribute7DerivedCfd : $@convention(method) (@guaranteed Derived) -> @owned Builtin.NativeObject
+// CHECK-LABEL: sil [serialized] @_T020inlineable_attribute7DerivedCfD : $@convention(method) (@owned Derived) -> ()
+
+// Make sure the synthesized delegating initializer is inlineable also
+
+// CHECK-LABEL: sil [serialized] @_T020inlineable_attribute7DerivedCAcA5HorseC5horse_tcfc : $@convention(method) (@owned Horse, @owned Derived) -> @owned Derived
+@_versioned class Derived : Base {
+  // Allow @_inlineable deinits
+  @_inlineable deinit {}
+}
diff --git a/test/SILGen/pgo_checked_cast.swift b/test/SILGen/pgo_checked_cast.swift
new file mode 100644
index 0000000..6ee7a21
--- /dev/null
+++ b/test/SILGen/pgo_checked_cast.swift
@@ -0,0 +1,71 @@
+// RUN: rm -rf %t && mkdir %t
+// RUN: %target-build-swift %s -profile-generate -Xfrontend -disable-incremental-llvm-codegen -module-name pgo_checked_cast -o %t/main
+// RUN: env LLVM_PROFILE_FILE=%t/default.profraw %target-run %t/main
+// RUN: %llvm-profdata merge %t/default.profraw -o %t/default.profdata
+// RUN: %target-swift-frontend %s -Xllvm -sil-full-demangle -profile-use=%t/default.profdata -emit-sorted-sil -emit-sil -module-name pgo_checked_cast -o - | %FileCheck %s --check-prefix=SIL
+// need to lower checked_cast_addr_br(addr) into IR for this
+// %target-swift-frontend %s -Xllvm -sil-full-demangle -profile-use=%t/default.profdata -emit-ir -module-name pgo_checked_cast -o - | %FileCheck %s --check-prefix=IR
+// RUN: %target-swift-frontend %s -Xllvm -sil-full-demangle -profile-use=%t/default.profdata -O -emit-sorted-sil -emit-sil -module-name pgo_checked_cast -o - | %FileCheck %s --check-prefix=SIL-OPT
+// need to lower checked_cast_addr_br(addr) into IR for this
+// %target-swift-frontend %s -Xllvm -sil-full-demangle -profile-use=%t/default.profdata -O -emit-ir -module-name pgo_checked_cast -o - | %FileCheck %s --check-prefix=IR-OPT
+
+// REQUIRES: profile_runtime
+// REQUIRES: OS=macosx
+
+// SIL-LABEL: // pgo_checked_cast.check1<A>(Any, A) -> A
+// SIL-LABEL: sil @_T016pgo_checked_cast6check1xyp_xtlF : $@convention(thin) <T> (@in Any, @in T) -> @out T !function_entry_count(5001) {
+// IR-LABEL: define swiftcc i32 @_T06pgo_checked_cast6guess1s5Int32VAD1x_tF
+// IR-OPT-LABEL: define swiftcc i32 @_T06pgo_checked_cast6guess1s5Int32VAD1x_tF
+public func check1<T>(_ a : Any, _ t : T) -> T {
+  // SIL: checked_cast_addr_br take_always Any in {{.*}} : $*Any to T in {{.*}} : $*T, {{.*}}, {{.*}} !true_count(5000) !false_count(1)
+  // SIL-OPT: checked_cast_addr_br take_always Any in {{.*}} : $*Any to T in {{.*}} : $*T, {{.*}}, {{.*}} !true_count(5000) !false_count(1)
+  if let x = a as? T {
+    return x
+  } else {
+    return t
+  }
+}
+
+public class B {}
+public class C : B {}
+public class D : C {}
+
+// SIL-LABEL: // pgo_checked_cast.check2(pgo_checked_cast.B) -> Swift.Int32
+// SIL-LABEL: sil @_T016pgo_checked_cast6check2s5Int32VAA1BCF : $@convention(thin) (@owned B) -> Int32 !function_entry_count(5003) {
+// IR-LABEL: define swiftcc i32 @_T06pgo_checked_cast6guess1s5Int32VAD1x_tF
+// IR-OPT-LABEL: define swiftcc i32 @_T06pgo_checked_cast6guess1s5Int32VAD1x_tF
+public func check2(_ a : B) -> Int32 {
+  // SIL: checked_cast_br %0 : $B to $D, {{.*}}, {{.*}} !true_count(5000)
+  // SIL: checked_cast_br %0 : $B to $C, {{.*}}, {{.*}} !true_count(2)
+  // SIL-OPT: checked_cast_br %0 : $B to $D, {{.*}}, {{.*}} !true_count(5000)
+  // SIL-OPT: checked_cast_br %0 : $B to $C, {{.*}}, {{.*}} !true_count(2)
+  switch a {
+    case is D:
+      return 42
+    case is C:
+      return 23
+    default:
+      return 13
+  }
+}
+
+func main() {
+  let answer : Int32 = 42
+  var sum : Int32 = 0
+
+  sum += check1("The answer to the life, the universe, and everything", answer)
+  
+  sum += check2(B())
+  sum += check2(C())
+  sum += check2(C())
+
+  for i : Int32 in 1...5000 {
+    sum += check1(i, answer)
+    sum += check2(D())
+  }
+}
+
+main()
+
+// IR: !{!"branch_weights", i32 5001, i32 2}
+// IR-OPT: !{!"branch_weights", i32 5001, i32 2}
diff --git a/test/SILGen/pgo_foreach.swift b/test/SILGen/pgo_foreach.swift
new file mode 100644
index 0000000..2ab281c
--- /dev/null
+++ b/test/SILGen/pgo_foreach.swift
@@ -0,0 +1,68 @@
+// RUN: rm -rf %t && mkdir %t
+// RUN: %target-build-swift %s -profile-generate -Xfrontend -disable-incremental-llvm-codegen -module-name pgo_foreach -o %t/main
+// RUN: env LLVM_PROFILE_FILE=%t/default.profraw %target-run %t/main
+// RUN: %llvm-profdata merge %t/default.profraw -o %t/default.profdata
+// need to move counts attached to expr for this
+// RUN: %target-swift-frontend %s -Xllvm -sil-full-demangle -profile-use=%t/default.profdata -emit-sorted-sil -emit-sil -module-name pgo_foreach -o - | %FileCheck %s --check-prefix=SIL
+// need to lower switch_enum(addr) into IR for this
+// %target-swift-frontend %s -Xllvm -sil-full-demangle -profile-use=%t/default.profdata -emit-ir -module-name pgo_foreach -o - | %FileCheck %s --check-prefix=IR
+// need to check Opt support
+// %target-swift-frontend %s -Xllvm -sil-full-demangle -profile-use=%t/default.profdata -O -emit-sorted-sil -emit-sil -module-name pgo_foreach -o - | %FileCheck %s --check-prefix=SIL-OPT
+// need to lower switch_enum(addr) into IR for this
+// %target-swift-frontend %s -Xllvm -sil-full-demangle -profile-use=%t/default.profdata -O -emit-ir -module-name pgo_foreach -o - | %FileCheck %s --check-prefix=IR-OPT
+
+// REQUIRES: profile_runtime
+// REQUIRES: OS=macosx
+
+// SIL-LABEL: // pgo_foreach.guessForEach1
+// SIL-LABEL: sil @_T011pgo_foreach13guessForEach1s5Int32VAD1x_tF : $@convention(thin) (Int32) -> Int32 !function_entry_count(42) {
+// IR-LABEL: define swiftcc i32 @_T09pgo_foreach10guessWhiles5Int32VAD1x_tF
+// IR-OPT-LABEL: define swiftcc i32 @_T09pgo_foreach10guessWhiles5Int32VAD1x_tF
+
+public func guessForEach1(x: Int32) -> Int32 {
+  // SIL: switch_enum {{.*}} : $Optional<Int32>, case #Optional.some!enumelt.1: {{.*}} !case_count(798), case #Optional.none!enumelt: {{.*}} !case_count(42)
+
+  var ret : Int32 = 0
+  for currVal in stride(from: 5, to: x, by: 5) {
+    ret += currVal
+  }
+  return ret
+}
+
+// SIL-LABEL: // pgo_foreach.guessForEach2
+// SIL-LABEL: sil @_T011pgo_foreach13guessForEach2s5Int32VAD1x_tF : $@convention(thin) (Int32) -> Int32 !function_entry_count(42) {
+// IR-LABEL: define swiftcc i32 @_T09pgo_foreach10guessWhiles5Int32VAD1x_tF
+// IR-OPT-LABEL: define swiftcc i32 @_T09pgo_foreach10guessWhiles5Int32VAD1x_tF
+
+public func guessForEach2(x: Int32) -> Int32 {
+  // SIL: switch_enum {{.*}} : $Optional<(String, Int32)>, case #Optional.some!enumelt.1: {{.*}} !case_count(168), case #Optional.none!enumelt: {{.*}} !case_count(42)
+
+  var ret : Int32 = 0
+  let names = ["John" : Int32(1), "Paul" : Int32(2), "George" : Int32(3), "Ringo" : Int32(x)]
+  for (name, number) in names {
+    ret += Int32(name.count)
+    ret += number
+  }
+  return ret
+}
+
+// SIL-LABEL: // pgo_foreach.main()
+// IR-LABEL: define swiftcc i32 @_T09pgo_foreach10guessWhiles5Int32VAD1x_tF
+// IR-OPT-LABEL: define swiftcc i32 @_T09pgo_foreach10guessWhiles5Int32VAD1x_tF
+
+func main() {
+  // SIL: switch_enum {{.*}} : $Optional<Int>, case #Optional.some!enumelt.1: {{.*}} !case_count(42), case #Optional.none!enumelt: {{.*}} !case_count(1)
+  var guesses : Int32 = 0;
+
+  for _ in 1...42 {
+    guesses += guessForEach1(x: 100)
+    guesses += guessForEach2(x: 100)
+  }
+}
+
+main()
+
+// IR: !{!"branch_weights", i32 421, i32 43}
+// IR: !{!"branch_weights", i32 176401, i32 421}
+// IR-OPT: !{!"branch_weights", i32 421, i32 43}
+// IR-OPT: !{!"branch_weights", i32 176401, i32 421}
diff --git a/test/SILGen/pgo_guard.swift b/test/SILGen/pgo_guard.swift
new file mode 100644
index 0000000..0b79a52
--- /dev/null
+++ b/test/SILGen/pgo_guard.swift
@@ -0,0 +1,44 @@
+// RUN: rm -rf %t && mkdir %t
+// RUN: %target-build-swift %s -profile-generate -Xfrontend -disable-incremental-llvm-codegen -module-name pgo_guard -o %t/main
+// RUN: env LLVM_PROFILE_FILE=%t/default.profraw %target-run %t/main
+// RUN: %llvm-profdata merge %t/default.profraw -o %t/default.profdata
+// RUN: %target-swift-frontend %s -Xllvm -sil-full-demangle -profile-use=%t/default.profdata -emit-sorted-sil -emit-sil -module-name pgo_guard -o - | %FileCheck %s --check-prefix=SIL
+// RUN: %target-swift-frontend %s -Xllvm -sil-full-demangle -profile-use=%t/default.profdata -emit-ir -module-name pgo_guard -o - | %FileCheck %s --check-prefix=IR
+// RUN: %target-swift-frontend %s -Xllvm -sil-full-demangle -profile-use=%t/default.profdata -O -emit-sorted-sil -emit-sil -module-name pgo_guard -o - | %FileCheck %s --check-prefix=SIL-OPT
+// RUN: %target-swift-frontend %s -Xllvm -sil-full-demangle -profile-use=%t/default.profdata -O -emit-ir -module-name pgo_guard -o - | %FileCheck %s --check-prefix=IR-OPT
+
+// REQUIRES: profile_runtime
+// REQUIRES: OS=macosx
+
+// SIL-LABEL: // pgo_guard.guess1
+// SIL-LABEL: sil @_T09pgo_guard6guess1s5Int32VAD1x_tF : $@convention(thin) (Int32) -> Int32 !function_entry_count(5002) {
+// IR-LABEL: define swiftcc i32 @_T09pgo_guard6guess1s5Int32VAD1x_tF
+// IR-OPT-LABEL: define swiftcc i32 @_T09pgo_guard6guess1s5Int32VAD1x_tF
+
+public func guess1(x: Int32) -> Int32 {
+  // SIL: cond_br {{.*}} !true_count(5000) !false_count(2)
+  // SIL-OPT: cond_br {{.*}} !true_count(5000) !false_count(2)
+
+  // IR: br {{.*}}, !prof ![[BWMD:[0-9]+]]
+  guard (x == 10) else {
+    return 30
+  }
+  return 20
+}
+
+
+func main() {
+  var guesses : Int32 = 0;
+
+  guesses += guess1(x: 0)
+  guesses += guess1(x: 42)
+
+  for _ in 1...5000 {
+    guesses += guess1(x: 10)
+  }
+}
+
+main()
+
+// IR: !{!"branch_weights", i32 5001, i32 3}
+// IR-OPT: !{!"branch_weights", i32 5001, i32 3}
diff --git a/test/SILGen/pgo_if.swift b/test/SILGen/pgo_if.swift
new file mode 100644
index 0000000..018dc62
--- /dev/null
+++ b/test/SILGen/pgo_if.swift
@@ -0,0 +1,54 @@
+// RUN: rm -rf %t && mkdir %t
+// RUN: %target-build-swift %s -profile-generate -Xfrontend -disable-incremental-llvm-codegen -module-name pgo_if -o %t/main
+// RUN: env LLVM_PROFILE_FILE=%t/default.profraw %target-run %t/main
+// RUN: %llvm-profdata merge %t/default.profraw -o %t/default.profdata
+// RUN: %target-swift-frontend %s -Xllvm -sil-full-demangle -profile-use=%t/default.profdata -emit-sorted-sil -emit-sil -module-name pgo_if -o - | %FileCheck %s --check-prefix=SIL
+// RUN: %target-swift-frontend %s -Xllvm -sil-full-demangle -profile-use=%t/default.profdata -emit-ir -module-name pgo_if -o - | %FileCheck %s --check-prefix=IR
+// RUN: %target-swift-frontend %s -Xllvm -sil-full-demangle -profile-use=%t/default.profdata -O -emit-sorted-sil -emit-sil -module-name pgo_if -o - | %FileCheck %s --check-prefix=SIL-OPT
+// RUN: %target-swift-frontend %s -Xllvm -sil-full-demangle -profile-use=%t/default.profdata -O -emit-ir -module-name pgo_if -o - | %FileCheck %s --check-prefix=IR-OPT
+
+// REQUIRES: profile_runtime
+// REQUIRES: OS=macosx
+
+// SIL-LABEL: // pgo_if.guess1
+// SIL-LABEL: sil @_T06pgo_if6guess1s5Int32VAD1x_tF : $@convention(thin) (Int32) -> Int32 !function_entry_count(5001) {
+// IR-LABEL: define swiftcc i32 @_T06pgo_if6guess1s5Int32VAD1x_tF
+// IR-OPT-LABEL: define swiftcc i32 @_T06pgo_if6guess1s5Int32VAD1x_tF
+public func guess1(x: Int32) -> Int32 {
+  // SIL: cond_br {{.*}} !true_count(5000) !false_count(1)
+  // SIL-OPT: cond_br {{.*}} !true_count(5000) !false_count(1)
+
+  // IR: br {{.*}}, !prof ![[BWMD:[0-9]+]]
+  if (x == 10) {
+    return 20
+  } else {
+    return 30
+  }
+}
+
+// SIL-LABEL: // pgo_if.guess2
+// SIL-LABEL: sil @_T06pgo_if6guess2s5Int32VAD1x_tF : $@convention(thin) (Int32) -> Int32 !function_entry_count(5001) {
+// IR-LABEL: define swiftcc i32 @_T06pgo_if6guess2s5Int32VAD1x_tF
+// IR-OPT-LABEL: define swiftcc i32 @_T06pgo_if6guess2s5Int32VAD1x_tF
+public func guess2(x: Int32) -> Int32 {
+  // SIL: cond_br {{.*}} !true_count(5000) !false_count(1)
+  // SIL-OPT: cond_br {{.*}} !true_count(5000) !false_count(1)
+
+  // IR: br {{.*}}, !prof ![[BWMD]]
+  return (x == 5) ? 10 : 15
+}
+
+func main() {
+  var guesses : Int32 = 0;
+
+  guesses += guess1(x: 0) + guess2(x: 0)
+
+  for _ in 1...5000 {
+    guesses += guess1(x: 10) + guess2(x: 5)
+  }
+}
+
+main()
+
+// IR: !{!"branch_weights", i32 5001, i32 2}
+// IR-OPT: !{!"branch_weights", i32 5001, i32 2}
diff --git a/test/SILGen/pgo_repeatwhile.swift b/test/SILGen/pgo_repeatwhile.swift
new file mode 100644
index 0000000..e55ddfa
--- /dev/null
+++ b/test/SILGen/pgo_repeatwhile.swift
@@ -0,0 +1,51 @@
+// RUN: rm -rf %t && mkdir %t
+// RUN: %target-build-swift %s -profile-generate -Xfrontend -disable-incremental-llvm-codegen -module-name pgo_repeatwhile -o %t/main
+// RUN: env LLVM_PROFILE_FILE=%t/default.profraw %target-run %t/main
+// RUN: %llvm-profdata merge %t/default.profraw -o %t/default.profdata
+// RUN: %target-swift-frontend %s -Xllvm -sil-full-demangle -profile-use=%t/default.profdata -emit-sorted-sil -emit-sil -module-name pgo_repeatwhile -o - | %FileCheck %s --check-prefix=SIL
+// RUN: %target-swift-frontend %s -Xllvm -sil-full-demangle -profile-use=%t/default.profdata -emit-ir -module-name pgo_repeatwhile -o - | %FileCheck %s --check-prefix=IR
+// RUN: %target-swift-frontend %s -Xllvm -sil-full-demangle -profile-use=%t/default.profdata -O -emit-sorted-sil -emit-sil -module-name pgo_repeatwhile -o - | %FileCheck %s --check-prefix=SIL-OPT
+// need to check Opt support
+// %target-swift-frontend %s -Xllvm -sil-full-demangle -profile-use=%t/default.profdata -O -emit-ir -module-name pgo_repeatwhile -o - | %FileCheck %s --check-prefix=IR-OPT
+
+// REQUIRES: profile_runtime
+// REQUIRES: OS=macosx
+
+// SIL-LABEL: // pgo_repeatwhile.guessWhile
+// SIL-LABEL: sil @_T015pgo_repeatwhile10guessWhiles5Int32VAD1x_tF : $@convention(thin) (Int32) -> Int32 !function_entry_count(42) {
+// IR-LABEL: define swiftcc i32 @_T015pgo_repeatwhile10guessWhiles5Int32VAD1x_tF
+// IR-OPT-LABEL: define swiftcc i32 @_T015pgo_repeatwhile10guessWhiles5Int32VAD1x_tF
+
+public func guessWhile(x: Int32) -> Int32 {
+  // SIL: cond_br {{.*}} !true_count(176400) !false_count(420)
+  // SIL: cond_br {{.*}} !true_count(420) !false_count(42)
+  // SIL-OPT: cond_br {{.*}} !true_count(176400) !false_count(420)
+  // SIL-OPT: cond_br {{.*}} !true_count(420) !false_count(42)
+
+  var ret : Int32 = 0
+  var currX : Int32 = 0
+  repeat {
+    var currInnerX : Int32 = x*42
+    repeat {
+      ret += currInnerX
+      currInnerX -= 1
+    } while (currInnerX > 0)
+    currX += 1
+  } while (currX < x)
+  return ret
+}
+
+func main() {
+  var guesses : Int32 = 0;
+
+  for _ in 1...42 {
+    guesses += guessWhile(x: 10)
+  }
+}
+
+main()
+
+// IR: !{!"branch_weights", i32 176401, i32 421}
+// IR: !{!"branch_weights", i32 421, i32 43}
+// IR-OPT: !{!"branch_weights", i32 176401, i32 421}
+// IR-OPT: !{!"branch_weights", i32 421, i32 43}
diff --git a/test/SILGen/pgo_switchenum.swift b/test/SILGen/pgo_switchenum.swift
new file mode 100644
index 0000000..079154b
--- /dev/null
+++ b/test/SILGen/pgo_switchenum.swift
@@ -0,0 +1,99 @@
+// RUN: rm -rf %t && mkdir %t
+// RUN: %target-build-swift %s -profile-generate -Xfrontend -disable-incremental-llvm-codegen -module-name pgo_switchenum -o %t/main
+// RUN: env LLVM_PROFILE_FILE=%t/default.profraw %target-run %t/main
+// RUN: %llvm-profdata merge %t/default.profraw -o %t/default.profdata
+// need to move counts attached to expr for this
+// RUN: %target-swift-frontend %s -Xllvm -sil-full-demangle -profile-use=%t/default.profdata -emit-sorted-sil -emit-sil -module-name pgo_switchenum -o - | %FileCheck %s --check-prefix=SIL
+// need to lower switch_enum(addr) into IR for this
+// %target-swift-frontend %s -Xllvm -sil-full-demangle -profile-use=%t/default.profdata -emit-ir -module-name pgo_switchenum -o - | %FileCheck %s --check-prefix=IR
+// need to check Opt support
+// %target-swift-frontend %s -Xllvm -sil-full-demangle -profile-use=%t/default.profdata -O -emit-sorted-sil -emit-sil -module-name pgo_switchenum -o - | %FileCheck %s --check-prefix=SIL-OPT
+// need to lower switch_enum(addr) into IR for this
+// %target-swift-frontend %s -Xllvm -sil-full-demangle -profile-use=%t/default.profdata -O -emit-ir -module-name pgo_switchenum -o - | %FileCheck %s --check-prefix=IR-OPT
+
+// REQUIRES: profile_runtime
+// REQUIRES: OS=macosx
+
+public enum MaybePair {
+  case Neither
+  case Left(Int32)
+  case Right(String)
+  case Both(Int32, String)
+}
+
+// SIL-LABEL: // pgo_switchenum.guess1
+// SIL-LABEL: sil @_T014pgo_switchenum6guess1s5Int32VAA9MaybePairO1x_tF : $@convention(thin) (@owned MaybePair) -> Int32 !function_entry_count(5011) {
+// IR-LABEL: define swiftcc i32 @_T09pgo_switchenum6guess1s5Int32VAD1x_tF
+// IR-OPT-LABEL: define swiftcc i32 @_T09pgo_switchenum6guess1s5Int32VAD1x_tF
+
+public func guess1(x: MaybePair) -> Int32 {
+  // SIL: switch_enum {{.*}} : $MaybePair, case #MaybePair.Neither!enumelt: {{.*}} !case_count(2), case #MaybePair.Left!enumelt.1: {{.*}} !case_count(5001), case #MaybePair.Right!enumelt.1: {{.*}} !case_count(3), case #MaybePair.Both!enumelt.1: {{.*}} !case_count(5)
+  // SIL-OPT: switch_enum {{.*}} : $MaybePair, case #MaybePair.Neither!enumelt: {{.*}} !case_count(2), case #MaybePair.Left!enumelt.1: {{.*}} !case_count(5001), case #MaybePair.Right!enumelt.1: {{.*}} !case_count(3), case #MaybePair.Both!enumelt.1: {{.*}} !case_count(5)
+  switch x {
+  case .Neither:
+    return 1
+  case let .Left(val):
+    return val*2
+  case let .Right(val):
+    return Int32(val.count)
+  case let .Both(valNum, valStr):
+    return valNum + Int32(valStr.count)
+  }
+}
+
+// SIL-LABEL: // pgo_switchenum.guess2
+// SIL-LABEL: sil @_T014pgo_switchenum6guess2s5Int32VAA9MaybePairO1x_tF : $@convention(thin) (@owned MaybePair) -> Int32 !function_entry_count(5011) {
+public func guess2(x: MaybePair) -> Int32 {
+  // SIL: switch_enum {{.*}} : $MaybePair, case #MaybePair.Neither!enumelt: {{.*}} !case_count(2), case #MaybePair.Left!enumelt.1: {{.*}} !case_count(5001), default {{.*}} !default_count(8)
+  // SIL-OPT: switch_enum {{.*}} : $MaybePair, case #MaybePair.Neither!enumelt: {{.*}} !case_count(2), case #MaybePair.Left!enumelt.1: {{.*}} !case_count(5001), default {{.*}} !default_count(8)
+  switch x {
+  case .Neither:
+    return 1
+  case let .Left(val):
+    return val*2
+  default:
+    return 42;
+  }
+}
+
+
+func main() {
+  var guesses : Int32 = 0;
+
+  guesses += guess1(x: MaybePair.Neither)
+  guesses += guess1(x: MaybePair.Neither)
+  guesses += guess1(x: MaybePair.Left(42))
+  guesses += guess1(x: MaybePair.Right("The Answer"))
+  guesses += guess1(x: MaybePair.Right("The Answer"))
+  guesses += guess1(x: MaybePair.Right("The Answer"))
+  guesses += guess1(x: MaybePair.Both(42, "The Answer"))
+  guesses += guess1(x: MaybePair.Both(42, "The Answer"))
+  guesses += guess1(x: MaybePair.Both(42, "The Answer"))
+  guesses += guess1(x: MaybePair.Both(42, "The Answer"))
+  guesses += guess1(x: MaybePair.Both(42, "The Answer"))
+
+  for _ in 1...5000 {
+    guesses += guess1(x: MaybePair.Left(10))
+  }
+  
+  guesses += guess2(x: MaybePair.Neither)
+  guesses += guess2(x: MaybePair.Neither)
+  guesses += guess2(x: MaybePair.Left(42))
+  guesses += guess2(x: MaybePair.Right("The Answer"))
+  guesses += guess2(x: MaybePair.Right("The Answer"))
+  guesses += guess2(x: MaybePair.Right("The Answer"))
+  guesses += guess2(x: MaybePair.Both(42, "The Answer"))
+  guesses += guess2(x: MaybePair.Both(42, "The Answer"))
+  guesses += guess2(x: MaybePair.Both(42, "The Answer"))
+  guesses += guess2(x: MaybePair.Both(42, "The Answer"))
+  guesses += guess2(x: MaybePair.Both(42, "The Answer"))
+
+  for _ in 1...5000 {
+    guesses += guess2(x: MaybePair.Left(10))
+  }
+}
+
+main()
+
+// IR: !{!"branch_weights", i32 5001, i32 3}
+// IR-OPT: !{!"branch_weights", i32 5001, i32 3}
diff --git a/test/SILGen/pgo_while.swift b/test/SILGen/pgo_while.swift
new file mode 100644
index 0000000..20238d7
--- /dev/null
+++ b/test/SILGen/pgo_while.swift
@@ -0,0 +1,51 @@
+// RUN: rm -rf %t && mkdir %t
+// RUN: %target-build-swift %s -profile-generate -Xfrontend -disable-incremental-llvm-codegen -module-name pgo_while -o %t/main
+// RUN: env LLVM_PROFILE_FILE=%t/default.profraw %target-run %t/main
+// RUN: %llvm-profdata merge %t/default.profraw -o %t/default.profdata
+// RUN: %target-swift-frontend %s -Xllvm -sil-full-demangle -profile-use=%t/default.profdata -emit-sorted-sil -emit-sil -module-name pgo_while -o - | %FileCheck %s --check-prefix=SIL
+// RUN: %target-swift-frontend %s -Xllvm -sil-full-demangle -profile-use=%t/default.profdata -emit-ir -module-name pgo_while -o - | %FileCheck %s --check-prefix=IR
+// RUN: %target-swift-frontend %s -Xllvm -sil-full-demangle -profile-use=%t/default.profdata -O -emit-sorted-sil -emit-sil -module-name pgo_while -o - | %FileCheck %s --check-prefix=SIL-OPT
+// need to check Opt support
+// %target-swift-frontend %s -Xllvm -sil-full-demangle -profile-use=%t/default.profdata -O -emit-ir -module-name pgo_while -o - | %FileCheck %s --check-prefix=IR-OPT
+
+// REQUIRES: profile_runtime
+// REQUIRES: OS=macosx
+
+// SIL-LABEL: // pgo_while.guessWhile
+// SIL-LABEL: sil @_T09pgo_while10guessWhiles5Int32VAD1x_tF : $@convention(thin) (Int32) -> Int32 !function_entry_count(42) {
+// IR-LABEL: define swiftcc i32 @_T09pgo_while10guessWhiles5Int32VAD1x_tF
+// IR-OPT-LABEL: define swiftcc i32 @_T09pgo_while10guessWhiles5Int32VAD1x_tF
+
+public func guessWhile(x: Int32) -> Int32 {
+  // SIL: cond_br {{.*}} !true_count(420) !false_count(42)
+  // SIL: cond_br {{.*}} !true_count(176400) !false_count(420)
+  // SIL-OPT: cond_br {{.*}} !true_count(420) !false_count(42)
+  // SIL-OPT: cond_br {{.*}} !true_count(176400) !false_count(420)
+
+  var ret : Int32 = 0
+  var currX : Int32 = 0
+  while (currX < x) {
+    var currInnerX : Int32 = x*42
+    while (currInnerX > 0) {
+      ret += currInnerX
+      currInnerX -= 1
+    }
+    currX += 1
+  }
+  return ret
+}
+
+func main() {
+  var guesses : Int32 = 0;
+
+  for _ in 1...42 {
+    guesses += guessWhile(x: 10)
+  }
+}
+
+main()
+
+// IR: !{!"branch_weights", i32 421, i32 43}
+// IR: !{!"branch_weights", i32 176401, i32 421}
+// IR-OPT: !{!"branch_weights", i32 421, i32 43}
+// IR-OPT: !{!"branch_weights", i32 176401, i32 421}
diff --git a/test/SILGen/versioned_attribute.swift b/test/SILGen/versioned_attribute.swift
new file mode 100644
index 0000000..5a01525
--- /dev/null
+++ b/test/SILGen/versioned_attribute.swift
@@ -0,0 +1,17 @@
+// RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership -emit-verbose-sil %s | %FileCheck %s
+
+@_versioned class Horse {
+  var mouth: AnyObject?
+}
+
+@_versioned class GiftHorse {
+  var mouth: AnyObject?
+
+  deinit {}
+}
+
+// CHECK-LABEL: sil @_T019versioned_attribute5HorseCfd : $@convention(method) (@guaranteed Horse) -> @owned Builtin.NativeObject
+// CHECK-LABEL: sil @_T019versioned_attribute5HorseCfD : $@convention(method) (@owned Horse) -> ()
+
+// CHEKC-LABEL: sil @_T019versioned_attribute9GiftHorseCfd : $@convention(method) (@guaranteed GiftHorse) -> @owned Builtin.NativeObject
+// CHECK-LABEL: sil @_T019versioned_attribute9GiftHorseCfD : $@convention(method) (@owned GiftHorse) -> ()
diff --git a/test/SILOptimizer/abcopts.sil b/test/SILOptimizer/abcopts.sil
index 79592b8..fb2f530 100644
--- a/test/SILOptimizer/abcopts.sil
+++ b/test/SILOptimizer/abcopts.sil
@@ -133,7 +133,7 @@
   // CHECK: apply [[CHECKBOUNDS]]([[IDX4]], {{.*}}[[LD1]]
   %26 = ref_to_raw_pointer %5 : $Builtin.NativeObject to $Builtin.RawPointer
   %27 = pointer_to_address %26 : $Builtin.RawPointer to [strict] $*Builtin.Int32
-  %29 = store %x1 to %27 : $*Builtin.Int32
+  store %x1 to %27 : $*Builtin.Int32
   %l4 = load %0 : $*ArrayInt
   retain_value %5 : $Builtin.NativeObject
   %30 = apply %2(%i4, %102, %l4) : $@convention(method) (Int32, Bool, @owned ArrayInt) -> _DependenceToken
@@ -141,7 +141,7 @@
   // CHECK: [[LD4:%[0-9]+]] = load %0
   // CHECK: apply [[CHECKBOUNDS]]([[IDX4]], {{.*}}[[LD4]]
 
-  %98 = dealloc_stack %18 : $*Int32
+  dealloc_stack %18 : $*Int32
   %99 = tuple ()
   return %99 : $()
 // CHECK: return
diff --git a/test/SILOptimizer/access_enforcement_selection.sil b/test/SILOptimizer/access_enforcement_selection.sil
index abb6025..dbf440e 100644
--- a/test/SILOptimizer/access_enforcement_selection.sil
+++ b/test/SILOptimizer/access_enforcement_selection.sil
@@ -61,7 +61,7 @@
   end_access %39 : $*Builtin.Int64
   destroy_value %2 : ${ var Builtin.Int64 }
   %98 = tuple ()
-  %99 = return %98 : $()
+  return %98 : $()
 }
 
 
@@ -95,7 +95,7 @@
   end_access %7 : $*Builtin.Int64
   destroy_value %2 : ${ var Builtin.Int64 }
   %9 = tuple ()
-  %10 = return %9 : $()
+  return %9 : $()
 }
 
 
@@ -132,7 +132,7 @@
   destroy_value %16 : ${ var Builtin.Int64 }
   destroy_value %2 : ${ var Builtin.Int64 }
   %98 = tuple ()
-  %99 = return %98 : $()
+  return %98 : $()
 }
 
 sil @closure : $@convention(thin) (@owned { var Builtin.Int64 }) -> () {
diff --git a/test/SILOptimizer/access_summary_analysis.sil b/test/SILOptimizer/access_summary_analysis.sil
index be06d6e..0f7d46b 100644
--- a/test/SILOptimizer/access_summary_analysis.sil
+++ b/test/SILOptimizer/access_summary_analysis.sil
@@ -81,10 +81,10 @@
 bb0(%0 : $*StructWithStoredProperties):
   %1 = begin_access [modify] [unknown] %0: $*StructWithStoredProperties
   %2 = struct_element_addr %1 : $*StructWithStoredProperties, #StructWithStoredProperties.f
-  %3 = end_access %1 : $*StructWithStoredProperties
+  end_access %1 : $*StructWithStoredProperties
   %4 = begin_access [read] [unknown] %0: $*StructWithStoredProperties
   %5 = struct_element_addr %4 : $*StructWithStoredProperties, #StructWithStoredProperties.g
-  %6 = end_access %4 : $*StructWithStoredProperties
+  end_access %4 : $*StructWithStoredProperties
   %7 = tuple ()
   return %7 : $()
 }
@@ -95,10 +95,10 @@
 bb0(%0 : $*(Int, Int)):
   %1 = begin_access [modify] [unknown] %0: $*(Int, Int)
   %2 = tuple_element_addr %1 : $*(Int, Int), 0
-  %3 = end_access %1 : $*(Int, Int)
+  end_access %1 : $*(Int, Int)
   %4 = begin_access [read] [unknown] %0: $*(Int, Int)
   %5 = tuple_element_addr %4 : $*(Int, Int), 1
-  %6 = end_access %4 : $*(Int, Int)
+  end_access %4 : $*(Int, Int)
   %7 = tuple ()
   return %7 : $()
 }
@@ -110,11 +110,11 @@
   %1 = begin_access [modify] [unknown] %0: $*StructWithStructWithStoredProperties
   %2 = struct_element_addr %1 : $*StructWithStructWithStoredProperties, #StructWithStructWithStoredProperties.a
   %3 = struct_element_addr %2 : $*StructWithStoredProperties, #StructWithStoredProperties.f
-  %4 = end_access %1 : $*StructWithStructWithStoredProperties
+  end_access %1 : $*StructWithStructWithStoredProperties
   %5 = begin_access [modify] [unknown] %0: $*StructWithStructWithStoredProperties
   %6 = struct_element_addr %5 : $*StructWithStructWithStoredProperties, #StructWithStructWithStoredProperties.b
   %7 = struct_element_addr %6 : $*StructWithStoredProperties, #StructWithStoredProperties.g
-  %8 = end_access %5 : $*StructWithStructWithStoredProperties
+  end_access %5 : $*StructWithStructWithStoredProperties
   %9 = tuple ()
   return %9 : $()
 }
@@ -126,10 +126,10 @@
 bb0(%0 : $*StructWithStoredProperties):
   %1 = begin_access [modify] [unknown] %0: $*StructWithStoredProperties
   %2 = struct_element_addr %1 : $*StructWithStoredProperties, #StructWithStoredProperties.g
-  %3 = end_access %1 : $*StructWithStoredProperties
+  end_access %1 : $*StructWithStoredProperties
   %4 = begin_access [read] [unknown] %0: $*StructWithStoredProperties
   %5 = struct_element_addr %4 : $*StructWithStoredProperties, #StructWithStoredProperties.f
-  %6 = end_access %4 : $*StructWithStoredProperties
+  end_access %4 : $*StructWithStoredProperties
   %7 = tuple ()
   return %7 : $()
 }
@@ -139,10 +139,10 @@
 sil private @accessAggregateDoesNotSubsumeAccessStoredProp : $@convention(thin) (@inout_aliasable StructWithStoredProperties) -> () {
 bb0(%0 : $*StructWithStoredProperties):
   %1 = begin_access [modify] [unknown] %0: $*StructWithStoredProperties
-  %3 = end_access %1 : $*StructWithStoredProperties
+  end_access %1 : $*StructWithStoredProperties
   %4 = begin_access [modify] [unknown] %0: $*StructWithStoredProperties
   %5 = struct_element_addr %4 : $*StructWithStoredProperties, #StructWithStoredProperties.g
-  %6 = end_access %4 : $*StructWithStoredProperties
+  end_access %4 : $*StructWithStoredProperties
   %7 = tuple ()
   return %7 : $()
 }
@@ -153,9 +153,9 @@
 bb0(%0 : $*StructWithStoredProperties):
   %1 = begin_access [modify] [unknown] %0: $*StructWithStoredProperties
   %2 = struct_element_addr %1 : $*StructWithStoredProperties, #StructWithStoredProperties.f
-  %3 = end_access %1 : $*StructWithStoredProperties
+  end_access %1 : $*StructWithStoredProperties
   %4 = begin_access [modify] [unknown] %0: $*StructWithStoredProperties
-  %6 = end_access %4 : $*StructWithStoredProperties
+  end_access %4 : $*StructWithStoredProperties
   %7 = tuple ()
   return %7 : $()
 }
@@ -166,10 +166,10 @@
 bb0(%0 : $*StructWithStoredProperties):
   %1 = begin_access [read] [unknown] %0: $*StructWithStoredProperties
   %2 = struct_element_addr %1 : $*StructWithStoredProperties, #StructWithStoredProperties.f
-  %3 = end_access %1 : $*StructWithStoredProperties
+  end_access %1 : $*StructWithStoredProperties
   %4 = begin_access [modify] [unknown] %0: $*StructWithStoredProperties
   %5 = struct_element_addr %4 : $*StructWithStoredProperties, #StructWithStoredProperties.f
-  %6 = end_access %4 : $*StructWithStoredProperties
+  end_access %4 : $*StructWithStoredProperties
   %7 = tuple ()
   return %7 : $()
 }
@@ -241,7 +241,7 @@
 sil private @callThrowingClosureThatModifiesCapture : $@convention(thin) (@inout_aliasable Int) -> () {
 bb0(%0 : $*Int):
   %1 = function_ref @throwingClosureThatModifesCapture : $@convention(thin) (@inout_aliasable Int) -> @error Error
-  %2 = try_apply %1(%0) : $@convention(thin) (@inout_aliasable Int) -> @error Error, normal bb1, error bb2
+  try_apply %1(%0) : $@convention(thin) (@inout_aliasable Int) -> @error Error, normal bb1, error bb2
 bb1(%3 : $()):
   %4 = tuple ()
   return %4 : $()
diff --git a/test/SILOptimizer/allocbox_to_stack.sil b/test/SILOptimizer/allocbox_to_stack.sil
index 22ab57b..428caf5 100644
--- a/test/SILOptimizer/allocbox_to_stack.sil
+++ b/test/SILOptimizer/allocbox_to_stack.sil
@@ -17,10 +17,10 @@
 bb0(%0 : $Int):
   %1 = alloc_box ${ var Int }
   %1a = project_box %1 : ${ var Int }, 0
-  %2 = store %0 to %1a : $*Int
+  store %0 to %1a : $*Int
   %3 = load %1a : $*Int
-  %4 = strong_release %1 : ${ var Int }
-  %5 = return %3 : $Int
+  strong_release %1 : ${ var Int }
+  return %3 : $Int
 
 // CHECK: alloc_stack
 // CHECK-NOT: alloc_box
@@ -33,13 +33,13 @@
 bb0(%0 : $Int):
   %1 = alloc_box ${ var Int }
   %1a = project_box %1 : ${ var Int }, 0
-  %2 = store %0 to %1a : $*Int
+  store %0 to %1a : $*Int
   %3 = load %1a : $*Int
   %1b = project_box %1 : ${ var Int }, 0
   %3b = load %1b : $*Int
-  %4 = strong_release %1 : ${ var Int }
+  strong_release %1 : ${ var Int }
   %r = tuple (%3 : $Int, %3b : $Int)
-  %5 = return %r : $(Int, Int)
+  return %r : $(Int, Int)
 
 // CHECK: alloc_stack
 // CHECK-NOT: alloc_box
@@ -53,8 +53,8 @@
   %1 = alloc_box ${ var Int }
   %1a = project_box %1 : ${ var Int }, 0
   %3 = load %1a : $*Int
-  %4 = strong_release %1 : ${ var Int }
-  %5 = return %3 : $Int
+  strong_release %1 : ${ var Int }
+  return %3 : $Int
 
 // CHECK: %0 = alloc_stack
 // CHECK-NOT: alloc_box
@@ -71,13 +71,13 @@
   %1a = mark_uninitialized [rootself] %1 : ${ var Int }
   %2 = project_box %1a : ${ var Int }, 0
   %3 = load %2 : $*Int
-  %x = strong_retain %1a : ${ var Int }
-  %y = strong_release %1a : ${ var Int }
-  %b = br bb1
+  strong_retain %1a : ${ var Int }
+  strong_release %1a : ${ var Int }
+  br bb1
 bb1:
 
-  %4 = strong_release %1a : ${ var Int }
-  %5 = return %3 : $Int
+  strong_release %1a : ${ var Int }
+  return %3 : $Int
 
 // CHECK: %0 = alloc_stack
 // CHECK: bb1:
@@ -100,18 +100,18 @@
   %aa = project_box %a : ${ var (Int, Int) }, 0
 
   %2 = struct_element_addr %1a : $*TestStruct, #TestStruct.Elt
-  %3 = store %0 to %2 : $*Int
+  store %0 to %2 : $*Int
 
   %b = tuple_element_addr %aa : $*(Int, Int), 0
-  %c = store %0 to %b : $*Int
+  store %0 to %b : $*Int
 
   %6 = struct_element_addr %1a : $*TestStruct, #TestStruct.Elt
   %7 = load %6 : $*Int
-  %x = strong_release %a : ${ var (Int, Int) }
-  %8 = strong_release %1 : ${ var TestStruct }
+  strong_release %a : ${ var (Int, Int) }
+  strong_release %1 : ${ var TestStruct }
 
 
-  %9 = return %7 : $Int
+  return %7 : $Int
 
 // CHECK-DAG: dealloc_stack [[STRUCT]]
 // CHECK-DAG: dealloc_stack [[TUPLE]]
@@ -132,11 +132,11 @@
   %6 = function_ref @callee : $@convention(thin) (@inout Int) -> ()
   %7 = apply %6(%1a) : $@convention(thin) (@inout Int) -> ()
   %8 = load %1a : $*Int
-  %9 = strong_release %1 : ${ var Int }
+  strong_release %1 : ${ var Int }
   %10 = address_to_pointer %1a : $*Int to $Builtin.RawPointer
   %11 = pointer_to_address %10 : $Builtin.RawPointer to [strict] $*Int
   %12 = load %11 : $*Int
-  %13 = return %8 : $Int
+  return %8 : $Int
   // CHECK: return
 }
 
@@ -154,9 +154,9 @@
   %2 = alloc_box ${ var P }
   %2a = project_box %2 : ${ var P }, 0
   %3 = apply %1(%2a) : $@convention(thin) () -> @out P
-  %5 = strong_release %2 : ${ var P }
+  strong_release %2 : ${ var P }
   %0 = tuple ()
-  %6 = return %0 : $()
+  return %0 : $()
   // CHECK: return
 }
 
@@ -167,10 +167,10 @@
 bb0(%0 : $SomeClass):
   %1 = alloc_box ${ var SomeClass }
   %1a = project_box %1 : ${ var SomeClass }, 0
-  %2 = store %0 to %1a : $*SomeClass
+  store %0 to %1a : $*SomeClass
   %3 = load %1a : $*SomeClass
-  %4 = strong_release %1 : ${ var SomeClass }
-  %5 = return %3 : $SomeClass
+  strong_release %1 : ${ var SomeClass }
+  return %3 : $SomeClass
 
 // CHECK: %1 = alloc_stack
 // CHECK-NOT: alloc_box
@@ -212,7 +212,7 @@
   dealloc_box %1 : $<τ_0_0> { var Generic<τ_0_0> } <T>
 
   %0 = tuple ()    // CHECK: tuple ()
-  %6 = return %0 : $()
+  return %0 : $()
   // CHECK: return
 }
 
@@ -779,7 +779,7 @@
 
 bb2:
   %1a = project_box %1 : ${ var Int }, 0
-  %2 = store %0 to %1a : $*Int
+  store %0 to %1a : $*Int
   dealloc_stack %as1 : $*Bool
   %3 = load %1a : $*Int
   %as2 = alloc_stack $Bool
@@ -789,7 +789,7 @@
 
 bb3:
   %r = tuple ()
-  %5 = return %r : $()
+  return %r : $()
 }
 
 // CHECK-LABEL: sil @wrong_nesting_with_alloc_ref
@@ -806,12 +806,12 @@
   %as1 = alloc_ref [stack] $SomeClass
   %1 = alloc_box ${ var Int }
   %1a = project_box %1 : ${ var Int }, 0
-  %2 = store %0 to %1a : $*Int
+  store %0 to %1a : $*Int
   dealloc_ref [stack] %as1 : $SomeClass
   %3 = load %1a : $*Int
   strong_release %1 : ${ var Int }
   %r = tuple ()
-  %5 = return %r : $()
+  return %r : $()
 }
 
 // CHECK-LABEL: sil @nesting_and_unreachable1
@@ -841,12 +841,12 @@
   unreachable
 
 bb2:
-  %2 = store %0 to %1a : $*Int
+  store %0 to %1a : $*Int
   dealloc_stack %as1 : $*Bool
   %3 = load %1a : $*Int
   strong_release %1 : ${ var Int }
   %r = tuple ()
-  %5 = return %r : $()
+  return %r : $()
 }
 
 // CHECK-LABEL: sil @nesting_and_unreachable2
@@ -879,12 +879,12 @@
   unreachable
 
 bb2:
-  %2 = store %0 to %1a : $*Int
+  store %0 to %1a : $*Int
   dealloc_stack %as1 : $*Bool
   %3 = load %1a : $*Int
   strong_release %1 : ${ var Int }
   %r = tuple ()
-  %5 = return %r : $()
+  return %r : $()
 }
 
 // CHECK-LABEL: sil @nesting_and_unreachable3
@@ -913,12 +913,12 @@
   unreachable
 
 bb2:
-  %2 = store %0 to %1a : $*Int
+  store %0 to %1a : $*Int
   %3 = load %1a : $*Int
   dealloc_stack %as1 : $*Bool
   strong_release %1 : ${ var Int }
   %r = tuple ()
-  %5 = return %r : $()
+  return %r : $()
 }
 
 // CHECK-LABEL: sil @nesting_and_unreachable4
@@ -941,11 +941,11 @@
   unreachable
 
 bb2:
-  %2 = store %0 to %1a : $*Int
+  store %0 to %1a : $*Int
   %3 = load %1a : $*Int
   strong_release %1 : ${ var Int }
   %r = tuple ()
-  %5 = return %r : $()
+  return %r : $()
 }
 
 // CHECK-LABEL: sil @nesting_and_unreachable5
@@ -972,11 +972,11 @@
   unreachable
 
 bb2:
-  %2 = store %0 to %1a : $*Int
+  store %0 to %1a : $*Int
   %3 = load %1a : $*Int
   strong_release %1 : ${ var Int }
   %r = tuple ()
-  %5 = return %r : $()
+  return %r : $()
 }
 
 // CHECK-LABEL: sil @nesting_and_unreachable_critical_edge
@@ -1016,13 +1016,13 @@
   cond_br undef, bb2, bb3
 
 bb2:
-  %2 = store %0 to %1a : $*Int
+  store %0 to %1a : $*Int
   %3 = load %1a : $*Int
   dealloc_stack %as2 : $*Bool
   dealloc_stack %as1 : $*Bool
   strong_release %1 : ${ var Int }
   %r = tuple ()
-  %5 = return %r : $()
+  return %r : $()
 
 bb3:
   strong_release %1 : ${ var Int }
diff --git a/test/SILOptimizer/allocbox_to_stack_ownership.sil b/test/SILOptimizer/allocbox_to_stack_ownership.sil
index ef260ed..3511621 100644
--- a/test/SILOptimizer/allocbox_to_stack_ownership.sil
+++ b/test/SILOptimizer/allocbox_to_stack_ownership.sil
@@ -17,7 +17,7 @@
 bb0(%0 : @trivial $Int):
   %1 = alloc_box ${ var Int }
   %1a = project_box %1 : ${ var Int }, 0
-  %2 = store %0 to [trivial] %1a : $*Int
+  store %0 to [trivial] %1a : $*Int
 
   %3 = load [trivial] %1a : $*Int
   destroy_value %1 : ${ var Int }
@@ -33,7 +33,7 @@
 bb0(%0 : @trivial $Int):
   %1 = alloc_box ${ var Int }
   %1a = project_box %1 : ${ var Int }, 0
-  %2 = store %0 to [trivial] %1a : $*Int
+  store %0 to [trivial] %1a : $*Int
   %3 = load [trivial] %1a : $*Int
 
   %1b = project_box %1 : ${ var Int }, 0
@@ -54,8 +54,8 @@
   %1 = alloc_box ${ var Int }
   %1a = project_box %1 : ${ var Int }, 0
   %3 = load [trivial] %1a : $*Int
-  %4 = destroy_value %1 : ${ var Int }
-  %5 = return %3 : $Int
+  destroy_value %1 : ${ var Int }
+  return %3 : $Int
 
 // CHECK: %0 = alloc_stack
 // CHECK-NOT: alloc_box
@@ -78,7 +78,7 @@
 
 bb1:
   destroy_value %x : ${ var Int }
-  %5 = return %3 : $Int
+  return %3 : $Int
 
 // CHECK: %0 = alloc_stack
 // CHECK: bb1:
@@ -101,17 +101,17 @@
   %aa = project_box %a : ${ var (Int, Int) }, 0
 
   %2 = struct_element_addr %1a : $*TestStruct, #TestStruct.Elt
-  %3 = store %0 to [trivial] %2 : $*Int
+  store %0 to [trivial] %2 : $*Int
 
   %b = tuple_element_addr %aa : $*(Int, Int), 0
-  %c = store %0 to [trivial] %b : $*Int
+  store %0 to [trivial] %b : $*Int
 
   %6 = struct_element_addr %1a : $*TestStruct, #TestStruct.Elt
   %7 = load [trivial] %6 : $*Int
   destroy_value %a : ${ var (Int, Int) }
   destroy_value %1 : ${ var TestStruct }
 
-  %9 = return %7 : $Int
+  return %7 : $Int
 
 // CHECK-DAG: dealloc_stack [[STRUCT]]
 // CHECK-DAG: dealloc_stack [[TUPLE]]
@@ -133,7 +133,7 @@
   %10 = address_to_pointer %1a : $*Int to $Builtin.RawPointer
   %11 = pointer_to_address %10 : $Builtin.RawPointer to [strict] $*Int
   %12 = load [trivial] %11 : $*Int
-  %13 = return %8 : $Int
+  return %8 : $Int
   // CHECK: return
 }
 
@@ -152,7 +152,7 @@
   %3 = apply %1(%2a) : $@convention(thin) () -> @out P
   destroy_value %2 : ${ var P }
   %0 = tuple ()
-  %6 = return %0 : $()
+  return %0 : $()
   // CHECK: return
 }
 
@@ -208,7 +208,7 @@
   dealloc_box %1 : $<τ_0_0> { var Generic<τ_0_0> } <T>
 
   %0 = tuple ()    // CHECK: tuple ()
-  %6 = return %0 : $()
+  return %0 : $()
   // CHECK: return
 }
 
@@ -774,7 +774,7 @@
 
 bb2:
   %1a = project_box %1 : ${ var Int }, 0
-  %2 = store %0 to [trivial] %1a : $*Int
+  store %0 to [trivial] %1a : $*Int
   dealloc_stack %as1 : $*Bool
   %3 = load [trivial] %1a : $*Int
   %as2 = alloc_stack $Bool
@@ -784,7 +784,7 @@
 
 bb3:
   %r = tuple ()
-  %5 = return %r : $()
+  return %r : $()
 }
 
 // CHECK-LABEL: sil @wrong_nesting_with_alloc_ref
@@ -806,7 +806,7 @@
   %3 = load [trivial] %1a : $*Int
   destroy_value %1 : ${ var Int }
   %r = tuple ()
-  %5 = return %r : $()
+  return %r : $()
 }
 
 // CHECK-LABEL: sil @nesting_and_unreachable1
@@ -841,7 +841,7 @@
   %3 = load [trivial] %1a : $*Int
   destroy_value %1 : ${ var Int }
   %r = tuple ()
-  %5 = return %r : $()
+  return %r : $()
 }
 
 // CHECK-LABEL: sil @nesting_and_unreachable2
@@ -874,12 +874,12 @@
   unreachable
 
 bb2:
-  %2 = store %0 to [trivial] %1a : $*Int
+  store %0 to [trivial] %1a : $*Int
   dealloc_stack %as1 : $*Bool
   %3 = load [trivial] %1a : $*Int
   destroy_value %1 : ${ var Int }
   %r = tuple ()
-  %5 = return %r : $()
+  return %r : $()
 }
 
 // CHECK-LABEL: sil @nesting_and_unreachable3
@@ -913,7 +913,7 @@
   dealloc_stack %as1 : $*Bool
   destroy_value %1 : ${ var Int }
   %r = tuple ()
-  %5 = return %r : $()
+  return %r : $()
 }
 
 // CHECK-LABEL: sil @nesting_and_unreachable4
@@ -936,11 +936,11 @@
   unreachable
 
 bb2:
-  %2 = store %0 to [trivial] %1a : $*Int
+  store %0 to [trivial] %1a : $*Int
   %3 = load [trivial] %1a : $*Int
   destroy_value %1 : ${ var Int }
   %r = tuple ()
-  %5 = return %r : $()
+  return %r : $()
 }
 
 // CHECK-LABEL: sil @nesting_and_unreachable5
@@ -967,11 +967,11 @@
   unreachable
 
 bb2:
-  %2 = store %0 to [trivial] %1a : $*Int
+  store %0 to [trivial] %1a : $*Int
   %3 = load [trivial] %1a : $*Int
   destroy_value %1 : ${ var Int }
   %r = tuple ()
-  %5 = return %r : $()
+  return %r : $()
 }
 
 // CHECK-LABEL: sil @nesting_and_unreachable_critical_edge
@@ -1011,13 +1011,13 @@
   cond_br undef, bb2, bb3
 
 bb2:
-  %2 = store %0 to [trivial] %1a : $*Int
+  store %0 to [trivial] %1a : $*Int
   %3 = load [trivial] %1a : $*Int
   dealloc_stack %as2 : $*Bool
   dealloc_stack %as1 : $*Bool
   destroy_value %1 : ${ var Int }
   %r = tuple ()
-  %5 = return %r : $()
+  return %r : $()
 
 bb3:
   destroy_value %1 : ${ var Int }
diff --git a/test/SILOptimizer/array_specialize.sil b/test/SILOptimizer/array_specialize.sil
index c39d77d..fdab0ed 100644
--- a/test/SILOptimizer/array_specialize.sil
+++ b/test/SILOptimizer/array_specialize.sil
@@ -109,3 +109,70 @@
 bb5(%9 : $Error):
   throw %9 : $Error
 }
+
+sil @dominator_update_outside_non_exit_block : $@convention(thin) (@inout MyArray<MyClass>, @inout Builtin.Int1) -> Builtin.Int1 {
+bb0(%0 : $*MyArray<MyClass>, %1 : $*Builtin.Int1):
+  %3 = load %0 : $*MyArray<MyClass>
+  br bb1
+
+bb1:
+  %2 = function_ref @arrayPropertyIsNative : $@convention(method) (@owned MyArray<MyClass>) -> Bool
+  %4 = load %1 : $*Builtin.Int1
+  retain_value %3 : $MyArray<MyClass>
+  %5 = apply %2(%3) : $@convention(method) (@owned MyArray<MyClass>) -> Bool
+  cond_br %4, bb2, bb4
+
+bb2:
+ cond_br undef, bb3, bb5
+
+bb3:
+ %6 = integer_literal $Builtin.Int1, -1
+ cond_br %6, bb1, bb7
+
+bb4: // Exit block; b1 dom b4
+ cond_br undef, bb5, bb6
+
+bb5: // Exit Block; b1 dom b4
+ br bb6
+
+bb6: // Non-exit Dominated by bb1
+ br bb7
+
+bb7:
+  return %4 : $Builtin.Int1
+}
+
+sil @dominator_update_outside_non_exit_block_2 : $@convention(thin) (@inout MyArray<MyClass>, @inout Builtin.Int1) -> Builtin.Int1 {
+bb0(%0 : $*MyArray<MyClass>, %1 : $*Builtin.Int1):
+  %3 = load %0 : $*MyArray<MyClass>
+  br bb1
+
+bb1:
+  %2 = function_ref @arrayPropertyIsNative : $@convention(method) (@owned MyArray<MyClass>) -> Bool
+  %4 = load %1 : $*Builtin.Int1
+  retain_value %3 : $MyArray<MyClass>
+  %5 = apply %2(%3) : $@convention(method) (@owned MyArray<MyClass>) -> Bool
+  cond_br %4, bb2, bb4
+
+bb2:
+ cond_br undef, bb3, bb5
+
+bb3:
+ %6 = integer_literal $Builtin.Int1, -1
+ cond_br %6, bb1, bb7
+
+bb4: // Exit block; b1 dom b4
+ cond_br undef, bb5, bb6
+
+bb5: // Exit Block; b1 dom b4
+ br bb6
+
+bb6: // Non-exit Dominated by bb1
+ br bb8
+
+bb7: // Exit dominated by bb3
+ br bb8
+
+bb8: // Non-exit dominated by bb1
+  return %4 : $Builtin.Int1
+}
diff --git a/test/SILOptimizer/cast_foldings.sil b/test/SILOptimizer/cast_foldings.sil
index 6c45892..0a9bde5 100644
--- a/test/SILOptimizer/cast_foldings.sil
+++ b/test/SILOptimizer/cast_foldings.sil
@@ -35,7 +35,7 @@
 // CHECK:         store
 sil @function_cast_nothrow_to_nothrow : $@convention(thin) <T> () -> () {
 entry:
-  %a = unconditional_checked_cast_addr () -> ()        in undef : $*(@in ()) -> @out ()                 to () -> ()        in undef : $*(@in ()) -> @out ()
+  unconditional_checked_cast_addr () -> ()        in undef : $*(@in ()) -> @out ()                 to () -> ()        in undef : $*(@in ()) -> @out ()
   return undef : $()
 }
 
@@ -43,7 +43,7 @@
 // CHECK:         unconditional_checked_cast_addr
 sil @function_cast_nothrow_to_nothrow_substitutable : $@convention(thin) <T> () -> () {
 entry:
-  %a = unconditional_checked_cast_addr () -> ()        in undef : $*(@in ()) -> @out ()                 to (T) -> T        in undef : $*(@in T) -> @out T
+  unconditional_checked_cast_addr () -> ()        in undef : $*(@in ()) -> @out ()                 to (T) -> T        in undef : $*(@in T) -> @out T
   return undef : $()
 }
 
@@ -51,14 +51,15 @@
 // CHECK:         unconditional_checked_cast_addr
 sil @function_cast_nothrow_substitutable_to_nothrow : $@convention(thin) <T> () -> () {
 entry:
-  %a = unconditional_checked_cast_addr (T) -> T        in undef : $*(@in T) -> @out T                 to () -> ()        in undef : $*(@in ()) -> @out ()
+  unconditional_checked_cast_addr (T) -> T        in undef : $*(@in T) -> @out T                 to () -> ()        in undef : $*(@in ()) -> @out ()
   return undef : $()
 }
 
 // CHECK-LABEL: sil @function_cast_throw_to_nothrow
 // CHECK:         builtin "int_trap"
 sil @function_cast_throw_to_nothrow : $@convention(thin) <T> () -> () {
-  %b = unconditional_checked_cast_addr () throws -> () in undef : $*(@in ()) -> (@out (), @error Error) to () -> ()        in undef : $*(@in ()) -> @out ()
+entry:
+  unconditional_checked_cast_addr () throws -> () in undef : $*(@in ()) -> (@out (), @error Error) to () -> ()        in undef : $*(@in ()) -> @out ()
   return undef : $()
 }
 
@@ -66,7 +67,8 @@
 // CHECK-LABEL: sil @function_cast_nothrow_to_throw
 // CHECK:         unconditional_checked_cast_addr
 sil @function_cast_nothrow_to_throw : $@convention(thin) <T> () -> () {
-  %c = unconditional_checked_cast_addr () -> ()        in undef : $*(@in ()) -> @out ()                 to () throws -> () in undef : $*(@in ()) -> (@out (), @error Error)
+entry:
+  unconditional_checked_cast_addr () -> ()        in undef : $*(@in ()) -> @out ()                 to () throws -> () in undef : $*(@in ()) -> (@out (), @error Error)
   return undef : $()
 }
 
@@ -74,7 +76,8 @@
 // CHECK:         load
 // CHECK:         store
 sil @function_cast_throw_to_throw : $@convention(thin) <T> () -> () {
-  %d = unconditional_checked_cast_addr () throws -> () in undef : $*(@in ()) -> (@out (), @error Error) to () throws -> () in undef : $*(@in ()) -> (@out (), @error Error)
+entry:
+  unconditional_checked_cast_addr () throws -> () in undef : $*(@in ()) -> (@out (), @error Error) to () throws -> () in undef : $*(@in ()) -> (@out (), @error Error)
   return undef : $()
 }
 
diff --git a/test/SILOptimizer/cse.sil b/test/SILOptimizer/cse.sil
index f101457..d098716 100644
--- a/test/SILOptimizer/cse.sil
+++ b/test/SILOptimizer/cse.sil
@@ -112,17 +112,17 @@
 bb0(%0 : $B):
   %1 = alloc_box $<τ_0_0> { var τ_0_0 } <B>
   %1a = project_box %1 : $<τ_0_0> { var τ_0_0 } <B>, 0
-  %2 = store %0 to %1a : $*B
+  store %0 to %1a : $*B
   %3 = load %1a : $*B
-  %4 = strong_retain %3 : $B
+  strong_retain %3 : $B
   %5 = unchecked_ref_cast %3 : $B to $Builtin.NativeObject
-  %7 = strong_release %3 : $B
-  %8 = strong_release %1 : $<τ_0_0> { var τ_0_0 } <B>
+  strong_release %3 : $B
+  strong_release %1 : $<τ_0_0> { var τ_0_0 } <B>
   %9 = function_ref @exit : $@convention(thin) () -> Never // ret.exit : () -> ()
   %10 = apply %9() : $@convention(thin) () -> Never
   %6 = unchecked_ref_cast %5 : $Builtin.NativeObject to $B
   %11 = tuple()
-  %12 = return %11 : $()
+  return %11 : $()
 }
 
 // CHECK-LABEL: sil @removeTriviallyDeadCrossBasicBlocks
@@ -132,15 +132,15 @@
 sil @removeTriviallyDeadCrossBasicBlocks : $@convention(thin) (@owned B, Builtin.Int1) -> () {
 bb0(%0: $B, %1: $Builtin.Int1):
   %5 = unchecked_ref_cast %0 : $B to $Builtin.NativeObject
-  %13 = cond_br %1, bb1, bb2
+  cond_br %1, bb1, bb2
 bb1:
-  %22 = br bb2
+  br bb2
 bb2:
   %9 = function_ref @exit : $@convention(thin) () -> Never // ret.exit : () -> ()
   %10 = apply %9() : $@convention(thin) () -> Never
   %21 = unchecked_ref_cast %5 : $Builtin.NativeObject to $B
   %32 = tuple ()
-  %33 = return %32 : $()
+  return %32 : $()
 }
 
 // CHECK-LABEL: sil @dead_use_of_alloc_stack
@@ -710,14 +710,14 @@
 bb0(%0: $B, %1: $Builtin.Int1):
   %5 = unchecked_ref_cast %0 : $B to $Builtin.NativeObject
   strong_release %5 : $Builtin.NativeObject
-  %13 = cond_br %1, bb1, bb2
+  cond_br %1, bb1, bb2
 bb1:
-  %22 = br bb2
+  br bb2
 bb2:
   %21 = unchecked_ref_cast %0 : $B to $Builtin.NativeObject
   strong_release %21 : $Builtin.NativeObject
   %32 = tuple ()
-  %33 = return %32 : $()
+  return %32 : $()
 }
 
 // CHECK-LABEL: sil @cse_raw_pointer_to_ref
diff --git a/test/SILOptimizer/dead_store_elim.sil b/test/SILOptimizer/dead_store_elim.sil
index 295d9ea..e4d1436 100644
--- a/test/SILOptimizer/dead_store_elim.sil
+++ b/test/SILOptimizer/dead_store_elim.sil
@@ -240,10 +240,10 @@
 bb0(%0 : $B):
   %1 = alloc_box $<τ_0_0> { var τ_0_0 } <B>
   %1a = project_box %1 : $<τ_0_0> { var τ_0_0 } <B>, 0
-  %2 = store %0 to %1a : $*B
-  %3 = store %0 to %1a : $*B
+  store %0 to %1a : $*B
+  store %0 to %1a : $*B
   %4 = tuple()
-  %5 = return %4 : $()
+  return %4 : $()
 }
 
 // CHECK-LABEL: sil @dead_store_elimination_over_noread_builtins
diff --git a/test/SILOptimizer/definite_init_markuninitialized_var.sil b/test/SILOptimizer/definite_init_markuninitialized_var.sil
index 7306f94..f1eef16 100644
--- a/test/SILOptimizer/definite_init_markuninitialized_var.sil
+++ b/test/SILOptimizer/definite_init_markuninitialized_var.sil
@@ -19,7 +19,7 @@
   %1 = mark_uninitialized [var] %0a : $*Int // expected-note {{variable defined here}}
   %4 = load [trivial] %1 : $*Int                // expected-error {{variable '<unknown>' used before being initialized}}
   destroy_value %0 : $<τ_0_0> { var τ_0_0 } <Int>
-  %9 = return %4 : $Int
+  return %4 : $Int
 }
 
 // CHECK-LABEL: @inout_uninit
@@ -50,7 +50,7 @@
   %91 = alloc_box $<τ_0_0> { var τ_0_0 } <Int>
   %91a = project_box %91 : $<τ_0_0> { var τ_0_0 } <Int>, 0
   %1 = mark_uninitialized [var] %91a : $*Int
-  %2 = store %0 to [trivial] %1 : $*Int
+  store %0 to [trivial] %1 : $*Int
 
   %3 = load [trivial] %1 : $*Int
   %5 = function_ref @takes_Int_inout : $@convention(thin) (@inout Int) -> ()
@@ -58,7 +58,7 @@
   %7 = load [trivial] %1 : $*Int
   %8 = tuple (%3 : $Int, %7 : $Int)
   destroy_value %91 : $<τ_0_0> { var τ_0_0 } <Int>
-  %11 = return %8 : $(Int, Int)
+  return %8 : $(Int, Int)
 }
 
 struct AddressOnlyStruct {
diff --git a/test/SILOptimizer/diagnose_unreachable.sil b/test/SILOptimizer/diagnose_unreachable.sil
index 8bb789d..f857c81 100644
--- a/test/SILOptimizer/diagnose_unreachable.sil
+++ b/test/SILOptimizer/diagnose_unreachable.sil
@@ -6,12 +6,12 @@
 sil private @test1 : $() -> () {
 bb0:
   %5 = integer_literal $Builtin.Int1, 1
-  %7 = cond_br %5, bb1, bb2
+  cond_br %5, bb1, bb2
 bb1:                                              // Preds: bb0
-  %8 = br bb2
+  br bb2
 bb2:                                              // Preds: bb1 bb0
   %9 = tuple ()
-  %10 = return %9 : $()
+  return %9 : $()
 }
 // CHECK-LABEL:@test1
 // CHECK: bb0:
@@ -26,12 +26,12 @@
 sil @test2 : $@convention(thin) () -> () {
 bb0:
   %11 = integer_literal $Builtin.Int1, 0
-  %13 = cond_br %11, bb1, bb2
+  cond_br %11, bb1, bb2
 bb1:                                              // Preds: bb0
-  %22 = br bb2
+  br bb2
 bb2:                                              // Preds: bb1 bb0
   %32 = tuple ()
-  %33 = return %32 : $()
+  return %32 : $()
 }
 // CHECK-LABEL:sil @test2
 // CHECK: bb0:
@@ -49,27 +49,27 @@
 //}
 sil @loopWithFalse : $@convention(thin) () -> () {
 bb0:
-  %6 = br bb1
+  br bb1
 
 bb1:                                              // Preds: bb4 bb0
   %12 = integer_literal $Builtin.Int1, 0
-  %14 = cond_br %12, bb2, bb5
+  cond_br %12, bb2, bb5
 
 bb2:                                              // Preds: bb1
   %20 = integer_literal $Builtin.Int1, 0
-  %22 = cond_br %20, bb3, bb4
+  cond_br %20, bb3, bb4
 
 bb3:                                              // Preds: bb2
   br bb6
 bb4:                                              // Preds: bb2
-  %26 = br bb1
+  br bb1
 
 bb5:                                              // Preds: bb1
   br bb6
 
 bb6:
   %28 = tuple ()
-  %29 = return %28 : $()
+  return %28 : $()
 }
 // CHECK-LABEL: sil @loopWithFalse
 // CHECK: bb0:
@@ -92,28 +92,28 @@
 //}
 sil @InfLoop : $@convention(thin) () -> () {
 bb0:
-  %6 = br bb1
+  br bb1
 
 bb1:                                              // Preds: bb4 bb0
   %12 = integer_literal $Builtin.Int1, 1
-  %14 = cond_br %12, bb2, bb5
+  cond_br %12, bb2, bb5
 
 bb2:                                              // Preds: bb1
   %20 = integer_literal $Builtin.Int1, 0
-  %22 = cond_br %20, bb3, bb4
+  cond_br %20, bb3, bb4
 
 bb3:                                              // Preds: bb2
   br bb6
 
 bb4:                                              // Preds: bb2
-  %26 = br bb1
+  br bb1
 
 bb5:                                              // Preds: bb1
   br bb6
 
 bb6:
   %28 = tuple ()
-  %29 = return %28 : $()
+  return %28 : $()
 }
 // CHECK-LABEL:sil @InfLoop
 // CHECK: bb0:
@@ -139,17 +139,17 @@
 bb0(%0 : $B):
   %1 = alloc_box $<τ_0_0> { var τ_0_0 } <B>
   %1a = project_box %1 : $<τ_0_0> { var τ_0_0 } <B>, 0
-  %2 = store %0 to %1a : $*B                 // CHECK: store
+  store %0 to %1a : $*B                 // CHECK: store
   %3 = load %1a : $*B
-  %4 = strong_retain %3 : $B                         // CHECK: strong_retain
+  strong_retain %3 : $B                         // CHECK: strong_retain
   %5 = unchecked_ref_cast %3 : $B to $Builtin.NativeObject     // CHECK-NOT: unchecked_ref_cast
-  %7 = strong_release %3 : $B                        // CHECK: strong_release
-  %8 = strong_release %1 : $<τ_0_0> { var τ_0_0 } <B>  // CHECK-NEXT: strong_release
+  strong_release %3 : $B                        // CHECK: strong_release
+  strong_release %1 : $<τ_0_0> { var τ_0_0 } <B>  // CHECK-NEXT: strong_release
   %9 = function_ref @exit : $@convention(thin) () -> Never
   %10 = apply %9() : $@convention(thin) () -> Never
   %6 = unchecked_ref_cast %5 : $Builtin.NativeObject to $B // CHECK-NOT: unchecked_ref_cast
   %11 = tuple()
-  %12 = return %11 : $()
+  return %11 : $()
 }
 
 // CHECK-LABEL: sil @removeTriviallyDeadButUsedByUnreachableBlock
@@ -157,28 +157,28 @@
 bb0(%0 : $B):
   %5 = unchecked_ref_cast %0 : $B to $Builtin.NativeObject  // CHECK-NOT: unchecked_ref_cast
   %11 = integer_literal $Builtin.Int1, 0          // CHECK-NOT: integer_literal
-  %13 = cond_br %11, bb1, bb2                  // CHECK: br
+  cond_br %11, bb1, bb2                  // CHECK: br
 bb1:
   %21 = unchecked_ref_cast %5 : $Builtin.NativeObject to $B // CHECK-NOT: unchecked_ref_cast
-  %22 = br bb2
+  br bb2
 bb2:
   %32 = tuple ()
-  %33 = return %32 : $()                          // CHECK: return
+  return %32 : $()                          // CHECK: return
 }                                                 // CHECK: }
 
 // CHECK-LABEL: sil @removeTriviallyDeadCrossBasicBlocks
 sil @removeTriviallyDeadCrossBasicBlocks : $@convention(thin) (@owned B, Builtin.Int1) -> () {
 bb0(%0:  $B, %1: $Builtin.Int1):
   %5 = unchecked_ref_cast %0 : $B to $Builtin.NativeObject     // CHECK-NOT: unchecked_ref_cast
-  %13 = cond_br %1, bb1, bb2                   // CHECK: cond_br
+  cond_br %1, bb1, bb2                   // CHECK: cond_br
 bb1:
-  %22 = br bb2
+  br bb2
 bb2:
   %9 = function_ref @exit : $@convention(thin) () -> Never
   %10 = apply %9() : $@convention(thin) () -> Never
   %21 = unchecked_ref_cast %5 : $Builtin.NativeObject to $B // CHECK-NOT: unchecked_ref_cast
   %32 = tuple ()
-  %33 = return %32 : $()
+  return %32 : $()
 }                                                 // CHECK: }
 
 sil @testCondBranchBBArgs : $@convention(thin) (Int, Int) -> Int {
@@ -204,7 +204,7 @@
 sil @removePredecessorWithBBArgs : $@convention(thin) (Int, Int) -> Int {
 bb0(%0 : $Int, %1 : $Int):
  %2 = integer_literal $Builtin.Int1, 0
- %3 = cond_br %2, bb2(%0 : $Int), bb3(%1 : $Int)
+ cond_br %2, bb2(%0 : $Int), bb3(%1 : $Int)
 bb2(%4 : $Int):
  br bb4(%4 : $Int)
 bb3(%5 : $Int):
diff --git a/test/SILOptimizer/earlycodemotion.sil b/test/SILOptimizer/earlycodemotion.sil
index d5f26ab..2db1ec9 100644
--- a/test/SILOptimizer/earlycodemotion.sil
+++ b/test/SILOptimizer/earlycodemotion.sil
@@ -88,11 +88,11 @@
   cond_br %0, bb1, bb2
 
 bb1:
-  %2 = strong_retain %1 : $B
+  strong_retain %1 : $B
   br bb3
 
 bb2:
-  %3 = strong_retain %1 : $B
+  strong_retain %1 : $B
   br bb3
 
 bb3:
@@ -133,12 +133,12 @@
   cond_br %0, bb1, bb2
 
 bb1:
-  %2 = strong_retain %1 : $B
+  strong_retain %1 : $B
   %3 = integer_literal $Builtin.Int32, 9
   br bb3(%3 : $Builtin.Int32)
 
 bb2:
-  %4 = strong_retain %1 : $B
+  strong_retain %1 : $B
   %5 = integer_literal $Builtin.Int32, 7
   br bb3(%5 : $Builtin.Int32)
 
@@ -160,12 +160,12 @@
   cond_br %0, bb1, bb2
 
 bb1:
-  %2 = strong_retain %1 : $B
+  strong_retain %1 : $B
   %3 = integer_literal $Builtin.Int32, 7
   br bb3(%3 : $Builtin.Int32)
 
 bb2:
-  %4 = strong_retain %1 : $B
+  strong_retain %1 : $B
   %5 = integer_literal $Builtin.Int32, 7
   br bb3(%5 : $Builtin.Int32)
 
diff --git a/test/SILOptimizer/escape_analysis.sil b/test/SILOptimizer/escape_analysis.sil
index 7befabe..a36d9ae 100644
--- a/test/SILOptimizer/escape_analysis.sil
+++ b/test/SILOptimizer/escape_analysis.sil
@@ -376,8 +376,8 @@
   %2 = function_ref @copy_addr_content : $@convention(thin) (@in_guaranteed Int32) -> @out Int32
   %3 = apply %2(%0, %1) : $@convention(thin) (@in_guaranteed Int32) -> @out Int32
   %4 = tuple()
-  %6 = dealloc_stack %1 : $*Int32
-  %5 = dealloc_stack %0 : $*Int32
+  dealloc_stack %1 : $*Int32
+  dealloc_stack %0 : $*Int32
   return %4 : $()
 }
 
@@ -808,7 +808,7 @@
   %f = function_ref @unknown_set_y : $@convention(thin) () -> @out Y
   %a = apply %f(%0) : $@convention(thin) () -> @out Y
   %r = load %0 : $*Y
-  %5 = dealloc_stack %0 : $*Y
+  dealloc_stack %0 : $*Y
   return %r : $Y
 }
 
diff --git a/test/SILOptimizer/latecodemotion.sil b/test/SILOptimizer/latecodemotion.sil
index 5dfb194..1eeff4d 100644
--- a/test/SILOptimizer/latecodemotion.sil
+++ b/test/SILOptimizer/latecodemotion.sil
@@ -65,11 +65,11 @@
   cond_br %0, bb1, bb2
 
 bb1:
-  %2 = strong_retain %1 : $B
+  strong_retain %1 : $B
   br bb3
 
 bb2:
-  %3 = strong_retain %1 : $B
+  strong_retain %1 : $B
   br bb3
 
 bb3:
@@ -90,11 +90,11 @@
   cond_br %0, bb1, bb2
 
 bb1:
-  %r1 = strong_retain %1 : $B
+  strong_retain %1 : $B
   br bb3(%1 : $B)
 
 bb2:
-  %r2 = strong_retain %2 : $B
+  strong_retain %2 : $B
   br bb3(%2 : $B)
 
 bb3(%a1 : $B):
@@ -115,11 +115,11 @@
   cond_br %0, bb1, bb2
 
 bb1:
-  %r1 = strong_retain %1 : $B
+  strong_retain %1 : $B
   br bb3(%1 : $B)
 
 bb2:
-  %r2 = strong_retain %1 : $B
+  strong_retain %1 : $B
   br bb3(%2 : $B)
 
 bb3(%a1 : $B):
@@ -140,11 +140,11 @@
   cond_br %0, bb1, bb2
 
 bb1:
-  %r1 = strong_retain %1 : $B
+  strong_retain %1 : $B
   br bb3(%3 : $B, %1 : $B)
 
 bb2:
-  %r2 = strong_retain %2 : $B
+  strong_retain %2 : $B
   br bb3(%3 : $B, %2 : $B)
 
 bb3(%a1 : $B, %a2 : $B):
@@ -166,11 +166,11 @@
   cond_br %0, bb1, bb2
 
 bb1:
-  %r1 = strong_retain %1 : $B
+  strong_retain %1 : $B
   br bb3(%1 : $B)
 
 bb2:
-  %r2 = strong_retain %2 : $B
+  strong_retain %2 : $B
   br bb3(%3 : $B)
 
 bb3(%a1 : $B):
@@ -192,11 +192,11 @@
   cond_br %0, bb1, bb2
 
 bb1:
-  %r1 = strong_retain %1 : $B
+  strong_retain %1 : $B
   br bb3(%1 : $B, %3 : $B)
 
 bb2:
-  %r2 = strong_retain %2 : $B
+  strong_retain %2 : $B
   br bb3(%3 : $B, %2 : $B)
 
 bb3(%a1 : $B, %a2 : $B):
@@ -224,15 +224,15 @@
   cond_br %0, bb3, bb4
 
 bb2:
-  %r1 = strong_retain %1 : $B
+  strong_retain %1 : $B
   br bb5(%1 : $B)
 
 bb3:
-  %r2 = strong_retain %2 : $B
+  strong_retain %2 : $B
   br bb5(%2 : $B)
 
 bb4:
-  %r3 = strong_retain %1 : $B
+  strong_retain %1 : $B
   br bb5(%2 : $B)
 
 bb5(%a1 : $B):
@@ -260,15 +260,15 @@
   cond_br %0, bb3, bb4
 
 bb2:
-  %r1 = strong_retain %1 : $B
+  strong_retain %1 : $B
   br bb5(%2 : $B)
 
 bb3:
-  %r2 = strong_retain %2 : $B
+  strong_retain %2 : $B
   br bb5(%2 : $B)
 
 bb4:
-  %r3 = strong_retain %1 : $B
+  strong_retain %1 : $B
   br bb5(%1 : $B)
 
 bb5(%a1 : $B):
@@ -309,12 +309,12 @@
   cond_br %0, bb1, bb2
 
 bb1:
-  %2 = strong_retain %1 : $B
+  strong_retain %1 : $B
   %3 = integer_literal $Builtin.Int32, 9
   br bb3(%3 : $Builtin.Int32)
 
 bb2:
-  %4 = strong_retain %1 : $B
+  strong_retain %1 : $B
   %5 = integer_literal $Builtin.Int32, 7
   br bb3(%5 : $Builtin.Int32)
 
@@ -336,12 +336,12 @@
   cond_br %0, bb1, bb2
 
 bb1:
-  %2 = strong_retain %1 : $B
+  strong_retain %1 : $B
   %3 = integer_literal $Builtin.Int32, 7
   br bb3(%3 : $Builtin.Int32)
 
 bb2:
-  %4 = strong_retain %1 : $B
+  strong_retain %1 : $B
   %5 = integer_literal $Builtin.Int32, 7
   br bb3(%5 : $Builtin.Int32)
 
diff --git a/test/SILOptimizer/lslocation_expansion.sil b/test/SILOptimizer/lslocation_expansion.sil
index 0261142..22ed083 100644
--- a/test/SILOptimizer/lslocation_expansion.sil
+++ b/test/SILOptimizer/lslocation_expansion.sil
@@ -82,7 +82,7 @@
   store %9 to %1 : $*Builtin.Int64
   %4 = tuple()
   dealloc_stack %1 : $*Builtin.Int64        // id: %13
-  %5 = return %4 : $()
+  return %4 : $()
 }
 
 // CHECK-LABEL: @store_after_store
@@ -94,10 +94,10 @@
 bb0(%0 : $B):
   %1 = alloc_box $<τ_0_0> { var τ_0_0 } <B>
   %1a = project_box %1 : $<τ_0_0> { var τ_0_0 } <B>, 0
-  %2 = store %0 to %1a : $*B
-  %3 = store %0 to %1a : $*B
+  store %0 to %1a : $*B
+  store %0 to %1a : $*B
   %4 = tuple()
-  %5 = return %4 : $()
+  return %4 : $()
 }
 
 // CHECK-LABEL: @store_after_store_struct
@@ -120,7 +120,7 @@
   store %10 to %11 : $*Int
   %4 = tuple()
   dealloc_stack %1 : $*S1        // id: %13
-  %5 = return %4 : $()
+  return %4 : $()
 }
 
 // Make sure all the structs get expanded correctly.
diff --git a/test/SILOptimizer/lslocation_reduction.sil b/test/SILOptimizer/lslocation_reduction.sil
index 5223030..16a4e0e 100644
--- a/test/SILOptimizer/lslocation_reduction.sil
+++ b/test/SILOptimizer/lslocation_reduction.sil
@@ -82,7 +82,7 @@
   store %9 to %1 : $*Builtin.Int64
   %4 = tuple()
   dealloc_stack %1 : $*Builtin.Int64        // id: %13
-  %5 = return %4 : $()
+  return %4 : $()
 }
 
 // CHECK-LABEL: @store_after_store
@@ -94,10 +94,10 @@
 bb0(%0 : $B):
   %1 = alloc_box $<τ_0_0> { var τ_0_0 } <B>
   %1a = project_box %1 : $<τ_0_0> { var τ_0_0 } <B>, 0
-  %2 = store %0 to %1a : $*B
-  %3 = store %0 to %1a : $*B
+  store %0 to %1a : $*B
+  store %0 to %1a : $*B
   %4 = tuple()
-  %5 = return %4 : $()
+  return %4 : $()
 }
 
 // CHECK-LABEL: @store_after_store_struct
@@ -118,7 +118,7 @@
   store %10 to %11 : $*Int
   %4 = tuple()
   dealloc_stack %1 : $*S1        // id: %13
-  %5 = return %4 : $()
+  return %4 : $()
 }
 
 // Make sure all the structs get expanded correctly.
diff --git a/test/SILOptimizer/mandatory_inlining.sil b/test/SILOptimizer/mandatory_inlining.sil
index 4b5fd9d..72f001c 100644
--- a/test/SILOptimizer/mandatory_inlining.sil
+++ b/test/SILOptimizer/mandatory_inlining.sil
@@ -212,7 +212,7 @@
 bb0(%0 : $*SomeProtocol):
   %1 = function_ref @test_existential_metatype : $@convention(thin) (@in SomeProtocol) -> @thick SomeProtocol.Type
   %2 = apply %1(%0) : $@convention(thin) (@in SomeProtocol) -> @thick SomeProtocol.Type
-  %3 = return %2 : $@thick SomeProtocol.Type
+  return %2 : $@thick SomeProtocol.Type
 }
 
 ////////////////////////
diff --git a/test/SILOptimizer/pgo_si_inlinelarge.swift b/test/SILOptimizer/pgo_si_inlinelarge.swift
new file mode 100644
index 0000000..1efb9cd
--- /dev/null
+++ b/test/SILOptimizer/pgo_si_inlinelarge.swift
@@ -0,0 +1,130 @@
+// RUN: rm -rf %t && mkdir %t
+// RUN: %target-build-swift %s -profile-generate -Xfrontend -disable-incremental-llvm-codegen -module-name pgo_si_inlinelarge -o %t/main
+// RUN: env LLVM_PROFILE_FILE=%t/default.profraw %target-run %t/main
+// RUN: %llvm-profdata merge %t/default.profraw -o %t/default.profdata
+// RUN: %target-swift-frontend %s -profile-use=%t/default.profdata -emit-sorted-sil -emit-sil -module-name pgo_si_inlinelarge -o - | %FileCheck %s --check-prefix=SIL
+// RUN: %target-swift-frontend %s -profile-use=%t/default.profdata -O -emit-sorted-sil -emit-sil -module-name pgo_si_inlinelarge -o - | %FileCheck %s --check-prefix=SIL-OPT
+
+// REQUIRES: profile_runtime
+// REQUIRES: OS=macosx
+
+public func bar(_ x: Int64) -> Int64 {
+  if (x == 0) {
+    return 42
+  }
+  if (x == 1) {
+    return 6
+  }
+  if (x == 2) {
+    return 9
+  }
+  if (x == 3) {
+    return 93
+  }
+  if (x == 4) {
+    return 94
+  }
+  if (x == 5) {
+    return 95
+  }
+  if (x == 6) {
+    return 96
+  }
+  if (x == 7) {
+    return 97
+  }
+  if (x == 8) {
+    return 98
+  }
+  if (x == 9) {
+    return 99
+  }
+  if (x == 10) {
+    return 910
+  }
+  if (x == 11) {
+    return 911
+  }
+  if (x == 11) {
+    return 911
+  }
+  if (x == 11) {
+    return 911
+  }
+  if (x == 12) {
+    return 912
+  }
+  if (x == 13) {
+    return 913
+  }
+  if (x == 14) {
+    return 914
+  }
+  if (x == 15) {
+    return 916
+  }
+  if (x == 17) {
+    return 917
+  }
+  if (x == 18) {
+    return 918
+  }
+  if (x == 19) {
+    return 919
+  }
+  if (x % 2 == 0) {
+    return 4242
+  }
+  var ret : Int64 = 0
+  for currNum in stride(from: 5, to: x, by: 5) {
+    print("in bar stride")
+    ret += currNum
+    print(ret)
+    print("in bar stride")
+    ret += currNum
+    print(ret)
+    print("in bar stride")
+    ret += currNum
+    print(ret)
+    print("in bar stride")
+    ret += currNum
+    print(ret)
+    print("in bar stride")
+    ret += currNum
+    print(ret)
+    print("in bar stride")
+    ret += currNum
+    print(ret)
+    print("in bar stride")
+    ret += currNum
+    print(ret)
+  }
+  return ret
+}
+
+// SIL-LABEL: sil @_T018pgo_si_inlinelarge3fooys5Int64VF : $@convention(thin) (Int64) -> () !function_entry_count(1) {
+// SIL-OPT-LABEL: sil @_T018pgo_si_inlinelarge3fooys5Int64VF : $@convention(thin) (Int64) -> () !function_entry_count(1) {
+public func foo(_ x: Int64) {
+  // SIL: switch_enum {{.*}} : $Optional<Int64>, case #Optional.some!enumelt.1: {{.*}} !case_count(100), case #Optional.none!enumelt: {{.*}} !case_count(1)
+  // SIL: cond_br {{.*}}, {{.*}}, {{.*}} !true_count(50)
+  // SIL: cond_br {{.*}}, {{.*}}, {{.*}} !true_count(1)
+  // SIL-OPT: integer_literal $Builtin.Int64, 93
+  // SIL-OPT: integer_literal $Builtin.Int64, 42
+  // SIL-OPT: function_ref @_T018pgo_si_inlinelarge3bars5Int64VADF : $@convention(thin) (Int64) -> Int64
+
+  var sum : Int64 = 0
+  for index in 1...x {
+    if (index % 2 == 0) {
+      sum += bar(index)
+    }
+    if (index == 50) {
+      sum += bar(index)
+    }
+    sum += 1
+  }
+  print(sum)
+}
+// SIL-LABEL: } // end sil function '_T018pgo_si_inlinelarge3fooys5Int64VF'
+// SIL-OPT-LABEL: } // end sil function '_T018pgo_si_inlinelarge3fooys5Int64VF'
+
+foo(100)
diff --git a/test/SILOptimizer/pgo_si_reduce.swift b/test/SILOptimizer/pgo_si_reduce.swift
new file mode 100644
index 0000000..0982ad0
--- /dev/null
+++ b/test/SILOptimizer/pgo_si_reduce.swift
@@ -0,0 +1,56 @@
+// RUN: rm -rf %t && mkdir %t
+// RUN: %target-build-swift %s -profile-generate -Xfrontend -disable-incremental-llvm-codegen -module-name pgo_si_reduce -o %t/main
+// RUN: env LLVM_PROFILE_FILE=%t/default.profraw %target-run %t/main
+// RUN: %llvm-profdata merge %t/default.profraw -o %t/default.profdata
+// RUN: %target-swift-frontend %s -profile-use=%t/default.profdata -emit-sorted-sil -emit-sil -module-name pgo_si_reduce -o - | %FileCheck %s --check-prefix=SIL
+// RUN: %target-swift-frontend %s -profile-use=%t/default.profdata -O -emit-sorted-sil -emit-sil -module-name pgo_si_reduce -o - | %FileCheck %s --check-prefix=SIL-OPT
+
+// REQUIRES: profile_runtime
+// REQUIRES: OS=macosx
+
+public func bar(_ x: Int32) -> Int32 {
+  if (x == 0) {
+    return 42
+  }
+  if (x == 1) {
+    return 6
+  }
+  if (x == 2) {
+    return 9
+  }
+  if (x % 2 == 0) {
+    return 4242
+  }
+  var ret : Int32 = 0
+  for currNum in stride(from: 5, to: x, by: 5) {
+    ret += currNum
+  }
+  return ret
+}
+
+// SIL-LABEL: sil @_T013pgo_si_reduce3fooys5Int32VF : $@convention(thin) (Int32) -> () !function_entry_count(1) {
+// SIL-OPT-LABEL: sil @_T013pgo_si_reduce3fooys5Int32VF : $@convention(thin) (Int32) -> () !function_entry_count(1) {
+public func foo(_ x: Int32) {
+  // SIL: switch_enum {{.*}} : $Optional<Int32>, case #Optional.some!enumelt.1: {{.*}} !case_count(100), case #Optional.none!enumelt: {{.*}} !case_count(1)
+  // SIL: cond_br {{.*}}, {{.*}}, {{.*}} !true_count(50)
+  // SIL: cond_br {{.*}}, {{.*}}, {{.*}} !true_count(1)
+  // SIL-OPT: integer_literal $Builtin.Int32, 4242
+  // SIL-OPT: integer_literal $Builtin.Int32, 42
+  // SIL-OPT: function_ref @_T013pgo_si_reduce3bars5Int32VADF : $@convention(thin) (Int32) -> Int32
+  
+  var sum : Int32 = 0
+  for index in 1...x {
+    if (index % 2 == 0) {
+      sum += bar(index)
+    }
+    if (index == 50) {
+      sum += bar(index)
+    }
+    sum += 1
+  }
+  print(sum)
+}
+// SIL-LABEL: } // end sil function '_T013pgo_si_reduce3fooys5Int32VF'
+// SIL-OPT-LABEL: } // end sil function '_T013pgo_si_reduce3fooys5Int32VF'
+
+foo(100)
diff --git a/test/SILOptimizer/predictable_memopt.sil b/test/SILOptimizer/predictable_memopt.sil
index 037f07f..f798389 100644
--- a/test/SILOptimizer/predictable_memopt.sil
+++ b/test/SILOptimizer/predictable_memopt.sil
@@ -68,7 +68,7 @@
   // CHECK: %1 = alloc_box $<τ_0_0> { var τ_0_0 } <Int>
   %1 = alloc_box $<τ_0_0> { var τ_0_0 } <Int>
   %1a = project_box %1 : $<τ_0_0> { var τ_0_0 } <Int>, 0
-  %2 = store %0 to %1a : $*Int
+  store %0 to %1a : $*Int
 
   // This load should be eliminated.
   %3 = load %1a : $*Int
@@ -83,7 +83,7 @@
   // CHECK: tuple ({{.*}} : $Int, {{.*}} : $Int)
   %8 = tuple (%3 : $Int, %7 : $Int)
   strong_release %1 : $<τ_0_0> { var τ_0_0 } <Int>
-  %11 = return %8 : $(Int, Int)
+  return %8 : $(Int, Int)
 }
 
 
diff --git a/test/SILOptimizer/redundant_load_elim.sil b/test/SILOptimizer/redundant_load_elim.sil
index 6c2deca..ad61025 100644
--- a/test/SILOptimizer/redundant_load_elim.sil
+++ b/test/SILOptimizer/redundant_load_elim.sil
@@ -306,13 +306,13 @@
 bb0(%0 : $B):
   %1 = alloc_box $<τ_0_0> { var τ_0_0 } <B>
   %1a = project_box %1 : $<τ_0_0> { var τ_0_0 } <B>, 0
-  %2 = store %0 to %1a : $*B
+  store %0 to %1a : $*B
   %3 = load %1a : $*B
   %4 = load %1a : $*B
-  %5 = strong_retain %3 : $B
-  %6 = strong_retain %4 : $B
+  strong_retain %3 : $B
+  strong_retain %4 : $B
   %7 = tuple()
-  %8 = return %7 : $()
+  return %7 : $()
 }
 
 // CHECK-LABEL: sil @eliminate_duplicate_loads_over_noread_builtins
@@ -433,10 +433,10 @@
 bb0(%0 : $*Agg2, %1 : $*Agg1):
   %2 = load %1 : $*Agg1
   %3 = load %0 : $*Agg2
-  %4 = store %2 to %1 : $*Agg1
-  %5 = store %3 to %0 : $*Agg2
+  store %2 to %1 : $*Agg1
+  store %3 to %0 : $*Agg2
   %6 = tuple()
-  %7 = return %6 : $()
+  return %6 : $()
 }
 
 // Check load forwarding across strong_release in case the stored memory does
diff --git a/test/SILOptimizer/redundant_load_elim_with_casts.sil b/test/SILOptimizer/redundant_load_elim_with_casts.sil
index c176381..bb825c9 100644
--- a/test/SILOptimizer/redundant_load_elim_with_casts.sil
+++ b/test/SILOptimizer/redundant_load_elim_with_casts.sil
@@ -75,14 +75,14 @@
   %2 = alloc_box $<τ_0_0> { var τ_0_0 } <B>
   %2a = project_box %2 : $<τ_0_0> { var τ_0_0 } <B>, 0
   %3 = load %1 : $*Agg1
-  %4 = store %3 to %1 : $*Agg1
+  store %3 to %1 : $*Agg1
   %5 = load %2a : $*B
-  %6 = store %3 to %1 : $*Agg1
+  store %3 to %1 : $*Agg1
   %7 = load %2a : $*B
-  %8 = strong_retain %5 : $B   //%7 and %5 should really be one load.
-  %9 = strong_retain %7 : $B
+  strong_retain %5 : $B   //%7 and %5 should really be one load.
+  strong_retain %7 : $B
   %10 = tuple()
-  %11 = return %10 : $()
+  return %10 : $()
 }
 
 // FIXME: When RLE uses TBAA it should remove the second load.
@@ -99,7 +99,7 @@
   store %1 to %5 : $*A2
   %20 = load %2 : $*A
   %30 = tuple(%3 : $A, %20 : $A)
-  %31 = return %30 : $(A, A)
+  return %30 : $(A, A)
 }
 
 // Even with TBAA, RLE should not remove the second load.
@@ -121,7 +121,7 @@
   bind_memory %0 : $Builtin.RawPointer, %4 : $Builtin.Word to $A
   %20 = load %2 : $*A
   %30 = tuple(%3 : $A, %20 : $A)
-  %31 = return %30 : $(A, A)
+  return %30 : $(A, A)
 }
 
 // *NOTE* This does not handle raw pointer since raw pointer is only layout compatible with heap references.
diff --git a/test/SILOptimizer/semantic-arc-opts.sil b/test/SILOptimizer/semantic-arc-opts.sil
index 048a283..3270931 100644
--- a/test/SILOptimizer/semantic-arc-opts.sil
+++ b/test/SILOptimizer/semantic-arc-opts.sil
@@ -70,7 +70,7 @@
   %2 = function_ref @guaranteed_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
   %3 = begin_borrow %1 : $Builtin.NativeObject
   apply %2(%3) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
-  %4 = end_borrow %3 from %1 : $Builtin.NativeObject, $Builtin.NativeObject
+  end_borrow %3 from %1 : $Builtin.NativeObject, $Builtin.NativeObject
   destroy_value %1 : $Builtin.NativeObject
   %9999 = tuple()
   return %9999 : $()
diff --git a/test/SILOptimizer/sil_combine.sil b/test/SILOptimizer/sil_combine.sil
index c97f8b2..ed3e607 100644
--- a/test/SILOptimizer/sil_combine.sil
+++ b/test/SILOptimizer/sil_combine.sil
@@ -146,12 +146,12 @@
 bb0(%0 : $B):
   %1 = alloc_box $<τ_0_0> { var τ_0_0 } <B>
   %1a = project_box %1 : $<τ_0_0> { var τ_0_0 } <B>, 0
-  %2 = store %0 to %1a : $*B
+  store %0 to %1a : $*B
   %3 = load %1a : $*B
-  %4 = strong_retain %3 : $B
+  strong_retain %3 : $B
   %5 = unchecked_ref_cast %3 : $B to $Builtin.NativeObject
-  %7 = strong_release %3 : $B
-  %8 = strong_release %1 : $<τ_0_0> { var τ_0_0 } <B>
+  strong_release %3 : $B
+  strong_release %1 : $<τ_0_0> { var τ_0_0 } <B>
   %9 = function_ref @exit : $@convention(thin) () -> Never // ret.exit : () -> ()
   %10 = apply %9() : $@convention(thin) () -> Never
   unreachable
@@ -165,9 +165,9 @@
 sil @removeTriviallyDeadCrossBasicBlocks : $@convention(thin) (@owned B, Builtin.Int1) -> () {
 bb0(%0: $B, %1: $Builtin.Int1):
   %5 = unchecked_ref_cast %0 : $B to $Builtin.NativeObject
-  %13 = cond_br %1, bb1, bb2
+  cond_br %1, bb1, bb2
 bb1:
-  %22 = br bb2
+  br bb2
 bb2:
   %9 = function_ref @exit : $@convention(thin) () -> Never // ret.exit : () -> ()
   %10 = apply %9() : $@convention(thin) () -> Never
@@ -288,7 +288,7 @@
   %1 = load %0 : $*UInt8
   %2 = integer_literal $Builtin.Int8, 1
   %3 = struct_element_addr %0 : $*UInt8, #UInt8._value
-  %4 = store %2 to %3 : $*Builtin.Int8
+  store %2 to %3 : $*Builtin.Int8
   %5 = struct_extract %1 : $UInt8, #UInt8._value
   return %5 : $Builtin.Int8
 }
@@ -306,7 +306,7 @@
   %1 = load %0 : $*(Builtin.Int8, Builtin.Int8)
   %2 = integer_literal $Builtin.Int8, 1
   %3 = tuple_element_addr %0 : $*(Builtin.Int8, Builtin.Int8), 0
-  %4 = store %2 to %3 : $*Builtin.Int8
+  store %2 to %3 : $*Builtin.Int8
   %5 = tuple_extract %1 : $(Builtin.Int8, Builtin.Int8), 0
   return %5 : $Builtin.Int8
 }
@@ -327,7 +327,7 @@
   %1 = load %0 : $*UInt8
   %2 = integer_literal $Builtin.Int8, 1
   %3 = struct_element_addr %0 : $*UInt8, #UInt8._value
-  %4 = store %2 to %3 : $*Builtin.Int8
+  store %2 to %3 : $*Builtin.Int8
   %5 = struct_extract %1 : $UInt8, #UInt8._value
   %6 = tuple (%1 : $UInt8, %5 : $Builtin.Int8)
   return %6 : $(UInt8, Builtin.Int8)
@@ -349,7 +349,7 @@
   %1 = load %0 : $*(Builtin.Int8, Builtin.Int8)
   %2 = integer_literal $Builtin.Int8, 1
   %3 = tuple_element_addr %0 : $*(Builtin.Int8, Builtin.Int8), 0
-  %4 = store %2 to %3 : $*Builtin.Int8
+  store %2 to %3 : $*Builtin.Int8
   %5 = tuple_extract %1 : $(Builtin.Int8, Builtin.Int8), 0
   %6 = tuple (%1 : $(Builtin.Int8, Builtin.Int8), %5 : $Builtin.Int8)
   return %6 : $((Builtin.Int8, Builtin.Int8), Builtin.Int8)
@@ -1228,7 +1228,7 @@
 // CHECK-NEXT: return
 sil @unchecked_take_enum_data_addr_promotion : $@convention(thin) (@inout FakeOptional<B>) -> B {
 bb0(%0 : $*FakeOptional<B>):
-  %1 = switch_enum_addr %0 : $*FakeOptional<B>, case #FakeOptional.some!enumelt.1: bb1, case #FakeOptional.none!enumelt: bb2
+  switch_enum_addr %0 : $*FakeOptional<B>, case #FakeOptional.some!enumelt.1: bb1, case #FakeOptional.none!enumelt: bb2
 
 bb1:
   %2 = unchecked_take_enum_data_addr %0 : $*FakeOptional<B>, #FakeOptional.some!enumelt.1
@@ -2723,8 +2723,8 @@
 bb0(%0 : $*B, %1 : $B, %2 : $Builtin.Int1):
   %3 = function_ref @weird_function : $@convention(thin) (@inout E, E, Builtin.Int1) -> ()
   %4 = convert_function %3 : $@convention(thin) (@inout E, E, Builtin.Int1) -> () to $@convention(thin) (@inout B, B, Builtin.Int1) -> ()
-  %5 = retain_value %4: $@convention(thin) (@inout B, B, Builtin.Int1) -> ()
-  %6 = release_value %4: $@convention(thin) (@inout B, B, Builtin.Int1) -> ()
+  retain_value %4: $@convention(thin) (@inout B, B, Builtin.Int1) -> ()
+  release_value %4: $@convention(thin) (@inout B, B, Builtin.Int1) -> ()
   %7 = tuple()
   return %7 : $()
 }
diff --git a/test/SILOptimizer/sil_combine_enum_addr.sil b/test/SILOptimizer/sil_combine_enum_addr.sil
index 50bea8c..828da98 100644
--- a/test/SILOptimizer/sil_combine_enum_addr.sil
+++ b/test/SILOptimizer/sil_combine_enum_addr.sil
@@ -59,7 +59,7 @@
   unconditional_checked_cast_addr Int in %5 : $*Int to CustomStringConvertible in %4 : $*CustomStringConvertible
   inject_enum_addr %3 : $*Optional<CustomStringConvertible>, #Optional.some!enumelt.1
   dealloc_stack %5 : $*Int
-  %13 = switch_enum_addr %3 : $*Optional<CustomStringConvertible>, case #Optional.some!enumelt.1: bb3, case #Optional.none!enumelt: bb2
+  switch_enum_addr %3 : $*Optional<CustomStringConvertible>, case #Optional.some!enumelt.1: bb3, case #Optional.none!enumelt: bb2
 
 bb1:
   %15 = tuple ()
diff --git a/test/SILOptimizer/sil_combine_enums.sil b/test/SILOptimizer/sil_combine_enums.sil
index 82e660e..c6f6129 100644
--- a/test/SILOptimizer/sil_combine_enums.sil
+++ b/test/SILOptimizer/sil_combine_enums.sil
@@ -30,9 +30,9 @@
   store %1 to %2 : $*SomeClass                    // id: %3
   inject_enum_addr %0 : $*Optional<SomeClass>, #Optional.some!enumelt.1 // id: %4
   %5 = load %0 : $*Optional<SomeClass>          // users: %6, %8, %9, %14
-  %6 = retain_value %5 : $Optional<SomeClass>
+  retain_value %5 : $Optional<SomeClass>
   %7 = alloc_stack $Optional<SomeClass>           // users: %9, %10, %11, %13
-  %8 = retain_value %5 : $Optional<SomeClass>
+  retain_value %5 : $Optional<SomeClass>
   store %5 to %7 : $*Optional<SomeClass>        // id: %9
   switch_enum_addr %7 : $*Optional<SomeClass>, case #Optional.some!enumelt.1: bb1, case #Optional.none!enumelt: bb2 // id: %10
 
@@ -65,9 +65,9 @@
   store %1 to %2 : $*SomeClass
   inject_enum_addr %0 : $*Optional<SomeClass>, #Optional.some!enumelt.1
   %5 = load %0 : $*Optional<SomeClass>
-  %6 = retain_value %5 : $Optional<SomeClass>
+  retain_value %5 : $Optional<SomeClass>
   %7 = alloc_stack $Optional<SomeClass>
-  %8 = retain_value %5 : $Optional<SomeClass>
+  retain_value %5 : $Optional<SomeClass>
   store %5 to %7 : $*Optional<SomeClass>
   %t = integer_literal $Builtin.Int1, -1
   %f = integer_literal $Builtin.Int1, 0
diff --git a/test/SILOptimizer/sil_combine_opaque.sil b/test/SILOptimizer/sil_combine_opaque.sil
index e99bbf9..549fbed 100644
--- a/test/SILOptimizer/sil_combine_opaque.sil
+++ b/test/SILOptimizer/sil_combine_opaque.sil
@@ -16,10 +16,10 @@
 // CHECK-LABEL: } // end sil function 'testSpecializeOpaque'
 sil @testSpecializeOpaque : $@convention(thin) <T> (@in S<T>) -> () {
 bb0(%0 : $S<T>):
-  %retain = retain_value %0 : $S<T>
+  retain_value %0 : $S<T>
   %f = function_ref @testSpecializeOpaque : $@convention(thin) <T> (@in S<T>) -> ()
   %call = apply %f<T>(%0) : $@convention(thin) <τ_0_0> (@in S<τ_0_0>) -> ()
-  %release = release_value %0 : $S<T>
+  release_value %0 : $S<T>
   %999 = tuple ()
   return %999 : $()
 }
diff --git a/test/SILOptimizer/simplify_cfg.sil b/test/SILOptimizer/simplify_cfg.sil
index c9f1e41..3793559 100644
--- a/test/SILOptimizer/simplify_cfg.sil
+++ b/test/SILOptimizer/simplify_cfg.sil
@@ -2830,7 +2830,7 @@
   br bb6(%15 : $Builtin.Int8)
 
 bb4:
-  %60 = debug_value %0 : $TestEnum
+  debug_value %0 : $TestEnum
   %22 = alloc_existential_box $Error, $MyError2
   %23 = project_existential_box $MyError2 in %22 : $Error
   switch_enum %0 : $TestEnum, case #TestEnum.none!enumelt: bbnone, case #TestEnum.int64!enumelt.1: bb7, case #TestEnum.string!enumelt.1: bb10
diff --git a/test/SILOptimizer/unsafe_guaranteed_peephole.sil b/test/SILOptimizer/unsafe_guaranteed_peephole.sil
index a60b5fc..97c35cd 100644
--- a/test/SILOptimizer/unsafe_guaranteed_peephole.sil
+++ b/test/SILOptimizer/unsafe_guaranteed_peephole.sil
@@ -530,7 +530,7 @@
   %5 = tuple_extract %4 : $(Foo, Builtin.Int8), 0
   %6 = tuple_extract %4 : $(Foo, Builtin.Int8), 1
   %7 = function_ref @beep_or_throw : $@convention(thin) () -> @error Error
-  %8 = try_apply %7() : $@convention(thin) () -> @error Error, normal bb1, error bb2
+  try_apply %7() : $@convention(thin) () -> @error Error, normal bb1, error bb2
 
 bb1(%15: $()):
   strong_release %5 : $Foo
diff --git a/test/Sema/diag_type_conversion.swift b/test/Sema/diag_type_conversion.swift
index 3aa3917..9488f4b 100644
--- a/test/Sema/diag_type_conversion.swift
+++ b/test/Sema/diag_type_conversion.swift
@@ -66,3 +66,7 @@
 var p: UnsafeMutablePointer<C>? = nil
 
 _ = p =*= &o
+
+
+func rdar25963182(_ bytes: [UInt8] = nil) {}
+// expected-error@-1 {{nil default argument value cannot be converted to type}}
diff --git a/test/Sema/immutability.swift b/test/Sema/immutability.swift
index 4d2ba53..845fbfe 100644
--- a/test/Sema/immutability.swift
+++ b/test/Sema/immutability.swift
@@ -628,8 +628,7 @@
     return f(x)
   }
 
-  // expected-error@+1 {{expression type '(inout MutableSubscripts) -> ()' is ambiguous without more context}}
-  let closure = { val in val.x = 7 } as (inout MutableSubscripts) -> ()
+  let closure = { val in val.x = 7 } as (inout MutableSubscripts) -> () // Ok
   var v = MutableSubscripts()
   closure(&v)
   // FIXME: This diagnostic isn't really all that much better
diff --git a/test/Serialization/Inputs/def_basic.sil b/test/Serialization/Inputs/def_basic.sil
index 6c4bc1b..4bd889a 100644
--- a/test/Serialization/Inputs/def_basic.sil
+++ b/test/Serialization/Inputs/def_basic.sil
@@ -101,7 +101,7 @@
   %0 = integer_literal $Builtin.Word, 42
   // CHECK: integer_literal $Builtin.Word, 42
   %9 = tuple $(Builtin.Word, Builtin.Word) (%0, %0)
-  %10 = return %9 : $(Builtin.Word, Builtin.Word)
+  return %9 : $(Builtin.Word, Builtin.Word)
 }
 
 sil [serialized] @return_int : $@convention(thin) (Int) -> Int { // CHECK-LABEL: $@convention(thin) (Int) -> Int {
@@ -146,7 +146,7 @@
   // CHECK: apply
   %4 = apply %1(%3, %2) : $@convention(thin) (Builtin.Word, @thin Int.Type) -> Int
   // CHECK: return
-  %5 = return %4 : $Int
+  return %4 : $Int
 }
 
 sil [serialized] @_T0Si25convertFromIntegerLiteralSiBi64_3val_tcSimF : $@convention(thin) (Builtin.Word, @thin Int.Type) -> Int
@@ -177,8 +177,8 @@
   // CHECK: apply
   %3 = apply %2<@opened("01234567-89ab-cdef-0123-000000000000") P>(%1) : $@convention(witness_method) <T: P> (@inout T) -> ()
   %4 = tuple ()                       // CHECK: tuple ()
-  %5 = destroy_addr %0 : $*P          // CHECK: destroy_addr %0 : $*P
-  %6 = return %4 : $()                // CHECK: return
+  destroy_addr %0 : $*P          // CHECK: destroy_addr %0 : $*P
+  return %4 : $()                // CHECK: return
 }
 
 
@@ -214,7 +214,7 @@
   // CHECK: unconditional_checked_cast {{.*}} : $C to $D
   %5 = unconditional_checked_cast %C : $C to $D
   %6 = tuple ()
-  %7 = return %6 : $()
+  return %6 : $()
 }
 
 // Generated from:
@@ -238,14 +238,14 @@
   //%3 = alloc_stack $@thick T.U.Type
   //%4 = witness_method $*T, #Runcible.associated_method!1 : $@cc(method) (@inout T) -> @thick T.U.Type
   //%5 = apply %4(%0) : $@cc(method) ((), @inout T) -> @thick T.U.Type
-  //%6 = store %5 to %3#1 : $*@thick T.U.Type
+  //store %5 to %3#1 : $*@thick T.U.Type
   //%7 = metatype $@thick T.Type
   //%8 = witness_method [volatile] $*T, #Runcible.static_method!1 : $(@thick T.Type) -> ()
   //%9 = apply %8(%7) : $((), @thick T.Type) -> ()
-  //%10 = dealloc_stack %3#0 : $*@thick T.U.Type
+  //dealloc_stack %3#0 : $*@thick T.U.Type
   //%11 = tuple ()
-  //%12 = destroy_addr %0 : $*T
-  //%13 = return %11 : $()
+  //destroy_addr %0 : $*T
+  //return %11 : $()
 //}
 
 protocol Bendable { }
@@ -257,19 +257,19 @@
   %2 = alloc_box $<τ_0_0> { var τ_0_0 } <(Bendable & Runcible)>
   %2a = project_box %2 : $<τ_0_0> { var τ_0_0 } <Bendable & Runcible>, 0
   // CHECK: copy_addr [take] {{.*}} to [initialization] {{.*}} : $*Bendable & Runcible
-  %3 = copy_addr [take] %1 to [initialization] %2a : $*Bendable & Runcible
+  copy_addr [take] %1 to [initialization] %2a : $*Bendable & Runcible
   // CHECK: alloc_stack
   %4 = alloc_stack $Bendable & Runcible
   // CHECK: copy_addr {{.*}} to [initialization] {{.*}} : $*Bendable & Runcible
-  %5 = copy_addr %2a to [initialization] %4 : $*Bendable & Runcible
+  copy_addr %2a to [initialization] %4 : $*Bendable & Runcible
   %7 = tuple ()
   // CHECK: destroy_addr
-  %8 = destroy_addr %4 : $*Bendable & Runcible
+  destroy_addr %4 : $*Bendable & Runcible
   // CHECK: dealloc_stack
-  %9 = dealloc_stack %4 : $*Bendable & Runcible
-  %10 = strong_release %2 : $<τ_0_0> { var τ_0_0 } <Bendable & Runcible>
+  dealloc_stack %4 : $*Bendable & Runcible
+  strong_release %2 : $<τ_0_0> { var τ_0_0 } <Bendable & Runcible>
   // CHECK: return
-  %11 = return %7 : $()
+  return %7 : $()
 }
 
 protocol ClassBound : class {
@@ -281,17 +281,17 @@
 bb0(%0 : $ClassBound):
   %1 = alloc_box $<τ_0_0> { var τ_0_0 } <ClassBound>
   %1a = project_box %1 : $<τ_0_0> { var τ_0_0 } <ClassBound>, 0
-  %2 = store %0 to %1a : $*ClassBound
+  store %0 to %1a : $*ClassBound
   %3 = load %1a : $*ClassBound
-  %4 = strong_retain %3 : $ClassBound              // CHECK: strong_retain
+  strong_retain %3 : $ClassBound              // CHECK: strong_retain
   // CHECK: open_existential_ref {{%.*}} : $ClassBound to $@opened({{.*}}) ClassBound
   %5 = open_existential_ref %3 : $ClassBound to $@opened("01234567-89ab-cdef-0123-111111111111") ClassBound
   // CHECK: witness_method
   %6 = witness_method $@opened("01234567-89ab-cdef-0123-111111111111") ClassBound, #ClassBound.classBoundMethod!1, %5 : $@opened("01234567-89ab-cdef-0123-111111111111") ClassBound : $@convention(witness_method) <T: ClassBound> (T) -> ()
   %7 = apply %6<@opened("01234567-89ab-cdef-0123-111111111111") ClassBound>(%5) : $@convention(witness_method) <T: ClassBound> (T) -> ()
   %8 = tuple ()
-  %9 = strong_release %1 : $<τ_0_0> { var τ_0_0 } <ClassBound>
-  %10 = return %8 : $()
+  strong_release %1 : $<τ_0_0> { var τ_0_0 } <ClassBound>
+  return %8 : $()
 }
 
 struct Val {
@@ -301,7 +301,7 @@
 //bb0(%0 : $@thin Val.Type):
   //%1 = alloc_stack $Val
   //%3 = load %1#1 : $*Val
-  //%4 = return %3 : $Val
+  //return %3 : $Val
 //}
 
 class Ref {
@@ -316,7 +316,7 @@
 bb0(%0 : $Ref, %1 : $Val, %2 : $@thin Aleph.Type):
   // CHECK: struct $Aleph ({{%.*}} : $Ref, {{%.*}} : $Val)
   %3 = struct $Aleph (%0 : $Ref, %1 : $Val)
-  %4 = return %3 : $Aleph  // CHECK: return
+  return %3 : $Aleph  // CHECK: return
 }
 
 // CHECK-LABEL: @_T06struct5AlephVACycACmcfC : $@convention(thin) (@thin Aleph.Type) -> Aleph
@@ -328,13 +328,13 @@
   // CHECK: struct_element_addr {{.*}} : $*Aleph, #Aleph.a
   %5 = struct_element_addr %2a : $*Aleph, #Aleph.a
   %6 = load %5 : $*Ref
-  %8 = strong_release %6 : $Ref
+  strong_release %6 : $Ref
   %14 = load %2a : $*Aleph
   // CHECK: struct_extract {{%.*}} : $Aleph, #Aleph.a
   %15 = struct_extract %14 : $Aleph, #Aleph.a
-  %16 = strong_retain %15 : $Ref
-  %17 = strong_release %2 : $<τ_0_0> { var τ_0_0 } <Aleph>
-  %18 = return %14 : $Aleph
+  strong_retain %15 : $Ref
+  strong_release %2 : $<τ_0_0> { var τ_0_0 } <Aleph>
+  return %14 : $Aleph
 }
 
 enum Beth {
@@ -394,7 +394,7 @@
   %2 = alloc_box $<τ_0_0> { var τ_0_0 } <(Int, Float32)>
   %2a = project_box %2 : $<τ_0_0> { var τ_0_0 } <(Int, Float32)>, 0
   %3 = tuple (%0 : $Int, %1 : $Float32)
-  %4 = store %3 to %2a : $*(Int, Float32)
+  store %3 to %2a : $*(Int, Float32)
   // CHECK: tuple_element_addr {{%.*}} : $*(Int, Float), 0
   %6 = tuple_element_addr %2a : $*(Int, Float), 0
   %7 = load %6 : $*Int
@@ -412,8 +412,8 @@
   // CHECK: apply
   %24 = apply %19(%17) : $@convention(thin) (Float32) -> ()
   %25 = tuple ()
-  %26 = strong_release %2 : $<τ_0_0> { var τ_0_0 } <(Int, Float32)>
-  %27 = return %25 : $()
+  strong_release %2 : $<τ_0_0> { var τ_0_0 } <(Int, Float32)>
+  return %25 : $()
 }
 
 class M {
@@ -426,21 +426,21 @@
 bb0(%0 : $Int, %1 : $M):
   %2 = alloc_box $<τ_0_0> { var τ_0_0 } <Int>
   %2a = project_box %2 : $<τ_0_0> { var τ_0_0 } <Int>, 0
-  %3 = store %0 to %2a : $*Int
+  store %0 to %2a : $*Int
   %4 = alloc_box $<τ_0_0> { var τ_0_0 } <M>
   %4a = project_box %4 : $<τ_0_0> { var τ_0_0 } <M>, 0
-  %5 = store %1 to %4a : $*M
+  store %1 to %4a : $*M
   %6 = load %2a : $*Int
   %7 = load %4a : $*M
-  %8 = strong_retain %7 : $M
+  strong_retain %7 : $M
   // CHECK: ref_element_addr {{%.*}} : $M, #M.member
   %9 = ref_element_addr %7 : $M, #M.member
-  %10 = store %6 to %9 : $*Int
-  %11 = strong_release %7 : $M
+  store %6 to %9 : $*Int
+  strong_release %7 : $M
   %12 = tuple ()
-  %13 = strong_release %4 : $<τ_0_0> { var τ_0_0 } <M>
-  %14 = strong_release %2 : $<τ_0_0> { var τ_0_0 } <Int>
-  %15 = return %12 : $()
+  strong_release %4 : $<τ_0_0> { var τ_0_0 } <M>
+  strong_release %2 : $<τ_0_0> { var τ_0_0 } <Int>
+  return %12 : $()
 }
 
 class B { }
@@ -451,9 +451,9 @@
 bb0(%0 : $B):
   %1 = alloc_box $<τ_0_0> { var τ_0_0 } <B>
   %1a = project_box %1 : $<τ_0_0> { var τ_0_0 } <B>, 0
-  %2 = store %0 to %1a : $*B
+  store %0 to %1a : $*B
   %3 = load %1a : $*B
-  %4 = strong_retain %3 : $B
+  strong_retain %3 : $B
   checked_cast_br %3 : $B to $E, yes, no     // CHECK: checked_cast_br
 yes(%5 : $E):
   %y = integer_literal $Builtin.Int1, 1
@@ -462,9 +462,9 @@
   %n = integer_literal $Builtin.Int1, 0
   br isa(%n : $Builtin.Int1)
 isa(%6 : $Builtin.Int1):
-  %7 = strong_release %3 : $B
-  %8 = strong_release %1 : $<τ_0_0> { var τ_0_0 } <B>
-  %9 = return %6 : $Builtin.Int1
+  strong_release %3 : $B
+  strong_release %1 : $<τ_0_0> { var τ_0_0 } <B>
+  return %6 : $Builtin.Int1
 }
 
 sil [serialized] @_T07literal8literalsyyF : $@convention(thin) () -> ()
@@ -479,15 +479,15 @@
   %2a = project_box %2 : $<τ_0_0> { var τ_0_0 } <Builtin.RawPointer>, 0
   %3 = alloc_box $<τ_0_0> { var τ_0_0 } <Builtin.Word>
   %3a = project_box %3 : $<τ_0_0> { var τ_0_0 } <Builtin.Word>, 0
-  %4 = store %0 to %2a : $*Builtin.RawPointer
-  %5 = store %1 to %3a : $*Builtin.Word
+  store %0 to %2a : $*Builtin.RawPointer
+  store %1 to %3a : $*Builtin.Word
   %7 = load %2a : $*Builtin.RawPointer
   %8 = load %3a : $*Builtin.Word
   // CHECK: index_raw_pointer {{%.*}} : $Builtin.RawPointer, {{%.*}} : $Builtin.Word
   %9 = index_raw_pointer %7 : $Builtin.RawPointer, %8 : $Builtin.Word
-  %10 = strong_release %3 : $<τ_0_0> { var τ_0_0 } <Builtin.Word>
-  %11 = strong_release %2 : $<τ_0_0> { var τ_0_0 } <Builtin.RawPointer>
-  %12 = return %9 : $Builtin.RawPointer
+  strong_release %3 : $<τ_0_0> { var τ_0_0 } <Builtin.Word>
+  strong_release %2 : $<τ_0_0> { var τ_0_0 } <Builtin.RawPointer>
+  return %9 : $Builtin.RawPointer
 }
 
 sil_global @x : $Int
@@ -502,9 +502,9 @@
   %2 = metatype $@thin Int.Type
   %3 = integer_literal $Builtin.Int128, 0 // CHECK: integer_literal $Builtin.Int128, 0
   %4 = apply %1(%3, %2) : $@convention(thin) (Builtin.Int128, @thin Int.Type) -> Int
-  %5 = store %4 to %0 : $*Int
+  store %4 to %0 : $*Int
   %6 = tuple ()
-  %7 = return %6 : $()
+  return %6 : $()
 }
 
 class GlobalObject { }
@@ -534,26 +534,26 @@
   %2a = project_box %2 : $<τ_0_0> { var τ_0_0 } <SomeClass>, 0
   %3 = alloc_box $<τ_0_0> { var τ_0_0 } <SomeSubclass>
   %3a = project_box %3 : $<τ_0_0> { var τ_0_0 } <SomeSubclass>, 0
-  %4 = store %0 to %2a : $*SomeClass
-  %5 = store %1 to %3a : $*SomeSubclass
+  store %0 to %2a : $*SomeClass
+  store %1 to %3a : $*SomeSubclass
   %7 = load %2a : $*SomeClass
   // CHECK: strong_retain %{{.*}} : $SomeClass
-  %8 = strong_retain %7 : $SomeClass
+  strong_retain %7 : $SomeClass
   // CHECK: value_metatype $@thick SomeClass.Type, {{%.*}} : $SomeClass
   %9 = value_metatype $@thick SomeClass.Type, %7 : $SomeClass
   %11 = load %3a : $*SomeSubclass
-  %12 = strong_retain %11 : $SomeSubclass
+  strong_retain %11 : $SomeSubclass
   // CHECK: value_metatype $@thick SomeSubclass.Type, {{%.*}} : $SomeSubclass
   %13 = value_metatype $@thick SomeSubclass.Type, %11 : $SomeSubclass
   // CHECK: upcast %{{.*}} : $@thick SomeSubclass.Type to $@thick SomeClass.Type
   %14 = upcast %13 : $@thick SomeSubclass.Type to $@thick SomeClass.Type
   // CHECK: tuple (%{{.*}} : $@thick SomeClass.Type, %{{.*}} : $@thick SomeClass.Type)
   %15 = tuple (%9 : $@thick SomeClass.Type, %14 : $@thick SomeClass.Type)
-  %16 = strong_release %11 : $SomeSubclass
-  %17 = strong_release %7 : $SomeClass
-  %18 = strong_release %3 : $<τ_0_0> { var τ_0_0 } <SomeSubclass>
-  %19 = strong_release %2 : $<τ_0_0> { var τ_0_0 } <SomeClass>
-  %20 = return %15 : $(@thick SomeClass.Type, @thick SomeClass.Type)
+  strong_release %11 : $SomeSubclass
+  strong_release %7 : $SomeClass
+  strong_release %3 : $<τ_0_0> { var τ_0_0 } <SomeSubclass>
+  strong_release %2 : $<τ_0_0> { var τ_0_0 } <SomeClass>
+  return %15 : $(@thick SomeClass.Type, @thick SomeClass.Type)
 }
 
 // CHECK-LABEL: @test_existential_metatype : $@convention(thin) (@in SomeProtocol) -> @thick SomeProtocol.Type {
@@ -562,17 +562,17 @@
   %1 = alloc_box $<τ_0_0> { var τ_0_0 } <SomeProtocol>
   %1a = project_box %1 : $<τ_0_0> { var τ_0_0 } <SomeProtocol>, 0
   // CHECK: copy_addr [take] %0 to [initialization] %{{.*}} : $*SomeProtocol
-  %2 = copy_addr [take] %0 to [initialization] %1a : $*SomeProtocol
+  copy_addr [take] %0 to [initialization] %1a : $*SomeProtocol
   // CHECK: alloc_stack
   %4 = alloc_stack $SomeProtocol
   // CHECK: copy_addr %{{.*}} to [initialization] %{{.*}} : $*SomeProtocol
-  %5 = copy_addr %1a to [initialization] %4 : $*SomeProtocol
+  copy_addr %1a to [initialization] %4 : $*SomeProtocol
   // CHECK: existential_metatype $@thick SomeProtocol.Type, {{%.*}} : $*SomeProtocol
   %6 = existential_metatype $@thick SomeProtocol.Type, %4 : $*SomeProtocol
-  %7 = destroy_addr %4 : $*SomeProtocol
-  %8 = dealloc_stack %4 : $*SomeProtocol
-  %9 = strong_release %1 : $<τ_0_0> { var τ_0_0 } <SomeProtocol>
-  %10 = return %6 : $@thick SomeProtocol.Type
+  destroy_addr %4 : $*SomeProtocol
+  dealloc_stack %4 : $*SomeProtocol
+  strong_release %1 : $<τ_0_0> { var τ_0_0 } <SomeProtocol>
+  return %6 : $@thick SomeProtocol.Type
 }
 
 // CHECK-LABEL: sil public_external [serialized] @test_unreachable
@@ -587,14 +587,14 @@
 bb0(%0 : $SomeClass):
   %1 = ref_to_unowned %0 : $SomeClass to $@sil_unowned SomeClass
   // CHECK: ref_to_unowned %0 : $SomeClass to $@sil_unowned SomeClass
-  %2 = unowned_retain %1 : $@sil_unowned SomeClass
+  unowned_retain %1 : $@sil_unowned SomeClass
   // CHECK: unowned_retain %1 : $@sil_unowned SomeClass
-  %3 = unowned_release %1 : $@sil_unowned SomeClass
+  unowned_release %1 : $@sil_unowned SomeClass
   // CHECK: unowned_release %1 : $@sil_unowned SomeClass
   %4 = unowned_to_ref %1 : $@sil_unowned SomeClass to $SomeClass
   // CHECK: unowned_to_ref %1 : $@sil_unowned SomeClass to $SomeClass
   %5 = tuple ()
-  %6 = return %5 : $()
+  return %5 : $()
 }
 
 // CHECK-LABEL: sil public_external [serialized] @test_basic_block_arguments
@@ -883,14 +883,14 @@
   %0 = function_ref @classes : $@convention(thin) () -> ()
   %1 = apply %0() : $@convention(thin) () -> ()
   %2 = tuple ()
-  %3 = return %2 : $()
+  return %2 : $()
 }
 
 // CHECK-LABEL: sil public_external [serialized] [thunk] @test_thunk : $@convention(thin) () -> () {
 sil [serialized] [thunk] @test_thunk : $@convention(thin) () -> () {
 bb0:
   %0 = tuple ()
-  %1 = return %0 : $()
+  return %0 : $()
 }
 
 // CHECK-LABEL: [noinline] @noinline_callee
@@ -917,7 +917,7 @@
 sil [serialized] [_semantics "foo"] @test_semantics : $@convention(thin) () -> () {
 bb0:
   %2 = tuple ()
-  %3 = return %2 : $()
+  return %2 : $()
 }
 
 sil [serialized] @takes_unnamed_closure : $@convention(thin) (@callee_owned () -> Int) -> @callee_owned () -> @callee_owned () -> Int
@@ -930,7 +930,7 @@
   %1 = function_ref @takes_int64_float32 : $@convention(thin) (Int, Float) -> ()
   // CHECK: partial_apply %{{.*}}(%{{.*}}) : $@convention(thin) (Int, Float) -> ()
   %2 = partial_apply %1(%0) : $@convention(thin) (Int, Float) -> ()
-  %3 = return %2 : $@callee_owned Int -> ()
+  return %2 : $@callee_owned Int -> ()
 }
 
 class X {
diff --git a/test/SwiftSyntax/LazyCaching.swift b/test/SwiftSyntax/LazyCaching.swift
index a3e50c0..1970935 100644
--- a/test/SwiftSyntax/LazyCaching.swift
+++ b/test/SwiftSyntax/LazyCaching.swift
@@ -1,7 +1,6 @@
 // RUN: %target-run-simple-swift
 // REQUIRES: executable_test
 // REQUIRES: OS=macosx
-// REQUIRES: rdar33888321
 
 import StdlibUnittest
 import Foundation
diff --git a/test/SwiftSyntax/ParseFile.swift b/test/SwiftSyntax/ParseFile.swift
index 23d7d37..8d9a2b9 100644
--- a/test/SwiftSyntax/ParseFile.swift
+++ b/test/SwiftSyntax/ParseFile.swift
@@ -1,7 +1,6 @@
 // RUN: %target-run-simple-swift
 // REQUIRES: executable_test
 // REQUIRES: OS=macosx
-// REQUIRES: rdar33888321
 
 import Foundation
 import StdlibUnittest
diff --git a/test/SwiftSyntax/SyntaxFactory.swift b/test/SwiftSyntax/SyntaxFactory.swift
index 59d0cd5..6686c57 100644
--- a/test/SwiftSyntax/SyntaxFactory.swift
+++ b/test/SwiftSyntax/SyntaxFactory.swift
@@ -1,7 +1,6 @@
 // RUN: %target-run-simple-swift
 // REQUIRES: executable_test
 // REQUIRES: OS=macosx
-// REQUIRES: rdar33888321
 
 import Foundation
 import StdlibUnittest
diff --git a/test/decl/protocol/req/recursion.swift b/test/decl/protocol/req/recursion.swift
index 4c8bd90..20bf860 100644
--- a/test/decl/protocol/req/recursion.swift
+++ b/test/decl/protocol/req/recursion.swift
@@ -97,12 +97,7 @@
 struct S4<A: PI> : I where A : I {
 }
 
-struct S5<A: PI> : I where A : I, A.T == S4<A> {
-// expected-warning@-1{{redundant conformance constraint 'A': 'I'}}
-// expected-warning@-2{{redundant conformance constraint 'A': 'PI'}}
-// expected-note@-3{{conformance constraint 'A': 'PI' inferred from type here}}
-// expected-note@-4{{conformance constraint 'A': 'I' inferred from type here}}
-}
+struct S5<A: PI> : I where A : I, A.T == S4<A> { }
 
 // Used to hit ArchetypeBuilder assertions
 struct SU<A: P> where A.T == SU {
diff --git a/test/sil-func-extractor/basic.sil b/test/sil-func-extractor/basic.sil
index 3f6f167..f4aaf96 100644
--- a/test/sil-func-extractor/basic.sil
+++ b/test/sil-func-extractor/basic.sil
@@ -26,7 +26,7 @@
   %3 = function_ref @inout_uninit : $@convention(thin)() -> ()
   apply %3() : $@convention(thin) () -> ()
   strong_release %1 : $<τ_0_0> { var τ_0_0 } <Int64>
-  %4 = return %2 : $Int64
+  return %2 : $Int64
 }
 
 // CHECK-NOT: sil @inout_uninit : $@convention(thin) () -> () {
diff --git a/test/stdlib/Inputs/SwiftNativeNSBase/SwiftNativeNSBase.m b/test/stdlib/Inputs/SwiftNativeNSBase/SwiftNativeNSBase.m
index fc52377..a4b93b2 100644
--- a/test/stdlib/Inputs/SwiftNativeNSBase/SwiftNativeNSBase.m
+++ b/test/stdlib/Inputs/SwiftNativeNSBase/SwiftNativeNSBase.m
@@ -40,8 +40,23 @@
   } while (0)
 
 
-void TestSwiftNativeNSBase(void)
+BOOL TestSwiftNativeNSBase_RetainCount(id object)
 {
+  Errors = 0;
+  NSUInteger rc1 = [object retainCount];
+  id object2 = [object retain];
+  expectTrue(object == object2);
+  NSUInteger rc2 = [object retainCount];
+  expectTrue(rc2 > rc1);
+  [object release];
+  NSUInteger rc3 = [object retainCount];
+  expectTrue(rc3 < rc2);
+  return Errors == 0;
+}
+
+BOOL TestSwiftNativeNSBase_UnwantedCdtors()
+{
+  Errors = 0;
   printf("TestSwiftNativeNSBase\n");
 
   unsigned int classCount;
@@ -82,5 +97,5 @@
 
   printf("TestSwiftNativeNSBase: %d error%s\n",
          Errors, Errors == 1 ? "" : "s");
-  exit(Errors ? 1 : 0);
+  return Errors == 0;
 }
diff --git a/test/stdlib/Inputs/VariadicBool/module.map b/test/stdlib/Inputs/VariadicBool/module.map
new file mode 100644
index 0000000..fa0bef5
--- /dev/null
+++ b/test/stdlib/Inputs/VariadicBool/module.map
@@ -0,0 +1,3 @@
+module VariadicBool {
+  header "variadicBool.h"
+}
diff --git a/test/stdlib/Inputs/VariadicBool/variadicBool.c b/test/stdlib/Inputs/VariadicBool/variadicBool.c
new file mode 100644
index 0000000..95aa6b4
--- /dev/null
+++ b/test/stdlib/Inputs/VariadicBool/variadicBool.c
@@ -0,0 +1,16 @@
+#include "variadicBool.h"
+
+int numberOfTrues(int count, va_list arguments) {  
+  int i, total;
+  total = 0;
+  
+  for(i = 0; i < count; i++) {
+    //we're passing int here because passing bool is actually incorrect since 
+    //bool is actually promoted to int in C
+    if(va_arg(arguments, int) == true) {
+      total += 1;
+    }
+  }
+  
+  return total;
+}
\ No newline at end of file
diff --git a/test/stdlib/Inputs/VariadicBool/variadicBool.h b/test/stdlib/Inputs/VariadicBool/variadicBool.h
new file mode 100644
index 0000000..7980068
--- /dev/null
+++ b/test/stdlib/Inputs/VariadicBool/variadicBool.h
@@ -0,0 +1,5 @@
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdbool.h>
+
+extern int numberOfTrues(int count, va_list arguments);
\ No newline at end of file
diff --git a/test/stdlib/TypeName.swift b/test/stdlib/TypeName.swift
index dfb93e4..496bd71 100644
--- a/test/stdlib/TypeName.swift
+++ b/test/stdlib/TypeName.swift
@@ -185,4 +185,28 @@
               _typeName(SomeOuterGenericClass<String>.SomeInnerGenericStruct<Int>.self));
 }
 
+extension SomeOuterGenericClass {
+  struct OtherInnerStruct {}
+  struct OtherInnerGenericStruct<U> {}
+}
+
+TypeNameTests.test("NestedInExtension") {
+  expectEqual("main.SomeOuterGenericClass<Swift.Int>.OtherInnerStruct",
+              _typeName(SomeOuterGenericClass<Int>.OtherInnerStruct.self));
+  expectEqual("main.SomeOuterGenericClass<Swift.Int>.OtherInnerGenericStruct<Swift.String>",
+              _typeName(SomeOuterGenericClass<Int>.OtherInnerGenericStruct<String>.self));
+}
+
+extension SomeOuterGenericClass where T == Int {
+  struct AnotherInnerStruct {}
+  struct AnotherInnerGenericStruct<U> {}
+}
+
+TypeNameTests.test("NestedInConstrainedExtension") {
+  expectEqual("main.SomeOuterGenericClass.AnotherInnerStruct",
+              _typeName(SomeOuterGenericClass<Int>.AnotherInnerStruct.self));
+  expectEqual("main.SomeOuterGenericClass.AnotherInnerGenericStruct<Swift.String>",
+              _typeName(SomeOuterGenericClass<Int>.AnotherInnerGenericStruct<String>.self));
+}
+
 runAllTests()
diff --git a/test/stmt/if_while_var.swift b/test/stmt/if_while_var.swift
index c2393ff..c35399a 100644
--- a/test/stmt/if_while_var.swift
+++ b/test/stmt/if_while_var.swift
@@ -94,7 +94,7 @@
 if 1 != 2, 4 == 57, let x = opt {} // expected-warning {{immutable value 'x' was never used; consider replacing with '_' or removing it}}
 
 // Test that these don't cause the parser to crash.
-if true { if a == 0; {} }   // expected-error {{expected '{' after 'if' condition}} expected-error 2{{}} expected-note 1{{}}
+if true { if a == 0; {} }   // expected-error {{use of unresolved identifier 'a'}} expected-error {{expected '{' after 'if' condition}}
 if a == 0, where b == 0 {}  // expected-error 3{{}} expected-note {{}} {{25-25=do }}
 
 
diff --git a/tools/SourceKit/include/SourceKit/Core/ProtocolUIDs.def b/tools/SourceKit/include/SourceKit/Core/ProtocolUIDs.def
index 8f019c7..b332d41 100644
--- a/tools/SourceKit/include/SourceKit/Core/ProtocolUIDs.def
+++ b/tools/SourceKit/include/SourceKit/Core/ProtocolUIDs.def
@@ -270,6 +270,7 @@
 KIND(ExprArray, "source.lang.swift.expr.array")
 KIND(ExprDictionary, "source.lang.swift.expr.dictionary")
 KIND(ExprObjectLiteral, "source.lang.swift.expr.object_literal")
+KIND(ExprTuple, "source.lang.swift.expr.tuple")
 KIND(StructureElemId, "source.lang.swift.structure.elem.id")
 KIND(StructureElemExpr, "source.lang.swift.structure.elem.expr")
 KIND(StructureElemInitExpr, "source.lang.swift.structure.elem.init_expr")
diff --git a/tools/SourceKit/lib/SwiftLang/SwiftLangSupport.cpp b/tools/SourceKit/lib/SwiftLang/SwiftLangSupport.cpp
index 3e7ad81..dfb75c6 100644
--- a/tools/SourceKit/lib/SwiftLang/SwiftLangSupport.cpp
+++ b/tools/SourceKit/lib/SwiftLang/SwiftLangSupport.cpp
@@ -421,6 +421,8 @@
       return KindExprDictionary;
     case SyntaxStructureKind::ObjectLiteralExpression:
       return KindExprObjectLiteral;
+    case SyntaxStructureKind::TupleExpression:
+      return KindExprTuple;
     case SyntaxStructureKind::Argument:
       return KindExprArg;
   }
diff --git a/tools/swift-ide-test/swift-ide-test.cpp b/tools/swift-ide-test/swift-ide-test.cpp
index e6f4d81..e2566ce 100644
--- a/tools/swift-ide-test/swift-ide-test.cpp
+++ b/tools/swift-ide-test/swift-ide-test.cpp
@@ -1090,6 +1090,7 @@
       case SyntaxStructureKind::DictionaryExpression: return "dictionary";
       case SyntaxStructureKind::ObjectLiteralExpression:
         return "object-literal-expression";
+      case SyntaxStructureKind::TupleExpression: return "tuple";
     }
     llvm_unreachable("unhandled tag?");
   }
diff --git a/unittests/runtime/Metadata.cpp b/unittests/runtime/Metadata.cpp
index d53b6dc..85e1beb 100644
--- a/unittests/runtime/Metadata.cpp
+++ b/unittests/runtime/Metadata.cpp
@@ -165,13 +165,14 @@
 uint32_t Global3 = 0;
 
 /// The general structure of a generic metadata.
-template <typename Instance>
+template <typename Instance, unsigned NumArguments>
 struct GenericMetadataTest {
   GenericMetadata Header;
   Instance Template;
+  void *Storage[NumArguments];
 };
 
-GenericMetadataTest<StructMetadata> MetadataTest1 = {
+GenericMetadataTest<StructMetadata, 1> MetadataTest1 = {
   // Header
   {
     // allocation function
@@ -191,9 +192,11 @@
   // Fields
   {
     MetadataKind::Struct,
-    reinterpret_cast<const NominalTypeDescriptor*>(&Global1),
-    nullptr
-  }
+    reinterpret_cast<const NominalTypeDescriptor*>(&Global1)
+  },
+
+  // Arguments
+  {nullptr}
 };
 
 struct TestObjContainer {
diff --git a/utils/build-script b/utils/build-script
index c377d7f..0345340 100755
--- a/utils/build-script
+++ b/utils/build-script
@@ -127,7 +127,11 @@
             test = (
                 deployment_platform not in invocation.platforms_to_skip_test)
             test_host_only = None
-            build_benchmark = build and deployment_target.supports_benchmark
+            dt_supports_benchmark = deployment_target.supports_benchmark
+            build_benchmarks = build and dt_supports_benchmark
+            build_external_benchmarks = all([build, dt_supports_benchmark,
+                                             args.build_external_benchmarks])
+
             # FIXME: Note, `build-script-impl` computed a property here
             # w.r.t. testing, but it was actually unused.
 
@@ -161,13 +165,20 @@
                 else:
                     self.swift_stdlib_build_targets.append(
                         "swift-test-stdlib-" + name)
-            if build_benchmark:
+            if build_benchmarks:
                 self.swift_benchmark_build_targets.append(
                     "swift-benchmark-" + name)
                 # FIXME: This probably should respect `args.benchmark`, but
                 # a typo in build-script-impl meant we always would do this.
                 self.swift_benchmark_run_targets.append(
                     "check-swift-benchmark-" + name)
+
+            if build_external_benchmarks:
+                # Add support for the external benchmarks.
+                self.swift_benchmark_build_targets.append(
+                    "swift-benchmark-{}-external".format(name))
+                self.swift_benchmark_run_targets.append(
+                    "check-swift-benchmark-{}-external".format(name))
             if test:
                 if test_host_only:
                     suffix = "-non-executable"
@@ -304,7 +315,7 @@
             self.platforms_to_skip_test.add(StdlibDeploymentTarget.Cygwin)
         if not args.test_osx:
             self.platforms_to_skip_test.add(StdlibDeploymentTarget.OSX)
-        if not args.test_ios_device:
+        if not args.test_ios_host:
             self.platforms_to_skip_test.add(StdlibDeploymentTarget.iOS)
         else:
             exit_rejecting_arguments("error: iOS device tests are not " +
@@ -315,7 +326,7 @@
         if not args.test_ios_32bit_simulator:
             self.platforms_archs_to_skip_test.add(
                 StdlibDeploymentTarget.iOSSimulator.i386)
-        if not args.test_tvos_device:
+        if not args.test_tvos_host:
             self.platforms_to_skip_test.add(StdlibDeploymentTarget.AppleTV)
         else:
             exit_rejecting_arguments("error: tvOS device tests are not " +
@@ -323,7 +334,7 @@
         if not args.test_tvos_simulator:
             self.platforms_to_skip_test.add(
                 StdlibDeploymentTarget.AppleTVSimulator)
-        if not args.test_watchos_device:
+        if not args.test_watchos_host:
             self.platforms_to_skip_test.add(StdlibDeploymentTarget.AppleWatch)
         else:
             exit_rejecting_arguments("error: watchOS device tests are not " +
@@ -332,16 +343,16 @@
             self.platforms_to_skip_test.add(
                 StdlibDeploymentTarget.AppleWatchSimulator)
 
-        if not args.test_android_device:
+        if not args.test_android_host:
             self.platforms_to_skip_test.add(StdlibDeploymentTarget.Android)
 
         self.platforms_to_skip_test_host = set()
-        if not args.test_ios_device:
+        if not args.test_ios_host:
             self.platforms_to_skip_test_host.add(StdlibDeploymentTarget.iOS)
-        if not args.test_tvos_device:
+        if not args.test_tvos_host:
             self.platforms_to_skip_test_host.add(
                 StdlibDeploymentTarget.AppleTV)
-        if not args.test_watchos_device:
+        if not args.test_watchos_host:
             self.platforms_to_skip_test_host.add(
                 StdlibDeploymentTarget.AppleWatch)
 
@@ -506,6 +517,9 @@
                           "--skip-build-swift"]
         if not args.build_benchmarks:
             impl_args += ["--skip-build-benchmarks"]
+        # Currently we do not build external benchmarks by default.
+        if args.build_external_benchmarks:
+            impl_args += ["--skip-build-external-benchmarks=0"]
         if not args.build_foundation:
             impl_args += ["--skip-build-foundation"]
         if not args.build_xctest:
@@ -579,21 +593,21 @@
             impl_args += ["--skip-test-cygwin"]
         if not args.test_osx:
             impl_args += ["--skip-test-osx"]
-        if not args.test_ios_device:
+        if not args.test_ios_host:
             impl_args += ["--skip-test-ios-host"]
         if not args.test_ios_simulator:
             impl_args += ["--skip-test-ios-simulator"]
         if not args.test_ios_32bit_simulator:
             impl_args += ["--skip-test-ios-32bit-simulator"]
-        if not args.test_tvos_device:
+        if not args.test_tvos_host:
             impl_args += ["--skip-test-tvos-host"]
         if not args.test_tvos_simulator:
             impl_args += ["--skip-test-tvos-simulator"]
-        if not args.test_watchos_device:
+        if not args.test_watchos_host:
             impl_args += ["--skip-test-watchos-host"]
         if not args.test_watchos_simulator:
             impl_args += ["--skip-test-watchos-simulator"]
-        if not args.test_android_device:
+        if not args.test_android_host:
             impl_args += ["--skip-test-android-host"]
         if args.build_runtime_with_host_compiler:
             impl_args += ["--build-runtime-with-host-compiler"]
diff --git a/utils/build-script-impl b/utils/build-script-impl
index 0de5738..5a65bba 100755
--- a/utils/build-script-impl
+++ b/utils/build-script-impl
@@ -126,6 +126,7 @@
     skip-build-libdispatch      ""               "set to skip building libdispatch"
     skip-build-libicu           ""               "set to skip building libicu"
     skip-build-benchmarks       ""               "set to skip building Swift Benchmark Suite"
+    skip-build-external-benchmarks "1"            "set to skip building the external Swift Benchmark Suite. (skipped by default)"
     skip-build-playgroundlogger ""               "set to skip building PlaygroundLogger"
     skip-build-playgroundsupport ""              "set to skip building PlaygroundSupport"
     skip-test-cmark             ""               "set to skip testing CommonMark"
@@ -1324,6 +1325,7 @@
         local test_this_target=1
         local test_host_only=
         local build_benchmark_this_target=
+        local build_external_benchmark_this_target=
         local test_benchmark_this_target=
 
         case ${stdlib_deployment_target} in
@@ -1352,6 +1354,7 @@
                 build_for_this_target=$(not ${SKIP_BUILD_OSX})
                 test_this_target=$(not ${SKIP_TEST_OSX})
                 build_benchmark_this_target=$(not ${SKIP_BUILD_OSX})
+                build_external_benchmark_this_target=$(not ${SKIP_BUILD_OSX})
                 test_benchmark_this_target=$(not ${SKIP_BUILD_OSX})
                 ;;
             iphoneos-*)
@@ -1363,10 +1366,12 @@
                     test_this_target=
                 fi
                 build_benchmark_this_target=$(not ${SKIP_BUILD_IOS_DEVICE})
+                build_external_benchmark_this_target=$(not ${SKIP_BUILD_IOS_DEVICE})
 
                 # Never build iOS armv7s benchmarks.
                 if [[ "${stdlib_deployment_target}" == "iphoneos-armv7s" ]]; then
                     build_benchmark_this_target=
+                    build_external_benchmark_this_target=
                 fi
                 ;;
             iphonesimulator-x86_64)
@@ -1391,6 +1396,7 @@
                     test_this_target=
                 fi
                 build_benchmark_this_target=$(not ${SKIP_BUILD_TVOS_DEVICE})
+                build_external_benchmark_this_target=$(not ${SKIP_BUILD_TVOS_DEVICE})
                 ;;
             appletvsimulator-*)
                 swift_sdk="TVOS_SIMULATOR"
@@ -1406,6 +1412,7 @@
                     test_this_target=
                 fi
                 build_benchmark_this_target=$(not ${SKIP_BUILD_WATCHOS_DEVICE})
+                build_external_benchmark_this_target=$(not ${SKIP_BUILD_WATCHOS_DEVICE})
                 ;;
             watchsimulator-*)
                 swift_sdk="WATCHOS_SIMULATOR"
@@ -1443,6 +1450,16 @@
               SWIFT_RUN_BENCHMARK_TARGETS+=("check-swift-benchmark-${stdlib_deployment_target}")
             fi
         fi
+
+        if [[ "$(true_false ${SKIP_BUILD_EXTERNAL_BENCHMARKS})" == "FALSE"  ]] &&
+           [[ "${build_external_benchmark_this_target}" ]] &&
+           [[ "${is_in_build_list}" ]] ; then
+            SWIFT_BENCHMARK_TARGETS+=("swift-benchmark-${stdlib_deployment_target}-external")
+            if [[ $(not ${SKIP_TEST_BENCHMARK}) ]] ; then
+                SWIFT_RUN_BENCHMARK_TARGETS+=("check-swift-benchmark-${stdlib_deployment_target}-external")
+            fi
+        fi
+
         if [[ "${test_this_target}" ]] && [[ "${is_in_build_list}" ]]; then
             test_target_suffix=""
             if [[ -n "${test_host_only}" ]] ; then
@@ -2098,13 +2115,16 @@
 
                     # Don't build benchmarks and tests when building cross compiler.
                     build_perf_testsuite_this_time=false
+                    build_external_perf_testsuite_this_time=false
                     build_tests_this_time=false
 
                     native_llvm_tools_path="$(build_directory "${LOCAL_HOST}" llvm)/bin"
                     native_clang_tools_path="$(build_directory "${LOCAL_HOST}" llvm)/bin"
                     native_swift_tools_path="$(build_directory "${LOCAL_HOST}" swift)/bin"
                 else
+                    # FIXME: Why is the next line not using false_true?
                     build_perf_testsuite_this_time=$(true_false "$(not ${SKIP_BUILD_BENCHMARKS})")
+                    build_external_perf_testsuite_this_time=$(false_true "${SKIP_BUILD_EXTERNAL_BENCHMARKS}")
                     build_tests_this_time=${SWIFT_INCLUDE_TESTS}
                 fi
 
@@ -2162,6 +2182,7 @@
                     -DSWIFT_BUILD_DYNAMIC_SDK_OVERLAY:BOOL=$(true_false "${BUILD_SWIFT_DYNAMIC_SDK_OVERLAY}")
                     -DSWIFT_BUILD_STATIC_SDK_OVERLAY:BOOL=$(true_false "${BUILD_SWIFT_STATIC_SDK_OVERLAY}")
                     -DSWIFT_BUILD_PERF_TESTSUITE:BOOL=$(true_false "${build_perf_testsuite_this_time}")
+                    -DSWIFT_BUILD_EXTERNAL_PERF_TESTSUITE:BOOL=$(true_false "${build_external_perf_testsuite_this_time}")
                     -DSWIFT_BUILD_EXAMPLES:BOOL=$(true_false "${BUILD_SWIFT_EXAMPLES}")
                     -DSWIFT_INCLUDE_TESTS:BOOL=$(true_false "${build_tests_this_time}")
                     -DSWIFT_INSTALL_COMPONENTS:STRING="${SWIFT_INSTALL_COMPONENTS}"
diff --git a/utils/build_swift/driver_arguments.py b/utils/build_swift/driver_arguments.py
index d7c43d5..2dff6ea 100644
--- a/utils/build_swift/driver_arguments.py
+++ b/utils/build_swift/driver_arguments.py
@@ -153,6 +153,7 @@
         args.build_watchos = False
         args.build_android = False
         args.build_benchmarks = False
+        args.build_external_benchmarks = False
         args.build_lldb = False
         args.build_llbuild = False
         args.build_swiftpm = False
@@ -214,43 +215,43 @@
 
     # --skip-test-ios is merely a shorthand for host and simulator tests.
     if not args.test_ios:
-        args.test_ios_device = False
+        args.test_ios_host = False
         args.test_ios_simulator = False
     # --skip-test-tvos is merely a shorthand for host and simulator tests.
     if not args.test_tvos:
-        args.test_tvos_device = False
+        args.test_tvos_host = False
         args.test_tvos_simulator = False
     # --skip-test-watchos is merely a shorthand for host and simulator
     # --tests.
     if not args.test_watchos:
-        args.test_watchos_device = False
+        args.test_watchos_host = False
         args.test_watchos_simulator = False
 
     # --skip-build-{ios,tvos,watchos}-{device,simulator} implies
     # --skip-test-{ios,tvos,watchos}-{host,simulator}
     if not args.build_ios_device:
-        args.test_ios_device = False
+        args.test_ios_host = False
     if not args.build_ios_simulator:
         args.test_ios_simulator = False
 
     if not args.build_tvos_device:
-        args.test_tvos_device = False
+        args.test_tvos_host = False
     if not args.build_tvos_simulator:
         args.test_tvos_simulator = False
 
     if not args.build_watchos_device:
-        args.test_watchos_device = False
+        args.test_watchos_host = False
     if not args.build_watchos_simulator:
         args.test_watchos_simulator = False
 
     if not args.build_android:
-        args.test_android_device = False
+        args.test_android_host = False
 
     if not args.host_test:
-        args.test_ios_device = False
-        args.test_tvos_device = False
-        args.test_watchos_device = False
-        args.test_android_device = False
+        args.test_ios_host = False
+        args.test_tvos_host = False
+        args.test_watchos_host = False
+        args.test_android_host = False
 
     if args.build_subdir is None:
         args.build_subdir = \
@@ -771,6 +772,12 @@
         action=arguments.action.optional_false,
         help="skip building Swift Benchmark Suite")
 
+    run_build_group.add_argument(
+        "--build-external-benchmarks",
+        dest='build_external_benchmarks',
+        action=arguments.action.optional_true,
+        help="skip building Swift Benchmark Suite")
+
     skip_test_group = parser.add_argument_group(
         title="Skip testing specified targets")
     skip_test_group.add_argument(
@@ -791,7 +798,7 @@
         help="skip testing iOS 32 bit simulator targets")
     skip_test_group.add_argument(
         "--skip-test-ios-host",
-        dest='test_ios_device',
+        dest='test_ios_host',
         action=arguments.action.optional_false,
         help="skip testing iOS device targets on the host machine (the phone "
              "itself)")
@@ -808,7 +815,7 @@
         help="skip testing tvOS simulator targets")
     skip_test_group.add_argument(
         "--skip-test-tvos-host",
-        dest='test_tvos_device',
+        dest='test_tvos_host',
         action=arguments.action.optional_false,
         help="skip testing tvOS device targets on the host machine (the TV "
              "itself)")
@@ -825,13 +832,13 @@
         help="skip testing watchOS simulator targets")
     skip_test_group.add_argument(
         "--skip-test-watchos-host",
-        dest='test_watchos_device',
+        dest='test_watchos_host',
         action=arguments.action.optional_false,
         help="skip testing watchOS device targets on the host machine (the "
              "watch itself)")
     skip_test_group.add_argument(
         "--skip-test-android-host",
-        dest='test_android_device',
+        dest='test_android_host',
         action=arguments.action.optional_false,
         help="skip testing Android device targets on the host machine (the "
              "phone itself)")
diff --git a/utils/build_swift/tests/expected_options.py b/utils/build_swift/tests/expected_options.py
index af46936..7282eb1 100644
--- a/utils/build_swift/tests/expected_options.py
+++ b/utils/build_swift/tests/expected_options.py
@@ -45,6 +45,7 @@
     'build_args': [],
     'build_benchmarks': True,
     'build_cygwin': True,
+    'build_external_benchmarks': False,
     'build_foundation': False,
     'build_freebsd': True,
     'build_ios': True,
@@ -153,12 +154,12 @@
     'swift_user_visible_version': '4.1',
     'symbols_package': None,
     'test': None,
-    'test_android_device': False,
+    'test_android_host': False,
     'test_cygwin': False,
     'test_freebsd': False,
     'test_ios': False,
     'test_ios_32bit_simulator': True,
-    'test_ios_device': False,
+    'test_ios_host': False,
     'test_ios_simulator': False,
     'test_linux': False,
     'test_optimize_for_size': None,
@@ -166,10 +167,10 @@
     'test_osx': False,
     'test_paths': [],
     'test_tvos': False,
-    'test_tvos_device': False,
+    'test_tvos_host': False,
     'test_tvos_simulator': False,
     'test_watchos': False,
-    'test_watchos_device': False,
+    'test_watchos_host': False,
     'test_watchos_simulator': False,
     'tvos': False,
     'tvos_all': False,
@@ -349,6 +350,8 @@
     Option('-x', dest='cmake_generator', value='Xcode'),
 
     ToggleOption('--android', dest='android'),
+    ToggleOption('--build-external-benchmarks',
+                 dest='build_external_benchmarks'),
     ToggleOption('--build-ninja', dest='build_ninja'),
     ToggleOption('--build-runtime-with-host-compiler',
                  dest='build_runtime_with_host_compiler'),
@@ -393,22 +396,22 @@
                  dest='build_watchos_device'),
     ToggleOption('--skip-build-watchos-simulator',
                  dest='build_watchos_simulator'),
-    ToggleOption('--skip-test-android-host', dest='test_android_device'),
+    ToggleOption('--skip-test-android-host', dest='test_android_host'),
     ToggleOption('--skip-test-cygwin', dest='test_cygwin'),
     ToggleOption('--skip-test-freebsd', dest='test_freebsd'),
     ToggleOption('--skip-test-ios', dest='test_ios'),
     ToggleOption('--skip-test-ios-32bit-simulator',
                  dest='test_ios_32bit_simulator'),
-    ToggleOption('--skip-test-ios-host', dest='test_ios_device'),
+    ToggleOption('--skip-test-ios-host', dest='test_ios_host'),
     ToggleOption('--skip-test-ios-simulator', dest='test_ios_simulator'),
     ToggleOption('--skip-test-linux', dest='test_linux'),
     ToggleOption('--skip-test-osx', dest='test_osx'),
     ToggleOption('--skip-test-tvos', dest='test_tvos'),
-    ToggleOption('--skip-test-tvos-host', dest='test_tvos_device'),
+    ToggleOption('--skip-test-tvos-host', dest='test_tvos_host'),
     ToggleOption('--skip-test-tvos-simulator',
                  dest='test_tvos_simulator'),
     ToggleOption('--skip-test-watchos', dest='test_watchos'),
-    ToggleOption('--skip-test-watchos-host', dest='test_watchos_device'),
+    ToggleOption('--skip-test-watchos-host', dest='test_watchos_host'),
     ToggleOption('--skip-test-watchos-simulator',
                  dest='test_watchos_simulator'),
     ToggleOption('--test', dest='test'),
diff --git a/utils/build_swift/tests/test_driver_arguments.py b/utils/build_swift/tests/test_driver_arguments.py
index f5c9b94..49ebe69 100644
--- a/utils/build_swift/tests/test_driver_arguments.py
+++ b/utils/build_swift/tests/test_driver_arguments.py
@@ -446,7 +446,7 @@
             self.assertFalse(args.build_ios_simulator)
 
             # Also implies that the tests should be skipped
-            self.assertFalse(args.test_ios_device)
+            self.assertFalse(args.test_ios_host)
             self.assertFalse(args.test_ios_simulator)
 
     def test_implied_defaults_skip_build_tvos(self):
@@ -456,7 +456,7 @@
             self.assertFalse(args.build_tvos_simulator)
 
             # Also implies that the tests should be skipped
-            self.assertFalse(args.test_tvos_device)
+            self.assertFalse(args.test_tvos_host)
             self.assertFalse(args.test_tvos_simulator)
 
     def test_implied_defaults_skip_build_watchos(self):
@@ -466,7 +466,7 @@
             self.assertFalse(args.build_watchos_simulator)
 
             # Also implies that the tests should be skipped
-            self.assertFalse(args.test_watchos_device)
+            self.assertFalse(args.test_watchos_host)
             self.assertFalse(args.test_watchos_simulator)
 
     def test_implied_defaults_validation_test(self):
@@ -503,37 +503,37 @@
     def test_implied_defaults_skip_test_ios(self):
         with self.assertNotRaises(ParserError):
             args = self.parse_args(['--skip-test-ios'])
-            self.assertFalse(args.test_ios_device)
+            self.assertFalse(args.test_ios_host)
             self.assertFalse(args.test_ios_simulator)
 
     def test_implied_defaults_skip_test_tvos(self):
         with self.assertNotRaises(ParserError):
             args = self.parse_args(['--skip-test-tvos'])
-            self.assertFalse(args.test_tvos_device)
+            self.assertFalse(args.test_tvos_host)
             self.assertFalse(args.test_tvos_simulator)
 
     def test_implied_defaults_skip_test_watchos(self):
         with self.assertNotRaises(ParserError):
             args = self.parse_args(['--skip-test-watchos'])
-            self.assertFalse(args.test_watchos_device)
+            self.assertFalse(args.test_watchos_host)
             self.assertFalse(args.test_watchos_simulator)
 
     def test_implied_defaults_skip_build_android(self):
         with self.assertNotRaises(ParserError):
             args = self.parse_args(['--android', '0'])
-            self.assertFalse(args.test_android_device)
+            self.assertFalse(args.test_android_host)
 
         with self.assertNotRaises(ParserError):
             args = self.parse_args(['--skip-build-android'])
-            self.assertFalse(args.test_android_device)
+            self.assertFalse(args.test_android_host)
 
     def test_implied_defaults_host_test(self):
         with self.assertNotRaises(ParserError):
             args = self.parse_args(['--host-test', '0'])
-            self.assertFalse(args.test_ios_device)
-            self.assertFalse(args.test_tvos_device)
-            self.assertFalse(args.test_watchos_device)
-            self.assertFalse(args.test_android_device)
+            self.assertFalse(args.test_ios_host)
+            self.assertFalse(args.test_tvos_host)
+            self.assertFalse(args.test_watchos_host)
+            self.assertFalse(args.test_android_host)
 
 
 if __name__ == '__main__':
diff --git a/validation-test/SIL/crashers_fixed/027-swift-nominaltypedecl-getdeclaredtype.sil b/validation-test/SIL/crashers_fixed/027-swift-nominaltypedecl-getdeclaredtype.sil
index d28e59d..cfc7e25 100644
--- a/validation-test/SIL/crashers_fixed/027-swift-nominaltypedecl-getdeclaredtype.sil
+++ b/validation-test/SIL/crashers_fixed/027-swift-nominaltypedecl-getdeclaredtype.sil
@@ -40,7 +40,7 @@
 }
 }
 bb0(thin) : AssocReqt module def_basic {}
-%12 = strong_release %5 : $*Spoon
+strong_release %5 : $*Spoon
 %8 = unchecked_addr_cast %101 = tuple(%2 : $*SomeClass.Type) -> (Int, 5
 sil [_semantics "foo(%2 = apply [fragile] @owned A>
 %14 = alloc_box $@convention(thin) : $@owned A, bb1:
diff --git a/validation-test/Sema/type_checker_perf/fast/rdar22282851.swift b/validation-test/Sema/type_checker_perf/slow/rdar22282851.swift
similarity index 63%
rename from validation-test/Sema/type_checker_perf/fast/rdar22282851.swift
rename to validation-test/Sema/type_checker_perf/slow/rdar22282851.swift
index 9c790d7..0dfe5a8 100644
--- a/validation-test/Sema/type_checker_perf/fast/rdar22282851.swift
+++ b/validation-test/Sema/type_checker_perf/slow/rdar22282851.swift
@@ -7,5 +7,6 @@
 
 func rdar22282851(_ a: [S]) -> [S] {
   let result = a.sorted{ $0.s < $1.s || ($0.s == $1.s && $0.s < $1.s) }
+  // expected-error@-1 {{expression was too complex to be solved in reasonable time; consider breaking up the expression into distinct sub-expressions}}
   return result
 }
diff --git a/validation-test/compiler_crashers_2_fixed/0119-rdar33613329.swift b/validation-test/compiler_crashers_2_fixed/0119-rdar33613329.swift
new file mode 100644
index 0000000..1d251d6
--- /dev/null
+++ b/validation-test/compiler_crashers_2_fixed/0119-rdar33613329.swift
@@ -0,0 +1,45 @@
+// RUN: %target-typecheck-verify-swift %s
+
+precedencegroup BindingPrecedence {
+  higherThan: DefaultPrecedence
+}
+
+infix operator ~>
+infix operator ≈> : BindingPrecedence
+
+struct M<L : P, R> {
+  let f: L
+  let b: (inout L.B) -> R
+
+  init(f: L, b: @escaping (inout L.B) -> R) {
+    self.f = f
+    self.b = b
+  }
+}
+
+protocol P {
+  associatedtype A
+  associatedtype B
+
+  func `in`<R>(_ a: inout A, apply body: (inout B) -> R) -> R
+
+  static func ~> (_: A, _: Self) -> B
+}
+
+extension P {
+  static func ≈> <R>(f: Self,  b: @escaping (inout B) -> R) -> M<Self, R> {}
+}
+
+extension WritableKeyPath : P {
+  typealias A = Root
+  typealias B = Value
+
+  func `in`<R>(_ a: inout A, apply body: (inout B) -> R) -> R {}
+
+  static func ~> (a: A, path: WritableKeyPath) -> B {}
+}
+
+struct X { var y: Int = 0 }
+var x = X()
+x ~> \X.y ≈> { a in a += 1; return 3 }
+// expected-error@-1 {{cannot convert call result type 'M<WritableKeyPath<X, Int>, _>' to expected type 'WritableKeyPath<_, _>'}}
diff --git a/validation-test/execution/crashers/rdar18157434.swift b/validation-test/execution/crashers_fixed/rdar33767511.swift
similarity index 90%
rename from validation-test/execution/crashers/rdar18157434.swift
rename to validation-test/execution/crashers_fixed/rdar33767511.swift
index 5d0bfd8..825e4b1 100644
--- a/validation-test/execution/crashers/rdar18157434.swift
+++ b/validation-test/execution/crashers_fixed/rdar33767511.swift
@@ -1,7 +1,7 @@
 // RUN: rm -rf %t
 // RUN: mkdir -p %t
 // RUN: %target-build-swift %s -o %t/a.out
-// RUN: not --crash %target-run %t/a.out
+// RUN: %target-run %t/a.out
 
 // REQUIRES: executable_test
 // REQUIRES: OS=macosx
diff --git a/validation-test/stdlib/Bool.swift b/validation-test/stdlib/Bool.swift
new file mode 100644
index 0000000..758f155
--- /dev/null
+++ b/validation-test/stdlib/Bool.swift
@@ -0,0 +1,44 @@
+// RUN: mkdir -p %t
+// RUN: %target-clang -x c %S/Inputs/VariadicBool/variadicBool.c -c -o %t/variadicBool.o
+// RUN: %target-build-swift -I %S/Inputs/VariadicBool/ %t/variadicBool.o %s -o %t/a.out
+// RUN: %target-run %t/a.out
+// REQUIRES: executable_test
+
+
+import Swift
+import StdlibUnittest
+import StdlibCollectionUnittest
+import VariadicBool
+
+func countTrues(_ count: Int, _ bools: CVarArg...) -> Int {
+  return Int(withVaList(bools) { numberOfTrues(Int32(count), $0) })
+}
+
+var BoolTestSuite = TestSuite("Bool")
+
+BoolTestSuite.test("AllTrues") {
+  let result = countTrues(2, true, true)
+  expectEqual(2, result)
+}
+
+BoolTestSuite.test("HalfAndHalf") {
+  let result = countTrues(4, true, true, false, false)
+  expectEqual(2, result)
+}
+
+BoolTestSuite.test("AllFalse") {
+  let result = countTrues(2, false, false)
+  expectEqual(0, result)
+}
+
+BoolTestSuite.test("Interleaved") {
+  let result = countTrues(7, false, true, false, true, false, true, false)
+  expectEqual(3, result)
+}
+
+BoolTestSuite.test("FalsePositive") {
+  let result = countTrues(7, false, true, false, true, false, true, false)
+  expectNotEqual(30, result)
+}
+
+runAllTests()
\ No newline at end of file
diff --git a/validation-test/stdlib/BoolDiagnostics.swift b/validation-test/stdlib/BoolDiagnostics.swift
new file mode 100644
index 0000000..95eee5e
--- /dev/null
+++ b/validation-test/stdlib/BoolDiagnostics.swift
@@ -0,0 +1,7 @@
+// RUN: %target-swift-frontend -typecheck -verify %s
+
+func CVarArgs_withBool() {
+  func varArgFunc(_ x: Bool, _ args: CVarArg...) { }
+  let x = false
+  varArgFunc(x, x)
+}
diff --git a/validation-test/stdlib/SwiftNativeNSBase.swift b/validation-test/stdlib/SwiftNativeNSBase.swift
index bb6fc8e..288b565 100644
--- a/validation-test/stdlib/SwiftNativeNSBase.swift
+++ b/validation-test/stdlib/SwiftNativeNSBase.swift
@@ -13,16 +13,71 @@
 // RUN: %empty-directory(%t)
 // 
 // RUN: %target-clang %S/Inputs/SwiftNativeNSBase/SwiftNativeNSBase.m -c -o %t/SwiftNativeNSBase.o -g
-// RUN: %target-build-swift %s -I %S/Inputs/SwiftNativeNSBase/ -Xlinker %t/SwiftNativeNSBase.o -o %t/SwiftNativeNSBase
+// RUN: %target-clang -fobjc-arc %S/Inputs/SlurpFastEnumeration/SlurpFastEnumeration.m -c -o %t/SlurpFastEnumeration.o
+// RUN: echo '#sourceLocation(file: "%s", line: 1)' > "%t/main.swift" && cat "%s" >> "%t/main.swift" && chmod -w "%t/main.swift"
+// RUN: %target-build-swift -Xfrontend -disable-access-control  %t/main.swift %S/Inputs/DictionaryKeyValueTypes.swift %S/Inputs/DictionaryKeyValueTypesObjC.swift -I %S/Inputs/SwiftNativeNSBase/ -I %S/Inputs/SlurpFastEnumeration/ -Xlinker %t/SlurpFastEnumeration.o -Xlinker %t/SwiftNativeNSBase.o -o %t/SwiftNativeNSBase
 // RUN: %target-run %t/SwiftNativeNSBase
 // REQUIRES: executable_test
 
 // REQUIRES: objc_interop
 
 import Foundation
+import StdlibUnittest
 
-@_silgen_name("TestSwiftNativeNSBase") 
-func TestSwiftNativeNSBase()
+@_silgen_name("TestSwiftNativeNSBase_UnwantedCdtors") 
+func TestSwiftNativeNSBase_UnwantedCdtors() -> Bool
+@_silgen_name("TestSwiftNativeNSBase_RetainCount") 
+func TestSwiftNativeNSBase_RetainCount(_: UnsafeMutableRawPointer) -> Bool
 
-TestSwiftNativeNSBase()
-// does not return
+func classChain(of cls: AnyClass) -> [String] {
+  var chain: [String] = []
+  var cls: AnyClass? = cls
+  while cls != nil {
+    chain.append(NSStringFromClass(cls!))
+    cls = class_getSuperclass(cls)
+  }
+  return chain
+}
+
+var SwiftNativeNSBaseTestSuite = TestSuite("SwiftNativeNSBase")
+
+SwiftNativeNSBaseTestSuite.test("UnwantedCdtors") {
+  expectTrue(TestSwiftNativeNSBase_UnwantedCdtors())
+}
+
+SwiftNativeNSBaseTestSuite.test("_SwiftNativeNSArrayBase.retainCount") {
+  let bridged = getBridgedNSArrayOfRefTypeVerbatimBridged()
+  assert(classChain(of: type(of: bridged)).contains("_SwiftNativeNSArrayBase"))
+  expectTrue(TestSwiftNativeNSBase_RetainCount(
+      Unmanaged.passUnretained(bridged).toOpaque()))
+  _fixLifetime(bridged)
+}
+
+SwiftNativeNSBaseTestSuite.test("_SwiftNativeNSDictionaryBase.retainCount") {
+  let bridged = getBridgedNSDictionaryOfRefTypesBridgedVerbatim()
+  assert(classChain(of: type(of: bridged))
+    .contains("_SwiftNativeNSDictionaryBase"))
+  expectTrue(TestSwiftNativeNSBase_RetainCount(
+      Unmanaged.passUnretained(bridged).toOpaque()))
+  _fixLifetime(bridged)
+}
+
+SwiftNativeNSBaseTestSuite.test("_SwiftNativeNSSetBase.retainCount") {
+  let bridged = Set([10, 20, 30].map{ TestObjCKeyTy($0) })._bridgeToObjectiveC()
+  assert(classChain(of: type(of: bridged)).contains("_SwiftNativeNSSetBase"))
+  expectTrue(TestSwiftNativeNSBase_RetainCount(
+      Unmanaged.passUnretained(bridged).toOpaque()))
+  _fixLifetime(bridged)
+}
+
+SwiftNativeNSBaseTestSuite.setUp {
+  resetLeaksOfDictionaryKeysValues()
+  resetLeaksOfObjCDictionaryKeysValues()
+}
+
+SwiftNativeNSBaseTestSuite.tearDown {
+  expectNoLeaksOfDictionaryKeysValues()
+  expectNoLeaksOfObjCDictionaryKeysValues()
+}
+
+runAllTests()