diff --git a/compiler-rt/include/profile/MemProfData.inc b/compiler-rt/include/profile/MemProfData.inc
--- a/compiler-rt/include/profile/MemProfData.inc
+++ b/compiler-rt/include/profile/MemProfData.inc
@@ -80,71 +80,73 @@
   }
 });
 
+
+
+// Packed struct definition for MSVC. We can't use the PACKED macro defined in
+// MemProfData.inc since it would mean we are embedding a directive (the
+// #include for MIBEntryDef) into the macros which is undefined behaviour.
+#ifdef _MSC_VER
+__pragma(pack(push,1))
+#endif
+
 // A struct representing the heap allocation characteristics of a particular
 // runtime context. This struct is shared between the compiler-rt runtime and
 // the raw profile reader. The indexed format uses a separate, self-describing
 // backwards compatible format.
-PACKED(struct MemInfoBlock {
-  uint32_t alloc_count;
-  uint64_t total_access_count, min_access_count, max_access_count;
-  uint64_t total_size;
-  uint32_t min_size, max_size;
-  uint32_t alloc_timestamp, dealloc_timestamp;
-  uint64_t total_lifetime;
-  uint32_t min_lifetime, max_lifetime;
-  uint32_t alloc_cpu_id, dealloc_cpu_id;
-  uint32_t num_migrated_cpu;
-
-  // Only compared to prior deallocated object currently.
-  uint32_t num_lifetime_overlaps;
-  uint32_t num_same_alloc_cpu;
-  uint32_t num_same_dealloc_cpu;
-
-  uint64_t data_type_id; // TODO: hash of type name
-
-  MemInfoBlock() : alloc_count(0) {}
-
-  MemInfoBlock(uint32_t size, uint64_t access_count, uint32_t alloc_timestamp,
-               uint32_t dealloc_timestamp, uint32_t alloc_cpu, uint32_t dealloc_cpu)
-      : alloc_count(1), total_access_count(access_count),
-        min_access_count(access_count), max_access_count(access_count),
-        total_size(size), min_size(size), max_size(size),
-        alloc_timestamp(alloc_timestamp), dealloc_timestamp(dealloc_timestamp),
-        total_lifetime(dealloc_timestamp - alloc_timestamp),
-        min_lifetime(total_lifetime), max_lifetime(total_lifetime),
-        alloc_cpu_id(alloc_cpu), dealloc_cpu_id(dealloc_cpu),
-        num_lifetime_overlaps(0), num_same_alloc_cpu(0),
-        num_same_dealloc_cpu(0) {
-    num_migrated_cpu = alloc_cpu_id != dealloc_cpu_id;
-  }
-
-  void Merge(const MemInfoBlock &newMIB) {
-    alloc_count += newMIB.alloc_count;
-
-    total_access_count += newMIB.total_access_count;
-    min_access_count = newMIB.min_access_count < min_access_count ? newMIB.min_access_count : min_access_count;
-    max_access_count = newMIB.max_access_count < max_access_count ? newMIB.max_access_count : max_access_count;
+struct MemInfoBlock{
+
+#define MIBEntryDef(NameTag, Name, TypeTag, Type) Type Name;
+#include "MemProfMIB.inc"
+#undef MIBEntryDef
+
+MemInfoBlock() : AllocCount(0) {}
+
+MemInfoBlock(uint32_t size, uint64_t access_count, uint32_t alloc_timestamp,
+             uint32_t dealloc_timestamp, uint32_t alloc_cpu, uint32_t dealloc_cpu)
+    : AllocCount(1), TotalAccessCount(access_count),
+      MinAccessCount(access_count), MaxAccessCount(access_count),
+      TotalSize(size), MinSize(size), MaxSize(size),
+      AllocTimestamp(alloc_timestamp), DeallocTimestamp(dealloc_timestamp),
+      TotalLifetime(dealloc_timestamp - alloc_timestamp),
+      MinLifetime(TotalLifetime), MaxLifetime(TotalLifetime),
+      AllocCpuId(alloc_cpu), DeallocCpuId(dealloc_cpu),
+      NumLifetimeOverlaps(0), NumSameAllocCpu(0),
+      NumSameDeallocCpu(0) {
+  NumMigratedCpu = AllocCpuId != DeallocCpuId;
+}
+
+void Merge(const MemInfoBlock &newMIB) {
+  AllocCount += newMIB.AllocCount;
+
+  TotalAccessCount += newMIB.TotalAccessCount;
+  MinAccessCount = newMIB.MinAccessCount < MinAccessCount ? newMIB.MinAccessCount : MinAccessCount;
+  MaxAccessCount = newMIB.MaxAccessCount < MaxAccessCount ? newMIB.MaxAccessCount : MaxAccessCount;
+
+  TotalSize += newMIB.TotalSize;
+  MinSize = newMIB.MinSize < MinSize ? newMIB.MinSize : MinSize;
+  MaxSize = newMIB.MaxSize < MaxSize ? newMIB.MaxSize : MaxSize;
+
+  TotalLifetime += newMIB.TotalLifetime;
+  MinLifetime = newMIB.MinLifetime < MinLifetime ? newMIB.MinLifetime : MinLifetime;
+  MaxLifetime = newMIB.MaxLifetime > MaxLifetime ? newMIB.MaxLifetime : MaxLifetime;
+
+  // We know newMIB was deallocated later, so just need to check if it was
+  // allocated before last one deallocated.
+  NumLifetimeOverlaps += newMIB.AllocTimestamp < DeallocTimestamp;
+  AllocTimestamp = newMIB.AllocTimestamp;
+  DeallocTimestamp = newMIB.DeallocTimestamp;
+
+  NumSameAllocCpu += AllocCpuId == newMIB.AllocCpuId;
+  NumSameDeallocCpu += DeallocCpuId == newMIB.DeallocCpuId;
+  AllocCpuId = newMIB.AllocCpuId;
+  DeallocCpuId = newMIB.DeallocCpuId;
+}
 
-    total_size += newMIB.total_size;
-    min_size = newMIB.min_size < min_size ? newMIB.min_size : min_size;
-    max_size = newMIB.max_size < max_size ? newMIB.max_size : max_size;
-
-    total_lifetime += newMIB.total_lifetime;
-    min_lifetime = newMIB.min_lifetime < min_lifetime ? newMIB.min_lifetime : min_lifetime;
-    max_lifetime = newMIB.max_lifetime > max_lifetime ? newMIB.max_lifetime : max_lifetime;
-
-    // We know newMIB was deallocated later, so just need to check if it was
-    // allocated before last one deallocated.
-    num_lifetime_overlaps += newMIB.alloc_timestamp < dealloc_timestamp;
-    alloc_timestamp = newMIB.alloc_timestamp;
-    dealloc_timestamp = newMIB.dealloc_timestamp;
-
-    num_same_alloc_cpu += alloc_cpu_id == newMIB.alloc_cpu_id;
-    num_same_dealloc_cpu += dealloc_cpu_id == newMIB.dealloc_cpu_id;
-    alloc_cpu_id = newMIB.alloc_cpu_id;
-    dealloc_cpu_id = newMIB.dealloc_cpu_id;
-  }
-});
+#ifdef _MSC_VER
+} __pragma(pack(pop));
+#else
+} __attribute__((__packed__));
+#endif
 
 } // namespace memprof
 } // namespace llvm
diff --git a/compiler-rt/include/profile/MemProfMIB.inc b/compiler-rt/include/profile/MemProfMIB.inc
new file mode 100644
--- /dev/null
+++ b/compiler-rt/include/profile/MemProfMIB.inc
@@ -0,0 +1,45 @@
+#ifndef MIBEntryDef
+#define MIBEntryDef(NameTag, Name, TypeTag, Type)
+#endif
+
+MIBEntryDef(AllocCount = 1, AllocCount,
+            MIBMeta::MIBFieldType::UINT32, uint32_t)
+MIBEntryDef(TotalAccessCount = 2, TotalAccessCount,
+            MIBMeta::MIBFieldType::UINT64, uint64_t)
+MIBEntryDef(MinAccessCount = 3, MinAccessCount,
+            MIBMeta::MIBFieldType::UINT64, uint64_t)
+MIBEntryDef(MaxAccessCount = 4, MaxAccessCount,
+            MIBMeta::MIBFieldType::UINT64, uint64_t)
+MIBEntryDef(TotalSize = 5, TotalSize,
+            MIBMeta::MIBFieldType::UINT64, uint64_t)
+MIBEntryDef(MinSize = 6, MinSize,
+            MIBMeta::MIBFieldType::UINT32, uint32_t)
+MIBEntryDef(MaxSize = 7, MaxSize,
+            MIBMeta::MIBFieldType::UINT32, uint32_t)
+MIBEntryDef(AllocTimestamp = 8, AllocTimestamp,
+            MIBMeta::MIBFieldType::UINT32, uint32_t)
+MIBEntryDef(DeallocTimestamp = 9, DeallocTimestamp,
+            MIBMeta::MIBFieldType::UINT32, uint32_t)
+MIBEntryDef(TotalLifetime = 10, TotalLifetime,
+            MIBMeta::MIBFieldType::UINT64, uint64_t)
+MIBEntryDef(MinLifetime = 11, MinLifetime,
+            MIBMeta::MIBFieldType::UINT32, uint32_t)
+MIBEntryDef(MaxLifetime = 12, MaxLifetime,
+            MIBMeta::MIBFieldType::UINT32, uint32_t)
+MIBEntryDef(AllocCpuId = 13, AllocCpuId,
+            MIBMeta::MIBFieldType::UINT32, uint32_t)
+MIBEntryDef(DeallocCpuId = 14, DeallocCpuId,
+            MIBMeta::MIBFieldType::UINT32, uint32_t)
+MIBEntryDef(NumMigratedCpu = 15, NumMigratedCpu,
+            MIBMeta::MIBFieldType::UINT32, uint32_t)
+MIBEntryDef(NumLifetimeOverlaps = 16, NumLifetimeOverlaps,
+            MIBMeta::MIBFieldType::UINT32, uint32_t)
+MIBEntryDef(NumSameAllocCpu = 17, NumSameAllocCpu,
+            MIBMeta::MIBFieldType::UINT32, uint32_t)
+MIBEntryDef(NumSameDeallocCpu = 18, NumSameDeallocCpu,
+            MIBMeta::MIBFieldType::UINT32, uint32_t)
+MIBEntryDef(DataTypeId = 19, DataTypeId,
+            MIBMeta::MIBFieldType::UINT64, uint64_t)
+
+
+
diff --git a/compiler-rt/lib/memprof/memprof_allocator.cpp b/compiler-rt/lib/memprof/memprof_allocator.cpp
--- a/compiler-rt/lib/memprof/memprof_allocator.cpp
+++ b/compiler-rt/lib/memprof/memprof_allocator.cpp
@@ -43,32 +43,32 @@
   u64 p;
 
   if (print_terse) {
-    p = M.total_size * 100 / M.alloc_count;
-    Printf("MIB:%llu/%u/%llu.%02llu/%u/%u/", id, M.alloc_count, p / 100,
-           p % 100, M.min_size, M.max_size);
-    p = M.total_access_count * 100 / M.alloc_count;
-    Printf("%llu.%02llu/%llu/%llu/", p / 100, p % 100, M.min_access_count,
-           M.max_access_count);
-    p = M.total_lifetime * 100 / M.alloc_count;
-    Printf("%llu.%02llu/%u/%u/", p / 100, p % 100, M.min_lifetime,
-           M.max_lifetime);
-    Printf("%u/%u/%u/%u\n", M.num_migrated_cpu, M.num_lifetime_overlaps,
-           M.num_same_alloc_cpu, M.num_same_dealloc_cpu);
+    p = M.TotalSize * 100 / M.AllocCount;
+    Printf("MIB:%llu/%u/%llu.%02llu/%u/%u/", id, M.AllocCount, p / 100, p % 100,
+           M.MinSize, M.MaxSize);
+    p = M.TotalAccessCount * 100 / M.AllocCount;
+    Printf("%llu.%02llu/%llu/%llu/", p / 100, p % 100, M.MinAccessCount,
+           M.MaxAccessCount);
+    p = M.TotalLifetime * 100 / M.AllocCount;
+    Printf("%llu.%02llu/%u/%u/", p / 100, p % 100, M.MinLifetime,
+           M.MaxLifetime);
+    Printf("%u/%u/%u/%u\n", M.NumMigratedCpu, M.NumLifetimeOverlaps,
+           M.NumSameAllocCpu, M.NumSameDeallocCpu);
   } else {
-    p = M.total_size * 100 / M.alloc_count;
+    p = M.TotalSize * 100 / M.AllocCount;
     Printf("Memory allocation stack id = %llu\n", id);
     Printf("\talloc_count %u, size (ave/min/max) %llu.%02llu / %u / %u\n",
-           M.alloc_count, p / 100, p % 100, M.min_size, M.max_size);
-    p = M.total_access_count * 100 / M.alloc_count;
+           M.AllocCount, p / 100, p % 100, M.MinSize, M.MaxSize);
+    p = M.TotalAccessCount * 100 / M.AllocCount;
     Printf("\taccess_count (ave/min/max): %llu.%02llu / %llu / %llu\n", p / 100,
-           p % 100, M.min_access_count, M.max_access_count);
-    p = M.total_lifetime * 100 / M.alloc_count;
+           p % 100, M.MinAccessCount, M.MaxAccessCount);
+    p = M.TotalLifetime * 100 / M.AllocCount;
     Printf("\tlifetime (ave/min/max): %llu.%02llu / %u / %u\n", p / 100,
-           p % 100, M.min_lifetime, M.max_lifetime);
+           p % 100, M.MinLifetime, M.MaxLifetime);
     Printf("\tnum migrated: %u, num lifetime overlaps: %u, num same alloc "
            "cpu: %u, num same dealloc_cpu: %u\n",
-           M.num_migrated_cpu, M.num_lifetime_overlaps, M.num_same_alloc_cpu,
-           M.num_same_dealloc_cpu);
+           M.NumMigratedCpu, M.NumLifetimeOverlaps, M.NumSameAllocCpu,
+           M.NumSameDeallocCpu);
   }
 }
 } // namespace
diff --git a/compiler-rt/lib/memprof/tests/rawprofile.cpp b/compiler-rt/lib/memprof/tests/rawprofile.cpp
--- a/compiler-rt/lib/memprof/tests/rawprofile.cpp
+++ b/compiler-rt/lib/memprof/tests/rawprofile.cpp
@@ -82,8 +82,8 @@
   // Since we want to override the constructor set vals to make it easier to
   // test.
   memset(&FakeMIB, 0, sizeof(MemInfoBlock));
-  FakeMIB.alloc_count = 0x1;
-  FakeMIB.total_access_count = 0x2;
+  FakeMIB.AllocCount = 0x1;
+  FakeMIB.TotalAccessCount = 0x2;
 
   uint64_t FakeIds[2];
   FakeIds[0] = PopulateFakeMap(FakeMIB, /*StackPCBegin=*/2, FakeMap);
diff --git a/llvm/include/llvm/ProfileData/MemProf.h b/llvm/include/llvm/ProfileData/MemProf.h
--- a/llvm/include/llvm/ProfileData/MemProf.h
+++ b/llvm/include/llvm/ProfileData/MemProf.h
@@ -5,12 +5,77 @@
 #include <string>
 #include <vector>
 
+#include "llvm/ADT/SmallVector.h"
 #include "llvm/ProfileData/MemProfData.inc"
 #include "llvm/Support/raw_ostream.h"
 
 namespace llvm {
 namespace memprof {
 
+enum class Meta {
+  Start = 0,
+#define MIBEntryDef(NameTag, Name, TypeTag, Type) NameTag,
+#include "llvm/ProfileData/MemProfMIB.inc"
+#undef MIBEntryDef
+  Size
+};
+
+struct PortableMemInfoBlock {
+  PortableMemInfoBlock() {}
+  PortableMemInfoBlock(const MemInfoBlock &Block) : Info(Block) {}
+  PortableMemInfoBlock(const llvm::SmallVectorImpl<Meta> &Schema, char *Ptr) {
+    for (const Meta Id : Schema) {
+      switch (Id) {
+#define MIBEntryDef(NameTag, Name, TypeTag, Type)                              \
+  case Meta::Name: {                                                           \
+    Info.Name = *reinterpret_cast<Type *>(Ptr);                                \
+    Ptr += sizeof(Type);                                                       \
+  } break;
+#include "llvm/ProfileData/MemProfMIB.inc"
+#undef MIBEntryDef
+      default:
+        llvm_unreachable("Unknown meta type id, is the profile collected from "
+                         "a newer version of the runtime?");
+      }
+    }
+  }
+
+  void serialize(const llvm::SmallVectorImpl<Meta> &Schema, char *Ptr) {
+    for (const Meta Id : Schema) {
+      switch (Id) {
+#define MIBEntryDef(NameTag, Name, TypeTag, Type)                              \
+  case Meta::Name: {                                                           \
+    *(Type *)Ptr = Info.Name;                                                  \
+    Ptr += sizeof(Type);                                                       \
+  } break;
+#include "llvm/ProfileData/MemProfMIB.inc"
+#undef MIBEntryDef
+      default:
+        llvm_unreachable("Unknown meta type id, invalid input?");
+      }
+    }
+  }
+
+  void printYAML(raw_ostream &OS) const {
+    OS << "    MemInfoBlock:\n";
+#define MIBEntryDef(NameTag, Name, TypeTag, Type)                              \
+  OS << "      " << #Name << ": " << Info.Name << "\n";
+#include "llvm/ProfileData/MemProfMIB.inc"
+#undef MIBEntryDef
+  }
+
+  // Define getters for each type which can be called by analyses.
+#define MIBEntryDef(NameTag, Name, TypeTag, Type)                              \
+  Type get##Name() { return Info.Name; }
+#include "llvm/ProfileData/MemProfMIB.inc"
+#undef MIBEntryDef
+
+  void clear() { Info = MemInfoBlock(); }
+
+private:
+  MemInfoBlock Info;
+};
+
 struct MemProfRecord {
   struct Frame {
     std::string Function;
@@ -24,14 +89,11 @@
   };
 
   std::vector<Frame> CallStack;
-  // TODO: Replace this with the entry format described in the RFC so
-  // that the InstrProfRecord reader and writer do not have to be concerned
-  // about backwards compat.
-  MemInfoBlock Info;
+  PortableMemInfoBlock Info;
 
   void clear() {
     CallStack.clear();
-    Info = MemInfoBlock();
+    Info.clear();
   }
 
   // Prints out the contents of the memprof record in YAML.
@@ -45,29 +107,7 @@
          << "      Inline: " << Frame.IsInlineFrame << "\n";
     }
 
-    OS << "    MemInfoBlock:\n";
-
-    // TODO: Replace this once the format is updated to be version agnostic.
-#define PRINT(Field) OS << "      " #Field ": " << Info.Field << "\n"
-    PRINT(alloc_count);
-    PRINT(total_access_count);
-    PRINT(min_access_count);
-    PRINT(max_access_count);
-    PRINT(total_size);
-    PRINT(min_size);
-    PRINT(max_size);
-    PRINT(alloc_timestamp);
-    PRINT(dealloc_timestamp);
-    PRINT(total_lifetime);
-    PRINT(min_lifetime);
-    PRINT(max_lifetime);
-    PRINT(alloc_cpu_id);
-    PRINT(dealloc_cpu_id);
-    PRINT(num_migrated_cpu);
-    PRINT(num_lifetime_overlaps);
-    PRINT(num_same_alloc_cpu);
-    PRINT(num_same_dealloc_cpu);
-#undef PRINT
+    Info.printYAML(OS);
   }
 };
 
diff --git a/llvm/include/llvm/ProfileData/MemProfData.inc b/llvm/include/llvm/ProfileData/MemProfData.inc
--- a/llvm/include/llvm/ProfileData/MemProfData.inc
+++ b/llvm/include/llvm/ProfileData/MemProfData.inc
@@ -80,71 +80,82 @@
   }
 });
 
+
+
+// Packed struct definition for MSVC. We can't use the PACKED macro defined in
+// MemProfData.inc since it would mean we are embedding a directive (the
+// #include for MIBEntryDef) into the macros which is undefined behaviour.
+#ifdef _MSC_VER
+__pragma(pack(push,1))
+#endif
+
 // A struct representing the heap allocation characteristics of a particular
 // runtime context. This struct is shared between the compiler-rt runtime and
 // the raw profile reader. The indexed format uses a separate, self-describing
 // backwards compatible format.
-PACKED(struct MemInfoBlock {
-  uint32_t alloc_count;
-  uint64_t total_access_count, min_access_count, max_access_count;
-  uint64_t total_size;
-  uint32_t min_size, max_size;
-  uint32_t alloc_timestamp, dealloc_timestamp;
-  uint64_t total_lifetime;
-  uint32_t min_lifetime, max_lifetime;
-  uint32_t alloc_cpu_id, dealloc_cpu_id;
-  uint32_t num_migrated_cpu;
-
-  // Only compared to prior deallocated object currently.
-  uint32_t num_lifetime_overlaps;
-  uint32_t num_same_alloc_cpu;
-  uint32_t num_same_dealloc_cpu;
-
-  uint64_t data_type_id; // TODO: hash of type name
-
-  MemInfoBlock() : alloc_count(0) {}
-
-  MemInfoBlock(uint32_t size, uint64_t access_count, uint32_t alloc_timestamp,
-               uint32_t dealloc_timestamp, uint32_t alloc_cpu, uint32_t dealloc_cpu)
-      : alloc_count(1), total_access_count(access_count),
-        min_access_count(access_count), max_access_count(access_count),
-        total_size(size), min_size(size), max_size(size),
-        alloc_timestamp(alloc_timestamp), dealloc_timestamp(dealloc_timestamp),
-        total_lifetime(dealloc_timestamp - alloc_timestamp),
-        min_lifetime(total_lifetime), max_lifetime(total_lifetime),
-        alloc_cpu_id(alloc_cpu), dealloc_cpu_id(dealloc_cpu),
-        num_lifetime_overlaps(0), num_same_alloc_cpu(0),
-        num_same_dealloc_cpu(0) {
-    num_migrated_cpu = alloc_cpu_id != dealloc_cpu_id;
-  }
-
-  void Merge(const MemInfoBlock &newMIB) {
-    alloc_count += newMIB.alloc_count;
-
-    total_access_count += newMIB.total_access_count;
-    min_access_count = newMIB.min_access_count < min_access_count ? newMIB.min_access_count : min_access_count;
-    max_access_count = newMIB.max_access_count < max_access_count ? newMIB.max_access_count : max_access_count;
+struct MemInfoBlock{
+
+#define MIBEntryDef(NameTag, Name, TypeTag, Type) Type Name;
+#include "MemProfMIB.inc"
+#undef MIBEntryDef
+
+bool operator==(const MemInfoBlock& Other) const {
+  bool IsEqual = true;
+#define MIBEntryDef(NameTag, Name, TypeTag, Type) \
+  IsEqual = (IsEqual && Name == Other.Name);
+#include "MemProfMIB.inc"
+#undef MIBEntryDef
+  return IsEqual;
+}
+
+MemInfoBlock() : AllocCount(0) {}
+
+MemInfoBlock(uint32_t size, uint64_t access_count, uint32_t alloc_timestamp,
+             uint32_t dealloc_timestamp, uint32_t alloc_cpu, uint32_t dealloc_cpu)
+    : AllocCount(1), TotalAccessCount(access_count),
+      MinAccessCount(access_count), MaxAccessCount(access_count),
+      TotalSize(size), MinSize(size), MaxSize(size),
+      AllocTimestamp(alloc_timestamp), DeallocTimestamp(dealloc_timestamp),
+      TotalLifetime(dealloc_timestamp - alloc_timestamp),
+      MinLifetime(TotalLifetime), MaxLifetime(TotalLifetime),
+      AllocCpuId(alloc_cpu), DeallocCpuId(dealloc_cpu),
+      NumLifetimeOverlaps(0), NumSameAllocCpu(0),
+      NumSameDeallocCpu(0) {
+  NumMigratedCpu = AllocCpuId != DeallocCpuId;
+}
+
+void Merge(const MemInfoBlock &newMIB) {
+  AllocCount += newMIB.AllocCount;
+
+  TotalAccessCount += newMIB.TotalAccessCount;
+  MinAccessCount = newMIB.MinAccessCount < MinAccessCount ? newMIB.MinAccessCount : MinAccessCount;
+  MaxAccessCount = newMIB.MaxAccessCount < MaxAccessCount ? newMIB.MaxAccessCount : MaxAccessCount;
+
+  TotalSize += newMIB.TotalSize;
+  MinSize = newMIB.MinSize < MinSize ? newMIB.MinSize : MinSize;
+  MaxSize = newMIB.MaxSize < MaxSize ? newMIB.MaxSize : MaxSize;
+
+  TotalLifetime += newMIB.TotalLifetime;
+  MinLifetime = newMIB.MinLifetime < MinLifetime ? newMIB.MinLifetime : MinLifetime;
+  MaxLifetime = newMIB.MaxLifetime > MaxLifetime ? newMIB.MaxLifetime : MaxLifetime;
+
+  // We know newMIB was deallocated later, so just need to check if it was
+  // allocated before last one deallocated.
+  NumLifetimeOverlaps += newMIB.AllocTimestamp < DeallocTimestamp;
+  AllocTimestamp = newMIB.AllocTimestamp;
+  DeallocTimestamp = newMIB.DeallocTimestamp;
+
+  NumSameAllocCpu += AllocCpuId == newMIB.AllocCpuId;
+  NumSameDeallocCpu += DeallocCpuId == newMIB.DeallocCpuId;
+  AllocCpuId = newMIB.AllocCpuId;
+  DeallocCpuId = newMIB.DeallocCpuId;
+}
 
-    total_size += newMIB.total_size;
-    min_size = newMIB.min_size < min_size ? newMIB.min_size : min_size;
-    max_size = newMIB.max_size < max_size ? newMIB.max_size : max_size;
-
-    total_lifetime += newMIB.total_lifetime;
-    min_lifetime = newMIB.min_lifetime < min_lifetime ? newMIB.min_lifetime : min_lifetime;
-    max_lifetime = newMIB.max_lifetime > max_lifetime ? newMIB.max_lifetime : max_lifetime;
-
-    // We know newMIB was deallocated later, so just need to check if it was
-    // allocated before last one deallocated.
-    num_lifetime_overlaps += newMIB.alloc_timestamp < dealloc_timestamp;
-    alloc_timestamp = newMIB.alloc_timestamp;
-    dealloc_timestamp = newMIB.dealloc_timestamp;
-
-    num_same_alloc_cpu += alloc_cpu_id == newMIB.alloc_cpu_id;
-    num_same_dealloc_cpu += dealloc_cpu_id == newMIB.dealloc_cpu_id;
-    alloc_cpu_id = newMIB.alloc_cpu_id;
-    dealloc_cpu_id = newMIB.dealloc_cpu_id;
-  }
-});
+#ifdef _MSC_VER
+} __pragma(pack(pop));
+#else
+} __attribute__((__packed__));
+#endif
 
 } // namespace memprof
 } // namespace llvm
diff --git a/llvm/include/llvm/ProfileData/MemProfMIB.inc b/llvm/include/llvm/ProfileData/MemProfMIB.inc
new file mode 100644
--- /dev/null
+++ b/llvm/include/llvm/ProfileData/MemProfMIB.inc
@@ -0,0 +1,71 @@
+/*===-- MemProfMIB.inc - MemProf profiling primitives -*- C++ -*-=== *\
+|*
+|* Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+|* See https://llvm.org/LICENSE.txt for license information.
+|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+|*
+\*===----------------------------------------------------------------------===*/
+/*
+ * This file has two identical copies. The primary copy lives in LLVM and
+ * the other one sits in compiler-rt/include/profile directory. To make changes
+ * in this file, first modify the primary copy and copy it over to compiler-rt.
+ * Testing of any change in this file can start only after the two copies are
+ * synced up.
+ * 
+ * This file defines the primitives for data structures used in the profiling
+ * runtime and the serialized profile file.
+ * E.g. To declare the fields in a struct  
+ *
+ * struct MemInfoBlock {  
+ *   #define MIBEntryDef(NameTag, Name, TypeTag, Type) Type Tag; 
+ *   #include "MemProfMIB.inc"
+ *   #undef MIBEntryDef
+ * };
+\*===----------------------------------------------------------------------===*/
+
+// If the MIBEntryDef macro has not been defined then define it to silently
+// consume the arguments. 
+#ifndef MIBEntryDef
+#define MIBEntryDef(NameTag, Name, TypeTag, Type)
+#endif
+
+// Ensure that the constructor and methods of MemInfoBlock in MemProfData.inc
+// are updated if new members are added.
+MIBEntryDef(AllocCount = 1, AllocCount,
+            MIBMeta::MIBFieldType::UINT32, uint32_t)
+MIBEntryDef(TotalAccessCount = 2, TotalAccessCount,
+            MIBMeta::MIBFieldType::UINT64, uint64_t)
+MIBEntryDef(MinAccessCount = 3, MinAccessCount,
+            MIBMeta::MIBFieldType::UINT64, uint64_t)
+MIBEntryDef(MaxAccessCount = 4, MaxAccessCount,
+            MIBMeta::MIBFieldType::UINT64, uint64_t)
+MIBEntryDef(TotalSize = 5, TotalSize,
+            MIBMeta::MIBFieldType::UINT64, uint64_t)
+MIBEntryDef(MinSize = 6, MinSize,
+            MIBMeta::MIBFieldType::UINT32, uint32_t)
+MIBEntryDef(MaxSize = 7, MaxSize,
+            MIBMeta::MIBFieldType::UINT32, uint32_t)
+MIBEntryDef(AllocTimestamp = 8, AllocTimestamp,
+            MIBMeta::MIBFieldType::UINT32, uint32_t)
+MIBEntryDef(DeallocTimestamp = 9, DeallocTimestamp,
+            MIBMeta::MIBFieldType::UINT32, uint32_t)
+MIBEntryDef(TotalLifetime = 10, TotalLifetime,
+            MIBMeta::MIBFieldType::UINT64, uint64_t)
+MIBEntryDef(MinLifetime = 11, MinLifetime,
+            MIBMeta::MIBFieldType::UINT32, uint32_t)
+MIBEntryDef(MaxLifetime = 12, MaxLifetime,
+            MIBMeta::MIBFieldType::UINT32, uint32_t)
+MIBEntryDef(AllocCpuId = 13, AllocCpuId,
+            MIBMeta::MIBFieldType::UINT32, uint32_t)
+MIBEntryDef(DeallocCpuId = 14, DeallocCpuId,
+            MIBMeta::MIBFieldType::UINT32, uint32_t)
+MIBEntryDef(NumMigratedCpu = 15, NumMigratedCpu,
+            MIBMeta::MIBFieldType::UINT32, uint32_t)
+MIBEntryDef(NumLifetimeOverlaps = 16, NumLifetimeOverlaps,
+            MIBMeta::MIBFieldType::UINT32, uint32_t)
+MIBEntryDef(NumSameAllocCpu = 17, NumSameAllocCpu,
+            MIBMeta::MIBFieldType::UINT32, uint32_t)
+MIBEntryDef(NumSameDeallocCpu = 18, NumSameDeallocCpu,
+            MIBMeta::MIBFieldType::UINT32, uint32_t)
+MIBEntryDef(DataTypeId = 19, DataTypeId,
+            MIBMeta::MIBFieldType::UINT64, uint64_t)
diff --git a/llvm/test/tools/llvm-profdata/memprof-basic.test b/llvm/test/tools/llvm-profdata/memprof-basic.test
--- a/llvm/test/tools/llvm-profdata/memprof-basic.test
+++ b/llvm/test/tools/llvm-profdata/memprof-basic.test
@@ -58,24 +58,25 @@
 CHECK-NEXT:       Column: 0
 CHECK-NEXT:       Inline: 0
 CHECK-NEXT:     MemInfoBlock:
-CHECK-NEXT:       alloc_count: 1
-CHECK-NEXT:       total_access_count: 0
-CHECK-NEXT:       min_access_count: 0
-CHECK-NEXT:       max_access_count: 0
-CHECK-NEXT:       total_size: 53
-CHECK-NEXT:       min_size: 53
-CHECK-NEXT:       max_size: 53
-CHECK-NEXT:       alloc_timestamp: 0
-CHECK-NEXT:       dealloc_timestamp: 987
-CHECK-NEXT:       total_lifetime: 987
-CHECK-NEXT:       min_lifetime: 987
-CHECK-NEXT:       max_lifetime: 987
-CHECK-NEXT:       alloc_cpu_id: 4294967295
-CHECK-NEXT:       dealloc_cpu_id: 56
-CHECK-NEXT:       num_migrated_cpu: 1
-CHECK-NEXT:       num_lifetime_overlaps: 0
-CHECK-NEXT:       num_same_alloc_cpu: 0
-CHECK-NEXT:       num_same_dealloc_cpu: 0
+CHECK-NEXT:       AllocCount: 1
+CHECK-NEXT:       TotalAccessCount: 0
+CHECK-NEXT:       MinAccessCount: 0
+CHECK-NEXT:       MaxAccessCount: 0
+CHECK-NEXT:       TotalSize: 53
+CHECK-NEXT:       MinSize: 53
+CHECK-NEXT:       MaxSize: 53
+CHECK-NEXT:       AllocTimestamp: 0
+CHECK-NEXT:       DeallocTimestamp: 987
+CHECK-NEXT:       TotalLifetime: 987
+CHECK-NEXT:       MinLifetime: 987
+CHECK-NEXT:       MaxLifetime: 987
+CHECK-NEXT:       AllocCpuId: 4294967295
+CHECK-NEXT:       DeallocCpuId: 56
+CHECK-NEXT:       NumMigratedCpu: 1
+CHECK-NEXT:       NumLifetimeOverlaps: 0
+CHECK-NEXT:       NumSameAllocCpu: 0
+CHECK-NEXT:       NumSameDeallocCpu: 0
+CHECK-NEXT:       DataTypeId: {{[0-9]+}}
 CHECK-NEXT:   -
 CHECK-NEXT:     Callstack:
 CHECK-NEXT:     -
@@ -94,24 +95,25 @@
 CHECK-NEXT:       Column: 0
 CHECK-NEXT:       Inline: 0
 CHECK-NEXT:     MemInfoBlock:
-CHECK-NEXT:       alloc_count: 1
-CHECK-NEXT:       total_access_count: 2
-CHECK-NEXT:       min_access_count: 2
-CHECK-NEXT:       max_access_count: 2
-CHECK-NEXT:       total_size: 10
-CHECK-NEXT:       min_size: 10
-CHECK-NEXT:       max_size: 10
-CHECK-NEXT:       alloc_timestamp: 986
-CHECK-NEXT:       dealloc_timestamp: 986
-CHECK-NEXT:       total_lifetime: 0
-CHECK-NEXT:       min_lifetime: 0
-CHECK-NEXT:       max_lifetime: 0
-CHECK-NEXT:       alloc_cpu_id: 56
-CHECK-NEXT:       dealloc_cpu_id: 56
-CHECK-NEXT:       num_migrated_cpu: 0
-CHECK-NEXT:       num_lifetime_overlaps: 0
-CHECK-NEXT:       num_same_alloc_cpu: 0
-CHECK-NEXT:       num_same_dealloc_cpu: 0
+CHECK-NEXT:       AllocCount: 1
+CHECK-NEXT:       TotalAccessCount: 2
+CHECK-NEXT:       MinAccessCount: 2
+CHECK-NEXT:       MaxAccessCount: 2
+CHECK-NEXT:       TotalSize: 10
+CHECK-NEXT:       MinSize: 10
+CHECK-NEXT:       MaxSize: 10
+CHECK-NEXT:       AllocTimestamp: 986
+CHECK-NEXT:       DeallocTimestamp: 986
+CHECK-NEXT:       TotalLifetime: 0
+CHECK-NEXT:       MinLifetime: 0
+CHECK-NEXT:       MaxLifetime: 0
+CHECK-NEXT:       AllocCpuId: 56
+CHECK-NEXT:       DeallocCpuId: 56
+CHECK-NEXT:       NumMigratedCpu: 0
+CHECK-NEXT:       NumLifetimeOverlaps: 0
+CHECK-NEXT:       NumSameAllocCpu: 0
+CHECK-NEXT:       NumSameDeallocCpu: 0
+CHECK-NEXT:       DataTypeId: {{[0-9]+}}
 CHECK-NEXT:   -
 CHECK-NEXT:     Callstack:
 CHECK-NEXT:     -
@@ -130,21 +132,22 @@
 CHECK-NEXT:       Column: 0
 CHECK-NEXT:       Inline: 0
 CHECK-NEXT:     MemInfoBlock:
-CHECK-NEXT:       alloc_count: 1
-CHECK-NEXT:       total_access_count: 2
-CHECK-NEXT:       min_access_count: 2
-CHECK-NEXT:       max_access_count: 2
-CHECK-NEXT:       total_size: 10
-CHECK-NEXT:       min_size: 10
-CHECK-NEXT:       max_size: 10
-CHECK-NEXT:       alloc_timestamp: 987
-CHECK-NEXT:       dealloc_timestamp: 987
-CHECK-NEXT:       total_lifetime: 0
-CHECK-NEXT:       min_lifetime: 0
-CHECK-NEXT:       max_lifetime: 0
-CHECK-NEXT:       alloc_cpu_id: 56
-CHECK-NEXT:       dealloc_cpu_id: 56
-CHECK-NEXT:       num_migrated_cpu: 0
-CHECK-NEXT:       num_lifetime_overlaps: 0
-CHECK-NEXT:       num_same_alloc_cpu: 0
-CHECK-NEXT:       num_same_dealloc_cpu: 0
+CHECK-NEXT:       AllocCount: 1
+CHECK-NEXT:       TotalAccessCount: 2
+CHECK-NEXT:       MinAccessCount: 2
+CHECK-NEXT:       MaxAccessCount: 2
+CHECK-NEXT:       TotalSize: 10
+CHECK-NEXT:       MinSize: 10
+CHECK-NEXT:       MaxSize: 10
+CHECK-NEXT:       AllocTimestamp: 987
+CHECK-NEXT:       DeallocTimestamp: 987
+CHECK-NEXT:       TotalLifetime: 0
+CHECK-NEXT:       MinLifetime: 0
+CHECK-NEXT:       MaxLifetime: 0
+CHECK-NEXT:       AllocCpuId: 56
+CHECK-NEXT:       DeallocCpuId: 56
+CHECK-NEXT:       NumMigratedCpu: 0
+CHECK-NEXT:       NumLifetimeOverlaps: 0
+CHECK-NEXT:       NumSameAllocCpu: 0
+CHECK-NEXT:       NumSameDeallocCpu: 0
+CHECK-NEXT:       DataTypeId: {{[0-9]+}}
diff --git a/llvm/unittests/ProfileData/MemProfTest.cpp b/llvm/unittests/ProfileData/MemProfTest.cpp
--- a/llvm/unittests/ProfileData/MemProfTest.cpp
+++ b/llvm/unittests/ProfileData/MemProfTest.cpp
@@ -24,6 +24,8 @@
 using ::llvm::memprof::CallStackMap;
 using ::llvm::memprof::MemInfoBlock;
 using ::llvm::memprof::MemProfRecord;
+using ::llvm::memprof::Meta;
+using ::llvm::memprof::PortableMemInfoBlock;
 using ::llvm::memprof::RawMemProfReader;
 using ::llvm::memprof::SegmentEntry;
 using ::llvm::object::SectionedAddress;
@@ -122,8 +124,8 @@
   CSM[0x2] = {0x6000, 0x2000};
 
   llvm::MapVector<uint64_t, MemInfoBlock> Prof;
-  Prof[0x1].alloc_count = 1;
-  Prof[0x2].alloc_count = 2;
+  Prof[0x1].AllocCount = 1;
+  Prof[0x2].AllocCount = 2;
 
   auto Seg = makeSegments();
 
@@ -135,8 +137,8 @@
   }
   EXPECT_EQ(Records.size(), 2U);
 
-  EXPECT_EQ(Records[0].Info.alloc_count, 1U);
-  EXPECT_EQ(Records[1].Info.alloc_count, 2U);
+  EXPECT_EQ(Records[0].Info.getAllocCount(), 1U);
+  EXPECT_EQ(Records[1].Info.getAllocCount(), 2U);
   EXPECT_THAT(Records[0].CallStack[0], FrameContains("foo", 5U, 30U, false));
   EXPECT_THAT(Records[0].CallStack[1], FrameContains("bar", 51U, 20U, true));
 
@@ -146,4 +148,26 @@
   EXPECT_THAT(Records[1].CallStack[3], FrameContains("bar", 51U, 20U, true));
 }
 
+TEST(MemProf, PortableWrapper) {
+  MemInfoBlock Info(/*size=*/16, /*access_count=*/7, /*alloc_timestamp=*/1000,
+                    /*dealloc_timestamp=*/2000, /*alloc_cpu=*/3,
+                    /*dealloc_cpu=*/4);
+
+  llvm::SmallVector<Meta, static_cast<size_t>(Meta::Size)> Schema;
+#define MIBEntryDef(NameTag, Name, TypeTag, Type) Schema.push_back(Meta::Name);
+#include "llvm/ProfileData/MemProfMIB.inc"
+#undef MIBEntryDef
+
+  PortableMemInfoBlock Block(Schema, reinterpret_cast<char *>(&Info));
+
+  EXPECT_EQ(Block.getAllocCount(), Info.AllocCount);
+  EXPECT_EQ(Block.getTotalAccessCount(), Info.MaxAccessCount);
+  EXPECT_EQ(Block.getAllocCpuId(), Info.AllocCpuId);
+
+  char Output[sizeof(MemInfoBlock)] = {0};
+  Block.serialize(Schema, Output);
+
+  EXPECT_EQ(*reinterpret_cast<MemInfoBlock *>(Output), Info);
+}
+
 } // namespace