Merge pull request #21240 from rjmccall/remove-xi-witnesses-5.0

[5.0] Remove the extra-inhabitant value witnesses
diff --git a/docs/Runtime.md b/docs/Runtime.md
index 2af89aa..a4fe69c 100644
--- a/docs/Runtime.md
+++ b/docs/Runtime.md
@@ -260,9 +260,7 @@
 0000000000023a40 T _swift_assignExistentialWithCopy
 000000000001dbf0 T _swift_copyPOD
 000000000001c560 T _swift_getEnumCaseMultiPayload
-000000000001be60 T _swift_getEnumCaseSinglePayload
 000000000001c400 T _swift_storeEnumTagMultiPayload
-000000000001bf90 T _swift_storeEnumTagSinglePayload
 ```
 
 ## Type metadata lookup
diff --git a/include/swift/ABI/Metadata.h b/include/swift/ABI/Metadata.h
index 99832e9..dc59061 100644
--- a/include/swift/ABI/Metadata.h
+++ b/include/swift/ABI/Metadata.h
@@ -295,10 +295,9 @@
   // Handle the data witnesses explicitly so we can use more specific
   // types for the flags enums.
   typedef size_t size;
-  typedef ValueWitnessFlags flags;
   typedef size_t stride;
-  typedef ExtraInhabitantFlags extraInhabitantFlags;
-
+  typedef ValueWitnessFlags flags;
+  typedef uint32_t extraInhabitantCount;
 };
 
 struct TypeLayout;
@@ -376,16 +375,9 @@
   
   /// The number of extra inhabitants, that is, bit patterns that do not form
   /// valid values of the type, in this type's binary representation.
-  unsigned getNumExtraInhabitants() const;
-
-  /// Assert that this value witness table is an extra-inhabitants
-  /// value witness table and return it as such.
-  ///
-  /// This has an awful name because it's supposed to be internal to
-  /// this file.  Code outside this file should use LLVM's cast/dyn_cast.
-  /// We don't want to use those here because we need to avoid accidentally
-  /// introducing ABI dependencies on LLVM structures.
-  const struct ExtraInhabitantsValueWitnessTable *_asXIVWT() const;
+  unsigned getNumExtraInhabitants() const {
+    return extraInhabitantCount;
+  }
 
   /// Assert that this value witness table is an enum value witness table
   /// and return it as such.
@@ -608,13 +600,6 @@
   #define DATA_VALUE_WITNESS(LOWER, UPPER, TYPE)
   #include "swift/ABI/ValueWitness.def"
 
-  int vw_getExtraInhabitantIndex(const OpaqueValue *value) const  {
-    return getValueWitnesses()->_asXIVWT()->getExtraInhabitantIndex(value, this);
-  }
-  void vw_storeExtraInhabitant(OpaqueValue *value, int index) const {
-    getValueWitnesses()->_asXIVWT()->storeExtraInhabitant(value, index, this);
-  }
-
   unsigned vw_getEnumTag(const OpaqueValue *value) const {
     return getValueWitnesses()->_asEVWT()->getEnumTag(const_cast<OpaqueValue*>(value), this);
   }
@@ -637,6 +622,10 @@
     return getValueWitnesses()->getStride();
   }
 
+  unsigned vw_getNumExtraInhabitants() const {
+    return getValueWitnesses()->getNumExtraInhabitants();
+  }
+
   /// Allocate an out-of-line buffer if values of this type don't fit in the
   /// ValueBuffer.
   /// NOTE: This is not a box for copy-on-write existentials.
diff --git a/include/swift/ABI/MetadataValues.h b/include/swift/ABI/MetadataValues.h
index fde8311..bf2ce18 100644
--- a/include/swift/ABI/MetadataValues.h
+++ b/include/swift/ABI/MetadataValues.h
@@ -121,24 +121,27 @@
   // flags of the field types can be mostly bitwise-or'ed together to derive the
   // flags for the struct. (The "non-inline" and "has-extra-inhabitants" bits
   // still require additional fixup.)
-  enum : int_type {
+  enum : uint32_t {
     AlignmentMask =       0x000000FF,
+    // unused             0x0000FF00,
     IsNonPOD =            0x00010000,
     IsNonInline =         0x00020000,
-    HasExtraInhabitants = 0x00040000,
+    // unused             0x00040000,
     HasSpareBits =        0x00080000,
     IsNonBitwiseTakable = 0x00100000,
     HasEnumWitnesses =    0x00200000,
     Incomplete =          0x00400000,
-
-    // Everything else is reserved.
+    // unused             0xFF800000,
   };
 
+  static constexpr const uint32_t MaxNumExtraInhabitants = 0x7FFFFFFF;
+
 private:
-  int_type Data;
+  uint32_t Data;
+
+  explicit constexpr TargetValueWitnessFlags(uint32_t data) : Data(data) {}
 
 public:
-  explicit constexpr TargetValueWitnessFlags(int_type data) : Data(data) {}
   constexpr TargetValueWitnessFlags() : Data(0) {}
 
   /// The required alignment of the first byte of an object of this
@@ -192,22 +195,12 @@
     return TargetValueWitnessFlags((Data & ~IsNonBitwiseTakable) |
                                    (isBT ? 0 : IsNonBitwiseTakable));
   }
-  /// True if this type's binary representation has extra inhabitants, that is,
-  /// bit patterns that do not form valid values of the type.
-  ///
-  /// If true, then the extra inhabitant value witness table entries are
-  /// available in this type's value witness table.
-  bool hasExtraInhabitants() const { return Data & HasExtraInhabitants; }
+
   /// True if this type's binary representation is that of an enum, and the
   /// enum value witness table entries are available in this type's value
   /// witness table.
   bool hasEnumWitnesses() const { return Data & HasEnumWitnesses; }
   constexpr TargetValueWitnessFlags
-  withExtraInhabitants(bool hasExtraInhabitants) const {
-    return TargetValueWitnessFlags((Data & ~HasExtraInhabitants) |
-                               (hasExtraInhabitants ? HasExtraInhabitants : 0));
-  }
-  constexpr TargetValueWitnessFlags
   withEnumWitnesses(bool hasEnumWitnesses) const {
     return TargetValueWitnessFlags((Data & ~HasEnumWitnesses) |
                                    (hasEnumWitnesses ? HasEnumWitnesses : 0));
@@ -223,44 +216,12 @@
                                    (isIncomplete ? Incomplete : 0));
   }
 
-  constexpr int_type getOpaqueValue() const { return Data; }
-  static constexpr TargetValueWitnessFlags getFromOpaqueValue(int_type data) {
-    return TargetValueWitnessFlags(data);
+  constexpr uint32_t getOpaqueValue() const {
+    return Data;
   }
 };
 using ValueWitnessFlags = TargetValueWitnessFlags<size_t>;
 
-/// Flags stored in a value-witness table with extra inhabitants.
-template <typename int_type>
-class TargetExtraInhabitantFlags {
-public:
-  enum : int_type {
-    NumExtraInhabitantsMask = 0x7FFFFFFFU,
-    ExtraInhabitantFlags
-  };
-  int_type Data;
-
-  constexpr TargetExtraInhabitantFlags(int_type data) : Data(data) {}
-
-public:
-  constexpr TargetExtraInhabitantFlags() : Data(0) {}
-  /// The number of extra inhabitants in the type's representation.
-  int getNumExtraInhabitants() const { return Data & NumExtraInhabitantsMask; }
-
-  constexpr TargetExtraInhabitantFlags
-  withNumExtraInhabitants(unsigned numExtraInhabitants) const {
-    return TargetExtraInhabitantFlags((Data & ~NumExtraInhabitantsMask) |
-                                      numExtraInhabitants);
-  }
-
-  constexpr int_type getOpaqueValue() const { return Data; }
-  static constexpr TargetExtraInhabitantFlags getFromOpaqueValue(int_type data){
-    return TargetExtraInhabitantFlags(data);
-  }
-};
-using ExtraInhabitantFlags =
-  TargetExtraInhabitantFlags<size_t>;
-
 /// Flags for dynamic-cast operations.
 enum class DynamicCastFlags : size_t {
   /// All flags clear.
diff --git a/include/swift/ABI/ValueWitness.def b/include/swift/ABI/ValueWitness.def
index bc43600..d07eca2 100644
--- a/include/swift/ABI/ValueWitness.def
+++ b/include/swift/ABI/ValueWitness.def
@@ -23,7 +23,6 @@
 #if defined(WANT_ALL_VALUE_WITNESSES)
 #undef WANT_ALL_VALUE_WITNESSES
 #define WANT_REQUIRED_VALUE_WITNESSES         1
-#define WANT_EXTRA_INHABITANT_VALUE_WITNESSES 1
 #define WANT_ENUM_VALUE_WITNESSES             1
 
 /// WANT_ONLY_REQUIRED_VALUE_WITNESSES
@@ -31,15 +30,6 @@
 #elif defined(WANT_ONLY_REQUIRED_VALUE_WITNESSES)
 #undef WANT_ONLY_REQUIRED_VALUE_WITNESSES
 #define WANT_REQUIRED_VALUE_WITNESSES         1
-#define WANT_EXTRA_INHABITANT_VALUE_WITNESSES 0
-#define WANT_ENUM_VALUE_WITNESSES             0
-
-/// WANT_ONLY_EXTRA_INHABITANT_VALUE_WITNESSES
-///   Define this to expand only the extra-inhabitant value witnesses.
-#elif defined(WANT_ONLY_EXTRA_INHABITANT_VALUE_WITNESSES)
-#undef WANT_ONLY_EXTRA_INHABITANT_VALUE_WITNESSES
-#define WANT_REQUIRED_VALUE_WITNESSES         0
-#define WANT_EXTRA_INHABITANT_VALUE_WITNESSES 1
 #define WANT_ENUM_VALUE_WITNESSES             0
 
 /// WANT_ONLY_ENUM_VALUE_WITNESSES
@@ -47,15 +37,13 @@
 #elif  defined(WANT_ONLY_ENUM_VALUE_WITNESSES)
 #undef  WANT_ONLY_ENUM_VALUE_WITNESSES
 #define WANT_REQUIRED_VALUE_WITNESSES         0
-#define WANT_EXTRA_INHABITANT_VALUE_WITNESSES 0
 #define WANT_ENUM_VALUE_WITNESSES             1
 
 /// WANT_REQUIRED_VALUE_WITNESSES
-/// WANT_EXTRA_INHABITANT_VALUE_WITNESSES
 /// WANT_ENUM_VALUE_WITNESSES
 ///   Define all of these to control exactly what to expand.
 #else
-#if !defined(WANT_REQUIRED_VALUE_WITNESSES) ||  !defined(WANT_EXTRA_INHABITANT_VALUE_WITNESSES) || !defined(WANT_ENUM_VALUE_WITNESSES)
+#if !defined(WANT_REQUIRED_VALUE_WITNESSES) || !defined(WANT_ENUM_VALUE_WITNESSES)
 #error failed to define a WANT macro; possible typo?
 #endif
 #endif
@@ -206,7 +194,16 @@
 BEGIN_VALUE_WITNESS_RANGE(RequiredTypeLayoutWitness,
                           Size)
 
-///   SIZE_TYPE flags;
+///   SIZE_TYPE stride;
+///
+/// The required size per element of an array of this type. It is at least
+/// one, even for zero-sized types, like the empty tuple.
+DATA_VALUE_WITNESS(stride,
+                   Stride,
+                   SIZE_TYPE)
+
+
+///   UINT_TYPE flags;
 ///
 /// The ValueWitnessAlignmentMask bits represent the required
 /// alignment of the first byte of an object of this type, expressed
@@ -222,10 +219,9 @@
 /// The ValueWitnessIsNonInline bit is set if the type cannot be
 /// represented in a fixed-size buffer or if it is not bitwise takable.
 ///
-/// The Enum_HasExtraInhabitants bit is set if the type's binary
-/// representation has "extra inhabitants" that do not form valid values of
-/// the type, and the value witness table contains the ExtraInhabitantWitness
-/// entries.
+/// The ExtraInhabitantsMask bits represent the number of "extra inhabitants"
+/// of the bit representation of the value that do not form valid values of
+/// the type.
 ///
 /// The Enum_HasSpareBits bit is set if the type's binary representation
 /// has unused bits.
@@ -233,86 +229,25 @@
 /// The HasEnumWitnesses bit is set if the type is an enum type.
 DATA_VALUE_WITNESS(flags,
                    Flags,
-                   SIZE_TYPE)
+                   UINT_TYPE)
 
-///   SIZE_TYPE stride;
+///   UINT_TYPE extraInhabitantCount;
 ///
-/// The required size per element of an array of this type. It is at least
-/// one, even for zero-sized types, like the empty tuple.
-DATA_VALUE_WITNESS(stride,
-                   Stride,
-                   SIZE_TYPE)
+/// The number of extra inhabitants in the type.
+DATA_VALUE_WITNESS(extraInhabitantCount,
+                   ExtraInhabitantCount,
+                   UINT_TYPE)
 
 END_VALUE_WITNESS_RANGE(RequiredTypeLayoutWitness,
-                        Stride)
+                        ExtraInhabitantCount)
 
 END_VALUE_WITNESS_RANGE(RequiredValueWitness,
-                        Stride)
-
-#endif /* WANT_REQUIRED_VALUE_WITNESSES */
-
-#if WANT_EXTRA_INHABITANT_VALUE_WITNESSES
-
-// The following value witnesses are conditionally present based on
-// the Enum_HasExtraInhabitants bit of the flags.
-
-///   SIZE_TYPE extraInhabitantFlags;
-///
-/// These bits are always present if the extra inhabitants witnesses are:
-///
-/// - The NumExtraInhabitantsMask bits contain the number of extra
-///   inhabitants of the type representation.
-///
-/// If the Enum_HasSpareBits flag is set in the value witness flags, these
-/// additional flags are available:
-///
-/// - The NumSpareBitsMask bits contain the number of (host-endian) contiguous
-///   spare bits in the type representation.
-/// - The SpareBitsShiftMask bits contain the (host-endian) bit offset of the
-///   lowest spare bit.
-DATA_VALUE_WITNESS(extraInhabitantFlags,
-                   ExtraInhabitantFlags,
-                   SIZE_TYPE)
-
-BEGIN_VALUE_WITNESS_RANGE(ExtraInhabitantValueWitness,
-                          ExtraInhabitantFlags)
+                        ExtraInhabitantCount)
 
 END_VALUE_WITNESS_RANGE(TypeLayoutWitness,
-                        ExtraInhabitantFlags)
+                        ExtraInhabitantCount)
 
-///   void (*storeExtraInhabitant)(T *obj, int index, M *self);
-///
-/// Given an invalid object of this type, store the representation of an
-/// extra inhabitant of the type. The object will remain invalid, because
-/// an extra inhabitant is by definition an invalid representation of the
-/// type. index must be less than numExtraInhabitants.
-FUNCTION_VALUE_WITNESS(storeExtraInhabitant,
-                       StoreExtraInhabitant,
-                       VOID_TYPE,
-                       (MUTABLE_VALUE_TYPE, INT_TYPE, TYPE_TYPE))
-
-BEGIN_VALUE_WITNESS_RANGE(ExtraInhabitantValueWitnessFunction,
-                          StoreExtraInhabitant)
-
-///   int (*getExtraInhabitantIndex)(T *obj, M *self);
-///
-/// Given an invalid object of this type with an extra inhabitant
-/// representation, returns the index of the extra inhabitant representation.
-/// Returns -1 if the object is a valid value of the type. If non-negative,
-/// the return value is the same index that can be passed to
-/// storeExtraInhabitant to reproduce the representation.
-FUNCTION_VALUE_WITNESS(getExtraInhabitantIndex,
-                       GetExtraInhabitantIndex,
-                       INT_TYPE,
-                       (IMMUTABLE_VALUE_TYPE, TYPE_TYPE))
-
-END_VALUE_WITNESS_RANGE(ExtraInhabitantValueWitnessFunction,
-                        GetExtraInhabitantIndex)
-
-END_VALUE_WITNESS_RANGE(ExtraInhabitantValueWitness,
-                        GetExtraInhabitantIndex)
-
-#endif /* WANT_EXTRA_INHABITANT_VALUE_WITNESSES */
+#endif /* WANT_REQUIRED_VALUE_WITNESSES */
 
 #if WANT_ENUM_VALUE_WITNESSES
 
@@ -372,9 +307,7 @@
 #undef FUNCTION_VALUE_WITNESS
 #undef VALUE_WITNESS
 #undef ENUM_VALUE_WITNESS
-#undef EXTRA_INHABITANT_VALUE_WITNESS
 #undef NON_REQUIRED_VALUE_WITNESS
 #undef REQUIRED_VALUE_WITNESS
 #undef WANT_ENUM_VALUE_WITNESSES
-#undef WANT_EXTRA_INHABITANT_VALUE_WITNESSES
 #undef WANT_REQUIRED_VALUE_WITNESSES
diff --git a/include/swift/Runtime/Enum.h b/include/swift/Runtime/Enum.h
index aba2436..2d0d2c9 100644
--- a/include/swift/Runtime/Enum.h
+++ b/include/swift/Runtime/Enum.h
@@ -58,37 +58,50 @@
                                          const TypeLayout *payload,
                                          unsigned emptyCases);
 
-/// \brief Faster variant of the above which avoids digging into the enum type
-/// metadata when the caller already has the payload information handy.
+using getExtraInhabitantTag_t =
+  SWIFT_CC(swift) unsigned (const OpaqueValue *vaue,
+                            unsigned numExtraInhabitants,
+                            const Metadata *payloadType);
+
+/// Implement getEnumTagSinglePayload generically in terms of a
+/// payload type with a getExtraInhabitantIndex function.
 ///
 /// \param value - pointer to the enum value.
-/// \param payload - type metadata for the payload case of the enum.
+/// \param payloadType - type metadata for the payload case of the enum.
 /// \param emptyCases - the number of empty cases in the enum.
 ///
 /// \returns 0 if the payload case is inhabited. If an empty case is inhabited,
 ///          returns a value greater than or equal to one and less than or equal
 ///          emptyCases.
-SWIFT_RUNTIME_EXPORT
-unsigned swift_getEnumCaseSinglePayload(const OpaqueValue *value,
-                                        const Metadata *payload,
-                                        unsigned emptyCases);
+SWIFT_RUNTIME_EXPORT SWIFT_CC(swift)
+unsigned swift_getEnumTagSinglePayloadGeneric(const OpaqueValue *value,
+                                              unsigned emptyCases,
+                                              const Metadata *payloadType,
+                                              getExtraInhabitantTag_t *getTag);
 
-/// \brief Store the tag value for the given case into a single-payload enum,
-///        whose associated payload (if any) has already been initialized.
+using storeExtraInhabitantTag_t =
+  SWIFT_CC(swift) void (OpaqueValue *value,
+                        unsigned whichCase,
+                        unsigned numExtraInhabitants,
+                        const Metadata *payloadType);
+
+/// Implement storeEnumTagSinglePayload generically in terms of a
+/// payload type with a storeExtraInhabitant function.
 ///
 /// \param value - pointer to the enum value. If the case being initialized is
 ///                the payload case (0), then the payload should be
 ///                initialized.
-/// \param payload - type metadata for the payload case of the enum.
+/// \param payloadType - type metadata for the payload case of the enum.
 /// \param whichCase - unique value identifying the case. 0 for the payload
 ///                    case, or a value greater than or equal to one and less
 ///                    than or equal emptyCases for an empty case.
 /// \param emptyCases - the number of empty cases in the enum.
-SWIFT_RUNTIME_EXPORT
-void swift_storeEnumTagSinglePayload(OpaqueValue *value,
-                                     const Metadata *payload,
-                                     unsigned whichCase,
-                                     unsigned emptyCases);
+SWIFT_RUNTIME_EXPORT SWIFT_CC(swift)
+void swift_storeEnumTagSinglePayloadGeneric(OpaqueValue *value,
+                                            unsigned whichCase,
+                                            unsigned emptyCases,
+                                            const Metadata *payloadType,
+                                            storeExtraInhabitantTag_t *storeTag);
 
 /// \brief Initialize the type metadata for a generic, multi-payload
 ///        enum instance.
diff --git a/include/swift/Runtime/Metadata.h b/include/swift/Runtime/Metadata.h
index 0aec2af..265b3bb 100644
--- a/include/swift/Runtime/Metadata.h
+++ b/include/swift/Runtime/Metadata.h
@@ -90,56 +90,26 @@
                            OpaqueValue *src,
                            const Metadata *self);
  
-/// A value-witness table with extra inhabitants entry points.
-/// These entry points are available only if the HasExtraInhabitants flag bit is
-/// set in the 'flags' field.
-struct ExtraInhabitantsValueWitnessTable : ValueWitnessTable {
-#define WANT_ONLY_EXTRA_INHABITANT_VALUE_WITNESSES
-#define VALUE_WITNESS(LOWER_ID, UPPER_ID) \
-  ValueWitnessTypes::LOWER_ID LOWER_ID;
-#include "swift/ABI/ValueWitness.def"
-
-#define SET_WITNESS(NAME) base.NAME,
-
-  constexpr ExtraInhabitantsValueWitnessTable()
-    : ValueWitnessTable{}, extraInhabitantFlags(),
-      storeExtraInhabitant(nullptr),
-      getExtraInhabitantIndex(nullptr) {}
-  constexpr ExtraInhabitantsValueWitnessTable(
-                            const ValueWitnessTable &base,
-                            ValueWitnessTypes::extraInhabitantFlags eif,
-                            ValueWitnessTypes::storeExtraInhabitant sei,
-                            ValueWitnessTypes::getExtraInhabitantIndex geii)
-    : ValueWitnessTable(base),
-      extraInhabitantFlags(eif),
-      storeExtraInhabitant(sei),
-      getExtraInhabitantIndex(geii) {}
-
-  static bool classof(const ValueWitnessTable *table) {
-    return table->flags.hasExtraInhabitants();
-  }
-};
-
 /// A value-witness table with enum entry points.
 /// These entry points are available only if the HasEnumWitnesses flag bit is
 /// set in the 'flags' field.
-struct EnumValueWitnessTable : ExtraInhabitantsValueWitnessTable {
+struct EnumValueWitnessTable : ValueWitnessTable {
 #define WANT_ONLY_ENUM_VALUE_WITNESSES
 #define VALUE_WITNESS(LOWER_ID, UPPER_ID) \
   ValueWitnessTypes::LOWER_ID LOWER_ID;
 #include "swift/ABI/ValueWitness.def"
 
   constexpr EnumValueWitnessTable()
-    : ExtraInhabitantsValueWitnessTable(),
+    : ValueWitnessTable{},
       getEnumTag(nullptr),
       destructiveProjectEnumData(nullptr),
       destructiveInjectEnumTag(nullptr) {}
   constexpr EnumValueWitnessTable(
-          const ExtraInhabitantsValueWitnessTable &base,
+          const ValueWitnessTable &base,
           ValueWitnessTypes::getEnumTag getEnumTag,
           ValueWitnessTypes::destructiveProjectEnumData destructiveProjectEnumData,
           ValueWitnessTypes::destructiveInjectEnumTag destructiveInjectEnumTag)
-    : ExtraInhabitantsValueWitnessTable(base),
+    : ValueWitnessTable(base),
       getEnumTag(getEnumTag),
       destructiveProjectEnumData(destructiveProjectEnumData),
       destructiveInjectEnumTag(destructiveInjectEnumTag) {}
@@ -155,47 +125,44 @@
 /// extra inhabitants, and miscellaneous flags about the type.
 struct TypeLayout {
   ValueWitnessTypes::size size;
-  ValueWitnessTypes::flags flags;
   ValueWitnessTypes::stride stride;
+  ValueWitnessTypes::flags flags;
+  ValueWitnessTypes::extraInhabitantCount extraInhabitantCount;
 
 private:
-  // Only available if the "hasExtraInhabitants" flag is set.
-  ValueWitnessTypes::extraInhabitantFlags extraInhabitantFlags;
-
   void _static_assert_layout();
 public:
   TypeLayout() = default;
   constexpr TypeLayout(ValueWitnessTypes::size size,
-                       ValueWitnessTypes::flags flags,
                        ValueWitnessTypes::stride stride,
-                       ValueWitnessTypes::extraInhabitantFlags eiFlags =
-                         ValueWitnessTypes::extraInhabitantFlags())
-    : size(size), flags(flags), stride(stride),
-      extraInhabitantFlags(eiFlags) {}
-
-  ValueWitnessTypes::extraInhabitantFlags getExtraInhabitantFlags() const {
-    assert(flags.hasExtraInhabitants());
-    return extraInhabitantFlags;
-  }
+                       ValueWitnessTypes::flags flags,
+                       ValueWitnessTypes::extraInhabitantCount xiCount)
+    : size(size), stride(stride), flags(flags), extraInhabitantCount(xiCount) {}
 
   const TypeLayout *getTypeLayout() const { return this; }
 
   /// The number of extra inhabitants, that is, bit patterns that do not form
   /// valid values of the type, in this type's binary representation.
-  unsigned getNumExtraInhabitants() const;
+  unsigned getNumExtraInhabitants() const {
+    return extraInhabitantCount;
+  }
+
+  bool hasExtraInhabitants() const {
+    return extraInhabitantCount != 0;
+  }
 };
 
 inline void TypeLayout::_static_assert_layout() {
   #define CHECK_TYPE_LAYOUT_OFFSET(FIELD)                               \
-    static_assert(offsetof(ExtraInhabitantsValueWitnessTable, FIELD)    \
-                    - offsetof(ExtraInhabitantsValueWitnessTable, size) \
+    static_assert(offsetof(ValueWitnessTable, FIELD)                    \
+                    - offsetof(ValueWitnessTable, size)                 \
                   == offsetof(TypeLayout, FIELD),                       \
                   "layout of " #FIELD " in TypeLayout doesn't match "   \
                   "value witness table")
   CHECK_TYPE_LAYOUT_OFFSET(size);
   CHECK_TYPE_LAYOUT_OFFSET(flags);
+  CHECK_TYPE_LAYOUT_OFFSET(extraInhabitantCount);
   CHECK_TYPE_LAYOUT_OFFSET(stride);
-  CHECK_TYPE_LAYOUT_OFFSET(extraInhabitantFlags);
 
   #undef CHECK_TYPE_LAYOUT_OFFSET
 }
@@ -204,6 +171,7 @@
 inline void ValueWitnessTable::publishLayout(const TypeLayout &layout) {
   size = layout.size;
   stride = layout.stride;
+  extraInhabitantCount = layout.extraInhabitantCount;
 
   // Currently there is nothing in the runtime or ABI which tries to
   // asynchronously check completion, so we can just do a normal store here.
@@ -221,53 +189,32 @@
 }
 
 template <>
-inline const ExtraInhabitantsValueWitnessTable *
-ValueWitnessTable::_asXIVWT() const {
-  assert(ExtraInhabitantsValueWitnessTable::classof(this));
-  return static_cast<const ExtraInhabitantsValueWitnessTable *>(this);
-}
-
-template <>
 inline const EnumValueWitnessTable *ValueWitnessTable::_asEVWT() const {
   assert(EnumValueWitnessTable::classof(this));
   return static_cast<const EnumValueWitnessTable *>(this);
 }
 
-template <> inline unsigned ValueWitnessTable::getNumExtraInhabitants() const {
-  // If the table does not have extra inhabitant witnesses, then there are zero.
-  if (!flags.hasExtraInhabitants())
-    return 0;
-  return this->_asXIVWT()->extraInhabitantFlags.getNumExtraInhabitants();
-}
-
-inline unsigned TypeLayout::getNumExtraInhabitants() const {
-  // If the table does not have extra inhabitant witnesses, then there are zero.
-  if (!flags.hasExtraInhabitants())
-    return 0;
-  return extraInhabitantFlags.getNumExtraInhabitants();
-}
-
 // Standard value-witness tables.
 
 #define BUILTIN_TYPE(Symbol, _) \
   SWIFT_RUNTIME_EXPORT const ValueWitnessTable VALUE_WITNESS_SYM(Symbol);
 #define BUILTIN_POINTER_TYPE(Symbol, _) \
-  SWIFT_RUNTIME_EXPORT const ExtraInhabitantsValueWitnessTable VALUE_WITNESS_SYM(Symbol);
+  SWIFT_RUNTIME_EXPORT const ValueWitnessTable VALUE_WITNESS_SYM(Symbol);
 #include "swift/Runtime/BuiltinTypes.def"
 
 // The () -> () table can be used for arbitrary function types.
 SWIFT_RUNTIME_EXPORT
-const ExtraInhabitantsValueWitnessTable
+const ValueWitnessTable
   VALUE_WITNESS_SYM(FUNCTION_MANGLING);     // () -> ()
 
 // The @escaping () -> () table can be used for arbitrary escaping function types.
 SWIFT_RUNTIME_EXPORT
-const ExtraInhabitantsValueWitnessTable
+const ValueWitnessTable
   VALUE_WITNESS_SYM(NOESCAPE_FUNCTION_MANGLING);     // @noescape () -> ()
 
 // The @convention(thin) () -> () table can be used for arbitrary thin function types.
 SWIFT_RUNTIME_EXPORT
-const ExtraInhabitantsValueWitnessTable
+const ValueWitnessTable
   VALUE_WITNESS_SYM(THIN_FUNCTION_MANGLING);    // @convention(thin) () -> ()
 
 // The () table can be used for arbitrary empty types.
@@ -276,7 +223,7 @@
 
 // The table for aligned-pointer-to-pointer types.
 SWIFT_RUNTIME_EXPORT
-const ExtraInhabitantsValueWitnessTable METATYPE_VALUE_WITNESS_SYM(Bo); // Builtin.NativeObject.Type
+const ValueWitnessTable METATYPE_VALUE_WITNESS_SYM(Bo); // Builtin.NativeObject.Type
 
 /// Return the value witnesses for unmanaged pointers.
 static inline const ValueWitnessTable &getUnmanagedPointerValueWitnesses() {
@@ -289,7 +236,7 @@
 
 /// Return value witnesses for a pointer-aligned pointer type.
 static inline
-const ExtraInhabitantsValueWitnessTable &
+const ValueWitnessTable &
 getUnmanagedPointerPointerValueWitnesses() {
   return METATYPE_VALUE_WITNESS_SYM(Bo);
 }
diff --git a/include/swift/Runtime/RuntimeFunctions.def b/include/swift/Runtime/RuntimeFunctions.def
index 4723fe5..cb6a0d2 100644
--- a/include/swift/Runtime/RuntimeFunctions.def
+++ b/include/swift/Runtime/RuntimeFunctions.def
@@ -863,15 +863,6 @@
          ARGS(TypeMetadataPtrTy, SizeTy, SizeTy, Int8PtrPtrTy->getPointerTo(0)),
          ATTRS(NoUnwind))
 
-// int swift_getEnumCaseSinglePayload(opaque_t *obj, Metadata *payload,
-//                                    unsigned num_empty_cases);
-FUNCTION(GetEnumCaseSinglePayload,
-         swift_getEnumCaseSinglePayload,
-         C_CC,
-         RETURNS(Int32Ty),
-         ARGS(OpaquePtrTy, TypeMetadataPtrTy, Int32Ty),
-         ATTRS(NoUnwind, ReadOnly))
-
 // int swift_getEnumCaseMultiPayload(opaque_t *obj, Metadata *enumTy);
 FUNCTION(GetEnumCaseMultiPayload,
          swift_getEnumCaseMultiPayload,
@@ -880,14 +871,39 @@
          ARGS(OpaquePtrTy, TypeMetadataPtrTy),
          ATTRS(NoUnwind, ReadOnly))
 
-// void swift_storeEnumTagSinglePayload(opaque_t *obj, Metadata *payload,
-//                                      unsigned case_index,
-//                                      unsigned num_empty_cases);
-FUNCTION(StoreEnumTagSinglePayload,
-         swift_storeEnumTagSinglePayload,
-         C_CC,
+// int swift_getEnumTagSinglePayloadGeneric(opaque_t *obj,
+//                                          unsigned num_empty_cases,
+//                                          Metadata *payloadType,
+//                         int (*getExtraInhabitantIndex)(opaque_t *obj,
+//                                                        unsigned numPayloadXI,
+//                                                        Metadata *payload));
+FUNCTION(GetEnumTagSinglePayloadGeneric,
+         swift_getEnumTagSinglePayloadGeneric,
+         SwiftCC,
+         RETURNS(Int32Ty),
+         ARGS(OpaquePtrTy, Int32Ty, TypeMetadataPtrTy,
+              llvm::FunctionType::get(Int32Ty, {OpaquePtrTy, Int32Ty,
+                                                TypeMetadataPtrTy},
+                                      false)->getPointerTo()),
+         ATTRS(NoUnwind, ReadOnly))
+
+
+// void swift_storeEnumTagSinglePayloadGeneric(opaque_t *obj,
+//                                             unsigned case_index,
+//                                             unsigned num_empty_cases,
+//                                             Metadata *payloadType,
+//                           void (*storeExtraInhabitant)(opaque_t *obj,
+//                                                        unsigned case_index,
+//                                                        unsigned numPayloadXI,
+//                                                        Metadata *payload));
+FUNCTION(StoreEnumTagSinglePayloadGeneric,
+         swift_storeEnumTagSinglePayloadGeneric,
+         SwiftCC,
          RETURNS(VoidTy),
-         ARGS(OpaquePtrTy, TypeMetadataPtrTy, Int32Ty, Int32Ty),
+         ARGS(OpaquePtrTy, Int32Ty, Int32Ty, TypeMetadataPtrTy,
+              llvm::FunctionType::get(VoidTy, {OpaquePtrTy, Int32Ty, Int32Ty,
+                                               TypeMetadataPtrTy},
+                                      false)->getPointerTo()),
          ATTRS(NoUnwind))
 
 // void swift_storeEnumTagMultiPayload(opaque_t *obj, Metadata *enumTy,
diff --git a/lib/IRGen/ExtraInhabitants.cpp b/lib/IRGen/ExtraInhabitants.cpp
index 7805656..1bd0564 100644
--- a/lib/IRGen/ExtraInhabitants.cpp
+++ b/lib/IRGen/ExtraInhabitants.cpp
@@ -19,6 +19,7 @@
 #include "IRGenModule.h"
 #include "IRGenFunction.h"
 #include "SwiftTargetInfo.h"
+#include "swift/ABI/MetadataValues.h"
 
 using namespace swift;
 using namespace irgen;
@@ -44,8 +45,9 @@
   uint64_t rawCount =
     IGM.TargetInfo.LeastValidPointerValue >> numReservedLowBits;
   
-  // The runtime limits the count to INT_MAX.
-  return std::min((uint64_t)INT_MAX, rawCount);
+  // The runtime limits the count.
+  return std::min(uint64_t(ValueWitnessFlags::MaxNumExtraInhabitants),
+                  rawCount);
 }
 
 unsigned irgen::getHeapObjectExtraInhabitantCount(const IRGenModule &IGM) {
diff --git a/lib/IRGen/FixedTypeInfo.h b/lib/IRGen/FixedTypeInfo.h
index 97981f2..2834622 100644
--- a/lib/IRGen/FixedTypeInfo.h
+++ b/lib/IRGen/FixedTypeInfo.h
@@ -167,9 +167,9 @@
   
   /// Map an extra inhabitant representation in memory to a unique 31-bit
   /// identifier, and map a valid representation of the type to -1.
-  llvm::Value *getExtraInhabitantIndex(IRGenFunction &IGF,
-                                       Address src, SILType T,
-                                       bool isOutlined) const override {
+  virtual llvm::Value *getExtraInhabitantIndex(IRGenFunction &IGF,
+                                               Address src, SILType T,
+                                               bool isOutlined) const {
     return getSpareBitExtraInhabitantIndex(IGF, src);
   }
   
@@ -180,10 +180,10 @@
   
   /// Store the extra inhabitant representation indexed by a 31-bit identifier
   /// to memory.
-  void storeExtraInhabitant(IRGenFunction &IGF,
-                            llvm::Value *index,
-                            Address dest, SILType T,
-                            bool isOutlined) const override {
+  virtual void storeExtraInhabitant(IRGenFunction &IGF,
+                                    llvm::Value *index,
+                                    Address dest, SILType T,
+                                    bool isOutlined) const {
     storeSpareBitExtraInhabitant(IGF, index, dest);
   }
   
@@ -236,16 +236,30 @@
   llvm::Value *getEnumTagSinglePayload(IRGenFunction &IGF,
                                        llvm::Value *numEmptyCases,
                                        Address enumAddr,
-                                       SILType T) const override;
+                                       SILType T,
+                                       bool isOutlined) const override;
 
   void storeEnumTagSinglePayload(IRGenFunction &IGF, llvm::Value *whichCase,
                                  llvm::Value *numEmptyCases, Address enumAddr,
-                                 SILType T) const override;
+                                 SILType T, bool isOutlined) const override;
 
   static bool classof(const FixedTypeInfo *type) { return true; }
   static bool classof(const TypeInfo *type) { return type->isFixedSize(); }
 };
 
+llvm::Value *getFixedTypeEnumTagSinglePayload(IRGenFunction &IGF,
+                                              const FixedTypeInfo &fixedTI,
+                                              llvm::Value *numEmptyCases,
+                                              Address enumAddr,
+                                              SILType T, bool isOutlined);
+
+void storeFixedTypeEnumTagSinglePayload(IRGenFunction &IGF,
+                                        const FixedTypeInfo &fixedTI,
+                                        llvm::Value *index,
+                                        llvm::Value *numEmptyCases,
+                                        Address enumAddr,
+                                        SILType T, bool isOutlined);
+
 }
 }
 
diff --git a/lib/IRGen/GenEnum.cpp b/lib/IRGen/GenEnum.cpp
index c1caaff..72c78a0 100644
--- a/lib/IRGen/GenEnum.cpp
+++ b/lib/IRGen/GenEnum.cpp
@@ -649,7 +649,7 @@
         return llvm::ConstantInt::getSigned(IGF.IGM.Int32Ty, -1);
       }
 
-      return getSingleton()->getExtraInhabitantIndex(IGF,
+      return getFixedSingleton()->getExtraInhabitantIndex(IGF,
                                              getSingletonAddress(IGF, src),
                                              getSingletonType(IGF.IGM, T),
                                              isOutlined);
@@ -663,10 +663,44 @@
         // Nothing to store for empty singletons.
         return;
       }
-      getSingleton()->storeExtraInhabitant(IGF, index,
-                                           getSingletonAddress(IGF, dest),
-                                           getSingletonType(IGF.IGM, T),
+      getFixedSingleton()->storeExtraInhabitant(IGF, index,
+                                                getSingletonAddress(IGF, dest),
+                                                getSingletonType(IGF.IGM, T),
+                                                isOutlined);
+    }
+
+    llvm::Value *getEnumTagSinglePayload(IRGenFunction &IGF,
+                                         llvm::Value *numEmptyCases,
+                                         Address src, SILType T,
+                                         bool isOutlined) const override {
+      if (!getSingleton()) {
+        return getFixedTypeEnumTagSinglePayload(IGF, cast<FixedTypeInfo>(*TI),
+                                                numEmptyCases, src, T,
+                                                isOutlined);
+      }
+
+      return getSingleton()->getEnumTagSinglePayload(IGF, numEmptyCases,
+                                                getSingletonAddress(IGF, src),
+                                                getSingletonType(IGF.IGM, T),
+                                                isOutlined);
+    }
+
+    void storeEnumTagSinglePayload(IRGenFunction &IGF,
+                                   llvm::Value *index,
+                                   llvm::Value *numEmptyCases,
+                                   Address src, SILType T,
+                                   bool isOutlined) const override {
+      if (!getSingleton()) {
+        storeFixedTypeEnumTagSinglePayload(IGF, cast<FixedTypeInfo>(*TI),
+                                           index, numEmptyCases, src, T,
                                            isOutlined);
+        return;
+      }
+
+      getSingleton()->storeEnumTagSinglePayload(IGF, index, numEmptyCases,
+                                                getSingletonAddress(IGF, src),
+                                                getSingletonType(IGF.IGM, T),
+                                                isOutlined);
     }
 
     unsigned getFixedExtraInhabitantCount(IRGenModule &IGM) const override {
@@ -1007,7 +1041,9 @@
       assert(bits < 32 && "freakishly huge no-payload enum");
 
       size_t shifted = static_cast<size_t>(static_cast<size_t>(1) << bits);
-      return shifted - ElementsWithNoPayload.size();
+      size_t rawCount = shifted - ElementsWithNoPayload.size();
+      return std::min(rawCount,
+                      size_t(ValueWitnessFlags::MaxNumExtraInhabitants));
     }
 
     APInt getFixedExtraInhabitantValue(IRGenModule &IGM,
@@ -1061,6 +1097,25 @@
                 llvm::ConstantInt::get(payloadTy, ElementsWithNoPayload.size()));
       IGF.Builder.CreateStore(index, dest);
     }
+
+    llvm::Value *getEnumTagSinglePayload(IRGenFunction &IGF,
+                                         llvm::Value *numEmptyCases,
+                                         Address src, SILType T,
+                                         bool isOutlined) const override {
+      return getFixedTypeEnumTagSinglePayload(IGF, cast<FixedTypeInfo>(*TI),
+                                              numEmptyCases, src, T,
+                                              isOutlined);
+    }
+
+    void storeEnumTagSinglePayload(IRGenFunction &IGF,
+                                   llvm::Value *index,
+                                   llvm::Value *numEmptyCases,
+                                   Address src, SILType T,
+                                   bool isOutlined) const override {
+      storeFixedTypeEnumTagSinglePayload(IGF, cast<FixedTypeInfo>(*TI),
+                                         index, numEmptyCases, src, T,
+                                         isOutlined);
+    }
   };
 
   /// Implementation strategy for C-compatible enums, where none of the cases
@@ -1137,6 +1192,25 @@
       llvm_unreachable("no extra inhabitants");
     }
 
+    llvm::Value *getEnumTagSinglePayload(IRGenFunction &IGF,
+                                         llvm::Value *numEmptyCases,
+                                         Address src, SILType T,
+                                         bool isOutlined) const override {
+      return getFixedTypeEnumTagSinglePayload(IGF, cast<FixedTypeInfo>(*TI),
+                                              numEmptyCases, src, T,
+                                              isOutlined);
+    }
+
+    void storeEnumTagSinglePayload(IRGenFunction &IGF,
+                                   llvm::Value *index,
+                                   llvm::Value *numEmptyCases,
+                                   Address src, SILType T,
+                                   bool isOutlined) const override {
+      storeFixedTypeEnumTagSinglePayload(IGF, cast<FixedTypeInfo>(*TI),
+                                         index, numEmptyCases, src, T,
+                                         isOutlined);
+    }
+
     bool isReflectable() const override {
       // C enums have arbitrary values and we don't preserve the mapping
       // between the case and raw value at runtime, so don't mark it as
@@ -2927,10 +3001,17 @@
                             bool isOutlined) const override {
       auto payload = projectPayloadData(IGF, src);
       llvm::Value *index
-        = getPayloadTypeInfo().getExtraInhabitantIndex(IGF, payload,
+        = getFixedPayloadTypeInfo().getExtraInhabitantIndex(IGF, payload,
                                                    getPayloadType(IGF.IGM, T),
                                                    isOutlined);
 
+      return adjustPayloadExtraInhabitantIndex(IGF, index);
+    }
+
+    /// Given an extra inhabitant index for the payload type, adjust it to
+    /// be an appropriate extra inhabitant index for the enum type.
+    llvm::Value *adjustPayloadExtraInhabitantIndex(IRGenFunction &IGF,
+                                                   llvm::Value *index) const {
       // Offset the payload extra inhabitant index by the number of inhabitants
       // we used. If less than zero, it's a valid value of the enum type.
       index = IGF.Builder.CreateSub(index,
@@ -2947,16 +3028,147 @@
                               llvm::Value *index,
                               Address dest, SILType T,
                               bool isOutlined) const override {
-      // Offset the index to skip the extra inhabitants we used.
-      index = IGF.Builder.CreateAdd(index,
-          llvm::ConstantInt::get(IGF.IGM.Int32Ty, ElementsWithNoPayload.size()));
-
+      index = adjustExtraInhabitantIndexForPayload(IGF, index);
       auto payload = projectPayloadData(IGF, dest);
-      getPayloadTypeInfo().storeExtraInhabitant(IGF, index, payload,
+      getFixedPayloadTypeInfo().storeExtraInhabitant(IGF, index, payload,
                                                 getPayloadType(IGF.IGM, T),
                                                 isOutlined);
     }
-    
+
+    /// Given an extra inhabitant index, adjust it to be an appropriate
+    /// extra inhabitant index for the payload type.
+    llvm::Value *adjustExtraInhabitantIndexForPayload(IRGenFunction &IGF,
+                                                      llvm::Value *index) const{
+      // Skip the extra inhabitants this enum uses.
+      index = IGF.Builder.CreateAdd(index,
+        llvm::ConstantInt::get(IGF.IGM.Int32Ty, ElementsWithNoPayload.size()));
+      return index;
+    }
+
+    llvm::Value *getEnumTagSinglePayload(IRGenFunction &IGF,
+                                         llvm::Value *numEmptyCases,
+                                         Address addr, SILType T,
+                                         bool isOutlined) const override {
+      if (TIK >= Fixed) {
+        return getFixedTypeEnumTagSinglePayload(IGF, cast<FixedTypeInfo>(*TI),
+                                                numEmptyCases, addr, T,
+                                                isOutlined);
+      }
+
+      // If we're not emitting an outlined copy, just call the value witness.
+      if (!isOutlined) {
+        return emitGetEnumTagSinglePayloadCall(IGF, T, numEmptyCases, addr);
+      }
+
+      // Otherwise, fall back on a generic implementation.
+      // TODO: consider inlining some of this so that we don't have to
+      // bounce into the runtime when e.g. dynamically working with
+      // double-optionals.
+      return emitGetEnumTagSinglePayloadGenericCall(IGF, T, *TI, numEmptyCases,
+                                                    addr,
+          [this, T](IRGenFunction &IGF, Address addr,
+                    llvm::Value *numXI) -> llvm::Value* {
+        auto payloadType = getPayloadType(IGF.IGM, T);
+        auto payloadAddr = projectPayloadData(IGF, addr);
+
+        // For the case count, we just use the XI count from the payload type.
+        auto payloadNumExtraCases = numXI;
+
+        llvm::Value *tag
+          = getPayloadTypeInfo().getEnumTagSinglePayload(IGF,
+                                                         payloadNumExtraCases,
+                                                         payloadAddr,
+                                                         payloadType,
+                                                         /*outlined*/ false);
+
+        // We need to adjust that for the number of cases we're using
+        // in this enum.
+        return adjustPayloadExtraInhabitantTag(IGF, tag);
+      });
+    }
+
+    /// Given an extra inhabitant tag for the payload type, adjust it to
+    /// be an appropriate extra inhabitant tag for the enum type.
+    llvm::Value *adjustPayloadExtraInhabitantTag(IRGenFunction &IGF,
+                                                 llvm::Value *tag) const {
+      auto numExtraCases = IGF.IGM.getInt32(ElementsWithNoPayload.size());
+
+      // Adjust the tag.
+      llvm::Value *adjustedTag = IGF.Builder.CreateSub(tag, numExtraCases);
+
+      // If tag <= numExtraCases, then this is a valid value of the enum type,
+      // and the proper tag to return is 0.
+      auto isEnumValue = IGF.Builder.CreateICmpULE(tag, numExtraCases);
+      adjustedTag = IGF.Builder.CreateSelect(isEnumValue,
+                                             IGF.IGM.getInt32(0),
+                                             adjustedTag);
+      return adjustedTag;
+    }
+
+    void storeEnumTagSinglePayload(IRGenFunction &IGF,
+                                   llvm::Value *tag,
+                                   llvm::Value *numEmptyCases,
+                                   Address dest, SILType T,
+                                   bool isOutlined) const override {
+      if (TIK >= Fixed) {
+        storeFixedTypeEnumTagSinglePayload(IGF, cast<FixedTypeInfo>(*TI),
+                                           tag, numEmptyCases, dest, T,
+                                           isOutlined);
+        return;
+      }
+
+      // If we're not emitting an outlined copy, just call the value witness.
+      if (!isOutlined) {
+        emitStoreEnumTagSinglePayloadCall(IGF, T, tag, numEmptyCases, dest);
+        return;
+      }
+
+      // Otherwise, fall back on a generic implementation.
+      // TODO: consider inlining some of this so that we don't have to
+      // bounce into the runtime when e.g. dynamically working with
+      // double-optionals.
+      emitStoreEnumTagSinglePayloadGenericCall(IGF, T, *TI, tag,
+                                               numEmptyCases, dest,
+          [this, T](IRGenFunction &IGF, Address dest, llvm::Value *tag,
+                    llvm::Value *payloadNumXI) {
+        auto payloadType = getPayloadType(IGF.IGM, T);
+        auto payloadDest = projectPayloadData(IGF, dest);
+        auto payloadTag = adjustExtraInhabitantTagForPayload(IGF, tag,
+                                                             /*nonzero*/false);
+
+        getPayloadTypeInfo().storeEnumTagSinglePayload(IGF, payloadTag,
+                                                       payloadNumXI,
+                                                       payloadDest,
+                                                       payloadType,
+                                                       /*outlined*/ false);
+      });
+    }
+
+    /// Given an extra inhabitant tag for the payload type, which is known
+    /// not to be 0, adjust it to be an appropriate extra inhabitant tag
+    /// for the enum type.
+    llvm::Value *adjustExtraInhabitantTagForPayload(IRGenFunction &IGF,
+                                                    llvm::Value *tag,
+                                                    bool isKnownNonZero) const {
+      auto numExtraCases = IGF.IGM.getInt32(ElementsWithNoPayload.size());
+
+      // Adjust the tag.
+      llvm::Value *adjustedTag = IGF.Builder.CreateAdd(tag, numExtraCases);
+
+      // Preserve the zero tag so that we don't pass down a meaningless XI
+      // value that the payload will waste time installing before we
+      // immediately overwrite it.
+      if (!isKnownNonZero) {
+        // If tag <= numExtraCases, then this is a valid value of the enum type,
+        // and the proper tag to return is 0.
+        auto isEnumValue = IGF.Builder.CreateIsNull(tag);
+        adjustedTag = IGF.Builder.CreateSelect(isEnumValue,
+                                               IGF.IGM.getInt32(0),
+                                               adjustedTag);
+      }
+      return adjustedTag;
+    }
+
     APInt
     getFixedExtraInhabitantMask(IRGenModule &IGM) const override {
       auto &payloadTI = getFixedPayloadTypeInfo();
@@ -4874,11 +5086,15 @@
                                          Address src,
                                          SILType T,
                                          bool isOutlined) const override {
-      // For dynamic layouts, the runtime provides a value witness to do this.
-      if (TIK < Fixed) {
-        return emitGetExtraInhabitantIndexCall(IGF, T, src);
-      }
-      
+      assert(TIK >= Fixed);
+      return getExtraInhabitantIndexImpl(IGF, src, T, isOutlined,
+                                         getFixedExtraInhabitantCount(IGF.IGM));
+    }
+
+    llvm::Value *getExtraInhabitantIndexImpl(IRGenFunction &IGF,
+                                             Address src, SILType T,
+                                             bool isOutlined,
+                                             unsigned xiCount) const {
       llvm::Value *tag;
       if (CommonSpareBits.count()) {
         auto payload = EnumPayload::load(IGF, projectPayload(IGF, src),
@@ -4932,8 +5148,7 @@
                                llvm::ConstantInt::get(IGF.IGM.Int32Ty, maxTag),
                                tag);
       auto isExtraInhabitant = IGF.Builder.CreateICmpULT(index,
-                 llvm::ConstantInt::get(IGF.IGM.Int32Ty,
-                                        getFixedExtraInhabitantCount(IGF.IGM)));
+                              llvm::ConstantInt::get(IGF.IGM.Int32Ty, xiCount));
       return IGF.Builder.CreateSelect(isExtraInhabitant,
                             index, llvm::ConstantInt::get(IGF.IGM.Int32Ty, -1));
     }
@@ -4943,11 +5158,7 @@
                               Address dest,
                               SILType T,
                               bool isOutlined) const override {
-      // For dynamic layouts, the runtime provides a value witness to do this.
-      if (TIK < Fixed) {
-        emitStoreExtraInhabitantCall(IGF, T, index, dest);
-        return;
-      }
+      assert(TIK >= Fixed);
 
       auto indexValue = IGF.Builder.CreateNot(index);
       
@@ -4995,6 +5206,36 @@
         IGF.Builder.CreateStore(indexValue, tagAddr);
       }
     }
+
+    llvm::Value *getEnumTagSinglePayload(IRGenFunction &IGF,
+                                         llvm::Value *numEmptyCases,
+                                         Address src, SILType T,
+                                         bool isOutlined) const override {
+      if (TIK < Fixed) {
+        // For dynamic layouts, the runtime provides a value witness to do this.
+        return emitGetEnumTagSinglePayloadCall(IGF, T, numEmptyCases, src);
+      }
+
+      return getFixedTypeEnumTagSinglePayload(IGF, cast<FixedTypeInfo>(*TI),
+                                              numEmptyCases, src, T,
+                                              isOutlined);
+    }
+
+    void storeEnumTagSinglePayload(IRGenFunction &IGF,
+                                   llvm::Value *index,
+                                   llvm::Value *numEmptyCases,
+                                   Address src, SILType T,
+                                   bool isOutlined) const override {
+      if (TIK < Fixed) {
+        // For dynamic layouts, the runtime provides a value witness to do this.
+        emitStoreEnumTagSinglePayloadCall(IGF, T, index, numEmptyCases, src);
+        return;
+      }
+
+      storeFixedTypeEnumTagSinglePayload(IGF, cast<FixedTypeInfo>(*TI),
+                                         index, numEmptyCases, src, T,
+                                         isOutlined);
+    }
     
     APInt
     getFixedExtraInhabitantMask(IRGenModule &IGM) const override {
@@ -5014,9 +5255,12 @@
     unsigned getFixedExtraInhabitantCount(IRGenModule &IGM) const override {
       unsigned totalTagBits = CommonSpareBits.count() + getExtraTagBitCountForExtraInhabitants();
       if (totalTagBits >= 32)
-        return INT_MAX;
+        return ValueWitnessFlags::MaxNumExtraInhabitants;
       unsigned totalTags = 1u << totalTagBits;
-      return totalTags - ElementsWithPayload.size() - NumEmptyElementTags;
+      unsigned rawCount =
+        totalTags - ElementsWithPayload.size() - NumEmptyElementTags;
+      return std::min(rawCount,
+                      unsigned(ValueWitnessFlags::MaxNumExtraInhabitants));
     }
 
     APInt
@@ -5433,7 +5677,7 @@
                                          Address src,
                                          SILType T,
                                          bool isOutlined) const override {
-      return emitGetExtraInhabitantIndexCall(IGF, T, src);
+      llvm_unreachable("resilient enums are never fixed-layout types");
     }
 
     void storeExtraInhabitant(IRGenFunction &IGF,
@@ -5441,7 +5685,22 @@
                               Address dest,
                               SILType T,
                               bool isOutlined) const override {
-      emitStoreExtraInhabitantCall(IGF, T, index, dest);
+      llvm_unreachable("resilient enums are never fixed-layout types");
+    }
+
+    llvm::Value *getEnumTagSinglePayload(IRGenFunction &IGF,
+                                         llvm::Value *numEmptyCases,
+                                         Address src, SILType T,
+                                         bool isOutlined) const override {
+      return emitGetEnumTagSinglePayloadCall(IGF, T, numEmptyCases, src);
+    }
+
+    void storeEnumTagSinglePayload(IRGenFunction &IGF,
+                                   llvm::Value *index,
+                                   llvm::Value *numEmptyCases,
+                                   Address src, SILType T,
+                                   bool isOutlined) const override {
+      emitStoreEnumTagSinglePayloadCall(IGF, T, index, numEmptyCases, src);
     }
 
     APInt
@@ -5663,18 +5922,22 @@
     bool mayHaveExtraInhabitants(IRGenModule &IGM) const override {
       return Strategy.mayHaveExtraInhabitants(IGM);
     }
-    llvm::Value *getExtraInhabitantIndex(IRGenFunction &IGF,
-                                         Address src,
+    llvm::Value *getEnumTagSinglePayload(IRGenFunction &IGF,
+                                         llvm::Value *numEmptyCases,
+                                         Address enumAddr,
                                          SILType T,
                                          bool isOutlined) const override {
-      return Strategy.getExtraInhabitantIndex(IGF, src, T, isOutlined);
+      return Strategy.getEnumTagSinglePayload(IGF, numEmptyCases, enumAddr, T,
+                                              isOutlined);
     }
-    void storeExtraInhabitant(IRGenFunction &IGF,
-                              llvm::Value *index,
-                              Address dest,
-                              SILType T,
-                              bool isOutlined) const override {
-      return Strategy.storeExtraInhabitant(IGF, index, dest, T, isOutlined);
+    void storeEnumTagSinglePayload(IRGenFunction &IGF,
+                                   llvm::Value *whichCase,
+                                   llvm::Value *numEmptyCases,
+                                   Address enumAddr,
+                                   SILType T,
+                                   bool isOutlined) const override {
+      return Strategy.storeEnumTagSinglePayload(IGF, whichCase, numEmptyCases,
+                                                enumAddr, T, isOutlined);
     }
     bool isSingleRetainablePointer(ResilienceExpansion expansion,
                                    ReferenceCounting *rc) const override {
@@ -5682,15 +5945,13 @@
     }
   };
 
-  /// TypeInfo for fixed-layout, address-only enum types.
-  class FixedEnumTypeInfo : public EnumTypeInfoBase<FixedTypeInfo> {
+  template <class Base>
+  class FixedEnumTypeInfoBase : public EnumTypeInfoBase<Base> {
+  protected:
+    using EnumTypeInfoBase<Base>::EnumTypeInfoBase;
+
   public:
-    FixedEnumTypeInfo(EnumImplStrategy &strategy,
-                      llvm::StructType *T, Size S, SpareBitVector SB,
-                      Alignment A, IsPOD_t isPOD, IsBitwiseTakable_t isBT,
-                      IsFixedSize_t alwaysFixedSize)
-      : EnumTypeInfoBase(strategy, T, S, std::move(SB), A, isPOD, isBT,
-                         alwaysFixedSize) {}
+    using EnumTypeInfoBase<Base>::Strategy;
 
     /// \group Methods delegated to the EnumImplStrategy
 
@@ -5708,18 +5969,43 @@
     APInt getFixedExtraInhabitantMask(IRGenModule &IGM) const override {
       return Strategy.getFixedExtraInhabitantMask(IGM);
     }
+
+    llvm::Value *getExtraInhabitantIndex(IRGenFunction &IGF,
+                                         Address src,
+                                         SILType T,
+                                         bool isOutlined) const override {
+      return Strategy.getExtraInhabitantIndex(IGF, src, T, isOutlined);
+    }
+    void storeExtraInhabitant(IRGenFunction &IGF,
+                              llvm::Value *index,
+                              Address dest,
+                              SILType T,
+                              bool isOutlined) const override {
+      return Strategy.storeExtraInhabitant(IGF, index, dest, T, isOutlined);
+    }
+  };
+
+  /// TypeInfo for fixed-layout but address-only enum types.
+  class FixedEnumTypeInfo : public FixedEnumTypeInfoBase<FixedTypeInfo> {
+  public:
+    FixedEnumTypeInfo(EnumImplStrategy &strategy,
+                      llvm::StructType *T, Size S, SpareBitVector SB,
+                      Alignment A, IsPOD_t isPOD, IsBitwiseTakable_t isBT,
+                      IsFixedSize_t alwaysFixedSize)
+      : FixedEnumTypeInfoBase(strategy, T, S, std::move(SB), A, isPOD, isBT,
+                              alwaysFixedSize) {}
   };
 
   /// TypeInfo for loadable enum types.
-  class LoadableEnumTypeInfo : public EnumTypeInfoBase<LoadableTypeInfo> {
+  class LoadableEnumTypeInfo : public FixedEnumTypeInfoBase<LoadableTypeInfo> {
   public:
     // FIXME: Derive spare bits from element layout.
     LoadableEnumTypeInfo(EnumImplStrategy &strategy,
                          llvm::StructType *T, Size S, SpareBitVector SB,
                          Alignment A, IsPOD_t isPOD,
                          IsFixedSize_t alwaysFixedSize)
-      : EnumTypeInfoBase(strategy, T, S, std::move(SB), A, isPOD,
-                         alwaysFixedSize) {}
+      : FixedEnumTypeInfoBase(strategy, T, S, std::move(SB), A, isPOD,
+                              alwaysFixedSize) {}
 
     void addToAggLowering(IRGenModule &IGM, SwiftAggLowering &lowering,
                           Size offset) const override {
@@ -5772,20 +6058,6 @@
                                unsigned offset) const override {
       return Strategy.unpackFromEnumPayload(IGF, payload, dest, offset);
     }
-    unsigned getFixedExtraInhabitantCount(IRGenModule &IGM) const override {
-      return Strategy.getFixedExtraInhabitantCount(IGM);
-    }
-
-    APInt getFixedExtraInhabitantValue(IRGenModule &IGM,
-                                       unsigned bits,
-                                       unsigned index)
-    const override {
-      return Strategy.getFixedExtraInhabitantValue(IGM, bits, index);
-    }
-    
-    APInt getFixedExtraInhabitantMask(IRGenModule &IGM) const override {
-      return Strategy.getFixedExtraInhabitantMask(IGM);
-    }
     LoadedRef loadRefcountedPtr(IRGenFunction &IGF,
                                 SourceLoc loc, Address addr) const override {
       return LoadedRef(Strategy.loadRefcountedPtr(IGF, loc, addr), false);
diff --git a/lib/IRGen/GenEnum.h b/lib/IRGen/GenEnum.h
index 50f56e0..d392f60 100644
--- a/lib/IRGen/GenEnum.h
+++ b/lib/IRGen/GenEnum.h
@@ -373,15 +373,28 @@
 
   virtual bool mayHaveExtraInhabitants(IRGenModule &IGM) const = 0;
 
+  // Only ever called for fixed types.
   virtual llvm::Value *getExtraInhabitantIndex(IRGenFunction &IGF,
                                                Address src,
                                                SILType T,
                                                bool isOutlined) const = 0;
+  // Only ever called for fixed types.
   virtual void storeExtraInhabitant(IRGenFunction &IGF,
                                     llvm::Value *index,
                                     Address dest,
                                     SILType T,
                                     bool isOutlined) const = 0;
+  virtual llvm::Value *getEnumTagSinglePayload(IRGenFunction &IGF,
+                                               llvm::Value *numEmptyCases,
+                                               Address enumAddr,
+                                               SILType T,
+                                               bool isOutlined) const = 0;
+  virtual void storeEnumTagSinglePayload(IRGenFunction &IGF,
+                                         llvm::Value *whichCase,
+                                         llvm::Value *numEmptyCases,
+                                         Address enumAddr,
+                                         SILType T,
+                                         bool isOutlined) const = 0;
   
   /// \group Delegated FixedTypeInfo operations
   
diff --git a/lib/IRGen/GenOpaque.cpp b/lib/IRGen/GenOpaque.cpp
index de170fa..c7cab4d 100644
--- a/lib/IRGen/GenOpaque.cpp
+++ b/lib/IRGen/GenOpaque.cpp
@@ -28,6 +28,7 @@
 #include "swift/IRGen/ValueWitness.h"
 
 #include "Callee.h"
+#include "Explosion.h"
 #include "FixedTypeInfo.h"
 #include "IRGenFunction.h"
 #include "IRGenModule.h"
@@ -85,28 +86,6 @@
     return llvm::FunctionType::get(ptrTy, args, /*isVarArg*/ false);
   }
       
-  /// void (*storeExtraInhabitant)(T *obj, unsigned index, M *self);
-  case ValueWitness::StoreExtraInhabitant: {
-    llvm::Type *ptrTy = IGM.OpaquePtrTy;
-    llvm::Type *indexTy = IGM.Int32Ty;
-    llvm::Type *metaTy = IGM.TypeMetadataPtrTy;
-    llvm::Type *voidTy = IGM.VoidTy;
-    llvm::Type *args[] = {ptrTy, indexTy, metaTy};
-    
-    return llvm::FunctionType::get(voidTy, args, /*isVarArg*/ false);
-  }
-      
-  /// int (*getExtraInhabitantIndex)(T *obj, M *self);
-  case ValueWitness::GetExtraInhabitantIndex: {
-    llvm::Type *ptrTy = IGM.OpaquePtrTy;
-    llvm::Type *metaTy = IGM.TypeMetadataPtrTy;
-    llvm::Type *indexTy = IGM.Int32Ty;
-    
-    llvm::Type *args[] = {ptrTy, metaTy};
-    
-    return llvm::FunctionType::get(indexTy, args, /*isVarArg*/ false);
-  }
-  
   /// unsigned (*getEnumTag)(T *obj, M *self);
   case ValueWitness::GetEnumTag: {
     llvm::Type *ptrTy = IGM.OpaquePtrTy;
@@ -166,11 +145,11 @@
   }
 
   case ValueWitness::Size:
-  case ValueWitness::Flags:
   case ValueWitness::Stride:
-  case ValueWitness::ExtraInhabitantFlags:
-    // Non-function witnesses all have type size_t.
     return IGM.SizeTy;
+  case ValueWitness::Flags:
+  case ValueWitness::ExtraInhabitantCount:
+    return IGM.Int32Ty;
   }
 
   llvm_unreachable("bad value witness!");
@@ -196,8 +175,6 @@
   case ValueWitness::DestructiveInjectEnumTag:
   case ValueWitness::DestructiveProjectEnumData:
   case ValueWitness::GetEnumTag:
-  case ValueWitness::GetExtraInhabitantIndex:
-  case ValueWitness::StoreExtraInhabitant:
   case ValueWitness::StoreEnumTagSinglePayload:
     return attrs.addAttribute(ctx, 1, llvm::Attribute::NoAlias);
 
@@ -217,8 +194,8 @@
 
   case ValueWitness::Size:
   case ValueWitness::Flags:
+  case ValueWitness::ExtraInhabitantCount:
   case ValueWitness::Stride:
-  case ValueWitness::ExtraInhabitantFlags:
     llvm_unreachable("not a function value witness");
   }
   llvm_unreachable("bad witness");
@@ -260,14 +237,10 @@
     return "size";
   case ValueWitness::Flags:
     return "flags";
+  case ValueWitness::ExtraInhabitantCount:
+    return "extraInhabitantCount";
   case ValueWitness::Stride:
     return "stride";
-  case ValueWitness::StoreExtraInhabitant:
-    return "storeExtraInhabitant";
-  case ValueWitness::GetExtraInhabitantIndex:
-    return "getExtraInhabitantIndex";
-  case ValueWitness::ExtraInhabitantFlags:
-    return "extraInhabitantFlags";
   case ValueWitness::GetEnumTag:
     return "getEnumTag";
   case ValueWitness::DestructiveProjectEnumData:
@@ -282,6 +255,58 @@
   llvm_unreachable("bad value witness index");
 }
 
+static llvm::PointerType *
+getOrCreateValueWitnessTablePtrTy(IRGenModule &IGM, llvm::PointerType *&cache,
+                                  StringRef name, bool includeEnumWitnesses) {
+  if (cache) return cache;
+
+  SmallVector<llvm::Type*, 16> types;
+
+#define FUNC(lowerId, upperId, retTy, paramTys) \
+  types.push_back(IGM.Int8PtrTy);
+#define DATA(lowerId, upperId, ty) \
+  types.push_back(IGM.getValueWitnessTy(ValueWitness::upperId));
+
+  // Add the base value witnesses.
+#define WANT_ONLY_REQUIRED_VALUE_WITNESSES
+#define FUNCTION_VALUE_WITNESS FUNC
+#define DATA_VALUE_WITNESS DATA
+#include "swift/ABI/ValueWitness.def"
+
+  // Add the enum value witnesses.
+  if (includeEnumWitnesses) {
+#define WANT_ONLY_ENUM_VALUE_WITNESSES
+#define FUNCTION_VALUE_WITNESS FUNC
+#define DATA_VALUE_WITNESS DATA
+#include "swift/ABI/ValueWitness.def"
+  }
+
+#undef DATA
+#undef FUNC
+
+  auto structTy = llvm::StructType::create(types, name);
+  auto ptrTy = structTy->getPointerTo();
+  cache = ptrTy;
+  return ptrTy;
+}
+
+llvm::StructType *IRGenModule::getValueWitnessTableTy() {
+  return cast<llvm::StructType>(getValueWitnessTablePtrTy()->getElementType());
+}
+llvm::PointerType *IRGenModule::getValueWitnessTablePtrTy() {
+  return getOrCreateValueWitnessTablePtrTy(*this, ValueWitnessTablePtrTy,
+                                           "swift.vwtable", false);
+}
+
+llvm::StructType *IRGenModule::getEnumValueWitnessTableTy() {
+  return cast<llvm::StructType>(getEnumValueWitnessTablePtrTy()
+           ->getElementType());
+}
+llvm::PointerType *IRGenModule::getEnumValueWitnessTablePtrTy() {
+  return getOrCreateValueWitnessTablePtrTy(*this, EnumValueWitnessTablePtrTy,
+                                           "swift.enum_vwtable", true);
+}
+
 /// Load a specific witness from a known table.  The result is
 /// always an i8*.
 llvm::Value *irgen::emitInvariantLoadOfOpaqueWitness(IRGenFunction &IGF,
@@ -321,12 +346,31 @@
 /// The result has the appropriate type for the witness.
 static llvm::Value *emitLoadOfValueWitnessValue(IRGenFunction &IGF,
                                                 llvm::Value *table,
-                                                ValueWitness index) {
-  assert(!isValueWitnessFunction(index));
-  llvm::Value *witness = emitInvariantLoadOfOpaqueWitness(IGF, table, index);
-  auto label = getValueWitnessLabel(index);
-  auto type = IGF.IGM.getValueWitnessTy(index);
-  return IGF.Builder.CreatePtrToInt(witness, type, label);
+                                                ValueWitness witness) {
+  assert(!isValueWitnessFunction(witness));
+  assert(unsigned(witness) <= unsigned(ValueWitness::ExtraInhabitantCount) &&
+         "extraInhabitantCount not the last non-function value witness");
+
+  auto pointerSize = IGF.IGM.getPointerSize();
+
+  // Most of the witnesses are at an offset that's just a multiple of the
+  // pointer size, but the extra-inhabitant count is packed in after the
+  // 32-bit flags.
+  // This computation is correct for all pointer sizes, including 16.
+  // It would be wrong if size_t is ever a different size from the pointer
+  // size, though.
+  Size offset =
+    (witness == ValueWitness::ExtraInhabitantCount
+       ? unsigned(ValueWitness::Flags) * pointerSize + Size(4)
+       : unsigned(witness) * pointerSize);
+
+  Address addr = Address(table, IGF.IGM.getPointerAlignment());
+  addr = IGF.Builder.CreateBitCast(addr, IGF.IGM.getValueWitnessTablePtrTy());
+  addr = IGF.Builder.CreateStructGEP(addr, unsigned(witness), offset);
+
+  auto load = IGF.Builder.CreateLoad(addr, getValueWitnessLabel(witness));
+  IGF.setInvariantLoad(load);
+  return load;
 }
 
 /// Given a type metadata pointer, load one of the value witnesses from its
@@ -345,7 +389,23 @@
                                                       llvm::Value *table,
                                                       ValueWitness index) {
   assert(isValueWitnessFunction(index));
-  llvm::Value *witness = emitInvariantLoadOfOpaqueWitness(IGF, table, index);
+
+  WitnessIndex windex = [&] {
+    unsigned i = unsigned(index);
+    if (i > unsigned(ValueWitness::Flags)) {
+      if (IGF.IGM.getPointerSize() == Size(8)) {
+        i--; // one pointer width skips both flags and xiCount
+      } else if (IGF.IGM.getPointerSize() == Size(4)) {
+        // no adjustment required
+      } else {
+        assert(IGF.IGM.getPointerSize() == Size(2));
+        i += 2; // flags and xiCount take up two pointers apiece
+      }
+    }
+    return WitnessIndex(i, false);
+  }();
+
+  llvm::Value *witness = emitInvariantLoadOfOpaqueWitness(IGF, table, windex);
   auto label = getValueWitnessLabel(index);
   auto signature = IGF.IGM.getValueWitnessSignature(index);
 
@@ -665,36 +725,6 @@
   IGF.Builder.CreateCall(IGF.IGM.getArrayDestroyFn(), {obj, count, metadata});
 }
 
-/// Emit a call to the 'getExtraInhabitantIndex' operation.
-/// The type must be dynamically known to have extra inhabitant witnesses.
-llvm::Value *irgen::emitGetExtraInhabitantIndexCall(IRGenFunction &IGF,
-                                                    SILType T,
-                                                    Address srcObject) {
-  llvm::Value *metadata;
-  auto fn = IGF.emitValueWitnessFunctionRef(T, metadata,
-                                       ValueWitness::GetExtraInhabitantIndex);
-
-  auto src = emitCastToOpaquePtr(IGF, srcObject);
-  llvm::CallInst *call =
-    IGF.Builder.CreateCall(fn, {src, metadata});
-  return call;
-}
-
-/// Emit a call to the 'storeExtraInhabitant' operation.
-/// The type must be dynamically known to have extra inhabitant witnesses.
-llvm::Value *irgen::emitStoreExtraInhabitantCall(IRGenFunction &IGF,
-                                                 SILType T,
-                                                 llvm::Value *index,
-                                                 Address destObject) {
-  llvm::Value *metadata;
-  auto fn = IGF.emitValueWitnessFunctionRef(T, metadata,
-                                          ValueWitness::StoreExtraInhabitant);
-  auto dest = emitCastToOpaquePtr(IGF, destObject);
-  llvm::CallInst *call =
-    IGF.Builder.CreateCall(fn, {dest, index, metadata});
-  return call;
-}
-
 /// Emit a trampoline to call the getEnumTagSinglePayload witness. API:
 /// UINT_TYPE (const T* enum, UINT_TYPE emptyCases, M *self)
 static llvm::Constant *
@@ -774,7 +804,7 @@
   return result;
 }
 
-llvm::Value *irgen::emitStoreEnumTagSinglePayloadCall(
+void irgen::emitStoreEnumTagSinglePayloadCall(
     IRGenFunction &IGF, SILType T, llvm::Value *whichCase,
     llvm::Value *numEmptyCases, Address destObject) {
   if (!IGF.optimizeForSize()) {
@@ -782,17 +812,14 @@
     auto fn = IGF.emitValueWitnessFunctionRef(
         T, metadata, ValueWitness::StoreEnumTagSinglePayload);
     auto dest = emitCastToOpaquePtr(IGF, destObject);
-    llvm::CallInst *call = IGF.Builder.CreateCall(
-        fn, {dest, whichCase, numEmptyCases, metadata});
-    return call;
+    IGF.Builder.CreateCall(fn, {dest, whichCase, numEmptyCases, metadata});
+    return;
   }
 
   auto *metadata = IGF.emitTypeMetadataRefForLayout(T);
   auto *func = getStoreEnumTagSinglePayloadTrampolineFn(IGF.IGM);
   auto dest = emitCastToOpaquePtr(IGF, destObject);
-  auto *result = IGF.Builder.CreateCall(func,
-                                    {dest, whichCase, numEmptyCases, metadata});
-  return result;
+  IGF.Builder.CreateCall(func, {dest, whichCase, numEmptyCases, metadata});
 }
 
 /// Emit a call to the 'getEnumTag' operation.
@@ -842,47 +869,36 @@
 /// Load the 'alignmentMask' value witness from the given table as a size_t.
 llvm::Value *irgen::emitLoadOfAlignmentMask(IRGenFunction &IGF, SILType T) {
   auto flags = IGF.emitValueWitnessValue(T, ValueWitness::Flags);
-  auto mask = IGF.IGM.getSize(Size(ValueWitnessFlags::AlignmentMask));
-  return IGF.Builder.CreateAnd(flags, mask,
-                               flags->getName() + ".alignmentMask");
+  return emitAlignMaskFromFlags(IGF, flags);
 }
 
 /// Load the 'isPOD' valueWitness from the given table as an i1.
 llvm::Value *irgen::emitLoadOfIsPOD(IRGenFunction &IGF, SILType T) {
   auto flags = IGF.emitValueWitnessValue(T, ValueWitness::Flags);
-  auto mask = IGF.IGM.getSize(Size(ValueWitnessFlags::IsNonPOD));
+  auto mask = IGF.IGM.getInt32(ValueWitnessFlags::IsNonPOD);
   auto masked = IGF.Builder.CreateAnd(flags, mask);
-  return IGF.Builder.CreateICmpEQ(masked, IGF.IGM.getSize(Size(0)),
+  return IGF.Builder.CreateICmpEQ(masked, IGF.IGM.getInt32(0),
                                   flags->getName() + ".isPOD");
 }
 
 /// Load the 'isBitwiseTakable' valueWitness from the given table as an i1.
 llvm::Value *irgen::emitLoadOfIsBitwiseTakable(IRGenFunction &IGF, SILType T) {
   auto flags = IGF.emitValueWitnessValue(T, ValueWitness::Flags);
-  auto mask = IGF.IGM.getSize(Size(ValueWitnessFlags::IsNonBitwiseTakable));
+  auto mask = IGF.IGM.getInt32(ValueWitnessFlags::IsNonBitwiseTakable);
   auto masked = IGF.Builder.CreateAnd(flags, mask);
-  return IGF.Builder.CreateICmpEQ(masked, IGF.IGM.getSize(Size(0)),
+  return IGF.Builder.CreateICmpEQ(masked, IGF.IGM.getInt32(0),
                                   flags->getName() + ".isBitwiseTakable");
 }
 
 /// Load the 'isInline' valueWitness from the given table as an i1.
 llvm::Value *irgen::emitLoadOfIsInline(IRGenFunction &IGF, SILType T) {
   auto flags = IGF.emitValueWitnessValue(T, ValueWitness::Flags);
-  auto mask = IGF.IGM.getSize(Size(ValueWitnessFlags::IsNonInline));
+  auto mask = IGF.IGM.getInt32(ValueWitnessFlags::IsNonInline);
   auto masked = IGF.Builder.CreateAnd(flags, mask);
-  return IGF.Builder.CreateICmpEQ(masked, IGF.IGM.getSize(Size(0)),
+  return IGF.Builder.CreateICmpEQ(masked, IGF.IGM.getInt32(0),
                                   flags->getName() + ".isInline");
 }
 
-/// Load the 'hasExtraInhabitants' valueWitness from the given table as an i1.
-llvm::Value *irgen::emitLoadOfHasExtraInhabitants(IRGenFunction &IGF, SILType T) {
-  auto flags = IGF.emitValueWitnessValue(T, ValueWitness::Flags);
-  auto mask = IGF.IGM.getSize(Size(ValueWitnessFlags::HasExtraInhabitants));
-  auto masked = IGF.Builder.CreateAnd(flags, mask);
-  return IGF.Builder.CreateICmpNE(masked, IGF.IGM.getSize(Size(0)),
-                                  flags->getName() + ".hasExtraInhabitants");
-}
-
 /// Load the 'stride' value witness from the given table as a size_t.
 llvm::Value *irgen::emitLoadOfStride(IRGenFunction &IGF, SILType T) {
   return IGF.emitValueWitnessValue(T, ValueWitness::Stride);
@@ -890,22 +906,17 @@
 
 llvm::Value *irgen::emitLoadOfExtraInhabitantCount(IRGenFunction &IGF,
                                                    SILType T) {
-  auto xiFlags =
-    IGF.emitValueWitnessValue(T, ValueWitness::ExtraInhabitantFlags);
-  auto mask = IGF.IGM.getSize(
-                          Size(ExtraInhabitantFlags::NumExtraInhabitantsMask));
-  return IGF.Builder.CreateAnd(xiFlags, mask,
-                               xiFlags->getName() + ".extraInhabitantCount");
+  return IGF.emitValueWitnessValue(T, ValueWitness::ExtraInhabitantCount);
 }
 
 std::pair<llvm::Value *, llvm::Value *>
 irgen::emitLoadOfIsInline(IRGenFunction &IGF, llvm::Value *metadata) {
   auto *flags = emitLoadOfValueWitnessValueFromMetadata(IGF, metadata,
                                                         ValueWitness::Flags);
-  auto mask = IGF.IGM.getSize(Size(ValueWitnessFlags::IsNonInline));
+  auto mask = IGF.IGM.getInt32(ValueWitnessFlags::IsNonInline);
   auto masked = IGF.Builder.CreateAnd(flags, mask);
   return std::make_pair(
-      IGF.Builder.CreateICmpEQ(masked, IGF.IGM.getSize(Size(0)),
+      IGF.Builder.CreateICmpEQ(masked, IGF.IGM.getInt32(0),
                                flags->getName() + ".isInline"),
       flags);
 }
@@ -918,8 +929,9 @@
 
 llvm::Value *irgen::emitAlignMaskFromFlags(IRGenFunction &IGF,
                                            llvm::Value *flags) {
+  auto flagsAsSize = IGF.Builder.CreateZExtOrTrunc(flags, IGF.IGM.SizeTy);
   auto *alignMask = IGF.IGM.getSize(Size(ValueWitnessFlags::AlignmentMask));
-  return IGF.Builder.CreateAnd(flags, alignMask,
+  return IGF.Builder.CreateAnd(flagsAsSize, alignMask,
                                flags->getName() + ".alignmentMask");
 }
 
@@ -1246,3 +1258,190 @@
   call->setCallingConv(IGF.IGM.DefaultCC);
   call->setDoesNotThrow();
 }
+
+llvm::Value *
+irgen::emitGetEnumTagSinglePayloadGenericCall(IRGenFunction &IGF,
+                                              SILType payloadType,
+                                              const TypeInfo &payloadTI,
+                                              llvm::Value *numExtraCases,
+                                              Address address,
+                                         GetExtraInhabitantTagEmitter emitter) {
+  auto getExtraInhabitantTagFn =
+    getOrCreateGetExtraInhabitantTagFunction(IGF.IGM, payloadType,
+                                             payloadTI, emitter);
+
+  // We assume this is never a reabstracted type.
+  auto type = payloadType.getASTType();
+  assert(type->isLegalFormalType());
+  auto metadata = IGF.emitTypeMetadataRef(type);
+
+  auto ptr = IGF.Builder.CreateBitCast(address.getAddress(),
+                                       IGF.IGM.OpaquePtrTy);
+
+  auto getEnumTagGenericFn =
+    IGF.IGM.getGetEnumTagSinglePayloadGenericFn();
+  auto call = IGF.Builder.CreateCall(getEnumTagGenericFn,
+                                     {ptr,
+                                      numExtraCases,
+                                      metadata,
+                                      getExtraInhabitantTagFn});
+  call->setCallingConv(IGF.IGM.SwiftCC);
+  return call;
+}
+
+llvm::Constant *
+irgen::getOrCreateGetExtraInhabitantTagFunction(IRGenModule &IGM,
+                                                SILType objectType,
+                                                const TypeInfo &objectTI,
+                                         GetExtraInhabitantTagEmitter emitter) {
+  // We assume this is never a reabstracted type.
+  CanType type = objectType.getASTType();
+  assert(type->isLegalFormalType());
+
+  auto fnTy = llvm::FunctionType::get(IGM.Int32Ty,
+                                      {IGM.OpaquePtrTy,
+                                       IGM.Int32Ty,
+                                       IGM.TypeMetadataPtrTy},
+                                      false);
+
+  // TODO: use a meaningful mangled name and internal/shared linkage.
+  auto fn = llvm::Function::Create(fnTy, llvm::Function::PrivateLinkage,
+                                   "__swift_get_extra_inhabitant_index",
+                                   &IGM.Module);
+  fn->setCallingConv(IGM.SwiftCC);
+  IRGenFunction IGF(IGM, fn);
+  auto parameters = IGF.collectParameters();
+  auto ptr = parameters.claimNext();
+  auto xiCount = parameters.claimNext();
+  auto metadata = parameters.claimNext();
+
+  // Bind the metadata to make any archetypes available.
+  IGF.bindLocalTypeDataFromTypeMetadata(type, IsExact, metadata,
+                                        MetadataState::Complete);
+
+  // Form a well-typed address from the opaque pointer.
+  ptr = IGF.Builder.CreateBitCast(ptr,
+                                  objectTI.getStorageType()->getPointerTo());
+  Address addr = objectTI.getAddressForPointer(ptr);
+
+  auto tag = emitter(IGF, addr, xiCount);
+  IGF.Builder.CreateRet(tag);
+
+  return fn;
+}
+
+void
+irgen::emitStoreEnumTagSinglePayloadGenericCall(IRGenFunction &IGF,
+                                                SILType payloadType,
+                                                const TypeInfo &payloadTI,
+                                                llvm::Value *whichCase,
+                                                llvm::Value *numExtraCases,
+                                                Address address,
+                                       StoreExtraInhabitantTagEmitter emitter) {
+  auto storeExtraInhabitantTagFn =
+    getOrCreateStoreExtraInhabitantTagFunction(IGF.IGM, payloadType,
+                                               payloadTI, emitter);
+
+  // We assume this is never a reabstracted type.
+  auto type = payloadType.getASTType();
+  assert(type->isLegalFormalType());
+  auto metadata = IGF.emitTypeMetadataRef(type);
+
+  auto ptr = IGF.Builder.CreateBitCast(address.getAddress(),
+                                       IGF.IGM.OpaquePtrTy);
+
+  auto storeEnumTagGenericFn =
+    IGF.IGM.getStoreEnumTagSinglePayloadGenericFn();
+  auto call = IGF.Builder.CreateCall(storeEnumTagGenericFn,
+                                     {ptr,
+                                      whichCase,
+                                      numExtraCases,
+                                      metadata,
+                                      storeExtraInhabitantTagFn});
+  call->setCallingConv(IGF.IGM.SwiftCC);
+}
+
+llvm::Constant *
+irgen::getOrCreateStoreExtraInhabitantTagFunction(IRGenModule &IGM,
+                                                  SILType objectType,
+                                                  const TypeInfo &objectTI,
+                                       StoreExtraInhabitantTagEmitter emitter) {
+  // We assume this is never a reabstracted type.
+  CanType type = objectType.getASTType();
+  assert(type->isLegalFormalType());
+
+  auto fnTy = llvm::FunctionType::get(IGM.VoidTy,
+                                      {IGM.OpaquePtrTy,
+                                       IGM.Int32Ty,
+                                       IGM.Int32Ty,
+                                       IGM.TypeMetadataPtrTy},
+                                      false);
+
+  // TODO: use a meaningful mangled name and internal/shared linkage.
+  auto fn = llvm::Function::Create(fnTy, llvm::Function::PrivateLinkage,
+                                   "__swift_get_extra_inhabitant_index",
+                                   &IGM.Module);
+  fn->setCallingConv(IGM.SwiftCC);
+  IRGenFunction IGF(IGM, fn);
+  auto parameters = IGF.collectParameters();
+  auto ptr = parameters.claimNext();
+  auto tag = parameters.claimNext();
+  auto xiCount = parameters.claimNext();
+  auto metadata = parameters.claimNext();
+
+  // Bind the metadata to make any archetypes available.
+  IGF.bindLocalTypeDataFromTypeMetadata(type, IsExact, metadata,
+                                        MetadataState::Complete);
+
+  // Form a well-typed address from the opaque pointer.
+  ptr = IGF.Builder.CreateBitCast(ptr,
+                                  objectTI.getStorageType()->getPointerTo());
+  Address addr = objectTI.getAddressForPointer(ptr);
+
+  emitter(IGF, addr, tag, xiCount);
+  IGF.Builder.CreateRetVoid();
+
+  return fn;
+}
+
+llvm::Value *TypeInfo::getExtraInhabitantTagDynamic(IRGenFunction &IGF,
+                                                    Address address,
+                                                    SILType T,
+                                                    llvm::Value *knownXICount,
+                                                    bool isOutlined) const {
+  if (auto fixedTI = dyn_cast<FixedTypeInfo>(this)) {
+    auto index = fixedTI->getExtraInhabitantIndex(IGF, address, T, isOutlined);
+    // The runtime APIs expect that 0 means the payload case and 1+
+    // means the extra cases, but in IRGen, getExtraInhabitantIndex
+    // returns -1 for the payload case and 0+ for extra inhabitants.
+    // This is an easy adjustment to make.
+    auto one = llvm::ConstantInt::get(IGF.IGM.Int32Ty, 1);
+    auto tag = IGF.Builder.CreateAdd(index, one);
+    return tag;
+  } else {
+    if (!knownXICount)
+      knownXICount = emitLoadOfExtraInhabitantCount(IGF, T);
+
+    auto tag = getEnumTagSinglePayload(IGF, /*num extra cases*/ knownXICount,
+                                       address, T, isOutlined);
+    return tag;
+  }
+}
+
+void TypeInfo::storeExtraInhabitantTagDynamic(IRGenFunction &IGF,
+                                              llvm::Value *tag,
+                                              Address address,
+                                              SILType T,
+                                              bool isOutlined) const {
+  if (auto fixedTI = dyn_cast<FixedTypeInfo>(this)) {
+    // The runtime APIs expect that 0 means the payload case and 1+
+    // means the extra cases, but in IRGen, storeExtraInhabitant
+    // expects extra inhabitants to be indexed as 0+.
+    // This is an easy adjustment to make.
+    auto one = llvm::ConstantInt::get(IGF.IGM.Int32Ty, 1);
+    auto index = IGF.Builder.CreateSub(tag, one);
+    fixedTI->storeExtraInhabitant(IGF, index, address, T, isOutlined);
+  } else {
+    storeEnumTagSinglePayload(IGF, tag, tag, address, T, isOutlined);
+  }
+}
\ No newline at end of file
diff --git a/lib/IRGen/GenOpaque.h b/lib/IRGen/GenOpaque.h
index 6cb9f8d..b5c8116 100644
--- a/lib/IRGen/GenOpaque.h
+++ b/lib/IRGen/GenOpaque.h
@@ -28,6 +28,7 @@
   class Address;
   class IRGenFunction;
   class IRGenModule;
+  class TypeInfo;
   enum class ValueWitness : unsigned;
   class WitnessIndex;
 
@@ -164,29 +165,16 @@
                             Address object,
                             llvm::Value *count);
 
-  /// Emit a call to the 'getExtraInhabitantIndex' operation.
-  /// The type must be dynamically known to have extra inhabitant witnesses.
-  llvm::Value *emitGetExtraInhabitantIndexCall(IRGenFunction &IGF,
-                                               SILType T,
-                                               Address srcObject);
-  
-  /// Emit a call to the 'storeExtraInhabitant' operation.
-  /// The type must be dynamically known to have extra inhabitant witnesses.
-  llvm::Value *emitStoreExtraInhabitantCall(IRGenFunction &IGF,
-                                            SILType T,
-                                            llvm::Value *index,
-                                            Address destObject);
-
   /// Emit a call to the 'getEnumTagSinglePayload' operation.
   llvm::Value *emitGetEnumTagSinglePayloadCall(IRGenFunction &IGF, SILType T,
                                                llvm::Value *numEmptyCases,
                                                Address destObject);
 
   /// Emit a call to the 'storeEnumTagSinglePayload' operation.
-  llvm::Value *emitStoreEnumTagSinglePayloadCall(IRGenFunction &IGF, SILType T,
-                                                 llvm::Value *whichCase,
-                                                 llvm::Value *numEmptyCases,
-                                                 Address destObject);
+  void emitStoreEnumTagSinglePayloadCall(IRGenFunction &IGF, SILType T,
+                                         llvm::Value *whichCase,
+                                         llvm::Value *numEmptyCases,
+                                         Address destObject);
 
   /// Emit a call to the 'getEnumTag' operation.
   llvm::Value *emitGetEnumTagCall(IRGenFunction &IGF,
@@ -224,11 +212,7 @@
   /// Emit a load of the 'isInline' value witness.
   llvm::Value *emitLoadOfIsInline(IRGenFunction &IGF, SILType T);
 
-  /// Emit a load of the 'hasExtraInhabitants' value witness.
-  llvm::Value *emitLoadOfHasExtraInhabitants(IRGenFunction &IGF, SILType T);
-  
   /// Emit a load of the 'extraInhabitantCount' value witness.
-  /// The type must be dynamically known to have extra inhabitant witnesses.
   llvm::Value *emitLoadOfExtraInhabitantCount(IRGenFunction &IGF, SILType T);
 
   /// Returns the IsInline flag and the loaded flags value.
@@ -251,6 +235,46 @@
   void emitDeallocateValueInBuffer(IRGenFunction &IGF,
                                    SILType type,
                                    Address buffer);
+
+
+  using GetExtraInhabitantTagEmitter =
+    llvm::function_ref<llvm::Value*(IRGenFunction &IGF,
+                                    Address addr,
+                                    llvm::Value *xiCount)>;
+
+  llvm::Constant *
+  getOrCreateGetExtraInhabitantTagFunction(IRGenModule &IGM,
+                                           SILType objectType,
+                                           const TypeInfo &objectTI,
+                                           GetExtraInhabitantTagEmitter emit);
+
+  llvm::Value *
+  emitGetEnumTagSinglePayloadGenericCall(IRGenFunction &IGF,
+                                         SILType payloadType,
+                                         const TypeInfo &payloadTI,
+                                         llvm::Value *numExtraCases,
+                                         Address address,
+                                         GetExtraInhabitantTagEmitter emit);
+
+  using StoreExtraInhabitantTagEmitter =
+    llvm::function_ref<void(IRGenFunction &IGF,
+                            Address addr,
+                            llvm::Value *tag,
+                            llvm::Value *xiCount)>;
+
+  llvm::Constant *
+  getOrCreateStoreExtraInhabitantTagFunction(IRGenModule &IGM,
+                                             SILType objectType,
+                                             const TypeInfo &objectTI,
+                                        StoreExtraInhabitantTagEmitter emit);
+
+  void emitStoreEnumTagSinglePayloadGenericCall(IRGenFunction &IGF,
+                                                SILType payloadType,
+                                                const TypeInfo &payloadTI,
+                                                llvm::Value *index,
+                                                llvm::Value *numExtraCases,
+                                                Address address,
+                                           StoreExtraInhabitantTagEmitter emit);
 } // end namespace irgen
 } // end namespace swift
 
diff --git a/lib/IRGen/GenRecord.h b/lib/IRGen/GenRecord.h
index b9c261a..9bdb2ef 100644
--- a/lib/IRGen/GenRecord.h
+++ b/lib/IRGen/GenRecord.h
@@ -303,21 +303,17 @@
   llvm::Value *withExtraInhabitantProvidingField(IRGenFunction &IGF,
          Address structAddr,
          SILType structType,
-         bool isOutlined,
+         llvm::Value *knownStructNumXI,
          llvm::Type *resultTy,
-         llvm::function_ref<llvm::Value* (const FieldImpl &field)> body,
-         llvm::function_ref<llvm::Value* ()> outline) const {
+         llvm::function_ref<llvm::Value* (const FieldImpl &field,
+                                          llvm::Value *numXI)> body) const {
     // If we know one field consistently provides extra inhabitants, delegate
     // to that field.
     if (auto field = asImpl().getFixedExtraInhabitantProvidingField(IGF.IGM)){
-      return body(*field);
+      return body(*field, knownStructNumXI);
     }
     
     // Otherwise, we have to figure out which field at runtime.
-    // The decision tree could be rather large, so invoke the value witness
-    // unless we're emitting the value witness.
-    if (!isOutlined)
-      return outline();
 
     // The number of extra inhabitants the instantiated type has can be used
     // to figure out which field the runtime chose. The runtime uses the same
@@ -351,7 +347,9 @@
     // Loop through checking to see whether we picked the fixed candidate
     // (if any) or one of the unknown-layout fields.
     llvm::Value *instantiatedCount
-      = emitLoadOfExtraInhabitantCount(IGF, structType);
+      = (knownStructNumXI
+           ? knownStructNumXI
+           : emitLoadOfExtraInhabitantCount(IGF, structType));
     
     auto contBB = IGF.createBasicBlock("chose_field_for_xi");
     llvm::PHINode *contPhi = nullptr;
@@ -376,7 +374,7 @@
         if (&field != fixedCandidate)
           continue;
         
-        fieldCount = llvm::ConstantInt::get(IGF.IGM.SizeTy, fixedCount);
+        fieldCount = IGF.IGM.getInt32(fixedCount);
       } else {
         auto fieldTy = field.getType(IGF.IGM, structType);
         // If this field has the same type as a field we already tested,
@@ -395,7 +393,7 @@
       IGF.Builder.CreateCondBr(equalsCount, yesBB, noBB);
       
       IGF.Builder.emitBlock(yesBB);
-      auto value = body(field);
+      auto value = body(field, instantiatedCount);
       if (contPhi)
         contPhi->addIncoming(value, IGF.Builder.GetInsertBlock());
       IGF.Builder.CreateBr(contBB);
@@ -414,46 +412,6 @@
     return contPhi;
   }
 
-  llvm::Value *getExtraInhabitantIndex(IRGenFunction &IGF,
-                                       Address structAddr,
-                                       SILType structType,
-                                       bool isOutlined) const override {
-    return withExtraInhabitantProvidingField(IGF, structAddr, structType,
-                                             isOutlined,
-                                             IGF.IGM.Int32Ty,
-      [&](const FieldImpl &field) -> llvm::Value* {
-        Address fieldAddr = asImpl().projectFieldAddress(
-                                            IGF, structAddr, structType, field);
-        return field.getTypeInfo().getExtraInhabitantIndex(IGF, fieldAddr,
-                                         field.getType(IGF.IGM, structType),
-                                         false /*not outlined for field*/);
-      },
-      [&]() -> llvm::Value * {
-        return emitGetExtraInhabitantIndexCall(IGF, structType, structAddr);
-      });
-  }
-
-  void storeExtraInhabitant(IRGenFunction &IGF,
-                            llvm::Value *index,
-                            Address structAddr,
-                            SILType structType,
-                            bool isOutlined) const override {
-    withExtraInhabitantProvidingField(IGF, structAddr, structType, isOutlined,
-                                      IGF.IGM.VoidTy,
-      [&](const FieldImpl &field) -> llvm::Value* {
-        Address fieldAddr = asImpl().projectFieldAddress(
-                                            IGF, structAddr, structType, field);
-        field.getTypeInfo().storeExtraInhabitant(IGF, index, fieldAddr,
-                                         field.getType(IGF.IGM, structType),
-                                         false /*not outlined for field*/);
-        return nullptr;
-      },
-      [&]() -> llvm::Value * {
-        emitStoreExtraInhabitantCall(IGF, structType, index, structAddr);
-        return nullptr;
-      });
-  }
-      
   const FieldImpl *
   getFixedExtraInhabitantProvidingField(IRGenModule &IGM) const {
     if (!ExtraInhabitantProvidingField.hasValue()) {
@@ -658,6 +616,33 @@
     fieldMask = fieldMask.shl(field->getFixedByteOffset().getValueInBits());
     return fieldMask;
   }
+
+  llvm::Value *getExtraInhabitantIndex(IRGenFunction &IGF,
+                                       Address structAddr,
+                                       SILType structType,
+                                       bool isOutlined) const override {
+    auto field = *asImpl().getFixedExtraInhabitantProvidingField(IGF.IGM);
+    Address fieldAddr =
+      asImpl().projectFieldAddress(IGF, structAddr, structType, field);
+    auto &fieldTI = cast<FixedTypeInfo>(field.getTypeInfo());
+    return fieldTI.getExtraInhabitantIndex(IGF, fieldAddr,
+                                     field.getType(IGF.IGM, structType),
+                                     false /*not outlined for field*/);
+  }
+
+  void storeExtraInhabitant(IRGenFunction &IGF,
+                            llvm::Value *index,
+                            Address structAddr,
+                            SILType structType,
+                            bool isOutlined) const override {
+    auto field = *asImpl().getFixedExtraInhabitantProvidingField(IGF.IGM);
+    Address fieldAddr =
+      asImpl().projectFieldAddress(IGF, structAddr, structType, field);
+    auto &fieldTI = cast<FixedTypeInfo>(field.getTypeInfo());
+    fieldTI.storeExtraInhabitant(IGF, index, fieldAddr,
+                                 field.getType(IGF.IGM, structType),
+                                 false /*not outlined for field*/);
+  }
 };
 
 /// An implementation of RecordTypeInfo for loadable types. 
diff --git a/lib/IRGen/GenStruct.cpp b/lib/IRGen/GenStruct.cpp
index e2b273b..036afaa 100644
--- a/lib/IRGen/GenStruct.cpp
+++ b/lib/IRGen/GenStruct.cpp
@@ -472,6 +472,67 @@
       return StructNonFixedOffsets(T).getFieldAccessStrategy(IGM,
                                               field.getNonFixedElementIndex());
     }
+
+    llvm::Value *getEnumTagSinglePayload(IRGenFunction &IGF,
+                                         llvm::Value *numEmptyCases,
+                                         Address structAddr,
+                                         SILType structType,
+                                         bool isOutlined) const override {
+      // If we're not emitting the value witness table's implementation,
+      // just call that.
+      if (!isOutlined) {
+        return emitGetEnumTagSinglePayloadCall(IGF, structType, numEmptyCases,
+                                               structAddr);
+      }
+
+      return emitGetEnumTagSinglePayloadGenericCall(IGF, structType, *this,
+                                                    numEmptyCases, structAddr,
+        [this,structType](IRGenFunction &IGF, Address structAddr,
+                          llvm::Value *structNumXI) {
+          return withExtraInhabitantProvidingField(IGF, structAddr, structType,
+                                                   structNumXI, IGF.IGM.Int32Ty,
+            [&](const FieldImpl &field, llvm::Value *numXI) -> llvm::Value* {
+              Address fieldAddr = asImpl().projectFieldAddress(
+                                           IGF, structAddr, structType, field);
+              auto fieldTy = field.getType(IGF.IGM, structType);
+              return field.getTypeInfo()
+                          .getExtraInhabitantTagDynamic(IGF, fieldAddr, fieldTy,
+                                                     numXI, /*outlined*/ false);
+            });
+        });
+    }
+
+    void storeEnumTagSinglePayload(IRGenFunction &IGF,
+                                   llvm::Value *whichCase,
+                                   llvm::Value *numEmptyCases,
+                                   Address structAddr,
+                                   SILType structType,
+                                   bool isOutlined) const override {
+      // If we're not emitting the value witness table's implementation,
+      // just call that.
+      if (!isOutlined) {
+        return emitStoreEnumTagSinglePayloadCall(IGF, structType, whichCase,
+                                                 numEmptyCases, structAddr);
+      }
+
+      emitStoreEnumTagSinglePayloadGenericCall(IGF, structType, *this,
+                                               whichCase, numEmptyCases,
+                                               structAddr,
+        [this,structType](IRGenFunction &IGF, Address structAddr,
+                          llvm::Value *tag, llvm::Value *structNumXI) {
+          withExtraInhabitantProvidingField(IGF, structAddr, structType,
+                                            structNumXI, IGF.IGM.VoidTy,
+            [&](const FieldImpl &field, llvm::Value *numXI) -> llvm::Value* {
+              Address fieldAddr = asImpl().projectFieldAddress(
+                                           IGF, structAddr, structType, field);
+              auto fieldTy = field.getType(IGF.IGM, structType);
+              field.getTypeInfo()
+                   .storeExtraInhabitantTagDynamic(IGF, tag, fieldAddr, fieldTy,
+                                                   /*outlined*/ false);
+              return nullptr;
+            });
+        });
+    }
   };
 
   class StructTypeBuilder :
diff --git a/lib/IRGen/GenTuple.cpp b/lib/IRGen/GenTuple.cpp
index 6d2e564..cbc3252 100644
--- a/lib/IRGen/GenTuple.cpp
+++ b/lib/IRGen/GenTuple.cpp
@@ -295,6 +295,29 @@
                                             SILType T) const {
       return TupleNonFixedOffsets(T);
     }
+
+    llvm::Value *getEnumTagSinglePayload(IRGenFunction &IGF,
+                                         llvm::Value *numEmptyCases,
+                                         Address structAddr,
+                                         SILType structType,
+                                         bool isOutlined) const override {
+      // The runtime will overwrite this with a concrete implementation
+      // in the value witness table.
+      return emitGetEnumTagSinglePayloadCall(IGF, structType, numEmptyCases,
+                                             structAddr);
+    }
+
+    void storeEnumTagSinglePayload(IRGenFunction &IGF,
+                                   llvm::Value *index,
+                                   llvm::Value *numEmptyCases,
+                                   Address structAddr,
+                                   SILType structType,
+                                   bool isOutlined) const override {
+      // The runtime will overwrite this with a concrete implementation
+      // in the value witness table.
+      emitStoreEnumTagSinglePayloadCall(IGF, structType, index,
+                                        numEmptyCases, structAddr);
+    }
   };
 
   class TupleTypeBuilder :
diff --git a/lib/IRGen/GenType.cpp b/lib/IRGen/GenType.cpp
index adecc37..5045a83 100644
--- a/lib/IRGen/GenType.cpp
+++ b/lib/IRGen/GenType.cpp
@@ -240,15 +240,16 @@
 unsigned FixedTypeInfo::getSpareBitExtraInhabitantCount() const {
   if (SpareBits.none())
     return 0;
-  // The runtime supports a max of 0x7FFFFFFF extra inhabitants, which ought
-  // to be enough for anybody.
+  // Make sure the arithmetic below doesn't overflow.
   if (getFixedSize().getValue() >= 4)
-    return 0x7FFFFFFF;
+    return ValueWitnessFlags::MaxNumExtraInhabitants;
   unsigned spareBitCount = SpareBits.count();
   assert(spareBitCount <= getFixedSize().getValueInBits()
          && "more spare bits than storage bits?!");
   unsigned inhabitedBitCount = getFixedSize().getValueInBits() - spareBitCount;
-  return ((1U << spareBitCount) - 1U) << inhabitedBitCount;
+  unsigned rawCount = ((1U << spareBitCount) - 1U) << inhabitedBitCount;
+  return std::min(rawCount,
+                  unsigned(ValueWitnessFlags::MaxNumExtraInhabitants));
 }
 
 void FixedTypeInfo::applyFixedSpareBitsMask(SpareBitVector &mask,
@@ -426,15 +427,26 @@
 llvm::Value *FixedTypeInfo::getEnumTagSinglePayload(IRGenFunction &IGF,
                                                     llvm::Value *numEmptyCases,
                                                     Address enumAddr,
-                                                    SILType T) const {
+                                                    SILType T,
+                                                    bool isOutlined) const {
+  return getFixedTypeEnumTagSinglePayload(IGF, *this, numEmptyCases, enumAddr,
+                                          T, isOutlined);
+}
+
+llvm::Value *irgen::getFixedTypeEnumTagSinglePayload(IRGenFunction &IGF,
+                                                     const FixedTypeInfo &ti,
+                                                     llvm::Value *numEmptyCases,
+                                                     Address enumAddr,
+                                                     SILType T,
+                                                     bool isOutlined) {
   auto &IGM = IGF.IGM;
   auto &Ctx = IGF.IGM.getLLVMContext();
   auto &Builder = IGF.Builder;
 
-  auto *size = getSize(IGF, T);
-  Size fixedSize = getFixedSize();
+  auto *size = ti.getSize(IGF, T);
+  Size fixedSize = ti.getFixedSize();
   auto *numExtraInhabitants =
-      llvm::ConstantInt::get(IGM.Int32Ty, getFixedExtraInhabitantCount(IGM));
+      llvm::ConstantInt::get(IGM.Int32Ty, ti.getFixedExtraInhabitantCount(IGM));
 
   auto *zero = llvm::ConstantInt::get(IGM.Int32Ty, 0U);
   auto *one = llvm::ConstantInt::get(IGM.Int32Ty, 1U);
@@ -513,8 +525,8 @@
   Builder.emitBlock(noExtraTagBitsBB);
   // If there are extra inhabitants, see whether the payload is valid.
   llvm::Value *result0;
-  if (mayHaveExtraInhabitants(IGM)) {
-    result0 = getExtraInhabitantIndex(IGF, enumAddr, T, false);
+  if (ti.mayHaveExtraInhabitants(IGM)) {
+    result0 = ti.getExtraInhabitantIndex(IGF, enumAddr, T, false);
     noExtraTagBitsBB = Builder.GetInsertBlock();
   } else {
     result0 = llvm::ConstantInt::getSigned(IGM.Int32Ty, -1);
@@ -605,7 +617,19 @@
                                               llvm::Value *whichCase,
                                               llvm::Value *numEmptyCases,
                                               Address enumAddr,
-                                              SILType T) const {
+                                              SILType T,
+                                              bool isOutlined) const {
+  storeFixedTypeEnumTagSinglePayload(IGF, *this, whichCase, numEmptyCases,
+                                     enumAddr, T, isOutlined);
+}
+
+void irgen::storeFixedTypeEnumTagSinglePayload(IRGenFunction &IGF,
+                                               const FixedTypeInfo &ti,
+                                               llvm::Value *whichCase,
+                                               llvm::Value *numEmptyCases,
+                                               Address enumAddr,
+                                               SILType T,
+                                               bool isOutlined) {
   auto &IGM = IGF.IGM;
   auto &Ctx = IGF.IGM.getLLVMContext();
   auto &Builder = IGF.Builder;
@@ -616,15 +640,15 @@
   auto *four = llvm::ConstantInt::get(int32Ty, 4U);
   auto *eight = llvm::ConstantInt::get(int32Ty, 8U);
 
-  auto fixedSize = getFixedSize();
+  auto fixedSize = ti.getFixedSize();
 
   Address valueAddr = Builder.CreateElementBitCast(enumAddr, IGM.Int8Ty);
   Address extraTagBitsAddr =
     Builder.CreateConstByteArrayGEP(valueAddr, fixedSize);
 
   auto *numExtraInhabitants =
-      llvm::ConstantInt::get(IGM.Int32Ty, getFixedExtraInhabitantCount(IGM));
-  auto *size = getSize(IGF, T);
+      llvm::ConstantInt::get(IGM.Int32Ty, ti.getFixedExtraInhabitantCount(IGM));
+  auto *size = ti.getSize(IGF, T);
 
   // Do we need extra tag bytes.
   auto *entryBB = Builder.GetInsertBlock();
@@ -666,11 +690,11 @@
   Builder.CreateCondBr(isPayload, returnBB, storeInhabitantBB);
 
   Builder.emitBlock(storeInhabitantBB);
-  if (mayHaveExtraInhabitants(IGM)) {
+  if (ti.mayHaveExtraInhabitants(IGM)) {
     // Store an index in the range [0..ElementsWithNoPayload-1].
     auto *nonPayloadElementIndex = Builder.CreateSub(whichCase, one);
-    storeExtraInhabitant(IGF, nonPayloadElementIndex, enumAddr, T,
-                         /*outlined*/ false);
+    ti.storeExtraInhabitant(IGF, nonPayloadElementIndex, enumAddr, T,
+                            /*outlined*/ false);
   }
   Builder.CreateBr(returnBB);
 
@@ -728,30 +752,6 @@
   Builder.emitBlock(returnBB);
 }
 
-llvm::Value *irgen::emitGetEnumTagSinglePayload(IRGenFunction &IGF,
-                                                llvm::Value *numEmptyCases,
-                                                Address enumAddr, SILType T) {
-  auto metadata = IGF.emitTypeMetadataRefForLayout(T);
-  auto opaqueAddr =
-      IGF.Builder.CreateBitCast(enumAddr.getAddress(), IGF.IGM.OpaquePtrTy);
-
-  return IGF.Builder.CreateCall(IGF.IGM.getGetEnumCaseSinglePayloadFn(),
-                                {opaqueAddr, metadata, numEmptyCases});
-}
-
-void irgen::emitStoreEnumTagSinglePayload(IRGenFunction &IGF,
-                                          llvm::Value *whichCase,
-                                          llvm::Value *numEmptyCases,
-                                          Address enumAddr,
-                                          SILType T) {
-  auto metadata = IGF.emitTypeMetadataRefForLayout(T);
-  auto opaqueAddr =
-      IGF.Builder.CreateBitCast(enumAddr.getAddress(), IGF.IGM.OpaquePtrTy);
-
-  IGF.Builder.CreateCall(IGF.IGM.getStoreEnumTagSinglePayloadFn(),
-                         {opaqueAddr, metadata, whichCase, numEmptyCases});
-}
-
 void
 FixedTypeInfo::storeSpareBitExtraInhabitant(IRGenFunction &IGF,
                                             llvm::Value *index,
diff --git a/lib/IRGen/GenValueWitness.cpp b/lib/IRGen/GenValueWitness.cpp
index 072c564..6650383 100644
--- a/lib/IRGen/GenValueWitness.cpp
+++ b/lib/IRGen/GenValueWitness.cpp
@@ -56,15 +56,13 @@
   CASE(InitializeBufferWithCopyOfBuffer)
   CASE(InitializeWithCopy)
   CASE(InitializeWithTake)
-  CASE(StoreExtraInhabitant)
-  CASE(GetExtraInhabitantIndex)
   CASE(GetEnumTag)
   CASE(DestructiveProjectEnumData)
   CASE(DestructiveInjectEnumTag)
   CASE(Size)
   CASE(Flags)
+  CASE(ExtraInhabitantCount)
   CASE(Stride)
-  CASE(ExtraInhabitantFlags)
   CASE(GetEnumTagSinglePayload)
   CASE(StoreEnumTagSinglePayload)
 #undef CASE
@@ -510,27 +508,6 @@
     return;
   }
 
-  case ValueWitness::StoreExtraInhabitant: {
-    Address dest = getArgAs(IGF, argv, type, "dest");
-    llvm::Value *index = getArg(argv, "index");
-    getArgAsLocalSelfTypeMetadata(IGF, argv, abstractType);
-
-    type.storeExtraInhabitant(IGF, index, dest, concreteType,
-                              /*outlined*/ true);
-    IGF.Builder.CreateRetVoid();
-    return;
-  }
-
-  case ValueWitness::GetExtraInhabitantIndex: {
-    Address src = getArgAs(IGF, argv, type, "src");
-    getArgAsLocalSelfTypeMetadata(IGF, argv, abstractType);
-
-    llvm::Value *idx = type.getExtraInhabitantIndex(IGF, src, concreteType,
-                                                    /*outlined*/ true);
-    IGF.Builder.CreateRet(idx);
-    return;
-  }
-
   case ValueWitness::GetEnumTag: {
     auto &strategy = getEnumImplStrategy(IGM, concreteType);
 
@@ -593,7 +570,7 @@
 
     llvm::Value *idx = type.getEnumTagSinglePayload(
         IGF, numEmptyCases, Address(value, type.getBestKnownAlignment()),
-        concreteType);
+        concreteType, true);
     IGF.Builder.CreateRet(idx);
     return;
   }
@@ -610,15 +587,15 @@
 
     type.storeEnumTagSinglePayload(IGF, whichCase, numEmptyCases,
                                    Address(value, type.getBestKnownAlignment()),
-                                   concreteType);
+                                   concreteType, true);
     IGF.Builder.CreateRetVoid();
     return;
   }
 
   case ValueWitness::Size:
   case ValueWitness::Flags:
+  case ValueWitness::ExtraInhabitantCount:
   case ValueWitness::Stride:
-  case ValueWitness::ExtraInhabitantFlags:
     llvm_unreachable("these value witnesses aren't functions");
   }
   llvm_unreachable("bad value witness kind!");
@@ -753,7 +730,7 @@
 /// Find a witness to the fact that a type is a value type.
 /// Always adds an i8*.
 static void addValueWitness(IRGenModule &IGM,
-                            ConstantArrayBuilder &B,
+                            ConstantStructBuilder &B,
                             ValueWitness index,
                             FixedPacking packing,
                             CanType abstractType,
@@ -815,10 +792,10 @@
 
   case ValueWitness::Size: {
     if (auto value = concreteTI.getStaticSize(IGM))
-      return B.add(llvm::ConstantExpr::getIntToPtr(value, IGM.Int8PtrTy));
+      return B.add(value);
 
-    // Just fill in null here if the type can't be statically laid out.
-    return B.add(llvm::ConstantPointerNull::get(IGM.Int8PtrTy));
+    // Just fill in 0 here if the type can't be statically laid out.
+    return B.addSize(Size(0));
   }
 
   case ValueWitness::Flags: {
@@ -836,8 +813,6 @@
       flags = flags.withAlignment(fixedTI->getFixedAlignment().getValue())
                   .withPOD(fixedTI->isPOD(ResilienceExpansion::Maximal))
                   .withInlineStorage(isInline)
-                  .withExtraInhabitants(
-                      fixedTI->getFixedExtraInhabitantCount(IGM) > 0)
                   .withBitwiseTakable(isBitwiseTakable);
     } else {
       flags = flags.withIncomplete(true);
@@ -846,50 +821,23 @@
     if (concreteType.getEnumOrBoundGenericEnum())
       flags = flags.withEnumWitnesses(true);
 
-    auto value = IGM.getSize(Size(flags.getOpaqueValue()));
-    return B.add(llvm::ConstantExpr::getIntToPtr(value, IGM.Int8PtrTy));
+    return B.addInt32(flags.getOpaqueValue());
+  }
+
+  case ValueWitness::ExtraInhabitantCount: {
+    unsigned value = 0;
+    if (auto *fixedTI = dyn_cast<FixedTypeInfo>(&concreteTI)) {
+      value = fixedTI->getFixedExtraInhabitantCount(IGM);
+    }
+    return B.addInt32(value);
   }
 
   case ValueWitness::Stride: {
     if (auto value = concreteTI.getStaticStride(IGM))
-      return B.add(llvm::ConstantExpr::getIntToPtr(value, IGM.Int8PtrTy));
+      return B.add(value);
 
     // Just fill in null here if the type can't be statically laid out.
-    return B.add(llvm::ConstantPointerNull::get(IGM.Int8PtrTy));
-  }
-
-  case ValueWitness::StoreExtraInhabitant:
-  case ValueWitness::GetExtraInhabitantIndex: {
-    if (!concreteTI.mayHaveExtraInhabitants(IGM)) {
-      assert(concreteType.getEnumOrBoundGenericEnum());
-      return B.addNullPointer(IGM.Int8PtrTy);
-    }
-
-    goto standard;
-  }
-
-  case ValueWitness::ExtraInhabitantFlags: {
-    if (!concreteTI.mayHaveExtraInhabitants(IGM)) {
-      assert(concreteType.getEnumOrBoundGenericEnum());
-      return B.add(llvm::ConstantPointerNull::get(IGM.Int8PtrTy));
-    }
-
-    // If we locally know that the type has fixed layout, we can emit
-    // meaningful flags for it.
-    if (auto *fixedTI = dyn_cast<FixedTypeInfo>(&concreteTI)) {
-      ExtraInhabitantFlags flags;
-
-      uint64_t numExtraInhabitants = fixedTI->getFixedExtraInhabitantCount(IGM);
-      assert(numExtraInhabitants <= ExtraInhabitantFlags::NumExtraInhabitantsMask);
-      flags = flags.withNumExtraInhabitants(numExtraInhabitants);
-
-      auto value = IGM.getSize(Size(flags.getOpaqueValue()));
-      return B.add(llvm::ConstantExpr::getIntToPtr(value, IGM.Int8PtrTy));
-    }
-
-    // Otherwise, just fill in null here if the type can't be statically
-    // queried for extra inhabitants.
-    return B.add(llvm::ConstantPointerNull::get(IGM.Int8PtrTy));
+    return B.addSize(Size(0));
   }
 
   case ValueWitness::GetEnumTagSinglePayload:
@@ -914,9 +862,21 @@
   addFunction(fn);
 }
 
+static bool shouldAddEnumWitnesses(CanType abstractType) {
+  // Needs to handle UnboundGenericType.
+  return dyn_cast_or_null<EnumDecl>(abstractType.getAnyNominal()) != nullptr;
+}
+
+static llvm::StructType *getValueWitnessTableType(IRGenModule &IGM,
+                                                  CanType abstractType) {
+  return shouldAddEnumWitnesses(abstractType)
+           ? IGM.getEnumValueWitnessTableTy()
+           : IGM.getValueWitnessTableTy();
+}
+
 /// Collect the value witnesses for a particular type.
 static void addValueWitnesses(IRGenModule &IGM,
-                              ConstantArrayBuilder &B,
+                              ConstantStructBuilder &B,
                               FixedPacking packing,
                               CanType abstractType,
                               SILType concreteType,
@@ -925,16 +885,7 @@
     addValueWitness(IGM, B, ValueWitness(i), packing,
                     abstractType, concreteType, concreteTI);
   }
-  if (concreteType.getEnumOrBoundGenericEnum() ||
-      concreteTI.mayHaveExtraInhabitants(IGM)) {
-    for (auto i = unsigned(ValueWitness::First_ExtraInhabitantValueWitness);
-         i <= unsigned(ValueWitness::Last_ExtraInhabitantValueWitness);
-         ++i) {
-      addValueWitness(IGM, B, ValueWitness(i), packing,
-                      abstractType, concreteType, concreteTI);
-    }
-  }
-  if (concreteType.getEnumOrBoundGenericEnum()) {
+  if (shouldAddEnumWitnesses(abstractType)) {
     for (auto i = unsigned(ValueWitness::First_EnumValueWitness);
          i <= unsigned(ValueWitness::Last_EnumValueWitness);
          ++i) {
@@ -952,7 +903,7 @@
 }
 
 static void addValueWitnessesForAbstractType(IRGenModule &IGM,
-                                             ConstantArrayBuilder &B,
+                                             ConstantStructBuilder &B,
                                              CanType abstractType,
                                              bool &canBeConstant) {
   CanType concreteFormalType = getFormalTypeInContext(abstractType);
@@ -1095,7 +1046,8 @@
          "emitting VWT pattern for fixed-layout type");
 
   ConstantInitBuilder builder(IGM);
-  auto witnesses = builder.beginArray(IGM.Int8PtrTy);
+  auto witnesses =
+    builder.beginStruct(getValueWitnessTableType(IGM, abstractType));
 
   bool canBeConstant = false;
   addValueWitnessesForAbstractType(IGM, witnesses, abstractType, canBeConstant);
@@ -1159,7 +1111,7 @@
 
   // Emit the layout values.
   ConstantInitBuilder builder(*this);
-  auto witnesses = builder.beginArray(Int8PtrTy);
+  auto witnesses = builder.beginStruct();
   FixedPacking packing = ti.getFixedPacking(*this);
   for (auto witness = ValueWitness::First_TypeLayoutWitness;
        witness <= ValueWitness::Last_RequiredTypeLayoutWitness;
@@ -1167,12 +1119,6 @@
     addValueWitness(*this, witnesses, witness, packing, t, silTy, ti);
   }
 
-  if (ti.mayHaveExtraInhabitants(*this))
-    for (auto witness = ValueWitness::First_ExtraInhabitantValueWitness;
-         witness <= ValueWitness::Last_TypeLayoutWitness;
-         witness = ValueWitness(unsigned(witness) + 1))
-      addValueWitness(*this, witnesses, witness, packing, t, silTy, ti);
-
   auto layoutVar
     = witnesses.finishAndCreateGlobal(
         "type_layout_" + llvm::Twine(size)
@@ -1184,10 +1130,8 @@
                                       /*constant*/ true,
                                       llvm::GlobalValue::PrivateLinkage);
 
-  auto zero = llvm::ConstantInt::get(Int32Ty, 0);
-  llvm::Constant *indices[] = {zero, zero};
-  auto layout = llvm::ConstantExpr::getGetElementPtr(layoutVar->getValueType(),
-                                                     layoutVar, indices);
+  // Cast to the standard currency type for type layouts.
+  auto layout = llvm::ConstantExpr::getBitCast(layoutVar, Int8PtrPtrTy);
 
   PrivateFixedLayouts.insert({key, layout});
   return layout;
diff --git a/lib/IRGen/IRGenMangler.cpp b/lib/IRGen/IRGenMangler.cpp
index 0714f3d..8e48720 100644
--- a/lib/IRGen/IRGenMangler.cpp
+++ b/lib/IRGen/IRGenMangler.cpp
@@ -49,16 +49,14 @@
     GET_MANGLING(AssignWithTake) \
     GET_MANGLING(GetEnumTagSinglePayload) \
     GET_MANGLING(StoreEnumTagSinglePayload) \
-    GET_MANGLING(StoreExtraInhabitant) \
-    GET_MANGLING(GetExtraInhabitantIndex) \
     GET_MANGLING(GetEnumTag) \
     GET_MANGLING(DestructiveProjectEnumData) \
     GET_MANGLING(DestructiveInjectEnumTag)
 #undef GET_MANGLING
     case ValueWitness::Size:
     case ValueWitness::Flags:
+    case ValueWitness::ExtraInhabitantCount:
     case ValueWitness::Stride:
-    case ValueWitness::ExtraInhabitantFlags:
       llvm_unreachable("not a function witness");
   }
   appendOperator("w", Code);
diff --git a/lib/IRGen/IRGenModule.cpp b/lib/IRGen/IRGenModule.cpp
index 69c33d2..bf3c9cb 100644
--- a/lib/IRGen/IRGenModule.cpp
+++ b/lib/IRGen/IRGenModule.cpp
@@ -848,6 +848,10 @@
                                   llvm::AttributeList::FunctionIndex, b);
 }
 
+llvm::Constant *IRGenModule::getInt32(uint32_t value) {
+  return llvm::ConstantInt::get(Int32Ty, value);
+}
+
 llvm::Constant *IRGenModule::getSize(Size size) {
   return llvm::ConstantInt::get(SizeTy, size.getValue());
 }
diff --git a/lib/IRGen/IRGenModule.h b/lib/IRGen/IRGenModule.h
index 47df73b..6d41125 100644
--- a/lib/IRGen/IRGenModule.h
+++ b/lib/IRGen/IRGenModule.h
@@ -629,7 +629,7 @@
   /// Get the bit width of an integer type for the target platform.
   unsigned getBuiltinIntegerWidth(BuiltinIntegerType *t);
   unsigned getBuiltinIntegerWidth(BuiltinIntegerWidth w);
-  
+
   Size getPointerSize() const { return PtrSize; }
   Alignment getPointerAlignment() const {
     // We always use the pointer's width as its swift ABI alignment.
@@ -703,6 +703,11 @@
 
   llvm::StructType *getIntegerLiteralTy();
 
+  llvm::StructType *getValueWitnessTableTy();
+  llvm::StructType *getEnumValueWitnessTableTy();
+  llvm::PointerType *getValueWitnessTablePtrTy();
+  llvm::PointerType *getEnumValueWitnessTablePtrTy();
+
   void unimplemented(SourceLoc, StringRef Message);
   LLVM_ATTRIBUTE_NORETURN
   void fatal_unimplemented(SourceLoc, StringRef Message);
@@ -733,7 +738,9 @@
   llvm::FunctionType *AssociatedTypeWitnessTableAccessFunctionTy = nullptr;
   llvm::StructType *GenericWitnessTableCacheTy = nullptr;
   llvm::StructType *IntegerLiteralTy = nullptr;
-  
+  llvm::PointerType *ValueWitnessTablePtrTy = nullptr;
+  llvm::PointerType *EnumValueWitnessTablePtrTy = nullptr;
+
   llvm::DenseMap<llvm::Type *, SpareBitVector> SpareBitsForTypes;
   
 //--- Types -----------------------------------------------------------------
@@ -1189,6 +1196,7 @@
                                       ForeignFunctionInfo *foreignInfo=nullptr);
   ForeignFunctionInfo getForeignFunctionInfo(CanSILFunctionType type);
 
+  llvm::Constant *getInt32(uint32_t value);
   llvm::Constant *getSize(Size size);
   llvm::Constant *getAlignment(Alignment align);
   llvm::Constant *getBool(bool condition);
diff --git a/lib/IRGen/Linking.cpp b/lib/IRGen/Linking.cpp
index aacb934..d43e396 100644
--- a/lib/IRGen/Linking.cpp
+++ b/lib/IRGen/Linking.cpp
@@ -799,7 +799,7 @@
   case Kind::ReflectionFieldDescriptor:
   case Kind::ReflectionAssociatedTypeDescriptor:
     return IGM.FieldDescriptorTy;
-  case Kind::ValueWitnessTable:
+  case Kind::ValueWitnessTable: // TODO: use ValueWitnessTableTy
   case Kind::ProtocolWitnessTable:
   case Kind::ProtocolWitnessTablePattern:
     return IGM.WitnessTableTy;
diff --git a/lib/IRGen/NonFixedTypeInfo.h b/lib/IRGen/NonFixedTypeInfo.h
index 171ea3d..f64a1d2 100644
--- a/lib/IRGen/NonFixedTypeInfo.h
+++ b/lib/IRGen/NonFixedTypeInfo.h
@@ -30,16 +30,6 @@
 namespace swift {
 namespace irgen {
 
-/// Emits the generic implementation for getEnumTagSinglePayload.
-llvm::Value *emitGetEnumTagSinglePayload(IRGenFunction &IGF,
-                                         llvm::Value *numEmptyCases,
-                                         Address enumAddr, SILType T);
-
-/// Emits the generic implementation for storeEnumTagSinglePayload.
-void emitStoreEnumTagSinglePayload(IRGenFunction &IGF, llvm::Value *whichCase,
-                                   llvm::Value *numEmptyCases, Address enumAddr,
-                                   SILType T);
-
 /// An abstract CRTP class designed for types whose storage size,
 /// alignment, and stride need to be fetched from the value witness
 /// table for the type.
@@ -119,19 +109,7 @@
     return emitLoadOfIsInline(IGF, T);
   }
 
-  /// FIXME: Dynamic extra inhabitant lookup.
-  bool mayHaveExtraInhabitants(IRGenModule &) const override { return false; }
-  llvm::Value *getExtraInhabitantIndex(IRGenFunction &IGF,
-                                       Address src, SILType T,
-                                       bool isOutlined) const override {
-    llvm_unreachable("dynamic extra inhabitants not supported");
-  }
-  void storeExtraInhabitant(IRGenFunction &IGF,
-                            llvm::Value *index,
-                            Address dest, SILType T,
-                            bool isOutlined) const override {
-    llvm_unreachable("dynamic extra inhabitants not supported");
-  }
+  bool mayHaveExtraInhabitants(IRGenModule &) const override { return true; }
 
   llvm::Constant *getStaticSize(IRGenModule &IGM) const override {
     return nullptr;
@@ -142,19 +120,6 @@
   llvm::Constant *getStaticStride(IRGenModule &IGM) const override {
     return nullptr;
   }
-
-  llvm::Value *getEnumTagSinglePayload(IRGenFunction &IGF,
-                                       llvm::Value *numEmptyCases,
-                                       Address enumAddr,
-                                       SILType T) const override {
-    return emitGetEnumTagSinglePayload(IGF, numEmptyCases, enumAddr, T);
-  }
-
-  void storeEnumTagSinglePayload(IRGenFunction &IGF, llvm::Value *whichCase,
-                                 llvm::Value *numEmptyCases, Address enumAddr,
-                                 SILType T) const override {
-    emitStoreEnumTagSinglePayload(IGF, whichCase, numEmptyCases, enumAddr, T);
-  }
 };
 }
 }
diff --git a/lib/IRGen/ResilientTypeInfo.h b/lib/IRGen/ResilientTypeInfo.h
index 65418e5..65beaa7 100644
--- a/lib/IRGen/ResilientTypeInfo.h
+++ b/lib/IRGen/ResilientTypeInfo.h
@@ -137,30 +137,18 @@
   bool mayHaveExtraInhabitants(IRGenModule &IGM) const override {
     return true;
   }
-  llvm::Value *getExtraInhabitantIndex(IRGenFunction &IGF,
-                                       Address src,
-                                       SILType T,
-                                       bool isOutlined) const override {
-    return emitGetExtraInhabitantIndexCall(IGF, T, src);
-  }
-  void storeExtraInhabitant(IRGenFunction &IGF,
-                            llvm::Value *index,
-                            Address dest,
-                            SILType T,
-                            bool isOutlined) const override {
-    emitStoreExtraInhabitantCall(IGF, T, index, dest);
-  }
 
   llvm::Value *getEnumTagSinglePayload(IRGenFunction &IGF,
                                        llvm::Value *numEmptyCases,
                                        Address enumAddr,
-                                       SILType T) const override {
+                                       SILType T,
+                                       bool isOutlined) const override {
     return emitGetEnumTagSinglePayloadCall(IGF, T, numEmptyCases, enumAddr);
   }
 
   void storeEnumTagSinglePayload(IRGenFunction &IGF, llvm::Value *whichCase,
                                  llvm::Value *numEmptyCases, Address enumAddr,
-                                 SILType T) const override {
+                                 SILType T, bool isOutlined) const override {
     emitStoreEnumTagSinglePayloadCall(IGF, T, whichCase, numEmptyCases, enumAddr);
   }
 
diff --git a/lib/IRGen/TypeInfo.h b/lib/IRGen/TypeInfo.h
index 94665f8..921681e 100644
--- a/lib/IRGen/TypeInfo.h
+++ b/lib/IRGen/TypeInfo.h
@@ -402,42 +402,48 @@
   /// Does this type statically have extra inhabitants, or may it dynamically
   /// have extra inhabitants based on type arguments?
   virtual bool mayHaveExtraInhabitants(IRGenModule &IGM) const = 0;
-  
-  /// Map an extra inhabitant representation in memory to a unique 31-bit
-  /// identifier, and map a valid representation of the type to -1.
-  ///
-  /// Calls to this witness must be dominated by a runtime check that the type
-  /// has extra inhabitants.
-  virtual llvm::Value *getExtraInhabitantIndex(IRGenFunction &IGF,
-                                               Address src,
-                                               SILType T,
-                                               bool isOutlined) const = 0;
-  
-  /// Store the extra inhabitant representation indexed by a 31-bit identifier
-  /// to memory.
-  ///
-  /// Calls to this witness must be dominated by a runtime check that the type
-  /// has extra inhabitants.
-  virtual void storeExtraInhabitant(IRGenFunction &IGF,
-                                    llvm::Value *index,
-                                    Address dest,
-                                    SILType T,
-                                    bool isOutlined) const = 0;
-  
+
   /// Get the tag of a single payload enum with a payload of this type (\p T) e.g
   /// Optional<T>.
   virtual llvm::Value *getEnumTagSinglePayload(IRGenFunction &IGF,
                                                llvm::Value *numEmptyCases,
                                                Address enumAddr,
-                                               SILType T) const = 0;
+                                               SILType T,
+                                               bool isOutlined) const = 0;
 
   /// Store the tag of a single payload enum with a payload of this type.
   virtual void storeEnumTagSinglePayload(IRGenFunction &IGF,
                                          llvm::Value *whichCase,
                                          llvm::Value *numEmptyCases,
                                          Address enumAddr,
-                                         SILType T) const = 0;
-  
+                                         SILType T,
+                                         bool isOutlined) const = 0;
+
+  /// Return an extra-inhabitant tag for the given type, which will be
+  /// 0 for a value that's not an extra inhabitant or else a value in
+  /// 1...extraInhabitantCount.  Note that the range is off by one relative
+  /// to the expectations of FixedTypeInfo::getExtraInhabitantIndex!
+  ///
+  /// Most places in IRGen shouldn't be using this.
+  ///
+  /// knownXICount can be null.
+  llvm::Value *getExtraInhabitantTagDynamic(IRGenFunction &IGF,
+                                            Address address,
+                                            SILType T,
+                                            llvm::Value *knownXICount,
+                                            bool isOutlined) const;
+
+  /// Store an extra-inhabitant tag for the given type, which is known to be
+  /// in 1...extraInhabitantCount.  Note that the range is off by one
+  /// relative to the expectations of FixedTypeInfo::storeExtraInhabitant!
+  ///
+  /// Most places in IRGen shouldn't be using this.
+  void storeExtraInhabitantTagDynamic(IRGenFunction &IGF,
+                                      llvm::Value *index,
+                                      Address address,
+                                      SILType T,
+                                      bool isOutlined) const;
+
   /// Compute the packing of values of this type into a fixed-size buffer.
   /// A value might not be stored in the fixed-size buffer because it does not
   /// fit or because it is not bit-wise takable. Non bit-wise takable values are
diff --git a/lib/IRGen/TypeLayoutVerifier.cpp b/lib/IRGen/TypeLayoutVerifier.cpp
index d7e67a9..37e91f1 100644
--- a/lib/IRGen/TypeLayoutVerifier.cpp
+++ b/lib/IRGen/TypeLayoutVerifier.cpp
@@ -96,17 +96,12 @@
              "is-bitwise-takable bit");
       unsigned xiCount = fixedTI->getFixedExtraInhabitantCount(IGM);
       verifyValues(metadata,
-             emitLoadOfHasExtraInhabitants(*this, layoutType),
-             getBoolConstant(xiCount != 0),
-             "has-extra-inhabitants bit");
+             emitLoadOfExtraInhabitantCount(*this, layoutType),
+             IGM.getInt32(xiCount),
+             "extra inhabitant count");
 
       // Check extra inhabitants.
       if (xiCount > 0) {
-        verifyValues(metadata,
-               emitLoadOfExtraInhabitantCount(*this, layoutType),
-               getSizeConstant(Size(xiCount)),
-               "extra inhabitant count");
-        
         // Verify that the extra inhabitant representations are consistent.
         
         // TODO: Update for EnumPayload implementation changes.
@@ -122,10 +117,12 @@
         auto xiMask = fixedTI->getFixedExtraInhabitantMask(IGM);
         auto xiSchema = EnumPayloadSchema::withBitSize(xiMask.getBitWidth());
 
+        auto maxXiCount = std::min(xiCount, 256u);
+        auto numCases = llvm::ConstantInt::get(IGM.Int32Ty, maxXiCount);
+
         // TODO: Randomize the set of extra inhabitants we check.
         unsigned bits = fixedTI->getFixedSize().getValueInBits();
-        for (unsigned i = 0, e = std::min(xiCount, 256u);
-             i < e; ++i) {
+        for (unsigned i = 0, e = maxXiCount; i < e; ++i) {
           // Initialize the buffer with junk, to help ensure we're insensitive to
           // insignificant bits.
           // TODO: Randomize the filler.
@@ -135,8 +132,9 @@
                                    fixedTI->getFixedAlignment().getValue());
           
           // Ask the runtime to store an extra inhabitant.
-          auto index = llvm::ConstantInt::get(IGM.Int32Ty, i);
-          emitStoreExtraInhabitantCall(*this, layoutType, index, xiOpaque);
+          auto tag = llvm::ConstantInt::get(IGM.Int32Ty, i+1);
+          emitStoreEnumTagSinglePayloadCall(*this, layoutType, tag,
+                                            numCases, xiOpaque);
           
           // Compare the stored extra inhabitant against the fixed extra
           // inhabitant pattern.
@@ -171,11 +169,12 @@
             fixedXIValue, xiSchema);
           maskedXIPayload.store(*this, fixedXIBuf);
           
-          auto runtimeIndex = emitGetExtraInhabitantIndexCall(*this, layoutType,
-                                                              fixedXIOpaque);
+          auto runtimeTag =
+            emitGetEnumTagSinglePayloadCall(*this, layoutType, numCases,
+                                            fixedXIOpaque);
           verifyValues(metadata,
-                       runtimeIndex, index,
-                       llvm::Twine("extra inhabitant index calculation ")
+                       runtimeTag, tag,
+                       llvm::Twine("extra inhabitant tag calculation ")
                          + numberBuf.str());
         }
       }
diff --git a/lib/IRGen/WitnessIndex.h b/lib/IRGen/WitnessIndex.h
index 25717e4..5b64087 100644
--- a/lib/IRGen/WitnessIndex.h
+++ b/lib/IRGen/WitnessIndex.h
@@ -32,7 +32,6 @@
   unsigned IsPrefix : 1;
 public:
   WitnessIndex() = default;
-  WitnessIndex(ValueWitness index) : Value(int(index)) {}
   explicit WitnessIndex(int index, bool isPrefix)
       : Value(index), IsPrefix(isPrefix) {}
 
diff --git a/stdlib/public/Reflection/TypeLowering.cpp b/stdlib/public/Reflection/TypeLowering.cpp
index b01397c..84873fe 100644
--- a/stdlib/public/Reflection/TypeLowering.cpp
+++ b/stdlib/public/Reflection/TypeLowering.cpp
@@ -1076,10 +1076,12 @@
         // Dynamic multi-payload enums use the tag representations not assigned
         // to cases for extra inhabitants.
         if (tagCounts.numTagBytes >= 32) {
-          NumExtraInhabitants = INT_MAX;
+          NumExtraInhabitants = ValueWitnessFlags::MaxNumExtraInhabitants;
         } else {
           NumExtraInhabitants =
             (1 << (tagCounts.numTagBytes * 8)) - tagCounts.numTags;
+          NumExtraInhabitants = std::min(NumExtraInhabitants,
+                           unsigned(ValueWitnessFlags::MaxNumExtraInhabitants));
         }
       }
     }
diff --git a/stdlib/public/runtime/Casting.cpp b/stdlib/public/runtime/Casting.cpp
index 2d97e46..39b3575 100644
--- a/stdlib/public/runtime/Casting.cpp
+++ b/stdlib/public/runtime/Casting.cpp
@@ -1876,7 +1876,7 @@
   const Metadata *payloadType =
     cast<EnumMetadata>(srcType)->getGenericArgs()[0];
   unsigned enumCase =
-    swift_getEnumCaseSinglePayload(src, payloadType, 1 /*emptyCases=*/);
+    payloadType->vw_getEnumTagSinglePayload(src, /*emptyCases=*/1);
   if (enumCase != 0) {
     // Allow Optional<T>.none -> Optional<U>.none
     if (targetType->getKind() != MetadataKind::Optional) {
@@ -1889,8 +1889,8 @@
       cast<EnumMetadata>(targetType)->getGenericArgs()[0];
 
     // Inject the .none tag
-    swift_storeEnumTagSinglePayload(dest, targetPayloadType, enumCase,
-                                    1 /*emptyCases=*/);
+    targetPayloadType->vw_storeEnumTagSinglePayload(dest, enumCase, 
+                                                    /*emptyCases=*/1);
 
     // We don't have to destroy the source, because it was nil.
     return {true, nullptr};
@@ -2314,8 +2314,8 @@
     const Metadata *payloadType =
       cast<EnumMetadata>(targetType)->getGenericArgs()[0];
     if (swift_dynamicCast(dest, src, srcType, payloadType, flags)) {
-      swift_storeEnumTagSinglePayload(dest, payloadType, 0 /*case*/,
-                                      1 /*emptyCases*/);
+      payloadType->vw_storeEnumTagSinglePayload(dest, /*case*/ 0,
+                                                /*emptyCases*/ 1);
       return true;
     }
     return false;
@@ -2720,8 +2720,8 @@
   }
 
   // Initialize the buffer as an empty optional.
-  swift_storeEnumTagSinglePayload((OpaqueValue *)optDestBuffer, targetType, 
-                                  1, 1);
+  targetType->vw_storeEnumTagSinglePayload((OpaqueValue *)optDestBuffer,
+                                           1, 1);
 
   // Perform the bridging operation.
   bool success;
diff --git a/stdlib/public/runtime/Enum.cpp b/stdlib/public/runtime/Enum.cpp
index 83a519a..e693495 100644
--- a/stdlib/public/runtime/Enum.cpp
+++ b/stdlib/public/runtime/Enum.cpp
@@ -55,11 +55,6 @@
   layout.stride = payloadLayout->stride;
   layout.flags = payloadLayout->flags.withEnumWitnesses(true);
 
-  if (payloadLayout->flags.hasExtraInhabitants()) {
-    auto ew = static_cast<ExtraInhabitantsValueWitnessTable*>(vwtable);
-    ew->extraInhabitantFlags = payloadLayout->getExtraInhabitantFlags();
-  }
-
   vwtable->publishLayout(layout);
 }
 
@@ -93,10 +88,11 @@
   TypeLayout layout;
   layout.size = size;
   layout.flags =
-      payloadLayout->flags.withExtraInhabitants(unusedExtraInhabitants > 0)
+      payloadLayout->flags
           .withEnumWitnesses(true)
           .withInlineStorage(
               ValueWitnessTable::isValueInline(isBT, size, align));
+  layout.extraInhabitantCount = unusedExtraInhabitants;
   auto rawStride = llvm::alignTo(size, align);
   layout.stride = rawStride == 0 ? 1 : rawStride;
   
@@ -127,53 +123,39 @@
   }
 #endif
 
-
-  // If the payload has extra inhabitants left over after the ones we used,
-  // forward them as our own.
-  if (unusedExtraInhabitants > 0) {
-    auto xiVWTable = static_cast<ExtraInhabitantsValueWitnessTable*>(vwtable);
-    xiVWTable->extraInhabitantFlags = ExtraInhabitantFlags()
-      .withNumExtraInhabitants(unusedExtraInhabitants);
-  }
-
   vwtable->publishLayout(layout);
 }
 
-unsigned swift::swift_getEnumCaseSinglePayload(const OpaqueValue *value,
-                                               const Metadata *payload,
-                                               unsigned emptyCases) {
-
-  auto *payloadWitnesses = payload->getValueWitnesses();
-  auto size = payloadWitnesses->getSize();
-  auto numExtraInhabitants = payloadWitnesses->getNumExtraInhabitants();
-  auto EIVWT = dyn_cast<ExtraInhabitantsValueWitnessTable>(payloadWitnesses);
-  auto getExtraInhabitantIndex = EIVWT ? EIVWT->getExtraInhabitantIndex : nullptr;
-
-  return getEnumTagSinglePayloadImpl(value, emptyCases, payload, size,
+unsigned
+swift::swift_getEnumTagSinglePayloadGeneric(const OpaqueValue *value,
+                                            unsigned emptyCases,
+                                            const Metadata *payloadType,
+                               getExtraInhabitantTag_t *getExtraInhabitantTag) {
+  auto size = payloadType->vw_size();
+  auto numExtraInhabitants = payloadType->vw_getNumExtraInhabitants();
+  return getEnumTagSinglePayloadImpl(value, emptyCases, payloadType, size,
                                      numExtraInhabitants,
-                                     getExtraInhabitantIndex);
+                                     getExtraInhabitantTag);
 }
 
-void swift::swift_storeEnumTagSinglePayload(OpaqueValue *value,
-                                            const Metadata *payload,
-                                            unsigned whichCase,
-                                            unsigned emptyCases) {
-
-  auto *payloadWitnesses = payload->getValueWitnesses();
-  auto size = payloadWitnesses->getSize();
-  auto numExtraInhabitants = payloadWitnesses->getNumExtraInhabitants();
-  auto EIVWT = dyn_cast<ExtraInhabitantsValueWitnessTable>(payloadWitnesses);
-  auto storeExtraInhabitant = EIVWT ? EIVWT->storeExtraInhabitant : nullptr;
-
-  storeEnumTagSinglePayloadImpl(value, whichCase, emptyCases, payload, size,
-                                numExtraInhabitants, storeExtraInhabitant);
+void swift::swift_storeEnumTagSinglePayloadGeneric(OpaqueValue *value,
+                                                   unsigned whichCase,
+                                                   unsigned emptyCases,
+                                                   const Metadata *payloadType,
+                           storeExtraInhabitantTag_t *storeExtraInhabitantTag) {
+  auto size = payloadType->vw_size();
+  auto numExtraInhabitants = payloadType->vw_getNumExtraInhabitants();
+  storeEnumTagSinglePayloadImpl(value, whichCase, emptyCases, payloadType, size,
+                                numExtraInhabitants, storeExtraInhabitantTag);
 }
 
-static int32_t getMultiPayloadExtraInhabitantIndex(const OpaqueValue *value,
-                                                   const Metadata *enumType);
-static void storeMultiPayloadExtraInhabitant(OpaqueValue *value,
-                                             int32_t index,
-                                             const Metadata *enumType);
+static uint32_t getMultiPayloadEnumTagSinglePayload(const OpaqueValue *value,
+                                                    uint32_t numExtraCases,
+                                                    const Metadata *enumType);
+static void storeMultiPayloadEnumTagSinglePayload(OpaqueValue *value,
+                                                  uint32_t index,
+                                                  uint32_t numExtraCases,
+                                                  const Metadata *enumType);
 
 void
 swift::swift_initEnumMetadataMultiPayload(EnumMetadata *enumType,
@@ -205,32 +187,32 @@
   unsigned numExtraInhabitants = tagCounts.numTagBytes == 4
     ? INT_MAX
     : (1 << (tagCounts.numTagBytes * 8)) - tagCounts.numTags;
+  numExtraInhabitants = std::min(numExtraInhabitants,
+                          unsigned(ValueWitnessFlags::MaxNumExtraInhabitants));
 
   auto vwtable = getMutableVWTableForInit(enumType, layoutFlags);
 
   // Set up the layout info in the vwtable.
   auto rawStride = (totalSize + alignMask) & ~alignMask;
   TypeLayout layout{totalSize,
+                    rawStride == 0 ? 1 : rawStride,
                     ValueWitnessFlags()
                      .withAlignmentMask(alignMask)
                      .withPOD(isPOD)
                      .withBitwiseTakable(isBT)
-                     .withExtraInhabitants(numExtraInhabitants > 0)
                      .withEnumWitnesses(true)
                      .withInlineStorage(ValueWitnessTable::isValueInline(
                          isBT, totalSize, alignMask + 1)),
-                    rawStride == 0 ? 1 : rawStride,
-                    numExtraInhabitants > 0
-                      ? ExtraInhabitantFlags()
-                          .withNumExtraInhabitants(numExtraInhabitants)
-                      : ExtraInhabitantFlags()};
+                    numExtraInhabitants};
 
   installCommonValueWitnesses(layout, vwtable);
-  if (numExtraInhabitants > 0) {
-    vwtable->extraInhabitantFlags = layout.getExtraInhabitantFlags();
-    vwtable->storeExtraInhabitant = storeMultiPayloadExtraInhabitant;
-    vwtable->getExtraInhabitantIndex = getMultiPayloadExtraInhabitantIndex;
-  }
+
+  // Unconditionally overwrite the enum-tag witnesses.
+  // The compiler does not generate meaningful enum-tag witnesses for
+  // enums in this state.
+  vwtable->getEnumTagSinglePayload = getMultiPayloadEnumTagSinglePayload;
+  vwtable->storeEnumTagSinglePayload = storeMultiPayloadEnumTagSinglePayload;
+
   vwtable->publishLayout(layout);
 }
 
@@ -320,22 +302,45 @@
   return payloadValue;
 }
 
-static int32_t getMultiPayloadExtraInhabitantIndex(const OpaqueValue *value,
-                                                   const Metadata *enumType) {
+SWIFT_CC(swift)
+static unsigned getMultiPayloadExtraInhabitantTag(const OpaqueValue *value,
+                                                  unsigned enumNumXI,
+                                                  const Metadata *enumType) {
   auto layout = getMultiPayloadLayout(cast<EnumMetadata>(enumType));
   unsigned index = ~loadMultiPayloadTag(value, layout, ~0u);
   
   if (index >= enumType->getValueWitnesses()->getNumExtraInhabitants())
-    return -1;
-  return index;
-}
-static void storeMultiPayloadExtraInhabitant(OpaqueValue *value,
-                                             int32_t index,
-                                             const Metadata *enumType) {
-  auto layout = getMultiPayloadLayout(cast<EnumMetadata>(enumType));
-  storeMultiPayloadTag(value, layout, ~index);
+    return 0;
+  return index + 1;
 }
 
+SWIFT_CC(swift)
+static void storeMultiPayloadExtraInhabitantTag(OpaqueValue *value,
+                                                unsigned tag,
+                                                unsigned enumNumXI,
+                                                const Metadata *enumType) {
+  auto layout = getMultiPayloadLayout(cast<EnumMetadata>(enumType));
+  storeMultiPayloadTag(value, layout, ~(tag - 1));
+}
+
+static uint32_t getMultiPayloadEnumTagSinglePayload(const OpaqueValue *value,
+                                                    uint32_t numExtraCases,
+                                                    const Metadata *enumType) {
+  return getEnumTagSinglePayloadImpl(value, numExtraCases, enumType,
+                                     enumType->vw_size(),
+                                     enumType->vw_getNumExtraInhabitants(),
+                                     getMultiPayloadExtraInhabitantTag);
+}
+
+static void storeMultiPayloadEnumTagSinglePayload(OpaqueValue *value,
+                                                  uint32_t index,
+                                                  uint32_t numExtraCases,
+                                                  const Metadata *enumType) {
+  storeEnumTagSinglePayloadImpl(value, index, numExtraCases, enumType,
+                                enumType->vw_size(),
+                                enumType->vw_getNumExtraInhabitants(),
+                                storeMultiPayloadExtraInhabitantTag);
+}
 
 void
 swift::swift_storeEnumTagMultiPayload(OpaqueValue *value,
diff --git a/stdlib/public/runtime/EnumImpl.h b/stdlib/public/runtime/EnumImpl.h
index d0471f9..755504b 100644
--- a/stdlib/public/runtime/EnumImpl.h
+++ b/stdlib/public/runtime/EnumImpl.h
@@ -17,6 +17,7 @@
 #define SWIFT_RUNTIME_ENUMIMPL_H
 
 #include "swift/ABI/Enum.h"
+#include "swift/Runtime/Enum.h"
 
 namespace swift {
 
@@ -63,8 +64,8 @@
 
 inline unsigned getEnumTagSinglePayloadImpl(
     const OpaqueValue *enumAddr, unsigned emptyCases, const Metadata *payload,
-    size_t payloadSize, size_t payloadNumExtraInhabitants,
-    int (*getExtraInhabitantIndex)(const OpaqueValue *, const Metadata *)) {
+    size_t payloadSize, unsigned payloadNumExtraInhabitants,
+    getExtraInhabitantTag_t *getExtraInhabitantTag) {
 
   // If there are extra tag bits, check them.
   if (emptyCases > payloadNumExtraInhabitants) {
@@ -116,7 +117,7 @@
 
   // If there are extra inhabitants, see whether the payload is valid.
   if (payloadNumExtraInhabitants > 0) {
-    return getExtraInhabitantIndex(enumAddr, payload) + 1;
+    return getExtraInhabitantTag(enumAddr, payloadNumExtraInhabitants, payload);
   }
 
   // Otherwise, we have always have a valid payload.
@@ -126,9 +127,8 @@
 inline void storeEnumTagSinglePayloadImpl(
     OpaqueValue *value, unsigned whichCase, unsigned emptyCases,
     const Metadata *payload, size_t payloadSize,
-    size_t payloadNumExtraInhabitants,
-    void (*storeExtraInhabitant)(OpaqueValue *, int whichCase,
-                                 const Metadata *)) {
+    unsigned payloadNumExtraInhabitants,
+    storeExtraInhabitantTag_t *storeExtraInhabitantTag) {
 
   auto *valueAddr = reinterpret_cast<uint8_t *>(value);
   auto *extraTagBitAddr = valueAddr + payloadSize;
@@ -150,8 +150,8 @@
       return;
 
     // Store the extra inhabitant.
-    unsigned noPayloadIndex = whichCase - 1;
-    storeExtraInhabitant(value, noPayloadIndex, payload);
+    storeExtraInhabitantTag(value, whichCase, payloadNumExtraInhabitants,
+                            payload);
     return;
   }
 
diff --git a/stdlib/public/runtime/ExistentialMetadataImpl.h b/stdlib/public/runtime/ExistentialMetadataImpl.h
index 1eed70b..e8951c5 100644
--- a/stdlib/public/runtime/ExistentialMetadataImpl.h
+++ b/stdlib/public/runtime/ExistentialMetadataImpl.h
@@ -331,16 +331,16 @@
   static constexpr unsigned numExtraInhabitants =
     swift_getHeapObjectExtraInhabitantCount();
 
-  static void storeExtraInhabitant(Container *dest, int index) {
+  static void storeExtraInhabitantTag(Container *dest, unsigned tag) {
     swift_storeHeapObjectExtraInhabitant(
         const_cast<HeapObject **>(
             reinterpret_cast<const HeapObject **>(&dest->Header.Type)),
-        index);
+        tag - 1);
   }
 
-  static int getExtraInhabitantIndex(const Container *src) {
+  static unsigned getExtraInhabitantTag(const Container *src) {
     return swift_getHeapObjectExtraInhabitantIndex(const_cast<HeapObject **>(
-        reinterpret_cast<const HeapObject *const *>(&src->Header.Type)));
+        reinterpret_cast<const HeapObject *const *>(&src->Header.Type))) + 1;
   }
 };
 
@@ -387,14 +387,14 @@
   static constexpr unsigned numExtraInhabitants =
     swift_getHeapObjectExtraInhabitantCount();
   
-  static void storeExtraInhabitant(Container *dest, int index) {
+  static void storeExtraInhabitantTag(Container *dest, unsigned tag) {
     swift_storeHeapObjectExtraInhabitant(
-                            (HeapObject**)(uintptr_t)&dest->Header.Type, index);
+                            (HeapObject**)(uintptr_t)&dest->Header.Type, tag - 1);
   }
 
-  static int getExtraInhabitantIndex(const Container *src) {
+  static unsigned getExtraInhabitantTag(const Container *src) {
     return swift_getHeapObjectExtraInhabitantIndex(
-                             (HeapObject* const *)(uintptr_t)&src->Header.Type);
+                             (HeapObject* const *)(uintptr_t)&src->Header.Type) + 1;
   }
 };
 
@@ -452,15 +452,15 @@
   }
 
   template <class Container, class... A>
-  static void storeExtraInhabitant(Container *dest, int index, A... args) {
+  static void storeExtraInhabitantTag(Container *dest, unsigned tag, A... args) {
     swift_storeHeapObjectExtraInhabitant((HeapObject**) dest->getValueSlot(),
-                                         index);
+                                         tag - 1);
   }
 
   template <class Container, class... A>
-  static int getExtraInhabitantIndex(const Container *src, A... args) {
+  static int getExtraInhabitantTag(const Container *src, A... args) {
     return swift_getHeapObjectExtraInhabitantIndex(
-                                  (HeapObject* const *) src->getValueSlot());
+                                  (HeapObject* const *) src->getValueSlot()) + 1;
   }
   
 };
@@ -574,17 +574,17 @@
   }
 
   template <class Container, class... A>
-  static void storeExtraInhabitant(Container *dest, int index, A... args) {
+  static void storeExtraInhabitantTag(Container *dest, unsigned tag, A... args) {
     Metadata **MD = const_cast<Metadata **>(dest->getValueSlot());
     swift_storeHeapObjectExtraInhabitant(reinterpret_cast<HeapObject **>(MD),
-                                         index);
+                                         tag - 1);
   }
 
   template <class Container, class... A>
-  static int getExtraInhabitantIndex(const Container *src, A... args) {
+  static int getExtraInhabitantTag(const Container *src, A... args) {
     Metadata **MD = const_cast<Metadata **>(src->getValueSlot());
     return swift_getHeapObjectExtraInhabitantIndex(
-        reinterpret_cast<HeapObject *const *>(MD));
+        reinterpret_cast<HeapObject *const *>(MD)) + 1;
   }
 };
 
diff --git a/stdlib/public/runtime/KnownMetadata.cpp b/stdlib/public/runtime/KnownMetadata.cpp
index bc9b49e..2c24db7 100644
--- a/stdlib/public/runtime/KnownMetadata.cpp
+++ b/stdlib/public/runtime/KnownMetadata.cpp
@@ -157,7 +157,7 @@
                                     BuiltinType<ctypes::Symbol>::Alignment>>::table;
 
 #define BUILTIN_POINTER_TYPE(Symbol, Name)                 \
-const ExtraInhabitantsValueWitnessTable swift::VALUE_WITNESS_SYM(Symbol) =     \
+const ValueWitnessTable swift::VALUE_WITNESS_SYM(Symbol) =     \
   ValueWitnessTableForBox<pointer_types::Symbol>::table;
 
 #define BUILTIN_VECTOR_TYPE(ElementSymbol, _, Width)                           \
@@ -169,7 +169,7 @@
 #include "swift/Runtime/BuiltinTypes.def"
 
 /// The value-witness table for pointer-aligned unmanaged pointer types.
-const ExtraInhabitantsValueWitnessTable swift::METATYPE_VALUE_WITNESS_SYM(Bo) =
+const ValueWitnessTable swift::METATYPE_VALUE_WITNESS_SYM(Bo) =
   ValueWitnessTableForBox<PointerPointerBox>::table;
 
 /*** Functions ***************************************************************/
@@ -182,12 +182,12 @@
     static constexpr unsigned numExtraInhabitants =
       FunctionPointerBox::numExtraInhabitants;
 
-    static void storeExtraInhabitant(char *dest, int index) {
-      FunctionPointerBox::storeExtraInhabitant((void**) dest, index);
+    static void storeExtraInhabitantTag(char *dest, unsigned tag) {
+      FunctionPointerBox::storeExtraInhabitantTag((void**) dest, tag);
     }
 
-    static int getExtraInhabitantIndex(const char *src) {
-      return FunctionPointerBox::getExtraInhabitantIndex((void * const *) src);
+    static unsigned getExtraInhabitantTag(const char *src) {
+      return FunctionPointerBox::getExtraInhabitantTag((void * const *) src);
     }
   };
   /// @noescape function types.
@@ -197,28 +197,28 @@
     static constexpr unsigned numExtraInhabitants =
         FunctionPointerBox::numExtraInhabitants;
 
-    static void storeExtraInhabitant(char *dest, int index) {
-      FunctionPointerBox::storeExtraInhabitant((void **)dest, index);
+    static void storeExtraInhabitantTag(char *dest, unsigned tag) {
+      FunctionPointerBox::storeExtraInhabitantTag((void **)dest, tag);
     }
 
-    static int getExtraInhabitantIndex(const char *src) {
-      return FunctionPointerBox::getExtraInhabitantIndex((void *const *)src);
+    static unsigned getExtraInhabitantTag(const char *src) {
+      return FunctionPointerBox::getExtraInhabitantTag((void *const *)src);
     }
   };
 } // end anonymous namespace
 
 /// The basic value-witness table for escaping function types.
-const ExtraInhabitantsValueWitnessTable
+const ValueWitnessTable
   swift::VALUE_WITNESS_SYM(FUNCTION_MANGLING) =
     ValueWitnessTableForBox<ThickFunctionBox>::table;
 
 /// The basic value-witness table for @noescape function types.
-const ExtraInhabitantsValueWitnessTable
+const ValueWitnessTable
   swift::VALUE_WITNESS_SYM(NOESCAPE_FUNCTION_MANGLING) =
     ValueWitnessTableForBox<TrivialThickFunctionBox>::table;
 
 /// The basic value-witness table for thin function types.
-const ExtraInhabitantsValueWitnessTable
+const ValueWitnessTable
   swift::VALUE_WITNESS_SYM(THIN_FUNCTION_MANGLING) =
     ValueWitnessTableForBox<FunctionPointerBox>::table;
 
diff --git a/stdlib/public/runtime/Metadata.cpp b/stdlib/public/runtime/Metadata.cpp
index a6c93e6..91654b9 100644
--- a/stdlib/public/runtime/Metadata.cpp
+++ b/stdlib/public/runtime/Metadata.cpp
@@ -1039,7 +1039,7 @@
   // NOTE: if you change the layout of this type, you'll also need
   // to update tuple_getValueWitnesses().
   unsigned ExtraInhabitantProvidingElement;
-  ExtraInhabitantsValueWitnessTable Witnesses;
+  ValueWitnessTable Witnesses;
   FullMetadata<TupleTypeMetadata> Data;
 
   struct Key {
@@ -1151,7 +1151,7 @@
 /// Given a metatype pointer, produce the value-witness table for it.
 /// This is equivalent to metatype->ValueWitnesses but more efficient.
 static const ValueWitnessTable *tuple_getValueWitnesses(const Metadata *metatype) {
-  return ((const ExtraInhabitantsValueWitnessTable*) asFullMetadata(metatype)) - 1;
+  return ((const ValueWitnessTable*) asFullMetadata(metatype)) - 1;
 }
 
 /// Generic tuple value witness for 'projectBuffer'.
@@ -1309,29 +1309,37 @@
   return tuple_projectBuffer<IsPOD, IsInline>(dest, metatype);
 }
 
-static void tuple_storeExtraInhabitant(OpaqueValue *tuple,
-                                       int index,
-                                       const Metadata *_metatype) {
+SWIFT_CC(swift)
+static void tuple_storeExtraInhabitantTag(OpaqueValue *tuple,
+                                          unsigned tag,
+                                          unsigned xiCount,
+                                          const Metadata *_metatype) {
   auto &metatype = *(const TupleTypeMetadata*) _metatype;
   auto cacheEntry = TupleCacheStorage::resolveExistingEntry(&metatype);
   auto &eltInfo =
     metatype.getElement(cacheEntry->ExtraInhabitantProvidingElement);
+  assert(xiCount == eltInfo.Type->vw_getNumExtraInhabitants());
 
   auto *elt = (OpaqueValue*)((uintptr_t)tuple + eltInfo.Offset);
 
-  eltInfo.Type->vw_storeExtraInhabitant(elt, index);
+  assert(tag >= 1);
+  assert(tag <= xiCount);
+  eltInfo.Type->vw_storeEnumTagSinglePayload(elt, tag, xiCount);
 }
 
-static int tuple_getExtraInhabitantIndex(const OpaqueValue *tuple,
-                                         const Metadata *_metatype) {
+SWIFT_CC(swift)
+static unsigned tuple_getExtraInhabitantTag(const OpaqueValue *tuple,
+                                            unsigned xiCount,
+                                            const Metadata *_metatype) {
   auto &metatype = *(const TupleTypeMetadata*) _metatype;
 
   auto cacheEntry = TupleCacheStorage::resolveExistingEntry(&metatype);
   auto &eltInfo =
     metatype.getElement(cacheEntry->ExtraInhabitantProvidingElement);
+  assert(xiCount == eltInfo.Type->vw_getNumExtraInhabitants());
 
   auto *elt = (const OpaqueValue*)((uintptr_t)tuple + eltInfo.Offset);
-  return eltInfo.Type->vw_getExtraInhabitantIndex(elt);
+  return eltInfo.Type->vw_getEnumTagSinglePayload(elt, xiCount);
 }
 
 template <bool IsPOD, bool IsInline>
@@ -1342,12 +1350,11 @@
   auto *witnesses = tuple_getValueWitnesses(self);
   auto size = witnesses->getSize();
   auto numExtraInhabitants = witnesses->getNumExtraInhabitants();
-  auto getExtraInhabitantIndex = numExtraInhabitants > 0
-    ? tuple_getExtraInhabitantIndex : nullptr;
+  auto getExtraInhabitantTag = tuple_getExtraInhabitantTag;
 
   return getEnumTagSinglePayloadImpl(enumAddr, numEmptyCases, self, size,
                                      numExtraInhabitants,
-                                     getExtraInhabitantIndex);
+                                     getExtraInhabitantTag);
 }
 
 template <bool IsPOD, bool IsInline>
@@ -1357,11 +1364,10 @@
   auto *witnesses = tuple_getValueWitnesses(self);
   auto size = witnesses->getSize();
   auto numExtraInhabitants = witnesses->getNumExtraInhabitants();
-  auto storeExtraInhabitant = numExtraInhabitants > 0
-    ? tuple_storeExtraInhabitant : nullptr;
+  auto storeExtraInhabitantTag = tuple_storeExtraInhabitantTag;
 
   storeEnumTagSinglePayloadImpl(enumAddr, whichCase, numEmptyCases, self, size,
-                                numExtraInhabitants, storeExtraInhabitant);
+                                numExtraInhabitants, storeExtraInhabitantTag);
 }
 
 /// Various standard witness table for tuples.
@@ -1371,6 +1377,7 @@
 #define DATA_VALUE_WITNESS(LOWER_ID, UPPER_ID, TYPE)
 #include "swift/ABI/ValueWitness.def"
   0,
+  0,
   ValueWitnessFlags(),
   0
 };
@@ -1380,6 +1387,7 @@
 #define DATA_VALUE_WITNESS(LOWER_ID, UPPER_ID, TYPE)
 #include "swift/ABI/ValueWitness.def"
   0,
+  0,
   ValueWitnessFlags(),
   0
 };
@@ -1389,6 +1397,7 @@
 #define DATA_VALUE_WITNESS(LOWER_ID, UPPER_ID, TYPE)
 #include "swift/ABI/ValueWitness.def"
   0,
+  0,
   ValueWitnessFlags(),
   0
 };
@@ -1398,18 +1407,20 @@
 #define DATA_VALUE_WITNESS(LOWER_ID, UPPER_ID, TYPE)
 #include "swift/ABI/ValueWitness.def"
   0,
+  0,
   ValueWitnessFlags(),
   0
 };
 
 static constexpr TypeLayout getInitialLayoutForValueType() {
-  return {0, ValueWitnessFlags().withAlignment(1).withPOD(true), 0};
+  return {0, 0, ValueWitnessFlags().withAlignment(1).withPOD(true), 0};
 }
 
 static constexpr TypeLayout getInitialLayoutForHeapObject() {
   return {sizeof(HeapObject),
+          sizeof(HeapObject),
           ValueWitnessFlags().withAlignment(alignof(HeapObject)),
-          sizeof(HeapObject)};
+          0};
 }
 
 static size_t roundUpToAlignMask(size_t size, size_t alignMask) {
@@ -1460,6 +1471,7 @@
                      .withPOD(isPOD)
                      .withBitwiseTakable(isBitwiseTakable)
                      .withInlineStorage(isInline);
+  layout.extraInhabitantCount = 0;
   layout.stride = std::max(size_t(1), roundUpToAlignMask(size, alignMask));
 }
 
@@ -1505,10 +1517,9 @@
   
   if (numExtraInhabitants > 0) {
     *result = TypeLayout(result->size,
-                         result->flags.withExtraInhabitants(true),
                          result->stride,
-                         ExtraInhabitantFlags()
-                           .withNumExtraInhabitants(numExtraInhabitants));
+                         result->flags,
+                         numExtraInhabitants);
   }
 }
 
@@ -1649,22 +1660,16 @@
   unsigned extraInhabitantProvidingElement = ~0u;
   unsigned numExtraInhabitants = 0;
   for (unsigned i = 0, e = Data.NumElements; i < e; ++i) {
-    if (auto eltEIVWI = dyn_cast<ExtraInhabitantsValueWitnessTable>(
-                                Data.getElement(i).Type->getValueWitnesses())) {
-      unsigned eltEI = eltEIVWI->extraInhabitantFlags.getNumExtraInhabitants();
-      if (eltEI > numExtraInhabitants) {
-        extraInhabitantProvidingElement = i;
-        numExtraInhabitants = eltEI;
-      }
+    unsigned eltEI = Data.getElement(i).Type->getValueWitnesses()
+                                            ->getNumExtraInhabitants();
+    if (eltEI > numExtraInhabitants) {
+      extraInhabitantProvidingElement = i;
+      numExtraInhabitants = eltEI;
     }
   }
+  Witnesses.extraInhabitantCount = numExtraInhabitants;
   if (numExtraInhabitants > 0) {
     ExtraInhabitantProvidingElement = extraInhabitantProvidingElement;
-    Witnesses.flags = Witnesses.flags.withExtraInhabitants(true);
-    Witnesses.extraInhabitantFlags = ExtraInhabitantFlags()
-      .withNumExtraInhabitants(numExtraInhabitants);
-    Witnesses.storeExtraInhabitant = tuple_storeExtraInhabitant;
-    Witnesses.getExtraInhabitantIndex = tuple_getExtraInhabitantIndex;
   }
 
   // Copy the function witnesses in, either from the proposed
@@ -1882,61 +1887,21 @@
   return reinterpret_cast<OpaqueValue *>(bytePtr + byteOffset);
 }
 
-static void pod_noop(void *object, const Metadata *self) {
-}
-#define pod_direct_destroy \
-  pointer_function_cast<ValueWitnessTypes::destroy>(pod_noop)
-#define pod_indirect_destroy pod_direct_destroy
+static void pod_destroy(OpaqueValue *object, const Metadata *self) {}
 
-static OpaqueValue *pod_direct_initializeWithCopy(OpaqueValue *dest,
-                                                  OpaqueValue *src,
-                                                  const Metadata *self) {
+static OpaqueValue *pod_copy(OpaqueValue *dest, OpaqueValue *src,
+                             const Metadata *self) {
   memcpy(dest, src, self->getValueWitnesses()->size);
   return dest;
 }
-#define pod_indirect_initializeWithCopy pod_direct_initializeWithCopy
-#define pod_direct_initializeBufferWithCopyOfBuffer \
-  pointer_function_cast<ValueWitnessTypes::initializeBufferWithCopyOfBuffer> \
-    (pod_direct_initializeWithCopy)
-#define pod_direct_assignWithCopy pod_direct_initializeWithCopy
-#define pod_indirect_assignWithCopy pod_direct_initializeWithCopy
-#define pod_direct_initializeWithTake pod_direct_initializeWithCopy
-#define pod_indirect_initializeWithTake pod_direct_initializeWithCopy
-#define pod_direct_assignWithTake pod_direct_initializeWithCopy
-#define pod_indirect_assignWithTake pod_direct_initializeWithCopy
 
-static unsigned pod_direct_getEnumTagSinglePayload(const OpaqueValue *enumAddr,
-                                                   unsigned numEmptyCases,
-                                                   const Metadata *self) {
-  auto *witnesses = self->getValueWitnesses();
-  auto size = witnesses->getSize();
-  auto numExtraInhabitants = witnesses->getNumExtraInhabitants();
-  auto EIVWT = dyn_cast<ExtraInhabitantsValueWitnessTable>(witnesses);
-  auto getExtraInhabitantIndex = EIVWT ? EIVWT->getExtraInhabitantIndex : nullptr;
-
-  return getEnumTagSinglePayloadImpl(enumAddr, numEmptyCases, self, size,
-                                     numExtraInhabitants,
-                                     getExtraInhabitantIndex);
+static OpaqueValue *pod_direct_initializeBufferWithCopyOfBuffer(
+                    ValueBuffer *dest, ValueBuffer *src, const Metadata *self) {
+  return pod_copy(reinterpret_cast<OpaqueValue*>(dest),
+                  reinterpret_cast<OpaqueValue*>(src),
+                  self);
 }
 
-static void pod_direct_storeEnumTagSinglePayload(OpaqueValue *enumAddr,
-                                                 unsigned whichCase,
-                                                 unsigned numEmptyCases,
-                                                 const Metadata *self) {
-  auto *witnesses = self->getValueWitnesses();
-  auto size = witnesses->getSize();
-  auto numExtraInhabitants = witnesses->getNumExtraInhabitants();
-  auto EIVWT = dyn_cast<ExtraInhabitantsValueWitnessTable>(witnesses);
-  auto storeExtraInhabitant = EIVWT ? EIVWT->storeExtraInhabitant : nullptr;
-
-  storeEnumTagSinglePayloadImpl(enumAddr, whichCase, numEmptyCases, self, size,
-                                numExtraInhabitants, storeExtraInhabitant);
-}
-
-#define pod_indirect_getEnumTagSinglePayload pod_direct_getEnumTagSinglePayload
-#define pod_indirect_storeEnumTagSinglePayload \
-  pod_direct_storeEnumTagSinglePayload
-
 static constexpr uint64_t sizeWithAlignmentMask(uint64_t size,
                                                 uint64_t alignmentMask,
                                                 uint64_t hasExtraInhabitants) {
@@ -1951,25 +1916,26 @@
     // If the value has a common size and alignment, use specialized value
     // witnesses we already have lying around for the builtin types.
     const ValueWitnessTable *commonVWT;
-    bool hasExtraInhabitants = flags.hasExtraInhabitants();
+    bool hasExtraInhabitants = layout.hasExtraInhabitants();
     switch (sizeWithAlignmentMask(layout.size, flags.getAlignmentMask(),
                                   hasExtraInhabitants)) {
     default:
       // For uncommon layouts, use value witnesses that work with an arbitrary
       // size and alignment.
       if (flags.isInlineStorage()) {
-#define WANT_ONLY_REQUIRED_VALUE_WITNESSES
-#define VALUE_WITNESS(LOWER_ID, UPPER_ID) \
-        vwtable->LOWER_ID = pod_direct_##LOWER_ID;
-#define DATA_VALUE_WITNESS(LOWER_ID, UPPER_ID, TYPE)
-#include "swift/ABI/ValueWitness.def"
+        vwtable->initializeBufferWithCopyOfBuffer =
+          pod_direct_initializeBufferWithCopyOfBuffer;
       } else {
-#define WANT_ONLY_REQUIRED_VALUE_WITNESSES
-#define VALUE_WITNESS(LOWER_ID, UPPER_ID) \
-        vwtable->LOWER_ID = pod_indirect_##LOWER_ID;
-#define DATA_VALUE_WITNESS(LOWER_ID, UPPER_ID, TYPE)
-#include "swift/ABI/ValueWitness.def"
+        vwtable->initializeBufferWithCopyOfBuffer =
+          pod_indirect_initializeBufferWithCopyOfBuffer;
       }
+      vwtable->destroy = pod_destroy;
+      vwtable->initializeWithCopy = pod_copy;
+      vwtable->initializeWithTake = pod_copy;
+      vwtable->assignWithCopy = pod_copy;
+      vwtable->assignWithTake = pod_copy;
+      // getEnumTagSinglePayload and storeEnumTagSinglePayload are not
+      // interestingly optimizable based on POD-ness.
       return;
       
     case sizeWithAlignmentMask(1, 0, 0):
@@ -2006,11 +1972,7 @@
   
   if (flags.isBitwiseTakable()) {
     // Use POD value witnesses for operations that do an initializeWithTake.
-    if (flags.isInlineStorage()) {
-      vwtable->initializeWithTake = pod_direct_initializeWithTake;
-    } else {
-      vwtable->initializeWithTake = pod_indirect_initializeWithTake;
-    }
+    vwtable->initializeWithTake = pod_copy;
     return;
   }
 
@@ -2021,8 +1983,7 @@
 /***************************************************************************/
 
 static ValueWitnessTable *getMutableVWTableForInit(StructMetadata *self,
-                                                   StructLayoutFlags flags,
-                                                   bool hasExtraInhabitants) {
+                                                   StructLayoutFlags flags) {
   auto oldTable = self->getValueWitnesses();
 
   // If we can alter the existing table in-place, do so.
@@ -2030,17 +1991,9 @@
     return const_cast<ValueWitnessTable*>(oldTable);
 
   // Otherwise, allocate permanent memory for it and copy the existing table.
-  ValueWitnessTable *newTable;
-  if (hasExtraInhabitants) {
-    void *memory = allocateMetadata(sizeof(ExtraInhabitantsValueWitnessTable),
-                                    alignof(ExtraInhabitantsValueWitnessTable));
-    newTable = new (memory) ExtraInhabitantsValueWitnessTable(
-              *static_cast<const ExtraInhabitantsValueWitnessTable*>(oldTable));
-  } else {
-    void *memory = allocateMetadata(sizeof(ValueWitnessTable),
-                                    alignof(ValueWitnessTable));
-    newTable = new (memory) ValueWitnessTable(*oldTable);
-  }
+  void *memory = allocateMetadata(sizeof(ValueWitnessTable),
+                                  alignof(ValueWitnessTable));
+  auto newTable = new (memory) ValueWitnessTable(*oldTable);
 
   // If we ever need to check layout-completeness asynchronously from
   // initialization, we'll need this to be a store-release (and rely on
@@ -2066,33 +2019,18 @@
     });
 
   // We have extra inhabitants if any element does. Use the field with the most.
-  unsigned extraInhabitantField = ~0u;
   unsigned extraInhabitantCount = 0;
   for (unsigned i = 0; i < numFields; ++i) {
-    if (!fieldTypes[i]->flags.hasExtraInhabitants())
-      continue;
     unsigned fieldExtraInhabitantCount =
-      fieldTypes[i]->getExtraInhabitantFlags().getNumExtraInhabitants();
+      fieldTypes[i]->getNumExtraInhabitants();
     if (fieldExtraInhabitantCount > extraInhabitantCount) {
-      extraInhabitantField = i;
       extraInhabitantCount = fieldExtraInhabitantCount;
     }
   }
-    
-  auto vwtable =
-    getMutableVWTableForInit(structType, layoutFlags,
-                             extraInhabitantCount > 0);
 
-  if (extraInhabitantCount > 0) {
-    layout.flags = layout.flags.withExtraInhabitants(true);
-    auto xiVWT = static_cast<ExtraInhabitantsValueWitnessTable*>(vwtable);
-    xiVWT->extraInhabitantFlags =
-      fieldTypes[extraInhabitantField]->getExtraInhabitantFlags();
+  auto vwtable = getMutableVWTableForInit(structType, layoutFlags);
 
-    // The compiler should already have initialized these.
-    assert(xiVWT->storeExtraInhabitant);
-    assert(xiVWT->getExtraInhabitantIndex);
-  }
+  layout.extraInhabitantCount = extraInhabitantCount;
 
   // Substitute in better value witnesses if we have them.
   installCommonValueWitnesses(layout, vwtable);
@@ -2878,7 +2816,7 @@
 /// A cache entry for existential metatype witness tables.
 class ExistentialMetatypeValueWitnessTableCacheEntry {
 public:
-  ExtraInhabitantsValueWitnessTable Data;
+  ValueWitnessTable Data;
 
   unsigned getNumWitnessTables() const {
     return (Data.size - sizeof(ExistentialMetatypeContainer))
@@ -2934,16 +2872,16 @@
 /// The uniquing structure for existential metatype type metadata.
 static SimpleGlobalCache<ExistentialMetatypeCacheEntry> ExistentialMetatypes;
 
-static const ExtraInhabitantsValueWitnessTable
+static const ValueWitnessTable
 ExistentialMetatypeValueWitnesses_1 =
   ValueWitnessTableForBox<ExistentialMetatypeBox<1>>::table;
-static const ExtraInhabitantsValueWitnessTable
+static const ValueWitnessTable
 ExistentialMetatypeValueWitnesses_2 =
   ValueWitnessTableForBox<ExistentialMetatypeBox<2>>::table;
 
 /// Instantiate a value witness table for an existential metatype
 /// container with the given number of witness table pointers.
-static const ExtraInhabitantsValueWitnessTable *
+static const ValueWitnessTable *
 getExistentialMetatypeValueWitnesses(unsigned numWitnessTables) {
   if (numWitnessTables == 0)
     return &getUnmanagedPointerPointerValueWitnesses();
@@ -2977,11 +2915,9 @@
     .withAlignment(Box::Container::getAlignment(numWitnessTables))
     .withPOD(true)
     .withBitwiseTakable(true)
-    .withInlineStorage(false)
-    .withExtraInhabitants(true);
+    .withInlineStorage(false);
   Data.stride = Box::Container::getStride(numWitnessTables);
-  Data.extraInhabitantFlags = ExtraInhabitantFlags()
-    .withNumExtraInhabitants(Witnesses::numExtraInhabitants);
+  Data.extraInhabitantCount = Witnesses::numExtraInhabitants;
 
   assert(getNumWitnessTables() == numWitnessTables);
 }
@@ -3073,7 +3009,7 @@
 
 class OpaqueExistentialValueWitnessTableCacheEntry {
 public:
-  ExtraInhabitantsValueWitnessTable Data;
+  ValueWitnessTable Data;
 
   OpaqueExistentialValueWitnessTableCacheEntry(unsigned numTables);
 
@@ -3100,7 +3036,7 @@
 
 class ClassExistentialValueWitnessTableCacheEntry {
 public:
-  ExtraInhabitantsValueWitnessTable Data;
+  ValueWitnessTable Data;
 
   ClassExistentialValueWitnessTableCacheEntry(unsigned numTables);
 
@@ -3130,10 +3066,10 @@
 /// The uniquing structure for existential type metadata.
 static SimpleGlobalCache<ExistentialCacheEntry> ExistentialTypes;
 
-static const ExtraInhabitantsValueWitnessTable
+static const ValueWitnessTable
 OpaqueExistentialValueWitnesses_0 =
   ValueWitnessTableForBox<OpaqueExistentialBox<0>>::table;
-static const ExtraInhabitantsValueWitnessTable
+static const ValueWitnessTable
 OpaqueExistentialValueWitnesses_1 =
   ValueWitnessTableForBox<OpaqueExistentialBox<1>>::table;
 
@@ -3201,22 +3137,16 @@
     .withAlignment(Box::Container::getAlignment(numWitnessTables))
     .withPOD(false)
     .withBitwiseTakable(true)
-    .withInlineStorage(false)
-    .withExtraInhabitants(true);
+    .withInlineStorage(false);
+  Data.extraInhabitantCount = Witnesses::numExtraInhabitants;
   Data.stride = Box::Container::getStride(numWitnessTables);
-  
-  // Extra inhabitant behavior does not change with the number of witnesses.
-  constexpr auto extraInhabitantFlags = Witnesses::extraInhabitantFlags;
-  Data.extraInhabitantFlags = extraInhabitantFlags;
-  Data.getExtraInhabitantIndex = Witnesses::getExtraInhabitantIndex;
-  Data.storeExtraInhabitant = Witnesses::storeExtraInhabitant;
 
   assert(getNumWitnessTables() == numWitnessTables);
 }
 
-static const ExtraInhabitantsValueWitnessTable ClassExistentialValueWitnesses_1 =
+static const ValueWitnessTable ClassExistentialValueWitnesses_1 =
   ValueWitnessTableForBox<ClassExistentialBox<1>>::table;
-static const ExtraInhabitantsValueWitnessTable ClassExistentialValueWitnesses_2 =
+static const ValueWitnessTable ClassExistentialValueWitnesses_2 =
   ValueWitnessTableForBox<ClassExistentialBox<2>>::table;
 
 /// The uniquing structure for class existential value witness tables.
@@ -3225,7 +3155,7 @@
 
 /// Instantiate a value witness table for a class-constrained existential
 /// container with the given number of witness table pointers.
-static const ExtraInhabitantsValueWitnessTable *
+static const ValueWitnessTable *
 getClassExistentialValueWitnesses(const Metadata *superclass,
                                   unsigned numWitnessTables) {
   // FIXME: If the superclass is not @objc, use native reference counting.
@@ -3266,11 +3196,9 @@
     .withAlignment(Box::Container::getAlignment(numWitnessTables))
     .withPOD(false)
     .withBitwiseTakable(true)
-    .withInlineStorage(false)
-    .withExtraInhabitants(true);
+    .withInlineStorage(false);
+  Data.extraInhabitantCount = Witnesses::numExtraInhabitants;
   Data.stride = Box::Container::getStride(numWitnessTables);
-  Data.extraInhabitantFlags = ExtraInhabitantFlags()
-    .withNumExtraInhabitants(Witnesses::numExtraInhabitants);
 
   assert(getNumWitnessTables() == numWitnessTables);
 }
diff --git a/stdlib/public/runtime/MetadataImpl.h b/stdlib/public/runtime/MetadataImpl.h
index b6677ff..29b63ae 100644
--- a/stdlib/public/runtime/MetadataImpl.h
+++ b/stdlib/public/runtime/MetadataImpl.h
@@ -71,8 +71,8 @@
 //   static T *assignWithCopy(T *dest, T *src);
 //   static T *assignWithTake(T *dest, T *src);
 //   // Only if numExtraInhabitants is non-zero:
-//   static void storeExtraInhabitant(T *dest, int index);
-//   static int getExtraInhabitantIndex(const T *src);
+//   static void storeExtraInhabitantTag(T *dest, unsigned index);
+//   static unsigned getExtraInhabitantTag(const T *src);
 // };
 
 /// A box class implemented in terms of C/C++ primitive operations.
@@ -178,12 +178,12 @@
   static constexpr unsigned numExtraInhabitants =
     swift_getHeapObjectExtraInhabitantCount();
 
-  static void storeExtraInhabitant(T *dest, int index) {
-    swift_storeHeapObjectExtraInhabitant((HeapObject**) dest, index);
+  static void storeExtraInhabitantTag(T *dest, unsigned tag) {
+    swift_storeHeapObjectExtraInhabitant((HeapObject**) dest, tag - 1);
   }
 
-  static int getExtraInhabitantIndex(const T *src) {
-    return swift_getHeapObjectExtraInhabitantIndex((HeapObject* const *) src);
+  static unsigned getExtraInhabitantTag(const T *src) {
+    return swift_getHeapObjectExtraInhabitantIndex((HeapObject* const *) src) +1;
   }
 };
 
@@ -233,13 +233,13 @@
   // disabled.
   static constexpr unsigned numExtraInhabitants = 1;
 
-  static void storeExtraInhabitant(HeapObject **dest, int index) {
-    assert(index == 0);
+  static void storeExtraInhabitant(HeapObject **dest, unsigned index) {
+    assert(index == 1);
     *dest = nullptr;
   }
 
-  static int getExtraInhabitantIndex(const HeapObject * const *src) {
-    return (*src == nullptr ? 0 : -1);
+  static unsigned getExtraInhabitantTag(const HeapObject * const *src) {
+    return (*src == nullptr ? 1 : 0);
   }
 #endif
 };
@@ -311,12 +311,12 @@
     : WeakRetainableBoxBase<ObjCUnownedRetainableBox, UnownedReference> {
 
   static constexpr unsigned numExtraInhabitants = 1;
-  static void storeExtraInhabitant(UnownedReference *dest, int index) {
-    assert(index == 0);
+  static void storeExtraInhabitantTag(UnownedReference *dest, unsigned index) {
+    assert(index == 1);
     dest->Value = nullptr;
   }
-  static int getExtraInhabitantIndex(const UnownedReference *src) {
-    return (src->Value == nullptr ? 0 : -1);
+  static unsigned getExtraInhabitantTag(const UnownedReference *src) {
+    return (src->Value == nullptr ? 1 : 0);
   }
 
   static void destroy(UnownedReference *ref) {
@@ -424,12 +424,12 @@
   static constexpr unsigned numExtraInhabitants =
     swift_getHeapObjectExtraInhabitantCount();
 
-  static void storeExtraInhabitant(void ***dest, int index) {
-    swift_storeHeapObjectExtraInhabitant((HeapObject**) dest, index);
+  static void storeExtraInhabitantTag(void ***dest, unsigned tag) {
+    swift_storeHeapObjectExtraInhabitant((HeapObject**) dest, tag - 1);
   }
 
-  static int getExtraInhabitantIndex(void ** const *src) {
-    return swift_getHeapObjectExtraInhabitantIndex((HeapObject* const *) src);
+  static unsigned getExtraInhabitantTag(void ** const *src) {
+    return swift_getHeapObjectExtraInhabitantIndex((HeapObject* const *) src)+1;
   }
 };
 
@@ -440,12 +440,13 @@
 struct RawPointerBox : NativeBox<void*> {
   static constexpr unsigned numExtraInhabitants = 1;
 
-  static void storeExtraInhabitant(void **dest, int index) {
+  static void storeExtraInhabitantTag(void **dest, unsigned tag) {
+    assert(tag == 1);
     *dest = nullptr;
   }
 
-  static int getExtraInhabitantIndex(void* const *src) {
-    return *src == nullptr ? 0 : -1;
+  static unsigned getExtraInhabitantTag(void* const *src) {
+    return *src == nullptr ? 1 : 0;
   }
 };
 
@@ -456,12 +457,12 @@
   static constexpr unsigned numExtraInhabitants =
     swift_getFunctionPointerExtraInhabitantCount();
 
-  static void storeExtraInhabitant(void **dest, int index) {
-    swift_storeFunctionPointerExtraInhabitant(dest, index);
+  static void storeExtraInhabitantTag(void **dest, unsigned tag) {
+    swift_storeFunctionPointerExtraInhabitant(dest, tag - 1);
   }
 
-  static int getExtraInhabitantIndex(void * const *src) {
-    return swift_getFunctionPointerExtraInhabitantIndex(src);
+  static unsigned getExtraInhabitantTag(void * const *src) {
+    return swift_getFunctionPointerExtraInhabitantIndex(src) + 1;
   }
 };
 
@@ -709,8 +710,8 @@
                                           unsigned numEmptyCases,
                                           const Metadata *self) {
     return getEnumTagSinglePayloadImpl(enumAddr, numEmptyCases, self, Size,
-                                       Impl::numExtraInhabitants,
-                                       Impl::getExtraInhabitantIndex);
+                                       Impl::extraInhabitantCount,
+                                       Impl::getExtraInhabitantTag);
   }
 
   static void storeEnumTagSinglePayload(OpaqueValue *enumAddr,
@@ -718,8 +719,8 @@
                                         unsigned numEmptyCases,
                                         const Metadata *self) {
     return storeEnumTagSinglePayloadImpl(enumAddr, whichCase, numEmptyCases,
-                                         self, Size, Impl::numExtraInhabitants,
-                                         Impl::storeExtraInhabitant);
+                                         self, Size, Impl::extraInhabitantCount,
+                                         Impl::storeExtraInhabitantTag);
   }
 };
 
@@ -768,16 +769,13 @@
   static constexpr size_t alignment = Box::alignment;
   static constexpr bool isPOD = Box::isPOD;
   static constexpr bool isBitwiseTakable = Box::isBitwiseTakable;
-  static constexpr unsigned numExtraInhabitants = Box::numExtraInhabitants;
-  static constexpr bool hasExtraInhabitants = (numExtraInhabitants != 0);
+  static constexpr unsigned extraInhabitantCount = Box::numExtraInhabitants;
+  static constexpr bool hasExtraInhabitants = (extraInhabitantCount != 0);
   static constexpr ValueWitnessFlags flags =
     ValueWitnessFlags().withAlignmentMask(alignment - 1)
                        .withInlineStorage(Base::isInline && isBitwiseTakable)
                        .withPOD(isPOD)
-                       .withBitwiseTakable(isBitwiseTakable)
-                       .withExtraInhabitants(hasExtraInhabitants);
-  static constexpr ExtraInhabitantFlags extraInhabitantFlags =
-    ExtraInhabitantFlags().withNumExtraInhabitants(numExtraInhabitants);
+                       .withBitwiseTakable(isBitwiseTakable);
 
   static void destroy(OpaqueValue *value, const Metadata *self) {
     return Box::destroy((typename Box::type*) value);
@@ -810,14 +808,17 @@
   // These should not get instantiated if the type doesn't have extra
   // inhabitants.
 
-  static void storeExtraInhabitant(OpaqueValue *dest, int index,
-                                   const Metadata *self) {
-    Box::storeExtraInhabitant((typename Box::type*) dest, index);
+  SWIFT_CC(swift)
+  static void storeExtraInhabitantTag(OpaqueValue *dest, unsigned tag,
+                                      unsigned xiCount, const Metadata *self) {
+    Box::storeExtraInhabitantTag((typename Box::type*) dest, tag);
   }
 
-  static int getExtraInhabitantIndex(const OpaqueValue *src,
-                                     const Metadata *self) {
-    return Box::getExtraInhabitantIndex((typename Box::type const *) src);
+  SWIFT_CC(swift)
+  static unsigned getExtraInhabitantTag(const OpaqueValue *src,
+                                        unsigned xiCount,
+                                        const Metadata *self) {
+    return Box::getExtraInhabitantTag((typename Box::type const *) src);
   }
 };
 
@@ -839,8 +840,6 @@
 
   static constexpr unsigned numExtraInhabitants = Box::numExtraInhabitants;
   static constexpr bool hasExtraInhabitants = (numExtraInhabitants != 0);
-  static constexpr ExtraInhabitantFlags extraInhabitantFlags =
-    ExtraInhabitantFlags().withNumExtraInhabitants(numExtraInhabitants);
 
   static void destroy(OpaqueValue *value, const Metadata *self) {
     return Box::destroy((typename Box::type*) value, self);
@@ -879,12 +878,11 @@
                                           const Metadata *self) {
     auto *payloadWitnesses = self->getValueWitnesses();
     auto size = payloadWitnesses->getSize();
-    auto EIVWT = dyn_cast<ExtraInhabitantsValueWitnessTable>(payloadWitnesses);
-    auto getExtraInhabitantIndex = EIVWT ? EIVWT->getExtraInhabitantIndex : nullptr;
+    auto numExtraInhabitants = payloadWitnesses->getNumExtraInhabitants();
 
     return getEnumTagSinglePayloadImpl(enumAddr, numEmptyCases, self, size,
                                        numExtraInhabitants,
-                                       getExtraInhabitantIndex);
+                                       getExtraInhabitantTag);
   }
 
   static void storeEnumTagSinglePayload(OpaqueValue *enumAddr,
@@ -894,34 +892,32 @@
     auto *payloadWitnesses = self->getValueWitnesses();
     auto size = payloadWitnesses->getSize();
     auto numExtraInhabitants = payloadWitnesses->getNumExtraInhabitants();
-    auto EIVWT = dyn_cast<ExtraInhabitantsValueWitnessTable>(payloadWitnesses);
-    auto storeExtraInhabitant = EIVWT ? EIVWT->storeExtraInhabitant : nullptr;
 
     storeEnumTagSinglePayloadImpl(enumAddr, whichCase, numEmptyCases, self,
                                   size, numExtraInhabitants,
-                                  storeExtraInhabitant);
+                                  storeExtraInhabitantTag);
   }
 
   // These should not get instantiated if the type doesn't have extra
   // inhabitants.
 
-  static void storeExtraInhabitant(OpaqueValue *dest, int index,
-                                   const Metadata *self) {
-    Box::storeExtraInhabitant((typename Box::type*) dest, index);
+  SWIFT_CC(swift)
+  static void storeExtraInhabitantTag(OpaqueValue *dest, unsigned tag,
+                                      unsigned xiCount, const Metadata *self) {
+    Box::storeExtraInhabitantTag((typename Box::type*) dest, tag);
   }
 
-  static int getExtraInhabitantIndex(const OpaqueValue *src,
-                                     const Metadata *self) {
-    return Box::getExtraInhabitantIndex((typename Box::type const *) src);
+  SWIFT_CC(swift)
+  static unsigned getExtraInhabitantTag(const OpaqueValue *src,
+                                        unsigned xiCount,
+                                        const Metadata *self) {
+    return Box::getExtraInhabitantTag((typename Box::type const *) src);
   }
 };
 
 /// A class which defines a ValueWitnessTable.
-template <class Witnesses,
-          bool HasExtraInhabitants = Witnesses::hasExtraInhabitants>
-struct ValueWitnessTableGenerator;
-
-template <class Witnesses> struct ValueWitnessTableGenerator<Witnesses, false> {
+template <class Witnesses>
+struct ValueWitnessTableGenerator {
   static constexpr const ValueWitnessTable table = {
 #define WANT_ONLY_REQUIRED_VALUE_WITNESSES
 #define VALUE_WITNESS(LOWER_ID, UPPER_ID) Witnesses::LOWER_ID,
@@ -929,20 +925,6 @@
   };
 };
 
-/// A class which defines an ExtraInhabitantsValueWitnessTable.
-template <class Witnesses> struct ValueWitnessTableGenerator<Witnesses, true> {
-  static constexpr const ExtraInhabitantsValueWitnessTable table = {
-    {
-#define WANT_ONLY_REQUIRED_VALUE_WITNESSES
-#define VALUE_WITNESS(LOWER_ID, UPPER_ID) Witnesses::LOWER_ID,
-#include "swift/ABI/ValueWitness.def"
-    },
-#define WANT_ONLY_EXTRA_INHABITANT_VALUE_WITNESSES
-#define VALUE_WITNESS(LOWER_ID, UPPER_ID) Witnesses::LOWER_ID,
-#include "swift/ABI/ValueWitness.def"
-  };
-};
-
 /// A convenient way to get the value witness table for a box class.
 template <class Box>
 using ValueWitnessTableForBox = ValueWitnessTableGenerator<ValueWitnesses<Box>>;
diff --git a/test/IRGen/builtins.swift b/test/IRGen/builtins.swift
index 68132b5..99b61b4 100644
--- a/test/IRGen/builtins.swift
+++ b/test/IRGen/builtins.swift
@@ -183,14 +183,13 @@
 
 // CHECK: define hidden {{.*}}void @"$s8builtins27generic_sizeof_alignof_testyyxlF"
 func generic_sizeof_alignof_test<T>(_: T) {
-  // CHECK:      [[T0:%.*]] = getelementptr inbounds i8*, i8** [[T:%.*]], i32 8
-  // CHECK-NEXT: [[T1:%.*]] = load i8*, i8** [[T0]]
-  // CHECK-NEXT: [[SIZE:%.*]] = ptrtoint i8* [[T1]] to i64
+  // CHECK:      [[T0:%.*]] = getelementptr inbounds %swift.vwtable, %swift.vwtable* [[T:%.*]], i32 0, i32 8
+  // CHECK-NEXT: [[SIZE:%.*]] = load i64, i64* [[T0]]
   // CHECK-NEXT: store i64 [[SIZE]], i64* [[S:%.*]]
   var s = Builtin.sizeof(T.self)
-  // CHECK: [[T0:%.*]] = getelementptr inbounds i8*, i8** [[T:%.*]], i32 9
-  // CHECK-NEXT: [[T1:%.*]] = load i8*, i8** [[T0]]
-  // CHECK-NEXT: [[T2:%.*]] = ptrtoint i8* [[T1]] to i64
+  // CHECK:      [[T0:%.*]] = getelementptr inbounds %swift.vwtable, %swift.vwtable* [[T:%.*]], i32 0, i32 10
+  // CHECK-NEXT: [[FLAGS:%.*]] = load i32, i32* [[T0]]
+  // CHECK-NEXT: [[T2:%.*]] = zext i32 [[FLAGS]] to i64
   // CHECK-NEXT: [[T3:%.*]] = and i64 [[T2]], 255
   // CHECK-NEXT: [[ALIGN:%.*]] = add i64 [[T3]], 1
   // CHECK-NEXT: store i64 [[ALIGN]], i64* [[A:%.*]]
@@ -199,9 +198,8 @@
 
 // CHECK: define hidden {{.*}}void @"$s8builtins21generic_strideof_testyyxlF"
 func generic_strideof_test<T>(_: T) {
-  // CHECK:      [[T0:%.*]] = getelementptr inbounds i8*, i8** [[T:%.*]], i32 10
-  // CHECK-NEXT: [[T1:%.*]] = load i8*, i8** [[T0]]
-  // CHECK-NEXT: [[STRIDE:%.*]] = ptrtoint i8* [[T1]] to i64
+  // CHECK:      [[T0:%.*]] = getelementptr inbounds %swift.vwtable, %swift.vwtable* [[T:%.*]], i32 9
+  // CHECK-NEXT: [[STRIDE:%.*]] = load i64, i64* [[T0]]
   // CHECK-NEXT: store i64 [[STRIDE]], i64* [[S:%.*]]
   var s = Builtin.strideof(T.self)
 }
@@ -681,11 +679,10 @@
 
 // CHECK-LABEL: define {{.*}} @{{.*}}generic_ispod_test
 func generic_ispod_test<T>(_: T) {
-  // CHECK:      [[T0:%.*]] = getelementptr inbounds i8*, i8** [[T:%.*]], i32 9
-  // CHECK-NEXT: [[T1:%.*]] = load i8*, i8** [[T0]]
-  // CHECK-NEXT: [[FLAGS:%.*]] = ptrtoint i8* [[T1]] to i64
-  // CHECK-NEXT: [[ISNOTPOD:%.*]] = and i64 [[FLAGS]], 65536
-  // CHECK-NEXT: [[ISPOD:%.*]] = icmp eq i64 [[ISNOTPOD]], 0
+  // CHECK:      [[T0:%.*]] = getelementptr inbounds %swift.vwtable, %swift.vwtable* [[T:%.*]], i32 10
+  // CHECK-NEXT: [[FLAGS:%.*]] = load i32, i32* [[T0]]
+  // CHECK-NEXT: [[ISNOTPOD:%.*]] = and i32 [[FLAGS]], 65536
+  // CHECK-NEXT: [[ISPOD:%.*]] = icmp eq i32 [[ISNOTPOD]], 0
   // CHECK-NEXT: store i1 [[ISPOD]], i1* [[S:%.*]]
   var s = Builtin.ispod(T.self)
 }
@@ -700,11 +697,10 @@
 
 // CHECK-LABEL: define {{.*}} @{{.*}}generic_isbitwisetakable_test
 func generic_isbitwisetakable_test<T>(_: T) {
-  // CHECK:      [[T0:%.*]] = getelementptr inbounds i8*, i8** [[T:%.*]], i32 9
-  // CHECK-NEXT: [[T1:%.*]] = load i8*, i8** [[T0]]
-  // CHECK-NEXT: [[FLAGS:%.*]] = ptrtoint i8* [[T1]] to i64
-  // CHECK-NEXT: [[ISNOTBITWISETAKABLE:%.*]] = and i64 [[FLAGS]], 1048576
-  // CHECK-NEXT: [[ISBITWISETAKABLE:%.*]] = icmp eq i64 [[ISNOTBITWISETAKABLE]], 0
+  // CHECK:      [[T0:%.*]] = getelementptr inbounds %swift.vwtable, %swift.vwtable* [[T:%.*]], i32 10
+  // CHECK-NEXT: [[FLAGS:%.*]] = load i32, i32* [[T0]]
+  // CHECK-NEXT: [[ISNOTBITWISETAKABLE:%.*]] = and i32 [[FLAGS]], 1048576
+  // CHECK-NEXT: [[ISBITWISETAKABLE:%.*]] = icmp eq i32 [[ISNOTBITWISETAKABLE]], 0
   // CHECK-NEXT: store i1 [[ISBITWISETAKABLE]], i1* [[S:%.*]]
   var s = Builtin.isbitwisetakable(T.self)
 }
diff --git a/test/IRGen/enum.sil b/test/IRGen/enum.sil
index 29eee07..5d756c2 100644
--- a/test/IRGen/enum.sil
+++ b/test/IRGen/enum.sil
@@ -1,7 +1,7 @@
 // #if directives don't work with SIL keywords, therefore please put ObjC tests
 // in `enum_objc.sil`.
-// RUN: %target-swift-frontend -assume-parsing-unqualified-ownership-sil %s -gnone -emit-ir -enable-objc-interop  | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize --check-prefix=CHECK-objc --check-prefix=CHECK-objc-%target-ptrsize --check-prefix=CHECK-objc-%target-ptrsize-simulator-%target-is-simulator
-// RUN: %target-swift-frontend -assume-parsing-unqualified-ownership-sil %s -gnone -emit-ir -disable-objc-interop | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize --check-prefix=CHECK-native --check-prefix=CHECK-native-%target-ptrsize
+// RUN: %target-swift-frontend -assume-parsing-unqualified-ownership-sil %s -gnone -emit-ir -enable-objc-interop  | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize --check-prefix=CHECK-objc --check-prefix=CHECK-objc-%target-ptrsize --check-prefix=CHECK-objc-%target-ptrsize-simulator-%target-is-simulator -DWORD=i%target-ptrsize
+// RUN: %target-swift-frontend -assume-parsing-unqualified-ownership-sil %s -gnone -emit-ir -disable-objc-interop | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize --check-prefix=CHECK-native --check-prefix=CHECK-native-%target-ptrsize -DWORD=i%target-ptrsize
 
 // REQUIRES: CPU=i386 || CPU=x86_64
 
@@ -104,13 +104,17 @@
 
 // -- Dynamic metadata template carries a value witness table pattern
 //    we fill in on instantiation.
-//    The witness table pattern includes extra inhabitant witness
-//    implementations which are used if the instance has extra inhabitants.
 //    FIXME: Strings should be unnamed_addr. rdar://problem/22674524
 // CHECK: @"$s4enum16DynamicSingletonOWV" =
-// CHECK-SAME:   i8* null
-// CHECK-SAME:   i8* bitcast (void (%swift.opaque*, i32, %swift.type*)* @"$s4enum16DynamicSingletonOwxs" to i8*)
-// CHECK-SAME:   i8* bitcast (i32 (%swift.opaque*, %swift.type*)* @"$s4enum16DynamicSingletonOwxg" to i8*)
+// CHECK-SAME:   [[WORD]] 0,
+// CHECK-SAME:   [[WORD]] 0,
+//   6291456 == 0x600000 (enum, incomplete)
+// CHECK-SAME:   i32 6291456,
+// CHECK-SAME:   i32 0,
+//   Enum witnesses.
+// CHECK-SAME:   i8* bitcast (i32 (%swift.opaque*, %swift.type*)* @"$s4enum16DynamicSingletonOwug" to i8*)
+// CHECK-SAME:   i8* bitcast (void (%swift.opaque*, %swift.type*)* @"$s4enum16DynamicSingletonOwup" to i8*)
+// CHECK-SAME:   i8* bitcast (void (%swift.opaque*, i32, %swift.type*)* @"$s4enum16DynamicSingletonOwui" to i8*)
 
 // CHECK: [[DYNAMICSINGLETON_NAME:@.*]] = private constant [17 x i8] c"DynamicSingleton\00"
 // CHECK: @"$s4enum16DynamicSingletonOMn" = hidden constant <{
@@ -129,62 +133,55 @@
 
 // CHECK: @"$s4enum16DynamicSingletonOMP" = internal constant <{ {{.*}} }> <{
 // CHECK-SAME:   @"$s4enum16DynamicSingletonOMi"
-// CHECK-SAME:   [17 x i8*]* @"$s4enum16DynamicSingletonOWV"
+// CHECK-SAME:   %swift.enum_vwtable* @"$s4enum16DynamicSingletonOWV"
 
 // -- No-payload enums have extra inhabitants in
 //    their value witness table.
-// CHECK: @"$s4enum10NoPayloadsOWV" = internal constant [17 x i8*] [
+// CHECK: @"$s4enum10NoPayloadsOWV" = internal constant %swift.enum_vwtable {
 // -- ...
 // -- size
-// CHECK-SAME:   i8* inttoptr ([[WORD:i32|i64]] 1 to i8*),
-// -- flags                 0x24_0000 - alignment 1, has extra inhabitants and enum witnesses
-// CHECK-SAME:   i8* inttoptr ([[WORD]] 2359296 to i8*),
+// CHECK-SAME:   [[WORD]] 1,
 // -- stride
-// CHECK-SAME:   i8* inttoptr ([[WORD]] 1 to i8*),
+// CHECK-SAME:   [[WORD]] 1,
+// -- flags (0x20_0000: alignment 1 and enum witnesses)
+// CHECK-SAME:   i32 2097152,
 // -- num extra inhabitants (256 - 3 valid states)
-// CHECK-SAME:   i8* inttoptr ([[WORD]] 253 to i8*)
-// -- storeExtraInhabitant
-// CHECK-SAME:   i8* bitcast (void (%swift.opaque*, i32, %swift.type*)* @"$s4enum10NoPayloadsOwxs" to i8*)
-// -- getExtraInhabitantIndex
-// CHECK-SAME:   i8* bitcast (i32 (%swift.opaque*, %swift.type*)* @"$s4enum10NoPayloadsOwxg" to i8*)
-// CHECK-SAME: ]
+// CHECK-SAME:   i32 253,
+// CHECK-SAME: }, align
 
 // -- Single-payload enums take unused extra inhabitants from their payload
 //    as their own.
-// CHECK: @"$s4enum19SinglePayloadNestedOWV" = internal constant [17 x i8*] [
+// CHECK: @"$s4enum19SinglePayloadNestedOWV" = internal constant %swift.enum_vwtable {
 // -- ...
 // -- size
-// CHECK-SAME:   i8* inttoptr ([[WORD]] 1 to i8*),
-// -- flags                 0x4_0000 - alignment 1, has extra inhabitants
-// CHECK-SAME:   i8* inttoptr ([[WORD]] 2359296 to i8*),
+// CHECK-SAME:   [[WORD]] 1,
 // -- stride
-// CHECK-SAME:   i8* inttoptr ([[WORD]] 1 to i8*),
+// CHECK-SAME:   [[WORD]] 1,
+// -- flags (0x20_0000: alignment 1 and enum witnesses)
+// CHECK-SAME:   i32 2097152,
 // -- num extra inhabitants (253 from payload - 3 empty cases)
-// CHECK-SAME:   i8* inttoptr ([[WORD]] 250 to i8*)
-// -- storeExtraInhabitant
-// CHECK-SAME:   i8* bitcast (void (%swift.opaque*, i32, %swift.type*)* @"$s4enum19SinglePayloadNestedOwxs" to i8*)
-// -- getExtraInhabitantIndex
-// CHECK-SAME:   i8* bitcast (i32 (%swift.opaque*, %swift.type*)* @"$s4enum19SinglePayloadNestedOwxg" to i8*)
-// CHECK-SAME: ]
+// CHECK-SAME:   i32 250,
+// CHECK-SAME: }
 
-// CHECK: @"$s4enum20DynamicSinglePayloadOWV" = internal constant [17 x i8*] [
-// CHECK-SAME:   i8* null
-// CHECK-SAME:   i8* bitcast (void (%swift.opaque*, i32, %swift.type*)* @"$s4enum20DynamicSinglePayloadOwxs" to i8*)
-// CHECK-SAME:   i8* bitcast (i32 (%swift.opaque*, %swift.type*)* @"$s4enum20DynamicSinglePayloadOwxg" to i8*)
+// CHECK: @"$s4enum20DynamicSinglePayloadOWV" = internal constant %swift.enum_vwtable {
+// -- flags (0x60_0000: alignment 1, incomplete, enum witnesses)
+// CHECK-SAME:   i32 6291456,
+// -- num extra inhabitants (253 from payload - 3 empty cases)
+// CHECK-SAME:   i32 0,
 
 // CHECK: @"$s4enum20DynamicSinglePayloadOMP" = internal constant <{ {{.*}} }> <{
 // CHECK-SAME:   @"$s4enum20DynamicSinglePayloadOMi"
-// CHECK-SAME:   [17 x i8*]* @"$s4enum20DynamicSinglePayloadOWV"
+// CHECK-SAME:   %swift.enum_vwtable* @"$s4enum20DynamicSinglePayloadOWV"
 
-// CHECK: @"$s4enum18MultiPayloadNestedOWV" = internal constant [17 x i8*] [
+// CHECK: @"$s4enum18MultiPayloadNestedOWV" = internal constant %swift.enum_vwtable {
 // -- size
-// CHECK-32-SAME:   i8* inttoptr ([[WORD]] 5 to i8*),
-// CHECK-64-SAME:   i8* inttoptr ([[WORD]] 9 to i8*),
-// -- flags                 0x250003 - alignment 4
-// CHECK-32-SAME:   i8* inttoptr ([[WORD]] {{2686979|2359299}} to i8*)
-// -- flags                 0x240007 - alignment 8, extra inhabitants
-// CHECK-64-SAME:   i8* inttoptr ([[WORD]] 2359303 to i8*)
-// CHECK-SAME: ]
+// CHECK-32-SAME:   [[WORD]] 5,
+// CHECK-64-SAME:   [[WORD]] 9,
+// -- flags (0x250003: alignment 4, enum)
+// -- flags (0x200007: alignment 8, enum)
+// CHECK-32-SAME:   i32 2097155,
+// CHECK-64-SAME:   i32 2097159,
+// CHECK-SAME: }
 
 enum Empty {}
 
@@ -2688,18 +2685,19 @@
 // CHECK:   [[T_LAYOUT:%.*]] = getelementptr inbounds i8*, i8** [[T_VWT]], i32 8
 // CHECK:   call void @swift_initEnumMetadataSinglePayload(%swift.type* [[METADATA]], [[WORD]] 0, i8** [[T_LAYOUT]], i32 3)
 
-// CHECK-64-LABEL: define internal void @"$s4enum17StructWithWeakVarVwxs"(%swift.opaque* noalias %dest, i32 %index, %swift.type* %StructWithWeakVar)
+// CHECK-64-LABEL: define internal void @"$s4enum17StructWithWeakVarVwst"(%swift.opaque* noalias %value, i32 %whichCase, i32 %numEmptyCases, %swift.type* %StructWithWeakVar)
 // -- TODO: some pointless masking here.
 // -- TODO: should use EnumPayload word-chunking.
-// CHECK-64:         %1 = zext i32 %index to i128
+// CHECK-64:         [[INDEX:%.*]] = sub i32 %whichCase, 1
+// CHECK-64:         [[T0:%.*]] = zext i32 [[INDEX]] to i128
 // --                             0xFFFF_FFFF_FFFF_FFFF
-// CHECK-64:         %2 = and i128 %1, 18446744073709551615
-// CHECK-64:         %3 = shl i128 %1, 3
+// CHECK-64:         [[T1:%.*]] = and i128 [[T0]], 18446744073709551615
+// CHECK-64:         [[T2:%.*]] = shl i128 [[T0]], 3
 // --                             0xFFFF_FFFF_FFFF_FFF8__0000_0000_0000_0000
-// CHECK-64:         %4 = and i128 %3, 1329227995784915725329854470603931648
-// CHECK-64:         %5 = or i128 %2, %4
+// CHECK-64:         [[T3:%.*]] = and i128 [[T2]], 1329227995784915725329854470603931648
+// CHECK-64:         [[T4:%.*]] = or i128 [[T1]], [[T3]]
 // --                             0x1__0000_0000_0000_0000
-// CHECK-64:         %6 = or i128 %5, 18446744073709551616
+// CHECK-64:         [[T5:%.*]] = or i128 [[T4]], 18446744073709551616
 
 // CHECK-LABEL: define internal i32 @"$s4enum40MultiPayloadLessThan32BitsWithEmptyCasesOwug"(%swift.opaque* noalias %value
 // CHECK:  [[VAL00:%.*]] = bitcast %swift.opaque* %value to %T4enum40MultiPayloadLessThan32BitsWithEmptyCasesO*
diff --git a/test/IRGen/enum_objc.sil b/test/IRGen/enum_objc.sil
index c2d044e..f82d428 100644
--- a/test/IRGen/enum_objc.sil
+++ b/test/IRGen/enum_objc.sil
@@ -127,6 +127,3 @@
 x:
   return undef : $()
 }
-
-// Weak existentials allow extra inhabitants if not @objc, therefore StructWithWeakVar must emit:
-// CHECK: define internal void @"$s9enum_objc17StructWithWeakVarVwxs"
diff --git a/test/IRGen/enum_resilience.swift b/test/IRGen/enum_resilience.swift
index 31f7697..2975d77 100644
--- a/test/IRGen/enum_resilience.swift
+++ b/test/IRGen/enum_resilience.swift
@@ -6,7 +6,7 @@
 // RUN: %target-swift-frontend -emit-ir -enable-resilience -module-name=resilient_enum -I %t %S/../Inputs/resilient_enum.swift | %FileCheck %t/enum_resilience.swift --check-prefix=ENUM_RES
 // RUN: %target-swift-frontend -emit-ir -module-name=resilient_enum -I %t %S/../Inputs/resilient_enum.swift | %FileCheck %t/enum_resilience.swift --check-prefix=ENUM_NOT_RES
 // RUN: %target-swift-frontend -emit-module -enable-resilience -emit-module-path=%t/resilient_enum.swiftmodule -module-name=resilient_enum -I %t %S/../Inputs/resilient_enum.swift
-// RUN: %target-swift-frontend -module-name enum_resilience -I %t -emit-ir -enable-resilience %s | %FileCheck %t/enum_resilience.swift -DINT=i%target-ptrsize
+// RUN: %target-swift-frontend -module-name enum_resilience -I %t -emit-ir -enable-resilience %s | %FileCheck %t/enum_resilience.swift --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize -DINT=i%target-ptrsize
 // RUN: %target-swift-frontend -module-name enum_resilience -I %t -emit-ir -enable-resilience -O %s
 
 import resilient_enum
@@ -133,7 +133,9 @@
 // CHECK-NEXT: [[VWT_ADDR:%.*]] = getelementptr inbounds i8**, i8*** [[METADATA_ADDR]], [[INT]] -1
 // CHECK-NEXT: [[VWT:%.*]] = load i8**, i8*** [[VWT_ADDR]]
 
-// CHECK-NEXT: [[WITNESS_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 16
+// CHECK-16-NEXT: [[WITNESS_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 16
+// CHECK-32-NEXT: [[WITNESS_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 14
+// CHECK-64-NEXT: [[WITNESS_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 13
 // CHECK-NEXT: [[WITNESS:%.*]] = load i8*, i8** [[WITNESS_ADDR]]
 // CHECK-NEXT: [[WITNESS_FN:%.*]] = bitcast i8* [[WITNESS]]
 // CHECK-NEXT: call void [[WITNESS_FN]](%swift.opaque* noalias %0, i32 [[TAG]], %swift.type* [[METADATA]])
@@ -162,7 +164,9 @@
 // CHECK-NEXT: [[VWT_ADDR2:%.*]] = getelementptr inbounds i8**, i8*** [[METADATA_ADDR2]], [[INT]] -1
 // CHECK-NEXT: [[VWT2:%.*]] = load i8**, i8*** [[VWT_ADDR2]]
 
-// CHECK-NEXT: [[WITNESS_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT2]], i32 16
+// CHECK-16-NEXT: [[WITNESS_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT2]], i32 16
+// CHECK-32-NEXT: [[WITNESS_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT2]], i32 14
+// CHECK-64-NEXT: [[WITNESS_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT2]], i32 13
 // CHECK-NEXT: [[WITNESS:%.*]] = load i8*, i8** [[WITNESS_ADDR]]
 // CHECK-NEXT: [[WITNESS_FN:%destructiveInjectEnumTag]] = bitcast i8* [[WITNESS]]
 // CHECK-NEXT: call void [[WITNESS_FN]](%swift.opaque* noalias %0, i32 [[TAG]], %swift.type* [[METADATA2]])
@@ -179,9 +183,9 @@
 // CHECK: [[VWT_ADDR:%.*]] = getelementptr inbounds i8**, i8*** [[METADATA_ADDR]], [[INT]] -1
 // CHECK: [[VWT:%.*]] = load i8**, i8*** [[VWT_ADDR]]
 
-// CHECK: [[WITNESS_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 8
-// CHECK: [[WITNESS:%.*]] = load i8*, i8** [[WITNESS_ADDR]]
-// CHECK: [[WITNESS_FOR_SIZE:%size]] = ptrtoint i8* [[WITNESS]]
+// CHECK: [[VWT_CAST:%.*]] = bitcast i8** [[VWT]] to %swift.vwtable*
+// CHECK: [[WITNESS_ADDR:%.*]] = getelementptr inbounds %swift.vwtable, %swift.vwtable* [[VWT_CAST]], i32 0, i32 8
+// CHECK: [[WITNESS_FOR_SIZE:%size]] = load [[INT]], [[INT]]* [[WITNESS_ADDR]]
 // CHECK: [[ALLOCA:%.*]] = alloca i8, {{.*}} [[WITNESS_FOR_SIZE]], align 16
 // CHECK: [[ALLOCA:%.*]] = alloca i8, {{.*}} [[WITNESS_FOR_SIZE]], align 16
 // CHECK: [[ENUM_STORAGE:%.*]] = bitcast i8* [[ALLOCA]] to %swift.opaque*
@@ -191,7 +195,9 @@
 // CHECK: [[WITNESS_FN:%initializeWithCopy]] = bitcast i8* [[WITNESS]]
 // CHECK: [[ENUM_COPY:%.*]] = call %swift.opaque* [[WITNESS_FN]](%swift.opaque* noalias [[ENUM_STORAGE]], %swift.opaque* noalias %0, %swift.type* [[METADATA]])
 
-// CHECK: [[WITNESS_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 14
+// CHECK-16-NEXT: [[WITNESS_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 14
+// CHECK-32-NEXT: [[WITNESS_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 12
+// CHECK-64-NEXT: [[WITNESS_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 11
 // CHECK: [[WITNESS:%.*]] = load i8*, i8** [[WITNESS_ADDR]]
 // CHECK: [[WITNESS_FN:%getEnumTag]] = bitcast i8* [[WITNESS]]
 // CHECK: [[TAG:%.*]] = call i32 [[WITNESS_FN]](%swift.opaque* noalias [[ENUM_STORAGE]], %swift.type* [[METADATA]])
diff --git a/test/IRGen/enum_value_semantics.sil b/test/IRGen/enum_value_semantics.sil
index 23bb584..027b094 100644
--- a/test/IRGen/enum_value_semantics.sil
+++ b/test/IRGen/enum_value_semantics.sil
@@ -95,7 +95,7 @@
 }
 
 
-// CHECK-LABEL: @"$s20enum_value_semantics20SinglePayloadTrivialOWV" = internal constant [17 x i8*] [
+// CHECK-LABEL: @"$s20enum_value_semantics20SinglePayloadTrivialOWV" = internal constant %swift.enum_vwtable {
 // CHECK:   i8* bitcast (i8* (i8*, i8*, %swift.type*)* @__swift_memcpy9_8 to i8*),
 // CHECK:   i8* bitcast (void (i8*, %swift.type*)* @__swift_noop_void_return to i8*),
 // CHECK:   i8* bitcast (i8* (i8*, i8*, %swift.type*)* @__swift_memcpy9_8 to i8*),
@@ -104,49 +104,45 @@
 // CHECK:   i8* bitcast (i8* (i8*, i8*, %swift.type*)* @__swift_memcpy9_8 to i8*),
 // CHECK:   i8* bitcast (i32 (%swift.opaque*, i32, %swift.type*)* @"$s20enum_value_semantics20SinglePayloadTrivialOwet" to i8*),
 // CHECK:   i8* bitcast (void (%swift.opaque*, i32, i32, %swift.type*)* @"$s20enum_value_semantics20SinglePayloadTrivialOwst" to i8*),
-// CHECK:   i8* inttoptr (i64 9 to i8*),
-// CHECK:   i8* inttoptr (i64 2097159 to i8*),
-// CHECK:   i8* inttoptr (i64 16 to i8*),
-// CHECK:   i8* null,
-// CHECK:   i8* null,
-// CHECK:   i8* null,
+// CHECK:   i64 9,
+// CHECK:   i64 16,
+// CHECK:   i32 2097159,
+// CHECK:   i32 0,
 // CHECK:   i8* bitcast (i32 (%swift.opaque*, %swift.type*)* @"$s20enum_value_semantics20SinglePayloadTrivialOwug" to i8*),
 // CHECK:   i8* bitcast (void (%swift.opaque*, %swift.type*)* @"$s20enum_value_semantics20SinglePayloadTrivialOwup" to i8*),
 // CHECK:   i8* bitcast (void (%swift.opaque*, i32, %swift.type*)* @"$s20enum_value_semantics20SinglePayloadTrivialOwui" to i8*)
-// CHECK: ]
+// CHECK: }
 
 
 // CHECK-LABEL: @"$s20enum_value_semantics20SinglePayloadTrivialOMf" =
 // CHECK-SAME:   internal constant <{ {{.*}} }> <{
-// CHECK-SAME:   i8** getelementptr inbounds ([17 x i8*], [17 x i8*]* @"$s20enum_value_semantics20SinglePayloadTrivialOWV", i32 0, i32 0),
+// CHECK-SAME:   i8** getelementptr inbounds (%swift.enum_vwtable, %swift.enum_vwtable* @"$s20enum_value_semantics20SinglePayloadTrivialOWV", i32 0, i32 0),
 // CHECK-SAME:   i64 513,
 // CHECK-SAME:   {{.*}}* @"$s20enum_value_semantics20SinglePayloadTrivialOMn"
 // CHECK-SAME: }>
 
 
-// CHECK-LABEL: @"$s20enum_value_semantics23SinglePayloadNontrivialOWV" = internal constant [17 x i8*] [
+// CHECK-LABEL: @"$s20enum_value_semantics23SinglePayloadNontrivialOWV" = internal constant %swift.enum_vwtable {
 // CHECK:   i8* bitcast (%swift.opaque* ([24 x i8]*, [24 x i8]*, %swift.type*)* @"$s20enum_value_semantics23SinglePayloadNontrivialOwCP" to i8*),
 // CHECK:   i8* bitcast (void (%swift.opaque*, %swift.type*)* @"$s20enum_value_semantics23SinglePayloadNontrivialOwxx" to i8*),
 // CHECK:   i8* bitcast (%swift.opaque* (%swift.opaque*, %swift.opaque*, %swift.type*)* @"$s20enum_value_semantics23SinglePayloadNontrivialOwcp" to i8*),
 // CHECK:   i8* bitcast (%swift.opaque* (%swift.opaque*, %swift.opaque*, %swift.type*)* @"$s20enum_value_semantics23SinglePayloadNontrivialOwca" to i8*),
 // CHECK:   i8* bitcast (i8* (i8*, i8*, %swift.type*)* @__swift_memcpy8_8 to i8*),
 // CHECK:   i8* bitcast (%swift.opaque* (%swift.opaque*, %swift.opaque*, %swift.type*)* @"$s20enum_value_semantics23SinglePayloadNontrivialOwta" to i8*),
-// CHECK:   i8* inttoptr (i64 8 to i8*),
-// --                         0x250007
-// CHECK:   i8* inttoptr (i64 2424839 to i8*),
-// CHECK:   i8* inttoptr (i64 8 to i8*),
+// CHECK:   i64 8,
+// CHECK:   i64 8,
+// --           0x210007
+// CHECK:   i32 2162695,
 // -- On Darwin, the first 4 GiB are unmapped: 0x7ffffffc
 // -- Otherwise, one can only assume the first page (4 KiB) is unmapped: 0xffd
-// CHECK-ios:       i8* inttoptr (i64 2147483644 to i8*)
-// CHECK-macosx:    i8* inttoptr (i64 2147483644 to i8*)
-// CHECK-watchos:   i8* inttoptr (i64 2147483644 to i8*)
-// CHECK-darwin:    i8* inttoptr (i64 2147483644 to i8*)
-// CHECK-objc-linux-gnu:   i8* inttoptr (i64 2045 to i8*)
-// CHECK-native-linux-gnu: i8* inttoptr (i64 4093 to i8*)
-// CHECK-objc-windows:     i8* inttoptr (i64 2045 to i8*)
-// CHECK-native-windows:   i8* inttoptr (i64 4093 to i8*)
-// CHECK:   i8* bitcast (void (%swift.opaque*, i32, %swift.type*)* @"$s20enum_value_semantics23SinglePayloadNontrivialOwxs" to i8*)
-// CHECK:   i8* bitcast (i32 (%swift.opaque*, %swift.type*)* @"$s20enum_value_semantics23SinglePayloadNontrivialOwxg" to i8*)
+// CHECK-ios:       i32 2147483644
+// CHECK-macosx:    i32 2147483644
+// CHECK-watchos:   i32 2147483644
+// CHECK-darwin:    i32 2147483644
+// CHECK-objc-linux-gnu:   i32 2045
+// CHECK-native-linux-gnu: i32 4093
+// CHECK-objc-windows:     i32 2045
+// CHECK-native-windows:   i32 4093
 // CHECK:   i8* bitcast (i32 (%swift.opaque*, %swift.type*)* @"$s20enum_value_semantics23SinglePayloadNontrivialOwug" to i8*),
 // CHECK:   i8* bitcast (void (%swift.opaque*, %swift.type*)* @"$s20enum_value_semantics23SinglePayloadNontrivialOwup" to i8*)
 // CHECK:   i8* bitcast (void (%swift.opaque*, i32, %swift.type*)* @"$s20enum_value_semantics23SinglePayloadNontrivialOwui" to i8*)
@@ -155,7 +151,7 @@
 
 // CHECK-LABEL: @"$s20enum_value_semantics23SinglePayloadNontrivialOMf" =
 // CHECK-SAME: internal constant <{ {{.*}} }> <{
-// CHECK-SAME:   i8** getelementptr inbounds ([17 x i8*], [17 x i8*]* @"$s20enum_value_semantics23SinglePayloadNontrivialOWV", i32 0, i32 0),
+// CHECK-SAME:   i8** getelementptr inbounds (%swift.enum_vwtable, %swift.enum_vwtable* @"$s20enum_value_semantics23SinglePayloadNontrivialOWV", i32 0, i32 0),
 // CHECK-SAME:   i64 513,
 // CHECK-SAME:   {{.*}}* @"$s20enum_value_semantics23SinglePayloadNontrivialOMn"
 // CHECK-SAME: }>
@@ -173,7 +169,7 @@
 //   Pattern flags.  0x4020_0000 == (MetadataKind::Enum << 21).
 // CHECK-SAME:    i32 1075838976,
 //   Value witness table.
-// CHECK-SAME:    i32 trunc (i64 sub (i64 ptrtoint ([17 x i8*]* @"$s20enum_value_semantics18GenericFixedLayoutOWV" to i64), i64 ptrtoint (i32* getelementptr inbounds (<{ i32, i32, i32, i32 }>, <{ i32, i32, i32, i32 }>* @"$s20enum_value_semantics18GenericFixedLayoutOMP", i32 0, i32 3) to i64)) to i32)
+// CHECK-SAME:    i32 trunc (i64 sub (i64 ptrtoint (%swift.enum_vwtable* @"$s20enum_value_semantics18GenericFixedLayoutOWV" to i64), i64 ptrtoint (i32* getelementptr inbounds (<{ i32, i32, i32, i32 }>, <{ i32, i32, i32, i32 }>* @"$s20enum_value_semantics18GenericFixedLayoutOMP", i32 0, i32 3) to i64)) to i32)
 // CHECK-SAME:  }>
 
 sil @single_payload_nontrivial_copy_destroy : $(@owned SinglePayloadNontrivial) -> () {
@@ -197,16 +193,6 @@
 //
 
 
-// -- NoPayload getExtraInhabitants
-// CHECK-LABEL: define internal i32 @"$s20enum_value_semantics9NoPayloadOwxg"
-// CHECK:      [[VALUE:%.*]] = load i8, i8* {{%.*}}, align 1
-// CHECK-NEXT: [[ZEXT:%.*]] = zext i8 [[VALUE]] to i32
-// CHECK-NEXT: [[SUB:%.*]] = sub i32 [[ZEXT]], 3
-// CHECK-NEXT: [[EXTRA:%.*]] = icmp slt i32 [[SUB]], 0
-// CHECK-NEXT: [[RES:%.*]] = select i1 [[EXTRA]], i32 -1, i32 [[SUB]]
-// CHECK-NEXT: ret i32 [[RES]]
-
-
 // -- NoPayload getEnumTag
 // CHECK-LABEL: define internal i32 @"$s20enum_value_semantics9NoPayloadOwug"
 // CHECK:      [[SELF:%.*]] = bitcast %swift.opaque* %value to %T20enum_value_semantics9NoPayloadO*
diff --git a/test/IRGen/existentials.sil b/test/IRGen/existentials.sil
index 3f48965..5298898 100644
--- a/test/IRGen/existentials.sil
+++ b/test/IRGen/existentials.sil
@@ -8,8 +8,8 @@
 protocol P {}
 
 // NonBitwiseTakableBit = 0x00100000. This struct is bitwise takable because
-// 0x70007 = 458759
-// CHECK: @"$s12existentials14BitwiseTakableVWV" = internal constant [14 x i8*] {{.*}} i8* inttoptr (i64 458759 to i8*)
+// 0x30007 = 196615
+// CHECK: @"$s12existentials14BitwiseTakableVWV" = internal constant %swift.vwtable {{.*}} i32 196615
 struct BitwiseTakable {
   var p: P
 }
diff --git a/test/IRGen/existentials_opaque_boxed.sil b/test/IRGen/existentials_opaque_boxed.sil
index 378ec3c..1d7f2c8 100644
--- a/test/IRGen/existentials_opaque_boxed.sil
+++ b/test/IRGen/existentials_opaque_boxed.sil
@@ -1,4 +1,4 @@
-// RUN: %target-swift-frontend -assume-parsing-unqualified-ownership-sil %s -emit-ir | %FileCheck %s -check-prefix=CHECK -check-prefix=CHECK-%target-ptrsize
+// RUN: %target-swift-frontend -assume-parsing-unqualified-ownership-sil %s -emit-ir | %FileCheck %s -check-prefix=CHECK -check-prefix=CHECK-%target-ptrsize -DINT=i%target-ptrsize
 
 sil_stage canonical
 
@@ -41,11 +41,11 @@
 // CHECK:  [[CAST:%.*]] = bitcast %swift.type* [[METATYPE]]
 // CHECK:  [[VWT_ADDR:%.*]] = getelementptr inbounds i8**, i8*** [[CAST]], {{(i64|i32)}} -1
 // CHECK:  [[VWT:%.*]] = load i8**, i8*** [[VWT_ADDR]]
-// CHECK:  [[FLAG_WITNESS_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 9
-// CHECK:  [[FLAG_WITNESS:%.*]] = load i8*, i8** [[FLAG_WITNESS_ADDR]]
-// CHECK:  [[FLAGS:%.*]] = ptrtoint i8* [[FLAG_WITNESS]]
-// CHECK:  [[ISNOTINLINE:%.*]] = and {{(i64|i32)}} [[FLAGS]], 131072
-// CHECK:  [[ISINLINE:%.*]] = icmp eq {{(i64|i32)}} [[ISNOTINLINE]], 0
+// CHECK:  [[VWT_CAST:%.*]] = bitcast i8** [[VWT]] to %swift.vwtable*
+// CHECK:  [[FLAGS_ADDR:%.*]] = getelementptr inbounds %swift.vwtable, %swift.vwtable* [[VWT_CAST]], i32 0, i32 10
+// CHECK:  [[FLAGS:%.*]] = load i32, i32* [[FLAGS_ADDR]]
+// CHECK:  [[ISNOTINLINE:%.*]] = and i32 [[FLAGS]], 131072
+// CHECK:  [[ISINLINE:%.*]] = icmp eq i32 [[ISNOTINLINE]], 0
 // CHECK:  [[EXISTENTIAL_BUFFER:%.*]] = getelementptr inbounds %T25existentials_opaque_boxed11ExistentialP, %T25existentials_opaque_boxed11ExistentialP* %0, i32 0, i32 0
 // CHECK:  [[EXISTENTIAL_BUFFER_OPAQUE:%.*]] = bitcast [{{(24|12)}} x i8]* [[EXISTENTIAL_BUFFER]] to %swift.opaque*
 // CHECK:  br i1 [[ISINLINE]], label %done, label %allocateBox
@@ -115,11 +115,11 @@
 // CHECK:   [[CAST:%.*]] = bitcast %swift.type* [[META]] to i8***
 // CHECK:   [[VWT_ADDR:%.*]] = getelementptr inbounds i8**, i8*** %3, {{(i64|i32)}} -1
 // CHECK:   [[VWT:%.*]] = load i8**, i8*** [[VWT_ADDR]]
-// CHECK:   [[VW_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 9
-// CHECK:   [[VW:%.*]] = load i8*, i8** [[VW_ADDR]]
-// CHECK:   [[FLAGS:%.*]] = ptrtoint i8* [[VW]] to {{(i64|i32)}}
-// CHECK:   [[MASKED:%.*]] = and {{(i64|i32)}} [[FLAGS]], 131072
-// CHECK:   [[ISINLINE:%.*]] = icmp eq {{(i64|i32)}} [[MASKED]], 0
+// CHECK:   [[VWT_CAST:%.*]] = bitcast i8** [[VWT]] to %swift.vwtable*
+// CHECK:   [[FLAGS_ADDR:%.*]] = getelementptr inbounds %swift.vwtable, %swift.vwtable* [[VWT_CAST]], i32 0, i32 10
+// CHECK:   [[FLAGS:%.*]] = load i32, i32* [[FLAGS_ADDR]]
+// CHECK:   [[ISNOTINLINE:%.*]] = and i32 [[FLAGS]], 131072
+// CHECK:   [[ISINLINE:%.*]] = icmp eq i32 [[ISNOTINLINE]], 0
 // CHECK:   br i1 [[ISINLINE]], label %done, label %deallocateBox
 
 // CHECK: done:
@@ -132,10 +132,14 @@
 // CHECK:   [[CAST:%.*]] = bitcast %swift.type* [[META]] to i8***
 // CHECK:   [[VWT_ADDR2:%.*]] = getelementptr inbounds i8**, i8*** [[CAST]], {{(i64|i32)}} -1
 // CHECK:   [[VWT2:%.*]] = load i8**, i8*** [[VWT_ADDR2]]
-// CHECK:   [[VW_ADDR2:%.*]] = getelementptr inbounds i8*, i8** [[VWT2]], i32 8
-// CHECK:   [[VW2:%.*]] = load i8*, i8** [[VW_ADDR2]]
-// CHECK:   [[SIZE:%.*]] = ptrtoint i8* [[VW2]] to {{(i64|i32)}}
-// CHECK:   [[ALIGNMASK:%.*]] = and {{(i64|i32)}} [[FLAGS]], 255
+// CHECK:   [[VWT2_CAST:%.*]] = bitcast i8** [[VWT2]] to %swift.vwtable*
+// CHECK:   [[SIZE2_ADDR:%.*]] = getelementptr inbounds %swift.vwtable, %swift.vwtable* [[VWT2_CAST]], i32 0, i32 8
+// CHECK:   [[SIZE:%.*]] = load [[INT]], [[INT]]* [[SIZE2_ADDR]]
+// CHECK-64:[[T0:%.*]] = zext i32 [[FLAGS]] to i64
+// CHECK-64:[[ALIGNMASK:%.*]] = and i64 [[T0]], 255
+// CHECK-32:[[ALIGNMASK:%.*]] = and i32 [[FLAGS]], 255
+// CHECK-16:[[T0:%.*]] = trunc i32 [[FLAGS]] to i16
+// CHECK-16:[[ALIGNMASK:%.*]] = and i16 [[T0]], 255
 // CHECK:   [[HEADERSIZEPLUSALIGN:%.*]] = add {{(i64 16|i32 8)}}, [[ALIGNMASK]]
 // CHECK:   [[NOTALIGNMASK:%.*]] = xor {{(i64|i32)}} [[ALIGNMASK]], -1
 // CHECK:   [[ALIGNEDSTART:%.*]] = and {{(i64|i32)}} [[HEADERSIZEPLUSALIGN]], [[NOTALIGNMASK]]
@@ -164,11 +168,11 @@
 // CHECK:   [[CAST:%.*]] = bitcast %swift.type* %1 to i8***
 // CHECK:   [[VWT_ADDR:%.*]] = getelementptr inbounds i8**, i8*** [[CAST]], {{(i64|i32)}} -1
 // CHECK:   [[VWT:%.*]] = load i8**, i8*** [[VWT_ADDR]]
-// CHECK:   [[VW_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 9
-// CHECK:   [[VW:%.*]] = load i8*, i8** [[VW_ADDR]]
-// CHECK:   [[FLAGS:%.*]] = ptrtoint i8* [[VW]] to {{(i64|i32)}}
-// CHECK:   [[ISNOTINLINE:%.*]] = and {{(i64|i32)}} [[FLAGS]], 131072
-// CHECK:   [[ISINLINE:%.*]] = icmp eq {{(i64|i32)}} [[ISNOTINLINE]], 0
+// CHECK:   [[VWT_CAST:%.*]] = bitcast i8** [[VWT]] to %swift.vwtable*
+// CHECK:   [[FLAGS_ADDR:%.*]] = getelementptr inbounds %swift.vwtable, %swift.vwtable* [[VWT_CAST]], i32 0, i32 10
+// CHECK:   [[FLAGS:%.*]] = load i32, i32* [[FLAGS_ADDR]]
+// CHECK:   [[ISNOTINLINE:%.*]] = and i32 [[FLAGS]], 131072
+// CHECK:   [[ISINLINE:%.*]] = icmp eq i32 [[ISNOTINLINE]], 0
 // CHECK:   [[VALUEADDRINLINE:%.*]] = bitcast [{{(24|12)}} x i8]* %0 to %swift.opaque*
 // CHECK:   br i1 [[ISINLINE]], label %done, label %boxed
 //
@@ -178,7 +182,11 @@
 // CHECK: boxed:
 // CHECK:   [[REFADDR:%.*]] = bitcast [{{(24|12)}} x i8]* %0 to %swift.refcounted**
 // CHECK:   [[REF:%.*]] = load %swift.refcounted*, %swift.refcounted** [[REFADDR]]
-// CHECK:   [[ALIGNMASK:%.*]] = and {{(i64|i32)}} [[FLAGS]], 255
+// CHECK-64:[[T0:%.*]] = zext i32 [[FLAGS]] to i64
+// CHECK-64:[[ALIGNMASK:%.*]] = and i64 [[T0]], 255
+// CHECK-32:[[ALIGNMASK:%.*]] = and i32 [[FLAGS]], 255
+// CHECK-16:[[T0:%.*]] = trunc i32 [[FLAGS]] to i16
+// CHECK-16:[[ALIGNMASK:%.*]] = and i16 [[T0]], 255
 // CHECK:   [[HEADERSIZEPLUSALIGN:%.*]] = add {{(i64 16|i32 8)}}, [[ALIGNMASK]]
 // CHECK:   [[NOTALIGNMASK:%.*]] = xor {{(i64|i32)}} [[ALIGNMASK]], -1
 // CHECK:   [[ALIGNEDSTART:%.*]] = and {{(i64|i32)}} [[HEADERSIZEPLUSALIGN]], [[NOTALIGNMASK]]
@@ -207,11 +215,11 @@
 // CHECK:   [[CAST:%.*]] = bitcast %swift.type* %1 to i8***
 // CHECK:   [[VWT_ADDR:%.*]] = getelementptr inbounds i8**, i8*** [[CAST]], {{(i64|i32)}} -1
 // CHECK:   [[VWT:%.*]] = load i8**, i8*** [[VWT_ADDR]]
-// CHECK:   [[VW_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 9
-// CHECK:   [[VW:%.*]] = load i8*, i8** [[VW_ADDR]]
-// CHECK:   [[FLAGS:%.*]] = ptrtoint i8* [[VW]] to {{(i64|i32)}}
-// CHECK:   [[ISNOTINLINE:%.*]] = and {{(i64|i32)}} [[FLAGS]], 131072
-// CHECK:   [[ISINLINE:%.*]] = icmp eq {{(i64|i32)}} [[ISNOTINLINE]], 0
+// CHECK:   [[VWT_CAST:%.*]] = bitcast i8** [[VWT]] to %swift.vwtable*
+// CHECK:   [[FLAGS_ADDR:%.*]] = getelementptr inbounds %swift.vwtable, %swift.vwtable* [[VWT_CAST]], i32 0, i32 10
+// CHECK:   [[FLAGS:%.*]] = load i32, i32* [[FLAGS_ADDR]]
+// CHECK:   [[ISNOTINLINE:%.*]] = and i32 [[FLAGS]], 131072
+// CHECK:   [[ISINLINE:%.*]] = icmp eq i32 [[ISNOTINLINE]], 0
 // CHECK:   [[VALUEADDRINLINE:%.*]] = bitcast [{{(24|12)}} x i8]* %0 to %swift.opaque*
 // CHECK:   br i1 [[ISINLINE]], label %done, label %boxed
 //
@@ -219,7 +227,11 @@
 // CHECK:   ret %swift.opaque* [[VALUEADDRINLINE]]
 
 // CHECK: boxed:
-// CHECK:  [[ALIGNMASK:%.*]] = and {{(i64|i32)}} [[FLAGS]], 255
+// CHECK-64:[[T0:%.*]] = zext i32 [[FLAGS]] to i64
+// CHECK-64:[[ALIGNMASK:%.*]] = and i64 [[T0]], 255
+// CHECK-32:[[ALIGNMASK:%.*]] = and i32 [[FLAGS]], 255
+// CHECK-16:[[T0:%.*]] = trunc i32 [[FLAGS]] to i16
+// CHECK-16:[[ALIGNMASK:%.*]] = and i16 [[T0]], 255
 // CHECK:  [[OPAQUE_ADDR:%.*]] = bitcast [{{(24|12)}} x i8]* %0 to %swift.opaque*
 // CHECK:  [[REFANDADDR:%.*]] = call swiftcc { %swift.refcounted*, %swift.opaque* } @swift_makeBoxUnique(%swift.opaque* [[OPAQUE_ADDR]], %swift.type* %1, {{(i64|i32)}} [[ALIGNMASK]])
 // CHECK:  [[REF:%.*]] = extractvalue { %swift.refcounted*, %swift.opaque* } [[REFANDADDR]], 0
@@ -244,11 +256,11 @@
 // CHECK:  [[CAST:%.*]] = bitcast %swift.type* [[METADATA]] to i8***
 // CHECK:  [[VWT_ADDR:%.*]] = getelementptr inbounds i8**, i8*** [[CAST]], {{(i64|i32)}} -1
 // CHECK:  [[VWT:%.*]] = load i8**, i8*** [[VWT_ADDR]]
-// CHECK:  [[VW_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 9
-// CHECK:  [[VW:%.*]] = load i8*, i8** [[VW_ADDR]]
-// CHECK:  [[FLAGS:%.*]] = ptrtoint i8* [[VW]] to {{(i64|i32)}}
-// CHECK:  [[ISNOTINLINE:%.*]] = and {{(i64|i32)}} [[FLAGS]], 131072
-// CHECK:  [[ISINLINE:%.*]] = icmp eq {{(i64|i32)}} [[ISNOTINLINE]], 0
+// CHECK:  [[VWT_CAST:%.*]] = bitcast i8** [[VWT]] to %swift.vwtable*
+// CHECK:  [[FLAGS_ADDR:%.*]] = getelementptr inbounds %swift.vwtable, %swift.vwtable* [[VWT_CAST]], i32 0, i32 10
+// CHECK:  [[FLAGS:%.*]] = load i32, i32* [[FLAGS_ADDR]]
+// CHECK:  [[ISNOTINLINE:%.*]] = and i32 [[FLAGS]], 131072
+// CHECK:  [[ISINLINE:%.*]] = icmp eq i32 [[ISNOTINLINE]], 0
 // CHECK:  br i1 [[ISINLINE]], label %inline, label %outline
 //
 // CHECK: inline:
@@ -301,11 +313,11 @@
 // CHECK:   [[CAST:%.*]] = bitcast %swift.type* [[DEST_TYPE]] to i8***
 // CHECK:   [[VWT_ADDR:%.*]] = getelementptr inbounds i8**, i8*** [[CAST]], {{(i64|i32)}} -1
 // CHECK:   [[VWT:%.*]] = load i8**, i8*** [[VWT_ADDR]]
-// CHECK:   [[VW_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 9
-// CHECK:   [[VW:%.*]] = load i8*, i8** [[VW_ADDR]]
-// CHECK:   [[FLAGS:%.*]] = ptrtoint i8* [[VW]] to {{(i64|i32)}}
-// CHECK:   [[MASKED:%.*]] = and {{(i64|i32)}} [[FLAGS]], 131072
-// CHECK:   [[ISINLINE:%.*]] = icmp eq {{(i64|i32)}} [[MASKED]], 0
+// CHECK:   [[VWT_CAST:%.*]] = bitcast i8** [[VWT]] to %swift.vwtable*
+// CHECK:   [[FLAGS_ADDR:%.*]] = getelementptr inbounds %swift.vwtable, %swift.vwtable* [[VWT_CAST]], i32 0, i32 10
+// CHECK:   [[FLAGS:%.*]] = load i32, i32* [[FLAGS_ADDR]]
+// CHECK:   [[ISNOTINLINE:%.*]] = and i32 [[FLAGS]], 131072
+// CHECK:   [[ISINLINE:%.*]] = icmp eq i32 [[ISNOTINLINE]], 0
 // CHECK:   br i1 [[ISINLINE]], label %match-inline, label %match-outline
 //
 // CHECK: match-inline:
@@ -339,19 +351,19 @@
 // CHECK:   [[CAST:%.*]] = bitcast %swift.type* [[DEST_TYPE]] to i8***
 // CHECK:   [[DEST_VWT_ADDR:%.*]] = getelementptr inbounds i8**, i8*** [[CAST]], {{(i64|i32)}} -1
 // CHECK:   [[DEST_VWT:%.*]] = load i8**, i8*** [[DEST_VWT_ADDR]]
-// CHECK:   [[DEST_VW_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[DEST_VWT]], i32 9
-// CHECK:   [[DEST_VW:%.*]] = load i8*, i8** [[DEST_VW_ADDR]]
-// CHECK:   [[DEST_FLAGS:%.*]] = ptrtoint i8* [[DEST_VW]] to {{(i64|i32)}}
-// CHECK:   [[DEST_ISNOTINLINE:%.*]] = and {{(i64|i32)}} [[DEST_FLAGS]], 131072
-// CHECK:   [[DEST_ISINLINE:%.*]] = icmp eq {{(i64|i32)}} [[DEST_ISNOTINLINE]], 0
+// CHECK:   [[DEST_VWT_CAST:%.*]] = bitcast i8** [[DEST_VWT]] to %swift.vwtable*
+// CHECK:   [[DEST_FLAGS_ADDR:%.*]] = getelementptr inbounds %swift.vwtable, %swift.vwtable* [[DEST_VWT_CAST]], i32 0, i32 10
+// CHECK:   [[DEST_FLAGS:%.*]] = load i32, i32* [[DEST_FLAGS_ADDR]]
+// CHECK:   [[DEST_ISNOTINLINE:%.*]] = and i32 [[DEST_FLAGS]], 131072
+// CHECK:   [[DEST_ISINLINE:%.*]] = icmp eq i32 [[DEST_ISNOTINLINE]], 0
 // CHECK:   [[CAST:%.*]] = bitcast %swift.type* [[SRC_TYPE]] to i8***
 // CHECK:   [[SRC_VWT_ADDR:%.*]] = getelementptr inbounds i8**, i8*** [[CAST]], {{(i64|i32)}} -1
 // CHECK:   [[SRC_VWT:%.*]] = load i8**, i8*** [[SRC_VWT_ADDR]]
-// CHECK:   [[SRC_VW_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[SRC_VWT]], i32 9
-// CHECK:   [[SRC_VW:%.*]] = load i8*, i8** [[SRC_VW_ADDR]]
-// CHECK:   [[SRC_FLAGS:%.*]] = ptrtoint i8* [[SRC_VW]] to {{(i64|i32)}}
-// CHECK:   [[SRC_ISNOTINLINE:%.*]] = and {{(i64|i32)}} [[SRC_FLAGS]], 131072
-// CHECK:   [[SRC_ISINLINE:%.*]] = icmp eq {{(i64|i32)}} [[SRC_ISNOTINLINE]], 0
+// CHECK:   [[SRC_VWT_CAST:%.*]] = bitcast i8** [[SRC_VWT]] to %swift.vwtable*
+// CHECK:   [[SRC_FLAGS_ADDR:%.*]] = getelementptr inbounds %swift.vwtable, %swift.vwtable* [[SRC_VWT_CAST]], i32 0, i32 10
+// CHECK:   [[SRC_FLAGS:%.*]] = load i32, i32* [[SRC_FLAGS_ADDR]]
+// CHECK:   [[SRC_ISNOTINLINE:%.*]] = and i32 [[SRC_FLAGS]], 131072
+// CHECK:   [[SRC_ISINLINE:%.*]] = icmp eq i32 [[SRC_ISNOTINLINE]], 0
 // CHECK:   br i1 [[DEST_ISINLINE]], label %dest-inline, label %dest-outline
 //
 // CHECK: dest-inline:
diff --git a/test/IRGen/generic_casts.swift b/test/IRGen/generic_casts.swift
index cafedc0..ed100e7 100644
--- a/test/IRGen/generic_casts.swift
+++ b/test/IRGen/generic_casts.swift
@@ -38,9 +38,9 @@
 	// CHECK: [[TYPE_ADDR:%.*]] = bitcast %swift.type* %T to i8***
   // CHECK: [[VWT_ADDR:%.*]] = getelementptr inbounds i8**, i8*** [[TYPE_ADDR]], i64 -1
   // CHECK: [[VWT:%.*]] = load i8**, i8*** [[VWT_ADDR]]
-  // CHECK: [[SIZE_WITNESS_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 8
-  // CHECK: [[SIZE_WITNESS:%.*]] = load i8*, i8** [[SIZE_WITNESS_ADDR]]
-  // CHECK: [[SIZE:%.*]] = ptrtoint i8* [[SIZE_WITNESS]]
+  // CHECK: [[VWT_CAST:%.*]] = bitcast i8** [[VWT]] to %swift.vwtable*
+  // CHECK: [[SIZE_ADDR:%.*]] = getelementptr inbounds %swift.vwtable, %swift.vwtable* [[VWT_CAST]], i32 0, i32 8
+  // CHECK: [[SIZE:%.*]] = load i64, i64* [[SIZE_ADDR]]
   // CHECK: [[T_ALLOCA:%.*]] = alloca i8, {{.*}} [[SIZE]], align 16
   // CHECK: [[T_TMP:%.*]] = bitcast i8* [[T_ALLOCA]] to %swift.opaque*
   // CHECK: [[TEMP:%.*]] = call %swift.opaque* {{.*}}(%swift.opaque* noalias [[T_TMP]], %swift.opaque* noalias %0, %swift.type* %T)
diff --git a/test/IRGen/generic_structs.sil b/test/IRGen/generic_structs.sil
index 1ce6ed2..602dc61 100644
--- a/test/IRGen/generic_structs.sil
+++ b/test/IRGen/generic_structs.sil
@@ -28,12 +28,11 @@
 // CHECK: @"$s15generic_structs13SingleDynamicVWV" = internal constant
 // CHECK-SAME:   i8* bitcast (%swift.opaque* ([24 x i8]*, [24 x i8]*, %swift.type*)* @"$s15generic_structs13SingleDynamicVwCP" to i8*),
 // -- ...
-// -- placeholder for size, flags, stride
-// CHECK-SAME:   i8* null, i8* inttoptr (i64 4194304 to i8*), i8* null
-// -- extra inhabitants
-// CHECK-SAME:   i8* null,
-// CHECK-SAME:   i8* bitcast (void (%swift.opaque*, i32, %swift.type*)* @"$s15generic_structs13SingleDynamicVwxs" to i8*),
-// CHECK-SAME:   i8* bitcast (i32 (%swift.opaque*, %swift.type*)* @"$s15generic_structs13SingleDynamicVwxg" to i8*)]
+// -- placeholder for size, stride, flags
+// CHECK-SAME:   i64 0,
+// CHECK-SAME:   i64 0,
+// CHECK-SAME:   i32 4194304,
+// CHECK-SAME:   i32 0 }
 
 //    FIXME: Strings should be unnamed_addr. rdar://problem/22674524
 // CHECK: [[SINGLEDYNAMIC_NAME:@.*]] = private constant [14 x i8] c"SingleDynamic\00"
diff --git a/test/IRGen/generic_tuples.swift b/test/IRGen/generic_tuples.swift
index f001ed8..b00c140 100644
--- a/test/IRGen/generic_tuples.swift
+++ b/test/IRGen/generic_tuples.swift
@@ -18,9 +18,9 @@
 // CHECK: [[TYPE_ADDR:%.*]] = bitcast %swift.type* %T to i8***
 // CHECK: [[VWT_ADDR:%.*]] = getelementptr inbounds i8**, i8*** [[TYPE_ADDR]], i64 -1
 // CHECK: [[VWT:%.*]] = load i8**, i8*** [[VWT_ADDR]]
-// CHECK: [[SIZE_WITNESS_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 8
-// CHECK: [[SIZE_WITNESS:%.*]] = load i8*, i8** [[SIZE_WITNESS_ADDR]]
-// CHECK: [[SIZE:%.*]] = ptrtoint i8* [[SIZE_WITNESS]]
+// CHECK: [[VWT_CAST:%.*]] = bitcast i8** [[VWT]] to %swift.vwtable*
+// CHECK: [[SIZE_ADDR:%.*]] = getelementptr inbounds %swift.vwtable, %swift.vwtable* [[VWT_CAST]], i32 0, i32 8
+// CHECK: [[SIZE:%.*]] = load i64, i64* [[SIZE_ADDR]]
 // CHECK: [[X_ALLOCA:%.*]] = alloca i8, {{.*}} [[SIZE]], align 16
 // CHECK: [[X_TMP:%.*]] = bitcast i8* [[X_ALLOCA]] to %swift.opaque*
 // Debug info shadow copy.
diff --git a/test/IRGen/global_resilience.sil b/test/IRGen/global_resilience.sil
index 800c56f..c73f154 100644
--- a/test/IRGen/global_resilience.sil
+++ b/test/IRGen/global_resilience.sil
@@ -128,21 +128,21 @@
 // CHECK:   [[CAST:%.*]] = bitcast %swift.type* %0 to i8***
 // CHECK:   [[VWT_ADDR:%.*]] = getelementptr inbounds i8**, i8*** [[CAST]], {{.*}} -1
 // CHECK:   [[VWT:%.*]] = load i8**, i8*** [[VWT_ADDR]]
-// CHECK:   [[FLAGS_ADDR:%.*]] = getelementptr inbounds i8*, i8** %.valueWitnesses, i32 9
-// CHECK:   [[FLAGSWITNESS:%.*]] = load i8*, i8** [[FLAGS_ADDR]]
-// CHECK:   [[FLAGS:%.*]] = ptrtoint i8* [[FLAGSWITNESS]] to i{{.*}}
-// CHECK:   [[ISNOTINLINE:%.*]] = and {{.*}} [[FLAGS]], 131072
-// CHECK:   [[ISINLINE:%.*]] = icmp eq {{.*}} [[ISNOTINLINE]], 0
+// CHECK:   [[VWT_CAST:%.*]] = bitcast i8** [[VWT]] to %swift.vwtable*
+// CHECK:   [[FLAGS_ADDR:%.*]] = getelementptr inbounds %swift.vwtable, %swift.vwtable* [[VWT_CAST]], i32 0, i32 10
+// CHECK:   [[FLAGS:%.*]] = load i32, i32* [[FLAGS_ADDR]]
+// CHECK:   [[ISNOTINLINE:%.*]] = and i32 [[FLAGS]], 131072
+// CHECK:   [[ISINLINE:%.*]] = icmp eq i32 [[ISNOTINLINE]], 0
 // CHECK:   br i1 [[ISINLINE]], label %done, label %outline.allocateValueInBuffer
 //
 // CHECK: outline.allocateValueInBuffer:
 // CHECK:   [[CAST:%.*]] = bitcast %swift.type* %0 to i8***
 // CHECK:   [[VWT_ADDR:%.*]] = getelementptr inbounds i8**, i8*** [[CAST]], {{.*}} -1
 // CHECK:   [[VWT:%.*]] = load i8**, i8*** [[VWT_ADDR]]
-// CHECK:   [[SIZE_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 8
-// CHECK:   [[SIZEWITNESS:%.*]] = load i8*, i8** [[SIZE_ADDR]]
-// CHECK:   [[SIZE:%.*]] = ptrtoint i8* [[SIZEWITNESS]]
-// CHECK:   [[ALIGN:%.*]] = and {{.*}} [[FLAGS]], 255
+// CHECK:   [[VWT_CAST:%.*]] = bitcast i8** [[VWT]] to %swift.vwtable*
+// CHECK:   [[SIZE_ADDR:%.*]] = getelementptr inbounds %swift.vwtable, %swift.vwtable* [[VWT_CAST]], i32 0, i32 8
+// CHECK:   [[SIZE:%.*]] = load [[INT]], [[INT]]* [[SIZE_ADDR]]
+// CHECK:   [[ALIGN:%.*]] = and {{.*}}, 255
 // CHECK:   [[PTR:%.*]] = call noalias i8* @swift_slowAlloc({{.*}} [[SIZE]], {{.*}} [[ALIGN]])
 // CHECK:   [[ADDR:%.*]] = bitcast %swift.opaque* %1 to i8**
 // CHECK:   store i8* [[PTR]], i8** [[ADDR]]
@@ -158,11 +158,11 @@
 // CHECK:   [[CAST:%.*]] = bitcast %swift.type* %0 to i8***
 // CHECK:   [[VWT_ADDR:%.*]] = getelementptr inbounds i8**, i8*** [[CAST]], {{.*}} -1
 // CHECK:   [[VWT:%.*]] = load i8**, i8*** [[VWT_ADDR]]
-// CHECK:   [[FLAGS_ADDR:%.*]] = getelementptr inbounds i8*, i8** %.valueWitnesses, i32 9
-// CHECK:   [[FLAGSWITNESS:%.*]] = load i8*, i8** [[FLAGS_ADDR]]
-// CHECK:   [[FLAGS:%.*]] = ptrtoint i8* [[FLAGSWITNESS]] to i{{.*}}
-// CHECK:   [[ISNOTINLINE:%.*]] = and {{.*}} [[FLAGS]], 131072
-// CHECK:   [[ISINLINE:%.*]] = icmp eq {{.*}} [[ISNOTINLINE]], 0
+// CHECK:   [[VWT_CAST:%.*]] = bitcast i8** [[VWT]] to %swift.vwtable*
+// CHECK:   [[FLAGS_ADDR:%.*]] = getelementptr inbounds %swift.vwtable, %swift.vwtable* [[VWT_CAST]], i32 0, i32 10
+// CHECK:   [[FLAGS:%.*]] = load i32, i32* [[FLAGS_ADDR]]
+// CHECK:   [[ISNOTINLINE:%.*]] = and i32 [[FLAGS]], 131072
+// CHECK:   [[ISINLINE:%.*]] = icmp eq i32 [[ISNOTINLINE]], 0
 // CHECK:   br i1 [[ISINLINE]], label %done, label %outline.projectValueInBuffer
 //
 // CHECK: outline.projectValueInBuffer:
diff --git a/test/IRGen/indexing.sil b/test/IRGen/indexing.sil
index d8153fe..add599e 100644
--- a/test/IRGen/indexing.sil
+++ b/test/IRGen/indexing.sil
@@ -42,14 +42,14 @@
 }
 
 // CHECK:      define{{( protected)?}} {{.*}}void @dynamic_size(%swift.opaque* noalias nocapture, i64, %swift.type* %T) {{.*}} {
-// CHECK:        %3 = bitcast %swift.type* %T to i8***
-// CHECK-NEXT:   %4 = getelementptr inbounds i8**, i8*** %3, i64 -1
-// CHECK-NEXT:   %T.valueWitnesses = load i8**, i8*** %4, align 8
-// CHECK-NEXT:   %5 = getelementptr inbounds i8*, i8** %T.valueWitnesses, i32 10
-// CHECK-NEXT:   %6 = load i8*, i8** %5, align 8
-// CHECK-NEXT:   %stride = ptrtoint i8* %6 to i64
-// CHECK-NEXT:   %7 = mul nsw i64 %1, %stride
-// CHECK-NEXT:   %8 = getelementptr inbounds i8, i8* %2, i64 %7
+// CHECK:        [[T0:%.*]] = bitcast %swift.type* %T to i8***
+// CHECK-NEXT:   [[T1:%.*]] = getelementptr inbounds i8**, i8*** [[T0]], i64 -1
+// CHECK-NEXT:   [[VWT:%T.valueWitnesses]] = load i8**, i8*** [[T1]], align 8
+// CHECK:        [[VWT_CAST:%.*]] = bitcast i8** [[VWT]] to %swift.vwtable*
+// CHECK:        [[STRIDE_ADDR:%.*]] = getelementptr inbounds %swift.vwtable, %swift.vwtable* [[VWT_CAST]], i32 0, i32 9
+// CHECK:        [[STRIDE:%.*]] = load i64, i64* [[STRIDE_ADDR]]
+// CHECK-NEXT:   [[T0:%.*]] = mul nsw i64 %1, [[STRIDE]]
+// CHECK-NEXT:   getelementptr inbounds i8, i8* %2, i64 [[T0]]
 
 sil @dynamic_size : $@convention(thin) <T> (@in T, Builtin.Word) -> () {
 entry(%p : $*T, %i: $Builtin.Word):
diff --git a/test/IRGen/indirect_enum.sil b/test/IRGen/indirect_enum.sil
index 9ecc1cf..401bb3b 100644
--- a/test/IRGen/indirect_enum.sil
+++ b/test/IRGen/indirect_enum.sil
@@ -2,8 +2,8 @@
 
 import Swift
 
-// CHECK-64: @"$s13indirect_enum5TreeAOWV" = internal constant {{.*}} i8* inttoptr ([[WORD:i64]] 8 to i8*), i8* inttoptr (i64 2424839 to i8*), i8* inttoptr (i64 8 to i8*)
-// CHECK-32: @"$s13indirect_enum5TreeAOWV" = internal constant {{.*}} i8* inttoptr ([[WORD:i32]] 4 to i8*), i8* inttoptr (i32 2424835 to i8*), i8* inttoptr (i32 4 to i8*)
+// CHECK-64: @"$s13indirect_enum5TreeAOWV" = internal constant %swift.enum_vwtable { {{.*}}, i64 8, i64 8, i32 2162695, 
+// CHECK-32: @"$s13indirect_enum5TreeAOWV" = internal constant %swift.enum_vwtable { {{.*}}, i32 4, i32 4, i32 2162691,
 
 // CHECK-NOT: define{{( protected)?}} private %swift.type** @get_field_types_TreeA
 indirect enum TreeA<T> {
diff --git a/test/IRGen/lifetime.sil b/test/IRGen/lifetime.sil
index 365302c..db8b5a2 100644
--- a/test/IRGen/lifetime.sil
+++ b/test/IRGen/lifetime.sil
@@ -1,4 +1,4 @@
-// RUN: %target-swift-frontend -assume-parsing-unqualified-ownership-sil -gnone -emit-ir %s | %FileCheck %s
+// RUN: %target-swift-frontend -assume-parsing-unqualified-ownership-sil -gnone -emit-ir %s | %FileCheck %s -DINT=i%target-ptrsize
 
 // CHECK: [[OPAQUE:%swift.opaque]] = type opaque
 // CHECK: [[TYPE:%swift.type]] = type
@@ -22,9 +22,9 @@
 // CHECK: [[TYPE_ADDR:%.*]] = bitcast %swift.type* %T to i8***
 // CHECK-NEXT: [[VWT_ADDR:%.*]] = getelementptr inbounds i8**, i8*** [[TYPE_ADDR]], {{(i32|i64)}} -1
 // CHECK-NEXT: [[VWT:%.*]] = load i8**, i8*** [[VWT_ADDR]]
-// CHECK-NEXT: [[SIZE_WITNESS_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 8
-// CHECK-NEXT: [[SIZE_WITNESS:%.*]] = load i8*, i8** [[SIZE_WITNESS_ADDR]]
-// CHECK-NEXT: [[SIZE:%.*]] = ptrtoint i8* [[SIZE_WITNESS]]
+// CHECK-NEXT: [[VWT_CAST:%.*]] = bitcast i8** [[VWT]] to %swift.vwtable*
+// CHECK-NEXT: [[SIZE_ADDR:%.*]] = getelementptr inbounds %swift.vwtable, %swift.vwtable* [[VWT_CAST]], i32 0, i32 8
+// CHECK-NEXT: [[SIZE:%.*]] = load [[INT]], [[INT]]* [[SIZE_ADDR]]
 // CHECK-NEXT: [[Y_ALLOCA:%.*]] = alloca i8, {{.*}} [[SIZE]], align 16
 // CHECK-NEXT: call void @llvm.lifetime.start.p0i8({{(i32|i64)}} -1, i8* [[Y_ALLOCA]])
 // CHECK-NEXT: [[Y_TMP:%.*]] = bitcast i8* [[Y_ALLOCA]] to %swift.opaque*
@@ -61,9 +61,9 @@
 // CHECK: [[TYPE_ADDR:%.*]] = bitcast %swift.type* %T to i8***
 // CHECK-NEXT: [[VWT_ADDR:%.*]] = getelementptr inbounds i8**, i8*** [[TYPE_ADDR]], {{(i32|i64)}} -1
 // CHECK-NEXT: [[VWT:%.*]] = load i8**, i8*** [[VWT_ADDR]]
-// CHECK-NEXT: [[SIZE_WITNESS_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 8
-// CHECK-NEXT: [[SIZE_WITNESS:%.*]] = load i8*, i8** [[SIZE_WITNESS_ADDR]]
-// CHECK-NEXT: [[SIZE:%.*]] = ptrtoint i8* [[SIZE_WITNESS]]
+// CHECK-NEXT: [[VWT_CAST:%.*]] = bitcast i8** [[VWT]] to %swift.vwtable*
+// CHECK-NEXT: [[SIZE_ADDR:%.*]] = getelementptr inbounds %swift.vwtable, %swift.vwtable* [[VWT_CAST]], i32 0, i32 8
+// CHECK-NEXT: [[SIZE:%.*]] = load [[INT]], [[INT]]* [[SIZE_ADDR]]
 // CHECK-NEXT: [[Y_ALLOCA:%.*]] = alloca i8, {{.*}} [[SIZE]], align 16
 // CHECK-NEXT: call void @llvm.lifetime.start.p0i8({{(i32|i64)}} -1, i8* [[Y_ALLOCA]])
 // CHECK-NEXT: [[Y_TMP:%.*]] = bitcast i8* [[Y_ALLOCA]] to %swift.opaque*
diff --git a/test/IRGen/multi_file_resilience.swift b/test/IRGen/multi_file_resilience.swift
index dd0ee00..2b64442 100644
--- a/test/IRGen/multi_file_resilience.swift
+++ b/test/IRGen/multi_file_resilience.swift
@@ -16,9 +16,9 @@
 // CHECK: [[METADATA:%.*]] = extractvalue %swift.metadata_response [[T0]], 0
 // CHECK: [[VWT:%.*]] = load i8**,
 //   Allocate 'copy'.
-// CHECK: [[T0:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 8
-// CHECK: [[T1:%.*]] = load i8*, i8** [[T0]],
-// CHECK: [[SIZE:%.*]] = ptrtoint i8* [[T1]] to [[INT]]
+// CHECK: [[VWT_CAST:%.*]] = bitcast i8** [[VWT]] to %swift.vwtable*
+// CHECK: [[SIZE_ADDR:%.*]] = getelementptr inbounds %swift.vwtable, %swift.vwtable* [[VWT_CAST]], i32 0, i32 8
+// CHECK: [[SIZE:%.*]] = load [[INT]], [[INT]]* [[SIZE_ADDR]]
 // CHECK: [[ALLOCA:%.*]] = alloca i8, [[INT]] [[SIZE]],
 // CHECK: [[COPY:%.*]] = bitcast i8* [[ALLOCA]] to [[FOO:%T4main3FooV]]*
 //   Perform 'initializeWithCopy' via the VWT instead of trying to inline it.
diff --git a/test/IRGen/multi_module_resilience.swift b/test/IRGen/multi_module_resilience.swift
index 30328ce..3e1df12 100644
--- a/test/IRGen/multi_module_resilience.swift
+++ b/test/IRGen/multi_module_resilience.swift
@@ -20,9 +20,9 @@
 // CHECK: [[METADATA:%.*]] = extractvalue %swift.metadata_response [[T0]], 0
 // CHECK: [[VWT:%.*]] = load i8**,
 //   Allocate 'copy'.
-// CHECK: [[T0:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 8
-// CHECK: [[T1:%.*]] = load i8*, i8** [[T0]],
-// CHECK: [[SIZE:%.*]] = ptrtoint i8* [[T1]] to [[INT]]
+// CHECK: [[VWT_CAST:%.*]] = bitcast i8** [[VWT]] to %swift.vwtable*
+// CHECK: [[SIZE_ADDR:%.*]] = getelementptr inbounds %swift.vwtable, %swift.vwtable* [[VWT_CAST]], i32 0, i32 8
+// CHECK: [[SIZE:%.*]] = load [[INT]], [[INT]]* [[SIZE_ADDR]]
 // CHECK: [[ALLOCA:%.*]] = alloca i8, [[INT]] [[SIZE]],
 // CHECK: [[COPY:%.*]] = bitcast i8* [[ALLOCA]] to [[FOO:%T11OtherModule3FooV]]*
 //   Perform 'initializeWithCopy' via the VWT instead of trying to inline it.
@@ -49,9 +49,9 @@
 // CHECK: [[METADATA:%.*]] = extractvalue %swift.metadata_response [[T0]], 0
 // CHECK: [[VWT:%.*]] = load i8**,
 //   Allocate 'copy'.
-// CHECK: [[T0:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 8
-// CHECK: [[T1:%.*]] = load i8*, i8** [[T0]],
-// CHECK: [[SIZE:%.*]] = ptrtoint i8* [[T1]] to [[INT]]
+// CHECK: [[VWT_CAST:%.*]] = bitcast i8** [[VWT]] to %swift.vwtable*
+// CHECK: [[SIZE_ADDR:%.*]] = getelementptr inbounds %swift.vwtable, %swift.vwtable* [[VWT_CAST]], i32 0, i32 8
+// CHECK: [[SIZE:%.*]] = load [[INT]], [[INT]]* [[SIZE_ADDR]]
 // CHECK: [[ALLOCA:%.*]] = alloca i8, [[INT]] [[SIZE]],
 // CHECK: [[COPY:%.*]] = bitcast i8* [[ALLOCA]] to [[BAR:%T11OtherModule3BarV]]*
 //   Perform 'initializeWithCopy' via the VWT instead of trying to inline it.
diff --git a/test/IRGen/partial_apply.sil b/test/IRGen/partial_apply.sil
index a060d06..6880591 100644
--- a/test/IRGen/partial_apply.sil
+++ b/test/IRGen/partial_apply.sil
@@ -233,10 +233,14 @@
 // CHECK:         [[T_METADATA_BASE:%.*]] = bitcast %swift.type* %T to i8***
 // CHECK:         [[T_VWTABLE_ADDR:%.*]] = getelementptr {{.*}} [[T_METADATA_BASE]], [[WORD:i[0-9]+]] -1
 // CHECK:         [[T_VWTABLE:%.*]] = load {{.*}} [[T_VWTABLE_ADDR]]
-// CHECK:         [[T_FLAGS_ADDR:%.*]] = getelementptr {{.*}} [[T_VWTABLE]], i32 9
-// CHECK:         [[T_FLAGS_PTR:%.*]] = load {{.*}} [[T_FLAGS_ADDR]]
-// CHECK:         [[T_FLAGS:%.*]] = ptrtoint {{.*}} [[T_FLAGS_PTR]] to [[WORD]]
-// CHECK:         [[T_ALIGN_MASK:%.*]] = and [[WORD]] [[T_FLAGS]], 255
+// CHECK:         [[T_VWTABLE_CAST:%.*]] = bitcast i8** [[T_VWTABLE]] to %swift.vwtable*
+// CHECK:         [[T_FLAGS_ADDR:%.*]] = getelementptr inbounds %swift.vwtable, %swift.vwtable* [[T_VWTABLE_CAST]], i32 0, i32 10
+// CHECK:         [[T_FLAGS:%.*]] = load i32, i32* [[T_FLAGS_ADDR]]
+// CHECK-64:      [[T0:%.*]] = zext i32 [[T_FLAGS]] to i64
+// CHECK-64:      [[T_ALIGN_MASK:%.*]] = and i64 [[T0]], 255
+// CHECK-32:      [[T_ALIGN_MASK:%.*]] = and i32 [[T_FLAGS]], 255
+// CHECK-16:      [[T0:%.*]] = trunc i32 [[T_FLAGS]] to i16
+// CHECK-16:      [[T_ALIGN_MASK:%.*]] = and i16 [[T0]], 255
 // CHECK:         [[T_ALIGN_MASK_NOT:%.*]] = xor [[WORD]] [[T_ALIGN_MASK]], -1
 // -- 32 is 64-bit offset of 'T' field, 16 for obj header + 8 for T metadata + 8 for SwiftClass field
 // CHECK-64:      [[T_UP_TO_ALIGN_1:%.*]] = add i64 32, [[T_ALIGN_MASK]]
@@ -245,9 +249,9 @@
 // CHECK:         [[T_OFFSET:%.*]] = and [[WORD]] [[T_UP_TO_ALIGN_1]], [[T_ALIGN_MASK_NOT]]
 
 // -- Add the size of T to start the Int field.
-// CHECK:         [[T_SIZE_ADDR:%.*]] = getelementptr {{.*}} [[T_VWTABLE]], i32 8
-// CHECK:         [[T_SIZE_PTR:%.*]] = load {{.*}} [[T_SIZE_ADDR]]
-// CHECK:         [[T_SIZE:%.*]] = ptrtoint {{.*}} [[T_SIZE_PTR]] to [[WORD]]
+// CHECK:         [[T_VWTABLE_CAST:%.*]] = bitcast i8** [[T_VWTABLE]] to %swift.vwtable*
+// CHECK:         [[T_SIZE_ADDR:%.*]] = getelementptr inbounds %swift.vwtable, %swift.vwtable* [[T_VWTABLE_CAST]], i32 0, i32 8
+// CHECK:         [[T_SIZE:%.*]] = load [[WORD]], [[WORD]]* [[T_SIZE_ADDR]]
 // CHECK:         [[T_END:%.*]] = add [[WORD]] [[T_OFFSET]], [[T_SIZE]]
 
 // -- Accumulate total alignment.
diff --git a/test/IRGen/struct_layout.sil b/test/IRGen/struct_layout.sil
index 9f08ccc..b76758c 100644
--- a/test/IRGen/struct_layout.sil
+++ b/test/IRGen/struct_layout.sil
@@ -9,9 +9,9 @@
 // 64: %T4main14Rdar15410780_CV = type <{ %TSSSg }>
 // 64: %TSSSg = type <{ [16 x i8] }>
 
-// 64: @"$s4main14Rdar15410780_AVWV" = internal constant {{.*}} (i64 257
-// 64: @"$s4main14Rdar15410780_BVWV" = internal constant {{.*}} (i64 258
-// 64: @"$s4main14Rdar15410780_CVWV" = internal constant {{.*}} (i64 16
+// 64: @"$s4main14Rdar15410780_AVWV" = internal constant {{.*}} i64 257
+// 64: @"$s4main14Rdar15410780_BVWV" = internal constant {{.*}} i64 258
+// 64: @"$s4main14Rdar15410780_CVWV" = internal constant {{.*}} i64 16
 
 
 // 32: %T4main14Rdar15410780_AV = type <{ i2048, %Ts4Int8V }>
@@ -20,9 +20,9 @@
 // 32: %T4main14Rdar15410780_CV = type <{ %TSSSg }>
 // 32: %TSSSg = type <{ [12 x i8] }>
 
-// 32: @"$s4main14Rdar15410780_AVWV" = internal constant {{.*}} (i32 257
-// 32: @"$s4main14Rdar15410780_BVWV" = internal constant {{.*}} (i32 258
-// 32: @"$s4main14Rdar15410780_CVWV" = internal constant {{.*}} (i32 12
+// 32: @"$s4main14Rdar15410780_AVWV" = internal constant {{.*}} i32 257
+// 32: @"$s4main14Rdar15410780_BVWV" = internal constant {{.*}} i32 258
+// 32: @"$s4main14Rdar15410780_CVWV" = internal constant {{.*}} i32 12
 
 
 // <rdar://problem/15410780>
diff --git a/test/IRGen/struct_resilience.swift b/test/IRGen/struct_resilience.swift
index 8ff8aa2..d6d61fd 100644
--- a/test/IRGen/struct_resilience.swift
+++ b/test/IRGen/struct_resilience.swift
@@ -25,9 +25,9 @@
 // CHECK: [[VWT_ADDR:%.*]] = getelementptr inbounds i8**, i8*** [[METADATA_ADDR]], [[INT]] -1
 // CHECK: [[VWT:%.*]] = load i8**, i8*** [[VWT_ADDR]]
 
-// CHECK-NEXT: [[WITNESS_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 8
-// CHECK: [[WITNESS:%.*]] = load i8*, i8** [[WITNESS_ADDR]]
-// CHECK: [[WITNESS_FOR_SIZE:%.*]] = ptrtoint i8* [[WITNESS]]
+// CHECK-NEXT: [[VWT_CAST:%.*]] = bitcast i8** [[VWT]] to %swift.vwtable*
+// CHECK-NEXT: [[WITNESS_ADDR:%.*]] = getelementptr inbounds %swift.vwtable, %swift.vwtable* [[VWT_CAST]], i32 0, i32 8
+// CHECK: [[WITNESS_FOR_SIZE:%.*]] = load [[INT]], [[INT]]* [[WITNESS_ADDR]]
 // CHECK: [[ALLOCA:%.*]] = alloca i8, {{.*}} [[WITNESS_FOR_SIZE]], align 16
 // CHECK: [[STRUCT_ADDR:%.*]] = bitcast i8* [[ALLOCA]] to %swift.opaque*
 
diff --git a/test/IRGen/struct_with_resilient_type.swift b/test/IRGen/struct_with_resilient_type.swift
index 0c2c8ba..8312df7 100644
--- a/test/IRGen/struct_with_resilient_type.swift
+++ b/test/IRGen/struct_with_resilient_type.swift
@@ -28,7 +28,8 @@
     fooImp.foo(ptr: bar)
   }
 // CHECK-LABEL: define{{.*}} @"$s26struct_with_resilient_type18ProtAndResilStructV3baryyFTc"(%T26struct_with_resilient_type18ProtAndResilStructV* noalias nocapture)
-// CHECK:   %flags.alignmentMask = and i64 %flags, 255
+// CHECK: [[T0:%.*]] = zext i32 %flags to i64
+// CHECK: %flags.alignmentMask = and i64 [[T0]], 255
 // CHECK: [[XOR_ALIGN:%.*]] = xor i64 %flags.alignmentMask, -1
 // CHECK: [[INIT_OFFSET:%.*]] = add i64 16, %flags.alignmentMask
 // CHECK: [[T0:%.*]] = and i64 [[INIT_OFFSET]], [[XOR_ALIGN]]
diff --git a/test/IRGen/type_layout.swift b/test/IRGen/type_layout.swift
index c0e4535..d500096 100644
--- a/test/IRGen/type_layout.swift
+++ b/test/IRGen/type_layout.swift
@@ -48,19 +48,19 @@
   // CHECK:       store i8** getelementptr inbounds (i8*, i8** @"$sBi64_WV", i32 8)
   var c: SSing
   // -- Multi-element structs use open-coded layouts
-  // CHECK:    store i8** getelementptr inbounds ([3 x i8*], [3 x i8*]* @type_layout_16_8_0_pod, i32 0, i32 0)
+  // CHECK:    store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_16_8_0_pod to i8**)
   var d: SMult
-  // CHECK-64:    store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_16_8_[[REF_XI:[0-9a-f]+]]_bt, i32 0, i32 0)
-  // CHECK-32:    store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_8_4_[[REF_XI:[0-9a-f]+]]_bt, i32 0, i32 0)
+  // CHECK-64:    store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_16_8_[[REF_XI:[0-9a-f]+]]_bt to i8**)
+  // CHECK-32:    store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_8_4_[[REF_XI:[0-9a-f]+]]_bt to i8**)
   var e: SMult2
-  // CHECK-64:    store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_16_8_[[REF_XI]]_bt, i32 0, i32 0)
-  // CHECK-32:    store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_8_4_[[REF_XI]]_bt, i32 0, i32 0)
+  // CHECK-64:    store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_16_8_[[REF_XI]]_bt to i8**)
+  // CHECK-32:    store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_8_4_[[REF_XI]]_bt to i8**)
   var f: SMult3
   // -- Single-case enum, shares layout of its field (Builtin.Int64)
   // CHECK:       store i8** getelementptr inbounds (i8*, i8** @"$sBi64_WV", i32 8)
   var g: ESing
   // -- Multi-case enum, open-coded layout
-  // CHECK:    store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_9_8_fe_pod, i32 0, i32 0)
+  // CHECK:    store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_9_8_fe_pod to i8**)
   var h: EMult
   // -- Single-element generic struct, shares layout of its field (T)
   // CHECK:       [[T_LAYOUT:%.*]] = getelementptr inbounds i8*, i8** [[T_VALUE_WITNESSES]], i32 8
diff --git a/test/IRGen/type_layout_objc.swift b/test/IRGen/type_layout_objc.swift
index 636a4d6..175aa22 100644
--- a/test/IRGen/type_layout_objc.swift
+++ b/test/IRGen/type_layout_objc.swift
@@ -46,19 +46,19 @@
   // CHECK:       store i8** getelementptr inbounds (i8*, i8** @"$sBi64_WV", i32 8)
   var c: SSing
   // -- Multi-element structs use open-coded layouts
-  // CHECK:    store i8** getelementptr inbounds ([3 x i8*], [3 x i8*]* @type_layout_16_8_0_pod, i32 0, i32 0)
+  // CHECK:    store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_16_8_0_pod to i8**)
   var d: SMult
-  // CHECK-64:    store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_16_8_7fffffff_bt, i32 0, i32 0)
-  // CHECK-32:    store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_8_4_1000_bt, i32 0, i32 0)
+  // CHECK-64:    store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_16_8_7fffffff_bt to i8**)
+  // CHECK-32:    store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_8_4_1000_bt to i8**)
   var e: SMult2
-  // CHECK-64:    store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_16_8_7fffffff_bt, i32 0, i32 0)
-  // CHECK-32:    store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_8_4_1000_bt, i32 0, i32 0)
+  // CHECK-64:    store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_16_8_7fffffff_bt to i8**)
+  // CHECK-32:    store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_8_4_1000_bt to i8**)
   var f: SMult3
   // -- Single-case enum, shares layout of its field (Builtin.Int64)
   // CHECK:       store i8** getelementptr inbounds (i8*, i8** @"$sBi64_WV", i32 8)
   var g: ESing
   // -- Multi-case enum, open-coded layout
-  // CHECK:    store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_9_8_fe_pod, i32 0, i32 0)
+  // CHECK:    store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_9_8_fe_pod to i8**)
   var h: EMult
   // -- Single-element generic struct, shares layout of its field (T)
   // CHECK:       [[T_LAYOUT:%.*]] = getelementptr inbounds i8*, i8** [[T_VALUE_WITNESSES]], i32 8
diff --git a/test/IRGen/type_layout_reference_storage.swift b/test/IRGen/type_layout_reference_storage.swift
index 27fd9e9..b2361b5 100644
--- a/test/IRGen/type_layout_reference_storage.swift
+++ b/test/IRGen/type_layout_reference_storage.swift
@@ -11,35 +11,35 @@
   var z: T
 
   // -- Known-Swift-refcounted type
-  // CHECK-64: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_8_8_[[REF_XI:[0-9a-f][0-9a-f][0-9a-f]+]]_pod, i32 0, i32 0)
-  // CHECK-32: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_4_4_[[REF_XI:[0-9a-f][0-9a-f][0-9a-f]+]]_pod, i32 0, i32 0)
+  // CHECK-64: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_8_8_[[REF_XI:[0-9a-f][0-9a-f][0-9a-f]+]]_pod to i8**)
+  // CHECK-32: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_4_4_[[REF_XI:[0-9a-f][0-9a-f][0-9a-f]+]]_pod to i8**)
   unowned(unsafe) var cu:  C
-  // CHECK-native-64: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_8_8_[[REF_XI]]_bt, i32 0, i32 0)
-  // CHECK-objc-64:   store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_8_8_1_bt, i32 0, i32 0)
-  // CHECK-native-32: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_4_4_[[REF_XI]]_bt, i32 0, i32 0)
-  // CHECK-objc-32:   store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_4_4_1_bt, i32 0, i32 0)
+  // CHECK-native-64: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_8_8_[[REF_XI]]_bt to i8**)
+  // CHECK-objc-64:   store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_8_8_1_bt to i8**)
+  // CHECK-native-32: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_4_4_[[REF_XI]]_bt to i8**)
+  // CHECK-objc-32:   store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_4_4_1_bt to i8**)
   unowned(safe)   var cs:  C
-  // CHECK-64: store i8** getelementptr inbounds ([3 x i8*], [3 x i8*]* @type_layout_8_8_0, i32 0, i32 0)
-  // CHECK-32: store i8** getelementptr inbounds ([3 x i8*], [3 x i8*]* @type_layout_4_4_0, i32 0, i32 0)
+  // CHECK-64: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_8_8_0 to i8**)
+  // CHECK-32: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_4_4_0 to i8**)
   weak            var cwo: C?
-  // CHECK-64: store i8** getelementptr inbounds ([3 x i8*], [3 x i8*]* @type_layout_8_8_0, i32 0, i32 0)
-  // CHECK-32: store i8** getelementptr inbounds ([3 x i8*], [3 x i8*]* @type_layout_4_4_0, i32 0, i32 0)
+  // CHECK-64: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_8_8_0 to i8**)
+  // CHECK-32: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_4_4_0 to i8**)
   weak            var cwi: C!
 
   // -- Known-Swift-refcounted archetype
-  // CHECK-64: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_8_8_[[REF_XI]]_pod, i32 0, i32 0)
-  // CHECK-32: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_4_4_[[REF_XI]]_pod, i32 0, i32 0)
+  // CHECK-64: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_8_8_[[REF_XI]]_pod to i8**)
+  // CHECK-32: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_4_4_[[REF_XI]]_pod to i8**)
   unowned(unsafe) var nu:  Native
-  // CHECK-native-64: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_8_8_[[REF_XI]]_bt, i32 0, i32 0)
-  // CHECK-objc-64:   store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_8_8_1_bt, i32 0, i32 0)
-  // CHECK-native-32: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_4_4_[[REF_XI]]_bt, i32 0, i32 0)
-  // CHECK-objc-32:   store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_4_4_1_bt, i32 0, i32 0)
+  // CHECK-native-64: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_8_8_[[REF_XI]]_bt to i8**)
+  // CHECK-objc-64:   store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_8_8_1_bt to i8**)
+  // CHECK-native-32: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_4_4_[[REF_XI]]_bt to i8**)
+  // CHECK-objc-32:   store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_4_4_1_bt to i8**)
   unowned(safe)   var nc:  Native
-  // CHECK-64: store i8** getelementptr inbounds ([3 x i8*], [3 x i8*]* @type_layout_8_8_0, i32 0, i32 0)
-  // CHECK-32: store i8** getelementptr inbounds ([3 x i8*], [3 x i8*]* @type_layout_4_4_0, i32 0, i32 0)
+  // CHECK-64: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_8_8_0 to i8**)
+  // CHECK-32: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_4_4_0 to i8**)
   weak            var nwo: Native?
-  // CHECK-64: store i8** getelementptr inbounds ([3 x i8*], [3 x i8*]* @type_layout_8_8_0, i32 0, i32 0)
-  // CHECK-32: store i8** getelementptr inbounds ([3 x i8*], [3 x i8*]* @type_layout_4_4_0, i32 0, i32 0)
+  // CHECK-64: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_8_8_0 to i8**)
+  // CHECK-32: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_4_4_0 to i8**)
   weak            var nwi: Native!
 
   // -- Open-code layout for protocol types with witness tables. Note:
@@ -47,81 +47,81 @@
   //       when ObjC interop is disabled.
   //    2) 0x7fffffff is the max extra inhabitant count, but not all types in
   //       all scenarios.
-  // CHECK-64: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_16_8_[[REF_XI]]_pod, i32 0, i32 0)
-  // CHECK-32: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_8_4_[[REF_XI]]_pod, i32 0, i32 0)
+  // CHECK-64: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_16_8_[[REF_XI]]_pod to i8**)
+  // CHECK-32: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_8_4_[[REF_XI]]_pod to i8**)
   unowned(unsafe) var pu:  P
-  // CHECK-native-64: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_16_8_[[REF_XI]]_bt, i32 0, i32 0)
-  // CHECK-objc-64:   store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_16_8_7fffffff, i32 0, i32 0)
-  // CHECK-native-32: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_8_4_[[REF_XI]]_bt, i32 0, i32 0)
-  // CHECK-objc-32:   store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_8_4_7fffffff, i32 0, i32 0)
+  // CHECK-native-64: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_16_8_[[REF_XI]]_bt to i8**)
+  // CHECK-objc-64:   store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_16_8_7fffffff to i8**)
+  // CHECK-native-32: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_8_4_[[REF_XI]]_bt to i8**)
+  // CHECK-objc-32:   store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_8_4_7fffffff to i8**)
   unowned(safe)   var ps:  P
-  // CHECK-64: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_16_8_7fffffff, i32 0, i32 0)
-  // CHECK-32: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_8_4_7fffffff, i32 0, i32 0)
+  // CHECK-64: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_16_8_7fffffff to i8**)
+  // CHECK-32: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_8_4_7fffffff to i8**)
   weak            var pwo: P?
-  // CHECK-64: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_16_8_7fffffff, i32 0, i32 0)
-  // CHECK-32: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_8_4_7fffffff, i32 0, i32 0)
+  // CHECK-64: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_16_8_7fffffff to i8**)
+  // CHECK-32: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_8_4_7fffffff to i8**)
   weak            var pwi: P!
 
-  // CHECK-native-64: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_24_8_[[REF_XI]]_bt, i32 0, i32 0)
-  // CHECK-objc-64:   store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_24_8_7fffffff, i32 0, i32 0)
-  // CHECK-native-32: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_12_4_[[REF_XI]]_bt, i32 0, i32 0)
-  // CHECK-objc-32:   store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_12_4_7fffffff, i32 0, i32 0)
+  // CHECK-native-64: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_24_8_[[REF_XI]]_bt to i8**)
+  // CHECK-objc-64:   store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_24_8_7fffffff to i8**)
+  // CHECK-native-32: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_12_4_[[REF_XI]]_bt to i8**)
+  // CHECK-objc-32:   store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_12_4_7fffffff to i8**)
   unowned(safe)   var pqs:  P & Q
-  // CHECK-64: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_24_8_[[REF_XI]]_pod, i32 0, i32 0)
-  // CHECK-32: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_12_4_[[REF_XI]]_pod, i32 0, i32 0)
+  // CHECK-64: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_24_8_[[REF_XI]]_pod to i8**)
+  // CHECK-32: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_12_4_[[REF_XI]]_pod to i8**)
   unowned(unsafe) var pqu:  P & Q
-  // CHECK-64: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_24_8_7fffffff, i32 0, i32 0)
-  // CHECK-32: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_12_4_7fffffff, i32 0, i32 0)
+  // CHECK-64: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_24_8_7fffffff to i8**)
+  // CHECK-32: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_12_4_7fffffff to i8**)
   weak            var pqwo: (P & Q)?
-  // CHECK-64: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_24_8_7fffffff, i32 0, i32 0)
-  // CHECK-32: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_12_4_7fffffff, i32 0, i32 0)
+  // CHECK-64: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_24_8_7fffffff to i8**)
+  // CHECK-32: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_12_4_7fffffff to i8**)
   weak            var pqwi: (P & Q)!
 
-  // CHECK-native-64: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_24_8_[[REF_XI]]_bt, i32 0, i32 0)
-  // CHECK-objc-64:   store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_24_8_7fffffff_bt, i32 0, i32 0)
-  // CHECK-native-32: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_12_4_[[REF_XI]]_bt, i32 0, i32 0)
-  // CHECK-objc-32:   store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_12_4_7fffffff_bt, i32 0, i32 0)
+  // CHECK-native-64: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_24_8_[[REF_XI]]_bt to i8**)
+  // CHECK-objc-64:   store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_24_8_7fffffff_bt to i8**)
+  // CHECK-native-32: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_12_4_[[REF_XI]]_bt to i8**)
+  // CHECK-objc-32:   store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_12_4_7fffffff_bt to i8**)
   unowned(safe)   var pqcs:  P & Q & C
-  // CHECK-64: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_24_8_[[REF_XI]]_pod, i32 0, i32 0)
-  // CHECK-32: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_12_4_[[REF_XI]]_pod, i32 0, i32 0)
+  // CHECK-64: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_24_8_[[REF_XI]]_pod to i8**)
+  // CHECK-32: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_12_4_[[REF_XI]]_pod to i8**)
   unowned(unsafe) var pqcu:  P & Q & C
-  // CHECK-64: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_24_8_7fffffff, i32 0, i32 0)
-  // CHECK-32: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_12_4_7fffffff, i32 0, i32 0)
+  // CHECK-64: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_24_8_7fffffff to i8**)
+  // CHECK-32: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_12_4_7fffffff to i8**)
   weak            var pqcwo: (P & Q & C)?
-  // CHECK-64: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_24_8_7fffffff, i32 0, i32 0)
-  // CHECK-32: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_12_4_7fffffff, i32 0, i32 0)
+  // CHECK-64: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_24_8_7fffffff to i8**)
+  // CHECK-32: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_12_4_7fffffff to i8**)
   weak            var pqcwi: (P & Q & C)!
 
   // -- Unknown-refcounted existential without witness tables.
-  // CHECK-64: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_8_8_[[REF_XI]]_pod, i32 0, i32 0)
-  // CHECK-32: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_4_4_[[REF_XI]]_pod, i32 0, i32 0)
+  // CHECK-64: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_8_8_[[REF_XI]]_pod to i8**)
+  // CHECK-32: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_4_4_[[REF_XI]]_pod to i8**)
   unowned(unsafe) var aou:  AnyObject
-  // CHECK-native-64: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_8_8_[[REF_XI]]_bt, i32 0, i32 0)
-  // CHECK-objc-64:   store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_8_8_1, i32 0, i32 0)
-  // CHECK-native-32: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_4_4_[[REF_XI]]_bt, i32 0, i32 0)
-  // CHECK-objc-32:   store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_4_4_1, i32 0, i32 0)
+  // CHECK-native-64: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_8_8_[[REF_XI]]_bt to i8**)
+  // CHECK-objc-64:   store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_8_8_1 to i8**)
+  // CHECK-native-32: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_4_4_[[REF_XI]]_bt to i8**)
+  // CHECK-objc-32:   store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_4_4_1 to i8**)
   unowned(safe)   var aos:  AnyObject
-  // CHECK-64: store i8** getelementptr inbounds ([3 x i8*], [3 x i8*]* @type_layout_8_8_0, i32 0, i32 0)
-  // CHECK-32: store i8** getelementptr inbounds ([3 x i8*], [3 x i8*]* @type_layout_4_4_0, i32 0, i32 0)
+  // CHECK-64: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_8_8_0 to i8**)
+  // CHECK-32: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_4_4_0 to i8**)
   weak            var aowo: AnyObject?
-  // CHECK-64: store i8** getelementptr inbounds ([3 x i8*], [3 x i8*]* @type_layout_8_8_0, i32 0, i32 0)
-  // CHECK-32: store i8** getelementptr inbounds ([3 x i8*], [3 x i8*]* @type_layout_4_4_0, i32 0, i32 0)
+  // CHECK-64: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_8_8_0 to i8**)
+  // CHECK-32: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_4_4_0 to i8**)
   weak            var aowi: AnyObject!
 
   // -- Unknown-refcounted archetype
-  // CHECK-64: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_8_8_[[REF_XI]]_pod, i32 0, i32 0)
-  // CHECK-32: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_4_4_[[REF_XI]]_pod, i32 0, i32 0)
+  // CHECK-64: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_8_8_[[REF_XI]]_pod to i8**)
+  // CHECK-32: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_4_4_[[REF_XI]]_pod to i8**)
   unowned(unsafe) var uu:  Unknown
-  // CHECK-native-64: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_8_8_[[REF_XI]]_bt, i32 0, i32 0)
-  // CHECK-objc-64:   store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_8_8_1, i32 0, i32 0)
-  // CHECK-native-32: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_4_4_[[REF_XI]]_bt, i32 0, i32 0)
-  // CHECK-objc-32:   store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_4_4_1, i32 0, i32 0)
+  // CHECK-native-64: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_8_8_[[REF_XI]]_bt to i8**)
+  // CHECK-objc-64:   store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_8_8_1 to i8**)
+  // CHECK-native-32: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_4_4_[[REF_XI]]_bt to i8**)
+  // CHECK-objc-32:   store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_4_4_1 to i8**)
   unowned(safe)   var us:  Unknown
-  // CHECK-64: store i8** getelementptr inbounds ([3 x i8*], [3 x i8*]* @type_layout_8_8_0, i32 0, i32 0)
-  // CHECK-32: store i8** getelementptr inbounds ([3 x i8*], [3 x i8*]* @type_layout_4_4_0, i32 0, i32 0)
+  // CHECK-64: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_8_8_0 to i8**)
+  // CHECK-32: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_4_4_0 to i8**)
   weak            var uwo: Unknown?
-  // CHECK-64: store i8** getelementptr inbounds ([3 x i8*], [3 x i8*]* @type_layout_8_8_0, i32 0, i32 0)
-  // CHECK-32: store i8** getelementptr inbounds ([3 x i8*], [3 x i8*]* @type_layout_4_4_0, i32 0, i32 0)
+  // CHECK-64: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_8_8_0 to i8**)
+  // CHECK-32: store i8** bitcast ({ [[INT]], [[INT]], i32, i32 }* @type_layout_4_4_0 to i8**)
   weak            var uwi: Unknown!
 }
 
diff --git a/test/IRGen/weak.sil b/test/IRGen/weak.sil
index a8a21c9..e946601 100644
--- a/test/IRGen/weak.sil
+++ b/test/IRGen/weak.sil
@@ -28,9 +28,9 @@
 }
 
 // size 8
-// flags 0x130007 == 1245191 (non-POD, non-inline, non-bitwise-takable)
 // stride 8
-// CHECK: @"$s4weak1AVWV" = {{.*}} i8* inttoptr (i64 8 to i8*), i8* inttoptr (i64 1245191 to i8*), i8* inttoptr (i64 8 to i8*)]
+// flags 0x130007 == 1245191 (non-POD, non-inline, non-bitwise-takable)
+// CHECK: @"$s4weak1AVWV" = {{.*}} i64 8, i64 8, i32 1245191,
 
 sil @test_weak_load_store : $@convention(thin) (@inout A, Optional<C>) -> () {
 bb0(%0 : $*A, %1 : $Optional<C>):
diff --git a/unittests/runtime/Enum.cpp b/unittests/runtime/Enum.cpp
index a8cb4c7..50ac951 100644
--- a/unittests/runtime/Enum.cpp
+++ b/unittests/runtime/Enum.cpp
@@ -16,33 +16,60 @@
 
 using namespace swift;
 
+SWIFT_CC(swift)
+static unsigned byte_getExtraInhabitantTag(const OpaqueValue *src,
+                                           unsigned numXI,
+                                           const Metadata *self) {
+  assert(numXI == 2);
+  uint8_t byte = *reinterpret_cast<const uint8_t*>(src);
+  if (byte > 253)
+    return byte - 253;
+  return 0;
+}
+
+static unsigned byte_getEnumTagSinglePayload(const OpaqueValue *value,
+                                             unsigned numEmptyCases,
+                                             const Metadata *self) {
+  return swift_getEnumTagSinglePayloadGeneric(value, numEmptyCases, self,
+                                              byte_getExtraInhabitantTag);
+}
+
+SWIFT_CC(swift)
+static void byte_storeExtraInhabitantTag(OpaqueValue *dest, unsigned tag,
+                                         unsigned numXI, const Metadata *self) {
+  assert(numXI == 2);
+  assert(tag > 0 && tag <= 2);
+  *reinterpret_cast<uint8_t*>(dest) = 253 + tag;
+}
+
+static void byte_storeEnumTagSinglePayload(OpaqueValue *value,
+                                           unsigned tag,
+                                           unsigned numEmptyCases,
+                                           const Metadata *self) {
+  swift_storeEnumTagSinglePayloadGeneric(value, tag, numEmptyCases, self,
+                                         byte_storeExtraInhabitantTag);
+}
+
+// Just use the normal operations for copying i8.
+#define byte_initializeBufferWithCopyOfBuffer \
+  VALUE_WITNESS_SYM(Bi8_).initializeBufferWithCopyOfBuffer
+#define byte_destroy            VALUE_WITNESS_SYM(Bi8_).destroy
+#define byte_initializeWithCopy VALUE_WITNESS_SYM(Bi8_).initializeWithCopy
+#define byte_assignWithCopy     VALUE_WITNESS_SYM(Bi8_).assignWithCopy
+#define byte_initializeWithTake VALUE_WITNESS_SYM(Bi8_).initializeWithTake
+#define byte_assignWithTake     VALUE_WITNESS_SYM(Bi8_).assignWithTake
+
 // Mock up a value witness table for Builtin.Int8 will 254 and 255 as extra
 // inhabitants.
-ExtraInhabitantsValueWitnessTable Int8WithExtraInhabitantValueWitness
-= {
-  // ValueWitnessTable
-  ValueWitnessTable{
+ValueWitnessTable Int8WithExtraInhabitantValueWitness = {
 #define WANT_ONLY_REQUIRED_VALUE_WITNESSES
-#define VALUE_WITNESS(LOWER_ID, UPPER_ID) VALUE_WITNESS_SYM(Bi8_).LOWER_ID,
+#define VALUE_WITNESS(LOWER_ID, UPPER_ID) byte_##LOWER_ID,
 #define DATA_VALUE_WITNESS(LOWER_ID, UPPER_ID, TYPE)
 #include "swift/ABI/ValueWitness.def"
-    VALUE_WITNESS_SYM(Bi8_).size,
-    VALUE_WITNESS_SYM(Bi8_).flags.withExtraInhabitants(true),
-    VALUE_WITNESS_SYM(Bi8_).stride
-  },
-  // extraInhabitantFlags
-  ExtraInhabitantFlags().withNumExtraInhabitants(2),
-  // storeExtraInhabitant
-  [](OpaqueValue *dest, int index, const Metadata *self) {
-    *reinterpret_cast<uint8_t*>(dest) = 254 + index;
-  },
-  // getExtraInhabitantIndex
-  [](const OpaqueValue *src, const Metadata *self) -> int {
-    uint8_t byte = *reinterpret_cast<const uint8_t*>(src);
-    if (byte >= 254)
-      return byte - 254;
-    return -1;
-  }
+  VALUE_WITNESS_SYM(Bi8_).size,
+  VALUE_WITNESS_SYM(Bi8_).stride,
+  VALUE_WITNESS_SYM(Bi8_).flags,
+  /*extraInhabitantCount*/ 2
 };
 
 FullMetadata<OpaqueMetadata> XI_TMBi8_ = {
@@ -58,10 +85,10 @@
 }
 
 int test_getEnumCaseSinglePayload(std::initializer_list<uint8_t> repr,
-                                       const FullOpaqueMetadata &metadata,
-                                       unsigned numEmptyCases) {
-  return swift_getEnumCaseSinglePayload(asOpaque(repr.begin()),
-                                         &metadata.base, numEmptyCases);
+                                  const FullOpaqueMetadata &metadata,
+                                  unsigned numEmptyCases) {
+  return metadata.base.vw_getEnumTagSinglePayload(asOpaque(repr.begin()),
+                                                  numEmptyCases);
 }
 
 TEST(EnumTest, getEnumCaseSinglePayload) {
@@ -110,10 +137,9 @@
   buf.resize(before.size());
   memcpy(buf.data(), before.begin(), before.size());
 
-  swift_storeEnumTagSinglePayload(asOpaque(buf.data()),
-                                   &metadata.base,
-                                   whichCase,
-                                   numEmptyCases);
+  metadata.base.vw_storeEnumTagSinglePayload(asOpaque(buf.data()),
+                                             whichCase,
+                                             numEmptyCases);
 
   return memcmp(buf.data(), after.begin(), after.size()) == 0;
 }
diff --git a/validation-test/stdlib/MicroStdlib/Inputs/RuntimeStubs.c b/validation-test/stdlib/MicroStdlib/Inputs/RuntimeStubs.c
index a617edc..e2bc223 100644
--- a/validation-test/stdlib/MicroStdlib/Inputs/RuntimeStubs.c
+++ b/validation-test/stdlib/MicroStdlib/Inputs/RuntimeStubs.c
@@ -6,14 +6,14 @@
 int $sBi32_WV;
 int $sBi64_WV;
 int $sBi8_WV;
-void swift_getEnumCaseSinglePayload(void) {}
 void swift_getGenericMetadata(void) {}
 void swift_checkMetadataState(void) {}
 void swift_slowAlloc(void) {}
 void swift_slowDealloc(void) {}
-void swift_storeEnumTagSinglePayload(void) {}
 void swift_allocateGenericValueMetadata(void) {}
 void swift_initEnumMetadataSinglePayload(void) {}
+void swift_getEnumTagSinglePayloadGeneric(void) {}
+void swift_storeEnumTagSinglePayloadGeneric(void) {}
 void swift_retain(){}
 void swift_allocBox(){}
 void swift_getWitnessTable(void) {}