//===--- DeserializeSIL.cpp - Read SIL ------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "deserialize"

#include "DeserializeSIL.h"
#include "BCReadingExtras.h"
#include "DeserializationErrors.h"
#include "ModuleFile.h"
#include "SILFormat.h"
#include "SILSerializationFunctionBuilder.h"
#include "SerializationFormat.h"

#include "swift/AST/DiagnosticsSIL.h"
#include "swift/AST/GenericSignature.h"
#include "swift/AST/PrettyStackTrace.h"
#include "swift/AST/ProtocolConformance.h"
#include "swift/Basic/Assertions.h"
#include "swift/Basic/CodeGenerationModel.h"
#include "swift/Basic/Defer.h"
#include "swift/Basic/PrettyStackTrace.h"
#include "swift/SIL/SILArgument.h"
#include "swift/SIL/SILBuilder.h"
#include "swift/SIL/SILDebugScope.h"
#include "swift/SIL/SILModule.h"
#include "swift/SIL/SILMoveOnlyDeinit.h"
#include "swift/SIL/SILProperty.h"
#include "swift/SIL/SILUndef.h"

#include "swift/SIL/OwnershipUtils.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/DJB.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/OnDiskHashTable.h"

#include <type_traits>

using namespace swift;
using namespace swift::serialization;
using namespace swift::serialization::sil_block;
using namespace llvm::support;

const char SILEntityError::ID = '\0';
void SILEntityError::anchor() {}
const char SILFunctionTypeMismatch::ID = '\0';
void SILFunctionTypeMismatch::anchor() {}

STATISTIC(NumDeserializedFunc, "Number of deserialized SIL functions");

static std::optional<StringLiteralInst::Encoding>
fromStableStringEncoding(unsigned value) {
  switch (value) {
  case SIL_BYTES: return StringLiteralInst::Encoding::Bytes;
  case SIL_UTF8: return StringLiteralInst::Encoding::UTF8;
  case SIL_OBJC_SELECTOR: return StringLiteralInst::Encoding::ObjCSelector;
  case SIL_UTF8_OSLOG: return StringLiteralInst::Encoding::UTF8_OSLOG;
  default:
    return std::nullopt;
  }
}

static std::optional<SILLinkage> fromStableSILLinkage(unsigned value) {
  switch (value) {
  case SIL_LINKAGE_PUBLIC: return SILLinkage::Public;
  case SIL_LINKAGE_PUBLIC_NON_ABI: return SILLinkage::PublicNonABI;
  case SIL_LINKAGE_PACKAGE: return SILLinkage::Package;
  case SIL_LINKAGE_PACKAGE_NON_ABI: return SILLinkage::PackageNonABI;
  case SIL_LINKAGE_HIDDEN: return SILLinkage::Hidden;
  case SIL_LINKAGE_SHARED: return SILLinkage::Shared;
  case SIL_LINKAGE_PRIVATE: return SILLinkage::Private;
  case SIL_LINKAGE_PUBLIC_EXTERNAL: return SILLinkage::PublicExternal;
  case SIL_LINKAGE_PACKAGE_EXTERNAL: return SILLinkage::PackageExternal;
  case SIL_LINKAGE_HIDDEN_EXTERNAL: return SILLinkage::HiddenExternal;
  }

  llvm_unreachable("Invalid SIL linkage");
}

static std::optional<SILVTable::Entry::Kind>
fromStableVTableEntryKind(unsigned value) {
  switch (value) {
  case SIL_VTABLE_ENTRY_NORMAL: return SILVTable::Entry::Kind::Normal;
  case SIL_VTABLE_ENTRY_INHERITED: return SILVTable::Entry::Kind::Inherited;
  case SIL_VTABLE_ENTRY_OVERRIDE: return SILVTable::Entry::Kind::Override;
  default:
    return std::nullopt;
  }
}

static std::optional<swift::DifferentiabilityKind>
fromStableDifferentiabilityKind(uint8_t diffKind) {
  switch (diffKind) {
#define CASE(THE_DK) \
  case (uint8_t)serialization::DifferentiabilityKind::THE_DK: \
    return swift::DifferentiabilityKind::THE_DK;
  CASE(NonDifferentiable)
  CASE(Forward)
  CASE(Reverse)
  CASE(Normal)
  CASE(Linear)
#undef CASE
  default:
    return std::nullopt;
  }
}

/// Used to deserialize entries in the on-disk func hash table.
class SILDeserializer::FuncTableInfo {
  ModuleFile &MF;

public:
  using internal_key_type = StringRef;
  using external_key_type = StringRef;
  using data_type = DeclID;
  using hash_value_type = uint32_t;
  using offset_type = unsigned;

  explicit FuncTableInfo(ModuleFile &MF) : MF(MF) {}

  internal_key_type GetInternalKey(external_key_type ID) { return ID; }

  external_key_type GetExternalKey(internal_key_type ID) { return ID; }

  hash_value_type ComputeHash(internal_key_type key) {
    return llvm::djbHash(key, SWIFTMODULE_HASH_SEED);
  }

  static bool EqualKey(internal_key_type lhs, internal_key_type rhs) {
    return lhs == rhs;
  }

  static std::pair<unsigned, unsigned> ReadKeyDataLength(const uint8_t *&data) {
    return { sizeof(uint32_t), sizeof(uint32_t) };
  }

  internal_key_type ReadKey(const uint8_t *data, unsigned length) {
    assert(length == sizeof(uint32_t) && "Expect a single IdentifierID.");
    IdentifierID keyID = readNext<uint32_t>(data);
    return MF.getIdentifierText(keyID);
  }

  static data_type ReadData(internal_key_type key, const uint8_t *data,
                            unsigned length) {
    assert(length == sizeof(uint32_t) && "Expect a single DeclID.");
    data_type result = readNext<uint32_t>(data);
    return result;
  }
};

/// Used to deserialize string -> string mappings in on-disk hash tables.
class SILDeserializer::StringTableInfo {
public:
  using internal_key_type = StringRef;
  using external_key_type = internal_key_type;
  using data_type = StringRef;
  using hash_value_type = uint32_t;
  using offset_type = uint32_t;

  internal_key_type GetInternalKey(external_key_type ID) { return ID; }

  external_key_type GetExternalKey(internal_key_type ID) { return ID; }

  hash_value_type ComputeHash(internal_key_type key) {
    return llvm::djbHash(key, SWIFTMODULE_HASH_SEED);
  }

  static bool EqualKey(internal_key_type lhs, internal_key_type rhs) {
    return lhs == rhs;
  }

  static std::pair<unsigned, unsigned> ReadKeyDataLength(const uint8_t *&data) {
    offset_type keyLength =
        llvm::support::endian::readNext<offset_type, llvm::endianness::little,
                                        llvm::support::unaligned>(data);
    offset_type dataLength =
        llvm::support::endian::readNext<offset_type, llvm::endianness::little,
                                        llvm::support::unaligned>(data);

    return { keyLength, dataLength };
  }

  internal_key_type ReadKey(const uint8_t *data, unsigned length) {
    return internal_key_type((const char *)data, length);
  }

  static data_type ReadData(internal_key_type key, const uint8_t *data,
                            unsigned length) {
    return data_type((const char *)data, length);
  }
};

SILDeserializer::SILDeserializer(
    ModuleFile *MF, SILModule &M,
    DeserializationNotificationHandlerSet *callback)
    : MF(MF), SILMod(M), Callback(callback) {

  SILCursor = MF->getSILCursor();
  SILIndexCursor = MF->getSILIndexCursor();
  // Early return if either sil block or sil index block does not exist.
  if (SILCursor.AtEndOfStream() || SILIndexCursor.AtEndOfStream())
    return;

  // Load any abbrev records at the start of the block.
  MF->fatalIfUnexpected(SILCursor.advance());

  llvm::BitstreamCursor cursor = SILIndexCursor;
  // We expect SIL_FUNC_NAMES first, then SIL_VTABLE_NAMES, then
  // SIL_GLOBALVAR_NAMES, then SIL_WITNESS_TABLE_NAMES, and finally
  // SIL_DEFAULT_WITNESS_TABLE_NAMES. But each one can be
  // omitted if no entries exist in the module file.
  unsigned kind = 0;
  while (kind != sil_index_block::SIL_PROPERTY_OFFSETS) {
    llvm::BitstreamEntry next = MF->fatalIfUnexpected(cursor.advance());
    if (next.Kind == llvm::BitstreamEntry::EndBlock)
      return;

    SmallVector<uint64_t, 4> scratch;
    StringRef blobData;
    unsigned prevKind = kind;
    kind =
        MF->fatalIfUnexpected(cursor.readRecord(next.ID, scratch, &blobData));
    assert((next.Kind == llvm::BitstreamEntry::Record && kind > prevKind &&
            (kind == sil_index_block::SIL_FUNC_NAMES ||
             kind == sil_index_block::SIL_VTABLE_NAMES ||
             kind == sil_index_block::SIL_MOVEONLYDEINIT_NAMES ||
             kind == sil_index_block::SIL_GLOBALVAR_NAMES ||
             kind == sil_index_block::SIL_WITNESS_TABLE_NAMES ||
             kind == sil_index_block::SIL_DEFAULT_WITNESS_TABLE_NAMES ||
             kind == sil_index_block::SIL_DEFAULT_OVERRIDE_TABLE_NAMES ||
             kind == sil_index_block::SIL_PROPERTY_OFFSETS ||
             kind == sil_index_block::SIL_DIFFERENTIABILITY_WITNESS_NAMES ||
             kind == sil_index_block::SIL_ASM_NAMES)) &&
           "Expect SIL_FUNC_NAMES, SIL_VTABLE_NAMES, SIL_GLOBALVAR_NAMES, \
          SIL_WITNESS_TABLE_NAMES, SIL_DEFAULT_WITNESS_TABLE_NAMES, \
          SIL_PROPERTY_OFFSETS, SIL_MOVEONLYDEINIT_NAMES, SIL_DIFFERENTIABILITY_WITNESS_NAMES, or SIL_ASM_NAMES.");
    (void)prevKind;

    if (kind == sil_index_block::SIL_FUNC_NAMES)
      FuncTable = readFuncTable(scratch, blobData);
    else if (kind == sil_index_block::SIL_VTABLE_NAMES)
      VTableList = readFuncTable(scratch, blobData);
    else if (kind == sil_index_block::SIL_MOVEONLYDEINIT_NAMES)
      MoveOnlyDeinitList = readFuncTable(scratch, blobData);
    else if (kind == sil_index_block::SIL_GLOBALVAR_NAMES)
      GlobalVarList = readFuncTable(scratch, blobData);
    else if (kind == sil_index_block::SIL_WITNESS_TABLE_NAMES)
      WitnessTableList = readFuncTable(scratch, blobData);
    else if (kind == sil_index_block::SIL_DEFAULT_WITNESS_TABLE_NAMES)
      DefaultWitnessTableList = readFuncTable(scratch, blobData);
    else if (kind == sil_index_block::SIL_DEFAULT_OVERRIDE_TABLE_NAMES)
      DefaultOverrideTableList = readFuncTable(scratch, blobData);
    else if (kind == sil_index_block::SIL_DIFFERENTIABILITY_WITNESS_NAMES)
      DifferentiabilityWitnessList = readFuncTable(scratch, blobData);
    else if (kind == sil_index_block::SIL_ASM_NAMES) {
      // No matching offset block.
      AsmNameTable = readStringTable(scratch, blobData);
      continue;
    } else if (kind == sil_index_block::SIL_PROPERTY_OFFSETS) {
      // No matching 'names' block for property descriptors needed yet.
      MF->allocateBuffer(Properties, scratch);
      continue;
    }

    // Read SIL_FUNC|VTABLE|GLOBALVAR_OFFSETS record.
    next = MF->fatalIfUnexpected(cursor.advance());
    scratch.clear();
    unsigned offKind =
        MF->fatalIfUnexpected(cursor.readRecord(next.ID, scratch, &blobData));
    (void)offKind;
    if (kind == sil_index_block::SIL_FUNC_NAMES) {
      assert((next.Kind == llvm::BitstreamEntry::Record &&
              offKind == sil_index_block::SIL_FUNC_OFFSETS) &&
             "Expect a SIL_FUNC_OFFSETS record.");
      MF->allocateBuffer(Funcs, scratch);
    } else if (kind == sil_index_block::SIL_VTABLE_NAMES) {
      assert((next.Kind == llvm::BitstreamEntry::Record &&
              offKind == sil_index_block::SIL_VTABLE_OFFSETS) &&
             "Expect a SIL_VTABLE_OFFSETS record.");
      MF->allocateBuffer(VTables, scratch);
    } else if (kind == sil_index_block::SIL_MOVEONLYDEINIT_NAMES) {
      assert((next.Kind == llvm::BitstreamEntry::Record &&
              offKind == sil_index_block::SIL_MOVEONLYDEINIT_OFFSETS) &&
             "Expect a SIL_MOVEONLYDEINIT_OFFSETS record.");
      MF->allocateBuffer(MoveOnlyDeinits, scratch);
    } else if (kind == sil_index_block::SIL_GLOBALVAR_NAMES) {
      assert((next.Kind == llvm::BitstreamEntry::Record &&
              offKind == sil_index_block::SIL_GLOBALVAR_OFFSETS) &&
             "Expect a SIL_GLOBALVAR_OFFSETS record.");
      MF->allocateBuffer(GlobalVars, scratch);
    } else if (kind == sil_index_block::SIL_WITNESS_TABLE_NAMES) {
      assert((next.Kind == llvm::BitstreamEntry::Record &&
              offKind == sil_index_block::SIL_WITNESS_TABLE_OFFSETS) &&
             "Expect a SIL_WITNESS_TABLE_OFFSETS record.");
      MF->allocateBuffer(WitnessTables, scratch);
    } else if (kind == sil_index_block::SIL_DEFAULT_WITNESS_TABLE_NAMES) {
      assert((next.Kind == llvm::BitstreamEntry::Record &&
              offKind == sil_index_block::SIL_DEFAULT_WITNESS_TABLE_OFFSETS) &&
             "Expect a SIL_DEFAULT_WITNESS_TABLE_OFFSETS record.");
      MF->allocateBuffer(DefaultWitnessTables, scratch);
    } else if (kind == sil_index_block::SIL_DEFAULT_OVERRIDE_TABLE_NAMES) {
      assert((next.Kind == llvm::BitstreamEntry::Record &&
              offKind == sil_index_block::SIL_DEFAULT_OVERRIDE_TABLE_OFFSETS) &&
             "Expect a SIL_DEFAULT_OVERRIDE_TABLE_OFFSETS record.");
      MF->allocateBuffer(DefaultOverrideTables, scratch);
    } else if (kind == sil_index_block::SIL_DIFFERENTIABILITY_WITNESS_NAMES) {
      assert((next.Kind == llvm::BitstreamEntry::Record &&
              offKind ==
                  sil_index_block::SIL_DIFFERENTIABILITY_WITNESS_OFFSETS) &&
             "Expect a SIL_DIFFERENTIABILITY_WITNESS_OFFSETS record.");
      MF->allocateBuffer(DifferentiabilityWitnesses, scratch);
    }
  }
}

std::unique_ptr<SILDeserializer::SerializedFuncTable>
SILDeserializer::readFuncTable(ArrayRef<uint64_t> fields, StringRef blobData) {
  uint32_t tableOffset;
  sil_index_block::ListLayout::readRecord(fields, tableOffset);
  auto base = reinterpret_cast<const uint8_t *>(blobData.data());

  using OwnedTable = std::unique_ptr<SerializedFuncTable>;
  return OwnedTable(SerializedFuncTable::Create(base + tableOffset,
                                                base + sizeof(uint32_t), base,
                                                FuncTableInfo(*MF)));
}

std::unique_ptr<SILDeserializer::SerializedStringTable>
SILDeserializer::readStringTable(ArrayRef<uint64_t> fields, StringRef blobData){
  uint32_t tableOffset;
  sil_index_block::ListLayout::readRecord(fields, tableOffset);
  auto base = reinterpret_cast<const uint8_t *>(blobData.data());

  using OwnedTable = std::unique_ptr<SerializedStringTable>;
  return OwnedTable(SerializedStringTable::Create(base + tableOffset,
                                                  base + sizeof(uint32_t), base,
                                                  StringTableInfo()));
}


/// A high-level overview of how forward references work in serializer and
/// deserializer:
/// In the serializer, we pre-assign a value ID in order, to each basic block
/// argument and each SILInstruction that has a value.
/// In the deserializer, we create a PlaceholderValue for a forward-referenced
/// value (a value that is used but not yet defined). LocalValues are updated in
/// setLocalValue where the ID passed in assumes the same ordering as in
/// serializer: in-order for each basic block argument and each SILInstruction
/// that has a value.
/// When a forward-referenced value is defined, it replaces the PlaceholderValue
/// in LocalValues.
void SILDeserializer::setLocalValue(ValueBase *Value, ValueID Id) {
  ValueBase *&Entry = LocalValues[Id];

  if (auto *placeholder = dyn_cast_or_null<PlaceholderValue>(Entry)) {
    placeholder->replaceAllUsesWith(Value);
    ::delete placeholder;
  } else {
    assert(!Entry && "We should not redefine the same value.");
  }

  // Store it in our map.
  Entry = Value;
}

SILValue SILDeserializer::getLocalValue(SILFunction *inContext, ValueID Id,
                                        SILType Type) {
  // The first two IDs are special undefined values.
  if (Id == 0) {
    assert(inContext &&
           "Should never have a SILUndef in a global variable initializer?!");
    return SILUndef::get(*inContext, Type);
  }

  assert(Id != 1 && "This used to be for SILUndef with OwnershipKind::Owned... "
                    "but we don't support that anymore. Make sure no one "
                    "changes that without updating this code if needed");

  // Check to see if this is already defined.
  ValueBase *&Entry = LocalValues[Id];
  if (!Entry) {
    // Otherwise, this is a forward reference.  Create a dummy node to represent
    // it until we see a real definition.
    Entry = ::new PlaceholderValue(inContext, Type);
  }
  // If this value was already defined, check it to make sure types match.
  assert(Entry->getType() == Type && "Value Type mismatch?");
  return Entry;
}

/// Return the SILBasicBlock of a given ID.
SILBasicBlock *SILDeserializer::getBBForDefinition(SILFunction *Fn,
                                                   SILBasicBlock *Prev,
                                                   unsigned ID) {
  SILBasicBlock *&BB = BlocksByID[ID];
  // If the block has never been named yet, just create it.
  if (BB == nullptr) {
    if (Prev) {
      BB = Fn->createBasicBlockAfter(Prev);      
    } else {
      BB = Fn->createBasicBlock();
    }
    return BB;
  }

  // If it already exists, it was either a forward reference or a redefinition.
  // The latter should never happen.
  bool wasForwardReferenced = UndefinedBlocks.erase(BB);
  assert(wasForwardReferenced);
  (void)wasForwardReferenced;

  if (Prev)
    Fn->moveBlockAfter(BB, Prev);
  return BB;
}

/// Return the SILBasicBlock of a given ID.
SILBasicBlock *SILDeserializer::getBBForReference(SILFunction *Fn,
                                                  unsigned ID) {
  SILBasicBlock *&BB = BlocksByID[ID];
  if (BB != nullptr)
    return BB;

  // Otherwise, create it and remember that this is a forward reference
  BB = Fn->createBasicBlock();
  UndefinedBlocks[BB] = ID;
  return BB;
}

/// Helper function to convert from Type to SILType.
SILType SILDeserializer::getSILType(Type Ty, SILValueCategory Category,
                                    SILFunction *inContext) {
  auto TyLoc = TypeLoc::withoutLoc(Ty);
  if (!inContext) {
    return SILType::getPrimitiveType(TyLoc.getType()->getCanonicalType(),
                                     Category);
  }
  return inContext->getLoweredType(TyLoc.getType()->getCanonicalType())
      .getCategoryType(Category);
}

llvm::Expected<unsigned>
SILDeserializer::readNextRecord(SmallVectorImpl<uint64_t> &scratch) {
  scratch.clear();
  llvm::Expected<llvm::BitstreamEntry> maybeEntry =
      SILCursor.advance(AF_DontPopBlockAtEnd);
  if (!maybeEntry)
    return maybeEntry.takeError();
  llvm::BitstreamEntry entry = maybeEntry.get();

  // EndBlock means the end of this SILFunction.
  assert(entry.Kind != llvm::BitstreamEntry::EndBlock);
  llvm::Expected<unsigned> maybeKind = SILCursor.readRecord(entry.ID, scratch);
  return maybeKind;
}

llvm::Expected<std::optional<SILLocation>>
SILDeserializer::readLoc(unsigned kind, SmallVectorImpl<uint64_t> &scratch) {
  unsigned LocationKind, Implicit = 0;
  SILLocation::FilenameAndLocation *FNameLoc = nullptr;
  // Each SourceLoc opaque pointer is serialized once. Successive appearences
  // are serialized as references to earlier serializations, with LocID as the
  // indexing key
  if (kind == SIL_SOURCE_LOC_REF) {
    ValueID LocID;
    SourceLocRefLayout::readRecord(scratch, LocID, LocationKind, Implicit);
    if (LocID == 0)
      return std::optional<SILLocation>();
    if (LocID > ParsedLocs.size())
      return llvm::createStringError("Source location reference out of range\n");
    FNameLoc = ParsedLocs[LocID - 1];
  } else {
    ValueID Row = 0, Col = 0, FNameID = 0;
    SourceLocLayout::readRecord(scratch, Row, Col, FNameID, LocationKind,
                                Implicit);

    FNameLoc = SILLocation::FilenameAndLocation::alloc(
        Row, Col, MF->getIdentifierText(FNameID), SILMod);

    ParsedLocs.push_back(FNameLoc);
  }

  switch (LocationKind) {
  case SILLocation::ReturnKind:
    return ReturnLocation(FNameLoc, Implicit);
  case SILLocation::ImplicitReturnKind:
    return ImplicitReturnLocation(FNameLoc, Implicit);
  case SILLocation::InlinedKind:
  case SILLocation::MandatoryInlinedKind:
  case SILLocation::CleanupKind:
  case SILLocation::ArtificialUnreachableKind:
  case SILLocation::RegularKind:
    return RegularLocation(FNameLoc, Implicit);
  }

  // LocationKind was not a recognized SILLocation::LocationKind.
  return std::nullopt;
}

llvm::Expected<const SILDebugScope *>
SILDeserializer::readDebugScopes(SILFunction *F,
                                 SmallVectorImpl<uint64_t> &scratch,
                                 SILBuilder &Builder, unsigned kind) {

  if (kind == SIL_DEBUG_SCOPE_REF) {
    ValueID ScopeID;
    SILDebugScopeRefLayout::readRecord(scratch, ScopeID);
    auto it = ParsedScopes.find(ScopeID);
    if (it == ParsedScopes.end())
      return llvm::createStringError("Referenced debug scope not found\n");
    return it->second;
  }

  BCOffsetRAII restoreOffset(SILCursor);
  const SILDebugScope *Scope = nullptr;
  do {
    ValueID ParentID = 0, InlinedID = 0, Row = 0, Column = 0, FName = 0;
    TypeID FuncType = 0;
    unsigned FuncCategory = 0;
    unsigned isFuncParent = false;

    SILDebugScopeLayout::readRecord(scratch, isFuncParent, ParentID, InlinedID,
                                    Row, Column, FName, FuncType, FuncCategory);
    assert(ParentID);

    PointerUnion<const SILDebugScope *, SILFunction *> Parent = nullptr;
    const SILDebugScope *InlinedCallSite = nullptr;

    std::optional<SILLocation> Loc;
    if (!Row && !Column && !FName)
      Loc = SILLocation::invalid();
    else
      Loc = RegularLocation(SILLocation::FilenameAndLocation::alloc(
          Row, Column, MF->getIdentifierText(FName), SILMod));

    if (isFuncParent) {
      Parent = getFuncForReference(MF->getIdentifierText(ParentID), true);
      assert(Parent);
    } else {
      if (ParsedScopes.find(ParentID) == ParsedScopes.end())
        return llvm::createStringError("Parent debug scope not found\n");
      Parent = ParsedScopes[ParentID];
    }

    if (InlinedID) {
      if (ParsedScopes.find(InlinedID) == ParsedScopes.end())
        return llvm::createStringError("Inlined at debug scope not found\n");
      InlinedCallSite = ParsedScopes[InlinedID];
    }

    if (isFuncParent)
      Scope = new (SILMod) SILDebugScope(
          Loc.value(), cast<SILFunction *>(Parent), nullptr, InlinedCallSite);
    else
      Scope = new (SILMod)
          SILDebugScope(Loc.value(), nullptr,
                        cast<const SILDebugScope *>(Parent), InlinedCallSite);

    ParsedScopes.insert({ParsedScopes.size() + 1, Scope});

    //  Fetch the next record.
    auto maybeKind = readNextRecord(scratch);

    if (!maybeKind)
      return maybeKind.takeError();

    kind = maybeKind.get();
    // restore the offset after last sil debug scope
    if (kind == SIL_DEBUG_SCOPE)
      restoreOffset.reset();

  } while (kind == SIL_DEBUG_SCOPE);

  assert(Scope);
  return Scope;
}

/// Helper function to find a SILDifferentiabilityWitness, given its mangled
/// key.
SILDifferentiabilityWitness *
SILDeserializer::getSILDifferentiabilityWitnessForReference(
    StringRef mangledKey) {
  // Check to see if we have a witness under this key already.
  auto *witness = SILMod.lookUpDifferentiabilityWitness(mangledKey);
  if (witness)
    return witness;
  // Otherwise, look for a witness under this key in the module.
  if (!DifferentiabilityWitnessList)
    return nullptr;
  auto iter = DifferentiabilityWitnessList->find(mangledKey);
  if (iter == DifferentiabilityWitnessList->end())
    return nullptr;
  return readDifferentiabilityWitness(*iter);
}

/// Helper function to find a SILFunction, given its name and type.
SILFunction *SILDeserializer::getFuncForReference(StringRef name,
                                                  SILType type,
                                                  TypeExpansionContext context) {
  // Check to see if we have a function by this name already.
  SILFunction *fn = SILMod.lookUpFunction(name);
  if (!fn) {
    // Otherwise, look for a function with this name in the module.
    auto iter = FuncTable->find(name);
    if (iter != FuncTable->end()) {
      auto maybeFn = readSILFunctionChecked(*iter, nullptr, name,
                                            /*declarationOnly*/ true);
      if (maybeFn) {
        fn = maybeFn.get();
      } else {
        // Ignore the failure; we'll synthesize a bogus function instead.
        llvm::consumeError(maybeFn.takeError());
      }
    }
  }

  // At this point, if fn is set, we know that we have a good function to use.
  if (fn) {
    SILType fnType = fn->getLoweredTypeInContext(context);
    if (fnType != type &&
        // It can happen that opaque return types cause a mismatch when merging
        // modules, without causing any further assertion failures.
        // TODO: fix the underlying problem
        fnType.hasOpaqueArchetype() == type.hasOpaqueArchetype()) {
      StringRef fnName = fn->getName();
      if (auto *dc = fn->getDeclContext()) {
        if (auto *decl = dyn_cast_or_null<AbstractFunctionDecl>(dc->getAsDecl()))
          fnName = decl->getNameStr();
      }
      auto &diags = fn->getModule().getASTContext().Diags;
      diags.diagnose(fn->getLocation().getSourceLoc(),
                     diag::deserialize_function_type_mismatch,
                     fnName, fnType.getASTType(), type.getASTType());
      diags.flushConsumers();
      exit(1);
    }
    return fn;
  }

  // Otherwise, create a function declaration with the right type and a bogus
  // source location. This ensures that we can at least parse the rest of the
  // SIL.
  SourceLoc sourceLoc;
  SILSerializationFunctionBuilder builder(SILMod);
  fn = builder.createDeclaration(name, type,
                                 RegularLocation(sourceLoc));
  // This declaration stands in for a function whose body we could not
  // deserialize (e.g. it referenced a Clang declaration broken by a context
  // change). It has no body, so give it external linkage; otherwise the
  // `didDeserialize` linkage update below would try to externalize a private
  // definition and assert.
  fn->setLinkage(SILLinkage::PublicExternal);
  // The function is not really de-serialized, but it's important to call
  // `didDeserialize` on every new function. Otherwise some Analysis might miss
  // `notifyAddedOrModifiedFunction` notifications.
  if (Callback)
    Callback->didDeserialize(MF->getAssociatedModule(), fn);
  return fn;
}

/// Helper function to find a SILFunction, given its name and type.
SILFunction *SILDeserializer::getFuncForReference(StringRef name,
                                                  bool forDebugScope) {
  // Check to see if we have a function by this name already.
  SILFunction *fn = SILMod.lookUpFunction(name);
  if (fn)
    return fn;

  // Otherwise, look for a function with this name in the module.
  auto iter = FuncTable->find(name);

  if (iter == FuncTable->end())
    return nullptr;

  auto maybeFn =
      readSILFunctionChecked(*iter, nullptr, name,
                             /*declarationOnly*/ true, true, forDebugScope);
  if (!maybeFn) {
    // Ignore the failure and just pretend the function doesn't exist
    llvm::consumeError(maybeFn.takeError());
    return nullptr;
  }

  return maybeFn.get();
}

/// Helper function to find a SILGlobalVariable given its name. It first checks
/// in the module. If we cannot find it in the module, we attempt to
/// deserialize it.
SILGlobalVariable *
SILDeserializer::getGlobalForReference(StringRef name, bool byAsmName) {
  // Check to see if we have a global by this name already.
  if (SILGlobalVariable *g = SILMod.lookUpGlobalVariable(name, byAsmName))
    return g;

  // Otherwise, look for a global with this name in the module.
  return readGlobalVar(name);
}

/// Deserialize a SILFunction if it is not already deserialized. The input
/// SILFunction can either be an empty declaration or null. If it is an empty
/// declaration, we fill in the contents. If the input SILFunction is
/// null, we create a SILFunction.
SILFunction *SILDeserializer::readSILFunction(DeclID FID,
                                              SILFunction *existingFn,
                                              StringRef name,
                                              bool declarationOnly,
                                              bool errorIfEmptyBody) {
  llvm::Expected<SILFunction *> deserialized =
      readSILFunctionChecked(FID, existingFn, name, declarationOnly,
                             errorIfEmptyBody);
  if (!deserialized) {
    MF->fatal(deserialized.takeError());
  }
  return deserialized.get();
}

llvm::Expected<SILFunction *> SILDeserializer::readSILFunctionChecked(
    DeclID FID, SILFunction *existingFn, StringRef name, bool declarationOnly,
    bool errorIfEmptyBody, bool forDebugScope) {
  // We can't deserialize function bodies after IRGen lowering passes have
  // happened since other definitions in the module will no longer be in
  // canonical SIL form.
  assert(!forDebugScope || declarationOnly); // debug scopes must always be read
                                             // declaration only
  switch (SILMod.getStage()) {
  case SILStage::Raw:
  case SILStage::Canonical:
    break;
    
  case SILStage::Lowered:
    // Allow declarations to be loaded from IRGen. This can happen if IRGen
    // loads a SIL Vtable from the modulefile.
    if (!declarationOnly) {
      llvm_unreachable("cannot deserialize into a module that has entered "
                       "Lowered stage");
    }
    break;
  }
  
  if (FID == 0)
    return nullptr;
  assert(FID <= Funcs.size() && "invalid SILFunction ID");

  PrettyStackTraceStringAction trace("deserializing SIL function", name);

  auto &cacheEntry = Funcs[FID - 1];

  if (cacheEntry.isFullyDeserialized() ||
      (cacheEntry.isDeserialized() && declarationOnly)) {
    auto fn = cacheEntry.get();

    // Functions onlyReferencedByDebugInfo (A) are a subset of functions
    // referred to by debug scopes forDebugScope=true (B)

    // I) Functions in A U B only ever get deserialized as zombies

    // II) For rest of functions (B - A), there are two orders of
    // deserialization:
    //  i) Deserialized for debugging -> deserialized by linker/optimizer:
    //    a) Deserialize as zombie. When referenced by linker/optimizer,
    //    createDeclaration would resurrect function as normal
    //  ii) Deserialized by linker/optimizer -> deserialized for debugging ->
    //  no zombie created

    if (fn->isZombie() && !forDebugScope) {
      if (cacheEntry.isFullyDeserialized())
        return nullptr;
      // else function resurrected below by createDeclaration
    } else {
      return fn;
    }
  }

  BCOffsetRAII restoreOffset(SILCursor);
  if (llvm::Error Err = SILCursor.JumpToBit(cacheEntry.getOffset()))
    return std::move(Err);

  llvm::Expected<llvm::BitstreamEntry> maybeEntry =
      SILCursor.advance(AF_DontPopBlockAtEnd);
  if (!maybeEntry)
    return maybeEntry.takeError();
  llvm::BitstreamEntry entry = maybeEntry.get();
  if (entry.Kind == llvm::BitstreamEntry::Error)
    return MF->diagnoseFatal("Cursor advance error in readSILFunction");

  SmallVector<uint64_t, 64> scratch;
  StringRef blobData;
  llvm::Expected<unsigned> maybeKind =
      SILCursor.readRecord(entry.ID, scratch, &blobData);
  if (!maybeKind)
    return MF->diagnoseFatal(maybeKind.takeError());
  unsigned kind = maybeKind.get();
  assert(kind == SIL_FUNCTION && "expect a sil function");
  (void)kind;

  DeclID clangNodeOwnerID;
  ModuleID parentModuleID;
  TypeID funcTyID;
  IdentifierID replacedFunctionID;
  IdentifierID usedAdHocWitnessFunctionID;
  GenericSignatureID genericSigID;
  unsigned rawLinkage, isTransparent, serializedKind, isThunk,
      isWithoutActuallyEscapingThunk, specialPurpose, inlineStrategy,
      optimizationMode, perfConstr, subclassScope, hasCReferences,
      markedAsUsed, effect, numAttrs, hasQualifiedOwnership, isWeakImported,
      codeGenerationModel,
      LIST_VER_TUPLE_PIECES(available), isDynamic, isExactSelfClass,
      isDistributed, isRuntimeAccessible, forceEnableLexicalLifetimes,
      onlyReferencedByDebugInfo;
  ArrayRef<uint64_t> SemanticsIDs;
  SILFunctionLayout::readRecord(
      scratch, rawLinkage, isTransparent, serializedKind, isThunk,
      isWithoutActuallyEscapingThunk, specialPurpose, inlineStrategy,
      optimizationMode, perfConstr, subclassScope, hasCReferences, markedAsUsed,
      effect, numAttrs, hasQualifiedOwnership, isWeakImported,
      codeGenerationModel,
      LIST_VER_TUPLE_PIECES(available), isDynamic, isExactSelfClass,
      isDistributed, isRuntimeAccessible, forceEnableLexicalLifetimes,
      onlyReferencedByDebugInfo, funcTyID, replacedFunctionID,
      usedAdHocWitnessFunctionID, genericSigID, clangNodeOwnerID,
      parentModuleID, SemanticsIDs);

  if (funcTyID == 0)
    return MF->diagnoseFatal("SILFunction typeID is 0");

  // A function with [serialized_for_package] and its body should only be
  // deserialized in clients within the same package as its defining module;
  // for external clients, it should appear only as a declaration. If the
  // function has shared linkage, it must have been internal or private in
  // its defining module that's optimized, thus should remain inaccessible
  // outside the package boundary. This ensures that instructions, which may
  // only be valid in resilient mode when package optimization is enabled,
  // aren't inlined at the call site, preventing potential assert fails during
  // sil-verify.
  if (serializedKind == SerializedKind_t::IsSerializedForPackage) {
    if (!SILMod.getSwiftModule()->inSamePackage(getFile()->getParentModule())) {
      if (rawLinkage == (unsigned int)(SILLinkage::Shared))
        return nullptr;
      if (!declarationOnly)
        declarationOnly = true;
    }
  }

  auto astType = MF->getTypeChecked(funcTyID);
  if (!astType) {
    if (!existingFn || errorIfEmptyBody) {
      return llvm::make_error<SILEntityError>(
          name, takeErrorInfo(astType.takeError()));
    }
    consumeError(astType.takeError());
    return existingFn;
  }
  auto ty = getSILType(astType.get(), SILValueCategory::Object, nullptr);
  if (!ty.is<SILFunctionType>())
    return MF->diagnoseFatal("not a function type for SILFunction");

  SILFunction *replacedFunction = nullptr;
  Identifier replacedObjectiveCFunc;
  if (replacedFunctionID &&
      ty.getAs<SILFunctionType>()->getExtInfo().getRepresentation() !=
          SILFunctionTypeRepresentation::ObjCMethod) {
    replacedFunction =
        getFuncForReference(MF->getIdentifier(replacedFunctionID).str());
  } else if (replacedFunctionID) {
    replacedObjectiveCFunc = MF->getIdentifier(replacedFunctionID);
  }

  SILFunction *usedAdHocWitnessFunction = nullptr;
  if (usedAdHocWitnessFunctionID) {
    auto usedAdHocWitnessFunctionStr =
        MF->getIdentifier(usedAdHocWitnessFunctionID).str();
    usedAdHocWitnessFunction = getFuncForReference(usedAdHocWitnessFunctionStr);
  }

  // don't want to load and return zombie if not for debugging
  if (onlyReferencedByDebugInfo && !forDebugScope)
    return nullptr;

  auto linkageOpt = fromStableSILLinkage(rawLinkage);
  if (!linkageOpt) {
    LLVM_DEBUG(llvm::dbgs() << "invalid linkage code " << rawLinkage
                            << " for SILFunction\n");
    return MF->diagnoseFatal("invalid linkage code");
  }
  SILLinkage linkage = linkageOpt.value();

  ValueDecl *clangNodeOwner = nullptr;
  if (clangNodeOwnerID != 0) {
    auto clangNodeOwnerOrErr = MF->getDeclChecked(clangNodeOwnerID);
    if (!clangNodeOwnerOrErr) {
      // Emit the diagnostic (e.g. a modularization issue such as a referenced
      // Clang declaration changing kind) without aborting, then fail this SIL
      // function read so the caller can recover.
      MF->diagnoseAndConsumeFatal(clangNodeOwnerOrErr.takeError());
      return MF->createFatalError();
    }
    clangNodeOwner = dyn_cast_or_null<ValueDecl>(clangNodeOwnerOrErr.get());
    if (!clangNodeOwner)
      return MF->diagnoseFatal("invalid clang node owner for SILFunction");
  }

  // If we weren't handed a function, check for an existing
  // declaration in the output module.
  if (!existingFn) existingFn = SILMod.lookUpFunction(name);
  assert(!existingFn || !existingFn->isZombie());
  auto fn = existingFn;

  // if is debug and we have declaration, we don't care about deserialization
  if (fn && forDebugScope)
    return fn;

  // TODO: use the correct SILLocation from module.
  SILLocation loc = RegularLocation::getAutoGeneratedLocation();

  // If we've already serialized the module, don't mark the function
  // as serialized, since we no longer need to enforce resilience
  // boundaries.
  if (SILMod.isSerialized())
    serializedKind = IsNotSerialized;

  SILSerializationFunctionBuilder builder(SILMod);

  // If we have an existing function, verify that the types match up.
  if (fn) {
    assert(!forDebugScope);

    if (fn->getLoweredType() != ty) {
      auto error = llvm::make_error<SILFunctionTypeMismatch>(
                     name,
                     fn->getLoweredType().getDebugDescription(),
                     ty.getDebugDescription());
      return MF->diagnoseFatal(std::move(error));
    }

    fn->setSerializedKind(SerializedKind_t(serializedKind));

    // If the serialized function comes from the same module, we're merging
    // modules, and can update the linkage directly. This is needed to
    // correctly update the linkage for forward declarations to entities defined
    // in another file of the same module – we want to ensure the linkage
    // reflects the fact that the entity isn't really external and shouldn't be
    // dropped from the resulting merged module.
    if (getFile()->getParentModule() == SILMod.getSwiftModule())
      fn->setLinkage(linkage);

    // Don't override the transparency or linkage of a function with
    // an existing declaration, except if we deserialized a
    // PublicNonABI function, which has HiddenExternal when
    // referenced as a declaration, and Shared when it has
    // a deserialized body.
    if (isAvailableExternally(fn->getLinkage())) {
      switch (linkage) {
      case SILLinkage::PublicNonABI:
      case SILLinkage::PackageNonABI:
      case SILLinkage::Shared:
        fn->setLinkage(SILLinkage::Shared);
        break;
      case SILLinkage::Public:
      case SILLinkage::Package:
      case SILLinkage::Hidden:
      case SILLinkage::Private:
      case SILLinkage::PublicExternal:
      case SILLinkage::PackageExternal:
      case SILLinkage::HiddenExternal:
        if (hasPublicVisibility(linkage)) {
          // Cross-module-optimization can change the linkage to public. In this
          // case we need to update the linkage of the function (which is
          // originally just derived from the AST).
          fn->setLinkage(SILLinkage::PublicExternal);
        }
        break;
      }
    }

    if (fn->isDynamicallyReplaceable() != isDynamic)
      return MF->diagnoseFatal("SILFunction dynamic replaceable mismatch");

  } else {
    // Otherwise, create a new function.
    fn = builder.createDeclaration(name, ty, loc);

    // TODO: for functions deserialized for debug scopes, set linkage to private
    // as public symbols make into the final binary even when zombies?
    fn->setLinkage(forDebugScope ? SILLinkage::Private : linkage);
    fn->setTransparent(IsTransparent_t(isTransparent == 1));
    fn->setSerializedKind(SerializedKind_t(serializedKind));
    fn->setThunk(IsThunk_t(isThunk));
    fn->setWithoutActuallyEscapingThunk(bool(isWithoutActuallyEscapingThunk));
    fn->setInlineStrategy(Inline_t(inlineStrategy));
    fn->setSpecialPurpose(SILFunction::Purpose(specialPurpose));
    fn->setEffectsKind(EffectsKind(effect));
    fn->setOptimizationMode(OptimizationMode(optimizationMode));
    fn->setPerfConstraints((PerformanceConstraints)perfConstr);
    fn->setIsAlwaysWeakImported(isWeakImported);
    if (codeGenerationModel) {
      fn->setCodeGenerationModel(static_cast<CodeGenerationModel>(codeGenerationModel - 1));
    } else {
      fn->setCodeGenerationModel(std::nullopt);
    }
    fn->setClassSubclassScope(SubclassScope(subclassScope));
    fn->setHasCReferences(bool(hasCReferences));
    fn->setMarkedAsUsed(bool(markedAsUsed));

    llvm::VersionTuple available;
    DECODE_VER_TUPLE(available);
    fn->setAvailabilityForLinkage(available.empty()
                                      ? AvailabilityRange::alwaysAvailable()
                                      : AvailabilityRange(available));

    fn->setIsDynamic(IsDynamicallyReplaceable_t(isDynamic));
    fn->setIsExactSelfClass(IsExactSelfClass_t(isExactSelfClass));
    fn->setIsDistributed(IsDistributed_t(isDistributed));
    fn->setIsRuntimeAccessible(IsRuntimeAccessible_t(isRuntimeAccessible));
    fn->setForceEnableLexicalLifetimes(
        ForceEnableLexicalLifetimes_t(forceEnableLexicalLifetimes));
    if (replacedFunction)
      fn->setDynamicallyReplacedFunction(replacedFunction);
    if (!replacedObjectiveCFunc.empty())
      fn->setObjCReplacement(replacedObjectiveCFunc);
    if (usedAdHocWitnessFunction)
      fn->setReferencedAdHocRequirementWitnessFunction(usedAdHocWitnessFunction);
    if (clangNodeOwner)
      fn->setClangNodeOwner(clangNodeOwner);
    for (auto ID : SemanticsIDs) {
      fn->addSemanticsAttr(MF->getIdentifierText(ID));
    }
    if (forDebugScope)
      SILMod.eraseFunction(fn);
    if (Callback && !forDebugScope)
      Callback->didDeserialize(MF->getAssociatedModule(), fn);
  }

  // First before we do /anything/ validate that our function is truly empty.
  assert(fn->empty() && "SILFunction to be deserialized starts being empty.");

  // Given that our original function was empty, just match the deserialized
  // function. Ownership doesn't really have a meaning without a body.
  builder.setHasOwnership(fn, hasQualifiedOwnership);

  // Mark this function as deserialized. This avoids rerunning diagnostic
  // passes. Certain passes in the mandatory pipeline may not work as expected
  // after arbitrary optimization and lowering.
  if (!MF->isSIB())
    fn->setWasDeserializedCanonical();

  fn->setBare(IsBare);
  if (!fn->getDebugScope()) {
    const SILDebugScope *DS = new (SILMod) SILDebugScope(loc, fn);
    fn->setDebugScope(DS);
  }

  // If we don't already have a DeclContext to use to find a parent module,
  // attempt to deserialize a parent module reference directly.
  if (!fn->getDeclContext() && parentModuleID)
    fn->setParentModule(MF->getModule(parentModuleID));

  // Read and instantiate the specialize attributes.
  bool shouldAddSpecAttrs = fn->getSpecializeAttrs().empty();
  bool shouldAddEffectAttrs = !fn->hasArgumentEffects();
  StringRef WasmImportModule;
  StringRef WasmImportField;
  for (unsigned attrIdx = 0; attrIdx < numAttrs; ++attrIdx) {
    llvm::Expected<llvm::BitstreamEntry> maybeNext =
        SILCursor.advance(AF_DontPopBlockAtEnd);
    if (!maybeNext)
      return maybeNext.takeError();
    llvm::BitstreamEntry next = maybeNext.get();
    assert(next.Kind == llvm::BitstreamEntry::Record);

    scratch.clear();
    StringRef blobData;
    llvm::Expected<unsigned> maybeKind = SILCursor.readRecord(next.ID, scratch,
                                                              &blobData);
    if (!maybeKind)
      return maybeKind.takeError();
    unsigned kind = maybeKind.get();
    
    if (kind == SIL_ARG_EFFECTS_ATTR) {
      IdentifierID effectID;
      unsigned isDerived;
      unsigned isGlobalSideEffects;
      unsigned argumentIndex;
      SILArgEffectsAttrLayout::readRecord(scratch, effectID, argumentIndex,
                                          isGlobalSideEffects, isDerived);
      if (shouldAddEffectAttrs) {
        StringRef effectStr = MF->getIdentifierText(effectID);
        std::pair<const char *, int> error;
        if (isGlobalSideEffects) {
          error = fn->parseGlobalEffectsFromSIL(effectStr);
        } else {
          error = fn->parseArgumentEffectsFromSIL(effectStr, (int)argumentIndex);
        }
        (void)error;
        assert(!error.first && "effects deserialization error");
      }
      continue;
    }

    if (kind == SIL_EXTRA_STRING) {
      unsigned stringFlavor;
      SILExtraStringLayout::readRecord(scratch, stringFlavor);

      switch (static_cast<ExtraStringFlavor>(stringFlavor)) {
      case ExtraStringFlavor::AsmName:
        fn->setAsmName(blobData);
        break;
      case ExtraStringFlavor::Section:
        fn->setSection(blobData);
        break;
      case ExtraStringFlavor::WasmImportModule:
        WasmImportModule = blobData;
        break;
      case ExtraStringFlavor::WasmImportName:
        WasmImportField = blobData;
        break;
      }
      continue;
    }

    assert(kind == SIL_SPECIALIZE_ATTR && "Missing specialization attribute");

    unsigned exported;
    unsigned specializationKindVal;
    GenericSignatureID specializedSigID;
    IdentifierID targetFunctionID;
    IdentifierID spiGroupID;
    ModuleID spiModuleID;
    ArrayRef<uint64_t> typeErasedParamsIDs;
    unsigned LIST_VER_TUPLE_PIECES(available);
    SILSpecializeAttrLayout::readRecord(
        scratch, exported, specializationKindVal, specializedSigID,
        targetFunctionID, spiGroupID, spiModuleID,
        LIST_VER_TUPLE_PIECES(available), typeErasedParamsIDs);

    SILFunction *target = nullptr;
    if (targetFunctionID) {
      target = getFuncForReference(MF->getIdentifier(targetFunctionID).str());
    }

    Identifier spiGroup;
    const ModuleDecl *spiModule = nullptr;
    if (spiGroupID) {
      spiGroup = MF->getIdentifier(spiGroupID);
      spiModule = MF->getModule(spiModuleID);
    }

    SILSpecializeAttr::SpecializationKind specializationKind =
        specializationKindVal ? SILSpecializeAttr::SpecializationKind::Partial
                              : SILSpecializeAttr::SpecializationKind::Full;

    llvm::VersionTuple available;
    DECODE_VER_TUPLE(available);
    auto availability = available.empty() ? AvailabilityRange::alwaysAvailable()
                                          : AvailabilityRange(available);

    llvm::SmallVector<Type, 4> typeErasedParams;
    for (auto id : typeErasedParamsIDs) {
      typeErasedParams.push_back(MF->getType(id));
    }

    auto specializedSig = MF->getGenericSignature(specializedSigID);
    // Only add the specialize attributes once.
    if (shouldAddSpecAttrs) {
      // Read the substitution list and construct a SILSpecializeAttr.
      fn->addSpecializeAttr(SILSpecializeAttr::create(
          SILMod, specializedSig, typeErasedParams,
          exported != 0, specializationKind, target,
          spiGroup, spiModule, availability));
    }
  }

  // If either wasm import attribute was present, record both even if one is
  // empty.
  if (!WasmImportModule.empty() || !WasmImportField.empty())
    fn->setWasmImportModuleAndField(WasmImportModule, WasmImportField);

  GenericEnvironment *genericEnv = nullptr;
  // Generic signatures are stored for declarations as well in a debug context.
  if (!declarationOnly || onlyReferencedByDebugInfo || genericSigID)
    genericEnv = MF->getGenericSignature(genericSigID).getGenericEnvironment();

  // If the next entry is the end of the block, then this function has
  // no contents.
  maybeEntry = SILCursor.advance(AF_DontPopBlockAtEnd);
  if (!maybeEntry)
    return maybeEntry.takeError();
  entry = maybeEntry.get();
  bool isEmptyFunction = (entry.Kind == llvm::BitstreamEntry::EndBlock);
  assert((!isEmptyFunction || !genericEnv || onlyReferencedByDebugInfo ||
        genericSigID) && "generic environment without body?!");

  // Remember this in our cache in case it's a recursive function.
  // Increase the reference count to keep it alive.
  bool isFullyDeserialized =
      (isEmptyFunction || !declarationOnly || onlyReferencedByDebugInfo);
  if (cacheEntry.isDeserialized()) {
    assert(fn == cacheEntry.get() && "changing SIL function during deserialization!");
  } else {
    fn->incrementRefCount();
  }
  cacheEntry.set(fn, isFullyDeserialized);

  // Stop here if we have nothing else to do.
  if (isEmptyFunction || declarationOnly) {
    if (genericEnv)
      fn->setGenericEnvironment(genericEnv);
    return fn;
  }

  ++NumDeserializedFunc;

  assert(!(fn->getGenericEnvironment() && !fn->empty())
         && "function already has context generic params?!");
  if (genericEnv)
    fn->setGenericEnvironment(genericEnv);

  scratch.clear();
  maybeKind = SILCursor.readRecord(entry.ID, scratch);
  if (!maybeKind)
    return maybeKind.takeError();
  kind = maybeKind.get();

  SILBasicBlock *CurrentBB = nullptr;

  // Clear up at the beginning of each SILFunction.
  BasicBlockID = 0;
  BlocksByID.clear();
  UndefinedBlocks.clear();
  ParsedScopes.clear();
  ParsedLocs.clear();

  // The first two IDs are reserved for SILUndef.
  LastValueID = 1;
  LocalValues.clear();

  SILBuilder Builder(*fn);

  // Worklist of debug_value instructions that have reconstruction blocks.
  // Populated during instruction deserialization and consumed when matching
  // trailing SIL_DEBUG_RECONSTRUCTION_BLOCK records.
  SmallVector<DebugValueInst *, 4> DebugBBWorklist;
  unsigned DebugBBWorklistIdx = 0;

  // Another SIL_FUNCTION record means the end of this SILFunction.
  // SIL_VTABLE or SIL_GLOBALVAR or SIL_WITNESS_TABLE record also means the end
  // of this SILFunction.
  bool isFirstScope = true;
  Builder.setCurrentDebugScope(fn->getDebugScope());
  while (kind != SIL_FUNCTION && kind != SIL_VTABLE && kind != SIL_GLOBALVAR &&
         kind != SIL_MOVEONLY_DEINIT && kind != SIL_WITNESS_TABLE &&
         kind != SIL_DEFAULT_OVERRIDE_TABLE &&
         kind != SIL_DIFFERENTIABILITY_WITNESS) {
    if (kind == SIL_BASIC_BLOCK)
      // Handle a SILBasicBlock record.
      CurrentBB = readSILBasicBlock(fn, CurrentBB, scratch);
    else if (kind == SIL_DEBUG_SCOPE || kind == SIL_DEBUG_SCOPE_REF) {
      auto maybeScope = readDebugScopes(fn, scratch, Builder, kind);
      if (!maybeScope)
        return maybeScope.takeError();

      auto Scope = maybeScope.get();
      if (isFirstScope) {
        if (!fn->getDebugScope() || fn->getDebugScope()->getLoc().isAutoGenerated())
          fn->setDebugScope(Scope);
        isFirstScope = false;
      }
      Builder.setCurrentDebugScope(Scope);
    } else if (kind == SIL_SOURCE_LOC || kind == SIL_SOURCE_LOC_REF) {
      auto Loc = readLoc(kind, scratch);
      if (!Loc)
        return Loc.takeError();
      Builder.applyDebugLocOverride(Loc.get());
    } else if (kind == SIL_DEBUG_RECONSTRUCTION_BLOCK) {
      CurrentBB = readSILDebugReconstructionBlock(fn, scratch,
                                                    DebugBBWorklist,
                                                    DebugBBWorklistIdx);
    } else {
      // If CurrentBB is empty, just return fn. The code in readSILInstruction
      // assumes that such a situation means that fn is a declaration. Thus it
      // is using return false to mean two different things, error a failure
      // occurred and this is a declaration. Work around that for now.
      if (!CurrentBB)
        return fn;
      Builder.setInsertionPoint(CurrentBB);

      // Handle a SILInstruction record.
      if (readSILInstruction(fn, Builder, kind, scratch, DebugBBWorklist))
        return MF->diagnoseFatal("readSILInstruction returns error");

      // If readSILInstruction just produced an apply whose record carried
      // HasArgumentLocs=1, NumArguments source-loc records follow inline.
      // Decode them via the shared readLoc path and stamp each onto the
      // apply (overwriting the placeholder anchor locations the apply
      // ctor seeded with). The bit on the apply record is the only
      // signal — there is no separate marker record.
      if (!CurrentBB->empty()) {
        auto applySite = ApplySite::isa(&CurrentBB->back());
        if (applySite && applySite.getArgumentLocs()) {
          for (unsigned i = 0, e = applySite.getNumArguments(); i != e; ++i) {
            scratch.clear();
            auto maybeNext = SILCursor.advance(AF_DontPopBlockAtEnd);
            if (!maybeNext)
              return maybeNext.takeError();
            auto next = maybeNext.get();
            if (next.Kind != llvm::BitstreamEntry::Record)
              return MF->diagnoseFatal(
                  "expected SIL_SOURCE_LOC record while deserializing "
                  "per-argument apply locations");
            auto maybeRecKind = SILCursor.readRecord(next.ID, scratch);
            if (!maybeRecKind)
              return maybeRecKind.takeError();
            unsigned recKind = maybeRecKind.get();
            if (recKind != SIL_SOURCE_LOC && recKind != SIL_SOURCE_LOC_REF)
              return MF->diagnoseFatal(
                  "unexpected record kind in per-argument apply locations");
            auto maybeLoc = readLoc(recKind, scratch);
            if (!maybeLoc)
              return maybeLoc.takeError();
            // A null SILLocation is encoded as a SIL_SOURCE_LOC_REF with
            // LocID=0; leave the placeholder anchor in place for those.
            if (auto loc = maybeLoc.get())
              applySite.setArgumentLoc(i, *loc);
          }
        }
      }
    }

    // Fetch the next record.
    scratch.clear();
    llvm::Expected<llvm::BitstreamEntry> maybeEntry =
        SILCursor.advance(AF_DontPopBlockAtEnd);
    if (!maybeEntry)
      return maybeEntry.takeError();
    llvm::BitstreamEntry entry = maybeEntry.get();

    // EndBlock means the end of this SILFunction.
    if (entry.Kind == llvm::BitstreamEntry::EndBlock)
      break;
    maybeKind = SILCursor.readRecord(entry.ID, scratch);
    if (!maybeKind)
      return maybeKind.takeError();
    kind = maybeKind.get();
  }

  // If fn is empty, we failed to deserialize its body. Return nullptr to signal
  // error.
  if (fn->empty() && errorIfEmptyBody)
    return nullptr;

  // Check that there are no unresolved forward definitions of local
  // archetypes.
  if (SILMod.hasUnresolvedLocalArchetypeDefinitions())
    llvm_unreachable(
        "All forward definitions of local archetypes should be resolved");

  // The de-serialized SIL is assumed to be in a correct state.
  fn->setNeedBreakInfiniteLoops(false);
  fn->setNeedCompleteLifetimes(false);

  if (Callback)
    Callback->didDeserializeFunctionBody(MF->getAssociatedModule(), fn);

  if (!MF->isSIB() && !SILMod.isSerialized()) {
    assert((fn->isAnySerialized() || fn->empty()) &&
           "deserialized function must have the IsSerialized or IsSerializedForPackage flag set");
  }
  return fn;
}

// We put these static asserts here to formalize our assumption that both
// SILValueCategory and ValueOwnershipKind have uint8_t as their underlying
// pointer values.
static_assert(
    std::is_same<std::underlying_type<SILValueCategory>::type, uint8_t>::value,
    "Expected an underlying uint8_t type");
// We put these static asserts here to formalize our assumption that both
// SILValueCategory and ValueOwnershipKind have uint8_t as their underlying
// pointer values.
static_assert(std::is_same<std::underlying_type<OwnershipKind::innerty>::type,
                           uint8_t>::value,
              "Expected an underlying uint8_t type");
SILBasicBlock *SILDeserializer::readSILBasicBlock(SILFunction *Fn,
                                                  SILBasicBlock *Prev,
                                    SmallVectorImpl<uint64_t> &scratch) {
  ArrayRef<uint64_t> Args;
  SILBasicBlockLayout::readRecord(scratch, Args);

  // Args should be a list of triples of the following form:
  //
  // 1. A TypeID.
  // 2. A flag of metadata. This currently includes the SILValueCategory and
  //    ValueOwnershipKind. We enforce size constraints of these types above.
  // 3. A ValueID.
  SILBasicBlock *CurrentBB = getBBForDefinition(Fn, Prev, BasicBlockID++);
  if (readBlockArgs(CurrentBB, Fn, Args))
    return nullptr;
  return CurrentBB;
}

bool SILDeserializer::readBlockArgs(SILBasicBlock *CurrentBB, SILFunction *Fn,
                                    ArrayRef<uint64_t> Args) {
  bool IsEntry = CurrentBB->isEntry();
  for (unsigned I = 0, E = Args.size(); I < E; I += 3) {
    TypeID TyID = Args[I];
    if (!TyID) return true;
    ValueID ValId = Args[I+2];
    if (!ValId) return true;

    auto ArgTy = MF->getType(TyID);
    SILArgument *Arg;
    auto ValueCategory = SILValueCategory(Args[I + 1] & 0xF);
    SILType SILArgTy = getSILType(ArgTy, ValueCategory, Fn);
    auto OwnershipKind = ValueOwnershipKind((Args[I + 1] >> 8) & 0x7);
    auto reborrow = (Args[I + 1] >> 11) & 0x1;
    auto pointerEscape = (Args[I + 1] >> 12) & 0x1;
    if (IsEntry) {
      auto *fArg = CurrentBB->createFunctionArgument(SILArgTy);
      bool isNoImplicitCopy = (Args[I + 1] >> 13) & 0x1;
      fArg->setNoImplicitCopy(isNoImplicitCopy);
      auto lifetime = (LifetimeAnnotation::Case)((Args[I + 1] >> 14) & 0x3);
      fArg->setLifetimeAnnotation(lifetime);
      bool isClosureCapture = (Args[I + 1] >> 16) & 0x1;
      fArg->setClosureCapture(isClosureCapture);
      bool isFormalParameterPack = (Args[I + 1] >> 17) & 0x1;
      fArg->setFormalParameterPack(isFormalParameterPack);
      bool isInferredImmutable = (Args[I + 1] >> 18) & 0x1;
      fArg->setInferredImmutable(isInferredImmutable);
      Arg = fArg;
    } else {
      Arg = CurrentBB->createPhiArgument(SILArgTy, OwnershipKind,
                                         /*decl*/ nullptr, reborrow,
                                         pointerEscape);
    }
    LastValueID = LastValueID + 1;
    setLocalValue(Arg, LastValueID);
  }
  return false;
}

SILBasicBlock *SILDeserializer::readSILDebugReconstructionBlock(
    SILFunction *Fn, SmallVectorImpl<uint64_t> &scratch,
    ArrayRef<DebugValueInst *> DebugBBWorklist, unsigned &DebugBBWorklistIdx) {
  // Clear local values and set up fresh IDs for this debug BB.
  LocalValues.clear();
  LastValueID = 1;

  ArrayRef<uint64_t> Args;
  SILDebugReconstructionBlockLayout::readRecord(scratch, Args);

  auto *DebugBB = Fn->createEmptyDebugReconstructionBlock();
  if (readBlockArgs(DebugBB, Fn, Args))
    return nullptr;

  // Pop the next DVI from the worklist and attach the debug BB.
  if (DebugBBWorklistIdx >= DebugBBWorklist.size())
    return nullptr;
  auto *DVI = DebugBBWorklist[DebugBBWorklistIdx++];
  DVI->setDebugReconstructionBlock(DebugBB);

  return DebugBB;
}

static CastConsumptionKind getCastConsumptionKind(unsigned attr) {
  switch (attr) {
  case SIL_CAST_CONSUMPTION_TAKE_ALWAYS:
    return CastConsumptionKind::TakeAlways;
  case SIL_CAST_CONSUMPTION_TAKE_ON_SUCCESS:
    return CastConsumptionKind::TakeOnSuccess;
  case SIL_CAST_CONSUMPTION_COPY_ON_SUCCESS:
    return CastConsumptionKind::CopyOnSuccess;
  case SIL_CAST_CONSUMPTION_BORROW_ALWAYS:
    return CastConsumptionKind::BorrowAlways;
  default:
    llvm_unreachable("not a valid CastConsumptionKind for SIL");
  }
}

/// Construct a SILDeclRef from ListOfValues.
static SILDeclRef getSILDeclRef(ModuleFile *MF,
                                ArrayRef<uint64_t> ListOfValues,
                                unsigned &NextIdx) {
  assert(ListOfValues.size() >= NextIdx+3 &&
         "Expect 3 numbers for SILDeclRef");
  SILDeclRef DRef(cast<ValueDecl>(MF->getDecl(ListOfValues[NextIdx])),
                  (SILDeclRef::Kind)ListOfValues[NextIdx+1],
                  /*isForeign=*/ListOfValues[NextIdx+2] > 0);
  NextIdx += 3;
  return DRef;
}

std::optional<KeyPathPatternComponent>
SILDeserializer::readKeyPathComponent(ArrayRef<uint64_t> ListOfValues,
                                      unsigned &nextValue) {
  auto kind =
    (KeyPathComponentKindEncoding)ListOfValues[nextValue++];
  
  if (kind == KeyPathComponentKindEncoding::Trivial)
    return std::nullopt;

  auto type = MF->getType(ListOfValues[nextValue++])
    ->getCanonicalType();

  auto handleComputedId =
  [&]() -> KeyPathPatternComponent::ComputedPropertyId {
    auto kind =
      (KeyPathComputedComponentIdKindEncoding)ListOfValues[nextValue++];
    switch (kind) {
    case KeyPathComputedComponentIdKindEncoding::Property:
      return cast<VarDecl>(MF->getDecl(ListOfValues[nextValue++]));
    case KeyPathComputedComponentIdKindEncoding::Function: {
      auto name = MF->getIdentifierText(ListOfValues[nextValue++]);
      return getFuncForReference(name);
    }
    case KeyPathComputedComponentIdKindEncoding::DeclRef: {
      // read SILDeclRef
      return getSILDeclRef(MF, ListOfValues, nextValue);
    }
    }
    llvm_unreachable("unhandled kind");
  };

  ArrayRef<KeyPathPatternComponent::Index> indices;
  SILFunction *indicesEquals = nullptr;
  SILFunction *indicesHash = nullptr;
  AbstractStorageDecl *externalDecl = nullptr;
  SubstitutionMap externalSubs;

  auto handleComputedExternalReferenceAndIndices = [&] {
    auto externalDeclID = ListOfValues[nextValue++];
    externalDecl =
      cast_or_null<AbstractStorageDecl>(MF->getDecl(externalDeclID));
    externalSubs = MF->getSubstitutionMap(ListOfValues[nextValue++]);
    
    SmallVector<KeyPathPatternComponent::Index, 4> indicesBuf;
    auto numIndexes = ListOfValues[nextValue++];
    indicesBuf.reserve(numIndexes);
    while (numIndexes-- > 0) {
      unsigned operand = ListOfValues[nextValue++];
      auto formalType = MF->getType(ListOfValues[nextValue++]);
      auto loweredType = MF->getType(ListOfValues[nextValue++]);
      auto loweredCategory = (SILValueCategory)ListOfValues[nextValue++];
      auto conformance = MF->getConformance(ListOfValues[nextValue++]);
      indicesBuf.push_back({
        operand, formalType->getCanonicalType(),
        SILType::getPrimitiveType(loweredType->getCanonicalType(),
                                  loweredCategory),
        conformance});
    }
    
    indices = MF->getContext().AllocateCopy(indicesBuf);
    if (!indices.empty()) {
      auto indicesEqualsName = MF->getIdentifierText(ListOfValues[nextValue++]);
      auto indicesHashName = MF->getIdentifierText(ListOfValues[nextValue++]);
      indicesEquals = getFuncForReference(indicesEqualsName);
      indicesHash = getFuncForReference(indicesHashName);
    }
  };

  switch (kind) {
  case KeyPathComponentKindEncoding::StoredProperty: {
    auto decl = cast<VarDecl>(MF->getDecl(ListOfValues[nextValue++]));
    return KeyPathPatternComponent::forStoredProperty(decl, type);
  }
  case KeyPathComponentKindEncoding::GettableProperty: {
    auto id = handleComputedId();
    auto getterName = MF->getIdentifierText(ListOfValues[nextValue++]);
    auto getter = getFuncForReference(getterName);
    handleComputedExternalReferenceAndIndices();
    return KeyPathPatternComponent::forComputedGettableProperty(
        id, getter, indices, indicesEquals, indicesHash,
        externalDecl, externalSubs, type);
  }
  case KeyPathComponentKindEncoding::SettableProperty: {
    auto id = handleComputedId();
    auto getterName = MF->getIdentifierText(ListOfValues[nextValue++]);
    auto getter = getFuncForReference(getterName);
    auto setterName = MF->getIdentifierText(ListOfValues[nextValue++]);
    auto setter = getFuncForReference(setterName);
    handleComputedExternalReferenceAndIndices();
    return KeyPathPatternComponent::forComputedSettableProperty(
        id, getter, setter, indices, indicesEquals, indicesHash,
        externalDecl, externalSubs, type);
    break;
  }
  case KeyPathComponentKindEncoding::OptionalChain:
    return KeyPathPatternComponent::forOptional(
        KeyPathPatternComponent::Kind::OptionalChain, type);
  case KeyPathComponentKindEncoding::OptionalForce:
    return KeyPathPatternComponent::forOptional(
        KeyPathPatternComponent::Kind::OptionalForce, type);
  case KeyPathComponentKindEncoding::OptionalWrap:
    return KeyPathPatternComponent::forOptional(
        KeyPathPatternComponent::Kind::OptionalWrap, type);
  case KeyPathComponentKindEncoding::TupleElement:
    return KeyPathPatternComponent::forTupleElement(
        ListOfValues[nextValue++], type);
  case KeyPathComponentKindEncoding::Trivial:
    llvm_unreachable("handled above");
  }
  
  llvm_unreachable("invalid key path component kind encoding");
}

bool SILDeserializer::readSILInstruction(SILFunction *Fn,
                                         SILBuilder &Builder,
                                         unsigned RecordKind,
                                         SmallVectorImpl<uint64_t> &scratch,
                                         SmallVectorImpl<DebugValueInst *> &DebugBBWorklist) {
  unsigned RawOpCode = 0, TyCategory = 0, TyCategory2 = 0, TyCategory3 = 0,
           Attr = 0, Attr2 = 0, Attr3 = 0, Attr4 = 0, SubID = 0;
  ValueID ValID, ValID2, ValID3;
  TypeID TyID, TyID2, TyID3;
  TypeID ConcreteTyID;
  ProtocolConformanceID ConformanceID;
  SourceLoc SLoc;
  ApplyOptions ApplyOpts;
  ArrayRef<uint64_t> ListOfValues;

  SILLocation Loc = RegularLocation(SLoc);
  ValueOwnershipKind forwardingOwnership(OwnershipKind::Any);
  auto decodeValueOwnership = [](unsigned field){
    // Invalid/Any ownership is never encoded.
    return ValueOwnershipKind(field+1);
  };

  unsigned ApplyCallerIsolation = unsigned(ActorIsolation::Unspecified);
  unsigned ApplyCalleeIsolation = unsigned(ActorIsolation::Unspecified);
  unsigned ApplyHasArgumentLocs = 0;

  switch (RecordKind) {
  default:
    llvm_unreachable("Record kind for a SIL instruction is not supported.");
  case SIL_DEBUG_VALUE_DELIMITER:
    return false;
  case SIL_ONE_VALUE_ONE_OPERAND:
    SILOneValueOneOperandLayout::readRecord(scratch, RawOpCode, Attr,
                                            ValID, TyID, TyCategory,
                                            ValID2);
    break;
  case SIL_ONE_TYPE:
    SILOneTypeLayout::readRecord(scratch, RawOpCode, Attr, TyID, TyCategory);
    break;
  case SIL_ONE_OPERAND:
    SILOneOperandLayout::readRecord(scratch, RawOpCode, Attr,
                                    TyID, TyCategory, ValID);
    break;
  case SIL_ONE_OPERAND_EXTRA_ATTR:
    SILOneOperandExtraAttributeLayout::readRecord(scratch, RawOpCode, Attr,
                                                  TyID, TyCategory, ValID);
    break;
  case SIL_ONE_TYPE_ONE_OPERAND:
    SILOneTypeOneOperandLayout::readRecord(scratch, RawOpCode, Attr,
                                           TyID, TyCategory,
                                           TyID2, TyCategory2,
                                           ValID);
    break;
  case SIL_ONE_TYPE_ONE_OPERAND_EXTRA_ATTR:
    SILOneTypeOneOperandExtraAttributeLayout::readRecord(scratch, RawOpCode,
                                                         Attr, TyID, TyCategory,
                                                         TyID2, TyCategory2,
                                                         ValID);
    break;
  case SIL_INIT_EXISTENTIAL:
    SILInitExistentialLayout::readRecord(scratch, RawOpCode,
                                         TyID, TyCategory,
                                         TyID2, TyCategory2,
                                         ValID,
                                         ConcreteTyID,
                                         ListOfValues);
    break;
  case SIL_ONE_TYPE_VALUES:
    SILOneTypeValuesLayout::readRecord(scratch, RawOpCode, TyID, TyCategory,
                                       ListOfValues);
    break;
  case SIL_ONE_TYPE_OWNERSHIP_VALUES: {
    unsigned ownershipField;
    SILOneTypeOwnershipValuesLayout::readRecord(scratch, RawOpCode,
                                                ownershipField, TyID,
                                                TyCategory, ListOfValues);
    forwardingOwnership = decodeValueOwnership(ownershipField);
    break;
  }
  case SIL_VALUES: {
    SILValuesLayout::readRecord(scratch, RawOpCode, ListOfValues);
    break;
  }
  case SIL_ONE_TYPE_VALUES_CATEGORIES: {
    // NOTE: This is the same as Values except we smuggle in the category in the
    // top bit.
    SILOneTypeValuesCategoriesLayout::readRecord(
        scratch, RawOpCode, TyID, TyCategory, Attr, ListOfValues);
    break;
  }
  case SIL_TWO_OPERANDS:
    SILTwoOperandsLayout::readRecord(scratch, RawOpCode, Attr,
                                     TyID, TyCategory, ValID,
                                     TyID2, TyCategory2, ValID2);
    break;
  case SIL_TWO_OPERANDS_EXTRA_ATTR:
    SILTwoOperandsExtraAttributeLayout::readRecord(scratch, RawOpCode, Attr,
                                                   TyID, TyCategory, ValID,
                                                   TyID2, TyCategory2, ValID2);
    break;
  case SIL_TAIL_ADDR:
    SILTailAddrLayout::readRecord(scratch, RawOpCode,
                                  TyID, ValID,
                                  TyID2, ValID2,
                                  TyID3);
    break;
  case SIL_INST_APPLY: {
    unsigned Kind, RawApplyOpts;
    SILInstApplyLayout::readRecord(
        scratch, Kind, RawApplyOpts, ApplyHasArgumentLocs, SubID, TyID, TyID2,
        ValID, ApplyCallerIsolation, ApplyCalleeIsolation, ListOfValues);
    switch (Kind) {
    case SIL_APPLY:
      RawOpCode = (unsigned)SILInstructionKind::ApplyInst;
      break;
    case SIL_PARTIAL_APPLY:
      RawOpCode = (unsigned)SILInstructionKind::PartialApplyInst;
      break;
    case SIL_BUILTIN:
      RawOpCode = (unsigned)SILInstructionKind::BuiltinInst;
      break;
    case SIL_TRY_APPLY:
      RawOpCode = (unsigned)SILInstructionKind::TryApplyInst;
      break;
    case SIL_BEGIN_APPLY:
      RawOpCode = (unsigned)SILInstructionKind::BeginApplyInst;
      break;
        
    default:
      llvm_unreachable("unexpected apply inst kind");
    }

    ApplyOpts = ApplyOptions(ApplyFlags(RawApplyOpts));
    break;
  }
  case SIL_INST_NO_OPERAND:
    SILInstNoOperandLayout::readRecord(scratch, RawOpCode);
    break;
  case SIL_INST_WITNESS_METHOD:
    SILInstWitnessMethodLayout::readRecord(
        scratch, TyID, TyCategory, Attr, TyID2, TyCategory2, TyID3,
        TyCategory3, ValID3, ConformanceID, ListOfValues);
    RawOpCode = (unsigned)SILInstructionKind::WitnessMethodInst;
    break;
  case SIL_INST_DIFFERENTIABLE_FUNCTION:
    SILInstDifferentiableFunctionLayout::readRecord(
        scratch, /*numParams*/ Attr, /*numResults*/ Attr2,
        /*numDiffParams*/ Attr3,
        /*hasDerivativeFunctions*/ Attr4, ListOfValues);
    RawOpCode = (unsigned)SILInstructionKind::DifferentiableFunctionInst;
    break;
  case SIL_INST_LINEAR_FUNCTION:
    SILInstLinearFunctionLayout::readRecord(scratch, /*numDiffParams*/ Attr,
                                            /*hasTransposeFunction*/ Attr2,
                                            ListOfValues);
    RawOpCode = (unsigned)SILInstructionKind::LinearFunctionInst;
    break;
  case SIL_INST_DIFFERENTIABLE_FUNCTION_EXTRACT:
    SILInstDifferentiableFunctionExtractLayout::readRecord(
        scratch, TyID, TyCategory, ValID, /*extractee*/ Attr,
        /*hasExplicitExtracteeType*/ Attr2, /*explicitExtracteeType*/ TyID2);
    RawOpCode = (unsigned)SILInstructionKind::DifferentiableFunctionExtractInst;
    break;
  case SIL_INST_LINEAR_FUNCTION_EXTRACT:
    SILInstLinearFunctionExtractLayout::readRecord(
        scratch, TyID, TyCategory, ValID, /*extractee*/ Attr);
    RawOpCode = (unsigned)SILInstructionKind::LinearFunctionExtractInst;
    break;
  case SIL_INST_INCREMENT_PROFILER_COUNTER:
    SILInstIncrementProfilerCounterLayout::readRecord(scratch, ValID, ValID2,
                                                      Attr, Attr2);
    RawOpCode = (unsigned)SILInstructionKind::IncrementProfilerCounterInst;
    break;
  case SIL_INST_HAS_SYMBOL:
    SILInstHasSymbolLayout::readRecord(scratch, ValID, ListOfValues);
    RawOpCode = (unsigned)SILInstructionKind::HasSymbolInst;
    break;
  case SIL_OPEN_PACK_ELEMENT:
    SILOpenPackElementLayout::readRecord(scratch, Attr,
                                         TyID, TyCategory, ValID);
    RawOpCode = (unsigned)SILInstructionKind::OpenPackElementInst;
    break;
  case SIL_PACK_ELEMENT_GET:
    SILPackElementGetLayout::readRecord(scratch, RawOpCode,
                                        TyID, TyCategory,
                                        TyID2, TyCategory2, ValID2,
                                        ValID3);
    break;
  case SIL_PACK_ELEMENT_SET:
    SILPackElementSetLayout::readRecord(scratch,
                                        TyID, TyCategory, ValID,
                                        TyID2, TyCategory2, ValID2,
                                        ValID3);
    RawOpCode = (unsigned)SILInstructionKind::PackElementSetInst;
    break;
  case SIL_TYPE_VALUE:
    SILTypeValueLayout::readRecord(scratch, TyID, TyCategory, TyID2);
    RawOpCode = (unsigned)SILInstructionKind::TypeValueInst;
    break;
  case SIL_THUNK:
    SILThunkLayout::readRecord(scratch, Attr, TyID, TyCategory, ValID, SubID);
    RawOpCode = unsigned(SILInstructionKind::ThunkInst);
    break;

  case SIL_DEBUG_VALUE:
    SILDebugValueLayout::readRecord(scratch, TyCategory, TyCategory2, Attr,
                                    ListOfValues);
    RawOpCode = (unsigned)SILInstructionKind::DebugValueInst;

    break;
  }

  // FIXME: validate
  SILInstructionKind OpCode = (SILInstructionKind) RawOpCode;

  SILInstruction *ResultInst;
  switch (OpCode) {
  case SILInstructionKind::DebugStepInst:
  case SILInstructionKind::SpecifyTestInst:
  case SILInstructionKind::AllocPackMetadataInst:
  case SILInstructionKind::DeallocPackMetadataInst:
    llvm_unreachable("not supported");

  case SILInstructionKind::DebugValueInst: {
    assert(ListOfValues.size() >= 2 && "Unexpected number of values");
    SILValue Value =
        getLocalValue(Fn, ListOfValues[0],
                      getSILType(MF->getType(ListOfValues[1]),
                                 (SILValueCategory)TyCategory, Fn));

    bool hasReconstructionBlock = Attr & 0x1;
    auto UsesMoveableValDebugInfo =
        UsesMoveableValueDebugInfo_t((Attr >> 1) & 0x1);
    auto HasTrace = (Attr >> 2) & 0x1;

    bool HaveDebugVar = (Attr >> 3) & 0x1;
    bool HasLoc = false;

    SILDebugVariable DebugVar;
    if (HaveDebugVar) {
      assert(ListOfValues.size() >= 4 && "Unexpected number of values");
      bool IsLet = (Attr >> 4) & 0x1;
      unsigned IsDenseMapSingleton = (Attr >> 5) & 0x3;
      bool HasType = (Attr >> 7) & 0x1;
      bool HasScope = (Attr >> 8) & 0x1;
      HasLoc = (Attr >> 9) & 0x1;

      auto VarName = MF->getIdentifierText(ListOfValues[2]);
      auto ArgNo = ListOfValues[3];
      std::optional<SILType> Type;

      unsigned I = 4;
      unsigned Row, Col;
      StringRef FileName;
      std::optional<SILLocation> Loc;
      if (HasType) {
        Type = getSILType(MF->getType(ListOfValues[I++]),
                          (SILValueCategory)TyCategory2, Fn);
      }

      if (HasLoc) {
        Row = ListOfValues[I++];
        Col = ListOfValues[I++];
        FileName = MF->getIdentifierText(ListOfValues[I++]);
        Loc = RegularLocation(SILLocation::FilenameAndLocation::alloc(
            Row, Col, FileName, Fn->getModule()));
      }

      SILDebugInfoExpression Expressions;
      while (I < ListOfValues.size()) {
        using DIExpr = SILDIExprElement;
        SILDIExprElement::Kind Kind = (SILDIExprElement::Kind)ListOfValues[I++];
        switch (Kind) {
        case DIExpr::OperatorKind:
          Expressions.push_back(
              DIExpr::createOperator((SILDIExprOperator)ListOfValues[I++]));
          break;
        case DIExpr::DeclKind:
          Expressions.push_back(
              DIExpr::createDecl(MF->getDecl(ListOfValues[I++])));
          break;
        case DIExpr::ConstIntKind: {
          auto Str = MF->getIdentifierText(ListOfValues[I++]);
          APInt Int;
          Str.getAsInteger(10, Int);
          Expressions.push_back(DIExpr::createConstInt(Int.getLimitedValue()));
          break;
        }
        case SILDIExprElement::Kind::TypeKind:
          Expressions.push_back(
              DIExpr::createType(MF->getType(ListOfValues[I++])));
          break;
        }
      }

      const SILDebugScope *Scope = nullptr;
      if (HasScope) {
        SmallVector<uint64_t, 64> scratch;
        auto maybeKind = readNextRecord(scratch);
        if (!maybeKind) MF->fatal(maybeKind.takeError());
        auto maybeScope = readDebugScopes(Fn, scratch, Builder, maybeKind.get());
        if (!maybeScope) MF->fatal(maybeScope.takeError());
        Scope = maybeScope.get();
      }

      DebugVar = SILDebugVariable(
          VarName, IsLet, ArgNo, Type, Loc, Scope,
          llvm::ArrayRef<SILDIExprElement>(Expressions.element_begin(),
                                           Expressions.element_end()));
      DebugVar.isDenseMapSingleton = IsDenseMapSingleton;
    }

    ResultInst =
        Builder.createDebugValue(Loc, Value, DebugVar,
                                 UsesMoveableValDebugInfo, HasTrace, !HasLoc);

    // If the serialized debug_value has a reconstruction block, add it to
    // the worklist. The matching SIL_DEBUG_RECONSTRUCTION_BLOCK records
    // appear after all regular blocks.
    if (hasReconstructionBlock)
      DebugBBWorklist.push_back(cast<DebugValueInst>(ResultInst));

    break;
  }
  case SILInstructionKind::AllocBoxInst: {
    assert(RecordKind == SIL_ONE_TYPE && "Layout should be OneType.");
    auto hasDynamicLifetime = HasDynamicLifetime_t(Attr & 0x1);
    bool reflection = (Attr >> 1) & 0x1;
    auto usesMoveableValueDebugInfo =
        UsesMoveableValueDebugInfo_t((Attr >> 2) & 0x1);
    auto pointerEscape = HasPointerEscape_t((Attr >> 3) & 0x1);
    auto inferredImmutable = (Attr >> 4) & 0x1;
    ResultInst = Builder.createAllocBox(
        Loc, cast<SILBoxType>(MF->getType(TyID)->getCanonicalType()),
        std::nullopt, hasDynamicLifetime, reflection,
        usesMoveableValueDebugInfo,
        /*skipVarDeclAssert*/ false, pointerEscape, inferredImmutable);
    break;
  }
  case SILInstructionKind::AllocStackInst: {
    assert(RecordKind == SIL_ONE_TYPE && "Layout should be OneType.");
    auto hasDynamicLifetime = HasDynamicLifetime_t(Attr & 0x1);
    auto isLexical = IsLexical_t((Attr >> 1) & 0x1);
    auto isFromVarDecl = IsFromVarDecl_t((Attr >> 2) & 0x1);
    auto wasMoved = UsesMoveableValueDebugInfo_t((Attr >> 3) & 0x1);
    auto isNested = StackAllocationIsNested_t((Attr >> 4) & 0x1);
    auto ASI = Builder.createAllocStack(
        Loc, getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn),
        std::nullopt, hasDynamicLifetime, isLexical, isFromVarDecl, wasMoved);
    ASI->setStackAllocationIsNested(isNested);
    ResultInst = ASI;
    break;
  }
  case SILInstructionKind::AllocPackInst: {
    assert(RecordKind == SIL_ONE_TYPE && "Layout should be OneType.");
    ResultInst = Builder.createAllocPack(
        Loc, getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn));
    break;
  }
  case SILInstructionKind::PackLengthInst: {
    assert(RecordKind == SIL_ONE_TYPE && "Layout should be OneType.");
    ResultInst = Builder.createPackLength(
        Loc, cast<PackType>(MF->getType(TyID)->getCanonicalType()));
    break;
  }
  case SILInstructionKind::MetatypeInst:
    assert(RecordKind == SIL_ONE_TYPE && "Layout should be OneType.");
    ResultInst = Builder.createMetatype(
        Loc, getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn));
    break;
      
  case SILInstructionKind::GetAsyncContinuationInst:
    assert(RecordKind == SIL_ONE_TYPE && "Layout should be OneType.");
    ResultInst = Builder.createGetAsyncContinuation(
        Loc, MF->getType(TyID)->getCanonicalType(),
        /*throws*/ Attr != 0);
    break;
  
  case SILInstructionKind::GetAsyncContinuationAddrInst:
    assert(RecordKind == SIL_ONE_TYPE_ONE_OPERAND
           && "Layout should be OneTypeOneOperand.");
    ResultInst = Builder.createGetAsyncContinuationAddr(
        Loc,
        getLocalValue(
            Builder.maybeGetFunction(), ValID,
            getSILType(MF->getType(TyID2), (SILValueCategory)TyCategory2, Fn)),
        MF->getType(TyID)->getCanonicalType(),
        /*throws*/ Attr != 0);
    break;

#define ONETYPE_ONEOPERAND_INST(ID)                                            \
  case SILInstructionKind::ID##Inst:                                           \
    assert(RecordKind == SIL_ONE_TYPE_ONE_OPERAND &&                           \
           "Layout should be OneTypeOneOperand.");                             \
    ResultInst = Builder.create##ID(                                           \
        Loc, getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn),  \
        getLocalValue(Builder.maybeGetFunction(), ValID,                       \
                      getSILType(MF->getType(TyID2),                           \
                                 (SILValueCategory)TyCategory2, Fn)));         \
    break;
    ONETYPE_ONEOPERAND_INST(ValueMetatype)
    ONETYPE_ONEOPERAND_INST(ExistentialMetatype)
    ONETYPE_ONEOPERAND_INST(ProjectExistentialBox)
#undef ONETYPE_ONEOPERAND_INST
  case SILInstructionKind::DeallocBoxInst: {
    assert(RecordKind == SIL_ONE_TYPE_ONE_OPERAND &&
           "Layout should be OneTypeOneOperand.");
    IsDeadEnd_t isDeadEnd = IsDeadEnd_t(Attr & 0x1);
    ResultInst = Builder.createDeallocBox(
        Loc,
        getLocalValue(
            Builder.maybeGetFunction(), ValID,
            getSILType(MF->getType(TyID2), (SILValueCategory)TyCategory2, Fn)),
        isDeadEnd);
    break;
  }
  case SILInstructionKind::OpenExistentialAddrInst:
    assert(RecordKind == SIL_ONE_TYPE_ONE_OPERAND &&
           "Layout should be OneTypeOneOperand.");
    ResultInst = Builder.createOpenExistentialAddr(
        Loc,
        getLocalValue(
            Builder.maybeGetFunction(), ValID,
            getSILType(MF->getType(TyID2), (SILValueCategory)TyCategory2, Fn)),
        getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn),
        Attr == 0 ? OpenedExistentialAccess::Immutable
                  : OpenedExistentialAccess::Mutable);
    break;
  case SILInstructionKind::DynamicPackIndexInst: {
    assert(RecordKind == SIL_ONE_TYPE_ONE_OPERAND &&
           "Layout should be OneTypeOneOperand.");
    auto indexOperand = getLocalValue(
        Builder.maybeGetFunction(), ValID,
        getSILType(MF->getType(TyID2), (SILValueCategory)TyCategory2, Fn));
    auto packType = cast<PackType>(MF->getType(TyID)->getCanonicalType());
    ResultInst = Builder.createDynamicPackIndex(Loc, indexOperand, packType);
    break;
  }
  case SILInstructionKind::PackPackIndexInst: {
    assert(RecordKind == SIL_ONE_TYPE_ONE_OPERAND &&
           "Layout should be OneTypeOneOperand.");
    auto indexOperand = getLocalValue(
        Builder.maybeGetFunction(), ValID,
        getSILType(MF->getType(TyID2), (SILValueCategory)TyCategory2, Fn));
    auto packType = cast<PackType>(MF->getType(TyID)->getCanonicalType());
    ResultInst =
      Builder.createPackPackIndex(Loc, Attr, indexOperand, packType);
    break;
  }
  case SILInstructionKind::ScalarPackIndexInst: {
    assert(RecordKind == SIL_ONE_TYPE && "Layout should be OneType.");
    auto packType = cast<PackType>(MF->getType(TyID)->getCanonicalType());
    ResultInst = Builder.createScalarPackIndex(Loc, Attr, packType);
    break;
  }
  case SILInstructionKind::OpenPackElementInst: {
    assert(RecordKind == SIL_OPEN_PACK_ELEMENT && "Layout should be OpenPackElement");
    auto index = getLocalValue(
        Builder.maybeGetFunction(), ValID,
        getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn));
    auto env = MF->getGenericEnvironmentChecked(Attr);
    if (!env) MF->fatal(env.takeError());
    ResultInst = Builder.createOpenPackElement(Loc, index, *env);
    break;
  }
  case SILInstructionKind::PackElementGetInst: {
    assert(RecordKind == SIL_PACK_ELEMENT_GET);
    auto elementType = getSILType(MF->getType(TyID),
                                  (SILValueCategory) TyCategory, Fn);
    auto packType = getSILType(MF->getType(TyID2),
                               (SILValueCategory) TyCategory2, Fn);
    auto pack = getLocalValue(Builder.maybeGetFunction(), ValID2, packType);
    auto indexType = SILType::getPackIndexType(MF->getContext());
    auto index = getLocalValue(Builder.maybeGetFunction(), ValID3, indexType);
    ResultInst = Builder.createPackElementGet(Loc, index, pack, elementType);
    break;
  }
  case SILInstructionKind::PackElementSetInst: {
    assert(RecordKind == SIL_PACK_ELEMENT_SET);
    auto elementType = getSILType(MF->getType(TyID),
                                  (SILValueCategory) TyCategory, Fn);
    auto value = getLocalValue(Builder.maybeGetFunction(), ValID, elementType);
    auto packType = getSILType(MF->getType(TyID2),
                               (SILValueCategory) TyCategory2, Fn);
    auto pack = getLocalValue(Builder.maybeGetFunction(), ValID2, packType);
    auto indexType = SILType::getPackIndexType(MF->getContext());
    auto index = getLocalValue(Builder.maybeGetFunction(), ValID3, indexType);
    ResultInst = Builder.createPackElementSet(Loc, value, index, pack);
    break;
  }
  case SILInstructionKind::TuplePackElementAddrInst: {
    assert(RecordKind == SIL_PACK_ELEMENT_GET);
    auto elementType = getSILType(MF->getType(TyID),
                                  (SILValueCategory) TyCategory, Fn);
    auto tupleType = getSILType(MF->getType(TyID2),
                               (SILValueCategory) TyCategory2, Fn);
    auto tuple = getLocalValue(Builder.maybeGetFunction(), ValID2, tupleType);
    auto indexType = SILType::getPackIndexType(MF->getContext());
    auto index = getLocalValue(Builder.maybeGetFunction(), ValID3, indexType);
    ResultInst = Builder.createTuplePackElementAddr(Loc, index, tuple,
                                                    elementType);
    break;
  }
  case SILInstructionKind::TuplePackExtractInst: {
    assert(RecordKind == SIL_PACK_ELEMENT_GET);
    auto elementType =
        getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn);
    auto tupleType =
        getSILType(MF->getType(TyID2), (SILValueCategory)TyCategory2, Fn);
    auto tuple = getLocalValue(Builder.maybeGetFunction(), ValID2, tupleType);
    auto indexType = SILType::getPackIndexType(MF->getContext());
    auto index = getLocalValue(Builder.maybeGetFunction(), ValID3, indexType);
    ResultInst = Builder.createTuplePackExtract(Loc, index, tuple, elementType);
    break;
  }
  case SILInstructionKind::ThunkInst: {
    assert(RecordKind == SIL_THUNK && "Layout should be OneTypeOneOperand.");
    SubstitutionMap Substitutions = MF->getSubstitutionMap(SubID);
    ResultInst = Builder.createThunk(
        Loc,
        getLocalValue(
            Builder.maybeGetFunction(), ValID,
            getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn)),
        ThunkInst::Kind(Attr), Substitutions);
    break;
  }

#define ONEOPERAND_ONETYPE_INST(ID)                                            \
  case SILInstructionKind::ID##Inst:                                           \
    assert(RecordKind == SIL_ONE_TYPE_ONE_OPERAND &&                           \
           "Layout should be OneTypeOneOperand.");                             \
    ResultInst = Builder.create##ID(                                           \
        Loc,                                                                   \
        getLocalValue(Builder.maybeGetFunction(), ValID,                       \
                      getSILType(MF->getType(TyID2),                           \
                                 (SILValueCategory)TyCategory2, Fn)),          \
        getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn));      \
    break;
    ONEOPERAND_ONETYPE_INST(OpenExistentialRef)
    ONEOPERAND_ONETYPE_INST(OpenExistentialMetatype)
    ONEOPERAND_ONETYPE_INST(OpenExistentialBox)
    ONEOPERAND_ONETYPE_INST(OpenExistentialValue)
    ONEOPERAND_ONETYPE_INST(OpenExistentialBoxValue)
    // Conversion instructions.
#define LOADABLE_REF_STORAGE(Name, ...) \
  ONEOPERAND_ONETYPE_INST(RefTo##Name) \
  ONEOPERAND_ONETYPE_INST(Name##ToRef)
#include "swift/AST/ReferenceStorage.def"
  ONEOPERAND_ONETYPE_INST(UncheckedAddrCast)
  ONEOPERAND_ONETYPE_INST(UncheckedTrivialBitCast)
  ONEOPERAND_ONETYPE_INST(UncheckedBitwiseCast)
  ONEOPERAND_ONETYPE_INST(UncheckedValueCast)
  ONEOPERAND_ONETYPE_INST(BridgeObjectToRef)
  ONEOPERAND_ONETYPE_INST(BridgeObjectToWord)
  ONEOPERAND_ONETYPE_INST(Upcast)
  ONEOPERAND_ONETYPE_INST(RefToRawPointer)
  ONEOPERAND_ONETYPE_INST(RawPointerToRef)
  ONEOPERAND_ONETYPE_INST(ThinToThickFunction)
  ONEOPERAND_ONETYPE_INST(ThickToObjCMetatype)
  ONEOPERAND_ONETYPE_INST(ObjCToThickMetatype)
  ONEOPERAND_ONETYPE_INST(ObjCMetatypeToObject)
  ONEOPERAND_ONETYPE_INST(ObjCExistentialMetatypeToObject)
  ONEOPERAND_ONETYPE_INST(ProjectBlockStorage)
  ONEOPERAND_ONETYPE_INST(EndApply)
#undef ONEOPERAND_ONETYPE_INST

  case SILInstructionKind::AddressToPointerInst: {
    assert(RecordKind == SIL_ONE_TYPE_ONE_OPERAND &&
           "Layout should be OneTypeOneOperand.");
    ResultInst = Builder.createAddressToPointer(
        Loc,
        getLocalValue(
            Builder.maybeGetFunction(), ValID,
            getSILType(MF->getType(TyID2), (SILValueCategory)TyCategory2, Fn)),
        getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn),
        /*needsStackProtection=*/Attr != 0);
    break;
  }
  case SILInstructionKind::ProjectBoxInst: {
    assert(RecordKind == SIL_ONE_TYPE_ONE_OPERAND &&
           "Layout should be OneTypeOneOperand.");
    ResultInst = Builder.createProjectBox(
        Loc,
        getLocalValue(
            Builder.maybeGetFunction(), ValID,
            getSILType(MF->getType(TyID2), (SILValueCategory)TyCategory2, Fn)),
        TyID);
    break;
  }
  case  SILInstructionKind::ConvertEscapeToNoEscapeInst: {
    assert(RecordKind == SIL_ONE_TYPE_ONE_OPERAND &&
           "Layout should be OneTypeOneOperand.");
    bool isLifetimeGuaranteed = Attr & 0x01;
    ResultInst = Builder.createConvertEscapeToNoEscape(
        Loc,
        getLocalValue(
            Builder.maybeGetFunction(), ValID,
            getSILType(MF->getType(TyID2), (SILValueCategory)TyCategory2, Fn)),
        getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn),
        isLifetimeGuaranteed);
    break;
  }
  case SILInstructionKind::ConvertFunctionInst: {
    assert(RecordKind == SIL_ONE_TYPE_ONE_OPERAND
           && "Layout should be OneTypeOneOperand.");
    bool withoutActuallyEscaping = Attr & 0x01;
    ResultInst = Builder.createConvertFunction(
        Loc,
        getLocalValue(
            Builder.maybeGetFunction(), ValID,
            getSILType(MF->getType(TyID2), (SILValueCategory)TyCategory2, Fn)),
        getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn),
        withoutActuallyEscaping);
    break;
  }
  case SILInstructionKind::PointerToAddressInst: {
    assert(RecordKind == SIL_ONE_TYPE_ONE_OPERAND_EXTRA_ATTR &&
           "Layout should be OneTypeOneOperand.");
    auto alignment = llvm::decodeMaybeAlign(Attr & 0xFF);
    bool isStrict = Attr & 0x100;
    bool isInvariant = Attr & 0x200;
    ResultInst = Builder.createPointerToAddress(
        Loc,
        getLocalValue(
            Builder.maybeGetFunction(), ValID,
            getSILType(MF->getType(TyID2), (SILValueCategory)TyCategory2, Fn)),
        getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn),
        isStrict, isInvariant, alignment);
    break;
  }
  case SILInstructionKind::DeallocExistentialBoxInst: {
    assert(RecordKind == SIL_ONE_TYPE_ONE_OPERAND &&
           "Layout should be OneTypeOneOperand.");
    ResultInst = Builder.createDeallocExistentialBox(
        Loc, MF->getType(TyID)->getCanonicalType(),
        getLocalValue(
            Builder.maybeGetFunction(), ValID,
            getSILType(MF->getType(TyID2), (SILValueCategory)TyCategory2, Fn)));
    break;

  }
  
  case SILInstructionKind::RefToBridgeObjectInst: {
    auto RefTy =
        getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn);
    auto Ref = getLocalValue(Builder.maybeGetFunction(), ValID, RefTy);
    auto BitsTy =
        getSILType(MF->getType(TyID2), (SILValueCategory)TyCategory2, Fn);
    auto Bits = getLocalValue(Builder.maybeGetFunction(), ValID2, BitsTy);

    ResultInst = Builder.createRefToBridgeObject(Loc, Ref, Bits);
    break;
  }

  case SILInstructionKind::ObjCProtocolInst: {
    auto Ty = getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn);
    auto Proto = MF->getDecl(ValID);
    ResultInst = Builder.createObjCProtocol(Loc, cast<ProtocolDecl>(Proto), Ty);
    break;
  }

  case SILInstructionKind::InitExistentialAddrInst:
  case SILInstructionKind::InitExistentialValueInst:
  case SILInstructionKind::InitExistentialMetatypeInst:
  case SILInstructionKind::InitExistentialRefInst:
  case SILInstructionKind::AllocExistentialBoxInst: {

    auto Ty = getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn);
    auto Ty2 = MF->getType(TyID2);
    CanType ConcreteTy;
    if (OpCode != SILInstructionKind::InitExistentialMetatypeInst)
      ConcreteTy = MF->getType(ConcreteTyID)->getCanonicalType();
    SILValue operand;
    if (OpCode != SILInstructionKind::AllocExistentialBoxInst)
      operand =
          getLocalValue(Builder.maybeGetFunction(), ValID,
                        getSILType(Ty2, (SILValueCategory)TyCategory2, Fn));

    SmallVector<ProtocolConformanceRef, 2> conformances;
    for (auto conformanceID: ListOfValues) {
      auto conformance = MF->getConformance(conformanceID);
      conformances.push_back(conformance);
    }

    auto ctxConformances = MF->getContext().AllocateCopy(conformances);

    switch (OpCode) {
    default: llvm_unreachable("Out of sync with parent switch");
    case SILInstructionKind::InitExistentialAddrInst:
      ResultInst = Builder.createInitExistentialAddr(Loc, operand, ConcreteTy,
                                                     Ty, ctxConformances);
      break;
    case SILInstructionKind::InitExistentialValueInst:
      ResultInst = Builder.createInitExistentialValue(Loc, Ty, ConcreteTy,
                                                      operand, ctxConformances);
      break;
    case SILInstructionKind::InitExistentialMetatypeInst:
      ResultInst = Builder.createInitExistentialMetatype(Loc, operand, Ty,
                                                         ctxConformances);
      break;
    case SILInstructionKind::InitExistentialRefInst:
      ResultInst = Builder.createInitExistentialRef(Loc, Ty, ConcreteTy,
                                                    operand, ctxConformances);
      break;
    case SILInstructionKind::AllocExistentialBoxInst:
      ResultInst = Builder.createAllocExistentialBox(Loc, Ty, ConcreteTy,
                                                     ctxConformances);
      break;
    }
    break;
  }
  case SILInstructionKind::AllocRefInst:
  case SILInstructionKind::AllocRefDynamicInst: {
    assert(RecordKind == SIL_ONE_TYPE_VALUES &&
           "Layout should be OneTypeValues.");
    unsigned NumVals = ListOfValues.size();
    assert(NumVals >= 1 && "Not enough values");
    unsigned Flags = ListOfValues[0];
    bool isObjC = (bool)(Flags & 1);
    bool canAllocOnStack = (bool)((Flags >> 1) & 1);
    bool isBare = (bool)((Flags >> 2) & 1);
    auto isNested = StackAllocationIsNested_t((bool) ((Flags >> 3) & 1));
    SILType ClassTy =
        getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn);
    SmallVector<SILValue, 4> Counts;
    SmallVector<SILType, 4> TailTypes;
    unsigned i = 1;
    for (; i + 2 < NumVals; i += 3) {
      SILType TailType = getSILType(MF->getType(ListOfValues[i]),
                                    SILValueCategory::Object, Fn);
      TailTypes.push_back(TailType);
      SILType CountType = getSILType(MF->getType(ListOfValues[i + 2]),
                                     SILValueCategory::Object, Fn);
      SILValue CountVal = getLocalValue(Builder.maybeGetFunction(),
                                        ListOfValues[i + 1], CountType);
      Counts.push_back(CountVal);
    }
    if (OpCode == SILInstructionKind::AllocRefDynamicInst) {
      assert(i + 2 == NumVals);
      SILType MetadataType = getSILType(MF->getType(ListOfValues[i+1]),
                                        SILValueCategory::Object, Fn);
      SILValue MetadataOp = getLocalValue(Builder.maybeGetFunction(),
                                          ListOfValues[i], MetadataType);
      ResultInst = Builder.createAllocRefDynamic(Loc, MetadataOp, ClassTy,
                                                 isObjC, canAllocOnStack,
                                                 isNested,
                                                 TailTypes, Counts);
    } else {
      assert(i == NumVals);
      ResultInst = Builder.createAllocRef(Loc, ClassTy, isObjC, canAllocOnStack, isBare,
                                          isNested, TailTypes, Counts);
    }
    break;
  }
  case SILInstructionKind::ApplyInst:
  case SILInstructionKind::BeginApplyInst: {
    // Format: attributes such as transparent, the callee's type, a value for
    // the callee and a list of values for the arguments. Each value in the list
    // is represented with 2 IDs: ValueID and ValueResultNumber.
    auto Ty = MF->getType(TyID);
    auto Ty2 = MF->getType(TyID2);
    SILType FnTy = getSILType(Ty, SILValueCategory::Object, Fn);
    SILType SubstFnTy = getSILType(Ty2, SILValueCategory::Object, Fn);
    SILFunctionConventions substConventions(
        SubstFnTy.castTo<SILFunctionType>(),
        SILAddressConventions::forFunctionOrRawSIL(Fn, Builder.getModule()));
    assert(substConventions.getNumSILArguments() == ListOfValues.size()
           && "Argument number mismatch in ApplyInst.");
    SmallVector<SILValue, 4> Args;
    for (unsigned I = 0, E = ListOfValues.size(); I < E; ++I)
      Args.push_back(getLocalValue(Builder.maybeGetFunction(), ListOfValues[I],
                                   substConventions.getSILArgumentType(
                                       I, Builder.getTypeExpansionContext())));
    SubstitutionMap Substitutions = MF->getSubstitutionMap(SubID);

    std::optional<ApplyIsolationCrossing> IsolationCrossing;
    if (bool(ApplyCallerIsolation) || bool(ApplyCalleeIsolation)) {
      auto caller = ActorIsolation(ActorIsolation::Kind(ApplyCallerIsolation),
                                   /*forSIL*/ true);
      auto callee = ActorIsolation(ActorIsolation::Kind(ApplyCalleeIsolation),
                                   /*forSIL*/ true);
      IsolationCrossing = {caller, callee};
    }

    // When the apply record carried HasArgumentLocs=1, NumArguments
    // SIL_SOURCE_LOC / SIL_SOURCE_LOC_REF records arrive immediately
    // after this instruction. Reserve trailing per-arg location storage
    // now, with placeholder anchor locations satisfying the "every slot
    // valid" invariant; the post-instruction loop in the main read loop
    // overwrites each slot with the real deserialized location via
    // setArgumentLoc.
    SmallVector<SILLocation, 8> placeholderArgLocs;
    std::optional<ArrayRef<SILLocation>> argLocsRef;
    if (ApplyHasArgumentLocs) {
      placeholderArgLocs.assign(Args.size(), Loc);
      argLocsRef = ArrayRef<SILLocation>(placeholderArgLocs);
    }

    if (OpCode == SILInstructionKind::ApplyInst) {
      ResultInst = Builder.createApply(
          Loc, getLocalValue(Builder.maybeGetFunction(), ValID, FnTy),
          Substitutions, Args, ApplyOpts, nullptr, IsolationCrossing,
          argLocsRef);
    } else {
      ResultInst = Builder.createBeginApply(
          Loc, getLocalValue(Builder.maybeGetFunction(), ValID, FnTy),
          Substitutions, Args, ApplyOpts, nullptr, IsolationCrossing,
          argLocsRef);
    }
    break;
  }
  case SILInstructionKind::TryApplyInst: {
    // Format: attributes such as transparent, the callee's type, a value for
    // the callee and a list of values for the arguments. Each value in the list
    // is represented with 2 IDs: ValueID and ValueResultNumber.  The final
    // two values in the list are the basic block identifiers.
    auto Ty = MF->getType(TyID);
    auto Ty2 = MF->getType(TyID2);
    SILType FnTy = getSILType(Ty, SILValueCategory::Object, Fn);
    SILType SubstFnTy = getSILType(Ty2, SILValueCategory::Object, Fn);

    SILBasicBlock *errorBB = getBBForReference(Fn, ListOfValues.back());
    ListOfValues = ListOfValues.drop_back();
    SILBasicBlock *normalBB = getBBForReference(Fn, ListOfValues.back());
    ListOfValues = ListOfValues.drop_back();

    SILFunctionConventions substConventions(
        SubstFnTy.castTo<SILFunctionType>(),
        SILAddressConventions::forFunctionOrRawSIL(Fn, Builder.getModule()));
    assert(substConventions.getNumSILArguments() == ListOfValues.size()
           && "Argument number mismatch in ApplyInst.");
    SmallVector<SILValue, 4> Args;
    for (unsigned I = 0, E = ListOfValues.size(); I < E; ++I)
      Args.push_back(getLocalValue(Builder.maybeGetFunction(), ListOfValues[I],
                                   substConventions.getSILArgumentType(
                                       I, Builder.getTypeExpansionContext())));
    SubstitutionMap Substitutions = MF->getSubstitutionMap(SubID);

    std::optional<ApplyIsolationCrossing> IsolationCrossing;
    if (bool(ApplyCallerIsolation) || bool(ApplyCalleeIsolation)) {
      auto caller = ActorIsolation(ActorIsolation::Kind(ApplyCallerIsolation),
                                   /*forSIL*/true);
      auto callee = ActorIsolation(ActorIsolation::Kind(ApplyCalleeIsolation),
                                   /*forSIL*/true);
      IsolationCrossing = {caller, callee};
    }

    SmallVector<SILLocation, 8> placeholderArgLocs;
    std::optional<ArrayRef<SILLocation>> argLocsRef;
    if (ApplyHasArgumentLocs) {
      placeholderArgLocs.assign(Args.size(), Loc);
      argLocsRef = ArrayRef<SILLocation>(placeholderArgLocs);
    }

    ResultInst = Builder.createTryApply(
        Loc, getLocalValue(Builder.maybeGetFunction(), ValID, FnTy),
        Substitutions, Args, normalBB, errorBB, ApplyOpts, nullptr,
        IsolationCrossing,
        /*normalCount=*/ProfileCounter(),
        /*errorCount=*/ProfileCounter(), argLocsRef);
    break;
  }
  case SILInstructionKind::PartialApplyInst: {
    auto Ty = MF->getType(TyID);
    auto Ty2 = MF->getType(TyID2);
    SILType FnTy = getSILType(Ty, SILValueCategory::Object, Fn);
    auto closureTy = getSILType(Ty2, SILValueCategory::Object, Fn)
                       .castTo<SILFunctionType>();

    SubstitutionMap Substitutions = MF->getSubstitutionMap(SubID);

    auto SubstFnTy = SILType::getPrimitiveObjectType(
        FnTy.castTo<SILFunctionType>()->substGenericArgs(
            Builder.getModule(), Substitutions,
            Builder.getTypeExpansionContext()));
    SILFunctionConventions fnConv(
        SubstFnTy.castTo<SILFunctionType>(),
        SILAddressConventions::forFunctionOrRawSIL(Fn, Builder.getModule()));

    unsigned numArgs = fnConv.getNumSILArguments();
    assert(numArgs >= ListOfValues.size()
           && "Argument number mismatch in PartialApplyInst.");

    SILValue FnVal = getLocalValue(Builder.maybeGetFunction(), ValID, FnTy);
    SmallVector<SILValue, 4> Args;
    unsigned unappliedArgs = numArgs - ListOfValues.size();
    for (unsigned I = 0, E = ListOfValues.size(); I < E; ++I)
      Args.push_back(getLocalValue(
          Builder.maybeGetFunction(), ListOfValues[I],
          fnConv.getSILArgumentType(I + unappliedArgs,
                                    Builder.getTypeExpansionContext())));
    auto onStack = closureTy->isNoEscape()
                       ? PartialApplyInst::OnStackKind::OnStack
                       : PartialApplyInst::OnStackKind::NotOnStack;

    unsigned flags = ApplyCallerIsolation;
    auto isNested = StackAllocationIsNested_t(
      IsNestedEncoding((flags >> 0) & 1) == IsNestedEncoding::IsNested);

    SmallVector<SILLocation, 8> placeholderArgLocs;
    std::optional<ArrayRef<SILLocation>> argLocsRef;
    if (ApplyHasArgumentLocs) {
      placeholderArgLocs.assign(Args.size(), Loc);
      argLocsRef = ArrayRef<SILLocation>(placeholderArgLocs);
    }

    // FIXME: Why the arbitrary order difference in IRBuilder type argument?
    ResultInst = Builder.createPartialApply(
        Loc, FnVal, Substitutions, Args, closureTy->getCalleeConvention(),
        closureTy->getIsolation(), onStack, isNested,
        /*SpecializationInfo=*/nullptr, argLocsRef);
    break;
  }
  case SILInstructionKind::BuiltinInst: {
    auto ASTTy = MF->getType(TyID);
    auto ResultTy = getSILType(ASTTy, (SILValueCategory)(unsigned)TyID2, Fn);
    SmallVector<SILValue, 4> Args;
    for (unsigned i = 0, e = ListOfValues.size(); i < e; i += 3) {
      auto ArgASTTy = MF->getType(ListOfValues[i+1]);
      auto ArgTy = getSILType(
          ArgASTTy, (SILValueCategory)(unsigned)ListOfValues[i + 2], Fn);
      Args.push_back(
          getLocalValue(Builder.maybeGetFunction(), ListOfValues[i], ArgTy));
    }
    SubstitutionMap Substitutions = MF->getSubstitutionMap(SubID);
    Identifier Name = MF->getIdentifier(ValID);

    ResultInst =
        Builder.createBuiltin(Loc, Name, ResultTy, Substitutions, Args);
    break;
  }
  case SILInstructionKind::AllocGlobalInst: {
    // Format: Name and type. Use SILOneOperandLayout.
    StringRef Name = MF->getIdentifierText(ValID);

    // Find the global variable.
    SILGlobalVariable *g = getGlobalForReference(Name);
    assert(g && "Can't deserialize global variable");

    ResultInst = Builder.createAllocGlobal(Loc, g);
    break;
  }
  case SILInstructionKind::GlobalValueInst: {
    // Format: Name and type. Use SILOneOperandLayout.
    auto Ty = MF->getType(TyID);
    StringRef Name = MF->getIdentifierText(ValID);

    // Find the global variable.
    SILGlobalVariable *g = getGlobalForReference(Name);
    assert(g && "Can't deserialize global variable");
    SILType expectedType = g->getLoweredTypeInContext(TypeExpansionContext(*Fn));
    assert(expectedType == getSILType(Ty, (SILValueCategory)TyCategory, Fn) &&
           "Type of a global variable does not match GlobalAddr.");
    (void)Ty;
    (void)expectedType;
    ResultInst = Builder.createGlobalValue(Loc, g, /*isBare=*/ (Attr & 1) != 0);
    break;
  }
  case SILInstructionKind::GlobalAddrInst: {
    // Format: Name and type. Use SILOneOperandLayout.
    auto Ty = MF->getType(TyID);
    StringRef Name = MF->getIdentifierText(ValID);

    // Find the global variable.
    SILGlobalVariable *g = getGlobalForReference(Name);
    assert(g && "Can't deserialize global variable");
    SILType expectedType = g->getLoweredTypeInContext(TypeExpansionContext(*Fn))
                            .getAddressType();
    assert(expectedType == getSILType(Ty, (SILValueCategory)TyCategory, Fn) &&
           "Type of a global variable does not match GlobalAddr.");
    (void)Ty;
    (void)expectedType;
    SILValue token =
        ValID2 == 0 ? SILValue()
                    : getLocalValue(Builder.maybeGetFunction(), ValID2,
                                    SILType::getSILTokenType(MF->getContext()));
    ResultInst = Builder.createGlobalAddr(Loc, g, token);
    break;
  }
  case SILInstructionKind::BaseAddrForOffsetInst:
    assert(RecordKind == SIL_ONE_TYPE && "Layout should be OneType.");
    ResultInst = Builder.createBaseAddrForOffset(
        Loc, getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn));
    break;
  case SILInstructionKind::DeallocStackInst: {
    auto Ty = MF->getType(TyID);
    ResultInst = Builder.createDeallocStack(
        Loc, getLocalValue(Builder.maybeGetFunction(), ValID,
                           getSILType(Ty, (SILValueCategory)TyCategory, Fn)));
    break;
  }
  case SILInstructionKind::DeallocStackRefInst: {
    auto Ty = MF->getType(TyID);
    ResultInst = Builder.createDeallocStackRef(
        Loc, getLocalValue(Builder.maybeGetFunction(), ValID,
                           getSILType(Ty, (SILValueCategory)TyCategory, Fn)));
    break;
  }
  case SILInstructionKind::IgnoredUseInst: {
    assert(RecordKind == SIL_ONE_OPERAND && "Should be one operand");
    auto Ty = MF->getType(TyID);
    ResultInst = Builder.createIgnoredUse(
        Loc, getLocalValue(Builder.maybeGetFunction(), ValID,
                           getSILType(Ty, (SILValueCategory)TyCategory, Fn)));
    break;
  }
  case SILInstructionKind::DeallocPackInst: {
    auto Ty = MF->getType(TyID);
    ResultInst = Builder.createDeallocPack(
        Loc, getLocalValue(Builder.maybeGetFunction(), ValID,
                           getSILType(Ty, (SILValueCategory)TyCategory, Fn)));
    break;
  }
  case SILInstructionKind::DeallocRefInst: {
    auto Ty = MF->getType(TyID);
    ResultInst = Builder.createDeallocRef(
        Loc, getLocalValue(Builder.maybeGetFunction(), ValID,
                           getSILType(Ty, (SILValueCategory)TyCategory, Fn)));
    break;
  }
  case SILInstructionKind::DeallocPartialRefInst: {
    auto Ty = MF->getType(TyID);
    auto Ty2 = MF->getType(TyID2);
    ResultInst = Builder.createDeallocPartialRef(
        Loc,
        getLocalValue(Builder.maybeGetFunction(), ValID,
                      getSILType(Ty, (SILValueCategory)TyCategory, Fn)),
        getLocalValue(Builder.maybeGetFunction(), ValID2,
                      getSILType(Ty2, (SILValueCategory)TyCategory2, Fn)));
    break;
  }
  case SILInstructionKind::FunctionRefInst: {
    auto Ty = MF->getType(TyID);
    StringRef FuncName = MF->getIdentifierText(ValID);
    ResultInst = Builder.createFunctionRef(
        Loc,
        getFuncForReference(
            FuncName, getSILType(Ty, (SILValueCategory)TyCategory, nullptr),
            Builder.getTypeExpansionContext()));
    break;
  }
  case SILInstructionKind::DynamicFunctionRefInst: {
    auto Ty = MF->getType(TyID);
    StringRef FuncName = MF->getIdentifierText(ValID);
    ResultInst = Builder.createDynamicFunctionRef(
        Loc,
        getFuncForReference(
            FuncName, getSILType(Ty, (SILValueCategory)TyCategory, nullptr),
            Builder.getTypeExpansionContext()));
    break;
  }
  case SILInstructionKind::PreviousDynamicFunctionRefInst: {
    auto Ty = MF->getType(TyID);
    StringRef FuncName = MF->getIdentifierText(ValID);
    ResultInst = Builder.createPreviousDynamicFunctionRef(
        Loc,
        getFuncForReference(
            FuncName, getSILType(Ty, (SILValueCategory)TyCategory, nullptr),
            Builder.getTypeExpansionContext()));
    break;
  }
  case SILInstructionKind::MarkDependenceInst: {
    auto Ty = MF->getType(TyID);
    auto Ty2 = MF->getType(TyID2);
    ResultInst = Builder.createMarkDependence(
        Loc,
        getLocalValue(Builder.maybeGetFunction(), ValID,
                      getSILType(Ty, (SILValueCategory)TyCategory, Fn)),
        getLocalValue(Builder.maybeGetFunction(), ValID2,
                      getSILType(Ty2, (SILValueCategory)TyCategory2, Fn)),
        MarkDependenceKind(Attr));
    break;
  }
  case SILInstructionKind::MarkDependenceAddrInst: {
    auto Ty = MF->getType(TyID);
    auto Ty2 = MF->getType(TyID2);
    ResultInst = Builder.createMarkDependenceAddr(
        Loc,
        getLocalValue(Builder.maybeGetFunction(), ValID,
                      getSILType(Ty, (SILValueCategory)TyCategory, Fn)),
        getLocalValue(Builder.maybeGetFunction(), ValID2,
                      getSILType(Ty2, (SILValueCategory)TyCategory2, Fn)),
        MarkDependenceKind(Attr));
    break;
  }
  case SILInstructionKind::BeginDeallocRefInst: {
    auto Ty = MF->getType(TyID);
    auto Ty2 = MF->getType(TyID2);
    ResultInst = Builder.createBeginDeallocRef(
        Loc,
        getLocalValue(Builder.maybeGetFunction(), ValID,
                      getSILType(Ty, (SILValueCategory)TyCategory, Fn)),
        getLocalValue(Builder.maybeGetFunction(), ValID2,
                      getSILType(Ty2, (SILValueCategory)TyCategory2, Fn)));
    break;
  }
  case SILInstructionKind::CopyBlockWithoutEscapingInst: {
    auto Ty = MF->getType(TyID);
    auto Ty2 = MF->getType(TyID2);
    ResultInst = Builder.createCopyBlockWithoutEscaping(
        Loc,
        getLocalValue(Builder.maybeGetFunction(), ValID,
                      getSILType(Ty, (SILValueCategory)TyCategory, Fn)),
        getLocalValue(Builder.maybeGetFunction(), ValID2,
                      getSILType(Ty2, (SILValueCategory)TyCategory2, Fn)));
    break;
  }
  case SILInstructionKind::VectorBaseAddrInst: {
    assert(RecordKind == SIL_ONE_TYPE_ONE_OPERAND);
    ResultInst = Builder.createVectorBaseAddr(
        Loc,
        getLocalValue(
            Builder.maybeGetFunction(), ValID,
            getSILType(MF->getType(TyID2), (SILValueCategory)TyCategory2, Fn)));
    break;
  }
  case SILInstructionKind::IndexAddrInst: {
    auto Ty = MF->getType(TyID);
    auto Ty2 = MF->getType(TyID2);
    ResultInst = Builder.createIndexAddr(
        Loc,
        getLocalValue(Builder.maybeGetFunction(), ValID,
                      getSILType(Ty, (SILValueCategory)TyCategory, Fn)),
        getLocalValue(Builder.maybeGetFunction(), ValID2,
                      getSILType(Ty2, (SILValueCategory)TyCategory2, Fn)),
        /*needsStackProtection=*/(Attr & 1) != 0,
        /*isProjection=*/(Attr & 2) != 0);
    break;
  }
  case SILInstructionKind::TailAddrInst: {
    auto Ty = MF->getType(TyID);
    auto Ty2 = MF->getType(TyID2);
    auto ResultTy = MF->getType(TyID3);
    ResultInst = Builder.createTailAddr(
        Loc,
        getLocalValue(Builder.maybeGetFunction(), ValID,
                      getSILType(Ty, SILValueCategory::Address, Fn)),
        getLocalValue(Builder.maybeGetFunction(), ValID2,
                      getSILType(Ty2, SILValueCategory::Object, Fn)),
        getSILType(ResultTy, SILValueCategory::Address, Fn));
    break;
  }
  case SILInstructionKind::IndexRawPointerInst: {
    auto Ty = MF->getType(TyID);
    auto Ty2 = MF->getType(TyID2);
    ResultInst = Builder.createIndexRawPointer(
        Loc,
        getLocalValue(Builder.maybeGetFunction(), ValID,
                      getSILType(Ty, (SILValueCategory)TyCategory, Fn)),
        getLocalValue(Builder.maybeGetFunction(), ValID2,
                      getSILType(Ty2, (SILValueCategory)TyCategory2, Fn)));
    break;
  }
  case SILInstructionKind::IncrementProfilerCounterInst: {
    auto PGOFuncName = MF->getIdentifierText(ValID);
    auto PGOHashStr = MF->getIdentifierText(ValID2);

    uint64_t PGOHash;
    auto HadError = PGOHashStr.getAsInteger(/*radix*/ 10, PGOHash);
    assert(!HadError && "Failed to deserialize PGO hash");
    (void)HadError;

    ResultInst = Builder.createIncrementProfilerCounter(
        Loc, /*CounterIdx*/ Attr, PGOFuncName, /*NumCounters*/ Attr2, PGOHash);
    break;
  }
  case SILInstructionKind::IntegerLiteralInst: {
    auto Ty = MF->getType(TyID);
    auto intTy = Ty->castTo<AnyBuiltinIntegerType>();
    StringRef text = MF->getIdentifierText(ValID);
    bool negate = text[0] == '-';
    if (negate) text = text.drop_front();
    APInt value = intTy->getWidth().parse(text, 10, negate);
    ResultInst = Builder.createIntegerLiteral(
        Loc, getSILType(Ty, (SILValueCategory)TyCategory, Fn), value);
    break;
  }
  case SILInstructionKind::FloatLiteralInst: {
    auto Ty = MF->getType(TyID);
    auto floatTy = Ty->castTo<BuiltinFloatType>();
    StringRef StringVal = MF->getIdentifierText(ValID);
    // Build APInt from string.
    APInt bits(floatTy->getBitWidth(), StringVal, 16);
    if (bits.getBitWidth() != floatTy->getBitWidth())
      bits = bits.zextOrTrunc(floatTy->getBitWidth());

    APFloat value(floatTy->getAPFloatSemantics(), bits);

    ResultInst = Builder.createFloatLiteral(
        Loc, getSILType(Ty, (SILValueCategory)TyCategory, Fn), value);
    break;
  }
  case SILInstructionKind::StringLiteralInst: {
    StringRef StringVal = MF->getIdentifierText(ValID);
    auto encoding = fromStableStringEncoding(Attr);
    if (!encoding) return true;
    ResultInst =
        Builder.createStringLiteral(Loc, StringVal, encoding.value());
    break;
  }
  case SILInstructionKind::CondFailInst: {
    SILValue Op = getLocalValue(
        Builder.maybeGetFunction(), ValID,
        getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn));
    StringRef StringVal = MF->getIdentifierText(ValID2);
    ResultInst = Builder.createCondFail(Loc, Op, StringVal);
    break;
  }
  case SILInstructionKind::MarkFunctionEscapeInst: {
    // Format: a list of typed values. A typed value is expressed by 4 IDs:
    // TypeID, TypeCategory, ValueID, ValueResultNumber.
    SmallVector<SILValue, 4> OpList;
    for (unsigned I = 0, E = ListOfValues.size(); I < E; I += 3) {
      auto EltTy = MF->getType(ListOfValues[I]);
      OpList.push_back(getLocalValue(
          Builder.maybeGetFunction(), ListOfValues[I + 2],
          getSILType(EltTy, (SILValueCategory)ListOfValues[I + 1], Fn)));
    }
    ResultInst = Builder.createMarkFunctionEscape(Loc, OpList);
    break;
  }
  // Checked Conversion instructions.
  case SILInstructionKind::UnconditionalCheckedCastInst: {
    CheckedCastInstOptions options(ListOfValues[4]);
    SILType srcLoweredType = getSILType(MF->getType(ListOfValues[1]),
                                        (SILValueCategory)ListOfValues[2], Fn);
    SILValue src = getLocalValue(Builder.maybeGetFunction(), ListOfValues[0],
                                 srcLoweredType);

    SILType targetLoweredType =
        getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn);
    CanType targetFormalType =
        MF->getType(ListOfValues[3])->getCanonicalType();
    ResultInst = Builder.createUnconditionalCheckedCast(
        Loc, options, src, targetLoweredType, targetFormalType);
    break;
  }

#define UNARY_INSTRUCTION(ID)                                                  \
  case SILInstructionKind::ID##Inst:                                           \
    assert(RecordKind == SIL_ONE_OPERAND && "Layout should be OneOperand.");   \
    ResultInst = Builder.create##ID(                                           \
        Loc, getLocalValue(Builder.maybeGetFunction(), ValID,                  \
                           getSILType(MF->getType(TyID),                       \
                                      (SILValueCategory)TyCategory, Fn)));     \
    break;

#define REFCOUNTING_INSTRUCTION(ID)                                            \
  case SILInstructionKind::ID##Inst:                                           \
    assert(RecordKind == SIL_ONE_OPERAND && "Layout should be OneOperand.");   \
    ResultInst = Builder.create##ID(                                           \
        Loc,                                                                   \
        getLocalValue(                                                         \
            Builder.maybeGetFunction(), ValID,                                 \
            getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn)),  \
        (Atomicity)Attr);                                                      \
    break;

    UNARY_INSTRUCTION(UnownedCopyValue)
    UNARY_INSTRUCTION(WeakCopyValue)
#define UNCHECKED_REF_STORAGE(Name, ...)                                       \
  UNARY_INSTRUCTION(StrongCopy##Name##Value)
#define ALWAYS_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...)            \
  REFCOUNTING_INSTRUCTION(Name##Retain)                                        \
  REFCOUNTING_INSTRUCTION(Name##Release)                                       \
  REFCOUNTING_INSTRUCTION(StrongRetain##Name)                                  \
  UNARY_INSTRUCTION(StrongCopy##Name##Value)
#define NEVER_LOADABLE_CHECKED_REF_STORAGE(Name, ...)                          \
  UNARY_INSTRUCTION(StrongCopy##Name##Value)
#include "swift/AST/ReferenceStorage.def"
  REFCOUNTING_INSTRUCTION(RetainValue)
  REFCOUNTING_INSTRUCTION(RetainValueAddr)
  REFCOUNTING_INSTRUCTION(UnmanagedRetainValue)
  UNARY_INSTRUCTION(CopyValue)
  UNARY_INSTRUCTION(ExplicitCopyValue)
  REFCOUNTING_INSTRUCTION(ReleaseValue)
  REFCOUNTING_INSTRUCTION(ReleaseValueAddr)
  REFCOUNTING_INSTRUCTION(UnmanagedReleaseValue)
  REFCOUNTING_INSTRUCTION(AutoreleaseValue)
  REFCOUNTING_INSTRUCTION(UnmanagedAutoreleaseValue)
  UNARY_INSTRUCTION(DeinitExistentialAddr)
  UNARY_INSTRUCTION(DeinitExistentialValue)
  UNARY_INSTRUCTION(EndBorrow)
  UNARY_INSTRUCTION(DestroyAddr)
  UNARY_INSTRUCTION(Return)
  UNARY_INSTRUCTION(Throw)
  UNARY_INSTRUCTION(ClassifyBridgeObject)
  UNARY_INSTRUCTION(ValueToBridgeObject)
  UNARY_INSTRUCTION(FixLifetime)
  UNARY_INSTRUCTION(EndLifetime)
  UNARY_INSTRUCTION(ExtendLifetime)
  UNARY_INSTRUCTION(CopyBlock)
  UNARY_INSTRUCTION(EndInitLetRef)
  REFCOUNTING_INSTRUCTION(StrongRetain)
  REFCOUNTING_INSTRUCTION(StrongRelease)
  UNARY_INSTRUCTION(IsUnique)
  UNARY_INSTRUCTION(AbortApply)
  UNARY_INSTRUCTION(ExtractExecutor)
  UNARY_INSTRUCTION(FunctionExtractIsolation)
  UNARY_INSTRUCTION(MakeBorrow)
  UNARY_INSTRUCTION(DereferenceBorrow)
  UNARY_INSTRUCTION(MakeAddrBorrow)
  UNARY_INSTRUCTION(DereferenceAddrBorrow)
  UNARY_INSTRUCTION(DereferenceBorrowAddr)
#undef UNARY_INSTRUCTION
#undef REFCOUNTING_INSTRUCTION

  case SILInstructionKind::LoadBorrowInst: {
    assert(RecordKind == SIL_ONE_OPERAND && "Layout should be OneOperand.");
    auto LB = Builder.createLoadBorrow(
        Loc, getLocalValue(Builder.maybeGetFunction(), ValID,
                           getSILType(MF->getType(TyID),
                                      (SILValueCategory)TyCategory, Fn)));
    LB->setUnchecked(Attr != 0);
    ResultInst = LB;
    break;
  }

  case SILInstructionKind::BeginBorrowInst: {
    assert(RecordKind == SIL_ONE_OPERAND && "Layout should be OneOperand.");
    auto isLexical = IsLexical_t(Attr & 0x1);
    auto hasPointerEscape = HasPointerEscape_t((Attr >> 1) & 0x1);
    auto fromVarDecl = IsFromVarDecl_t((Attr >> 2) & 0x1);
    auto isFixed = BeginBorrowInst::IsFixed_t((Attr >> 3) & 0x1);
    ResultInst = Builder.createBeginBorrow(
        Loc,
        getLocalValue(
            Builder.maybeGetFunction(), ValID,
            getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn)),
        isLexical, hasPointerEscape, fromVarDecl, isFixed);
    break;
  }

  case SILInstructionKind::DestroyNotEscapedClosureInst: {
    assert(RecordKind == SIL_ONE_OPERAND && "Layout should be OneOperand.");
    unsigned verificationType = Attr;
    ResultInst = Builder.createDestroyNotEscapedClosure(
        Loc,
        getLocalValue(
            Builder.maybeGetFunction(), ValID,
            getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn)),
        verificationType);
    break;
  }

  case SILInstructionKind::HopToExecutorInst: {
    assert(RecordKind == SIL_ONE_OPERAND && "Layout should be OneOperand.");
    unsigned mandatory = Attr;
    ResultInst = Builder.createHopToExecutor(
        Loc,
        getLocalValue(
            Builder.maybeGetFunction(), ValID,
            getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn)),
        mandatory != 0);
    break;
  }
  case SILInstructionKind::DestroyValueInst: {
    assert(RecordKind == SIL_ONE_OPERAND && "Layout should be OneOperand.");
    IsDeadEnd_t isDeadEnd = IsDeadEnd_t(Attr & 0x1);
    ResultInst = Builder.createDestroyValue(
        Loc,
        getLocalValue(
            Builder.maybeGetFunction(), ValID,
            getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn)),
        isDeadEnd);
    break;
  }

  case SILInstructionKind::BeginCOWMutationInst: {
    assert(RecordKind == SIL_ONE_OPERAND && "Layout should be OneOperand.");
    unsigned isNative = Attr;
    ResultInst = Builder.createBeginCOWMutation(
        Loc,
        getLocalValue(
            Builder.maybeGetFunction(), ValID,
            getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn)),
        isNative != 0);
    break;
  }

  case SILInstructionKind::EndCOWMutationInst: {
    assert(RecordKind == SIL_ONE_OPERAND && "Layout should be OneOperand.");
    unsigned keepUnique = Attr;
    ResultInst = Builder.createEndCOWMutation(
        Loc,
        getLocalValue(
            Builder.maybeGetFunction(), ValID,
            getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn)),
        keepUnique != 0);
    break;
  }

  case SILInstructionKind::EndCOWMutationAddrInst: {
    assert(RecordKind == SIL_ONE_OPERAND && "Layout should be OneOperand.");
    ResultInst = Builder.createEndCOWMutationAddr(
        Loc, getLocalValue(Builder.maybeGetFunction(), ValID,
                           getSILType(MF->getType(TyID),
                                      (SILValueCategory)TyCategory, Fn)));
    break;
  }

  case SILInstructionKind::DestructureTupleInst: {
    assert(RecordKind == SIL_ONE_OPERAND && "Layout should be OneOperand.");
    SILValue Operand = getLocalValue(
        Builder.maybeGetFunction(), ValID,
        getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn));
    ResultInst = Builder.createDestructureTuple(Loc, Operand);
    break;
  }
  case SILInstructionKind::DestructureStructInst: {
    assert(RecordKind == SIL_ONE_OPERAND && "Layout should be OneOperand.");
    SILValue Operand = getLocalValue(
        Builder.maybeGetFunction(), ValID,
        getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn));
    ResultInst = Builder.createDestructureStruct(Loc, Operand);
    break;
  }
  case SILInstructionKind::ImplicitActorToOpaqueIsolationCastInst: {
    assert(RecordKind == SIL_ONE_OPERAND);
    auto Ty = MF->getType(TyID);
    ResultInst = Builder.createImplicitActorToOpaqueIsolationCast(
        Loc, getLocalValue(Builder.maybeGetFunction(), ValID,
                           getSILType(Ty, (SILValueCategory)TyCategory, Fn)));
    break;
  }
  case SILInstructionKind::UncheckedOwnershipConversionInst: {
    auto Ty = MF->getType(TyID);
    auto ResultKind = decodeValueOwnership(Attr);
    ResultInst = Builder.createUncheckedOwnershipConversion(
        Loc,
        getLocalValue(Builder.maybeGetFunction(), ValID,
                      getSILType(Ty, (SILValueCategory)TyCategory, Fn)),
        ResultKind);
    break;
  }

  case SILInstructionKind::MoveValueInst: {
    auto Ty = MF->getType(TyID);
    bool AllowsDiagnostics = Attr & 0x1;
    IsLexical_t isLexical = IsLexical_t((Attr >> 1) & 0x1);
    auto isEscaping = HasPointerEscape_t((Attr >> 2) & 0x1);
    auto isFromVarDecl = IsFromVarDecl_t((Attr >> 3) & 0x1);
    auto *MVI = Builder.createMoveValue(
        Loc,
        getLocalValue(Builder.maybeGetFunction(), ValID,
                      getSILType(Ty, (SILValueCategory)TyCategory, Fn)),
        isLexical, isEscaping, isFromVarDecl);
    MVI->setAllowsDiagnostics(AllowsDiagnostics);
    ResultInst = MVI;
    break;
  }

  case SILInstructionKind::DropDeinitInst: {
    auto Ty = MF->getType(TyID);
    ResultInst = Builder.createDropDeinit(
        Loc, getLocalValue(Builder.maybeGetFunction(), ValID,
                           getSILType(Ty, (SILValueCategory)TyCategory, Fn)));
    break;
  }

  case SILInstructionKind::MarkUnresolvedReferenceBindingInst: {
    using Kind = MarkUnresolvedReferenceBindingInst::Kind;
    auto ty = MF->getType(TyID);
    auto kind = Kind(Attr);
    ResultInst = Builder.createMarkUnresolvedReferenceBindingInst(
        Loc,
        getLocalValue(Builder.maybeGetFunction(), ValID,
                      getSILType(ty, (SILValueCategory)TyCategory, Fn)),
        kind);
    break;
  }

  case SILInstructionKind::MoveOnlyWrapperToCopyableValueInst: {
    auto Ty = MF->getType(TyID);
    bool isOwned = bool(Attr);
    if (isOwned)
      ResultInst = Builder.createOwnedMoveOnlyWrapperToCopyableValue(
          Loc, getLocalValue(Builder.maybeGetFunction(), ValID,
                             getSILType(Ty, (SILValueCategory)TyCategory, Fn)));
    else
      ResultInst = Builder.createGuaranteedMoveOnlyWrapperToCopyableValue(
          Loc, getLocalValue(Builder.maybeGetFunction(), ValID,
                             getSILType(Ty, (SILValueCategory)TyCategory, Fn)));
    break;
  }

  case SILInstructionKind::CopyableToMoveOnlyWrapperValueInst: {
    auto Ty = MF->getType(TyID);
    bool isOwned = bool(Attr);
    if (isOwned)
      ResultInst = Builder.createOwnedCopyableToMoveOnlyWrapperValue(
          Loc, getLocalValue(Builder.maybeGetFunction(), ValID,
                             getSILType(Ty, (SILValueCategory)TyCategory, Fn)));
    else
      ResultInst = Builder.createGuaranteedCopyableToMoveOnlyWrapperValue(
          Loc, getLocalValue(Builder.maybeGetFunction(), ValID,
                             getSILType(Ty, (SILValueCategory)TyCategory, Fn)));
    break;
  }

  case SILInstructionKind::LoadInst: {
    auto Ty = MF->getType(TyID);
    auto Qualifier = LoadOwnershipQualifier(Attr);
    ResultInst = Builder.createLoad(
        Loc,
        getLocalValue(Builder.maybeGetFunction(), ValID,
                      getSILType(Ty, (SILValueCategory)TyCategory, Fn)),
        Qualifier);
    break;
  }

#define NEVER_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...)             \
  case SILInstructionKind::Load##Name##Inst: {                                 \
    auto Ty = MF->getType(TyID);                                               \
    bool isTake = (Attr > 0);                                                  \
    auto Val =                                                                 \
        getLocalValue(Builder.maybeGetFunction(), ValID,                       \
                      getSILType(Ty, SILValueCategory(TyCategory), Fn));       \
    ResultInst = Builder.createLoad##Name(Loc, Val, IsTake_t(isTake));         \
    break;                                                                     \
  }                                                                            \
  case SILInstructionKind::Store##Name##Inst: {                                \
    auto Ty = MF->getType(TyID);                                               \
    SILType addrType = getSILType(Ty, (SILValueCategory)TyCategory, Fn);       \
    auto refType = addrType.castTo<Name##StorageType>();                       \
    auto ValType = SILType::getPrimitiveObjectType(refType.getReferentType()); \
    bool isInit = (Attr > 0);                                                  \
    ResultInst = Builder.createStore##Name(                                    \
        Loc, getLocalValue(Builder.maybeGetFunction(), ValID, ValType),        \
        getLocalValue(Builder.maybeGetFunction(), ValID2, addrType),           \
        IsInitialization_t(isInit));                                           \
    break;                                                                     \
  }
#include "swift/AST/ReferenceStorage.def"
  case SILInstructionKind::MarkUninitializedInst: {
    auto Ty = getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn);
    auto Kind = (MarkUninitializedInst::Kind)Attr;
    auto Val = getLocalValue(Builder.maybeGetFunction(), ValID, Ty);
    ResultInst = Builder.createMarkUninitialized(Loc, Val, Kind);
    break;
  }
  case SILInstructionKind::MarkUnresolvedNonCopyableValueInst: {
    using CheckKind = MarkUnresolvedNonCopyableValueInst::CheckKind;
    auto Ty = MF->getType(TyID);
    auto CKind = CheckKind(Attr & 7);
    auto Strict = Attr & (1 << 3)
      ? MarkUnresolvedNonCopyableValueInst::IsStrict
      : MarkUnresolvedNonCopyableValueInst::IsNotStrict;
    ResultInst = Builder.createMarkUnresolvedNonCopyableValueInst(
        Loc,
        getLocalValue(Builder.maybeGetFunction(), ValID,
                      getSILType(Ty, (SILValueCategory)TyCategory, Fn)),
        CKind, Strict);
    break;
  }
  case SILInstructionKind::UncheckedOwnershipInst: {
    llvm_unreachable("Invalid unchecked_ownership in deserialization");
  }
  case SILInstructionKind::StoreInst: {
    auto Ty = MF->getType(TyID);
    SILType addrType = getSILType(Ty, (SILValueCategory)TyCategory, Fn);
    SILType ValType = addrType.getObjectType();
    auto Qualifier = StoreOwnershipQualifier(Attr);
    ResultInst = Builder.createStore(
        Loc, getLocalValue(Builder.maybeGetFunction(), ValID, ValType),
        getLocalValue(Builder.maybeGetFunction(), ValID2, addrType), Qualifier);
    break;
  }
  case SILInstructionKind::StoreBorrowInst: {
    auto Ty = MF->getType(TyID);
    SILType addrType = getSILType(Ty, (SILValueCategory)TyCategory, Fn);
    SILType ValType = addrType.getObjectType();
    ResultInst = Builder.createStoreBorrow(
        Loc, getLocalValue(Builder.maybeGetFunction(), ValID, ValType),
        getLocalValue(Builder.maybeGetFunction(), ValID2, addrType));
    break;
  }
  case SILInstructionKind::BeginAccessInst: {
    SILValue op = getLocalValue(
        Builder.maybeGetFunction(), ValID,
        getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn));
    auto accessKind = SILAccessKind(Attr & 0x3);
    auto enforcement = SILAccessEnforcement((Attr >> 2) & 0x07);
    bool noNestedConflict = (Attr >> 5) & 0x01;
    bool fromBuiltin = (Attr >> 6) & 0x01;
    ResultInst = Builder.createBeginAccess(Loc, op, accessKind, enforcement,
                                           noNestedConflict, fromBuiltin);
    break;
  }
  case SILInstructionKind::MoveOnlyWrapperToCopyableAddrInst: {
    assert(RecordKind == SIL_ONE_OPERAND);
    SILValue op = getLocalValue(
        Builder.maybeGetFunction(), ValID,
        getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn));
    ResultInst = Builder.createMoveOnlyWrapperToCopyableAddr(Loc, op);
    break;
  }
  case SILInstructionKind::MoveOnlyWrapperToCopyableBoxInst: {
    assert(RecordKind == SIL_ONE_OPERAND);
    SILValue op = getLocalValue(
        Builder.maybeGetFunction(), ValID,
        getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn));
    ResultInst = Builder.createMoveOnlyWrapperToCopyableBox(Loc, op);
    break;
  }
  case SILInstructionKind::CopyableToMoveOnlyWrapperAddrInst: {
    assert(RecordKind == SIL_ONE_OPERAND);
    SILValue op = getLocalValue(
        Builder.maybeGetFunction(), ValID,
        getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn));
    ResultInst = Builder.createCopyableToMoveOnlyWrapperAddr(Loc, op);
    break;
  }
  case SILInstructionKind::EndAccessInst: {
    SILValue op = getLocalValue(
        Builder.maybeGetFunction(), ValID,
        getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn));
    bool aborted = Attr & 0x1;
    ResultInst = Builder.createEndAccess(Loc, op, aborted);
    break;
  }
  case SILInstructionKind::BeginUnpairedAccessInst: {
    SILValue source = getLocalValue(
        Builder.maybeGetFunction(), ValID,
        getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn));
    SILValue buffer = getLocalValue(
        Builder.maybeGetFunction(), ValID2,
        getSILType(MF->getType(TyID2), (SILValueCategory)TyCategory2, Fn));
    auto accessKind = SILAccessKind(Attr & 0x3);
    auto enforcement = SILAccessEnforcement((Attr >> 2) & 0x07);
    bool noNestedConflict = (Attr >> 5) & 0x01;
    bool fromBuiltin = (Attr >> 6) & 0x01;
    ResultInst = Builder.createBeginUnpairedAccess(
        Loc, source, buffer, accessKind, enforcement, noNestedConflict,
        fromBuiltin);
    break;
  }
  case SILInstructionKind::EndUnpairedAccessInst: {
    SILValue op = getLocalValue(
        Builder.maybeGetFunction(), ValID,
        getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn));
    bool aborted = Attr & 0x1;
    auto enforcement = SILAccessEnforcement((Attr >> 1) & 0x07);
    bool fromBuiltin = (Attr >> 4) & 0x01;
    ResultInst = Builder.createEndUnpairedAccess(Loc, op, enforcement, aborted,
                                                 fromBuiltin);
    break;
  }
  case SILInstructionKind::InitBorrowAddrInst: {
    auto Ty = MF->getType(TyID);
    SILType addrType = getSILType(Ty, (SILValueCategory)TyCategory, Fn);
    auto refType = SILType::getPrimitiveAddressType(
      addrType.castTo<BuiltinBorrowType>()->getReferentType());
    auto referent = getLocalValue(Builder.maybeGetFunction(), ValID, refType);
    auto borrow = getLocalValue(Builder.maybeGetFunction(), ValID2, addrType);
    ResultInst = Builder.createInitBorrowAddr(Loc, borrow, referent);
    break;
  }
  case SILInstructionKind::CopyAddrInst: {
    auto Ty = MF->getType(TyID);
    SILType addrType = getSILType(Ty, (SILValueCategory)TyCategory, Fn);
    bool isInit = (Attr & 0x2) > 0;
    bool isTake = (Attr & 0x1) > 0;
    ResultInst = Builder.createCopyAddr(
        Loc, getLocalValue(Builder.maybeGetFunction(), ValID, addrType),
        getLocalValue(Builder.maybeGetFunction(), ValID2, addrType),
        IsTake_t(isTake), IsInitialization_t(isInit));
    break;
  }
  case SILInstructionKind::ExplicitCopyAddrInst: {
    auto Ty = MF->getType(TyID);
    SILType addrType = getSILType(Ty, (SILValueCategory)TyCategory, Fn);
    bool isInit = (Attr & 0x2) > 0;
    bool isTake = (Attr & 0x1) > 0;
    ResultInst = Builder.createExplicitCopyAddr(
        Loc, getLocalValue(Builder.maybeGetFunction(), ValID, addrType),
        getLocalValue(Builder.maybeGetFunction(), ValID2, addrType),
        IsTake_t(isTake), IsInitialization_t(isInit));
    break;
  }

  case SILInstructionKind::MarkUnresolvedMoveAddrInst: {
    auto Ty = MF->getType(TyID);
    SILType addrType = getSILType(Ty, (SILValueCategory)TyCategory, Fn);
    ResultInst = Builder.createMarkUnresolvedMoveAddr(
        Loc, getLocalValue(Builder.maybeGetFunction(), ValID, addrType),
        getLocalValue(Builder.maybeGetFunction(), ValID2, addrType));
    break;
  }

  case SILInstructionKind::AssignInst: {
    auto Ty = MF->getType(TyID);
    SILType addrType = getSILType(Ty, (SILValueCategory)TyCategory, Fn);
    SILType valType = addrType.getObjectType();
    auto qualifier = AssignOwnershipQualifier(Attr);
    ResultInst = Builder.createAssign(
        Loc, getLocalValue(Builder.maybeGetFunction(), ValID, valType),
        getLocalValue(Builder.maybeGetFunction(), ValID2, addrType), qualifier);
    break;
  }
  case SILInstructionKind::AssignOrInitInst:
    llvm_unreachable("not supported");
  case SILInstructionKind::BindMemoryInst: {
    assert(RecordKind == SIL_ONE_TYPE_VALUES &&
           "Layout should be OneTypeValues.");
    auto Ty = MF->getType(TyID);   // BoundTy
    ResultInst = Builder.createBindMemory(
        Loc,
        getLocalValue(Builder.maybeGetFunction(), ListOfValues[2],
                      getSILType(MF->getType(ListOfValues[0]),
                                 (SILValueCategory)ListOfValues[1], Fn)),
        getLocalValue(Builder.maybeGetFunction(), ListOfValues[5],
                      getSILType(MF->getType(ListOfValues[3]),
                                 (SILValueCategory)ListOfValues[4], Fn)),
        getSILType(Ty, (SILValueCategory)TyCategory, Fn));
    break;
  }
  case SILInstructionKind::RebindMemoryInst: {
    assert(RecordKind == SIL_TWO_OPERANDS && "Layout should be TwoOperands.");
    auto Ty = MF->getType(TyID);
    auto Ty2 = MF->getType(TyID2);
    ResultInst = Builder.createRebindMemory(
        Loc,
        getLocalValue(Builder.maybeGetFunction(), ValID,
                      getSILType(Ty, (SILValueCategory)TyCategory, Fn)),
        getLocalValue(Builder.maybeGetFunction(), ValID2,
                      getSILType(Ty2, (SILValueCategory)TyCategory2, Fn)));
    break;
  }
  case SILInstructionKind::StructElementAddrInst:
  case SILInstructionKind::StructExtractInst: {
    // Use SILOneValueOneOperandLayout.
    VarDecl *Field = cast<VarDecl>(MF->getDecl(ValID));
    auto Ty = MF->getType(TyID);
    auto Val = getLocalValue(Builder.maybeGetFunction(), ValID2,
                             getSILType(Ty, (SILValueCategory)TyCategory, Fn));
    auto ResultTy = Val->getType().getFieldType(
        Field, SILMod, Builder.getTypeExpansionContext());
    if (OpCode == SILInstructionKind::StructElementAddrInst)
      ResultInst = Builder.createStructElementAddr(Loc, Val, Field,
                                                   ResultTy.getAddressType());
    else
      ResultInst = Builder.createStructExtract(Loc, Val, Field,
                                               ResultTy.getObjectType());
    break;
  }
  case SILInstructionKind::StructInst:
  case SILInstructionKind::BorrowedFromInst: {
    // Format: a type followed by a list of typed values. A typed value is
    // expressed by 4 IDs: TypeID, TypeCategory, ValueID, ValueResultNumber.
    auto Ty = MF->getType(TyID);
    SmallVector<SILValue, 4> OpList;
    for (unsigned I = 0, E = ListOfValues.size(); I < E; I += 3) {
      auto EltTy = MF->getType(ListOfValues[I]);
      OpList.push_back(getLocalValue(
          Builder.maybeGetFunction(), ListOfValues[I + 2],
          getSILType(EltTy, (SILValueCategory)ListOfValues[I + 1], Fn)));
    }
    if (OpCode == SILInstructionKind::StructInst) {
      ResultInst = Builder.createStruct(
        Loc, getSILType(Ty, (SILValueCategory)TyCategory, Fn), OpList);
    } else {
      ResultInst = Builder.createBorrowedFrom(
        Loc, OpList[0], ArrayRef(OpList).drop_front());
    }
    break;
  }
  case SILInstructionKind::ReturnBorrowInst: {
    SmallVector<SILValue, 4> OpList;
    for (unsigned I = 0, E = ListOfValues.size(); I < E; I += 3) {
      auto EltTy = MF->getType(ListOfValues[I]);
      OpList.push_back(getLocalValue(
          Builder.maybeGetFunction(), ListOfValues[I + 2],
          getSILType(EltTy, (SILValueCategory)ListOfValues[I + 1], Fn)));
    }
    ResultInst = Builder.createReturnBorrow(Loc, OpList[0],
                                            ArrayRef(OpList).drop_front());
    break;
  }
  case SILInstructionKind::TupleElementAddrInst:
  case SILInstructionKind::TupleExtractInst: {
    // Use OneTypeOneOperand layout where the field number is stored in TypeID.
    auto Ty2 = MF->getType(TyID2);
    SILType ST = getSILType(Ty2, (SILValueCategory)TyCategory2, Fn);
    TupleType *TT = ST.castTo<TupleType>();

    auto ResultTy = TT->getElement(TyID).getType();
    switch (OpCode) {
    default: llvm_unreachable("Out of sync with parent switch");
    case SILInstructionKind::TupleElementAddrInst:
      ResultInst = Builder.createTupleElementAddr(
          Loc, getLocalValue(Builder.maybeGetFunction(), ValID, ST), TyID,
          getSILType(ResultTy, SILValueCategory::Address, Fn));
      break;
    case SILInstructionKind::TupleExtractInst:
      ResultInst = Builder.createTupleExtract(
          Loc, getLocalValue(Builder.maybeGetFunction(), ValID, ST), TyID,
          getSILType(ResultTy, SILValueCategory::Object, Fn));
      break;
    }
    break;
  }
  case SILInstructionKind::TupleInst: {
    // Format: a type followed by a list of values. A value is expressed by
    // 2 IDs: ValueID, ValueResultNumber.
    auto Ty = MF->getType(TyID);
    TupleType *TT = Ty->castTo<TupleType>();
    assert(TT && "Type of a TupleInst should be TupleType");
    SmallVector<SILValue, 4> OpList;
    for (unsigned I = 0, E = ListOfValues.size(); I < E; ++I) {
      Type EltTy = TT->getElement(I).getType();
      OpList.push_back(
          getLocalValue(Builder.maybeGetFunction(), ListOfValues[I],
                        getSILType(EltTy, SILValueCategory::Object, Fn)));
    }
    ResultInst = Builder.createTuple(
        Loc, getSILType(Ty, (SILValueCategory)TyCategory, Fn), OpList);
    break;
  }
  case SILInstructionKind::TupleAddrConstructorInst: {
    assert(RecordKind == SIL_ONE_TYPE_VALUES_CATEGORIES);

    // Format: A type followed by a list of values. A value is expressed by 2
    // IDs: ValueID, ValueResultNumber. The type is the type of the first
    // element (which is our dest).
    auto Ty = MF->getType(TyID);
    TupleType *TT = Ty->castTo<TupleType>();
    assert(
        TT &&
        "Type of the DestAddr of a TupleAddrConstructor should be TupleType");
    assert(ListOfValues.size() >= 2 &&
           "Should have at least a dest and one element");

    auto getValue = [&](Type type, uint64_t value) -> SILValue {
      assert((value & 0xFFFFFFFF00000000) == 0 &&
             "High bits should never be set");
      uint32_t count = value & 0x7FFFFFFF;
      SILValueCategory category = value & 0x80000000 ? SILValueCategory::Address
                                                     : SILValueCategory::Object;
      return getLocalValue(Builder.maybeGetFunction(), count,
                           getSILType(type, category, Fn));
    };

    SILValue DestAddr = getValue(TT, ListOfValues[0]);

    SmallVector<SILValue, 4> OpList;
    unsigned Count = 1;

    visitExplodedTupleType(DestAddr->getType(), [&](SILType eltType) {
      OpList.push_back(getValue(eltType.getRawASTType(), ListOfValues[Count]));
      ++Count;
      return true;
    });
    auto IsInitOfDest = IsInitialization_t(Attr & 0x1);
    ResultInst =
        Builder.createTupleAddrConstructor(Loc, DestAddr, OpList, IsInitOfDest);
    break;
  }

  case SILInstructionKind::MergeIsolationRegionInst: {
    assert(RecordKind == SIL_VALUES);

    // Format: A type followed by a list of values. A value is expressed by 2
    // IDs: ValueID, TypeID... so we at least need 2 values and thus four
    // entires.
    assert(ListOfValues.size() >= 4 && "Should have at least two values.");
    assert((ListOfValues.size() & 1) == 0 &&
           "Should always have an even number of values since we store "
           "valueid, typeid");
    auto getValue = [&](Type type, uint64_t value) -> SILValue {
      assert((value & 0xFFFFFFFF00000000) == 0 &&
             "High bits should never be set");
      uint32_t count = value & 0x7FFFFFFF;
      SILValueCategory category = value & 0x80000000 ? SILValueCategory::Address
                                                     : SILValueCategory::Object;
      return getLocalValue(Builder.maybeGetFunction(), count,
                           getSILType(type, category, Fn));
    };

    SmallVector<SILValue, 4> OpList;
    for (unsigned i = 0, e = ListOfValues.size(); i != e; i += 2) {
      auto value = ListOfValues[i];
      auto type = MF->getType(ListOfValues[i + 1]);
      OpList.push_back(getValue(type, value));
    }
    ResultInst = Builder.createMergeIsolationRegion(Loc, OpList);
    break;
  }
  case SILInstructionKind::ObjectInst: {
    assert(RecordKind == SIL_ONE_TYPE_VALUES &&
           "Layout should be OneTypeValues.");
    unsigned NumVals = ListOfValues.size();
    assert(NumVals >= 1 && "Not enough values");
    unsigned numBaseElements = ListOfValues[0];
    SILType ClassTy =
        getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn);
    SmallVector<SILValue, 4> elements;
    for (unsigned i = 1; i < NumVals; i += 2) {
      SILType elementType = getSILType(MF->getType(ListOfValues[i + 1]),
                                       SILValueCategory::Object, Fn);
      SILValue elementVal = getLocalValue(Builder.maybeGetFunction(),
                                          ListOfValues[i], elementType);
      elements.push_back(elementVal);
    }
    ResultInst = Builder.createObject(Loc, ClassTy, elements, numBaseElements);
    break;
  }
  case SILInstructionKind::VectorInst: {
    auto EltTy = MF->getType(TyID);
    SmallVector<SILValue, 4> OpList;
    for (unsigned I = 0, E = ListOfValues.size(); I < E; ++I) {
      OpList.push_back(
          getLocalValue(Builder.maybeGetFunction(), ListOfValues[I],
                        getSILType(EltTy, SILValueCategory::Object, Fn)));
    }
    ResultInst = Builder.createVector(Loc, OpList);
    break;
  }

  case SILInstructionKind::BranchInst: {
    SmallVector<SILValue, 4> Args;
    for (unsigned I = 0, E = ListOfValues.size(); I < E; I += 3)
      Args.push_back(
          getLocalValue(Builder.maybeGetFunction(), ListOfValues[I + 2],
                        getSILType(MF->getType(ListOfValues[I]),
                                   (SILValueCategory)ListOfValues[I + 1], Fn)));

    ResultInst = Builder.createBranch(Loc, getBBForReference(Fn, TyID), Args);
    break;
  }
  case SILInstructionKind::CondBranchInst: {
    // Format: condition, true basic block ID, false basic block ID, and a
    // (always zero) count of true arguments. A cond_br never passes branch
    // arguments because SIL does not contain critical edges.
    SILValue Cond = getLocalValue(
        Builder.maybeGetFunction(), ListOfValues[0],
        getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn));

    assert(ListOfValues[3] == 0 && "cond_br must not have branch arguments");

    ResultInst = Builder.createCondBranch(
        Loc, Cond, getBBForReference(Fn, ListOfValues[1]),
        getBBForReference(Fn, ListOfValues[2]));
    break;
  }
  case SILInstructionKind::AwaitAsyncContinuationInst: {
    // Format: continuation, resume block ID, error block ID if given
    SILValue Cont = getLocalValue(
        Builder.maybeGetFunction(), ListOfValues[0],
        getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn));

    SILBasicBlock *resultBB = getBBForReference(Fn, ListOfValues[1]);
    SILBasicBlock *errorBB = nullptr;
    if (ListOfValues.size() >= 3) {
      errorBB = getBBForReference(Fn, ListOfValues[2]);
    }
    
    ResultInst = Builder.createAwaitAsyncContinuation(Loc, Cont, resultBB, errorBB);
    break;
  }
  case SILInstructionKind::SwitchEnumInst:
  case SILInstructionKind::SwitchEnumAddrInst: {
    // Format: condition, a list of cases (EnumElementDecl + Basic Block ID),
    // default basic block ID. Use SILOneTypeValuesLayout: the type is
    // for condition, the list has value for condition, hasDefault, default
    // basic block ID, a list of (DeclID, BasicBlock ID).
    SILValue Cond = getLocalValue(
        Builder.maybeGetFunction(), ListOfValues[0],
        getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn));

    SILBasicBlock *DefaultBB = nullptr;
    if (ListOfValues[1])
      DefaultBB = getBBForReference(Fn, ListOfValues[2]);

    SmallVector<std::pair<EnumElementDecl*, SILBasicBlock*>, 4> CaseBBs;
    for (unsigned I = 3, E = ListOfValues.size(); I < E; I += 2) {
      CaseBBs.push_back( {cast<EnumElementDecl>(MF->getDecl(ListOfValues[I])),
                            getBBForReference(Fn, ListOfValues[I+1])} );
    }
    if (OpCode == SILInstructionKind::SwitchEnumInst) {
      ResultInst =
          Builder.createSwitchEnum(Loc, Cond, DefaultBB, CaseBBs, std::nullopt,
                                   ProfileCounter(), forwardingOwnership);
    } else {
      ResultInst = Builder.createSwitchEnumAddr(Loc, Cond, DefaultBB, CaseBBs);
    }
    break;
  }
  case SILInstructionKind::SelectEnumInst:
  case SILInstructionKind::SelectEnumAddrInst: {
    // Format: condition, a list of cases (EnumElementDecl + Value ID),
    // default value ID. Use SILOneTypeValuesLayout: the type is
    // for condition, the list has value for condition, result type,
    //   hasDefault, default
    // basic block ID, a list of (DeclID, BasicBlock ID).
    SILValue Cond = getLocalValue(
        Builder.maybeGetFunction(), ListOfValues[0],
        getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn));

    Type ResultLoweredTy = MF->getType(ListOfValues[1]);
    SILValueCategory ResultCategory = (SILValueCategory)ListOfValues[2];
    SILType ResultTy = getSILType(ResultLoweredTy, ResultCategory, Fn);

    SILValue DefaultVal = nullptr;
    if (ListOfValues[3])
      DefaultVal =
          getLocalValue(Builder.maybeGetFunction(), ListOfValues[4], ResultTy);

    SmallVector<std::pair<EnumElementDecl*, SILValue>, 4> CaseVals;
    for (unsigned I = 5, E = ListOfValues.size(); I < E; I += 2) {
      auto Value = getLocalValue(Builder.maybeGetFunction(),
                                 ListOfValues[I + 1], ResultTy);
      CaseVals.push_back({cast<EnumElementDecl>(MF->getDecl(ListOfValues[I])),
                         Value});
    }
    if (OpCode == SILInstructionKind::SelectEnumInst)
      ResultInst =
          Builder.createSelectEnum(Loc, Cond, ResultTy, DefaultVal, CaseVals);
    else
      ResultInst = Builder.createSelectEnumAddr(Loc, Cond, ResultTy, DefaultVal,
                                                CaseVals);
    break;
  }
  case SILInstructionKind::SwitchValueInst: {
    // Format: condition, a list of cases (Value ID + Basic Block ID),
    // default basic block ID. Use SILOneTypeValuesLayout: the type is
    // for condition, the list contains value for condition, hasDefault, default
    // basic block ID, a list of (Value ID, BasicBlock ID).
    SILType ResultTy = getSILType(MF->getType(TyID),
                                             (SILValueCategory)TyCategory, Fn);
    SILValue Cond = getLocalValue(
        Builder.maybeGetFunction(), ListOfValues[0],
        getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn));

    SILBasicBlock *DefaultBB = nullptr;
    if (ListOfValues[1])
      DefaultBB = getBBForReference(Fn, ListOfValues[2]);

    SmallVector<std::pair<SILValue, SILBasicBlock*>, 4> CaseBBs;
    for (unsigned I = 3, E = ListOfValues.size(); I < E; I += 2) {
      auto value =
          getLocalValue(Builder.maybeGetFunction(), ListOfValues[I], ResultTy);
      CaseBBs.push_back( {value, getBBForReference(Fn, ListOfValues[I+1])} );
    }
    ResultInst = Builder.createSwitchValue(Loc, Cond, DefaultBB, CaseBBs);
    break;
  }
  case SILInstructionKind::EnumInst: {
    // Format: a type, an operand and a decl ID. Use SILTwoOperandsLayout: type,
    // (DeclID + hasOperand), and an operand.
    SILValue Operand;
    if (Attr)
      Operand = getLocalValue(
          Builder.maybeGetFunction(), ValID2,
          getSILType(MF->getType(TyID2), (SILValueCategory)TyCategory2, Fn));
    ResultInst = Builder.createEnum(
        Loc, Operand, cast<EnumElementDecl>(MF->getDecl(ValID)),
        getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn));
    break;
  }
  case SILInstructionKind::InitEnumDataAddrInst: {
    // Use SILOneValueOneOperandLayout.
    EnumElementDecl *Elt = cast<EnumElementDecl>(MF->getDecl(ValID));
    SILType OperandTy = getSILType(MF->getType(TyID),
                                   (SILValueCategory) TyCategory, Fn);
    SILType ResultTy = OperandTy.getEnumElementType(
        Elt, SILMod, Builder.getTypeExpansionContext());
    ResultInst = Builder.createInitEnumDataAddr(
        Loc, getLocalValue(Builder.maybeGetFunction(), ValID2, OperandTy), Elt,
        ResultTy);
    break;
  }
  case SILInstructionKind::UncheckedEnumDataInst: {
    // Use SILOneValueOneOperandLayout.
    EnumElementDecl *Elt = cast<EnumElementDecl>(MF->getDecl(ValID));
    SILType OperandTy =
        getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn);
    SILType ResultTy = OperandTy.getEnumElementType(
        Elt, SILMod, Builder.getTypeExpansionContext());
    ResultInst = Builder.createUncheckedEnumData(
        Loc, getLocalValue(Builder.maybeGetFunction(), ValID2, OperandTy), Elt,
        ResultTy);
    break;
  }
  case SILInstructionKind::UncheckedTakeEnumDataAddrInst: {
    // Use SILOneValueOneOperandLayout.
    EnumElementDecl *Elt = cast<EnumElementDecl>(MF->getDecl(ValID));
    SILType OperandTy =
        getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn);
    SILType ResultTy = OperandTy.getEnumElementType(
        Elt, SILMod, Builder.getTypeExpansionContext());
    ResultInst = Builder.createUncheckedTakeEnumDataAddr(
        Loc, getLocalValue(Builder.maybeGetFunction(), ValID2, OperandTy), Elt,
        ResultTy);
    break;
  }
  case SILInstructionKind::UncheckedInPlaceEnumDataAddrInst: {
    // Use SILOneValueOneOperandLayout.
    EnumElementDecl *Elt = cast<EnumElementDecl>(MF->getDecl(ValID));
    SILType OperandTy =
        getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn);
    SILType ResultTy = OperandTy.getEnumElementType(
        Elt, SILMod, Builder.getTypeExpansionContext());
    ResultInst = Builder.createUncheckedInPlaceEnumDataAddr(
        Loc, getLocalValue(Builder.maybeGetFunction(), ValID2, OperandTy), Elt,
        ResultTy);
    break;
  }
  case SILInstructionKind::UncheckedBorrowEnumDataAddrInst: {
    // Use SILOneTypeValuesLayout.
    EnumElementDecl *Elt = cast<EnumElementDecl>(MF->getDecl(ListOfValues[0]));

    SILType EnumTy =
        getSILType(MF->getType(ListOfValues[1]), (SILValueCategory)ListOfValues[2], Fn);
    SILValue Enum = getLocalValue(Builder.maybeGetFunction(), ListOfValues[3],
                                  EnumTy);
    
    SILType ScratchTy =
        getSILType(MF->getType(ListOfValues[4]), (SILValueCategory)ListOfValues[5], Fn);
    SILValue Scratch = getLocalValue(Builder.maybeGetFunction(), ListOfValues[6],
                                  ScratchTy);

    ResultInst = Builder.createUncheckedBorrowEnumDataAddr(
        Loc, Enum, Scratch, Elt);
    break;
  }
  case SILInstructionKind::InjectEnumAddrInst: {
    // Use SILOneValueOneOperandLayout.
    EnumElementDecl *Elt = cast<EnumElementDecl>(MF->getDecl(ValID));
    auto Ty = MF->getType(TyID);
    ResultInst = Builder.createInjectEnumAddr(
        Loc,
        getLocalValue(Builder.maybeGetFunction(), ValID2,
                      getSILType(Ty, (SILValueCategory)TyCategory, Fn)),
        Elt);
    break;
  }
  case SILInstructionKind::RefElementAddrInst: {
    // Use SILOneValueOneOperandLayout.
    VarDecl *Field = cast<VarDecl>(MF->getDecl(ValID));
    auto Ty = MF->getType(TyID);
    auto Val = getLocalValue(Builder.maybeGetFunction(), ValID2,
                             getSILType(Ty, (SILValueCategory)TyCategory, Fn));
    auto ResultTy = Val->getType().getFieldType(
        Field, SILMod, Builder.getTypeExpansionContext());
    ResultInst = Builder.createRefElementAddr(Loc, Val, Field, ResultTy,
                                              /*Immutable*/ Attr & 0x1);
    break;
  }
  case SILInstructionKind::RefTailAddrInst: {
    assert(RecordKind == SIL_ONE_TYPE_ONE_OPERAND &&
           "Layout should be OneTypeOneOperand.");
    assert((SILValueCategory)TyCategory == SILValueCategory::Address);
    ResultInst = Builder.createRefTailAddr(
        Loc,
        getLocalValue(
            Builder.maybeGetFunction(), ValID,
            getSILType(MF->getType(TyID2), (SILValueCategory)TyCategory2, Fn)),
        getSILType(MF->getType(TyID), SILValueCategory::Address, Fn),
        /*Immutable*/ Attr & 0x1);
    break;
  }
  case SILInstructionKind::ClassMethodInst:
  case SILInstructionKind::SuperMethodInst:
  case SILInstructionKind::ObjCMethodInst:
  case SILInstructionKind::ObjCSuperMethodInst: {
    // Format: a type, an operand and a SILDeclRef. Use SILOneTypeValuesLayout:
    // type, Attr, SILDeclRef (DeclID, Kind, uncurryLevel), and an operand.
    unsigned NextValueIndex = 0;
    SILDeclRef DRef = getSILDeclRef(MF, ListOfValues, NextValueIndex);
    SILType Ty =
        getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn);
    assert(ListOfValues.size() >= NextValueIndex + 2 &&
           "Out of entries for MethodInst");
    SILType operandTy =
        getSILType(MF->getType(ListOfValues[NextValueIndex]),
                   (SILValueCategory)ListOfValues[NextValueIndex + 1], Fn);
    NextValueIndex += 2;

    switch (OpCode) {
    default: llvm_unreachable("Out of sync with parent switch");
    case SILInstructionKind::ClassMethodInst:
      ResultInst = Builder.createClassMethod(
          Loc,
          getLocalValue(Builder.maybeGetFunction(),
                        ListOfValues[NextValueIndex], operandTy),
          DRef, Ty);
      break;
    case SILInstructionKind::SuperMethodInst:
      ResultInst = Builder.createSuperMethod(
          Loc,
          getLocalValue(Builder.maybeGetFunction(),
                        ListOfValues[NextValueIndex], operandTy),
          DRef, Ty);
      break;
    case SILInstructionKind::ObjCMethodInst:
      ResultInst = Builder.createObjCMethod(
          Loc,
          getLocalValue(Builder.maybeGetFunction(),
                        ListOfValues[NextValueIndex], operandTy),
          DRef, Ty);
      break;
    case SILInstructionKind::ObjCSuperMethodInst:
      ResultInst = Builder.createObjCSuperMethod(
          Loc,
          getLocalValue(Builder.maybeGetFunction(),
                        ListOfValues[NextValueIndex], operandTy),
          DRef, Ty);
      break;
    }
    break;
  }
  case SILInstructionKind::WitnessMethodInst: {
    unsigned NextValueIndex = 0;
    SILDeclRef DRef = getSILDeclRef(MF, ListOfValues, NextValueIndex);
    assert(ListOfValues.size() >= NextValueIndex &&
           "Out of entries for MethodInst");

    CanType Ty = MF->getType(TyID)->getCanonicalType();
    SILType OperandTy =
        getSILType(MF->getType(TyID2), (SILValueCategory)TyCategory2, Fn);

    auto Conformance = MF->getConformance(ConformanceID);
    // Read the optional opened existential.
    SILValue ExistentialOperand;
    if (TyID3) {
      SILType ExistentialOperandTy =
          getSILType(MF->getType(TyID3), (SILValueCategory)TyCategory3, Fn);
      if (ValID3)
        ExistentialOperand = getLocalValue(Builder.maybeGetFunction(), ValID3,
                                           ExistentialOperandTy);
    }
    ResultInst =
        Builder.createWitnessMethod(Loc, Ty, Conformance, DRef, OperandTy);
    break;
  }
  case SILInstructionKind::DynamicMethodBranchInst: {
    // Format: a typed value, a SILDeclRef, a BasicBlock ID for method,
    // a BasicBlock ID for no method. Use SILOneTypeValuesLayout.
    unsigned NextValueIndex = 1;
    SILDeclRef DRef = getSILDeclRef(MF, ListOfValues, NextValueIndex);
    assert(ListOfValues.size() == NextValueIndex + 2 &&
           "Wrong number of entries for DynamicMethodBranchInst");
    ResultInst = Builder.createDynamicMethodBranch(
        Loc,
        getLocalValue(
            Builder.maybeGetFunction(), ListOfValues[0],
            getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn)),
        DRef, getBBForReference(Fn, ListOfValues[NextValueIndex]),
        getBBForReference(Fn, ListOfValues[NextValueIndex + 1]));
    break;
  }
  case SILInstructionKind::CheckedCastBranchInst: {
    // Format: the cast kind, a typed value, a BasicBlock ID for success,
    // a BasicBlock ID for failure. Uses SILOneTypeValuesLayout.
    bool isExact = (ListOfValues[0] & 0x01) != 0;
    CheckedCastInstOptions options(ListOfValues[0] >> 1);
    CanType sourceFormalType = MF->getType(ListOfValues[1])->getCanonicalType();
    SILType opTy = getSILType(MF->getType(ListOfValues[3]),
                              (SILValueCategory)ListOfValues[4], Fn);
    SILValue op =
        getLocalValue(Builder.maybeGetFunction(), ListOfValues[2], opTy);
    SILType targetLoweredType =
        getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn);
    CanType targetFormalType = MF->getType(ListOfValues[5])->getCanonicalType();
    auto *successBB = getBBForReference(Fn, ListOfValues[6]);
    auto *failureBB = getBBForReference(Fn, ListOfValues[7]);

    ResultInst =
        Builder.createCheckedCastBranch(Loc, isExact, options,
                                        op, sourceFormalType,
                                        targetLoweredType, targetFormalType,
                                        successBB, failureBB,
                                        forwardingOwnership);
    break;
  }
  case SILInstructionKind::UnconditionalCheckedCastAddrInst: {
    // ignore attr.
    CheckedCastInstOptions options(ListOfValues[6]);
    CanType srcFormalType = MF->getType(ListOfValues[0])->getCanonicalType();
    SILType srcLoweredType = getSILType(MF->getType(ListOfValues[2]),
                                       (SILValueCategory)ListOfValues[3], Fn);
    SILValue src = getLocalValue(Builder.maybeGetFunction(), ListOfValues[1],
                                 srcLoweredType);

    CanType targetFormalType = MF->getType(ListOfValues[4])->getCanonicalType();
    SILType targetLoweredType =
        getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn);
    SILValue dest = getLocalValue(Builder.maybeGetFunction(), ListOfValues[5],
                                  targetLoweredType);

    ResultInst = Builder.createUnconditionalCheckedCastAddr(
        Loc, options, src, srcFormalType, dest, targetFormalType);
    break;
  }
  case SILInstructionKind::CheckedCastAddrBranchInst: {
    unsigned flags = ListOfValues[0];
    CheckedCastInstOptions options(flags & 0xFF);
    CastConsumptionKind consumption = getCastConsumptionKind(flags >> 8);

    CanType srcFormalType = MF->getType(ListOfValues[1])->getCanonicalType();
    SILType srcLoweredType = getSILType(MF->getType(ListOfValues[3]),
                                        (SILValueCategory)ListOfValues[4], Fn);
    SILValue src = getLocalValue(Builder.maybeGetFunction(), ListOfValues[2],
                                 srcLoweredType);

    CanType targetFormalType =
        MF->getType(ListOfValues[5])->getCanonicalType();
    SILType targetLoweredType =
        getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn);
    SILValue dest = getLocalValue(Builder.maybeGetFunction(), ListOfValues[6],
                                  targetLoweredType);

    auto *successBB = getBBForReference(Fn, ListOfValues[7]);
    auto *failureBB = getBBForReference(Fn, ListOfValues[8]);
    ResultInst = Builder.createCheckedCastAddrBranch(
        Loc, options, consumption, src, srcFormalType, dest,
        targetFormalType, successBB, failureBB);
    break;
  }
  case SILInstructionKind::UncheckedRefCastInst: {
    assert(RecordKind == SIL_ONE_TYPE_ONE_OPERAND &&
           "Layout should be OneTypeOneOperand.");
    auto *urc = Builder.createUncheckedRefCast(
        Loc,
        getLocalValue(
            Builder.maybeGetFunction(), ValID,
            getSILType(MF->getType(TyID2), (SILValueCategory)TyCategory2, Fn)),
        getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn));
    urc->setForwardingOwnershipKind(decodeValueOwnership(Attr));
    ResultInst = urc;
    break;
  }
  case SILInstructionKind::UncheckedRefCastAddrInst: {
    CanType sourceType = MF->getType(ListOfValues[0])->getCanonicalType();
    // ignore attr.
    SILType srcAddrTy = getSILType(MF->getType(ListOfValues[2]),
                                   (SILValueCategory)ListOfValues[3], Fn);
    SILValue src =
        getLocalValue(Builder.maybeGetFunction(), ListOfValues[1], srcAddrTy);

    CanType targetType = MF->getType(ListOfValues[4])->getCanonicalType();
    SILType destAddrTy =
        getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn);
    SILValue dest =
        getLocalValue(Builder.maybeGetFunction(), ListOfValues[5], destAddrTy);

    ResultInst = Builder.createUncheckedRefCastAddr(Loc, src, sourceType, dest,
                                                    targetType);
    break;
  }
  case SILInstructionKind::InitBlockStorageHeaderInst: {
    assert(ListOfValues.size() == 5 &&
           "expected 5 values for InitBlockStorageHeader");
    SILType blockTy =
        getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn);

    SILType storageTy = getSILType(MF->getType(ListOfValues[1]),
                                   SILValueCategory::Address, Fn);
    SILValue storage =
        getLocalValue(Builder.maybeGetFunction(), ListOfValues[0], storageTy);

    SILType invokeTy =
        getSILType(MF->getType(ListOfValues[3]), SILValueCategory::Object, Fn);
    SILValue invoke =
        getLocalValue(Builder.maybeGetFunction(), ListOfValues[2], invokeTy);

    auto SubMap = MF->getSubstitutionMap(ListOfValues[4]);

    ResultInst = Builder.createInitBlockStorageHeader(Loc, storage, invoke,
                                                      blockTy, SubMap);
    break;
  }
  case SILInstructionKind::UnreachableInst: {
    ResultInst = Builder.createUnreachable(Loc);
    break;
  }
  case SILInstructionKind::UnwindInst: {
    ResultInst = Builder.createUnwind(Loc);
    break;
  }
  case SILInstructionKind::ThrowAddrInst: {
    ResultInst = Builder.createThrowAddr(Loc);
    break;
  }
  case SILInstructionKind::YieldInst: {
    SILBasicBlock *unwindBB = getBBForReference(Fn, ListOfValues.back());
    ListOfValues = ListOfValues.drop_back();
    SILBasicBlock *resumeBB = getBBForReference(Fn, ListOfValues.back());
    ListOfValues = ListOfValues.drop_back();

    SmallVector<SILValue, 4> yieldedValues;
    for (unsigned I = 0, E = ListOfValues.size(); I < E; I += 3) {
      auto valueTy = MF->getType(ListOfValues[I]);
      auto valueCategory = (SILValueCategory) ListOfValues[I+1];
      yieldedValues.push_back(
          getLocalValue(Builder.maybeGetFunction(), ListOfValues[I + 2],
                        getSILType(valueTy, valueCategory, Fn)));
    }

    ResultInst = Builder.createYield(Loc, yieldedValues, resumeBB, unwindBB);
    break;
  }
  case SILInstructionKind::KeyPathInst: {
    unsigned nextValue = 0;
    SILType kpTy =
        getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn);

    auto rootTy = MF->getType(ListOfValues[nextValue++]);
    auto valueTy = MF->getType(ListOfValues[nextValue++]);
    auto numComponents = ListOfValues[nextValue++];
    auto numOperands = ListOfValues[nextValue++];
    auto subMap = MF->getSubstitutionMap(ListOfValues[nextValue++]);
    auto objcString = MF->getIdentifierText(ListOfValues[nextValue++]);

    SmallVector<GenericTypeParamType *, 4> genericParams;
    SmallVector<Requirement, 4> requirements;
    auto numGenericParams = ListOfValues[nextValue++];
    for (unsigned i = 0; i != numGenericParams; ++i) {
      genericParams.push_back(MF->getType(ListOfValues[nextValue++])
                                ->castTo<GenericTypeParamType>());
    }
    if (numGenericParams != 0) {
      MF->deserializeGenericRequirements(ListOfValues, nextValue, requirements);
    }
    
    SmallVector<KeyPathPatternComponent, 4> components;
    components.reserve(numComponents);
    while (numComponents-- > 0) {
      components.push_back(*readKeyPathComponent(ListOfValues, nextValue));
    }
    
    CanGenericSignature sig = CanGenericSignature();
    if (!genericParams.empty() || !requirements.empty())
      sig = GenericSignature::get(genericParams, requirements)
                .getCanonicalSignature();

    auto pattern = KeyPathPattern::get(SILMod, sig,
                                       rootTy->getCanonicalType(),
                                       valueTy->getCanonicalType(),
                                       components,
                                       objcString);
    
    SmallVector<SILValue, 4> operands;
    
    operands.reserve(numOperands);
    while (numOperands-- > 0) {
      auto opValue = ListOfValues[nextValue++];
      auto opTy = MF->getType(ListOfValues[nextValue++]);
      auto opCat = (SILValueCategory)ListOfValues[nextValue++];
      operands.push_back(getLocalValue(Builder.maybeGetFunction(), opValue,
                                       getSILType(opTy, opCat, Fn)));
    }

    ResultInst = Builder.createKeyPath(Loc, pattern, subMap, operands, kpTy);
    break;
  }
  case SILInstructionKind::DifferentiableFunctionInst: {
    auto numParams = Attr;
    auto numResults = Attr2;
    auto numParamIndices = Attr3;
    bool hasDerivativeFunctions = (bool)Attr4;
    unsigned numOperands = hasDerivativeFunctions ? 3 : 1;
    auto numResultIndices =
        ListOfValues.size() - numOperands * 3 - numParamIndices;
    assert(ListOfValues.size() ==
           numParamIndices + numResultIndices + numOperands * 3);
    auto rawParamIndices =
        map<SmallVector<unsigned, 8>>(ListOfValues.take_front(numParamIndices),
                                      [](uint64_t i) { return (unsigned)i; });
    auto *paramIndices =
        IndexSubset::get(MF->getContext(), numParams, rawParamIndices);
    auto rawResultIndices = map<SmallVector<unsigned, 8>>(
        ListOfValues.slice(numParamIndices, numResultIndices),
        [](uint64_t i) { return (unsigned)i; });
    auto *resultIndices =
        IndexSubset::get(MF->getContext(), numResults, rawResultIndices);
    SmallVector<SILValue, 3> operands;
    for (auto i = numParamIndices + numResultIndices;
         i < numParamIndices + numOperands * 3; i += 3) {
      auto astTy = MF->getType(ListOfValues[i]);
      auto silTy = getSILType(astTy, (SILValueCategory)ListOfValues[i + 1], Fn);
      operands.push_back(getLocalValue(Builder.maybeGetFunction(),
                                       ListOfValues[i + 2], silTy));
    }
    std::optional<std::pair<SILValue, SILValue>> derivativeFunctions =
        std::nullopt;
    if (hasDerivativeFunctions)
      derivativeFunctions = std::make_pair(operands[1], operands[2]);
    ResultInst = Builder.createDifferentiableFunction(
        Loc, paramIndices, resultIndices, operands[0], derivativeFunctions);
    break;
  }
  case SILInstructionKind::LinearFunctionInst: {
    auto numDiffParams = Attr;
    bool hasLinearFunction = (bool)Attr2;
    unsigned numOperands = hasLinearFunction ? 2 : 1;
    auto numParamIndices = ListOfValues.size() - numOperands * 3;
    assert(ListOfValues.size() == numParamIndices + numOperands * 3);
    auto rawParamIndices =
       map<SmallVector<unsigned, 8>>(ListOfValues.take_front(numParamIndices),
                                     [](uint64_t i) { return (unsigned)i; });
    auto *paramIndices =
        IndexSubset::get(MF->getContext(), numDiffParams, rawParamIndices);
    SmallVector<SILValue, 3> operands;
    for (auto i = numParamIndices;
         i < numParamIndices + numOperands * 3; i += 3) {
      auto astTy = MF->getType(ListOfValues[i]);
      auto silTy = getSILType(astTy, (SILValueCategory)ListOfValues[i+1], Fn);
      operands.push_back(getLocalValue(Builder.maybeGetFunction(),
                                       ListOfValues[i + 2], silTy));
    }
    std::optional<SILValue> transposeFunction = std::nullopt;
    if (hasLinearFunction)
      transposeFunction = operands[1];
    ResultInst = Builder.createLinearFunction(Loc, paramIndices, operands[0],
                                              transposeFunction);
    break;
  }
  case SILInstructionKind::DifferentiableFunctionExtractInst: {
    auto astTy = MF->getType(TyID);
    auto silTy = getSILType(astTy, SILValueCategory::Object, Fn);
    auto val = getLocalValue(Builder.maybeGetFunction(), ValID, silTy);
    NormalDifferentiableFunctionTypeComponent extractee(Attr);
    std::optional<SILType> explicitExtracteeType = std::nullopt;
    if (Attr2) {
      auto extracteeASTType = MF->getType(TyID2);
      explicitExtracteeType =
          getSILType(extracteeASTType, SILValueCategory::Object, Fn);
    }
    ResultInst = Builder.createDifferentiableFunctionExtract(
        Loc, extractee, val, explicitExtracteeType);
    break;
  }
  case SILInstructionKind::LinearFunctionExtractInst: {
    auto astTy = MF->getType(TyID);
    auto silTy = getSILType(astTy, SILValueCategory::Object, Fn);
    auto val = getLocalValue(Builder.maybeGetFunction(), ValID, silTy);
    LinearDifferentiableFunctionTypeComponent extractee(Attr);
    ResultInst = Builder.createLinearFunctionExtract(Loc, extractee, val);
    break;
  }
  case SILInstructionKind::DifferentiabilityWitnessFunctionInst: {
    StringRef mangledKey = MF->getIdentifierText(ValID);
    auto *witness = getSILDifferentiabilityWitnessForReference(mangledKey);
    assert(witness && "SILDifferentiabilityWitness not found");
    DifferentiabilityWitnessFunctionKind witnessKind(Attr);
    std::optional<SILType> explicitFnTy = std::nullopt;
    auto astTy = MF->getType(TyID);
    if (TyID)
      explicitFnTy = getSILType(astTy, SILValueCategory::Object, Fn);
    ResultInst = Builder.createDifferentiabilityWitnessFunction(
        Loc, witnessKind, witness, explicitFnTy);
    break;
  }
  case SILInstructionKind::HasSymbolInst: {
    ValueDecl *decl = cast<ValueDecl>(MF->getDecl(ValID));
    ResultInst = Builder.createHasSymbol(Loc, decl);
    // Deserialize the functions that are implicitly referenced by the
    // instruction.
    for (auto fnID : ListOfValues) {
      (void)getFuncForReference(MF->getIdentifierText(fnID));
    }
    break;
  }
  case SILInstructionKind::TypeValueInst: {
    auto valueType = getSILType(MF->getType(TyID), (SILValueCategory)TyCategory,
                                Fn);
    auto paramType = MF->getType(TyID2)->getCanonicalType();
    ResultInst = Builder.createTypeValue(Loc, valueType, paramType);
    break;
  }
  }

  for (auto result : ResultInst->getResults()) {
    LastValueID = LastValueID + 1;
    setLocalValue(result, LastValueID);
  }

  return false;
}

SILFunction *SILDeserializer::lookupSILFunction(SILFunction *InFunc,
                                                bool onlyUpdateLinkage) {
  StringRef name = InFunc->getName();
  if (!FuncTable)
    return nullptr;
  auto iter = FuncTable->find(name);
  if (iter == FuncTable->end())
    return nullptr;

  // Re-reading the function as declaration will update the linkage.
  auto maybeFunc = readSILFunctionChecked(*iter, InFunc, name,
                                        /*declarationOnly*/ onlyUpdateLinkage);
  if (!maybeFunc) {
    // Ignore the error; treat it as if we didn't have a definition.
    consumeError(maybeFunc.takeError());
    return nullptr;
  }

  if (auto fn = maybeFunc.get()) {
    LLVM_DEBUG(llvm::dbgs() << "Deserialize SIL:\n";
               maybeFunc.get()->dump());
    assert(InFunc->getName() == maybeFunc.get()->getName());
    assert(!fn->isZombie());
  }

  return maybeFunc.get();
}

/// Check for existence of a function with a given name and required linkage.
/// This function is modeled after readSILFunction. But it does not
/// create a SILFunction object.
bool SILDeserializer::hasSILFunction(StringRef Name,
                                     std::optional<SILLinkage> Linkage) {
  if (!FuncTable)
    return false;
  auto iter = FuncTable->find(Name);
  if (iter == FuncTable->end())
    return false;

  // There is a function with the required name.
  // Find out which linkage it has.
  auto FID = *iter;
  auto &cacheEntry = Funcs[FID-1];
  if (cacheEntry.isFullyDeserialized() ||
      (cacheEntry.isDeserialized()))
    return !Linkage || cacheEntry.get()->getLinkage() == *Linkage;

  BCOffsetRAII restoreOffset(SILCursor);
  if (llvm::Error Err = SILCursor.JumpToBit(cacheEntry.getOffset())) {
    MF->diagnoseAndConsumeFatal(std::move(Err));
    return false;
  }

  llvm::Expected<llvm::BitstreamEntry> maybeEntry =
      SILCursor.advance(AF_DontPopBlockAtEnd);
  if (!maybeEntry) {
    MF->diagnoseAndConsumeFatal(maybeEntry.takeError());
    return false;
  }
  llvm::BitstreamEntry entry = maybeEntry.get();
  if (entry.Kind == llvm::BitstreamEntry::Error) {
    MF->diagnoseAndConsumeFatal("Cursor advance error in hasSILFunction");
    return false;
  }

  SmallVector<uint64_t, 64> scratch;
  StringRef blobData;
  llvm::Expected<unsigned> maybeKind =
      SILCursor.readRecord(entry.ID, scratch, &blobData);
  if (!maybeKind)
    MF->fatal(maybeKind.takeError());
  unsigned kind = maybeKind.get();
  assert(kind == SIL_FUNCTION && "expect a sil function");
  (void)kind;

  // Read function properties only, e.g. its linkage and other attributes.
  // TODO: If this results in any noticeable performance problems, Cache the
  // linkage to avoid re-reading it from the bitcode each time?
  DeclID clangOwnerID;
  ModuleID parentModuleID;
  TypeID funcTyID;
  IdentifierID replacedFunctionID;
  IdentifierID usedAdHocWitnessFunctionID;
  GenericSignatureID genericSigID;
  unsigned rawLinkage, isTransparent, serializedKind, isThunk,
      isWithoutActuallyEscapingThunk, isGlobal, inlineStrategy,
      optimizationMode, perfConstr, subclassScope, hasCReferences, markedAsUsed,
      effect, numSpecAttrs, hasQualifiedOwnership, isWeakImported,
      codeGenerationModel,
      LIST_VER_TUPLE_PIECES(available), isDynamic, isExactSelfClass,
      isDistributed, isRuntimeAccessible, forceEnableLexicalLifetimes,
      onlyReferencedByDebugInfo;
  ArrayRef<uint64_t> SemanticsIDs;
  SILFunctionLayout::readRecord(
      scratch, rawLinkage, isTransparent, serializedKind, isThunk,
      isWithoutActuallyEscapingThunk, isGlobal, inlineStrategy,
      optimizationMode, perfConstr, subclassScope, hasCReferences, markedAsUsed,
      effect, numSpecAttrs, hasQualifiedOwnership, isWeakImported,
      codeGenerationModel,
      LIST_VER_TUPLE_PIECES(available), isDynamic, isExactSelfClass,
      isDistributed, isRuntimeAccessible, forceEnableLexicalLifetimes,
      onlyReferencedByDebugInfo, funcTyID, replacedFunctionID,
      usedAdHocWitnessFunctionID, genericSigID, clangOwnerID, parentModuleID,
      SemanticsIDs);
  auto linkage = fromStableSILLinkage(rawLinkage);
  if (!linkage) {
    LLVM_DEBUG(llvm::dbgs() << "invalid linkage code " << rawLinkage
                            << " for SIL function " << Name << "\n");
    return false;
  }

  if (onlyReferencedByDebugInfo)
    return false;

  // Bail if it is not a required linkage.
  if (Linkage && linkage.value() != *Linkage)
    return false;

  LLVM_DEBUG(llvm::dbgs() << "Found SIL Function: " << Name << "\n");
  return true;
}

SILFunction *SILDeserializer::lookupSILFunction(StringRef name,
                                                bool declarationOnly,
                                                bool byAsmName) {
  // If we're looking up the function by its AsmName, check that table.
  if (byAsmName) {
    if (!AsmNameTable)
      return nullptr;

    auto iter = AsmNameTable->find(name);
    if (iter == AsmNameTable->end())
      return nullptr;

    // Now look for this name in the function table.
    name = *iter;
  }

  if (!FuncTable)
    return nullptr;
  auto iter = FuncTable->find(name);
  if (iter == FuncTable->end())
    return nullptr;

  auto maybeFunc = readSILFunctionChecked(*iter, nullptr, name,
                                          declarationOnly);

  if (!maybeFunc) {
    // Ignore the error; treat it as if we didn't have a definition.
    consumeError(maybeFunc.takeError());
    return nullptr;
  }

  if (auto fn = maybeFunc.get()) {
    LLVM_DEBUG(llvm::dbgs() << "Deserialize SIL:\n";
               maybeFunc.get()->dump());
    assert(!fn->isZombie());
  }
  return maybeFunc.get();
}

SILGlobalVariable *SILDeserializer::lookupSILGlobalVariable(StringRef name,
                                                            bool byAsmName) {
  return getGlobalForReference(name, byAsmName);
}

SILGlobalVariable *SILDeserializer::readGlobalVar(StringRef Name,
                                                  bool byAsmName) {
  // If we're looking up the variable by its AsmName, check that table.
  if (byAsmName) {
    if (!AsmNameTable)
      return nullptr;

    auto iter = AsmNameTable->find(Name);
    if (iter == AsmNameTable->end())
      return nullptr;

    // Now look for this name in the global variable table.
    Name = *iter;
  }

  if (!GlobalVarList)
    return nullptr;

  PrettyStackTraceStringAction trace("deserializing SIL global", Name);

  // If we already deserialized this global variable, just return it.
  if (auto *GV = SILMod.lookUpGlobalVariable(Name))
    return GV;

  // Find Id for the given name.
  auto iter = GlobalVarList->find(Name);
  if (iter == GlobalVarList->end())
    return nullptr;
  auto VId = *iter;
  if (VId == 0)
    return nullptr;

  assert(VId <= GlobalVars.size() && "invalid GlobalVar ID");
  auto &globalVarOrOffset = GlobalVars[VId-1];
  if (globalVarOrOffset.isFullyDeserialized())
    return globalVarOrOffset.get();

  BCOffsetRAII restoreOffset(SILCursor);
  if (llvm::Error Err = SILCursor.JumpToBit(globalVarOrOffset.getOffset()))
    MF->fatal(std::move(Err));
  llvm::Expected<llvm::BitstreamEntry> maybeEntry =
      SILCursor.advance(AF_DontPopBlockAtEnd);
  if (!maybeEntry)
    MF->fatal(maybeEntry.takeError());
  llvm::BitstreamEntry entry = maybeEntry.get();
  if (entry.Kind == llvm::BitstreamEntry::Error) {
    LLVM_DEBUG(llvm::dbgs() << "Cursor advance error in readGlobalVar.\n");
    return nullptr;
  }

  SmallVector<uint64_t, 64> scratch;
  StringRef blobData;
  llvm::Expected<unsigned> maybeKind =
      SILCursor.readRecord(entry.ID, scratch, &blobData);
  if (!maybeKind)
    MF->fatal(maybeKind.takeError());
  unsigned kind = maybeKind.get();
  assert(kind == SIL_GLOBALVAR && "expect a sil global var");
  (void)kind;

  TypeID TyID;
  DeclID dID;
  ModuleID parentModuleID;
  unsigned rawLinkage, serializedKind, IsDeclaration, IsLet, IsUsed,
      codeGenerationModel;
  unsigned numTrailingRecords;
  SILGlobalVarLayout::readRecord(scratch, rawLinkage, serializedKind,
                                 IsDeclaration, IsLet, IsUsed,
                                 codeGenerationModel,
                                 numTrailingRecords, TyID, dID,
                                 parentModuleID);
  if (TyID == 0) {
    LLVM_DEBUG(llvm::dbgs() << "SILGlobalVariable typeID is 0.\n");
    return nullptr;
  }

  auto linkage = fromStableSILLinkage(rawLinkage);
  if (!linkage) {
    LLVM_DEBUG(llvm::dbgs() << "invalid linkage code " << rawLinkage
                            << " for SILGlobalVariable\n");
    return nullptr;
  }

  // A SIL global variable that uses the Interface code generation model has a
  // unique strong definition in its defining module. When deserialized into a
  // different module, mark its linkage as externally available so that the
  // importer references the defining module's symbol rather than emitting
  // its own definition.
  if (codeGenerationModel &&
      static_cast<CodeGenerationModel>(codeGenerationModel - 1) ==
          CodeGenerationModel::Interface &&
      MF->getAssociatedModule() != SILMod.getSwiftModule()) {
    linkage = addExternalToLinkage(*linkage);
    IsDeclaration = true;
  }

  VarDecl *globalDecl = nullptr;
  if (dID) {
    llvm::Expected<Decl *> d = MF->getDeclChecked(dID);
    if (d) {
      globalDecl = cast<VarDecl>(d.get());
    } else {
      // This can happen with cross-module-optimizations, if the linkage of a
      // private global variable is changed to public.
      consumeError(d.takeError());
    }
  }

  auto Ty = MF->getType(TyID);
  SILGlobalVariable *v = SILGlobalVariable::create(
      SILMod, linkage.value(), SerializedKind_t(serializedKind),
      Name.str(), getSILType(Ty, SILValueCategory::Object, nullptr),
      std::nullopt, globalDecl);
  v->setLet(IsLet);
  v->setMarkedAsUsed(IsUsed);
  if (codeGenerationModel) {
    v->setCodeGenerationModel(
        static_cast<CodeGenerationModel>(codeGenerationModel - 1));
  } else {
    v->setCodeGenerationModel(std::nullopt);
  }
  globalVarOrOffset.set(v, true /*isFullyDeserialized*/);
  v->setDeclaration(IsDeclaration);

  if (parentModuleID)
    v->setParentModule(MF->getModule(parentModuleID));

  if (Callback)
    Callback->didDeserialize(MF->getAssociatedModule(), v);

  scratch.clear();

  // Read trailing reecords.
  for (unsigned recordIdx = 0; recordIdx < numTrailingRecords; ++recordIdx) {
    StringRef blobData;
    llvm::Expected<llvm::BitstreamEntry> maybeNext =
        SILCursor.advance(AF_DontPopBlockAtEnd);
    if (!maybeNext)
      return nullptr;
    llvm::BitstreamEntry next = maybeNext.get();
    assert(next.Kind == llvm::BitstreamEntry::Record);

    scratch.clear();
    llvm::Expected<unsigned> maybeKind = SILCursor.readRecord(next.ID, scratch,
                                                              &blobData);
    if (!maybeKind)
      return nullptr;
    unsigned kind = maybeKind.get();

    if (kind == SIL_EXTRA_STRING) {
      unsigned stringFlavor;
      SILExtraStringLayout::readRecord(scratch, stringFlavor);

      switch (static_cast<ExtraStringFlavor>(stringFlavor)) {
      case ExtraStringFlavor::AsmName:
        v->setAsmName(blobData);
        break;
      case ExtraStringFlavor::Section:
        v->setSection(blobData);
        break;
      case ExtraStringFlavor::WasmImportModule:
      case ExtraStringFlavor::WasmImportName:
        // TODO: we still don't support wasm import on global variables
        break;
      }
      continue;
    }

    return nullptr;
  }

  maybeEntry = SILCursor.advance(AF_DontPopBlockAtEnd);
  if (!maybeEntry)
    MF->fatal(maybeEntry.takeError());
  entry = maybeEntry.get();
  if (entry.Kind == llvm::BitstreamEntry::EndBlock)
    return v;

  scratch.clear();
  maybeKind = SILCursor.readRecord(entry.ID, scratch, &blobData);
  if (!maybeKind)
    MF->fatal(maybeKind.takeError());
  kind = maybeKind.get();

  SILBuilder Builder(v);
  
  llvm::DenseMap<uint32_t, ValueBase*> SavedLocalValues;
  serialization::ValueID SavedLastValueID = 1;
  
  SavedLocalValues.swap(LocalValues);
  std::swap(SavedLastValueID, LastValueID);

  // Ignored, global variables don't have inner variables.
  SmallVector<DebugValueInst *, 4> DebugBBWorklist;

  while (kind != SIL_FUNCTION && kind != SIL_VTABLE && kind != SIL_GLOBALVAR &&
         kind != SIL_MOVEONLY_DEINIT && kind != SIL_WITNESS_TABLE &&
         kind != SIL_DEFAULT_OVERRIDE_TABLE &&
         kind != SIL_DIFFERENTIABILITY_WITNESS) {
    if (readSILInstruction(nullptr, Builder, kind, scratch, DebugBBWorklist))
      MF->fatal("readSILInstruction returns error");

    // Fetch the next record.
    scratch.clear();
    llvm::Expected<llvm::BitstreamEntry> maybeEntry =
        SILCursor.advance(AF_DontPopBlockAtEnd);
    if (!maybeEntry)
      MF->fatal(maybeEntry.takeError());
    llvm::BitstreamEntry entry = maybeEntry.get();

    // EndBlock means the end of this SILFunction.
    if (entry.Kind == llvm::BitstreamEntry::EndBlock)
      break;
    maybeKind = SILCursor.readRecord(entry.ID, scratch);
    if (!maybeKind)
      MF->fatal(maybeKind.takeError());
    kind = maybeKind.get();
  }

  SavedLocalValues.swap(LocalValues);
  std::swap(SavedLastValueID, LastValueID);

  return v;
}

void SILDeserializer::getAllSILGlobalVariables() {
  if (!GlobalVarList)
    return;

  for (auto Key : GlobalVarList->keys()) {
    readGlobalVar(Key);
  }
}

void SILDeserializer::getAllSILFunctions() {
  if (!FuncTable)
    return;

  for (auto KI = FuncTable->key_begin(), KE = FuncTable->key_end(); KI != KE;
       ++KI) {
    // Attempt to lookup our name from the output module. If we have a
    // definition already, don't do anything.
    if (SILFunction *F = SILMod.lookUpFunction(*KI))
      if (!F->isExternalDeclaration())
        continue;

    auto DI = FuncTable->find(*KI);
    assert(DI != FuncTable->end() && "There should never be a key without data.");

    auto maybeFunc = readSILFunctionChecked(*DI, nullptr, *KI, false,
                                            false/*errorIfEmptyBody*/);
    if (!maybeFunc) {
      // Ignore the error; treat it as if we didn't have a definition.
      consumeError(maybeFunc.takeError());
    }
  }
}

SILVTable *SILDeserializer::readVTable(DeclID VId) {
  if (VId == 0)
    return nullptr;
  assert(VId <= VTables.size() && "invalid VTable ID");
  auto &vTableOrOffset = VTables[VId-1];

  if (vTableOrOffset.isFullyDeserialized())
    return vTableOrOffset.get();

  BCOffsetRAII restoreOffset(SILCursor);
  if (llvm::Error Err = SILCursor.JumpToBit(vTableOrOffset.getOffset()))
    MF->fatal(std::move(Err));
  llvm::Expected<llvm::BitstreamEntry> maybeEntry =
      SILCursor.advance(AF_DontPopBlockAtEnd);
  if (!maybeEntry)
    MF->fatal(maybeEntry.takeError());
  llvm::BitstreamEntry entry = maybeEntry.get();
  if (entry.Kind == llvm::BitstreamEntry::Error) {
    LLVM_DEBUG(llvm::dbgs() << "Cursor advance error in readVTable.\n");
    return nullptr;
  }

  SmallVector<uint64_t, 64> scratch;
  StringRef blobData;
  llvm::Expected<unsigned> maybeKind =
      SILCursor.readRecord(entry.ID, scratch, &blobData);
  if (!maybeKind)
    MF->fatal(maybeKind.takeError());
  unsigned kind = maybeKind.get();
  assert(kind == SIL_VTABLE && "expect a sil vtable");
  (void)kind;

  DeclID ClassID;
  unsigned Serialized;
  VTableLayout::readRecord(scratch, ClassID, Serialized);
  if (ClassID == 0) {
    LLVM_DEBUG(llvm::dbgs() << "VTable classID is 0.\n");
    return nullptr;
  }

  // Vtable with [serialized_for_package], i.e. optimized with Package CMO,
  // should only be deserialized into a client if its defning module and the
  // client are in the package.
  if (!SILMod.getSwiftModule()->inSamePackage(getFile()->getParentModule()) &&
      SerializedKind_t(Serialized) == SerializedKind_t::IsSerializedForPackage)
    return nullptr;

  ClassDecl *theClass = cast<ClassDecl>(MF->getDecl(ClassID));

  PrettyStackTraceDecl trace("deserializing SIL vtable for", theClass);

  // Fetch the next record.
  scratch.clear();
  maybeEntry = SILCursor.advance(AF_DontPopBlockAtEnd);
  if (!maybeEntry)
    MF->fatal(maybeEntry.takeError());
  entry = maybeEntry.get();
  if (entry.Kind == llvm::BitstreamEntry::EndBlock)
    // This vtable has no contents.
    return nullptr;
  maybeKind = SILCursor.readRecord(entry.ID, scratch);
  if (!maybeKind)
    MF->fatal(maybeKind.takeError());
  kind = maybeKind.get();

  std::vector<SILVTable::ConformanceEntry> conformances;

  while (kind == SIL_VTABLE_CONFORMANCE_ENTRY || kind == SIL_VTABLE_NO_CONFORMANCE_ENTRY) {
    if (kind == SIL_VTABLE_NO_CONFORMANCE_ENTRY) {
      DeclID protoId;
      VTableNoConformanceEntry::readRecord(scratch, protoId);
      ProtocolDecl *proto = cast<ProtocolDecl>(MF->getDecl(protoId));
      conformances.push_back(proto);
    } else {
      ASSERT(kind == SIL_VTABLE_CONFORMANCE_ENTRY);
      ProtocolConformanceID conformanceId;
      VTableConformanceEntry::readRecord(scratch, conformanceId);
      auto conformance = MF->getConformance(conformanceId);
      conformances.push_back(conformance.getConcrete());
    }

    // Fetch the next record.
    scratch.clear();
    maybeEntry = SILCursor.advance(AF_DontPopBlockAtEnd);
    if (!maybeEntry)
      MF->fatal(maybeEntry.takeError());
    entry = maybeEntry.get();
    if (entry.Kind == llvm::BitstreamEntry::EndBlock)
      // EndBlock means the end of this VTable.
      break;
    maybeKind = SILCursor.readRecord(entry.ID, scratch);
    if (!maybeKind)
      MF->fatal(maybeKind.takeError());
    kind = maybeKind.get();
  }

  std::vector<SILVTable::Entry> vtableEntries;
  // Another SIL_VTABLE record means the end of this VTable.
  while (kind == SIL_VTABLE_ENTRY) {
    ArrayRef<uint64_t> ListOfValues;
    DeclID NameID;
    unsigned RawEntryKind, IsNonOverridden;
    VTableEntryLayout::readRecord(scratch, NameID,
                                  RawEntryKind, IsNonOverridden,
                                  ListOfValues);

    auto EntryKind = fromStableVTableEntryKind(RawEntryKind);

    SILFunction *Func = getFuncForReference(MF->getIdentifierText(NameID));
    if (Func) {
      unsigned NextValueIndex = 0;
      vtableEntries.emplace_back(getSILDeclRef(MF, ListOfValues, NextValueIndex),
                                 Func, EntryKind.value(), (bool)IsNonOverridden);
    }

    // Fetch the next record.
    scratch.clear();
    maybeEntry = SILCursor.advance(AF_DontPopBlockAtEnd);
    if (!maybeEntry)
      MF->fatal(maybeEntry.takeError());
    entry = maybeEntry.get();
    if (entry.Kind == llvm::BitstreamEntry::EndBlock)
      // EndBlock means the end of this VTable.
      break;
    maybeKind = SILCursor.readRecord(entry.ID, scratch);
    if (!maybeKind)
      MF->fatal(maybeKind.takeError());
    kind = maybeKind.get();
  }

  // If we've already serialized the module, don't mark the witness table
  // as serialized, since we no longer need to enforce resilience
  // boundaries.
  if (SILMod.isSerialized())
    Serialized = unsigned(SerializedKind_t::IsNotSerialized);

  SILVTable *vT = SILVTable::create(
      SILMod, theClass,
      SerializedKind_t(Serialized),
      vtableEntries);
  vTableOrOffset.set(vT, true /*isFullyDeserialized*/);

  for (auto cEntry : conformances) {
    vT->appendConformance(cEntry);
  }

  if (Callback) Callback->didDeserialize(MF->getAssociatedModule(), vT);
  return vT;
}

SILVTable *SILDeserializer::lookupVTable(StringRef MangledClassName) {
  if (!VTableList)
    return nullptr;
  auto iter = VTableList->find(MangledClassName);
  if (iter == VTableList->end())
    return nullptr;

  auto VT = readVTable(*iter);
  return VT;
}

/// Deserialize all VTables inside the module and add them to SILMod.
void SILDeserializer::getAllVTables() {
  if (!VTableList)
    return;

  for (unsigned I = 0, E = VTables.size(); I < E; ++I)
    readVTable(I+1);
}

SILMoveOnlyDeinit *SILDeserializer::readMoveOnlyDeinit(DeclID tableID) {
  if (tableID == 0)
    return nullptr;
  assert(tableID <= MoveOnlyDeinits.size() && "invalid VTable ID");
  auto &moveOnlyDeinitOrOffset = MoveOnlyDeinits[tableID - 1];

  if (moveOnlyDeinitOrOffset.isFullyDeserialized())
    return moveOnlyDeinitOrOffset.get();

  BCOffsetRAII restoreOffset(SILCursor);
  if (llvm::Error Err = SILCursor.JumpToBit(moveOnlyDeinitOrOffset.getOffset()))
    MF->fatal(std::move(Err));
  llvm::Expected<llvm::BitstreamEntry> maybeEntry =
      SILCursor.advance(AF_DontPopBlockAtEnd);
  if (!maybeEntry)
    MF->fatal(maybeEntry.takeError());
  llvm::BitstreamEntry entry = maybeEntry.get();
  if (entry.Kind == llvm::BitstreamEntry::Error) {
    LLVM_DEBUG(llvm::dbgs() << "Cursor advance error in readVTable.\n");
    return nullptr;
  }

  SmallVector<uint64_t, 64> scratch;
  StringRef blobData;
  llvm::Expected<unsigned> maybeKind =
      SILCursor.readRecord(entry.ID, scratch, &blobData);
  if (!maybeKind)
    MF->fatal(maybeKind.takeError());
  unsigned kind = maybeKind.get();
  assert(kind == SIL_MOVEONLY_DEINIT && "expect a sil move only deinit table");
  (void)kind;

  DeclID nominalID;
  DeclID funcNameID;
  unsigned rawSerialized;
  MoveOnlyDeinitLayout::readRecord(scratch, nominalID, funcNameID,
                                   rawSerialized);
  if (nominalID == 0) {
    LLVM_DEBUG(llvm::dbgs() << "MoveOnlyDeinit nominalID is 0.\n");
    return nullptr;
  }

  auto *theNomDecl = cast<NominalTypeDecl>(MF->getDecl(nominalID));
  auto *theFunc = getFuncForReference(MF->getIdentifierText(funcNameID));

  // If we've already serialized the module, don't mark the witness table
  // as serialized, since we no longer need to enforce resilience
  // boundaries.
  if (SILMod.isSerialized())
    rawSerialized = 0;

  auto *deinit = SILMoveOnlyDeinit::create(
      SILMod, theNomDecl, SerializedKind_t(rawSerialized),
      theFunc);
  moveOnlyDeinitOrOffset.set(deinit, true /*isFullyDeserialized*/);

  if (Callback)
    Callback->didDeserialize(MF->getAssociatedModule(), deinit);
  return deinit;
}

SILMoveOnlyDeinit *
SILDeserializer::lookupMoveOnlyDeinit(StringRef MangledClassName) {
  if (!MoveOnlyDeinitList)
    return nullptr;
  auto iter = MoveOnlyDeinitList->find(MangledClassName);
  if (iter == MoveOnlyDeinitList->end())
    return nullptr;

  auto tbl = readMoveOnlyDeinit(*iter);
  return tbl;
}

/// Deserialize all move only deinit tables inside the module and add them to
/// SILMod.
void SILDeserializer::getAllMoveOnlyDeinits() {
  if (!MoveOnlyDeinitList)
    return;

  for (unsigned i : range(MoveOnlyDeinits.size()))
    readMoveOnlyDeinit(i + 1);
}

SILProperty *SILDeserializer::readProperty(DeclID PId) {
  auto &propOrOffset = Properties[PId-1];
  
  if (propOrOffset.isFullyDeserialized())
    return propOrOffset.get();

  BCOffsetRAII restoreOffset(SILCursor);
  if (llvm::Error Err = SILCursor.JumpToBit(propOrOffset.getOffset()))
    MF->fatal(std::move(Err));
  llvm::Expected<llvm::BitstreamEntry> maybeEntry =
      SILCursor.advance(AF_DontPopBlockAtEnd);
  if (!maybeEntry)
    MF->fatal(maybeEntry.takeError());
  llvm::BitstreamEntry entry = maybeEntry.get();
  if (entry.Kind == llvm::BitstreamEntry::Error) {
    LLVM_DEBUG(llvm::dbgs() << "Cursor advance error in readProperty.\n");
    return nullptr;
  }

  SmallVector<uint64_t, 64> scratch;
  StringRef blobData;
  llvm::Expected<unsigned> maybeKind =
      SILCursor.readRecord(entry.ID, scratch, &blobData);
  if (!maybeKind)
    MF->fatal(maybeKind.takeError());
  unsigned kind = maybeKind.get();
  assert(kind == SIL_PROPERTY && "expect a sil_property");
  (void)kind;

  unsigned Serialized;
  DeclID StorageID;
  ArrayRef<uint64_t> ComponentValues;
  PropertyLayout::readRecord(scratch, StorageID, Serialized, ComponentValues);

  auto decl = cast<AbstractStorageDecl>(MF->getDecl(StorageID));
  unsigned ComponentValueIndex = 0;
  auto component = readKeyPathComponent(ComponentValues, ComponentValueIndex);
  
  auto prop = SILProperty::create(SILMod, Serialized, decl, component);
  propOrOffset.set(prop, /*fully deserialized*/ true);
  return prop;
}

void SILDeserializer::getAllProperties() {
  for (unsigned I = 0, E = Properties.size(); I < E; ++I) {
    readProperty(I+1);
  }
}

void SILDeserializer::readWitnessTableEntries(
    llvm::BitstreamEntry &entry,
    std::vector<SILWitnessTable::Entry> &witnessEntries,
    std::vector<ProtocolConformanceRef> &conditionalConformances) {
  SmallVector<uint64_t, 64> scratch;
  llvm::Expected<unsigned> maybeKind = SILCursor.readRecord(entry.ID, scratch);
  if (!maybeKind)
    MF->fatal(maybeKind.takeError());
  unsigned kind = maybeKind.get();

  // Another record means the end of this WitnessTable.
  while (kind != SIL_WITNESS_TABLE && kind != SIL_DEFAULT_WITNESS_TABLE &&
         kind != SIL_DEFAULT_OVERRIDE_TABLE &&
         kind != SIL_DIFFERENTIABILITY_WITNESS && kind != SIL_FUNCTION) {
    if (kind == SIL_DEFAULT_WITNESS_TABLE_NO_ENTRY) {
      witnessEntries.push_back(SILDefaultWitnessTable::Entry());
    } else if (kind == SIL_WITNESS_BASE_ENTRY) {
      DeclID protoId;
      ProtocolConformanceID conformanceId;
      WitnessBaseEntryLayout::readRecord(scratch, protoId, conformanceId);
      ProtocolDecl *proto = cast<ProtocolDecl>(MF->getDecl(protoId));
      auto conformance = MF->getConformance(conformanceId);
      witnessEntries.push_back(SILWitnessTable::BaseProtocolWitness{
        proto, conformance.getConcrete()
      });
    } else if (kind == SIL_WITNESS_ASSOC_PROTOCOL) {
      TypeID origTypeId;
      ProtocolConformanceID conformanceId;
      WitnessAssocProtocolLayout::readRecord(scratch, origTypeId, conformanceId);
      CanType origType = MF->getType(origTypeId)->getCanonicalType();
      auto conformance = MF->getConformance(conformanceId);
      witnessEntries.push_back(SILWitnessTable::AssociatedConformanceWitness{
        origType, conformance
      });
    } else if (kind == SIL_WITNESS_ASSOC_ENTRY) {
      DeclID assocId;
      TypeID tyId;
      WitnessAssocEntryLayout::readRecord(scratch, assocId, tyId);
      AssociatedTypeDecl *assoc = cast<AssociatedTypeDecl>(MF->getDecl(assocId));
      witnessEntries.push_back(SILWitnessTable::AssociatedTypeWitness{
        assoc, MF->getType(tyId)->getCanonicalType()
      });
    } else if (kind == SIL_WITNESS_METHOD_ENTRY) {
      ArrayRef<uint64_t> ListOfValues;
      DeclID NameID;
      WitnessMethodEntryLayout::readRecord(scratch, NameID, ListOfValues);
      SILFunction *Func = nullptr;
      if (NameID != 0) {
        Func = getFuncForReference(MF->getIdentifierText(NameID));
      }
      if (Func || NameID == 0) {
        unsigned NextValueIndex = 0;
        witnessEntries.push_back(SILWitnessTable::MethodWitness{
          getSILDeclRef(MF, ListOfValues, NextValueIndex), Func
        });
      }
    } else {
      assert(kind == SIL_WITNESS_CONDITIONAL_CONFORMANCE &&
             "Content of WitnessTable should be in "
             "SIL_WITNESS_CONDITIONAL_CONFORMANCE.");
      ProtocolConformanceID conformanceId;
      WitnessConditionalConformanceLayout::readRecord(scratch,
                                                      conformanceId);
      auto conformance = MF->getConformance(conformanceId);
      conditionalConformances.push_back(conformance);
    }

    // Fetch the next record.
    scratch.clear();
    llvm::Expected<llvm::BitstreamEntry> maybeEntry =
        SILCursor.advance(AF_DontPopBlockAtEnd);
    if (!maybeEntry)
      MF->fatal(maybeEntry.takeError());
    entry = maybeEntry.get();
    if (entry.Kind == llvm::BitstreamEntry::EndBlock)
      // EndBlock means the end of this WitnessTable.
      break;
    maybeKind = SILCursor.readRecord(entry.ID, scratch);
    if (!maybeKind)
      MF->fatal(maybeKind.takeError());
    kind = maybeKind.get();
  }
}

SILWitnessTable *SILDeserializer::readWitnessTable(DeclID WId,
                                                   SILWitnessTable *existingWt) {
  auto deserialized = readWitnessTableChecked(WId, existingWt);
  if (!deserialized) {
    MF->fatal(deserialized.takeError());
  }
  return deserialized.get();
}

llvm::Expected<SILWitnessTable *>
  SILDeserializer::readWitnessTableChecked(DeclID WId,
                                           SILWitnessTable *existingWt) {
  if (WId == 0)
    return nullptr;
  assert(WId <= WitnessTables.size() && "invalid WitnessTable ID");

  auto &wTableOrOffset = WitnessTables[WId-1];

  if (wTableOrOffset.isFullyDeserialized())
    return wTableOrOffset.get();

  BCOffsetRAII restoreOffset(SILCursor);
  if (llvm::Error Err = SILCursor.JumpToBit(wTableOrOffset.getOffset()))
    MF->fatal(std::move(Err));
  llvm::Expected<llvm::BitstreamEntry> maybeEntry =
      SILCursor.advance(AF_DontPopBlockAtEnd);
  if (!maybeEntry)
    MF->fatal(maybeEntry.takeError());
  llvm::BitstreamEntry entry = maybeEntry.get();
  if (entry.Kind == llvm::BitstreamEntry::Error) {
    LLVM_DEBUG(llvm::dbgs() << "Cursor advance error in readWitnessTable.\n");
    return nullptr;
  }

  SmallVector<uint64_t, 64> scratch;
  StringRef blobData;
  llvm::Expected<unsigned> maybeKind =
      SILCursor.readRecord(entry.ID, scratch, &blobData);
  if (!maybeKind)
    MF->fatal(maybeKind.takeError());
  unsigned kind = maybeKind.get();
  assert(kind == SIL_WITNESS_TABLE && "expect a sil witnesstable");
  (void)kind;

  unsigned RawLinkage;
  unsigned IsDeclaration;
  unsigned IsSpecialized;
  unsigned Serialized;
  ProtocolConformanceID conformance;
  WitnessTableLayout::readRecord(scratch, RawLinkage, IsDeclaration, IsSpecialized,
                                 Serialized, conformance);
  auto Linkage = fromStableSILLinkage(RawLinkage);
  if (!Linkage) {
    LLVM_DEBUG(llvm::dbgs() << "invalid linkage code " << RawLinkage
                            << " for SILFunction\n");
    MF->fatal("invalid linkage code");
  }

  // Witness with [serialized_for_package], i.e. optimized with Package CMO,
  // should only be deserialized into a client if its defning module and the
  // client are in the package.
  if (!SILMod.getSwiftModule()->inSamePackage(getFile()->getParentModule()) &&
      SerializedKind_t(Serialized) == SerializedKind_t::IsSerializedForPackage)
    return nullptr;

  // Deserialize Conformance.
  auto maybeConformance = MF->getConformanceChecked(conformance);
  if (!maybeConformance)
    return maybeConformance.takeError();

  // Specialized witness tables can have a `SpecializedProtocolConformance`,
  // not just a `RootProtocolConformance`. The downstream APIs accept any
  // `ProtocolConformance *`.
  auto *theConformance = maybeConformance.get().getConcrete();

  PrettyStackTraceConformance trace("deserializing SIL witness table for",
                                    theConformance);

  if (!existingWt)
    existingWt = SILMod.lookUpWitnessTable(theConformance, IsSpecialized != 0);
  auto wT = existingWt;

  // If we have an existing witness table, verify that the conformance matches
  // up.
  if (wT) {
    if (wT->getConformance() != theConformance) {
      MF->fatal("Conformance mismatch");
    }

    // Don't override the linkage of a witness table with an existing
    // declaration.

  } else {
    // Otherwise, create a new witness table declaration.
    wT = SILWitnessTable::create(SILMod, *Linkage, theConformance, IsSpecialized != 0);
    if (Callback)
      Callback->didDeserialize(MF->getAssociatedModule(), wT);
  }
  
  // We may see multiple shared-linkage definitions of the same witness table
  // for the same conformance.
  if (wT->isDefinition() && hasSharedVisibility(*Linkage)
      && hasSharedVisibility(wT->getLinkage())) {
    wTableOrOffset.set(wT, /*fully deserialized*/ true);
    return wT;
  }

  assert(wT->isDeclaration() && "Our witness table at this point must be a "
                                "declaration.");

  // If we are asked to just emit a declaration, return the declaration and say
  // that the witness table is not fully deserialized.
  if (IsDeclaration) {
    wTableOrOffset.set(wT, /*fully deserialized*/ false);
    return wT;
  }

  // Fetch the next record.
  scratch.clear();
  maybeEntry = SILCursor.advance(AF_DontPopBlockAtEnd);
  if (!maybeEntry)
    MF->fatal(maybeEntry.takeError());
  entry = maybeEntry.get();
  if (entry.Kind == llvm::BitstreamEntry::EndBlock)
    return nullptr;

  std::vector<SILWitnessTable::Entry> witnessEntries;
  std::vector<ProtocolConformanceRef> conditionalConformances;
  readWitnessTableEntries(entry, witnessEntries, conditionalConformances);

  // If we've already serialized the module, don't mark the witness table
  // as serialized, since we no longer need to enforce resilience
  // boundaries.
  if (SILMod.isSerialized())
    Serialized = unsigned(SerializedKind_t::IsNotSerialized);

  wT->convertToDefinition(witnessEntries, conditionalConformances,
                          SerializedKind_t(Serialized));
  wTableOrOffset.set(wT, /*fully deserialized*/ true);
  if (Callback)
    Callback->didDeserializeWitnessTableEntries(MF->getAssociatedModule(), wT);
  return wT;
}

/// Deserialize all WitnessTables inside the module and add them to SILMod.
void SILDeserializer::getAllWitnessTables() {
  if (!WitnessTableList)
    return;
  for (unsigned I = 0, E = WitnessTables.size(); I < E; ++I) {
    auto maybeTable = readWitnessTableChecked(I + 1, nullptr);
    if (!maybeTable) {
      if (maybeTable.errorIsA<XRefNonLoadedModuleError>()) {
        // This is most likely caused by decls hidden by an implementation-only
        // import, it is safe to ignore for this function's purpose.
        consumeError(maybeTable.takeError());
      } else {
        MF->diagnoseAndConsumeFatal(maybeTable.takeError());
      }
    }
  }
}

SILWitnessTable *
SILDeserializer::lookupWitnessTable(SILWitnessTable *existingWt) {
  assert(existingWt && "Cannot deserialize a null witness table declaration.");
  assert(existingWt->isDeclaration() && "Cannot deserialize a witness table "
                                        "definition.");

  // If we don't have a witness table list, we can't look anything up.
  if (!WitnessTableList)
    return nullptr;

  // Use the name of the given witness table to lookup the partially
  // deserialized value from the witness table list.
  auto iter = WitnessTableList->find(existingWt->getName());
  if (iter == WitnessTableList->end())
    return nullptr;

  // Attempt to read the witness table.
  auto Wt = readWitnessTable(*iter, existingWt);
  if (Wt)
    LLVM_DEBUG(llvm::dbgs() << "Deserialize SIL:\n"; Wt->dump());

  return Wt;
}

SILDefaultWitnessTable *SILDeserializer::
readDefaultWitnessTable(DeclID WId, SILDefaultWitnessTable *existingWt) {
  if (WId == 0)
    return nullptr;
  assert(WId <= DefaultWitnessTables.size() &&
         "invalid DefaultWitnessTable ID");

  auto &wTableOrOffset = DefaultWitnessTables[WId-1];

  if (wTableOrOffset.isFullyDeserialized())
    return wTableOrOffset.get();

  BCOffsetRAII restoreOffset(SILCursor);
  if (llvm::Error Err = SILCursor.JumpToBit(wTableOrOffset.getOffset()))
    MF->fatal(std::move(Err));
  llvm::Expected<llvm::BitstreamEntry> maybeEntry =
      SILCursor.advance(AF_DontPopBlockAtEnd);
  if (!maybeEntry)
    MF->fatal(maybeEntry.takeError());
  llvm::BitstreamEntry entry = maybeEntry.get();
  if (entry.Kind == llvm::BitstreamEntry::Error) {
    LLVM_DEBUG(llvm::dbgs() << "Cursor advance error in "
                               "readDefaultWitnessTable.\n");
    return nullptr;
  }

  SmallVector<uint64_t, 64> scratch;
  StringRef blobData;
  llvm::Expected<unsigned> maybeKind =
      SILCursor.readRecord(entry.ID, scratch, &blobData);
  if (!maybeKind)
    MF->fatal(maybeKind.takeError());
  unsigned kind = maybeKind.get();
  assert(kind == SIL_DEFAULT_WITNESS_TABLE && "expect a sil default witness table");
  (void)kind;

  unsigned RawLinkage;
  DeclID protoId;
  DefaultWitnessTableLayout::readRecord(scratch, protoId, RawLinkage);

  auto Linkage = fromStableSILLinkage(RawLinkage);
  if (!Linkage) {
    LLVM_DEBUG(llvm::dbgs() << "invalid linkage code " << RawLinkage
                            << " for SILFunction\n");
    MF->fatal("invalid linkage code");
  }

  ProtocolDecl *proto = cast<ProtocolDecl>(MF->getDecl(protoId));
  if (proto == nullptr) {
    LLVM_DEBUG(llvm::dbgs() << "invalid protocol code " << protoId << "\n");
    MF->fatal("invalid protocol code");
  }

  PrettyStackTraceDecl trace("deserializing default witness table for", proto);

  if (!existingWt)
    existingWt = SILMod.lookUpDefaultWitnessTable(proto, /*deserializeLazily=*/ false);
  auto wT = existingWt;

  // If we have an existing default witness table, verify that the protocol
  // matches up.
  if (wT) {
    if (wT->getProtocol() != proto) {
      MF->fatal("Protocol mismatch");
    }

    // Don't override the linkage of a default witness table with an existing
    // declaration.

  } else {
    // Otherwise, create a new witness table declaration.
    wT = SILDefaultWitnessTable::create(SILMod, *Linkage, proto);
    if (Callback)
      Callback->didDeserialize(MF->getAssociatedModule(), wT);
  }

  // Fetch the next record.
  scratch.clear();
  maybeEntry = SILCursor.advance(AF_DontPopBlockAtEnd);
  if (!maybeEntry)
    MF->fatal(maybeEntry.takeError());
  entry = maybeEntry.get();
  if (entry.Kind == llvm::BitstreamEntry::EndBlock)
    return nullptr;

  std::vector<SILWitnessTable::Entry> witnessEntries;
  std::vector<ProtocolConformanceRef> conditionalConformances;
  readWitnessTableEntries(entry, witnessEntries, conditionalConformances);

  wT->convertToDefinition(witnessEntries);
  wTableOrOffset.set(wT, /*fully deserialized*/ true);
  if (Callback)
    Callback->didDeserializeDefaultWitnessTableEntries(MF->getAssociatedModule(), wT);
  return wT;
}

/// Deserialize all DefaultWitnessTables inside the module and add them to SILMod.
void SILDeserializer::getAllDefaultWitnessTables() {
  if (!DefaultWitnessTableList)
    return;
  for (unsigned I = 0, E = DefaultWitnessTables.size(); I < E; ++I)
    readDefaultWitnessTable(I + 1, nullptr);
}

SILDefaultWitnessTable *
SILDeserializer::lookupDefaultWitnessTable(SILDefaultWitnessTable *existingWt) {
  assert(existingWt && "Cannot deserialize a null default witness table declaration.");
  assert(existingWt->isDeclaration() && "Cannot deserialize a default witness table "
                                        "definition.");

  // If we don't have a default witness table list, we can't look anything up.
  if (!DefaultWitnessTableList)
    return nullptr;

  // Use the mangled name of the protocol to lookup the partially
  // deserialized value from the default witness table list.
  auto iter = DefaultWitnessTableList->find(existingWt->getUniqueName());
  if (iter == DefaultWitnessTableList->end())
    return nullptr;

  // Attempt to read the default witness table.
  auto Wt = readDefaultWitnessTable(*iter, existingWt);
  if (Wt)
    LLVM_DEBUG(llvm::dbgs() << "Deserialize SIL:\n"; Wt->dump());

  return Wt;
}

void SILDeserializer::readDefaultOverrideTableEntries(
    llvm::BitstreamEntry &entry,
    std::vector<SILDefaultOverrideTable::Entry> &entries) {
  SmallVector<uint64_t, 64> scratch;
  llvm::Expected<unsigned> maybeKind = SILCursor.readRecord(entry.ID, scratch);
  if (!maybeKind)
    MF->fatal(maybeKind.takeError());
  unsigned kind = maybeKind.get();

  // Another record means the end of this DefaultOverrideTable.
  while (kind == SIL_DEFAULT_OVERRIDE_TABLE_ENTRY) {
    ArrayRef<uint64_t> ListOfValues;
    DeclID NameID;
    DefaultOverrideTableEntryLayout::readRecord(scratch, NameID, ListOfValues);
    SILFunction *impl = nullptr;
    if (NameID != 0) {
      impl = getFuncForReference(MF->getIdentifierText(NameID));
    }
    if (impl || NameID == 0) {
      unsigned NextValueIndex = 0;
      auto method = getSILDeclRef(MF, ListOfValues, NextValueIndex);
      auto original = getSILDeclRef(MF, ListOfValues, NextValueIndex);
      entries.push_back(SILDefaultOverrideTable::Entry{method, original, impl});
    }

    // Fetch the next record.
    scratch.clear();
    llvm::Expected<llvm::BitstreamEntry> maybeEntry =
        SILCursor.advance(AF_DontPopBlockAtEnd);
    if (!maybeEntry)
      MF->fatal(maybeEntry.takeError());
    entry = maybeEntry.get();
    if (entry.Kind == llvm::BitstreamEntry::EndBlock)
      // EndBlock means the end of this DefaultOverrideTable.
      break;
    maybeKind = SILCursor.readRecord(entry.ID, scratch);
    if (!maybeKind)
      MF->fatal(maybeKind.takeError());
    kind = maybeKind.get();
  }
}

SILDefaultOverrideTable *
SILDeserializer::readDefaultOverrideTable(DeclID tableID,
                                          SILDefaultOverrideTable *existingOt) {
  if (tableID == 0)
    return nullptr;
  assert(tableID <= DefaultOverrideTables.size() &&
         "invalid DefaultOverrideTable ID");

  auto &oTableOrOffset = DefaultOverrideTables[tableID - 1];

  if (oTableOrOffset.isFullyDeserialized())
    return oTableOrOffset.get();

  BCOffsetRAII restoreOffset(SILCursor);
  if (llvm::Error Err = SILCursor.JumpToBit(oTableOrOffset.getOffset()))
    MF->fatal(std::move(Err));
  llvm::Expected<llvm::BitstreamEntry> maybeEntry =
      SILCursor.advance(AF_DontPopBlockAtEnd);
  if (!maybeEntry)
    MF->fatal(maybeEntry.takeError());
  llvm::BitstreamEntry entry = maybeEntry.get();
  if (entry.Kind == llvm::BitstreamEntry::Error) {
    LLVM_DEBUG(llvm::dbgs() << "Cursor advance error in "
                               "readDefaultOverrideTable.\n");
    return nullptr;
  }

  SmallVector<uint64_t, 64> scratch;
  StringRef blobData;
  llvm::Expected<unsigned> maybeKind =
      SILCursor.readRecord(entry.ID, scratch, &blobData);
  if (!maybeKind)
    MF->fatal(maybeKind.takeError());
  unsigned kind = maybeKind.get();
  assert(kind == SIL_DEFAULT_OVERRIDE_TABLE &&
         "expect a sil default override table");
  (void)kind;

  unsigned rawLinkage;
  DeclID classID;
  DefaultOverrideTableLayout::readRecord(scratch, classID, rawLinkage);

  auto Linkage = fromStableSILLinkage(rawLinkage);
  if (!Linkage) {
    LLVM_DEBUG(llvm::dbgs() << "invalid linkage code " << rawLinkage
                            << " for SILFunction\n");
    MF->fatal("invalid linkage code");
  }

  ClassDecl *decl = cast<ClassDecl>(MF->getDecl(classID));
  if (decl == nullptr) {
    LLVM_DEBUG(llvm::dbgs() << "invalid class code " << classID << "\n");
    MF->fatal("invalid class code");
  }

  PrettyStackTraceDecl trace("deserializing default override table for", decl);

  if (!existingOt)
    existingOt =
        SILMod.lookUpDefaultOverrideTable(decl, /*deserializeLazily=*/false);
  auto oT = existingOt;

  // If we have an existing default override table, verify that the class
  // matches up.
  if (oT) {
    if (oT->getClass() != decl) {
      MF->fatal("Protocol mismatch");
    }

    // Don't override the linkage of a default override table with an existing
    // declaration.

  } else {
    // Otherwise, create a new override table declaration.
    oT = SILDefaultOverrideTable::declare(SILMod, *Linkage, decl);
    if (Callback)
      Callback->didDeserialize(MF->getAssociatedModule(), oT);
  }

  // Fetch the next record.
  scratch.clear();
  maybeEntry = SILCursor.advance(AF_DontPopBlockAtEnd);
  if (!maybeEntry)
    MF->fatal(maybeEntry.takeError());
  entry = maybeEntry.get();
  if (entry.Kind == llvm::BitstreamEntry::EndBlock)
    return nullptr;

  std::vector<SILDefaultOverrideTable::Entry> entries;
  readDefaultOverrideTableEntries(entry, entries);

  oT->define(entries);
  oTableOrOffset.set(oT, /*fully deserialized*/ true);
  if (Callback)
    Callback->didDeserializeDefaultOverrideTableEntries(
        MF->getAssociatedModule(), oT);
  return oT;
}

SILDefaultOverrideTable *SILDeserializer::lookupDefaultOverrideTable(
    SILDefaultOverrideTable *existingOt) {
  assert(existingOt &&
         "Cannot deserialize a null default override table declaration.");
  assert(existingOt->isDeclaration() &&
         "Cannot deserialize a default override table "
         "definition.");

  // If we don't have a default override table list, we can't look anything up.
  if (!DefaultOverrideTableList)
    return nullptr;

  // Use the mangled name of the class to lookup the partially deserialized
  // value from the default override table list.
  auto iter = DefaultOverrideTableList->find(existingOt->getUniqueName());
  if (iter == DefaultOverrideTableList->end())
    return nullptr;

  // Attempt to read the default override table.
  auto Ot = readDefaultOverrideTable(*iter, existingOt);
  if (Ot)
    LLVM_DEBUG(llvm::dbgs() << "Deserialize SIL:\n"; Ot->dump());

  return Ot;
}

void SILDeserializer::getAllDefaultOverrideTables() {
  if (!DefaultOverrideTableList)
    return;
  for (unsigned index = 0, size = DefaultOverrideTables.size(); index < size;
       ++index)
    readDefaultOverrideTable(index + 1, nullptr);
}

SILDifferentiabilityWitness *
SILDeserializer::readDifferentiabilityWitness(DeclID DId) {
  if (DId == 0)
    return nullptr;
  assert(DId <= DifferentiabilityWitnesses.size() &&
         "Invalid SILDifferentiabilityWitness ID");

  auto &diffWitnessOrOffset = DifferentiabilityWitnesses[DId - 1];
  if (diffWitnessOrOffset.isFullyDeserialized())
    return diffWitnessOrOffset.get();

  BCOffsetRAII restoreOffset(SILCursor);
  if (auto err = SILCursor.JumpToBit(diffWitnessOrOffset.getOffset()))
    MF->fatal(std::move(err));
  llvm::Expected<llvm::BitstreamEntry> maybeEntry =
      SILCursor.advance(AF_DontPopBlockAtEnd);
  if (!maybeEntry)
    MF->fatal(maybeEntry.takeError());
  auto entry = maybeEntry.get();
  if (entry.Kind == llvm::BitstreamEntry::Error) {
    LLVM_DEBUG(llvm::dbgs() << "Cursor advance error in "
                               "readDefaultWitnessTable.\n");
    return nullptr;
  }

  SmallVector<uint64_t, 64> scratch;
  StringRef blobData;
  llvm::Expected<unsigned> maybeKind =
      SILCursor.readRecord(entry.ID, scratch, &blobData);
  if (!maybeKind)
    MF->fatal(maybeKind.takeError());
  unsigned kind = maybeKind.get();
  assert(kind == SIL_DIFFERENTIABILITY_WITNESS &&
         "Expected sil_differentiability_witness");
  (void)kind;

  DeclID originalNameId, jvpNameId, vjpNameId;
  unsigned rawLinkage, isDeclaration, isSerialized, isDefault, rawDiffKind,
      numParameterIndices, numResultIndices;
  GenericSignatureID derivativeGenSigID;
  ArrayRef<uint64_t> rawParameterAndResultIndices;

  DifferentiabilityWitnessLayout::readRecord(
      scratch, originalNameId, rawLinkage, isDeclaration, isSerialized,
      isDefault, rawDiffKind, derivativeGenSigID, jvpNameId, vjpNameId,
      numParameterIndices, numResultIndices, rawParameterAndResultIndices);

  if (isDeclaration) {
    assert(!isSerialized && "declaration must not be serialized");
  }

  auto linkageOpt = fromStableSILLinkage(rawLinkage);
  assert(linkageOpt &&
         "Expected value linkage for sil_differentiability_witness");
  auto diffKind = fromStableDifferentiabilityKind(rawDiffKind);
  assert(diffKind &&
         "Expected differentiability kind for sil_differentiability_witness");
  auto originalName = MF->getIdentifierText(originalNameId);
  auto jvpName = MF->getIdentifierText(jvpNameId);
  auto vjpName = MF->getIdentifierText(vjpNameId);
  auto *original = getFuncForReference(originalName);
  assert(original && "Original function must be found");
  auto *jvp = getFuncForReference(jvpName);
  if (!jvpName.empty()) {
    assert(!isDeclaration && "JVP must not be defined in declaration");
    assert(jvp && "JVP function must be found if JVP name is not empty");
  }
  auto *vjp = getFuncForReference(vjpName);
  if (!vjpName.empty()) {
    assert(!isDeclaration && "VJP must not be defined in declaration");
    assert(vjp && "VJP function must be found if VJP name is not empty");
  }
  auto derivativeGenSig = MF->getGenericSignature(derivativeGenSigID);

  auto originalFnType = original->getLoweredFunctionType();
  SmallVector<unsigned, 8> parameterAndResultIndices(
      rawParameterAndResultIndices.begin(), rawParameterAndResultIndices.end());
  assert(parameterAndResultIndices.size() ==
             numParameterIndices + numResultIndices &&
         "Parameter/result indices count mismatch");
  auto *parameterIndices =
      IndexSubset::get(MF->getContext(), originalFnType->getNumParameters(),
                       ArrayRef<unsigned>(parameterAndResultIndices)
                           .take_front(numParameterIndices));
  auto numResults = originalFnType->getNumResults() +
                    originalFnType->getNumIndirectMutatingParameters();
  auto *resultIndices =
      IndexSubset::get(MF->getContext(), numResults,
                       ArrayRef<unsigned>(parameterAndResultIndices)
                           .take_back(numResultIndices));

  AutoDiffConfig config(parameterIndices, resultIndices, derivativeGenSig);
  auto *diffWitness = SILMod.lookUpDifferentiabilityWitness(
      {originalName, *diffKind, config});

  // Witnesses that we deserialize are always available externally; we never
  // want to emit them ourselves.
  auto linkage = swift::addExternalToLinkage(*linkageOpt);

  // If there is no existing differentiability witness, create one.
  if (!diffWitness)
    diffWitness = SILDifferentiabilityWitness::createDeclaration(
        SILMod, linkage, original, *diffKind, parameterIndices, resultIndices,
        derivativeGenSig, isDefault);

  // If the current differentiability witness is merely a declaration, and the
  // deserialized witness is a definition, upgrade the current differentiability
  // witness to a definition. This can happen in the following situations:
  // 1. The witness was just created above.
  // 2. The witness started out as a declaration (e.g. the differentiation
  //    pass emitted a witness for an external function) and now we're loading
  //    the definition (e.g. an optimization pass asked for the definition and
  //    we found the definition serialized in this module).
  if (diffWitness->isDeclaration() && !isDeclaration)
    diffWitness->convertToDefinition(jvp, vjp, isSerialized);

  diffWitnessOrOffset.set(diffWitness,
                          /*isFullyDeserialized*/ diffWitness->isDefinition());
  return diffWitness;
}

SILDifferentiabilityWitness *SILDeserializer::lookupDifferentiabilityWitness(
    StringRef mangledDiffWitnessKey) {
  if (!DifferentiabilityWitnessList)
    return nullptr;
  auto iter = DifferentiabilityWitnessList->find(mangledDiffWitnessKey);
  if (iter == DifferentiabilityWitnessList->end())
    return nullptr;
  return readDifferentiabilityWitness(*iter);
}

void SILDeserializer::getAllDifferentiabilityWitnesses() {
  if (!DifferentiabilityWitnessList)
    return;
  for (unsigned I = 0, E = DifferentiabilityWitnesses.size(); I < E; ++I)
    readDifferentiabilityWitness(I + 1);
}

SILDeserializer::~SILDeserializer() {
  // Drop our references to anything we've deserialized.
  for (auto &fnEntry : Funcs) {
    if (fnEntry.isDeserialized())
      fnEntry.get()->decrementRefCount();
  }
}

// Invalidate all cached SILFunctions.
void SILDeserializer::invalidateFunctionCache() {
  for (auto &fnEntry : Funcs)
    if (fnEntry.isDeserialized()) {
      fnEntry.get()->decrementRefCount();
      fnEntry.reset();
    }
}

bool SILDeserializer::invalidateFunction(SILFunction *F) {
  for (auto &fnEntry : Funcs) {
    if (fnEntry.isDeserialized() && fnEntry.get() == F) {
      fnEntry.get()->decrementRefCount();
      fnEntry.reset();
      return true;
    }
  }
  return false;
}

// Invalidate all cached SILGlobalVariable.
void SILDeserializer::invalidateGlobalVariableCache() {
  for (auto &entry : GlobalVars) {
    if (entry.isDeserialized()) {
      entry.reset();
    }
  }
}

// Invalidate a specific cached GlobalVariable.
bool SILDeserializer::invalidateGlobalVariable(SILGlobalVariable *gv) {
  for (auto &entry : GlobalVars) {
    if (entry.isDeserialized() && entry.get() == gv) {
      entry.reset();
      return true;
    }
  }

  return false;
}

// Invalidate all cached SILVTable.
void SILDeserializer::invalidateVTableCache() {
  for (auto &entry : VTables) {
    if (entry.isDeserialized()) {
      entry.reset();
    }
  }
}

// Invalidate a specific cached SILVTable.
bool SILDeserializer::invalidateVTable(SILVTable *v) {
  for (auto &entry : VTables) {
    if (entry.isDeserialized() && entry.get() == v) {
      entry.reset();
      return true;
    }
  }

  return false;
}

// Invalidate all cached SILWitnessTable.
void SILDeserializer::invalidateWitnessTableCache() {
  for (auto &entry : WitnessTables) {
    if (entry.isDeserialized()) {
      entry.reset();
    }
  }
}

// Invalidate a specific cached SILWitnessTable.
bool SILDeserializer::invalidateWitnessTable(SILWitnessTable *wt) {
  for (auto &entry : WitnessTables) {
    if (entry.isDeserialized() && entry.get() == wt) {
      entry.reset();
      return true;
    }
  }
  return false;
}

// Invalidate all cached SILDefaultWitnessTable.
void SILDeserializer::invalidateDefaultWitnessTableCache() {
  for (auto &entry : DefaultWitnessTables) {
    if (entry.isDeserialized()) {
      entry.reset();
    }
  }
}

// Invalidate a specific cached SILDefaultWitnessTable.
bool SILDeserializer::invalidateDefaultWitnessTable(
    SILDefaultWitnessTable *wt) {
  for (auto &entry : DefaultWitnessTables) {
    if (entry.isDeserialized() && entry.get() == wt) {
      entry.reset();
      return true;
    }
  }
  return false;
}

// Invalidate all cached SILProperty.
void SILDeserializer::invalidatePropertyCache() {
  for (auto &entry : Properties) {
    if (entry.isDeserialized()) {
      entry.reset();
    }
  }
}

// Invalidate a specific cached SILProperty.
bool SILDeserializer::invalidateProperty(SILProperty *p) {
  for (auto &entry : Properties) {
    if (entry.isDeserialized() && entry.get() == p) {
      entry.reset();
      return true;
    }
  }
  return false;
}

// Invalidate all cached SILDifferentiabilityWitness.
void SILDeserializer::invalidateDifferentiabilityWitnessCache() {
  for (auto &entry : DifferentiabilityWitnesses) {
    if (entry.isDeserialized()) {
      entry.reset();
    }
  }
}

// Invalidate a specific cached SILDifferentiabilityWitness.
bool SILDeserializer::invalidateDifferentiabilityWitness(
    SILDifferentiabilityWitness *w) {
  for (auto &entry : DifferentiabilityWitnesses) {
    if (entry.isDeserialized() && entry.get() == w) {
      entry.reset();
      return true;
    }
  }
  return false;
}
