Add CodeViewRecordIO for reading and writing.

Using a pattern similar to that of YamlIO, this allows
us to have a single codepath for translating codeview
records to and from serialized byte streams.  The
current patch only hooks this up to the reading of
CodeView type records.  A subsequent patch will hook
it up for writing of CodeView type records, and then a
third patch will hook up the reading and writing of
CodeView symbols.

Differential Revision: https://reviews.llvm.org/D26040

llvm-svn: 285836
diff --git a/llvm/lib/DebugInfo/CodeView/CMakeLists.txt b/llvm/lib/DebugInfo/CodeView/CMakeLists.txt
index a070080..4bbc48d 100644
--- a/llvm/lib/DebugInfo/CodeView/CMakeLists.txt
+++ b/llvm/lib/DebugInfo/CodeView/CMakeLists.txt
@@ -1,5 +1,6 @@
 add_llvm_library(LLVMDebugInfoCodeView
   CodeViewError.cpp
+  CodeViewRecordIO.cpp
   CVSymbolVisitor.cpp
   CVTypeVisitor.cpp
   EnumTables.cpp
@@ -15,6 +16,7 @@
   TypeDumper.cpp
   TypeRecord.cpp
   TypeRecordBuilder.cpp
+  TypeRecordMapping.cpp
   TypeStreamMerger.cpp
   TypeTableBuilder.cpp
 
diff --git a/llvm/lib/DebugInfo/CodeView/CVTypeVisitor.cpp b/llvm/lib/DebugInfo/CodeView/CVTypeVisitor.cpp
index 2dee898..5f5d5fe 100644
--- a/llvm/lib/DebugInfo/CodeView/CVTypeVisitor.cpp
+++ b/llvm/lib/DebugInfo/CodeView/CVTypeVisitor.cpp
@@ -10,44 +10,29 @@
 #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
 
 #include "llvm/DebugInfo/CodeView/CodeViewError.h"
+#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
+#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
 #include "llvm/DebugInfo/MSF/ByteStream.h"
 
 using namespace llvm;
 using namespace llvm::codeview;
 
-static Error skipPadding(msf::StreamReader &Reader) {
-  if (Reader.empty())
-    return Error::success();
-
-  uint8_t Leaf = Reader.peek();
-  if (Leaf < LF_PAD0)
-    return Error::success();
-  // Leaf is greater than 0xf0. We should advance by the number of bytes in
-  // the low 4 bits.
-  unsigned BytesToAdvance = Leaf & 0x0F;
-  return Reader.skip(BytesToAdvance);
-}
-
 template <typename T>
 static Expected<CVMemberRecord>
-deserializeMemberRecord(msf::StreamReader &Reader, TypeLeafKind Kind) {
-  msf::StreamReader OldReader = Reader;
-  TypeRecordKind RK = static_cast<TypeRecordKind>(Kind);
-  auto ExpectedRecord = T::deserialize(RK, Reader);
-  if (!ExpectedRecord)
-    return ExpectedRecord.takeError();
-  assert(Reader.bytesRemaining() < OldReader.bytesRemaining());
-  if (auto EC = skipPadding(Reader))
+deserializeMemberRecord(FieldListDeserializer &Deserializer,
+                        msf::StreamReader &Reader, TypeLeafKind Kind) {
+  T MR(static_cast<TypeRecordKind>(Kind));
+  CVMemberRecord CVR;
+  CVR.Kind = Kind;
+
+  if (auto EC = Deserializer.visitMemberBegin(CVR))
+    return std::move(EC);
+  if (auto EC = Deserializer.visitKnownMember(CVR, MR))
+    return std::move(EC);
+  if (auto EC = Deserializer.visitMemberEnd(CVR))
     return std::move(EC);
 
-  CVMemberRecord CVMR;
-  CVMR.Kind = Kind;
-
-  uint32_t RecordLength = OldReader.bytesRemaining() - Reader.bytesRemaining();
-  if (auto EC = OldReader.readBytes(CVMR.Data, RecordLength))
-    return std::move(EC);
-
-  return CVMR;
+  return CVR;
 }
 
 CVTypeVisitor::CVTypeVisitor(TypeVisitorCallbacks &Callbacks)
@@ -138,22 +123,28 @@
 }
 
 template <typename MR>
-static Error visitKnownMember(msf::StreamReader &Reader, TypeLeafKind Leaf,
+static Error visitKnownMember(FieldListDeserializer &Deserializer,
+                              msf::StreamReader &Reader, TypeLeafKind Leaf,
                               TypeVisitorCallbacks &Callbacks) {
-  auto ExpectedRecord = deserializeMemberRecord<MR>(Reader, Leaf);
-  if (!ExpectedRecord)
-    return ExpectedRecord.takeError();
-  CVMemberRecord &Record = *ExpectedRecord;
-  if (auto EC = Callbacks.visitMemberBegin(Record))
+  MR Record(static_cast<TypeRecordKind>(Leaf));
+  CVMemberRecord CVR;
+  CVR.Kind = Leaf;
+
+  if (auto EC = Callbacks.visitMemberBegin(CVR))
     return EC;
-  if (auto EC = visitKnownMember<MR>(Record, Callbacks))
+  if (auto EC = Callbacks.visitKnownMember(CVR, Record))
     return EC;
-  if (auto EC = Callbacks.visitMemberEnd(Record))
+  if (auto EC = Callbacks.visitMemberEnd(CVR))
     return EC;
   return Error::success();
 }
 
 Error CVTypeVisitor::visitFieldListMemberStream(msf::StreamReader Reader) {
+  FieldListDeserializer Deserializer(Reader);
+  TypeVisitorCallbackPipeline Pipeline;
+  Pipeline.addCallbackToPipeline(Deserializer);
+  Pipeline.addCallbackToPipeline(Callbacks);
+
   TypeLeafKind Leaf;
   while (!Reader.empty()) {
     if (auto EC = Reader.readEnum(Leaf))
@@ -168,7 +159,8 @@
           cv_error_code::unknown_member_record);
 #define MEMBER_RECORD(EnumName, EnumVal, Name)                                 \
   case EnumName: {                                                             \
-    if (auto EC = visitKnownMember<Name##Record>(Reader, Leaf, Callbacks))     \
+    if (auto EC = visitKnownMember<Name##Record>(Deserializer, Reader, Leaf,   \
+                                                 Pipeline))                    \
       return EC;                                                               \
     break;                                                                     \
   }
diff --git a/llvm/lib/DebugInfo/CodeView/CodeViewRecordIO.cpp b/llvm/lib/DebugInfo/CodeView/CodeViewRecordIO.cpp
new file mode 100644
index 0000000..7841e4f
--- /dev/null
+++ b/llvm/lib/DebugInfo/CodeView/CodeViewRecordIO.cpp
@@ -0,0 +1,186 @@
+//===- CodeViewRecordIO.cpp -------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/CodeViewRecordIO.h"
+#include "llvm/DebugInfo/CodeView/CodeView.h"
+#include "llvm/DebugInfo/CodeView/RecordSerialization.h"
+#include "llvm/DebugInfo/MSF/StreamReader.h"
+#include "llvm/DebugInfo/MSF/StreamWriter.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+Error CodeViewRecordIO::beginRecord(uint16_t Kind) {
+  assert(!CurrentRecord.hasValue() && "There is already a record active!");
+  CurrentRecord.emplace();
+
+  CurrentRecord->Kind = Kind;
+  return Error::success();
+}
+
+Error CodeViewRecordIO::endRecord() {
+  assert(CurrentRecord.hasValue() && "Not in a record!");
+  CurrentRecord.reset();
+  return Error::success();
+}
+
+Error CodeViewRecordIO::skipPadding() {
+  assert(!isWriting() && "Cannot skip padding while writing!");
+
+  if (Reader->bytesRemaining() == 0)
+    return Error::success();
+
+  uint8_t Leaf = Reader->peek();
+  if (Leaf < LF_PAD0)
+    return Error::success();
+  // Leaf is greater than 0xf0. We should advance by the number of bytes in
+  // the low 4 bits.
+  unsigned BytesToAdvance = Leaf & 0x0F;
+  return Reader->skip(BytesToAdvance);
+}
+
+Error CodeViewRecordIO::mapByteVectorTail(ArrayRef<uint8_t> &Bytes) {
+  if (isWriting()) {
+    if (auto EC = Writer->writeBytes(Bytes))
+      return EC;
+  } else {
+    if (auto EC = Reader->readBytes(Bytes, Reader->bytesRemaining()))
+      return EC;
+  }
+  return Error::success();
+}
+
+Error CodeViewRecordIO::mapInteger(TypeIndex &TypeInd) {
+  if (isWriting()) {
+    if (auto EC = Writer->writeInteger(TypeInd.getIndex()))
+      return EC;
+    return Error::success();
+  }
+
+  uint32_t I;
+  if (auto EC = Reader->readInteger(I))
+    return EC;
+  TypeInd.setIndex(I);
+  return Error::success();
+}
+
+Error CodeViewRecordIO::mapEncodedInteger(int64_t &Value) {
+  if (isWriting()) {
+    if (Value >= 0) {
+      if (auto EC = writeEncodedUnsignedInteger(static_cast<uint64_t>(Value)))
+        return EC;
+    } else {
+      if (auto EC = writeEncodedSignedInteger(Value))
+        return EC;
+    }
+  } else {
+    APSInt N;
+    if (auto EC = consume(*Reader, N))
+      return EC;
+    Value = N.getExtValue();
+  }
+
+  return Error::success();
+}
+
+Error CodeViewRecordIO::mapEncodedInteger(uint64_t &Value) {
+  if (isWriting()) {
+    if (auto EC = writeEncodedUnsignedInteger(Value))
+      return EC;
+  } else {
+    APSInt N;
+    if (auto EC = consume(*Reader, N))
+      return EC;
+    Value = N.getZExtValue();
+  }
+  return Error::success();
+}
+
+Error CodeViewRecordIO::mapEncodedInteger(APSInt &Value) {
+  if (isWriting()) {
+    if (Value.isSigned())
+      return writeEncodedSignedInteger(Value.getSExtValue());
+    return writeEncodedUnsignedInteger(Value.getZExtValue());
+  }
+
+  return consume(*Reader, Value);
+}
+
+Error CodeViewRecordIO::mapStringZ(StringRef &Value) {
+  if (isWriting()) {
+    if (auto EC = Writer->writeZeroString(Value))
+      return EC;
+  } else {
+    if (auto EC = Reader->readZeroString(Value))
+      return EC;
+  }
+  return Error::success();
+}
+
+Error CodeViewRecordIO::mapGuid(StringRef &Guid) {
+  if (isWriting()) {
+    assert(Guid.size() == 16 && "Invalid Guid Size!");
+    if (auto EC = Writer->writeFixedString(Guid))
+      return EC;
+  } else {
+    if (auto EC = Reader->readFixedString(Guid, 16))
+      return EC;
+  }
+  return Error::success();
+}
+
+Error CodeViewRecordIO::writeEncodedSignedInteger(const int64_t &Value) {
+  assert(Value < 0 && "Encoded integer is not signed!");
+  if (Value >= std::numeric_limits<int8_t>::min()) {
+    if (auto EC = Writer->writeInteger(static_cast<uint16_t>(LF_CHAR)))
+      return EC;
+    if (auto EC = Writer->writeInteger(static_cast<int8_t>(Value)))
+      return EC;
+  } else if (Value >= std::numeric_limits<int16_t>::min()) {
+    if (auto EC = Writer->writeInteger(static_cast<uint16_t>(LF_SHORT)))
+      return EC;
+    if (auto EC = Writer->writeInteger(static_cast<int16_t>(Value)))
+      return EC;
+  } else if (Value >= std::numeric_limits<int32_t>::min()) {
+    if (auto EC = Writer->writeInteger(static_cast<uint16_t>(LF_LONG)))
+      return EC;
+    if (auto EC = Writer->writeInteger(static_cast<int32_t>(Value)))
+      return EC;
+  } else {
+    if (auto EC = Writer->writeInteger(static_cast<uint16_t>(LF_QUADWORD)))
+      return EC;
+    if (auto EC = Writer->writeInteger(Value))
+      return EC;
+  }
+  return Error::success();
+}
+
+Error CodeViewRecordIO::writeEncodedUnsignedInteger(const uint64_t &Value) {
+  if (Value < LF_NUMERIC) {
+    if (auto EC = Writer->writeInteger(static_cast<uint16_t>(Value)))
+      return EC;
+  } else if (Value <= std::numeric_limits<uint16_t>::max()) {
+    if (auto EC = Writer->writeInteger(static_cast<uint16_t>(LF_USHORT)))
+      return EC;
+    if (auto EC = Writer->writeInteger(static_cast<uint16_t>(Value)))
+      return EC;
+  } else if (Value <= std::numeric_limits<uint32_t>::max()) {
+    if (auto EC = Writer->writeInteger(static_cast<uint16_t>(LF_ULONG)))
+      return EC;
+    if (auto EC = Writer->writeInteger(static_cast<uint32_t>(Value)))
+      return EC;
+  } else {
+    if (auto EC = Writer->writeInteger(static_cast<uint16_t>(LF_UQUADWORD)))
+      return EC;
+    if (auto EC = Writer->writeInteger(Value))
+      return EC;
+  }
+
+  return Error::success();
+}
diff --git a/llvm/lib/DebugInfo/CodeView/TypeDumper.cpp b/llvm/lib/DebugInfo/CodeView/TypeDumper.cpp
index 1e7af16..84abad9 100644
--- a/llvm/lib/DebugInfo/CodeView/TypeDumper.cpp
+++ b/llvm/lib/DebugInfo/CodeView/TypeDumper.cpp
@@ -268,12 +268,7 @@
 
 Error CVTypeDumper::visitKnownRecord(CVRecord<TypeLeafKind> &CVR,
                                      FieldListRecord &FieldList) {
-  TypeDeserializer Deserializer;
-  TypeVisitorCallbackPipeline Pipeline;
-  Pipeline.addCallbackToPipeline(Deserializer);
-  Pipeline.addCallbackToPipeline(*this);
-
-  CVTypeVisitor Visitor(Pipeline);
+  CVTypeVisitor Visitor(*this);
   if (auto EC = Visitor.visitFieldListMemberStream(FieldList.Data))
     return EC;
 
diff --git a/llvm/lib/DebugInfo/CodeView/TypeRecord.cpp b/llvm/lib/DebugInfo/CodeView/TypeRecord.cpp
index 7a2dc8f..b951c06 100644
--- a/llvm/lib/DebugInfo/CodeView/TypeRecord.cpp
+++ b/llvm/lib/DebugInfo/CodeView/TypeRecord.cpp
@@ -17,384 +17,6 @@
 using namespace llvm::codeview;
 
 //===----------------------------------------------------------------------===//
-// Type record deserialization
-//===----------------------------------------------------------------------===//
-
-Expected<MemberPointerInfo>
-MemberPointerInfo::deserialize(msf::StreamReader &Reader) {
-  const Layout *L = nullptr;
-  if (auto EC = Reader.readObject(L))
-    return std::move(EC);
-
-  TypeIndex T = L->ClassType;
-  uint16_t R = L->Representation;
-  PointerToMemberRepresentation PMR =
-      static_cast<PointerToMemberRepresentation>(R);
-  return MemberPointerInfo(T, PMR);
-}
-
-Expected<ModifierRecord>
-ModifierRecord::deserialize(TypeRecordKind Kind, msf::StreamReader &Reader) {
-  const Layout *L = nullptr;
-  if (auto EC = Reader.readObject(L))
-    return std::move(EC);
-
-  TypeIndex M = L->ModifiedType;
-  uint16_t O = L->Modifiers;
-  ModifierOptions MO = static_cast<ModifierOptions>(O);
-  return ModifierRecord(M, MO);
-}
-
-Expected<ProcedureRecord>
-ProcedureRecord::deserialize(TypeRecordKind Kind, msf::StreamReader &Reader) {
-  const Layout *L = nullptr;
-  if (auto EC = Reader.readObject(L))
-    return std::move(EC);
-  return ProcedureRecord(L->ReturnType, L->CallConv, L->Options,
-                         L->NumParameters, L->ArgListType);
-}
-
-Expected<MemberFunctionRecord>
-MemberFunctionRecord::deserialize(TypeRecordKind Kind,
-                                  msf::StreamReader &Reader) {
-  const Layout *L = nullptr;
-  CV_DESERIALIZE(Reader, L);
-  return MemberFunctionRecord(L->ReturnType, L->ClassType, L->ThisType,
-                              L->CallConv, L->Options, L->NumParameters,
-                              L->ArgListType, L->ThisAdjustment);
-}
-
-Expected<MemberFuncIdRecord>
-MemberFuncIdRecord::deserialize(TypeRecordKind Kind,
-                                msf::StreamReader &Reader) {
-  const Layout *L = nullptr;
-  StringRef Name;
-  CV_DESERIALIZE(Reader, L, Name);
-  return MemberFuncIdRecord(L->ClassType, L->FunctionType, Name);
-}
-
-Expected<ArgListRecord> ArgListRecord::deserialize(TypeRecordKind Kind,
-                                                   msf::StreamReader &Reader) {
-  if (Kind != TypeRecordKind::StringList && Kind != TypeRecordKind::ArgList)
-    return make_error<CodeViewError>(
-        cv_error_code::corrupt_record,
-        "ArgListRecord contains unexpected TypeRecordKind");
-
-  const Layout *L = nullptr;
-  ArrayRef<TypeIndex> Indices;
-  CV_DESERIALIZE(Reader, L, CV_ARRAY_FIELD_N(Indices, L->NumArgs));
-  return ArgListRecord(Kind, Indices);
-}
-
-Expected<PointerRecord> PointerRecord::deserialize(TypeRecordKind Kind,
-                                                   msf::StreamReader &Reader) {
-  const Layout *L = nullptr;
-  if (auto EC = Reader.readObject(L))
-    return std::move(EC);
-
-  PointerKind PtrKind = L->getPtrKind();
-  PointerMode Mode = L->getPtrMode();
-  uint32_t Opts = L->Attrs;
-  PointerOptions Options = static_cast<PointerOptions>(Opts);
-  uint8_t Size = L->getPtrSize();
-
-  if (L->isPointerToMember()) {
-    if (auto ExpectedMPI = MemberPointerInfo::deserialize(Reader))
-      return PointerRecord(L->PointeeType, PtrKind, Mode, Options, Size,
-                           *ExpectedMPI);
-    else
-      return ExpectedMPI.takeError();
-  }
-
-  return PointerRecord(L->PointeeType, PtrKind, Mode, Options, Size);
-}
-
-Expected<NestedTypeRecord>
-NestedTypeRecord::deserialize(TypeRecordKind Kind, msf::StreamReader &Reader) {
-  const Layout *L = nullptr;
-  StringRef Name;
-  CV_DESERIALIZE(Reader, L, Name);
-  return NestedTypeRecord(L->Type, Name);
-}
-
-Expected<FieldListRecord>
-FieldListRecord::deserialize(TypeRecordKind Kind, msf::StreamReader &Reader) {
-  ArrayRef<uint8_t> Data;
-  if (auto EC = Reader.readBytes(Data, Reader.bytesRemaining()))
-    return std::move(EC);
-  return FieldListRecord(Data);
-}
-
-Expected<ArrayRecord> ArrayRecord::deserialize(TypeRecordKind Kind,
-                                               msf::StreamReader &Reader) {
-  const Layout *L = nullptr;
-  uint64_t Size;
-  StringRef Name;
-  CV_DESERIALIZE(Reader, L, CV_NUMERIC_FIELD(Size), Name);
-  return ArrayRecord(L->ElementType, L->IndexType, Size, Name);
-}
-
-Expected<ClassRecord> ClassRecord::deserialize(TypeRecordKind Kind,
-                                               msf::StreamReader &Reader) {
-  uint64_t Size = 0;
-  StringRef Name;
-  StringRef UniqueName;
-  uint16_t Props;
-  const Layout *L = nullptr;
-
-  CV_DESERIALIZE(Reader, L, CV_NUMERIC_FIELD(Size), Name,
-                 CV_CONDITIONAL_FIELD(UniqueName, L->hasUniqueName()));
-
-  Props = L->Properties;
-  uint16_t WrtValue = (Props & WinRTKindMask) >> WinRTKindShift;
-  WindowsRTClassKind WRT = static_cast<WindowsRTClassKind>(WrtValue);
-  uint16_t HfaMask = (Props & HfaKindMask) >> HfaKindShift;
-  HfaKind Hfa = static_cast<HfaKind>(HfaMask);
-
-  ClassOptions Options = static_cast<ClassOptions>(Props);
-  return ClassRecord(Kind, L->MemberCount, Options, Hfa, WRT, L->FieldList,
-                     L->DerivedFrom, L->VShape, Size, Name, UniqueName);
-}
-
-Expected<UnionRecord> UnionRecord::deserialize(TypeRecordKind Kind,
-                                               msf::StreamReader &Reader) {
-  uint64_t Size = 0;
-  StringRef Name;
-  StringRef UniqueName;
-  uint16_t Props;
-
-  const Layout *L = nullptr;
-  CV_DESERIALIZE(Reader, L, CV_NUMERIC_FIELD(Size), Name,
-                 CV_CONDITIONAL_FIELD(UniqueName, L->hasUniqueName()));
-
-  Props = L->Properties;
-
-  uint16_t HfaMask = (Props & HfaKindMask) >> HfaKindShift;
-  HfaKind Hfa = static_cast<HfaKind>(HfaMask);
-  ClassOptions Options = static_cast<ClassOptions>(Props);
-  return UnionRecord(L->MemberCount, Options, Hfa, L->FieldList, Size, Name,
-                     UniqueName);
-}
-
-Expected<EnumRecord> EnumRecord::deserialize(TypeRecordKind Kind,
-                                             msf::StreamReader &Reader) {
-  const Layout *L = nullptr;
-  StringRef Name;
-  StringRef UniqueName;
-  CV_DESERIALIZE(Reader, L, Name,
-                 CV_CONDITIONAL_FIELD(UniqueName, L->hasUniqueName()));
-
-  uint16_t P = L->Properties;
-  ClassOptions Options = static_cast<ClassOptions>(P);
-  return EnumRecord(L->NumEnumerators, Options, L->FieldListType, Name,
-                    UniqueName, L->UnderlyingType);
-}
-
-Expected<BitFieldRecord>
-BitFieldRecord::deserialize(TypeRecordKind Kind, msf::StreamReader &Reader) {
-  const Layout *L = nullptr;
-  CV_DESERIALIZE(Reader, L);
-  return BitFieldRecord(L->Type, L->BitSize, L->BitOffset);
-}
-
-Expected<VFTableShapeRecord>
-VFTableShapeRecord::deserialize(TypeRecordKind Kind,
-                                msf::StreamReader &Reader) {
-  const Layout *L = nullptr;
-  if (auto EC = Reader.readObject(L))
-    return std::move(EC);
-
-  std::vector<VFTableSlotKind> Slots;
-  uint16_t Count = L->VFEntryCount;
-  while (Count > 0) {
-    // Process up to 2 nibbles at a time (if there are at least 2 remaining)
-    uint8_t Data;
-    if (auto EC = Reader.readInteger(Data))
-      return std::move(EC);
-
-    uint8_t Value = Data & 0x0F;
-    Slots.push_back(static_cast<VFTableSlotKind>(Value));
-    if (--Count > 0) {
-      Value = (Data & 0xF0) >> 4;
-      Slots.push_back(static_cast<VFTableSlotKind>(Value));
-      --Count;
-    }
-  }
-
-  return VFTableShapeRecord(Slots);
-}
-
-Expected<TypeServer2Record>
-TypeServer2Record::deserialize(TypeRecordKind Kind, msf::StreamReader &Reader) {
-  const Layout *L = nullptr;
-  StringRef Name;
-  CV_DESERIALIZE(Reader, L, Name);
-  return TypeServer2Record(StringRef(L->Guid, 16), L->Age, Name);
-}
-
-Expected<StringIdRecord>
-StringIdRecord::deserialize(TypeRecordKind Kind, msf::StreamReader &Reader) {
-  const Layout *L = nullptr;
-  StringRef Name;
-  CV_DESERIALIZE(Reader, L, Name);
-  return StringIdRecord(L->id, Name);
-}
-
-Expected<FuncIdRecord> FuncIdRecord::deserialize(TypeRecordKind Kind,
-                                                 msf::StreamReader &Reader) {
-  const Layout *L = nullptr;
-  StringRef Name;
-  CV_DESERIALIZE(Reader, L, Name);
-  return FuncIdRecord(L->ParentScope, L->FunctionType, Name);
-}
-
-Expected<UdtSourceLineRecord>
-UdtSourceLineRecord::deserialize(TypeRecordKind Kind,
-                                 msf::StreamReader &Reader) {
-  const Layout *L = nullptr;
-  CV_DESERIALIZE(Reader, L);
-  return UdtSourceLineRecord(L->UDT, L->SourceFile, L->LineNumber);
-}
-
-Expected<BuildInfoRecord>
-BuildInfoRecord::deserialize(TypeRecordKind Kind, msf::StreamReader &Reader) {
-  const Layout *L = nullptr;
-  ArrayRef<TypeIndex> Indices;
-  CV_DESERIALIZE(Reader, L, CV_ARRAY_FIELD_N(Indices, L->NumArgs));
-  return BuildInfoRecord(Indices);
-}
-
-Expected<VFTableRecord> VFTableRecord::deserialize(TypeRecordKind Kind,
-                                                   msf::StreamReader &Reader) {
-  const Layout *L = nullptr;
-  StringRef Name;
-  std::vector<StringRef> Names;
-  CV_DESERIALIZE(Reader, L, Name, CV_ARRAY_FIELD_TAIL(Names));
-  return VFTableRecord(L->CompleteClass, L->OverriddenVFTable, L->VFPtrOffset,
-                       Name, Names);
-}
-
-Expected<OneMethodRecord>
-OneMethodRecord::deserialize(TypeRecordKind Kind, msf::StreamReader &Reader) {
-  const Layout *L = nullptr;
-  StringRef Name;
-  int32_t VFTableOffset = -1;
-
-  CV_DESERIALIZE(Reader, L, CV_CONDITIONAL_FIELD(
-                                VFTableOffset, L->Attrs.isIntroducedVirtual()),
-                 Name);
-
-  MethodOptions Options = L->Attrs.getFlags();
-  MethodKind MethKind = L->Attrs.getMethodKind();
-  MemberAccess Access = L->Attrs.getAccess();
-  OneMethodRecord Method(L->Type, MethKind, Options, Access, VFTableOffset,
-                         Name);
-  // Validate the vftable offset.
-  if (Method.isIntroducingVirtual() && Method.getVFTableOffset() < 0)
-    return make_error<CodeViewError>(cv_error_code::corrupt_record,
-                                     "Invalid VFTableOffset");
-  return Method;
-}
-
-Expected<MethodOverloadListRecord>
-MethodOverloadListRecord::deserialize(TypeRecordKind Kind,
-                                      msf::StreamReader &Reader) {
-  std::vector<OneMethodRecord> Methods;
-  while (!Reader.empty()) {
-    const Layout *L = nullptr;
-    int32_t VFTableOffset = -1;
-    CV_DESERIALIZE(
-        Reader, L,
-        CV_CONDITIONAL_FIELD(VFTableOffset, L->Attrs.isIntroducedVirtual()));
-
-    MethodOptions Options = L->Attrs.getFlags();
-    MethodKind MethKind = L->Attrs.getMethodKind();
-    MemberAccess Access = L->Attrs.getAccess();
-
-    Methods.emplace_back(L->Type, MethKind, Options, Access, VFTableOffset,
-                         StringRef());
-
-    // Validate the vftable offset.
-    auto &Method = Methods.back();
-    if (Method.isIntroducingVirtual() && Method.getVFTableOffset() < 0)
-      return make_error<CodeViewError>(cv_error_code::corrupt_record,
-                                       "Invalid VFTableOffset");
-  }
-  return MethodOverloadListRecord(Methods);
-}
-
-Expected<OverloadedMethodRecord>
-OverloadedMethodRecord::deserialize(TypeRecordKind Kind,
-                                    msf::StreamReader &Reader) {
-  const Layout *L = nullptr;
-  StringRef Name;
-  CV_DESERIALIZE(Reader, L, Name);
-  return OverloadedMethodRecord(L->MethodCount, L->MethList, Name);
-}
-
-Expected<DataMemberRecord>
-DataMemberRecord::deserialize(TypeRecordKind Kind, msf::StreamReader &Reader) {
-  const Layout *L = nullptr;
-  uint64_t Offset;
-  StringRef Name;
-  CV_DESERIALIZE(Reader, L, CV_NUMERIC_FIELD(Offset), Name);
-  return DataMemberRecord(L->Attrs.getAccess(), L->Type, Offset, Name);
-}
-
-Expected<StaticDataMemberRecord>
-StaticDataMemberRecord::deserialize(TypeRecordKind Kind,
-                                    msf::StreamReader &Reader) {
-  const Layout *L = nullptr;
-  StringRef Name;
-  CV_DESERIALIZE(Reader, L, Name);
-  return StaticDataMemberRecord(L->Attrs.getAccess(), L->Type, Name);
-}
-
-Expected<EnumeratorRecord>
-EnumeratorRecord::deserialize(TypeRecordKind Kind, msf::StreamReader &Reader) {
-  const Layout *L = nullptr;
-  APSInt Value;
-  StringRef Name;
-  CV_DESERIALIZE(Reader, L, Value, Name);
-  return EnumeratorRecord(L->Attrs.getAccess(), Value, Name);
-}
-
-Expected<VFPtrRecord> VFPtrRecord::deserialize(TypeRecordKind Kind,
-                                               msf::StreamReader &Reader) {
-  const Layout *L = nullptr;
-  if (auto EC = Reader.readObject(L))
-    return std::move(EC);
-  return VFPtrRecord(L->Type);
-}
-
-Expected<BaseClassRecord>
-BaseClassRecord::deserialize(TypeRecordKind Kind, msf::StreamReader &Reader) {
-  const Layout *L = nullptr;
-  uint64_t Offset;
-  CV_DESERIALIZE(Reader, L, CV_NUMERIC_FIELD(Offset));
-  return BaseClassRecord(L->Attrs.getAccess(), L->BaseType, Offset);
-}
-
-Expected<VirtualBaseClassRecord>
-VirtualBaseClassRecord::deserialize(TypeRecordKind Kind,
-                                    msf::StreamReader &Reader) {
-  const Layout *L = nullptr;
-  uint64_t Offset;
-  uint64_t Index;
-  CV_DESERIALIZE(Reader, L, CV_NUMERIC_FIELD(Offset), CV_NUMERIC_FIELD(Index));
-  return VirtualBaseClassRecord(Kind, L->Attrs.getAccess(), L->BaseType,
-                                L->VBPtrType, Offset, Index);
-}
-
-Expected<ListContinuationRecord>
-ListContinuationRecord::deserialize(TypeRecordKind Kind,
-                                    msf::StreamReader &Reader) {
-  const Layout *L = nullptr;
-  CV_DESERIALIZE(Reader, L);
-  return ListContinuationRecord(L->ContinuationIndex);
-}
-
-//===----------------------------------------------------------------------===//
 // Type index remapping
 //===----------------------------------------------------------------------===//
 
diff --git a/llvm/lib/DebugInfo/CodeView/TypeRecordMapping.cpp b/llvm/lib/DebugInfo/CodeView/TypeRecordMapping.cpp
new file mode 100644
index 0000000..d85a643
--- /dev/null
+++ b/llvm/lib/DebugInfo/CodeView/TypeRecordMapping.cpp
@@ -0,0 +1,417 @@
+//===- TypeRecordMapping.cpp ------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/TypeRecordMapping.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+#define error(X)                                                               \
+  if (auto EC = X)                                                             \
+    return EC;
+
+namespace {
+struct MapStringZ {
+  Error operator()(CodeViewRecordIO &IO, StringRef &S) const {
+    return IO.mapStringZ(S);
+  }
+};
+
+struct MapInteger {
+  template <typename T> Error operator()(CodeViewRecordIO &IO, T &N) const {
+    return IO.mapInteger(N);
+  }
+};
+
+struct MapEnum {
+  template <typename T> Error operator()(CodeViewRecordIO &IO, T &N) const {
+    return IO.mapEnum(N);
+  }
+};
+
+struct MapOneMethodRecord {
+  explicit MapOneMethodRecord(bool IsFromOverloadList)
+      : IsFromOverloadList(IsFromOverloadList) {}
+
+  Error operator()(CodeViewRecordIO &IO, OneMethodRecord &Method) const {
+    error(IO.mapInteger(Method.Attrs.Attrs));
+    if (IsFromOverloadList) {
+      uint16_t Padding = 0;
+      error(IO.mapInteger(Padding));
+    }
+    error(IO.mapInteger(Method.Type));
+    if (Method.isIntroducingVirtual()) {
+      error(IO.mapInteger(Method.VFTableOffset));
+    } else if (!IO.isWriting())
+      Method.VFTableOffset = -1;
+
+    if (!IsFromOverloadList)
+      error(IO.mapStringZ(Method.Name));
+
+    return Error::success();
+  }
+
+private:
+  bool IsFromOverloadList;
+};
+}
+
+static Error mapNameAndUniqueName(CodeViewRecordIO &IO, StringRef &Name,
+                                  StringRef &UniqueName, bool HasUniqueName) {
+  error(IO.mapStringZ(Name));
+  if (HasUniqueName)
+    error(IO.mapStringZ(UniqueName));
+
+  return Error::success();
+}
+
+Error TypeRecordMapping::visitTypeBegin(CVType &CVR) {
+  error(IO.beginRecord(CVR.Type));
+  TypeKind = CVR.Type;
+  return Error::success();
+}
+
+Error TypeRecordMapping::visitTypeEnd(CVType &Record) {
+  error(IO.endRecord());
+  TypeKind.reset();
+  return Error::success();
+}
+
+Error TypeRecordMapping::visitMemberBegin(CVMemberRecord &Record) {
+  return Error::success();
+}
+
+Error TypeRecordMapping::visitMemberEnd(CVMemberRecord &Record) {
+  if (!IO.isWriting()) {
+    if (auto EC = IO.skipPadding())
+      return EC;
+  }
+
+  return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR, ModifierRecord &Record) {
+  error(IO.mapInteger(Record.ModifiedType));
+  error(IO.mapEnum(Record.Modifiers));
+
+  return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
+                                          ProcedureRecord &Record) {
+  error(IO.mapInteger(Record.ReturnType));
+  error(IO.mapEnum(Record.CallConv));
+  error(IO.mapEnum(Record.Options));
+  error(IO.mapInteger(Record.ParameterCount));
+  error(IO.mapInteger(Record.ArgumentList));
+
+  return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
+                                          MemberFunctionRecord &Record) {
+  error(IO.mapInteger(Record.ReturnType));
+  error(IO.mapInteger(Record.ClassType));
+  error(IO.mapInteger(Record.ThisType));
+  error(IO.mapEnum(Record.CallConv));
+  error(IO.mapEnum(Record.Options));
+  error(IO.mapInteger(Record.ParameterCount));
+  error(IO.mapInteger(Record.ArgumentList));
+  error(IO.mapInteger(Record.ThisPointerAdjustment));
+
+  return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR, ArgListRecord &Record) {
+  error(IO.mapVectorN<uint32_t>(Record.StringIndices, MapInteger()));
+
+  return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR, PointerRecord &Record) {
+  error(IO.mapInteger(Record.ReferentType));
+  error(IO.mapInteger(Record.Attrs));
+
+  if (Record.isPointerToMember()) {
+    if (!IO.isWriting())
+      Record.MemberInfo.emplace();
+
+    MemberPointerInfo &M = *Record.MemberInfo;
+    error(IO.mapInteger(M.ContainingType));
+    error(IO.mapEnum(M.Representation));
+  }
+
+  return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR, ArrayRecord &Record) {
+  error(IO.mapInteger(Record.ElementType));
+  error(IO.mapInteger(Record.IndexType));
+  error(IO.mapEncodedInteger(Record.Size));
+  error(IO.mapStringZ(Record.Name));
+
+  return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR, ClassRecord &Record) {
+  assert((CVR.Type == TypeLeafKind::LF_STRUCTURE) ||
+         (CVR.Type == TypeLeafKind::LF_CLASS) ||
+         (CVR.Type == TypeLeafKind::LF_INTERFACE));
+
+  error(IO.mapInteger(Record.MemberCount));
+  error(IO.mapEnum(Record.Options));
+  error(IO.mapInteger(Record.FieldList));
+  error(IO.mapInteger(Record.DerivationList));
+  error(IO.mapInteger(Record.VTableShape));
+  error(IO.mapEncodedInteger(Record.Size));
+  error(mapNameAndUniqueName(IO, Record.Name, Record.UniqueName,
+                             Record.hasUniqueName()));
+
+  return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR, UnionRecord &Record) {
+  error(IO.mapInteger(Record.MemberCount));
+  error(IO.mapEnum(Record.Options));
+  error(IO.mapInteger(Record.FieldList));
+  error(IO.mapEncodedInteger(Record.Size));
+  error(mapNameAndUniqueName(IO, Record.Name, Record.UniqueName,
+                             Record.hasUniqueName()));
+
+  return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR, EnumRecord &Record) {
+  error(IO.mapInteger(Record.MemberCount));
+  error(IO.mapEnum(Record.Options));
+  error(IO.mapInteger(Record.UnderlyingType));
+  error(IO.mapInteger(Record.FieldList));
+  error(mapNameAndUniqueName(IO, Record.Name, Record.UniqueName,
+                             Record.hasUniqueName()));
+
+  return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR, BitFieldRecord &Record) {
+  error(IO.mapInteger(Record.Type));
+  error(IO.mapInteger(Record.BitSize));
+  error(IO.mapInteger(Record.BitOffset));
+
+  return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
+                                          VFTableShapeRecord &Record) {
+  uint16_t Size;
+  if (IO.isWriting()) {
+    ArrayRef<VFTableSlotKind> Slots = Record.getSlots();
+    Size = Slots.size();
+    error(IO.mapInteger(Size));
+
+    for (size_t SlotIndex = 0; SlotIndex < Slots.size(); SlotIndex += 2) {
+      uint8_t Byte = static_cast<uint8_t>(Slots[SlotIndex]) << 4;
+      if ((SlotIndex + 1) < Slots.size()) {
+        Byte |= static_cast<uint8_t>(Slots[SlotIndex + 1]);
+      }
+      error(IO.mapInteger(Byte));
+    }
+  } else {
+    error(IO.mapInteger(Size));
+    for (uint16_t I = 0; I < Size; I += 2) {
+      uint8_t Byte;
+      error(IO.mapInteger(Byte));
+      Record.Slots.push_back(static_cast<VFTableSlotKind>(Byte & 0xF));
+      if ((I + 1) < Size)
+        Record.Slots.push_back(static_cast<VFTableSlotKind>(Byte >> 4));
+    }
+  }
+
+  return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR, VFTableRecord &Record) {
+  error(IO.mapInteger(Record.CompleteClass));
+  error(IO.mapInteger(Record.OverriddenVFTable));
+  error(IO.mapInteger(Record.VFPtrOffset));
+  uint32_t NamesLen = 0;
+  if (IO.isWriting()) {
+    for (auto Name : Record.MethodNames)
+      NamesLen += Name.size() + 1;
+  }
+  error(IO.mapInteger(NamesLen));
+  error(IO.mapVectorTail(Record.MethodNames, MapStringZ()));
+
+  return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR, StringIdRecord &Record) {
+  error(IO.mapInteger(Record.Id));
+  error(IO.mapStringZ(Record.String));
+
+  return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
+                                          UdtSourceLineRecord &Record) {
+  error(IO.mapInteger(Record.UDT));
+  error(IO.mapInteger(Record.SourceFile));
+  error(IO.mapInteger(Record.LineNumber));
+
+  return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
+                                          UdtModSourceLineRecord &Record) {
+  error(IO.mapInteger(Record.UDT));
+  error(IO.mapInteger(Record.SourceFile));
+  error(IO.mapInteger(Record.LineNumber));
+  error(IO.mapInteger(Record.Module));
+
+  return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR, FuncIdRecord &Record) {
+  error(IO.mapInteger(Record.ParentScope));
+  error(IO.mapInteger(Record.FunctionType));
+  error(IO.mapStringZ(Record.Name));
+
+  return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
+                                          MemberFuncIdRecord &Record) {
+  error(IO.mapInteger(Record.ClassType));
+  error(IO.mapInteger(Record.FunctionType));
+  error(IO.mapStringZ(Record.Name));
+
+  return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
+                                          BuildInfoRecord &Record) {
+  error(IO.mapVectorN<uint16_t>(Record.ArgIndices, MapInteger()));
+
+  return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
+                                          MethodOverloadListRecord &Record) {
+  // TODO: Split the list into multiple records if it's longer than 64KB, using
+  // a subrecord of TypeRecordKind::Index to chain the records together.
+  error(IO.mapVectorTail(Record.Methods, MapOneMethodRecord(true)));
+
+  return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
+                                          FieldListRecord &Record) {
+  error(IO.mapByteVectorTail(Record.Data));
+
+  return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
+                                          TypeServer2Record &Record) {
+  return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
+                                          BaseClassRecord &Record) {
+  error(IO.mapInteger(Record.Attrs.Attrs));
+  error(IO.mapInteger(Record.Type));
+  error(IO.mapEncodedInteger(Record.Offset));
+
+  return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
+                                          EnumeratorRecord &Record) {
+  error(IO.mapInteger(Record.Attrs.Attrs));
+
+  // FIXME: Handle full APInt such as __int128.
+  error(IO.mapEncodedInteger(Record.Value));
+  error(IO.mapStringZ(Record.Name));
+
+  return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
+                                          DataMemberRecord &Record) {
+  error(IO.mapInteger(Record.Attrs.Attrs));
+  error(IO.mapInteger(Record.Type));
+  error(IO.mapEncodedInteger(Record.FieldOffset));
+  error(IO.mapStringZ(Record.Name));
+
+  return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
+                                          OverloadedMethodRecord &Record) {
+  error(IO.mapInteger(Record.NumOverloads));
+  error(IO.mapInteger(Record.MethodList));
+  error(IO.mapStringZ(Record.Name));
+
+  return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
+                                          OneMethodRecord &Record) {
+  MapOneMethodRecord Mapper(false);
+  return Mapper(IO, Record);
+}
+
+Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
+                                          NestedTypeRecord &Record) {
+  uint16_t Padding = 0;
+  error(IO.mapInteger(Padding));
+  error(IO.mapInteger(Record.Type));
+  error(IO.mapStringZ(Record.Name));
+
+  return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
+                                          StaticDataMemberRecord &Record) {
+
+  error(IO.mapInteger(Record.Attrs.Attrs));
+  error(IO.mapInteger(Record.Type));
+  error(IO.mapStringZ(Record.Name));
+
+  return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
+                                          VirtualBaseClassRecord &Record) {
+
+  error(IO.mapInteger(Record.Attrs.Attrs));
+  error(IO.mapInteger(Record.BaseType));
+  error(IO.mapInteger(Record.VBPtrType));
+  error(IO.mapEncodedInteger(Record.VBPtrOffset));
+  error(IO.mapEncodedInteger(Record.VTableIndex));
+
+  return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
+                                          VFPtrRecord &Record) {
+  uint16_t Padding = 0;
+  error(IO.mapInteger(Padding));
+  error(IO.mapInteger(Record.Type));
+
+  return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
+                                          ListContinuationRecord &Record) {
+  uint16_t Padding = 0;
+  error(IO.mapInteger(Padding));
+  error(IO.mapInteger(Record.ContinuationIndex));
+
+  return Error::success();
+}
diff --git a/llvm/lib/DebugInfo/CodeView/TypeStreamMerger.cpp b/llvm/lib/DebugInfo/CodeView/TypeStreamMerger.cpp
index acd7f74..551a98a 100644
--- a/llvm/lib/DebugInfo/CodeView/TypeStreamMerger.cpp
+++ b/llvm/lib/DebugInfo/CodeView/TypeStreamMerger.cpp
@@ -84,14 +84,7 @@
   }
 
   Error visitKnownRecordImpl(FieldListRecord &Record) {
-    // Don't do anything, this will get written in the call to visitTypeEnd().
-    TypeVisitorCallbackPipeline Pipeline;
-    TypeDeserializer Deserializer;
-
-    Pipeline.addCallbackToPipeline(Deserializer);
-    Pipeline.addCallbackToPipeline(*this);
-
-    CVTypeVisitor Visitor(Pipeline);
+    CVTypeVisitor Visitor(*this);
 
     if (auto EC = Visitor.visitFieldListMemberStream(Record.Data))
       return EC;
diff --git a/llvm/lib/DebugInfo/CodeView/TypeTableBuilder.cpp b/llvm/lib/DebugInfo/CodeView/TypeTableBuilder.cpp
index fcf2796..1bd0b3f 100644
--- a/llvm/lib/DebugInfo/CodeView/TypeTableBuilder.cpp
+++ b/llvm/lib/DebugInfo/CodeView/TypeTableBuilder.cpp
@@ -72,13 +72,7 @@
   TypeRecordBuilder Builder(Record.getKind());
 
   Builder.writeTypeIndex(Record.getReferentType());
-  uint32_t flags = static_cast<uint32_t>(Record.getOptions()) |
-                   (Record.getSize() << PointerRecord::PointerSizeShift) |
-                   (static_cast<uint32_t>(Record.getMode())
-                    << PointerRecord::PointerModeShift) |
-                   (static_cast<uint32_t>(Record.getPointerKind())
-                    << PointerRecord::PointerKindShift);
-  Builder.writeUInt32(flags);
+  Builder.writeUInt32(Record.Attrs);
 
   if (Record.isPointerToMember()) {
     const MemberPointerInfo &M = Record.getMemberInfo();
diff --git a/llvm/lib/DebugInfo/MSF/StreamWriter.cpp b/llvm/lib/DebugInfo/MSF/StreamWriter.cpp
index a91cffe..cdae7c5 100644
--- a/llvm/lib/DebugInfo/MSF/StreamWriter.cpp
+++ b/llvm/lib/DebugInfo/MSF/StreamWriter.cpp
@@ -25,6 +25,8 @@
   return Error::success();
 }
 
+Error StreamWriter::writeInteger(uint8_t Int) { return writeObject(Int); }
+
 Error StreamWriter::writeInteger(uint16_t Int) {
   return writeObject(support::ulittle16_t(Int));
 }
@@ -33,6 +35,24 @@
   return writeObject(support::ulittle32_t(Int));
 }
 
+Error StreamWriter::writeInteger(uint64_t Int) {
+  return writeObject(support::ulittle64_t(Int));
+}
+
+Error StreamWriter::writeInteger(int8_t Int) { return writeObject(Int); }
+
+Error StreamWriter::writeInteger(int16_t Int) {
+  return writeObject(support::little16_t(Int));
+}
+
+Error StreamWriter::writeInteger(int32_t Int) {
+  return writeObject(support::little32_t(Int));
+}
+
+Error StreamWriter::writeInteger(int64_t Int) {
+  return writeObject(support::little64_t(Int));
+}
+
 Error StreamWriter::writeZeroString(StringRef Str) {
   if (auto EC = writeFixedString(Str))
     return EC;