Merge pull request #12097 from DougGregor/gsb-nested-type-lookup

[GSB] Centralize, clean up, and cache nested type name lookup
diff --git a/benchmark/CMakeLists.txt b/benchmark/CMakeLists.txt
index 71a9d4f..8012413 100644
--- a/benchmark/CMakeLists.txt
+++ b/benchmark/CMakeLists.txt
@@ -11,6 +11,11 @@
 list(APPEND CMAKE_MODULE_PATH
     "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules")
 
+set(SWIFT_BENCHMARK_BUILT_STANDALONE FALSE)
+if("${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_CURRENT_SOURCE_DIR}")
+  set(SWIFT_BENCHMARK_BUILT_STANDALONE TRUE)
+endif()
+
 include(AddSwiftBenchmarkSuite)
 
 set(SWIFT_BENCH_MODULES
@@ -240,16 +245,12 @@
 
 set(executable_targets)
 
-if(SWIFT_SDKS)
-  set(IS_SWIFT_BUILD true)
-endif()
-
 set(srcdir "${CMAKE_CURRENT_SOURCE_DIR}")
 
-if(IS_SWIFT_BUILD)
-  get_filename_component(swift-bin-dir "${SWIFT_EXEC}" DIRECTORY)
-else()
+if(SWIFT_BENCHMARK_BUILT_STANDALONE)
   set(swift-bin-dir "${CMAKE_BINARY_DIR}/bin")
+else()
+  get_filename_component(swift-bin-dir "${SWIFT_EXEC}" DIRECTORY)
 endif()
 
 set(benchmark-bin-dir "${CMAKE_CURRENT_BINARY_DIR}/bin")
diff --git a/benchmark/cmake/modules/AddSwiftBenchmarkSuite.cmake b/benchmark/cmake/modules/AddSwiftBenchmarkSuite.cmake
index 7afc8e9..3a00b46 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"
@@ -120,89 +121,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_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()
 
@@ -415,7 +374,7 @@
 function(swift_benchmark_compile)
   cmake_parse_arguments(SWIFT_BENCHMARK_COMPILE "" "PLATFORM" "" ${ARGN})
 
-  if(IS_SWIFT_BUILD)
+  if(NOT SWIFT_BENCHMARK_BUILT_STANDALONE)
     set(stdlib_dependencies "swift")
     foreach(stdlib_dependency ${UNIVERSAL_LIBRARY_NAMES_${SWIFT_BENCHMARK_COMPILE_PLATFORM}})
       string(FIND "${stdlib_dependency}" "Unittest" find_output)
@@ -441,7 +400,7 @@
     add_custom_target("${executable_target}"
         DEPENDS ${platform_executables})
 
-    if(IS_SWIFT_BUILD AND "${SWIFT_BENCHMARK_COMPILE_PLATFORM}" STREQUAL "macosx")
+    if(NOT SWIFT_BENCHMARK_BUILT_STANDALONE AND "${SWIFT_BENCHMARK_COMPILE_PLATFORM}" STREQUAL "macosx")
       add_custom_command(
           TARGET "${executable_target}"
           POST_BUILD
diff --git a/benchmark/cmake/modules/SwiftBenchmarkUtils.cmake b/benchmark/cmake/modules/SwiftBenchmarkUtils.cmake
new file mode 100644
index 0000000..4806892
--- /dev/null
+++ b/benchmark/cmake/modules/SwiftBenchmarkUtils.cmake
@@ -0,0 +1,29 @@
+
+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()
diff --git a/docs/GenericsManifesto.md b/docs/GenericsManifesto.md
index 51b2a58..d1bbf26 100644
--- a/docs/GenericsManifesto.md
+++ b/docs/GenericsManifesto.md
@@ -27,7 +27,7 @@
 
 ### Recursive protocol constraints (*)
 
-*The feature is being reviewed in [SE-0157](https://github.com/apple/swift-evolution/blob/master/proposals/0157-recursive-protocol-constraints.md).*
+*This feature has been accepted in [SE-0157](https://github.com/apple/swift-evolution/blob/master/proposals/0157-recursive-protocol-constraints.md) and is tracked by [SR-1445](https://bugs.swift.org/browse/SR-1445).*
 
 Currently, an associated type cannot be required to conform to its enclosing protocol (or any protocol that inherits that protocol). For example, in the standard library `SubSequence` type of a `Sequence` should itself be a `Sequence`:
 
@@ -43,7 +43,7 @@
 
 ### Nested generics
 
-*This feature is tracked by [SR-1446](https://bugs.swift.org/browse/SR-1446) and is planned for release with Swift 3.1.*
+*This feature was tracked by [SR-1446](https://bugs.swift.org/browse/SR-1446) and was released with Swift 3.1.*
 
 Currently, a generic type cannot be nested within another generic type, e.g.
 
@@ -57,7 +57,7 @@
 
 ### Concrete same-type requirements
 
-*This feature is tracked by [SR-1009](https://bugs.swift.org/browse/SR-1009) and is planned for release with Swift 3.1.*
+*This feature was tracked by [SR-1009](https://bugs.swift.org/browse/SR-1009) and was released with Swift 3.1.*
 
 Currently, a constrained extension cannot use a same-type constraint to make a type parameter equivalent to a concrete type. For example:
 
@@ -90,7 +90,7 @@
 
 ### Generic subscripts
 
-*This feature has been accepted in [SE-0148](https://github.com/apple/swift-evolution/blob/master/proposals/0148-generic-subscripts.md), is tracked by [SR-115](https://bugs.swift.org/browse/SR-115) and is planned for release in Swift 4.*
+*This feature has been accepted in [SE-0148](https://github.com/apple/swift-evolution/blob/master/proposals/0148-generic-subscripts.md), was tracked by [SR-115](https://bugs.swift.org/browse/SR-115) and was released with Swift 4.*
 
 Subscripts could be allowed to have generic parameters. For example, we could introduce a generic subscript on a `Collection` that allows us to pull out the values at an arbitrary set of indices:
 
@@ -186,7 +186,7 @@
 
 ### Arbitrary requirements in protocols (*)
 
-*This feature has been accepted in [SE-0142](https://github.com/apple/swift-evolution/blob/master/proposals/0142-associated-types-constraints.md) and is under development.*
+*This feature has been accepted in [SE-0142](https://github.com/apple/swift-evolution/blob/master/proposals/0142-associated-types-constraints.md) and was released with Swift 4.*
 
 Currently, a new protocol can inherit from other protocols, introduce new associated types, and add new conformance constraints to associated types (by redeclaring an associated type from an inherited protocol). However, one cannot express more general constraints. Building on the example from "Recursive protocol constraints", we really want the element type of a `Sequence`'s `SubSequence` to be the same as the element type of the `Sequence`, e.g.,
 
@@ -202,7 +202,7 @@
 
 ### Typealiases in protocols and protocol extensions (*)
 
-*The feature has been accepted in [SE-0092](https://github.com/apple/swift-evolution/blob/master/proposals/0092-typealiases-in-protocols.md) and was released with Swift 3.*
+*This feature has been accepted in [SE-0092](https://github.com/apple/swift-evolution/blob/master/proposals/0092-typealiases-in-protocols.md) and was released with Swift 3.*
 
 Now that associated types have their own keyword (thanks!), it's reasonable to bring back `typealias`. Again with the `Sequence` protocol:
 
@@ -229,7 +229,7 @@
 
 ### Generalized `class` constraints
 
-*This feature will come as a consequence of proposal [SE-0156](https://github.com/apple/swift-evolution/blob/master/proposals/0156-subclass-existentials.md) which is in review.*
+*This feature is a consequence of proposal [SE-0156](https://github.com/apple/swift-evolution/blob/master/proposals/0156-subclass-existentials.md) and was released with Swift 4.*
 
 The `class` constraint can currently only be used for defining protocols. We could generalize it to associated type and type parameter declarations, e.g.,
 
@@ -691,7 +691,7 @@
 
 ### Associated type inference
 
-*The feature has been rejected in [SE-0108](https://github.com/apple/swift-evolution/blob/master/proposals/0108-remove-assoctype-inference.md).*
+*This feature has been rejected in [SE-0108](https://github.com/apple/swift-evolution/blob/master/proposals/0108-remove-assoctype-inference.md).*
 
 Associated type inference is the process by which we infer the type bindings for associated types from other requirements. For example:
 
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/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/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/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/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/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..b1b1511 100644
--- a/include/swift/SIL/SILBuilder.h
+++ b/include/swift/SIL/SILBuilder.h
@@ -1525,12 +1525,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
diff --git a/include/swift/SIL/SILCloner.h b/include/swift/SIL/SILCloner.h
index 6e05444..55bdc4a 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();
       }
     }
diff --git a/include/swift/SIL/SILFunction.h b/include/swift/SIL/SILFunction.h
index 60e14dd..7bb5e91 100644
--- a/include/swift/SIL/SILFunction.h
+++ b/include/swift/SIL/SILFunction.h
@@ -776,9 +776,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..5fea838 100644
--- a/include/swift/SIL/SILInstruction.h
+++ b/include/swift/SIL/SILInstruction.h
@@ -23,6 +23,7 @@
 #include "swift/AST/TypeAlignments.h"
 #include "swift/Basic/Compiler.h"
 #include "swift/Basic/NullablePtr.h"
+#include "swift/Basic/Range.h"
 #include "swift/SIL/Consumption.h"
 #include "swift/SIL/SILAllocated.h"
 #include "swift/SIL/SILFunctionConventions.h"
@@ -62,21 +63,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 +132,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 +187,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 +242,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 +317,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 +355,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 +413,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 +442,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 +491,185 @@
 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;
+
+  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 +680,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 +687,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 +708,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 +732,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 +741,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 +758,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 +810,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 +840,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 +902,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 +910,7 @@
       public StackPromotable {
 protected:
 
-  AllocRefInstBase(ValueKind Kind,
+  AllocRefInstBase(SILInstructionKind Kind,
                    SILDebugLocation DebugLoc,
                    SILType ObjectType,
                    bool objc, bool canBeOnStack,
@@ -774,7 +968,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 +978,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 +999,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 +1007,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 +1017,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 +1041,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 +1070,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 +1134,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 +1142,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 +1193,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 +1269,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 +1525,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 +1546,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 +1556,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 +1580,6 @@
   CanSILFunctionType getFunctionType() const {
     return getType().castTo<SILFunctionType>();
   }
-
-  static bool classof(const ValueBase *V) {
-    return V->getKind() == ValueKind::PartialApplyInst;
-  }
 };
 
 //===----------------------------------------------------------------------===//
@@ -1410,21 +1587,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 +1627,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 +1993,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 +2036,6 @@
     return const_cast<KeyPathInst*>(this)->getSubstitutions();
   }
   
-  static bool classof(const ValueBase *V) {
-    return V->getKind() == ValueKind::KeyPathInst;
-  }
-  
   void dropReferencedPattern();
   
   ~KeyPathInst();
@@ -1875,7 +2043,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 +2133,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 +2147,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 +2154,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 +2161,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 +2177,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 +2189,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 +2230,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 +2259,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 +2304,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 +2311,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 +2347,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 +2366,8 @@
 
 /// LoadInst - Represents a load from a memory location.
 class LoadInst
-  : public UnaryInstructionBase<ValueKind::LoadInst>
+  : public UnaryInstructionBase<SILInstructionKind::LoadInst,
+                                SingleValueInstruction>
 {
   friend SILBuilder;
 
@@ -2251,7 +2398,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 +2424,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 +2431,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 +2444,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 +2455,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 +2478,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 +2486,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 +2511,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 +2518,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 +2574,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 +2624,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 +2679,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 +2692,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 +2730,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 +2778,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 +2804,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 +2812,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 +2869,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 +2938,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 +2973,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 +3005,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 +3030,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 +3043,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 +3053,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 +3079,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 +3096,7 @@
 
 /// Represents a store to a @weak memory location.
 class StoreWeakInst
-  : public StoreReferenceInstBase<ValueKind::StoreWeakInst>
+  : public StoreReferenceInstBase<SILInstructionKind::StoreWeakInst>
 {
   friend SILBuilder;
 
@@ -2968,7 +3110,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 +3126,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 +3140,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 +3191,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 +3198,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 +3261,6 @@
   MutableArrayRef<Operand> getTypeDependentOperands() {
     return getAllOperands().slice(2);
   }
-
-  static bool classof(const ValueBase *V) {
-    return V->getKind() == ValueKind::BindMemoryInst;
-  }
 };
 
 //===----------------------------------------------------------------------===//
@@ -3133,10 +3270,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 +3282,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 +3306,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 +3320,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 +3337,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 +3357,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 +3368,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 +3395,9 @@
 /// checks.
 class UncheckedRefCastInst final
   : public UnaryInstructionWithTypeDependentOperandsBase<
-                                ValueKind::UncheckedRefCastInst,
+                                SILInstructionKind::UncheckedRefCastInst,
                                 UncheckedRefCastInst,
-                                ConversionInst,
-                                /* HAS_RESULT */ true>
+                                ConversionInst>
 {
   friend SILBuilder;
 
@@ -3277,7 +3414,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 +3444,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 +3466,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 +3486,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 +3504,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 +3536,7 @@
 
 /// Retrieve the bit pattern of a BridgeObject.
 class BridgeObjectToWordInst
-  : public UnaryInstructionBase<ValueKind::BridgeObjectToWordInst,
+  : public UnaryInstructionBase<SILInstructionKind::BridgeObjectToWordInst,
                                 ConversionInst>
 {
   friend SILBuilder;
@@ -3420,7 +3548,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 +3559,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 +3573,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 +3587,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 +3601,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 +3615,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 +3628,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 +3653,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 +3666,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 +3678,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 +3691,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 +3702,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 +3717,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 +3733,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 +3766,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 +3797,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 +3819,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 +3910,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 +3926,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 +3955,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 +3967,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 +3981,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 +3996,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 +4011,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 +4025,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 +4038,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 +4054,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 +4072,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 +4116,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 +4158,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 +4202,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 +4239,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 +4249,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 +4272,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 +4312,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 +4330,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 +4348,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 +4386,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 +4396,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,10 +4436,9 @@
   }
 
 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);
 
   template <typename SELECT_ENUM_INST>
   static SELECT_ENUM_INST *
@@ -4360,7 +4486,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:
@@ -4369,23 +4497,19 @@
   SelectEnumInst(SILDebugLocation DebugLoc, SILValue Operand, SILType Type,
                  SILValue DefaultValue,
                  ArrayRef<std::pair<EnumElementDecl *, SILValue>> CaseValues)
-      : SelectEnumInstBase(ValueKind::SelectEnumInst, DebugLoc, Operand, Type,
-                           DefaultValue, CaseValues) {}
+      : InstructionBase(DebugLoc, Type, Operand, DefaultValue, CaseValues) {}
 
   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;
-  }
 };
 
 /// 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;
 
@@ -4393,23 +4517,19 @@
       SILDebugLocation DebugLoc, SILValue Operand, SILType Type,
       SILValue DefaultValue,
       ArrayRef<std::pair<EnumElementDecl *, SILValue>> CaseValues)
-      : SelectEnumInstBase(ValueKind::SelectEnumAddrInst, DebugLoc, Operand,
-                           Type, DefaultValue, CaseValues) {}
+      : InstructionBase(DebugLoc, Type, Operand, DefaultValue, CaseValues) {}
 
   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;
-  }
 };
 
 /// 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 +4558,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 +4602,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 +4618,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 +4630,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 +4660,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 +4682,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 +4725,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 +4760,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 +4795,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 +4815,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 +4829,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 +4850,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 +4863,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 +4877,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 +4921,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 +4929,9 @@
 /// can fail at run-time
 class DynamicMethodInst final
   : public UnaryInstructionWithTypeDependentOperandsBase<
-                                   ValueKind::DynamicMethodInst,
+                                   SILInstructionKind::DynamicMethodInst,
                                    DynamicMethodInst,
-                                   MethodInst,
-                                   true>
+                                   MethodInst>
 {
   friend SILBuilder;
 
@@ -4844,7 +4958,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 +4975,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 +4987,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 +5001,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 +5014,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 +5026,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 +5041,9 @@
 /// concrete value inside the existential container.
 class InitExistentialAddrInst final
   : public UnaryInstructionWithTypeDependentOperandsBase<
-                                ValueKind::InitExistentialAddrInst,
+                                SILInstructionKind::InitExistentialAddrInst,
                                 InitExistentialAddrInst,
-                                SILInstruction,
-                                true>
+                                SingleValueInstruction>
 {
   friend SILBuilder;
 
@@ -4966,8 +5085,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 +5119,9 @@
 /// class instance.
 class InitExistentialRefInst final
   : public UnaryInstructionWithTypeDependentOperandsBase<
-                                ValueKind::InitExistentialRefInst,
+                                SILInstructionKind::InitExistentialRefInst,
                                 InitExistentialRefInst,
-                                SILInstruction,
-                                true>
+                                SingleValueInstruction>
 {
   friend SILBuilder;
 
@@ -5042,10 +5160,9 @@
 /// the metatype.
 class InitExistentialMetatypeInst final
   : public UnaryInstructionWithTypeDependentOperandsBase<
-                                  ValueKind::InitExistentialMetatypeInst,
+                                  SILInstructionKind::InitExistentialMetatypeInst,
                                   InitExistentialMetatypeInst,
-                                  SILInstruction,
-                                  true,
+                                  SingleValueInstruction,
                                   ProtocolConformanceRef>
 {
   friend SILBuilder;
@@ -5088,9 +5205,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 +5215,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 +5225,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 +5238,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 +5257,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 +5280,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 +5302,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 +5319,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 +5333,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 +5347,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 +5362,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 +5385,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 +5399,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 +5416,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 +5434,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 +5448,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 +5458,8 @@
 };
 
 class CopyUnownedValueInst
-    : public UnaryInstructionBase<ValueKind::CopyUnownedValueInst> {
+    : public UnaryInstructionBase<SILInstructionKind::CopyUnownedValueInst,
+                                  SingleValueInstruction> {
   friend class SILBuilder;
 
   CopyUnownedValueInst(SILDebugLocation DebugLoc, SILValue operand,
@@ -5356,7 +5469,8 @@
 };
 
 class DestroyValueInst
-    : public UnaryInstructionBase<ValueKind::DestroyValueInst> {
+    : public UnaryInstructionBase<SILInstructionKind::DestroyValueInst,
+                                  NonValueInstruction> {
   friend class SILBuilder;
 
   DestroyValueInst(SILDebugLocation DebugLoc, SILValue operand)
@@ -5365,7 +5479,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 +5492,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 +5507,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 +5535,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 +5556,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 +5566,7 @@
 
   DeallocPartialRefInst(SILDebugLocation DebugLoc, SILValue Operand,
                         SILValue Metatype)
-      : DeallocationInst(ValueKind::DeallocPartialRefInst, DebugLoc),
+      : InstructionBase(DebugLoc),
         Operands(this, Operand, Metatype) {}
 
 public:
@@ -5459,16 +5575,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 +5599,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 +5615,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 +5637,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 +5649,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 +5663,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 +5683,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 +5698,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 +5713,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 +5728,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 +5765,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 +5783,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 +5805,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 +5834,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 +5861,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 +5881,9 @@
 };
 
 /// BranchInst - An unconditional branch.
-class BranchInst : public TermInst {
+class BranchInst
+    : public InstructionBase<SILInstructionKind::BranchInst,
+                             TermInst> {
   friend SILBuilder;
 
   SILSuccessor DestBB;
@@ -5847,14 +5919,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:
@@ -5967,14 +6037,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 +6103,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,7 +6139,7 @@
 
 protected:
   SwitchEnumInstBase(
-      ValueKind Kind, SILDebugLocation DebugLoc, SILValue Operand,
+      SILInstructionKind Kind, SILDebugLocation DebugLoc, SILValue Operand,
       SILBasicBlock *DefaultBB,
       ArrayRef<std::pair<EnumElementDecl *, SILBasicBlock *>> CaseBBs);
 
@@ -6134,15 +6198,17 @@
     return getSuccessorBuf()[NumCases];
   }
 
-  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:
@@ -6151,22 +6217,18 @@
   SwitchEnumInst(
       SILDebugLocation DebugLoc, SILValue Operand, SILBasicBlock *DefaultBB,
       ArrayRef<std::pair<EnumElementDecl *, SILBasicBlock *>> CaseBBs)
-      : SwitchEnumInstBase(ValueKind::SwitchEnumInst, DebugLoc, Operand,
-                           DefaultBB, CaseBBs) {}
+      : InstructionBase(DebugLoc, Operand, DefaultBB, CaseBBs) {}
 
   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;
-  }
 };
 
 /// A switch on an enum's discriminator in memory.
-class SwitchEnumAddrInst : public SwitchEnumInstBase {
+class SwitchEnumAddrInst
+    : public InstructionBase<SILInstructionKind::SwitchEnumAddrInst,
+                             SwitchEnumInstBase> {
   friend SILBuilder;
 
 private:
@@ -6175,18 +6237,12 @@
   SwitchEnumAddrInst(
       SILDebugLocation DebugLoc, SILValue Operand, SILBasicBlock *DefaultBB,
       ArrayRef<std::pair<EnumElementDecl *, SILBasicBlock *>> CaseBBs)
-      : SwitchEnumInstBase(ValueKind::SwitchEnumAddrInst, DebugLoc, Operand,
-                           DefaultBB, CaseBBs) {}
+      : InstructionBase(DebugLoc, Operand, DefaultBB, CaseBBs) {}
 
   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;
-  }
 };
 
 /// Branch on the existence of an Objective-C method in the dynamic type of
@@ -6194,7 +6250,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 +6289,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 +6296,9 @@
 /// argument.
 class CheckedCastBranchInst final:
   public UnaryInstructionWithTypeDependentOperandsBase<
-                              ValueKind::CheckedCastBranchInst,
+                              SILInstructionKind::CheckedCastBranchInst,
                               CheckedCastBranchInst,
-                              TermInst,
-                              false> {
+                              TermInst> {
   friend SILBuilder;
 
   SILType DestTy;
@@ -6293,10 +6346,6 @@
   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::CheckedCastBranchInst;
-  }
 };
 
 /// Perform a checked cast operation and branch on whether the cast succeeds.
@@ -6304,8 +6353,9 @@
 /// argument.
 class CheckedCastValueBranchInst final
     : public UnaryInstructionWithTypeDependentOperandsBase<
-          ValueKind::CheckedCastValueBranchInst, CheckedCastValueBranchInst,
-          TermInst, false> {
+          SILInstructionKind::CheckedCastValueBranchInst,
+          CheckedCastValueBranchInst,
+          TermInst> {
   friend SILBuilder;
 
   SILType DestTy;
@@ -6346,15 +6396,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;
@@ -6375,7 +6423,7 @@
                             CastConsumptionKind consumptionKind, SILValue src,
                             CanType srcType, SILValue dest, CanType targetType,
                             SILBasicBlock *successBB, SILBasicBlock *failureBB)
-      : TermInst(ValueKind::CheckedCastAddrBranchInst, DebugLoc),
+      : InstructionBase(DebugLoc),
         ConsumptionKind(consumptionKind), Operands{this, src, dest},
         DestBBs{{this, successBB}, {this, failureBB}}, SourceType(srcType),
         TargetType(targetType) {}
@@ -6403,10 +6451,6 @@
   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::CheckedCastAddrBranchInst;
-  }
 };
 
 /// A private abstract class to store the destinations of a TryApplyInst.
@@ -6421,7 +6465,7 @@
   SILSuccessor DestBBs[2];
 
 protected:
-  TryApplyInstBase(ValueKind valueKind, SILDebugLocation Loc,
+  TryApplyInstBase(SILInstructionKind valueKind, SILDebugLocation Loc,
                    SILBasicBlock *normalBB, SILBasicBlock *errorBB);
 
 public:
@@ -6447,7 +6491,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 +6508,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 +6519,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 +6531,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 +6556,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 +6676,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 +6692,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 +6729,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 +6741,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 +6753,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 +6777,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 +6790,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 +6827,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..881d245 100644
--- a/include/swift/SIL/SILModule.h
+++ b/include/swift/SIL/SILModule.h
@@ -248,7 +248,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;
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/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..23d47fd 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(
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/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp
index 872ad2a..66a8338 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/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/GenMeta.cpp b/lib/IRGen/GenMeta.cpp
index 174a627..c9dc1ca 100644
--- a/lib/IRGen/GenMeta.cpp
+++ b/lib/IRGen/GenMeta.cpp
@@ -1684,7 +1684,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 +1866,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:
diff --git a/lib/IRGen/GenReflection.cpp b/lib/IRGen/GenReflection.cpp
index 5e4d832..98ece80 100644
--- a/lib/IRGen/GenReflection.cpp
+++ b/lib/IRGen/GenReflection.cpp
@@ -928,7 +928,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/IRGenSIL.cpp b/lib/IRGen/IRGenSIL.cpp
index 9252938..160af70 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);
 
@@ -3456,7 +3456,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 +3692,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/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/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/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..6916902 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,24 @@
 
   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));
+    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..560a0a6 100644
--- a/lib/SIL/SILFunction.cpp
+++ b/lib/SIL/SILFunction.cpp
@@ -139,15 +139,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/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..e893366 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,
@@ -1091,7 +1087,7 @@
                                SILBasicBlock *TrueBB, SILBasicBlock *FalseBB,
                                ArrayRef<SILValue> Args, unsigned NumTrue,
                                unsigned NumFalse)
-    : TermInst(ValueKind::CondBranchInst, Loc),
+    : InstructionBase(Loc),
       DestBBs{{this, TrueBB}, {this, FalseBB}}, NumTrueArgs(NumTrue),
       NumFalseArgs(NumFalse), Operands(this, Args, Condition) {
   assert(Args.size() == (NumTrueArgs + NumFalseArgs) &&
@@ -1209,7 +1205,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 +1277,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,8 +1329,8 @@
 }
 
 SelectEnumInstBase::SelectEnumInstBase(
-    ValueKind Kind, SILDebugLocation Loc, SILValue Operand, SILType Ty,
-    SILValue DefaultValue,
+    SILInstructionKind Kind, SILDebugLocation Loc,
+    SILType Ty, SILValue Operand, SILValue DefaultValue,
     ArrayRef<std::pair<EnumElementDecl *, SILValue>> CaseValues)
     : SelectInstBase(Kind, Loc, Ty, CaseValues.size(), bool(DefaultValue),
                      getCaseOperands(CaseValues, DefaultValue), Operand) {
@@ -1381,7 +1377,7 @@
 }
 
 SwitchEnumInstBase::SwitchEnumInstBase(
-    ValueKind Kind, SILDebugLocation Loc, SILValue Operand,
+    SILInstructionKind Kind, SILDebugLocation Loc, SILValue Operand,
     SILBasicBlock *DefaultBB,
     ArrayRef<std::pair<EnumElementDecl *, SILBasicBlock *>> CaseBBs)
     : TermInst(Kind, Loc), Operands(this, Operand), NumCases(CaseBBs.size()),
@@ -1555,7 +1551,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 +1756,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())
@@ -2223,7 +2219,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..777d3f8 100644
--- a/lib/SIL/SILModule.cpp
+++ b/lib/SIL/SILModule.cpp
@@ -734,9 +734,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..6cba643 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.
@@ -644,7 +643,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 +658,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 +686,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 +839,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 +959,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;
@@ -1657,6 +1707,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());
   }
@@ -1985,11 +2040,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);
 }
@@ -2429,10 +2497,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 +2855,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 +2871,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/SILGenDecl.cpp b/lib/SILGen/SILGenDecl.cpp
index 83c3554..ecc58e1 100644
--- a/lib/SILGen/SILGenDecl.cpp
+++ b/lib/SILGen/SILGenDecl.cpp
@@ -386,7 +386,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.
diff --git a/lib/SILGen/SILGenThunk.cpp b/lib/SILGen/SILGenThunk.cpp
index ea598d3..4d1d9ab 100644
--- a/lib/SILGen/SILGenThunk.cpp
+++ b/lib/SILGen/SILGenThunk.cpp
@@ -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);
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..05163cf 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,
@@ -677,11 +677,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 +813,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 +849,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 +1045,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 +1178,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..b94b6f2 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) {
@@ -387,7 +387,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..93ba678 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();
 
@@ -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..2d9fcde 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);
       }
     }
   }
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..cf413e4 100644
--- a/lib/SILOptimizer/PassManager/PassManager.cpp
+++ b/lib/SILOptimizer/PassManager/PassManager.cpp
@@ -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..e96f9f7 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,
@@ -811,7 +813,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..4fa55bd 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)
@@ -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..dc1fe7b 100644
--- a/lib/SILOptimizer/Transforms/PerformanceInliner.cpp
+++ b/lib/SILOptimizer/Transforms/PerformanceInliner.cpp
@@ -253,7 +253,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;
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..2199f10 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);
@@ -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));
@@ -2651,7 +2653,7 @@
     NewArgumentValues.push_back(NewArg);
   }
 
-  SILInstruction *Agg = nullptr;
+  SingleValueInstruction *Agg;
 
   {
     SILBuilder B(ParentBB->begin());
@@ -2663,7 +2665,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 +3142,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 +3391,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 +3412,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 +3423,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/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/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/Generics.cpp b/lib/SILOptimizer/Utils/Generics.cpp
index d4eb458..b2fa942 100644
--- a/lib/SILOptimizer/Utils/Generics.cpp
+++ b/lib/SILOptimizer/Utils/Generics.cpp
@@ -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..3f23321 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);
 }
 
@@ -444,7 +442,7 @@
     auto *Inst = &BB->back();
 
     // Replace any still-remaining uses with undef values and erase.
-    Inst->replaceAllUsesWithUndef();
+    Inst->replaceAllUsesOfAllResultsWithUndef();
     Inst->eraseFromParent();
   }
 }
@@ -673,7 +671,7 @@
   /// concatenation of string literals.
   ///
   /// Returns a new instruction if optimization was possible.
-  SILInstruction *optimize();
+  SingleValueInstruction *optimize();
 };
 
 } // end anonymous namespace
@@ -834,7 +832,7 @@
   return IsAsciiLeft && IsAsciiRight;
 }
 
-SILInstruction *StringConcatenationOptimizer::optimize() {
+SingleValueInstruction *StringConcatenationOptimizer::optimize() {
   // Bail out if string literals concatenation optimization is
   // not possible.
   if (!extractStringConcatOperands())
@@ -880,7 +878,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 +889,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 +1077,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 +1107,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 +1452,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 +1746,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 +1779,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 +1815,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 +2108,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 +2196,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 {
@@ -2538,10 +2538,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 +2573,6 @@
   EraseInstAction(Inst);
   WillSucceedAction();
   return Result;
-
-  return nullptr;
 }
 
 /// Deletes all instructions after \p UnreachableInst except dealloc_stack
@@ -2590,7 +2590,7 @@
         DeallocStack->moveBefore(TrapInst);
         continue;
       }
-    CurInst->replaceAllUsesWithUndef();
+    CurInst->replaceAllUsesOfAllResultsWithUndef();
     EraseInstAction(CurInst);
   }
 }
@@ -2679,7 +2679,6 @@
         }
         };
 
-        Inst->replaceAllUsesWithUndef();
         return true;
       }
     }
@@ -2725,7 +2724,6 @@
                           StoreOwnershipQualifier::Unqualified);
     }
     auto *TrapI = Builder.createBuiltinTrap(Loc);
-    Inst->replaceAllUsesWithUndef();
     EraseInstAction(Inst);
     Builder.setInsertionPoint(std::next(SILBasicBlock::iterator(TrapI)));
     auto *UnreachableInst =
@@ -2802,7 +2800,6 @@
       return nullptr;
     }
 
-    Inst->replaceAllUsesWithUndef();
     EraseInstAction(Inst);
     WillSucceedAction();
   }
@@ -2810,21 +2807,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 +2872,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 +2924,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 +3029,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/Serialization/DeserializeSIL.cpp b/lib/Serialization/DeserializeSIL.cpp
index 4000929..e41e338 100644
--- a/lib/Serialization/DeserializeSIL.cpp
+++ b/lib/Serialization/DeserializeSIL.cpp
@@ -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/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/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/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/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/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/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/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/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/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/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/CMakeLists.txt b/tools/SourceKit/CMakeLists.txt
index 0ba6c2a..9ac9b80 100644
--- a/tools/SourceKit/CMakeLists.txt
+++ b/tools/SourceKit/CMakeLists.txt
@@ -1,5 +1,9 @@
 include(CheckSymbolExists)
 
+# Append our own modules to the module path.
+list(APPEND CMAKE_MODULE_PATH
+    "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules")
+
 if (DARWIN_TOOLCHAIN_VERSION)
   set(SOURCEKIT_VERSION_STRING "${DARWIN_TOOLCHAIN_VERSION}")
 else()
@@ -28,441 +32,8 @@
   set(CMAKE_OSX_DEPLOYMENT_TARGET "")
 endif()
 
-function(add_sourcekit_symbol_exports target_name export_file)
-  # Makefile.rules contains special cases for different platforms.
-  # We restrict ourselves to Darwin for the time being.
-  if("${CMAKE_SYSTEM_NAME}" STREQUAL "Darwin")
-    add_custom_command(OUTPUT symbol.exports
-      COMMAND sed -e "s/^/_/" < ${export_file} > symbol.exports
-      DEPENDS ${export_file}
-      VERBATIM
-      COMMENT "Creating export file for ${target_name}")
-    add_custom_target(${target_name}_exports DEPENDS symbol.exports)
-    set_property(DIRECTORY APPEND
-      PROPERTY ADDITIONAL_MAKE_CLEAN_FILES symbol.exports)
-
-    get_property(srcs TARGET ${target_name} PROPERTY SOURCES)
-    foreach(src ${srcs})
-      get_filename_component(extension ${src} EXT)
-      if(extension STREQUAL ".cpp")
-        set(first_source_file ${src})
-        break()
-      endif()
-    endforeach()
-
-    # Force re-linking when the exports file changes. Actually, it
-    # forces recompilation of the source file. The LINK_DEPENDS target
-    # property only works for makefile-based generators.
-    set_property(SOURCE ${first_source_file} APPEND PROPERTY
-      OBJECT_DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/symbol.exports)
-
-    set_property(TARGET ${target_name} APPEND_STRING PROPERTY
-                 LINK_FLAGS " -Wl,-exported_symbols_list,${CMAKE_CURRENT_BINARY_DIR}/symbol.exports")
-
-    add_dependencies(${target_name} ${target_name}_exports)
-  endif()
-endfunction()
-
-# Add default compiler and linker flags to 'target'.
-#
-# FIXME: this is a HACK.  All SourceKit CMake code using this function
-# should be rewritten to use 'add_swift_library'.
-function(add_sourcekit_default_compiler_flags target)
-  set(sdk "${SWIFT_HOST_VARIANT_SDK}")
-  set(arch "${SWIFT_HOST_VARIANT_ARCH}")
-  set(c_compile_flags)
-  set(link_flags)
-
-  # Add variant-specific flags.
-  set(build_type "${CMAKE_BUILD_TYPE}")
-  set(enable_assertions "${LLVM_ENABLE_ASSERTIONS}")
-  set(analyze_code_coverage "${SWIFT_ANALYZE_CODE_COVERAGE}")
-  _add_variant_c_compile_flags(
-    SDK "${sdk}"
-    ARCH "${arch}"
-    BUILD_TYPE "${build_type}"
-    ENABLE_ASSERTIONS "${enable_assertions}"
-    ANALYZE_CODE_COVERAGE "${analyze_code_coverage}"
-    ENABLE_LTO "${SWIFT_TOOLS_ENABLE_LTO}"
-    RESULT_VAR_NAME c_compile_flags)
-  _add_variant_link_flags(
-    SDK "${sdk}"
-    ARCH "${arch}"
-    BUILD_TYPE "${build_type}"
-    ENABLE_ASSERTIONS "${enable_assertions}"
-    ENABLE_LTO "${SWIFT_TOOLS_ENABLE_LTO}"
-    LTO_OBJECT_NAME "${target}-${sdk}-${arch}"
-    ANALYZE_CODE_COVERAGE "${analyze_code_coverage}"
-    RESULT_VAR_NAME link_flags)
-
-  if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux")
-    list(APPEND c_compile_flags "-fblocks")
-    list(APPEND link_flags "-lBlocksRuntime")
-  endif()
-
-  # Convert variables to space-separated strings.
-  _list_escape_for_shell("${c_compile_flags}" c_compile_flags)
-  _list_escape_for_shell("${link_flags}" link_flags)
-
-  # Set compilation and link flags.
-  set_property(TARGET "${target}" APPEND_STRING PROPERTY
-      COMPILE_FLAGS " ${c_compile_flags}")
-  set_property(TARGET "${target}" APPEND_STRING PROPERTY
-      LINK_FLAGS " ${link_flags}")
-endfunction()
-
-# Add a new SourceKit library.
-#
-# Usage:
-#   add_sourcekit_library(name     # Name of the library
-#     [LINK_LIBS dep1 ...]         # Libraries this library will be linked with
-#     [DEPENDS dep1 ...]           # Targets this library depends on
-#     [LLVM_COMPONENT_DEPENDS comp1 ...]  # LLVM components this library depends on
-#     [INSTALL_IN_COMPONENT comp]  # The Swift installation component that this library belongs to.
-#     [SHARED]
-#     source1 [source2 source3 ...]) # Sources to add into this library
-macro(add_sourcekit_library name)
-  cmake_parse_arguments(SOURCEKITLIB
-      "SHARED"
-      "INSTALL_IN_COMPONENT"
-      "LINK_LIBS;DEPENDS;LLVM_COMPONENT_DEPENDS"
-      ${ARGN})
-  set(srcs ${SOURCEKITLIB_UNPARSED_ARGUMENTS})
-
-  llvm_process_sources(srcs ${srcs})
-  if(MSVC_IDE OR XCODE)
-    # Add public headers
-    file(RELATIVE_PATH lib_path
-      ${SOURCEKIT_SOURCE_DIR}/lib/
-      ${CMAKE_CURRENT_SOURCE_DIR}
-    )
-    if(NOT lib_path MATCHES "^[.][.]")
-      file(GLOB_RECURSE headers
-        ${SOURCEKIT_SOURCE_DIR}/include/SourceKit/${lib_path}/*.h
-        ${SOURCEKIT_SOURCE_DIR}/include/SourceKit/${lib_path}/*.def
-      )
-      set_source_files_properties(${headers} PROPERTIES HEADER_FILE_ONLY ON)
-
-      file(GLOB_RECURSE tds
-        ${SOURCEKIT_SOURCE_DIR}/include/SourceKit/${lib_path}/*.td
-      )
-      source_group("TableGen descriptions" FILES ${tds})
-      set_source_files_properties(${tds} PROPERTIES HEADER_FILE_ONLY ON)
-
-      set(srcs ${srcs} ${headers} ${tds})
-    endif()
-  endif()
-  if (MODULE)
-    set(libkind MODULE)
-  elseif(SOURCEKITLIB_SHARED)
-    set(libkind SHARED)
-  else()
-    set(libkind)
-  endif()
-  add_library(${name} ${libkind} ${srcs})
-  llvm_update_compile_flags(${name})
-
-  set_output_directory(${name}
-      BINARY_DIR ${SOURCEKIT_RUNTIME_OUTPUT_INTDIR}
-      LIBRARY_DIR ${SOURCEKIT_LIBRARY_OUTPUT_INTDIR})
-
-  if(LLVM_COMMON_DEPENDS)
-    add_dependencies(${name} ${LLVM_COMMON_DEPENDS})
-  endif(LLVM_COMMON_DEPENDS)
-
-  if(SOURCEKITLIB_DEPENDS)
-    add_dependencies(${name} ${SOURCEKITLIB_DEPENDS})
-  endif(SOURCEKITLIB_DEPENDS)
-
-  set(prefixed_link_libraries)
-  foreach(dep ${SOURCEKITLIB_LINK_LIBS})
-    if("${dep}" MATCHES "^clang")
-      set(dep "${LLVM_LIBRARY_OUTPUT_INTDIR}/lib${dep}.a")
-    endif()
-    list(APPEND prefixed_link_libraries "${dep}")
-  endforeach()
-  set(SOURCEKITLIB_LINK_LIBS "${prefixed_link_libraries}")
-
-  if("${libkind}" STREQUAL "SHARED")
-    target_link_libraries("${name}" PRIVATE ${SOURCEKITLIB_LINK_LIBS})
-  else()
-    target_link_libraries("${name}" INTERFACE ${SOURCEKITLIB_LINK_LIBS})
-  endif()
-
-  swift_common_llvm_config(${name} ${SOURCEKITLIB_LLVM_COMPONENT_DEPENDS})
-
-  if(SOURCEKITLIB_SHARED AND EXPORTED_SYMBOL_FILE)
-    add_sourcekit_symbol_exports(${name} ${EXPORTED_SYMBOL_FILE})
-  endif()
-
-  if("${CMAKE_SYSTEM_NAME}" STREQUAL "Darwin")
-    if(SOURCEKITLIB_SHARED)
-      set_target_properties(${name} PROPERTIES BUILD_WITH_INSTALL_RPATH TRUE)
-      set_target_properties(${name} PROPERTIES INSTALL_NAME_DIR "@rpath")
-    endif()
-  endif()
-
-  if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux")
-    if(SOURCEKITLIB_SHARED)
-      set_target_properties(${name} PROPERTIES BUILD_WITH_INSTALL_RPATH TRUE)
-      set_target_properties(${name} PROPERTIES INSTALL_RPATH "$ORIGIN/../lib/swift/linux:/usr/lib/swift/linux")
-    endif()
-  endif()
-
-  if("${SOURCEKITLIB_INSTALL_IN_COMPONENT}" STREQUAL "")
-    if(SOURCEKITLIB_SHARED)
-      set(SOURCEKITLIB_INSTALL_IN_COMPONENT tools)
-    else()
-      set(SOURCEKITLIB_INSTALL_IN_COMPONENT dev)
-    endif()
-  endif()
-  swift_install_in_component("${SOURCEKITLIB_INSTALL_IN_COMPONENT}"
-      TARGETS ${name}
-      LIBRARY DESTINATION "lib${LLVM_LIBDIR_SUFFIX}"
-      ARCHIVE DESTINATION "lib${LLVM_LIBDIR_SUFFIX}"
-      RUNTIME DESTINATION "bin")
-  set_target_properties(${name} PROPERTIES FOLDER "SourceKit libraries")
-  add_sourcekit_default_compiler_flags("${name}")
-endmacro()
-
-# Add a new SourceKit executable.
-#
-# Usage:
-#   add_sourcekit_executable(name        # Name of the executable
-#     [LINK_LIBS dep1 ...]               # Libraries this executable depends on
-#     [LLVM_COMPONENT_DEPENDS comp1 ...] # LLVM components this executable
-#                                        # depends on
-#     [EXCLUDE_FROM_ALL]              # Whether to exclude this executable from
-#                                     # the ALL_BUILD target
-#     source1 [source2 source3 ...])  # Sources to add into this executable
-macro(add_sourcekit_executable name)
-  cmake_parse_arguments(SOURCEKITEXE
-    "EXCLUDE_FROM_ALL"
-    ""
-    "LINK_LIBS;LLVM_COMPONENT_DEPENDS"
-    ${ARGN})
-
-  if (${SOURCEKITEXE_EXCLUDE_FROM_ALL})
-    add_executable(${name} EXCLUDE_FROM_ALL ${SOURCEKITEXE_UNPARSED_ARGUMENTS})
-  else()
-    add_executable(${name} ${SOURCEKITEXE_UNPARSED_ARGUMENTS})
-  endif()
-  llvm_update_compile_flags(${name})
-  set_output_directory(${name}
-      BINARY_DIR ${SOURCEKIT_RUNTIME_OUTPUT_INTDIR}
-      LIBRARY_DIR ${SOURCEKIT_LIBRARY_OUTPUT_INTDIR})
-
-  # Add appropriate dependencies
-  if(LLVM_COMMON_DEPENDS)
-    add_dependencies(${name} ${LLVM_COMMON_DEPENDS})
-  endif()
-
-  target_link_libraries(${name} ${SOURCEKITEXE_LINK_LIBS})
-  swift_common_llvm_config(${name} ${SOURCEKITEXE_LLVM_COMPONENT_DEPENDS})
-  target_link_libraries(${name} ${LLVM_COMMON_LIBS})
-
-  set_target_properties(${name} PROPERTIES FOLDER "SourceKit executables")
-  if (NOT SWIFT_ASAN_BUILD)
-    if("${CMAKE_SYSTEM_NAME}" STREQUAL "Darwin")
-      set_target_properties(${name}
-        PROPERTIES
-        LINK_FLAGS "-Wl,-exported_symbol,_main")
-    endif()
-    if(SWIFT_ANALYZE_CODE_COVERAGE)
-      set_property(TARGET "${name}" APPEND_STRING PROPERTY
-        LINK_FLAGS " -fprofile-instr-generate -fcoverage-mapping")
-    endif()
-  endif()
-  add_sourcekit_default_compiler_flags("${name}")
-endmacro()
-
-# Add a new SourceKit framework.
-#
-# Usage:
-#   add_sourcekit_framework(name     # Name of the framework
-#     [LINK_LIBS dep1 ...]           # Libraries this framework will link with
-#     [LLVM_COMPONENT_DEPENDS comp1 ...]  # LLVM components this framework depends on
-#     [MODULEMAP modulemap]          # Module map file for this framework
-#     [INSTALL_IN_COMPONENT comp]    # The Swift installation component that this framework belongs to.
-#     source1 [source2 source3 ...]) # Sources to add into this framework
-macro(add_sourcekit_framework name)
-  cmake_parse_arguments(SOURCEKITFW
-    "" "MODULEMAP;INSTALL_IN_COMPONENT" "LINK_LIBS;LLVM_COMPONENT_DEPENDS" ${ARGN})
-  set(srcs ${SOURCEKITFW_UNPARSED_ARGUMENTS})
-
-  set(lib_dir ${SOURCEKIT_LIBRARY_OUTPUT_INTDIR})
-  set(framework_location "${lib_dir}/${name}.framework")
-
-  if (NOT SOURCEKIT_DEPLOYMENT_OS MATCHES "^macosx")
-    set(FLAT_FRAMEWORK_NAME "${name}")
-    set(FLAT_FRAMEWORK_IDENTIFIER "com.apple.${name}")
-    set(FLAT_FRAMEWORK_SHORT_VERSION_STRING "1.0")
-    set(FLAT_FRAMEWORK_BUNDLE_VERSION "${SOURCEKIT_VERSION_STRING}")
-    set(FLAT_FRAMEWORK_DEPLOYMENT_TARGET "${SOURCEKIT_DEPLOYMENT_TARGET}")
-    configure_file(
-      "${SOURCEKIT_SOURCE_DIR}/cmake/FlatFrameworkInfo.plist.in"
-      "${CMAKE_CURRENT_BINARY_DIR}/${name}.Info.plist")
-    add_custom_command(OUTPUT "${framework_location}/Info.plist"
-      DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/${name}.Info.plist"
-      COMMAND ${CMAKE_COMMAND} -E copy_if_different
-      "${CMAKE_CURRENT_BINARY_DIR}/${name}.Info.plist" "${framework_location}/Info.plist")
-    list(APPEND srcs "${framework_location}/Info.plist")
-  endif()
-
-  llvm_process_sources(srcs ${srcs})
-  add_library(${name} SHARED ${srcs})
-  llvm_update_compile_flags(${name})
-
-  set(headers)
-  foreach(src ${srcs})
-    get_filename_component(extension ${src} EXT)
-    if(extension STREQUAL ".h")
-      list(APPEND headers ${src})
-    endif()
-  endforeach()
-
-  if(MSVC_IDE OR XCODE)
-    set_source_files_properties(${headers} PROPERTIES HEADER_FILE_ONLY ON)
-  endif(MSVC_IDE OR XCODE)
-
-  if(LLVM_COMMON_DEPENDS)
-    add_dependencies(${name} ${LLVM_COMMON_DEPENDS})
-  endif(LLVM_COMMON_DEPENDS)
-
-  target_link_libraries(${name} PRIVATE ${SOURCEKITFW_LINK_LIBS})
-  swift_common_llvm_config(${name} ${SOURCEKITFW_LLVM_COMPONENT_DEPENDS})
-
-  if (EXPORTED_SYMBOL_FILE)
-    add_sourcekit_symbol_exports(${name} ${EXPORTED_SYMBOL_FILE})
-  endif()
-
-  if(SOURCEKITFW_MODULEMAP)
-    set(modulemap "${CMAKE_CURRENT_SOURCE_DIR}/${SOURCEKITFW_MODULEMAP}")
-    if (SOURCEKIT_DEPLOYMENT_OS MATCHES "^macosx")
-      set(modules_dir "${framework_location}/Versions/A/Modules")
-      add_custom_command(TARGET ${name} PRE_BUILD
-        COMMAND ${CMAKE_COMMAND} -E copy "${modulemap}" "${modules_dir}/module.modulemap"
-        COMMAND ${CMAKE_COMMAND} -E create_symlink "Versions/Current/Modules" "${framework_location}/Modules")
-    else()
-      set(modules_dir "${framework_location}/Modules")
-      add_custom_command(TARGET ${name} PRE_BUILD
-        COMMAND ${CMAKE_COMMAND} -E copy "${modulemap}" "${modules_dir}/module.modulemap")
-    endif()
-  endif()
-
-
-  if (SOURCEKIT_DEPLOYMENT_OS MATCHES "^macosx")
-    swift_install_in_component(${SOURCEKITFW_INSTALL_IN_COMPONENT}
-        TARGETS ${name}
-        LIBRARY DESTINATION lib${LLVM_LIBDIR_SUFFIX}
-        ARCHIVE DESTINATION lib${LLVM_LIBDIR_SUFFIX}
-        RUNTIME DESTINATION bin)
-    set_target_properties(${name} PROPERTIES FOLDER "SourceKit frameworks")
-    set_output_directory(${name}
-        BINARY_DIR ${SOURCEKIT_RUNTIME_OUTPUT_INTDIR}
-        LIBRARY_DIR ${SOURCEKIT_LIBRARY_OUTPUT_INTDIR})
-    set_target_properties(${name} PROPERTIES FRAMEWORK TRUE)
-    set_target_properties(${name} PROPERTIES PUBLIC_HEADER "${headers}")
-    set_target_properties(${name} PROPERTIES MACOSX_FRAMEWORK_INFO_PLIST "${SOURCEKIT_SOURCE_DIR}/cmake/MacOSXFrameworkInfo.plist.in")
-    set_target_properties(${name} PROPERTIES MACOSX_FRAMEWORK_IDENTIFIER "com.apple.${name}")
-    set_target_properties(${name} PROPERTIES MACOSX_FRAMEWORK_SHORT_VERSION_STRING "1.0")
-    set_target_properties(${name} PROPERTIES MACOSX_FRAMEWORK_BUNDLE_VERSION "${SOURCEKIT_VERSION_STRING}")
-    set_target_properties(${name} PROPERTIES BUILD_WITH_INSTALL_RPATH TRUE)
-    set_target_properties(${name} PROPERTIES INSTALL_NAME_DIR "@rpath")
-  else()
-    swift_install_in_component(${SOURCEKITFW_INSTALL_IN_COMPONENT}
-        DIRECTORY ${framework_location}
-        DESTINATION lib${LLVM_LIBDIR_SUFFIX}
-        USE_SOURCE_PERMISSIONS)
-    set_target_properties(${name} PROPERTIES FOLDER "SourceKit frameworks")
-    set_output_directory(${name}
-        BINARY_DIR ${framework_location}
-        LIBRARY_DIR ${framework_location})
-    set_target_properties(${name} PROPERTIES PREFIX "")
-    set_target_properties(${name} PROPERTIES SUFFIX "")
-    set_target_properties(${name} PROPERTIES BUILD_WITH_INSTALL_RPATH TRUE)
-    set_target_properties(${name} PROPERTIES INSTALL_NAME_DIR "@rpath/${name}.framework")
-
-    foreach(hdr ${headers})
-      get_filename_component(hdrname ${hdr} NAME)
-      add_custom_command(TARGET ${name} PRE_BUILD
-        COMMAND ${CMAKE_COMMAND} -E copy "${hdr}" "${framework_location}/Headers/${hdrname}")
-    endforeach()
-  endif()
-  add_sourcekit_default_compiler_flags("${name}")
-endmacro(add_sourcekit_framework)
-
-# Add a new SourceKit XPC service to a framework.
-#
-# Usage:
-#   add_sourcekit_xpc_service(name      # Name of the XPC service
-#     [LINK_LIBS dep1 ...]              # Libraries this service will link with
-#     [LLVM_COMPONENT_DEPENDS comp1 ...]   # LLVM components this service depends on
-#     source1 [source2 source3 ...])    # Sources to add into this service
-macro(add_sourcekit_xpc_service name framework_target)
-  cmake_parse_arguments(SOURCEKITXPC "" "" "LINK_LIBS;LLVM_COMPONENT_DEPENDS" ${ARGN})
-  set(srcs ${SOURCEKITXPC_UNPARSED_ARGUMENTS})
-
-  set(lib_dir ${SOURCEKIT_LIBRARY_OUTPUT_INTDIR})
-  set(framework_location "${lib_dir}/${framework_target}.framework")
-  if (SOURCEKIT_DEPLOYMENT_OS MATCHES "^macosx")
-    set(xpc_bundle_dir "${framework_location}/Versions/A/XPCServices/${name}.xpc")
-    set(xpc_contents_dir "${xpc_bundle_dir}/Contents")
-    set(xpc_bin_dir "${xpc_contents_dir}/MacOS")
-  else()
-    set(xpc_bundle_dir "${framework_location}/XPCServices/${name}.xpc")
-    set(xpc_contents_dir "${xpc_bundle_dir}")
-    set(xpc_bin_dir "${xpc_contents_dir}")
-  endif()
-
-  set(XPCSERVICE_NAME ${name})
-  set(XPCSERVICE_IDENTIFIER "com.apple.${name}.${SOURCEKIT_VERSION_STRING}")
-  set(XPCSERVICE_BUNDLE_VERSION "${SOURCEKIT_VERSION_STRING}")
-  set(XPCSERVICE_SHORT_VERSION_STRING "1.0")
-  configure_file(
-    "${SOURCEKIT_SOURCE_DIR}/cmake/XPCServiceInfo.plist.in"
-    "${CMAKE_CURRENT_BINARY_DIR}/${name}.Info.plist")
-  add_custom_command(OUTPUT "${xpc_contents_dir}/Info.plist"
-    DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/${name}.Info.plist"
-    COMMAND ${CMAKE_COMMAND} -E copy_if_different
-      "${CMAKE_CURRENT_BINARY_DIR}/${name}.Info.plist" "${xpc_contents_dir}/Info.plist")
-  list(APPEND srcs "${xpc_contents_dir}/Info.plist")
-
-  add_llvm_executable(${name} ${srcs})
-  set_target_properties(${name} PROPERTIES FOLDER "XPC Services")
-  set_target_properties(${name} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${xpc_bin_dir}")
-
-  set_output_directory(${name}
-    BINARY_DIR "${xpc_bin_dir}"
-    LIBRARY_DIR "${xpc_bin_dir}")
-
-  # Add appropriate dependencies
-  if(LLVM_COMMON_DEPENDS)
-    add_dependencies(${name} ${LLVM_COMMON_DEPENDS})
-  endif(LLVM_COMMON_DEPENDS)
-
-  target_link_libraries(${name} ${SOURCEKITXPC_LINK_LIBS})
-  swift_common_llvm_config(${name} ${SOURCEKITXPC_LLVM_COMPONENT_DEPENDS})
-  target_link_libraries(${name} ${LLVM_COMMON_LIBS})
-
-  add_dependencies(${framework_target} ${name})
-
-  if (SOURCEKIT_DEPLOYMENT_OS MATCHES "^macosx")
-    add_custom_command(TARGET ${name} POST_BUILD
-      COMMAND ${CMAKE_COMMAND} -E create_symlink "Versions/Current/XPCServices" XPCServices
-      WORKING_DIRECTORY ${framework_location})
-  endif()
-
-  # ASan does not play well with exported_symbol option. This should be fixed soon.
-  if(NOT SWIFT_ASAN_BUILD)
-    if("${CMAKE_SYSTEM_NAME}" STREQUAL "Darwin")
-      set_target_properties(${name}
-        PROPERTIES
-        LINK_FLAGS "-Wl,-exported_symbol,_main")
-    endif()
-  endif()
-  add_sourcekit_default_compiler_flags("${name}")
-endmacro()
+# Now include AddSwiftSourceKit
+include(AddSwiftSourceKit)
 
 if("${CMAKE_SYSTEM_NAME}" STREQUAL "Darwin")
   # Choose a deployment target if none was set.
diff --git a/tools/SourceKit/cmake/modules/AddSwiftSourceKit.cmake b/tools/SourceKit/cmake/modules/AddSwiftSourceKit.cmake
new file mode 100644
index 0000000..0a42829
--- /dev/null
+++ b/tools/SourceKit/cmake/modules/AddSwiftSourceKit.cmake
@@ -0,0 +1,436 @@
+
+function(add_sourcekit_symbol_exports target_name export_file)
+  # Makefile.rules contains special cases for different platforms.
+  # We restrict ourselves to Darwin for the time being.
+  if("${CMAKE_SYSTEM_NAME}" STREQUAL "Darwin")
+    add_custom_command(OUTPUT symbol.exports
+      COMMAND sed -e "s/^/_/" < ${export_file} > symbol.exports
+      DEPENDS ${export_file}
+      VERBATIM
+      COMMENT "Creating export file for ${target_name}")
+    add_custom_target(${target_name}_exports DEPENDS symbol.exports)
+    set_property(DIRECTORY APPEND
+      PROPERTY ADDITIONAL_MAKE_CLEAN_FILES symbol.exports)
+
+    get_property(srcs TARGET ${target_name} PROPERTY SOURCES)
+    foreach(src ${srcs})
+      get_filename_component(extension ${src} EXT)
+      if(extension STREQUAL ".cpp")
+        set(first_source_file ${src})
+        break()
+      endif()
+    endforeach()
+
+    # Force re-linking when the exports file changes. Actually, it
+    # forces recompilation of the source file. The LINK_DEPENDS target
+    # property only works for makefile-based generators.
+    set_property(SOURCE ${first_source_file} APPEND PROPERTY
+      OBJECT_DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/symbol.exports)
+
+    set_property(TARGET ${target_name} APPEND_STRING PROPERTY
+                 LINK_FLAGS " -Wl,-exported_symbols_list,${CMAKE_CURRENT_BINARY_DIR}/symbol.exports")
+
+    add_dependencies(${target_name} ${target_name}_exports)
+  endif()
+endfunction()
+
+# Add default compiler and linker flags to 'target'.
+#
+# FIXME: this is a HACK.  All SourceKit CMake code using this function
+# should be rewritten to use 'add_swift_library'.
+function(add_sourcekit_default_compiler_flags target)
+  set(sdk "${SWIFT_HOST_VARIANT_SDK}")
+  set(arch "${SWIFT_HOST_VARIANT_ARCH}")
+  set(c_compile_flags)
+  set(link_flags)
+
+  # Add variant-specific flags.
+  set(build_type "${CMAKE_BUILD_TYPE}")
+  set(enable_assertions "${LLVM_ENABLE_ASSERTIONS}")
+  set(analyze_code_coverage "${SWIFT_ANALYZE_CODE_COVERAGE}")
+  _add_variant_c_compile_flags(
+    SDK "${sdk}"
+    ARCH "${arch}"
+    BUILD_TYPE "${build_type}"
+    ENABLE_ASSERTIONS "${enable_assertions}"
+    ANALYZE_CODE_COVERAGE "${analyze_code_coverage}"
+    ENABLE_LTO "${SWIFT_TOOLS_ENABLE_LTO}"
+    RESULT_VAR_NAME c_compile_flags)
+  _add_variant_link_flags(
+    SDK "${sdk}"
+    ARCH "${arch}"
+    BUILD_TYPE "${build_type}"
+    ENABLE_ASSERTIONS "${enable_assertions}"
+    ENABLE_LTO "${SWIFT_TOOLS_ENABLE_LTO}"
+    LTO_OBJECT_NAME "${target}-${sdk}-${arch}"
+    ANALYZE_CODE_COVERAGE "${analyze_code_coverage}"
+    RESULT_VAR_NAME link_flags)
+
+  if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux")
+    list(APPEND c_compile_flags "-fblocks")
+    list(APPEND link_flags "-lBlocksRuntime")
+  endif()
+
+  # Convert variables to space-separated strings.
+  _list_escape_for_shell("${c_compile_flags}" c_compile_flags)
+  _list_escape_for_shell("${link_flags}" link_flags)
+
+  # Set compilation and link flags.
+  set_property(TARGET "${target}" APPEND_STRING PROPERTY
+      COMPILE_FLAGS " ${c_compile_flags}")
+  set_property(TARGET "${target}" APPEND_STRING PROPERTY
+      LINK_FLAGS " ${link_flags}")
+endfunction()
+
+# Add a new SourceKit library.
+#
+# Usage:
+#   add_sourcekit_library(name     # Name of the library
+#     [LINK_LIBS dep1 ...]         # Libraries this library will be linked with
+#     [DEPENDS dep1 ...]           # Targets this library depends on
+#     [LLVM_COMPONENT_DEPENDS comp1 ...]  # LLVM components this library depends on
+#     [INSTALL_IN_COMPONENT comp]  # The Swift installation component that this library belongs to.
+#     [SHARED]
+#     source1 [source2 source3 ...]) # Sources to add into this library
+macro(add_sourcekit_library name)
+  cmake_parse_arguments(SOURCEKITLIB
+      "SHARED"
+      "INSTALL_IN_COMPONENT"
+      "LINK_LIBS;DEPENDS;LLVM_COMPONENT_DEPENDS"
+      ${ARGN})
+  set(srcs ${SOURCEKITLIB_UNPARSED_ARGUMENTS})
+
+  llvm_process_sources(srcs ${srcs})
+  if(MSVC_IDE OR XCODE)
+    # Add public headers
+    file(RELATIVE_PATH lib_path
+      ${SOURCEKIT_SOURCE_DIR}/lib/
+      ${CMAKE_CURRENT_SOURCE_DIR}
+    )
+    if(NOT lib_path MATCHES "^[.][.]")
+      file(GLOB_RECURSE headers
+        ${SOURCEKIT_SOURCE_DIR}/include/SourceKit/${lib_path}/*.h
+        ${SOURCEKIT_SOURCE_DIR}/include/SourceKit/${lib_path}/*.def
+      )
+      set_source_files_properties(${headers} PROPERTIES HEADER_FILE_ONLY ON)
+
+      file(GLOB_RECURSE tds
+        ${SOURCEKIT_SOURCE_DIR}/include/SourceKit/${lib_path}/*.td
+      )
+      source_group("TableGen descriptions" FILES ${tds})
+      set_source_files_properties(${tds} PROPERTIES HEADER_FILE_ONLY ON)
+
+      set(srcs ${srcs} ${headers} ${tds})
+    endif()
+  endif()
+  if (MODULE)
+    set(libkind MODULE)
+  elseif(SOURCEKITLIB_SHARED)
+    set(libkind SHARED)
+  else()
+    set(libkind)
+  endif()
+  add_library(${name} ${libkind} ${srcs})
+  llvm_update_compile_flags(${name})
+
+  set_output_directory(${name}
+      BINARY_DIR ${SOURCEKIT_RUNTIME_OUTPUT_INTDIR}
+      LIBRARY_DIR ${SOURCEKIT_LIBRARY_OUTPUT_INTDIR})
+
+  if(LLVM_COMMON_DEPENDS)
+    add_dependencies(${name} ${LLVM_COMMON_DEPENDS})
+  endif(LLVM_COMMON_DEPENDS)
+
+  if(SOURCEKITLIB_DEPENDS)
+    add_dependencies(${name} ${SOURCEKITLIB_DEPENDS})
+  endif(SOURCEKITLIB_DEPENDS)
+
+  set(prefixed_link_libraries)
+  foreach(dep ${SOURCEKITLIB_LINK_LIBS})
+    if("${dep}" MATCHES "^clang")
+      set(dep "${LLVM_LIBRARY_OUTPUT_INTDIR}/lib${dep}.a")
+    endif()
+    list(APPEND prefixed_link_libraries "${dep}")
+  endforeach()
+  set(SOURCEKITLIB_LINK_LIBS "${prefixed_link_libraries}")
+
+  if("${libkind}" STREQUAL "SHARED")
+    target_link_libraries("${name}" PRIVATE ${SOURCEKITLIB_LINK_LIBS})
+  else()
+    target_link_libraries("${name}" INTERFACE ${SOURCEKITLIB_LINK_LIBS})
+  endif()
+
+  swift_common_llvm_config(${name} ${SOURCEKITLIB_LLVM_COMPONENT_DEPENDS})
+
+  if(SOURCEKITLIB_SHARED AND EXPORTED_SYMBOL_FILE)
+    add_sourcekit_symbol_exports(${name} ${EXPORTED_SYMBOL_FILE})
+  endif()
+
+  if("${CMAKE_SYSTEM_NAME}" STREQUAL "Darwin")
+    if(SOURCEKITLIB_SHARED)
+      set_target_properties(${name} PROPERTIES BUILD_WITH_INSTALL_RPATH TRUE)
+      set_target_properties(${name} PROPERTIES INSTALL_NAME_DIR "@rpath")
+    endif()
+  endif()
+
+  if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux")
+    if(SOURCEKITLIB_SHARED)
+      set_target_properties(${name} PROPERTIES BUILD_WITH_INSTALL_RPATH TRUE)
+      set_target_properties(${name} PROPERTIES INSTALL_RPATH "$ORIGIN/../lib/swift/linux:/usr/lib/swift/linux")
+    endif()
+  endif()
+
+  if("${SOURCEKITLIB_INSTALL_IN_COMPONENT}" STREQUAL "")
+    if(SOURCEKITLIB_SHARED)
+      set(SOURCEKITLIB_INSTALL_IN_COMPONENT tools)
+    else()
+      set(SOURCEKITLIB_INSTALL_IN_COMPONENT dev)
+    endif()
+  endif()
+  swift_install_in_component("${SOURCEKITLIB_INSTALL_IN_COMPONENT}"
+      TARGETS ${name}
+      LIBRARY DESTINATION "lib${LLVM_LIBDIR_SUFFIX}"
+      ARCHIVE DESTINATION "lib${LLVM_LIBDIR_SUFFIX}"
+      RUNTIME DESTINATION "bin")
+  set_target_properties(${name} PROPERTIES FOLDER "SourceKit libraries")
+  add_sourcekit_default_compiler_flags("${name}")
+endmacro()
+
+# Add a new SourceKit executable.
+#
+# Usage:
+#   add_sourcekit_executable(name        # Name of the executable
+#     [LINK_LIBS dep1 ...]               # Libraries this executable depends on
+#     [LLVM_COMPONENT_DEPENDS comp1 ...] # LLVM components this executable
+#                                        # depends on
+#     [EXCLUDE_FROM_ALL]              # Whether to exclude this executable from
+#                                     # the ALL_BUILD target
+#     source1 [source2 source3 ...])  # Sources to add into this executable
+macro(add_sourcekit_executable name)
+  cmake_parse_arguments(SOURCEKITEXE
+    "EXCLUDE_FROM_ALL"
+    ""
+    "LINK_LIBS;LLVM_COMPONENT_DEPENDS"
+    ${ARGN})
+
+  if (${SOURCEKITEXE_EXCLUDE_FROM_ALL})
+    add_executable(${name} EXCLUDE_FROM_ALL ${SOURCEKITEXE_UNPARSED_ARGUMENTS})
+  else()
+    add_executable(${name} ${SOURCEKITEXE_UNPARSED_ARGUMENTS})
+  endif()
+  llvm_update_compile_flags(${name})
+  set_output_directory(${name}
+      BINARY_DIR ${SOURCEKIT_RUNTIME_OUTPUT_INTDIR}
+      LIBRARY_DIR ${SOURCEKIT_LIBRARY_OUTPUT_INTDIR})
+
+  # Add appropriate dependencies
+  if(LLVM_COMMON_DEPENDS)
+    add_dependencies(${name} ${LLVM_COMMON_DEPENDS})
+  endif()
+
+  target_link_libraries(${name} ${SOURCEKITEXE_LINK_LIBS})
+  swift_common_llvm_config(${name} ${SOURCEKITEXE_LLVM_COMPONENT_DEPENDS})
+  target_link_libraries(${name} ${LLVM_COMMON_LIBS})
+
+  set_target_properties(${name} PROPERTIES FOLDER "SourceKit executables")
+  if (NOT SWIFT_ASAN_BUILD)
+    if("${CMAKE_SYSTEM_NAME}" STREQUAL "Darwin")
+      set_target_properties(${name}
+        PROPERTIES
+        LINK_FLAGS "-Wl,-exported_symbol,_main")
+    endif()
+    if(SWIFT_ANALYZE_CODE_COVERAGE)
+      set_property(TARGET "${name}" APPEND_STRING PROPERTY
+        LINK_FLAGS " -fprofile-instr-generate -fcoverage-mapping")
+    endif()
+  endif()
+  add_sourcekit_default_compiler_flags("${name}")
+endmacro()
+
+# Add a new SourceKit framework.
+#
+# Usage:
+#   add_sourcekit_framework(name     # Name of the framework
+#     [LINK_LIBS dep1 ...]           # Libraries this framework will link with
+#     [LLVM_COMPONENT_DEPENDS comp1 ...]  # LLVM components this framework depends on
+#     [MODULEMAP modulemap]          # Module map file for this framework
+#     [INSTALL_IN_COMPONENT comp]    # The Swift installation component that this framework belongs to.
+#     source1 [source2 source3 ...]) # Sources to add into this framework
+macro(add_sourcekit_framework name)
+  cmake_parse_arguments(SOURCEKITFW
+    "" "MODULEMAP;INSTALL_IN_COMPONENT" "LINK_LIBS;LLVM_COMPONENT_DEPENDS" ${ARGN})
+  set(srcs ${SOURCEKITFW_UNPARSED_ARGUMENTS})
+
+  set(lib_dir ${SOURCEKIT_LIBRARY_OUTPUT_INTDIR})
+  set(framework_location "${lib_dir}/${name}.framework")
+
+  if (NOT SOURCEKIT_DEPLOYMENT_OS MATCHES "^macosx")
+    set(FLAT_FRAMEWORK_NAME "${name}")
+    set(FLAT_FRAMEWORK_IDENTIFIER "com.apple.${name}")
+    set(FLAT_FRAMEWORK_SHORT_VERSION_STRING "1.0")
+    set(FLAT_FRAMEWORK_BUNDLE_VERSION "${SOURCEKIT_VERSION_STRING}")
+    set(FLAT_FRAMEWORK_DEPLOYMENT_TARGET "${SOURCEKIT_DEPLOYMENT_TARGET}")
+    configure_file(
+      "${SOURCEKIT_SOURCE_DIR}/cmake/FlatFrameworkInfo.plist.in"
+      "${CMAKE_CURRENT_BINARY_DIR}/${name}.Info.plist")
+    add_custom_command(OUTPUT "${framework_location}/Info.plist"
+      DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/${name}.Info.plist"
+      COMMAND ${CMAKE_COMMAND} -E copy_if_different
+      "${CMAKE_CURRENT_BINARY_DIR}/${name}.Info.plist" "${framework_location}/Info.plist")
+    list(APPEND srcs "${framework_location}/Info.plist")
+  endif()
+
+  llvm_process_sources(srcs ${srcs})
+  add_library(${name} SHARED ${srcs})
+  llvm_update_compile_flags(${name})
+
+  set(headers)
+  foreach(src ${srcs})
+    get_filename_component(extension ${src} EXT)
+    if(extension STREQUAL ".h")
+      list(APPEND headers ${src})
+    endif()
+  endforeach()
+
+  if(MSVC_IDE OR XCODE)
+    set_source_files_properties(${headers} PROPERTIES HEADER_FILE_ONLY ON)
+  endif(MSVC_IDE OR XCODE)
+
+  if(LLVM_COMMON_DEPENDS)
+    add_dependencies(${name} ${LLVM_COMMON_DEPENDS})
+  endif(LLVM_COMMON_DEPENDS)
+
+  target_link_libraries(${name} PRIVATE ${SOURCEKITFW_LINK_LIBS})
+  swift_common_llvm_config(${name} ${SOURCEKITFW_LLVM_COMPONENT_DEPENDS})
+
+  if (EXPORTED_SYMBOL_FILE)
+    add_sourcekit_symbol_exports(${name} ${EXPORTED_SYMBOL_FILE})
+  endif()
+
+  if(SOURCEKITFW_MODULEMAP)
+    set(modulemap "${CMAKE_CURRENT_SOURCE_DIR}/${SOURCEKITFW_MODULEMAP}")
+    if (SOURCEKIT_DEPLOYMENT_OS MATCHES "^macosx")
+      set(modules_dir "${framework_location}/Versions/A/Modules")
+      add_custom_command(TARGET ${name} PRE_BUILD
+        COMMAND ${CMAKE_COMMAND} -E copy "${modulemap}" "${modules_dir}/module.modulemap"
+        COMMAND ${CMAKE_COMMAND} -E create_symlink "Versions/Current/Modules" "${framework_location}/Modules")
+    else()
+      set(modules_dir "${framework_location}/Modules")
+      add_custom_command(TARGET ${name} PRE_BUILD
+        COMMAND ${CMAKE_COMMAND} -E copy "${modulemap}" "${modules_dir}/module.modulemap")
+    endif()
+  endif()
+
+
+  if (SOURCEKIT_DEPLOYMENT_OS MATCHES "^macosx")
+    swift_install_in_component(${SOURCEKITFW_INSTALL_IN_COMPONENT}
+        TARGETS ${name}
+        LIBRARY DESTINATION lib${LLVM_LIBDIR_SUFFIX}
+        ARCHIVE DESTINATION lib${LLVM_LIBDIR_SUFFIX}
+        RUNTIME DESTINATION bin)
+    set_target_properties(${name} PROPERTIES FOLDER "SourceKit frameworks")
+    set_output_directory(${name}
+        BINARY_DIR ${SOURCEKIT_RUNTIME_OUTPUT_INTDIR}
+        LIBRARY_DIR ${SOURCEKIT_LIBRARY_OUTPUT_INTDIR})
+    set_target_properties(${name} PROPERTIES FRAMEWORK TRUE)
+    set_target_properties(${name} PROPERTIES PUBLIC_HEADER "${headers}")
+    set_target_properties(${name} PROPERTIES MACOSX_FRAMEWORK_INFO_PLIST "${SOURCEKIT_SOURCE_DIR}/cmake/MacOSXFrameworkInfo.plist.in")
+    set_target_properties(${name} PROPERTIES MACOSX_FRAMEWORK_IDENTIFIER "com.apple.${name}")
+    set_target_properties(${name} PROPERTIES MACOSX_FRAMEWORK_SHORT_VERSION_STRING "1.0")
+    set_target_properties(${name} PROPERTIES MACOSX_FRAMEWORK_BUNDLE_VERSION "${SOURCEKIT_VERSION_STRING}")
+    set_target_properties(${name} PROPERTIES BUILD_WITH_INSTALL_RPATH TRUE)
+    set_target_properties(${name} PROPERTIES INSTALL_NAME_DIR "@rpath")
+  else()
+    swift_install_in_component(${SOURCEKITFW_INSTALL_IN_COMPONENT}
+        DIRECTORY ${framework_location}
+        DESTINATION lib${LLVM_LIBDIR_SUFFIX}
+        USE_SOURCE_PERMISSIONS)
+    set_target_properties(${name} PROPERTIES FOLDER "SourceKit frameworks")
+    set_output_directory(${name}
+        BINARY_DIR ${framework_location}
+        LIBRARY_DIR ${framework_location})
+    set_target_properties(${name} PROPERTIES PREFIX "")
+    set_target_properties(${name} PROPERTIES SUFFIX "")
+    set_target_properties(${name} PROPERTIES BUILD_WITH_INSTALL_RPATH TRUE)
+    set_target_properties(${name} PROPERTIES INSTALL_NAME_DIR "@rpath/${name}.framework")
+
+    foreach(hdr ${headers})
+      get_filename_component(hdrname ${hdr} NAME)
+      add_custom_command(TARGET ${name} PRE_BUILD
+        COMMAND ${CMAKE_COMMAND} -E copy "${hdr}" "${framework_location}/Headers/${hdrname}")
+    endforeach()
+  endif()
+  add_sourcekit_default_compiler_flags("${name}")
+endmacro(add_sourcekit_framework)
+
+# Add a new SourceKit XPC service to a framework.
+#
+# Usage:
+#   add_sourcekit_xpc_service(name      # Name of the XPC service
+#     [LINK_LIBS dep1 ...]              # Libraries this service will link with
+#     [LLVM_COMPONENT_DEPENDS comp1 ...]   # LLVM components this service depends on
+#     source1 [source2 source3 ...])    # Sources to add into this service
+macro(add_sourcekit_xpc_service name framework_target)
+  cmake_parse_arguments(SOURCEKITXPC "" "" "LINK_LIBS;LLVM_COMPONENT_DEPENDS" ${ARGN})
+  set(srcs ${SOURCEKITXPC_UNPARSED_ARGUMENTS})
+
+  set(lib_dir ${SOURCEKIT_LIBRARY_OUTPUT_INTDIR})
+  set(framework_location "${lib_dir}/${framework_target}.framework")
+  if (SOURCEKIT_DEPLOYMENT_OS MATCHES "^macosx")
+    set(xpc_bundle_dir "${framework_location}/Versions/A/XPCServices/${name}.xpc")
+    set(xpc_contents_dir "${xpc_bundle_dir}/Contents")
+    set(xpc_bin_dir "${xpc_contents_dir}/MacOS")
+  else()
+    set(xpc_bundle_dir "${framework_location}/XPCServices/${name}.xpc")
+    set(xpc_contents_dir "${xpc_bundle_dir}")
+    set(xpc_bin_dir "${xpc_contents_dir}")
+  endif()
+
+  set(XPCSERVICE_NAME ${name})
+  set(XPCSERVICE_IDENTIFIER "com.apple.${name}.${SOURCEKIT_VERSION_STRING}")
+  set(XPCSERVICE_BUNDLE_VERSION "${SOURCEKIT_VERSION_STRING}")
+  set(XPCSERVICE_SHORT_VERSION_STRING "1.0")
+  configure_file(
+    "${SOURCEKIT_SOURCE_DIR}/cmake/XPCServiceInfo.plist.in"
+    "${CMAKE_CURRENT_BINARY_DIR}/${name}.Info.plist")
+  add_custom_command(OUTPUT "${xpc_contents_dir}/Info.plist"
+    DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/${name}.Info.plist"
+    COMMAND ${CMAKE_COMMAND} -E copy_if_different
+      "${CMAKE_CURRENT_BINARY_DIR}/${name}.Info.plist" "${xpc_contents_dir}/Info.plist")
+  list(APPEND srcs "${xpc_contents_dir}/Info.plist")
+
+  add_llvm_executable(${name} ${srcs})
+  set_target_properties(${name} PROPERTIES FOLDER "XPC Services")
+  set_target_properties(${name} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${xpc_bin_dir}")
+
+  set_output_directory(${name}
+    BINARY_DIR "${xpc_bin_dir}"
+    LIBRARY_DIR "${xpc_bin_dir}")
+
+  # Add appropriate dependencies
+  if(LLVM_COMMON_DEPENDS)
+    add_dependencies(${name} ${LLVM_COMMON_DEPENDS})
+  endif(LLVM_COMMON_DEPENDS)
+
+  target_link_libraries(${name} ${SOURCEKITXPC_LINK_LIBS})
+  swift_common_llvm_config(${name} ${SOURCEKITXPC_LLVM_COMPONENT_DEPENDS})
+  target_link_libraries(${name} ${LLVM_COMMON_LIBS})
+
+  add_dependencies(${framework_target} ${name})
+
+  if (SOURCEKIT_DEPLOYMENT_OS MATCHES "^macosx")
+    add_custom_command(TARGET ${name} POST_BUILD
+      COMMAND ${CMAKE_COMMAND} -E create_symlink "Versions/Current/XPCServices" XPCServices
+      WORKING_DIRECTORY ${framework_location})
+  endif()
+
+  # ASan does not play well with exported_symbol option. This should be fixed soon.
+  if(NOT SWIFT_ASAN_BUILD)
+    if("${CMAKE_SYSTEM_NAME}" STREQUAL "Darwin")
+      set_target_properties(${name}
+        PROPERTIES
+        LINK_FLAGS "-Wl,-exported_symbol,_main")
+    endif()
+  endif()
+  add_sourcekit_default_compiler_flags("${name}")
+endmacro()
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: