Index: include/llvm/ProfileData/CoverageMappingReader.h
===================================================================
--- include/llvm/ProfileData/CoverageMappingReader.h
+++ include/llvm/ProfileData/CoverageMappingReader.h
@@ -20,7 +20,7 @@
 #include "llvm/ADT/Triple.h"
 #include "llvm/Object/ObjectFile.h"
 #include "llvm/ProfileData/CoverageMapping.h"
-#include "llvm/ProfileData/InstrProf.h"
+#include "llvm/ProfileData/InstrProfReader.h"
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/MemoryBuffer.h"
 #include <iterator>
@@ -159,6 +159,7 @@
   std::vector<StringRef> Filenames;
   std::vector<ProfileMappingRecord> MappingRecords;
   size_t CurrentRecord;
+  std::unique_ptr<ProfSymtab> Symtab;
   std::vector<StringRef> FunctionsFilenames;
   std::vector<CounterExpression> Expressions;
   std::vector<CounterMappingRegion> MappingRegions;
Index: include/llvm/ProfileData/InstrProf.h
===================================================================
--- include/llvm/ProfileData/InstrProf.h
+++ include/llvm/ProfileData/InstrProf.h
@@ -17,6 +17,9 @@
 #define LLVM_PROFILEDATA_INSTRPROF_H_
 
 #include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/MD5.h"
 #include <cstdint>
 #include <system_error>
 #include <vector>
@@ -44,12 +47,50 @@
   return std::error_code(static_cast<int>(E), instrprof_category());
 }
 
+namespace IndexedInstrProf {
+
+enum class HashT : uint32_t {
+  MD5,
+
+  Last = MD5
+};
+
+static inline uint64_t MD5Hash(StringRef Str) {
+  MD5 Hash;
+  Hash.update(Str);
+  llvm::MD5::MD5Result Result;
+  Hash.final(Result);
+  // Return the least significant 8 bytes. Our MD5 implementation returns the
+  // result in little endian, so we may need to swap bytes.
+  using namespace llvm::support;
+  return endian::read<uint64_t, little, unaligned>(Result);
+}
+
+static inline uint64_t ComputeHash(HashT Type, StringRef K) {
+  switch (Type) {
+  case HashT::MD5:
+    return IndexedInstrProf::MD5Hash(K);
+  }
+  llvm_unreachable("Unhandled hash type");
+}
+
+const uint64_t Magic = 0x8169666f72706cff; // "\xfflprofi\x81"
+const uint64_t Version = 3;
+const HashT HashType = HashT::MD5;
+}
+
 /// Profiling information for a single function.
 struct InstrProfRecord {
   InstrProfRecord() {}
+  InstrProfRecord(uint64_t NameKey, uint64_t Hash, std::vector<uint64_t> Counts)
+      : NameKey(NameKey), Hash(Hash), Counts(std::move(Counts)) {}
   InstrProfRecord(StringRef Name, uint64_t Hash, std::vector<uint64_t> Counts)
-      : Name(Name), Hash(Hash), Counts(std::move(Counts)) {}
+      : Name(Name), NameKey(0), Hash(Hash), Counts(std::move(Counts)) {
+
+    NameKey = IndexedInstrProf::ComputeHash(IndexedInstrProf::HashType, Name);
+  }
   StringRef Name;
+  uint64_t NameKey;
   uint64_t Hash;
   std::vector<uint64_t> Counts;
 };
Index: include/llvm/ProfileData/InstrProfReader.h
===================================================================
--- include/llvm/ProfileData/InstrProfReader.h
+++ include/llvm/ProfileData/InstrProfReader.h
@@ -16,7 +16,9 @@
 #define LLVM_PROFILEDATA_INSTRPROFREADER_H
 
 #include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/StringExtras.h"
+#include "llvm/Object/ObjectFile.h"
 #include "llvm/ProfileData/InstrProf.h"
 #include "llvm/Support/EndianStream.h"
 #include "llvm/Support/ErrorOr.h"
@@ -129,34 +131,71 @@
 private:
   /// The profile data file contents.
   std::unique_ptr<MemoryBuffer> DataBuffer;
-  struct ProfileData {
+  struct ProfileDataV1 {
     const uint32_t NameSize;
     const uint32_t NumCounters;
     const uint64_t FuncHash;
-    const IntPtrT NamePtr;
+    const IntPtrT Name;
+    const IntPtrT CounterPtr;
+  };
+  struct ProfileData {
+    const uint64_t NameKey;
+    const uint64_t FuncHash;
     const IntPtrT CounterPtr;
+    const uint32_t NumCounters;
   };
   struct RawHeader {
     const uint64_t Magic;
     const uint64_t Version;
     const uint64_t DataSize;
     const uint64_t CountersSize;
-    const uint64_t NamesSize;
+    const uint64_t NamesSize; //  Used for V1
     const uint64_t CountersDelta;
-    const uint64_t NamesDelta;
+    const uint64_t NamesDelta; // Used for V1
   };
 
   bool ShouldSwapBytes;
   uint64_t CountersDelta;
   uint64_t NamesDelta;
-  const ProfileData *Data;
-  const ProfileData *DataEnd;
+  union {
+    const ProfileData *Data;
+    const ProfileDataV1 *DataV1;
+  } U1;
+  union {
+    const ProfileData *DataEnd;
+    const ProfileDataV1 *DataEndV1;
+  } U2;
   const uint64_t *CountersStart;
   const char *NamesStart;
   const char *ProfileEnd;
+  uint64_t Version;
 
   RawInstrProfReader(const RawInstrProfReader &) = delete;
   RawInstrProfReader &operator=(const RawInstrProfReader &) = delete;
+
+  ptrdiff_t getCounterOffset(ptrdiff_t DataOffset, uint64_t DataSize) {
+    if (Version == 1)
+      return DataOffset + sizeof(ProfileDataV1) * DataSize;
+    else
+      return DataOffset + sizeof(ProfileData) * DataSize;
+  }
+  void setDataEnd(uint64_t DataSize) {
+    if (Version == 1)
+      U2.DataEndV1 = U1.DataV1 + DataSize;
+    else
+      U2.DataEnd = U1.Data + DataSize;
+  }
+  void advanceData(void) {
+    if (Version == 1)
+      U1.Data++;
+    else
+      U1.DataV1++;
+  }
+
+  std::error_code readNameFromData(uint64_t &NameKey, StringRef &RawName);
+  std::error_code readRawCountsFromData(InstrProfRecord &Record);
+  std::error_code readFuncHashFromData(uint64_t &FuncHash);
+
 public:
   RawInstrProfReader(std::unique_ptr<MemoryBuffer> DataBuffer)
       : DataBuffer(std::move(DataBuffer)) { }
@@ -185,13 +224,19 @@
 typedef RawInstrProfReader<uint32_t> RawInstrProfReader32;
 typedef RawInstrProfReader<uint64_t> RawInstrProfReader64;
 
-namespace IndexedInstrProf {
-enum class HashT : uint32_t;
-}
-
 /// Trait for lookups into the on-disk hash table for the binary instrprof
 /// format.
-class InstrProfLookupTrait {
+template <class KeyType>
+inline KeyType ReadKeyHelper(const unsigned char *D, uint64_t N) {
+  return KeyType((const char *)D, N);
+}
+
+template <>
+inline uint64_t ReadKeyHelper<uint64_t>(const unsigned char *D, uint64_t N) {
+  return *((const uint64_t *)D);
+}
+
+template <class KeyType> class InstrProfLookupTrait {
   std::vector<InstrProfRecord> DataBuffer;
   IndexedInstrProf::HashT HashType;
   unsigned FormatVersion;
@@ -202,15 +247,15 @@
 
   typedef ArrayRef<InstrProfRecord> data_type;
 
-  typedef StringRef internal_key_type;
-  typedef StringRef external_key_type;
+  typedef KeyType internal_key_type;
+  typedef KeyType external_key_type;
   typedef uint64_t hash_value_type;
   typedef uint64_t offset_type;
 
-  static bool EqualKey(StringRef A, StringRef B) { return A == B; }
-  static StringRef GetInternalKey(StringRef K) { return K; }
+  static bool EqualKey(KeyType A, KeyType B) { return A == B; }
+  static KeyType GetInternalKey(KeyType K) { return K; }
 
-  hash_value_type ComputeHash(StringRef K);
+  hash_value_type ComputeHash(KeyType K);
 
   static std::pair<offset_type, offset_type>
   ReadKeyDataLength(const unsigned char *&D) {
@@ -220,35 +265,83 @@
     return std::make_pair(KeyLen, DataLen);
   }
 
-  StringRef ReadKey(const unsigned char *D, offset_type N) {
-    return StringRef((const char *)D, N);
+  KeyType ReadKey(const unsigned char *D, offset_type N) {
+    return ReadKeyHelper<KeyType>(D, N);
   }
 
-  data_type ReadData(StringRef K, const unsigned char *D, offset_type N);
+  data_type ReadData(KeyType K, const unsigned char *D, offset_type N);
 };
 
-typedef OnDiskIterableChainedHashTable<InstrProfLookupTrait>
+typedef OnDiskIterableChainedHashTable<InstrProfLookupTrait<uint64_t>>
     InstrProfReaderIndex;
+typedef OnDiskIterableChainedHashTable<InstrProfLookupTrait<StringRef>>
+    InstrProfReaderIndexV2;
 
-/// Reader for the indexed binary instrprof format.
-class IndexedInstrProfReader : public InstrProfReader {
+class InstrProfIndex {
 private:
-  /// The profile data file contents.
-  std::unique_ptr<MemoryBuffer> DataBuffer;
   /// The index into the profile data.
   std::unique_ptr<InstrProfReaderIndex> Index;
   /// Iterator over the profile data.
   InstrProfReaderIndex::data_iterator RecordIterator;
+  /// The index into the profile data of v2 format.
+  std::unique_ptr<InstrProfReaderIndexV2> IndexV2;
+  /// Iterator over the profile data.
+  InstrProfReaderIndexV2::data_iterator RecordIteratorV2;
   /// The file format version of the profile data.
   uint64_t FormatVersion;
+
+public:
+  InstrProfIndex() : Index(nullptr), IndexV2(nullptr) {}
+  void Init(const unsigned char *Buckets, const unsigned char *const Payload,
+            const unsigned char *const Base, IndexedInstrProf::HashT HashType,
+            uint64_t Version) {
+    FormatVersion = Version;
+    if (FormatVersion <= 2) {
+      IndexV2.reset(InstrProfReaderIndexV2::Create(
+          Buckets, Payload, Base,
+          InstrProfLookupTrait<StringRef>(HashType, Version)));
+      // Set up our iterator for readNextRecord.
+      RecordIteratorV2 = IndexV2->data_begin();
+    } else {
+      Index.reset(InstrProfReaderIndex::Create(
+          Buckets, Payload, Base,
+          InstrProfLookupTrait<uint64_t>(HashType, Version)));
+      RecordIterator = Index->data_begin();
+    }
+  }
+
+  std::error_code getRecordsForNextKey(ArrayRef<InstrProfRecord> &Data);
+  std::error_code getRecord(StringRef FuncName, uint64_t FuncNameKey,
+                            ArrayRef<InstrProfRecord> &Data);
+  void advanceToNextKey() {
+    if (FormatVersion <= 2)
+      RecordIteratorV2++;
+    else
+      RecordIterator++;
+  }
+  bool atEnd() {
+    return (FormatVersion <= 2 ? RecordIteratorV2 == IndexV2->data_end()
+                               : RecordIterator == Index->data_end());
+  }
+};
+
+/// Reader for the indexed binary instrprof format.
+class IndexedInstrProfReader : public InstrProfReader {
+private:
+  /// The profile data file contents.
+  std::unique_ptr<MemoryBuffer> DataBuffer;
+  InstrProfIndex Index;
   /// The maximal execution count among all functions.
   uint64_t MaxFunctionCount;
 
+  std::error_code getFunctionCounts(StringRef FuncName, uint64_t FuncNameKey,
+                                    uint64_t FuncHash,
+                                    std::vector<uint64_t> &Counts);
   IndexedInstrProfReader(const IndexedInstrProfReader &) = delete;
   IndexedInstrProfReader &operator=(const IndexedInstrProfReader &) = delete;
 public:
   IndexedInstrProfReader(std::unique_ptr<MemoryBuffer> DataBuffer)
-      : DataBuffer(std::move(DataBuffer)), Index(nullptr) {}
+      : DataBuffer(std::move(DataBuffer)), Index() {}
 
   /// Return true if the given buffer is in an indexed instrprof format.
   static bool hasFormat(const MemoryBuffer &DataBuffer);
@@ -261,6 +354,8 @@
   /// Fill Counts with the profile data for the given function name.
   std::error_code getFunctionCounts(StringRef FuncName, uint64_t FuncHash,
                                     std::vector<uint64_t> &Counts);
+  std::error_code getFunctionCounts(uint64_t FuncNamekey, uint64_t FuncHash,
+                                    std::vector<uint64_t> &Counts);
   /// Return the maximum of all known function counts.
   uint64_t getMaximumFunctionCount() { return MaxFunctionCount; }
 
@@ -272,6 +367,44 @@
   create(std::unique_ptr<MemoryBuffer> Buffer);
 };
 
+/// \brief A helper structure to access the data from a section
+/// in an object file.
+struct SymbolNameSectionData {
+  StringRef Data;
+  uint64_t Address;
+
+  std::error_code load(object::SectionRef &Section) {
+    if (auto Err = Section.getContents(Data))
+      return Err;
+    Address = Section.getAddress();
+    return std::error_code();
+  }
+
+  std::error_code get(uint64_t Pointer, size_t Size, StringRef &Result);
+};
+
+/// Class to represent profile symbol table used by llvm-cov and llvm-profdata
+/// tool
+class ProfSymtab {
+  /// Map from md5hash key to function name strings.
+  DenseMap<uint64_t, std::string> Symtab;
+  /// Data section that contains funciton names
+  SymbolNameSectionData SymtabSection;
+  bool UsesNameSection;
+
+public:
+  std::error_code getFunctionName(uintptr_t NameHashKeyOrAddr, size_t Size,
+                                  StringRef &Result);
+  ProfSymtab(object::ObjectFile::symbol_iterator_range Syms);
+  ProfSymtab(StringRef Data, uint64_t Base) : UsesNameSection(true) {
+    SymtabSection.Data = Data;
+    SymtabSection.Address = Base;
+  }
+  ProfSymtab(object::SectionRef &Section) : UsesNameSection(true) {
+    SymtabSection.load(Section);
+  }
+};
+
 } // end namespace llvm
 
 #endif
Index: include/llvm/ProfileData/InstrProfWriter.h
===================================================================
--- include/llvm/ProfileData/InstrProfWriter.h
+++ include/llvm/ProfileData/InstrProfWriter.h
@@ -31,7 +31,7 @@
 public:
   typedef SmallDenseMap<uint64_t, std::vector<uint64_t>, 1> CounterData;
 private:
-  StringMap<CounterData> FunctionData;
+  DenseMap<uint64_t, CounterData> FunctionData;
   uint64_t MaxFunctionCount;
 public:
   InstrProfWriter() : MaxFunctionCount(0) {}
@@ -39,6 +39,11 @@
   /// Add function counts for the given function. If there are already counts
   /// for this function and the hash and number of counts match, each counter is
   /// summed.
+  std::error_code addFunctionCounts(uint64_t FunctionNameKey,
+                                    uint64_t FunctionHash,
+                                    ArrayRef<uint64_t> Counters);
+
+  /// A wrapper function used in unit test only
   std::error_code addFunctionCounts(StringRef FunctionName,
                                     uint64_t FunctionHash,
                                     ArrayRef<uint64_t> Counters);
Index: lib/CodeGen/CodeGenPGO.cpp
===================================================================
--- lib/CodeGen/CodeGenPGO.cpp
+++ lib/CodeGen/CodeGenPGO.cpp
@@ -69,11 +69,9 @@
            Linkage == llvm::GlobalValue::ExternalLinkage)
     Linkage = llvm::GlobalValue::PrivateLinkage;
 
-  auto *Value =
-      llvm::ConstantDataArray::getString(CGM.getLLVMContext(), FuncName, false);
-  FuncNameVar =
-      new llvm::GlobalVariable(CGM.getModule(), Value->getType(), true, Linkage,
-                               Value, "__llvm_profile_name_" + FuncName);
+  FuncNameVar = new llvm::GlobalVariable(
+      CGM.getModule(), llvm::Type::getInt8Ty(CGM.getLLVMContext()), true,
+      Linkage, 0, "__llvm_prf_nm_" + FuncName);
 
   // Hide the symbol so that we correctly get a copy for each executable.
   if (!llvm::GlobalValue::isLocalLinkage(FuncNameVar->getLinkage()))
Index: lib/CodeGen/CoverageMappingGen.h
===================================================================
--- lib/CodeGen/CoverageMappingGen.h
+++ lib/CodeGen/CoverageMappingGen.h
@@ -54,6 +54,7 @@
   CoverageSourceInfo &SourceInfo;
   llvm::SmallDenseMap<const FileEntry *, unsigned, 8> FileEntries;
   std::vector<llvm::Constant *> FunctionRecords;
+  std::vector<llvm::Constant *> FunctionNames;
   llvm::StructType *FunctionRecordTy;
   std::string CoverageMappings;
 
Index: lib/CodeGen/CoverageMappingGen.cpp
===================================================================
--- lib/CodeGen/CoverageMappingGen.cpp
+++ lib/CodeGen/CoverageMappingGen.cpp
@@ -926,21 +926,26 @@
   llvm::LLVMContext &Ctx = CGM.getLLVMContext();
   auto *Int32Ty = llvm::Type::getInt32Ty(Ctx);
   auto *Int64Ty = llvm::Type::getInt64Ty(Ctx);
-  auto *Int8PtrTy = llvm::Type::getInt8PtrTy(Ctx);
   if (!FunctionRecordTy) {
-    llvm::Type *FunctionRecordTypes[] = {Int8PtrTy, Int32Ty, Int32Ty, Int64Ty};
+    llvm::Type *FunctionRecordTypes[] = {Int64Ty, Int32Ty, Int32Ty, Int64Ty};
     FunctionRecordTy =
         llvm::StructType::get(Ctx, makeArrayRef(FunctionRecordTypes),
                               /*isPacked=*/true);
   }
 
+  auto FuncNameKey = llvm::IndexedInstrProf::ComputeHash(
+      llvm::IndexedInstrProf::HashType,
+      FunctionName->getName().substr(strlen("__llvm_prf_nm_")));
+
   llvm::Constant *FunctionRecordVals[] = {
-      llvm::ConstantExpr::getBitCast(FunctionName, Int8PtrTy),
-      llvm::ConstantInt::get(Int32Ty, FunctionNameValue.size()),
+      llvm::ConstantInt::get(Int64Ty, FuncNameKey),
+      llvm::ConstantInt::get(Int32Ty, 0), // NameSize field in legacy format
       llvm::ConstantInt::get(Int32Ty, CoverageMapping.size()),
       llvm::ConstantInt::get(Int64Ty, FunctionHash)};
   FunctionRecords.push_back(llvm::ConstantStruct::get(
       FunctionRecordTy, makeArrayRef(FunctionRecordVals)));
+  FunctionNames.push_back(llvm::ConstantExpr::getBitCast(
+      FunctionName, llvm::Type::getInt8PtrTy(Ctx)));
   CoverageMappings += CoverageMapping;
 
   if (CGM.getCodeGenOpts().DumpCoverageMapping) {
@@ -1029,6 +1034,16 @@
 
   // Make sure the data doesn't get deleted.
   CGM.addUsedGlobal(CovData);
+
+  // Create the deferred function records array
+  auto NamesArrTy =
+      llvm::ArrayType::get(llvm::Type::getInt8PtrTy(Ctx), FunctionNames.size());
+  auto NamesArrVal = llvm::ConstantArray::get(NamesArrTy, FunctionNames);
+  // This variable will not be emitted to the object file. It is used
+  // to pass the list of names referenced to codegen.
+  new llvm::GlobalVariable(CGM.getModule(), NamesArrTy, true,
+                           llvm::GlobalValue::InternalLinkage, NamesArrVal,
+                           "__llvm_coverage_names");
 }
 
 unsigned CoverageMappingModuleGen::getFileID(const FileEntry *File) {
Index: lib/ProfileData/CoverageMappingReader.cpp
===================================================================
--- lib/ProfileData/CoverageMappingReader.cpp
+++ lib/ProfileData/CoverageMappingReader.cpp
@@ -13,6 +13,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "llvm/ProfileData/CoverageMappingReader.h"
+#include "llvm/ProfileData/InstrProfReader.h"
 #include "llvm/ADT/DenseSet.h"
 #include "llvm/Object/MachOUniversal.h"
 #include "llvm/Object/ObjectFile.h"
@@ -290,36 +291,55 @@
   return std::error_code();
 }
 
-namespace {
+std::error_code SymbolNameSectionData::get(uint64_t Pointer, size_t Size,
+                                           StringRef &Result) {
+  if (Pointer < Address)
+    return coveragemap_error::malformed;
+  auto Offset = Pointer - Address;
+  if (Offset + Size > Data.size())
+    return coveragemap_error::malformed;
+  Result = Data.substr(Pointer - Address, Size);
+  return std::error_code();
+}
 
-/// \brief A helper structure to access the data from a section
-/// in an object file.
-struct SectionData {
-  StringRef Data;
-  uint64_t Address;
+std::error_code ProfSymtab::getFunctionName(uintptr_t NameKeyOrAddr,
+                                            size_t Size, StringRef &Result) {
+  if (UsesNameSection)
+    return SymtabSection.get(NameKeyOrAddr, Size, Result);
 
-  std::error_code load(SectionRef &Section) {
-    if (auto Err = Section.getContents(Data))
-      return Err;
-    Address = Section.getAddress();
-    return std::error_code();
-  }
+  auto Iterator = Symtab.find(NameKeyOrAddr);
+  if (Iterator == Symtab.end())
+    return coveragemap_error::malformed;
 
-  std::error_code get(uint64_t Pointer, size_t Size, StringRef &Result) {
-    if (Pointer < Address)
-      return coveragemap_error::malformed;
-    auto Offset = Pointer - Address;
-    if (Offset + Size > Data.size())
-      return coveragemap_error::malformed;
-    Result = Data.substr(Pointer - Address, Size);
-    return std::error_code();
+  Result = Iterator->second;
+  return std::error_code();
+}
+
+ProfSymtab::ProfSymtab(object::ObjectFile::symbol_iterator_range Syms) {
+  UsesNameSection = false;
+  auto S = Syms.begin();
+  auto E = Syms.end();
+  for (; S != E; ++S) {
+    ErrorOr<StringRef> NameOrError = S->getName();
+    if (!NameOrError)
+      continue;
+    StringRef Name = *NameOrError;
+
+    // TODO: define name prefix
+    if (!Name.startswith("__llvm_prf_nm_"))
+      continue;
+
+    StringRef RealName = Name.substr(strlen("__llvm_prf_nm_"));
+    uint64_t FuncNameKey =
+        IndexedInstrProf::ComputeHash(IndexedInstrProf::HashType, RealName);
+
+    Symtab[FuncNameKey] = RealName.str();
   }
-};
 }
 
 template <typename T, support::endianness Endian>
 std::error_code readCoverageMappingData(
-    SectionData &ProfileNames, StringRef Data,
+    std::unique_ptr<ProfSymtab> &ProfileNames, StringRef Data,
     std::vector<BinaryCoverageReader::ProfileMappingRecord> &Records,
     std::vector<StringRef> &Filenames) {
   using namespace support;
@@ -343,7 +363,9 @@
 
     // Skip past the function records, saving the start and end for later.
     const char *FunBuf = Buf;
-    Buf += NRecords * (sizeof(T) + 2 * sizeof(uint32_t) + sizeof(uint64_t));
+    // TODO : this is very error-prone. Need to define size and structure of
+    // Function Record in coverage mapping in a single place.
+    Buf += NRecords * (3 * sizeof(uint64_t));
     const char *FunEnd = Buf;
 
     // Get the filenames.
@@ -368,7 +390,8 @@
 
     while (FunBuf < FunEnd) {
       // Read the function information
-      T NamePtr = endian::readNext<T, Endian, unaligned>(FunBuf);
+      uint64_t FuncNameKey =
+          endian::readNext<uint64_t, Endian, unaligned>(FunBuf);
       uint32_t NameSize = endian::readNext<uint32_t, Endian, unaligned>(FunBuf);
       uint32_t DataSize = endian::readNext<uint32_t, Endian, unaligned>(FunBuf);
       uint64_t FuncHash = endian::readNext<uint64_t, Endian, unaligned>(FunBuf);
@@ -382,12 +405,13 @@
       // Ignore this record if we already have a record that points to the same
       // function name. This is useful to ignore the redundant records for the
       // functions with ODR linkage.
-      if (!UniqueFunctionMappingData.insert(NamePtr).second)
+      if (!UniqueFunctionMappingData.insert(FuncNameKey).second)
         continue;
 
       // Finally, grab the name and create a record.
       StringRef FuncName;
-      if (std::error_code EC = ProfileNames.get(NamePtr, NameSize, FuncName))
+      if (std::error_code EC =
+              ProfileNames->getFunctionName(FuncNameKey, NameSize, FuncName))
         return EC;
       Records.push_back(BinaryCoverageReader::ProfileMappingRecord(
           CoverageMappingVersion(Version), FuncName, FuncHash, Mapping,
@@ -400,11 +424,10 @@
 
 static const char *TestingFormatMagic = "llvmcovmtestdata";
 
-static std::error_code loadTestingFormat(StringRef Data,
-                                         SectionData &ProfileNames,
-                                         StringRef &CoverageMapping,
-                                         uint8_t &BytesInAddress,
-                                         support::endianness &Endian) {
+static std::error_code
+loadTestingFormat(StringRef Data, std::unique_ptr<ProfSymtab> &ProfileNames,
+                  StringRef &CoverageMapping, uint8_t &BytesInAddress,
+                  support::endianness &Endian) {
   BytesInAddress = 8;
   Endian = support::endianness::little;
 
@@ -420,14 +443,14 @@
   if (Data.size() < 1)
     return coveragemap_error::truncated;
   N = 0;
-  ProfileNames.Address =
+  uint64_t Address =
       decodeULEB128(reinterpret_cast<const uint8_t *>(Data.data()), &N);
   if (N > Data.size())
     return coveragemap_error::malformed;
   Data = Data.substr(N);
   if (Data.size() < ProfileNamesSize)
     return coveragemap_error::malformed;
-  ProfileNames.Data = Data.substr(0, ProfileNamesSize);
+  ProfileNames.reset(new ProfSymtab(Data.substr(0, ProfileNamesSize), Address));
   CoverageMapping = Data.substr(ProfileNamesSize);
   return std::error_code();
 }
@@ -443,12 +466,11 @@
   return coveragemap_error::no_data_found;
 }
 
-static std::error_code loadBinaryFormat(MemoryBufferRef ObjectBuffer,
-                                        SectionData &ProfileNames,
-                                        StringRef &CoverageMapping,
-                                        uint8_t &BytesInAddress,
-                                        support::endianness &Endian,
-                                        StringRef Arch) {
+static std::error_code
+loadBinaryFormat(MemoryBufferRef ObjectBuffer,
+                 std::unique_ptr<ProfSymtab> &ProfileNames,
+                 StringRef &CoverageMapping, uint8_t &BytesInAddress,
+                 support::endianness &Endian, StringRef Arch) {
   auto BinOrErr = object::createBinary(ObjectBuffer);
   if (std::error_code EC = BinOrErr.getError())
     return EC;
@@ -476,10 +498,6 @@
   Endian = OF->isLittleEndian() ? support::endianness::little
                                 : support::endianness::big;
 
-  // Look for the sections that we are interested in.
-  auto NamesSection = lookupSection(*OF, "__llvm_prf_names");
-  if (auto EC = NamesSection.getError())
-    return EC;
   auto CoverageSection = lookupSection(*OF, "__llvm_covmap");
   if (auto EC = CoverageSection.getError())
     return EC;
@@ -487,8 +505,8 @@
   // Get the contents of the given sections.
   if (std::error_code EC = CoverageSection->getContents(CoverageMapping))
     return EC;
-  if (std::error_code EC = ProfileNames.load(*NamesSection))
-    return EC;
+
+  ProfileNames.reset(new ProfSymtab(OF->symbols()));
 
   return std::error_code();
 }
@@ -498,7 +516,7 @@
                              StringRef Arch) {
   std::unique_ptr<BinaryCoverageReader> Reader(new BinaryCoverageReader());
 
-  SectionData Profile;
+  std::unique_ptr<ProfSymtab> &Profile = Reader->Symtab;
   StringRef Coverage;
   uint8_t BytesInAddress;
   support::endianness Endian;
Index: lib/ProfileData/InstrProfIndexed.h
===================================================================
--- lib/ProfileData/InstrProfIndexed.h
+++ /dev/null
@@ -1,56 +0,0 @@
-//=-- InstrProfIndexed.h - Indexed profiling format support -------*- C++ -*-=//
-//
-//                     The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// Shared header for the instrumented profile data reader and writer.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_LIB_PROFILEDATA_INSTRPROFINDEXED_H
-#define LLVM_LIB_PROFILEDATA_INSTRPROFINDEXED_H
-
-#include "llvm/Support/Endian.h"
-#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/MD5.h"
-
-namespace llvm {
-
-namespace IndexedInstrProf {
-enum class HashT : uint32_t {
-  MD5,
-
-  Last = MD5
-};
-
-static inline uint64_t MD5Hash(StringRef Str) {
-  MD5 Hash;
-  Hash.update(Str);
-  llvm::MD5::MD5Result Result;
-  Hash.final(Result);
-  // Return the least significant 8 bytes. Our MD5 implementation returns the
-  // result in little endian, so we may need to swap bytes.
-  using namespace llvm::support;
-  return endian::read<uint64_t, little, unaligned>(Result);
-}
-
-static inline uint64_t ComputeHash(HashT Type, StringRef K) {
-  switch (Type) {
-  case HashT::MD5:
-    return IndexedInstrProf::MD5Hash(K);
-  }
-  llvm_unreachable("Unhandled hash type");
-}
-
-const uint64_t Magic = 0x8169666f72706cff; // "\xfflprofi\x81"
-const uint64_t Version = 2;
-const HashT HashType = HashT::MD5;
-}
-
-} // end namespace llvm
-
-#endif
Index: lib/ProfileData/InstrProfReader.cpp
===================================================================
--- lib/ProfileData/InstrProfReader.cpp
+++ lib/ProfileData/InstrProfReader.cpp
@@ -13,7 +13,6 @@
 //===----------------------------------------------------------------------===//
 
 #include "llvm/ProfileData/InstrProfReader.h"
-#include "InstrProfIndexed.h"
 #include "llvm/ADT/STLExtras.h"
 #include <cassert>
 
@@ -108,6 +107,8 @@
 
   // Read the function name.
   Record.Name = *Line++;
+  Record.NameKey =
+      IndexedInstrProf::ComputeHash(IndexedInstrProf::HashType, Record.Name);
 
   // Read the function hash.
   if (Line.is_at_end())
@@ -217,16 +218,15 @@
   return readHeader(*Header);
 }
 
-static uint64_t getRawVersion() {
-  return 1;
-}
+static uint64_t getRawVersion() { return 2; }
 
 template <class IntPtrT>
 std::error_code
 RawInstrProfReader<IntPtrT>::readHeader(const RawHeader &Header) {
-  if (swap(Header.Version) != getRawVersion())
+  if (swap(Header.Version) > getRawVersion())
     return error(instrprof_error::unsupported_version);
 
+  Version = swap(Header.Version);
   CountersDelta = swap(Header.CountersDelta);
   NamesDelta = swap(Header.NamesDelta);
   auto DataSize = swap(Header.DataSize);
@@ -234,7 +234,7 @@
   auto NamesSize = swap(Header.NamesSize);
 
   ptrdiff_t DataOffset = sizeof(RawHeader);
-  ptrdiff_t CountersOffset = DataOffset + sizeof(ProfileData) * DataSize;
+  ptrdiff_t CountersOffset = getCounterOffset(DataOffset, DataSize);
   ptrdiff_t NamesOffset = CountersOffset + sizeof(uint64_t) * CountersSize;
   size_t ProfileSize = NamesOffset + sizeof(char) * NamesSize;
 
@@ -242,8 +242,8 @@
   if (Start + ProfileSize > DataBuffer->getBufferEnd())
     return error(instrprof_error::bad_header);
 
-  Data = reinterpret_cast<const ProfileData *>(Start + DataOffset);
-  DataEnd = Data + DataSize;
+  U1.Data = reinterpret_cast<const ProfileData *>(Start + DataOffset);
+  setDataEnd(DataSize);
   CountersStart = reinterpret_cast<const uint64_t *>(Start + CountersOffset);
   NamesStart = Start + NamesOffset;
   ProfileEnd = Start + ProfileSize;
@@ -253,29 +253,48 @@
 
 template <class IntPtrT>
 std::error_code
-RawInstrProfReader<IntPtrT>::readNextRecord(InstrProfRecord &Record) {
-  if (Data == DataEnd)
-    if (std::error_code EC = readNextHeader(ProfileEnd))
-      return EC;
+RawInstrProfReader<IntPtrT>::readNameFromData(uint64_t &NameKey,
+                                              StringRef &RawName) {
+  if (Version == 1) {
+    RawName = StringRef(getName(U1.DataV1->Name), swap(U1.DataV1->NameSize));
+    if (RawName.data() < NamesStart ||
+        RawName.data() + RawName.size() > DataBuffer->getBufferEnd())
+      return error(instrprof_error::malformed);
+    NameKey =
+        IndexedInstrProf::ComputeHash(IndexedInstrProf::HashType, RawName);
+  } else {
+    RawName = StringRef();
+    NameKey = U1.Data->NameKey;
+  }
+  return success();
+}
+
+template <class IntPtrT>
+std::error_code
+RawInstrProfReader<IntPtrT>::readRawCountsFromData(InstrProfRecord &Record) {
+
+  uint32_t NumCounters;
+  IntPtrT CounterPtr;
+  if (Version == 1) {
+    NumCounters = swap(U1.DataV1->NumCounters);
+    CounterPtr = U1.DataV1->CounterPtr;
+  } else {
+    NumCounters = swap(U1.Data->NumCounters);
+    CounterPtr = U1.Data->CounterPtr;
+  }
 
-  // Get the raw data.
-  StringRef RawName(getName(Data->NamePtr), swap(Data->NameSize));
-  uint32_t NumCounters = swap(Data->NumCounters);
   if (NumCounters == 0)
     return error(instrprof_error::malformed);
-  auto RawCounts = makeArrayRef(getCounter(Data->CounterPtr), NumCounters);
 
-  // Check bounds.
+  auto RawCounts = makeArrayRef(getCounter(CounterPtr), NumCounters);
+
   auto *NamesStartAsCounter = reinterpret_cast<const uint64_t *>(NamesStart);
-  if (RawName.data() < NamesStart ||
-      RawName.data() + RawName.size() > DataBuffer->getBufferEnd() ||
-      RawCounts.data() < CountersStart ||
+
+  // Check bounds.
+  if (RawCounts.data() < CountersStart ||
       RawCounts.data() + RawCounts.size() > NamesStartAsCounter)
     return error(instrprof_error::malformed);
 
-  // Store the data in Record, byte-swapping as necessary.
-  Record.Hash = swap(Data->FuncHash);
-  Record.Name = RawName;
   if (ShouldSwapBytes) {
     Record.Counts.clear();
     Record.Counts.reserve(RawCounts.size());
@@ -284,8 +303,38 @@
   } else
     Record.Counts = RawCounts;
 
+  return success();
+}
+
+template <class IntPtrT>
+std::error_code
+RawInstrProfReader<IntPtrT>::readFuncHashFromData(uint64_t &FuncHash) {
+  // Store the data in Record, byte-swapping as necessary.
+  if (Version == 1)
+    FuncHash = swap(U1.DataV1->FuncHash);
+  else
+    FuncHash = swap(U1.Data->FuncHash);
+  return success();
+}
+
+template <class IntPtrT>
+std::error_code
+RawInstrProfReader<IntPtrT>::readNextRecord(InstrProfRecord &Record) {
+  if (U1.Data == U2.DataEnd)
+    if (std::error_code EC = readNextHeader(ProfileEnd))
+      return EC;
+
+  if (std::error_code EC = readNameFromData(Record.NameKey, Record.Name))
+    return EC;
+
+  if (std::error_code EC = readFuncHashFromData(Record.Hash))
+    return EC;
+
+  if (std::error_code EC = readRawCountsFromData(Record))
+    return EC;
+
   // Iterate.
-  ++Data;
+  advanceData();
   return success();
 }
 
@@ -294,16 +343,24 @@
 template class RawInstrProfReader<uint64_t>;
 }
 
-InstrProfLookupTrait::hash_value_type
-InstrProfLookupTrait::ComputeHash(StringRef K) {
+namespace llvm {
+template <class KeyType>
+typename InstrProfLookupTrait<KeyType>::hash_value_type
+InstrProfLookupTrait<KeyType>::ComputeHash(KeyType K) {
   return IndexedInstrProf::ComputeHash(HashType, K);
 }
 
-typedef InstrProfLookupTrait::data_type data_type;
-typedef InstrProfLookupTrait::offset_type offset_type;
+template <>
+InstrProfLookupTrait<uint64_t>::hash_value_type
+InstrProfLookupTrait<uint64_t>::ComputeHash(uint64_t K) {
+  return K;
+}
+}
 
-data_type InstrProfLookupTrait::ReadData(StringRef K, const unsigned char *D,
-                                         offset_type N) {
+template <class KeyType>
+typename InstrProfLookupTrait<KeyType>::data_type
+InstrProfLookupTrait<KeyType>::ReadData(KeyType K, const unsigned char *D,
+                                        offset_type N) {
 
   // Check if the data is corrupt. If so, don't try to read it.
   if (N % sizeof(uint64_t))
@@ -366,7 +423,7 @@
     return error(instrprof_error::bad_magic);
 
   // Read the version.
-  FormatVersion = endian::readNext<uint64_t, little, unaligned>(Cur);
+  uint64_t FormatVersion = endian::readNext<uint64_t, little, unaligned>(Cur);
   if (FormatVersion > IndexedInstrProf::Version)
     return error(instrprof_error::unsupported_version);
 
@@ -381,25 +438,62 @@
   uint64_t HashOffset = endian::readNext<uint64_t, little, unaligned>(Cur);
 
   // The rest of the file is an on disk hash table.
-  Index.reset(InstrProfReaderIndex::Create(
-      Start + HashOffset, Cur, Start,
-      InstrProfLookupTrait(HashType, FormatVersion)));
-  // Set up our iterator for readNextRecord.
-  RecordIterator = Index->data_begin();
-
+  Index.Init(Start + HashOffset, Cur, Start, HashType, FormatVersion);
   return success();
 }
 
-std::error_code IndexedInstrProfReader::getFunctionCounts(
-    StringRef FuncName, uint64_t FuncHash, std::vector<uint64_t> &Counts) {
-  auto Iter = Index->find(FuncName);
-  if (Iter == Index->end())
-    return error(instrprof_error::unknown_function);
+std::error_code InstrProfIndex::getRecord(StringRef FuncName,
+                                          uint64_t FuncNameKey,
+                                          ArrayRef<InstrProfRecord> &Data) {
+
+  if (FormatVersion <= 2) {
+    assert(!FuncName.empty());
+    auto Iter = IndexV2->find(FuncName);
+    if (Iter == IndexV2->end())
+      return instrprof_error::unknown_function;
+
+    // Found it. Look for counters with the right hash.
+    Data = (*Iter);
+  } else {
+    auto Iter = Index->find(FuncNameKey);
+    if (Iter == Index->end())
+      return instrprof_error::unknown_function;
+
+    // Found it. Look for counters with the right hash.
+    Data = (*Iter);
+  }
 
-  // Found it. Look for counters with the right hash.
-  ArrayRef<InstrProfRecord> Data = (*Iter);
   if (Data.empty())
-    return error(instrprof_error::malformed);
+    return instrprof_error::malformed;
+
+  return instrprof_error::success;
+}
+
+std::error_code
+InstrProfIndex::getRecordsForNextKey(ArrayRef<InstrProfRecord> &Data) {
+  // Are we out of records?
+  if (atEnd())
+    return instrprof_error::eof;
+
+  if (FormatVersion <= 2)
+    Data = *RecordIteratorV2;
+  else
+    Data = *RecordIterator;
+
+  if (Data.empty())
+    return instrprof_error::malformed;
+
+  return instrprof_error::success;
+}
+
+std::error_code IndexedInstrProfReader::getFunctionCounts(
+    StringRef FuncName, uint64_t FuncNameKey, uint64_t FuncHash,
+    std::vector<uint64_t> &Counts) {
+
+  ArrayRef<InstrProfRecord> Data;
+  std::error_code EC = Index.getRecord(FuncName, FuncNameKey, Data);
+  if (EC != instrprof_error::success)
+    return error(EC);
 
   for (unsigned I = 0, E = Data.size(); I < E; ++I) {
     // Check for a match and fill the vector if there is one.
@@ -412,19 +506,31 @@
 }
 
 std::error_code
-IndexedInstrProfReader::readNextRecord(InstrProfRecord &Record) {
-  // Are we out of records?
-  if (RecordIterator == Index->data_end())
-    return error(instrprof_error::eof);
+IndexedInstrProfReader::getFunctionCounts(StringRef FuncName, uint64_t FuncHash,
+                                          std::vector<uint64_t> &Counts) {
+  uint64_t FuncNameKey =
+      IndexedInstrProf::ComputeHash(IndexedInstrProf::HashType, FuncName);
+  return getFunctionCounts(FuncName, FuncNameKey, FuncHash, Counts);
+}
 
-  if ((*RecordIterator).empty())
-    return error(instrprof_error::malformed);
+std::error_code IndexedInstrProfReader::getFunctionCounts(
+    uint64_t FuncNameKey, uint64_t FuncHash, std::vector<uint64_t> &Counts) {
+  return getFunctionCounts(StringRef(), FuncNameKey, FuncHash, Counts);
+}
+
+std::error_code
+IndexedInstrProfReader::readNextRecord(InstrProfRecord &Record) {
 
   static unsigned RecordIndex = 0;
-  ArrayRef<InstrProfRecord> Data = (*RecordIterator);
+
+  ArrayRef<InstrProfRecord> Data;
+  std::error_code EC = Index.getRecordsForNextKey(Data);
+  if (EC != instrprof_error::success)
+    return error(EC);
+
   Record = Data[RecordIndex++];
   if (RecordIndex >= Data.size()) {
-    ++RecordIterator;
+    Index.advanceToNextKey();
     RecordIndex = 0;
   }
   return success();
Index: lib/ProfileData/InstrProfWriter.cpp
===================================================================
--- lib/ProfileData/InstrProfWriter.cpp
+++ lib/ProfileData/InstrProfWriter.cpp
@@ -13,7 +13,6 @@
 //===----------------------------------------------------------------------===//
 
 #include "llvm/ProfileData/InstrProfWriter.h"
-#include "InstrProfIndexed.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/Support/EndianStream.h"
 #include "llvm/Support/OnDiskHashTable.h"
@@ -23,8 +22,8 @@
 namespace {
 class InstrProfRecordTrait {
 public:
-  typedef StringRef key_type;
-  typedef StringRef key_type_ref;
+  typedef uint64_t key_type;
+  typedef uint64_t key_type_ref;
 
   typedef const InstrProfWriter::CounterData *const data_type;
   typedef const InstrProfWriter::CounterData *const data_type_ref;
@@ -32,16 +31,14 @@
   typedef uint64_t hash_value_type;
   typedef uint64_t offset_type;
 
-  static hash_value_type ComputeHash(key_type_ref K) {
-    return IndexedInstrProf::ComputeHash(IndexedInstrProf::HashType, K);
-  }
+  static hash_value_type ComputeHash(key_type_ref K) { return K; }
 
   static std::pair<offset_type, offset_type>
   EmitKeyDataLength(raw_ostream &Out, key_type_ref K, data_type_ref V) {
     using namespace llvm::support;
     endian::Writer<little> LE(Out);
 
-    offset_type N = K.size();
+    offset_type N = sizeof(key_type_ref);
     LE.write<offset_type>(N);
 
     offset_type M = 0;
@@ -53,7 +50,9 @@
   }
 
   static void EmitKey(raw_ostream &Out, key_type_ref K, offset_type N){
-    Out.write(K.data(), N);
+    using namespace llvm::support;
+    endian::Writer<little> LE(Out);
+    LE.write<uint64_t>(K);
   }
 
   static void EmitData(raw_ostream &Out, key_type_ref, data_type_ref V,
@@ -75,7 +74,16 @@
 InstrProfWriter::addFunctionCounts(StringRef FunctionName,
                                    uint64_t FunctionHash,
                                    ArrayRef<uint64_t> Counters) {
-  auto &CounterData = FunctionData[FunctionName];
+  return addFunctionCounts(
+      IndexedInstrProf::ComputeHash(IndexedInstrProf::HashType, FunctionName),
+      FunctionHash, Counters);
+}
+
+std::error_code
+InstrProfWriter::addFunctionCounts(uint64_t FunctionNameKey,
+                                   uint64_t FunctionHash,
+                                   ArrayRef<uint64_t> Counters) {
+  auto &CounterData = FunctionData[FunctionNameKey];
 
   auto Where = CounterData.find(FunctionHash);
   if (Where == CounterData.end()) {
@@ -111,7 +119,7 @@
 
   // Populate the hash table generator.
   for (const auto &I : FunctionData)
-    Generator.insert(I.getKey(), &I.getValue());
+    Generator.insert(I.getFirst(), &I.getSecond());
 
   using namespace llvm::support;
   endian::Writer<little> LE(OS);
Index: lib/Transforms/Instrumentation/InstrProfiling.cpp
===================================================================
--- lib/Transforms/Instrumentation/InstrProfiling.cpp
+++ lib/Transforms/Instrumentation/InstrProfiling.cpp
@@ -14,8 +14,10 @@
 //===----------------------------------------------------------------------===//
 
 #include "llvm/Transforms/Instrumentation.h"
+#include "llvm/ProfileData/InstrProf.h"
 
 #include "llvm/ADT/Triple.h"
+#include "llvm/ADT/StringExtras.h"
 #include "llvm/IR/IRBuilder.h"
 #include "llvm/IR/IntrinsicInst.h"
 #include "llvm/IR/Module.h"
@@ -61,11 +63,6 @@
     return isMachO() ? "__DATA,__llvm_prf_cnts" : "__llvm_prf_cnts";
   }
 
-  /// Get the section name for the name variables.
-  StringRef getNameSection() const {
-    return isMachO() ? "__DATA,__llvm_prf_names" : "__llvm_prf_names";
-  }
-
   /// Get the section name for the profile data variables.
   StringRef getDataSection() const {
     return isMachO() ? "__DATA,__llvm_prf_data" : "__llvm_prf_data";
@@ -80,7 +77,8 @@
   void lowerIncrement(InstrProfIncrementInst *Inc);
 
   /// Set up the section and uses for coverage data and its references.
-  void lowerCoverageData(GlobalVariable *CoverageData);
+  void lowerCoverageData(GlobalVariable *CoverageData,
+                         GlobalVariable *CoverageNames);
 
   /// Get the region counters for an increment, creating them if necessary.
   ///
@@ -128,7 +126,9 @@
           MadeChange = true;
         }
   if (GlobalVariable *Coverage = M.getNamedGlobal("__llvm_coverage_mapping")) {
-    lowerCoverageData(Coverage);
+    GlobalVariable *CoverageNames = M.getNamedGlobal("__llvm_coverage_names");
+    assert(CoverageNames);
+    lowerCoverageData(Coverage, CoverageNames);
     MadeChange = true;
   }
   if (!MadeChange)
@@ -153,40 +153,46 @@
   Inc->eraseFromParent();
 }
 
-void InstrProfiling::lowerCoverageData(GlobalVariable *CoverageData) {
+void InstrProfiling::lowerCoverageData(GlobalVariable *CoverageData,
+                                       GlobalVariable *CoverageNames) {
   CoverageData->setSection(getCoverageSection());
   CoverageData->setAlignment(8);
 
-  Constant *Init = CoverageData->getInitializer();
-  // We're expecting { i32, i32, i32, i32, [n x { i8*, i32, i32 }], [m x i8] }
+  Constant *Init __attribute__((unused)) = CoverageData->getInitializer();
+  // We're expecting { i32, i32, i32, i32, [n x { i64, i32, i32, i64 }], [m x
+  // i8] }
   // for some C. If not, the frontend's given us something broken.
   assert(Init->getNumOperands() == 6 && "bad number of fields in coverage map");
   assert(isa<ConstantArray>(Init->getAggregateElement(4)) &&
          "invalid function list in coverage map");
-  ConstantArray *Records = cast<ConstantArray>(Init->getAggregateElement(4));
-  for (unsigned I = 0, E = Records->getNumOperands(); I < E; ++I) {
-    Constant *Record = Records->getOperand(I);
-    Value *V = const_cast<Value *>(Record->getOperand(0))->stripPointerCasts();
 
-    assert(isa<GlobalVariable>(V) && "Missing reference to function name");
-    GlobalVariable *Name = cast<GlobalVariable>(V);
+  ConstantArray *Names = cast<ConstantArray>(CoverageNames->getInitializer());
+
+  for (unsigned I = 0, E = Names->getNumOperands(); I < E; ++I) {
+    Constant *NC = Names->getOperand(I);
+
+    assert(isa<GlobalVariable>(NC) && "Missing reference to function name");
+    GlobalVariable *Name = cast<GlobalVariable>(NC);
 
     // If we have region counters for this name, we've already handled it.
     auto It = RegionCounters.find(Name);
     if (It != RegionCounters.end())
       continue;
 
-    // Move the name variable to the right section.
-    Name->setSection(getNameSection());
-    Name->setAlignment(1);
+    // FE never emits the function with the name, but it is referenced
+    // by coverage data. Force emitting the name.
+    // Reset Name variable's linkage
+    Name->setLinkage(GlobalValue::ExternalWeakLinkage);
+    // Mark the name variable as used so that it isn't stripped out.
+    UsedVars.push_back(Name);
   }
 }
 
 /// Get the name of a profiling variable for a particular function.
 static std::string getVarName(InstrProfIncrementInst *Inc, StringRef VarName) {
-  auto *Arr = cast<ConstantDataArray>(Inc->getName()->getInitializer());
-  StringRef Name = Arr->isCString() ? Arr->getAsCString() : Arr->getAsString();
-  return ("__llvm_profile_" + VarName + "_" + Name).str();
+  // TODO define a macro for __llvm_prf_nm_ prefix and its size
+  StringRef Name = Inc->getName()->getName().substr(strlen("__llvm_prf_nm_"));
+  return ("__llvm_prf_" + VarName + "_" + Name).str();
 }
 
 GlobalVariable *
@@ -196,17 +202,10 @@
   if (It != RegionCounters.end())
     return It->second;
 
-  // Move the name variable to the right section. Place them in a COMDAT group
-  // if the associated function is a COMDAT. This will make sure that
-  // only one copy of counters of the COMDAT function will be emitted after
-  // linking.
   Function *Fn = Inc->getParent()->getParent();
   Comdat *ProfileVarsComdat = nullptr;
   if (Fn->hasComdat())
     ProfileVarsComdat = M->getOrInsertComdat(StringRef(getVarName(Inc, "vars")));
-  Name->setSection(getNameSection());
-  Name->setAlignment(1);
-  Name->setComdat(ProfileVarsComdat);
 
   uint64_t NumCounters = Inc->getNumCounters()->getZExtValue();
   LLVMContext &Ctx = M->getContext();
@@ -215,7 +214,7 @@
   // Create the counters variable.
   auto *Counters = new GlobalVariable(*M, CounterTy, false, Name->getLinkage(),
                                       Constant::getNullValue(CounterTy),
-                                      getVarName(Inc, "counters"));
+                                      getVarName(Inc, "cnts"));
   Counters->setVisibility(Name->getVisibility());
   Counters->setSection(getCountersSection());
   Counters->setAlignment(8);
@@ -224,20 +223,20 @@
   RegionCounters[Inc->getName()] = Counters;
 
   // Create data variable.
-  auto *NameArrayTy = Name->getType()->getPointerElementType();
   auto *Int32Ty = Type::getInt32Ty(Ctx);
   auto *Int64Ty = Type::getInt64Ty(Ctx);
-  auto *Int8PtrTy = Type::getInt8PtrTy(Ctx);
   auto *Int64PtrTy = Type::getInt64PtrTy(Ctx);
 
-  Type *DataTypes[] = {Int32Ty, Int32Ty, Int64Ty, Int8PtrTy, Int64PtrTy};
+  auto FuncNameKey = IndexedInstrProf::ComputeHash(
+      IndexedInstrProf::HashType,
+      Inc->getName()->getName().substr(strlen("__llvm_prf_nm_")));
+  Type *DataTypes[] = {Int64Ty, Int64Ty, Int64PtrTy, Int32Ty};
   auto *DataTy = StructType::get(Ctx, makeArrayRef(DataTypes));
   Constant *DataVals[] = {
-      ConstantInt::get(Int32Ty, NameArrayTy->getArrayNumElements()),
-      ConstantInt::get(Int32Ty, NumCounters),
+      ConstantInt::get(Int64Ty, FuncNameKey),
       ConstantInt::get(Int64Ty, Inc->getHash()->getZExtValue()),
-      ConstantExpr::getBitCast(Name, Int8PtrTy),
-      ConstantExpr::getBitCast(Counters, Int64PtrTy)};
+      ConstantExpr::getBitCast(Counters, Int64PtrTy),
+      ConstantInt::get(Int32Ty, NumCounters)};
   auto *Data = new GlobalVariable(*M, DataTy, true, Name->getLinkage(),
                                   ConstantStruct::get(DataTy, DataVals),
                                   getVarName(Inc, "data"));
@@ -249,6 +248,11 @@
   // Mark the data variable as used so that it isn't stripped out.
   UsedVars.push_back(Data);
 
+  // Reset Name variable's linkage
+  Name->setLinkage(GlobalValue::ExternalWeakLinkage);
+  // Mark the name variable as used so that it isn't stripped out.
+  UsedVars.push_back(Name);
+
   return Counters;
 }
 
@@ -274,7 +278,8 @@
 
   IRBuilder<> IRB(BasicBlock::Create(M->getContext(), "", RegisterF));
   for (Value *Data : UsedVars)
-    IRB.CreateCall(RuntimeRegisterF, IRB.CreateBitCast(Data, VoidPtrTy));
+    if (!cast<GlobalVariable>(Data)->isDeclaration())
+      IRB.CreateCall(RuntimeRegisterF, IRB.CreateBitCast(Data, VoidPtrTy));
   IRB.CreateRetVoid();
 }
 
Index: lib/profile/InstrProfiling.h
===================================================================
--- lib/profile/InstrProfiling.h
+++ lib/profile/InstrProfiling.h
@@ -30,11 +30,10 @@
 #define PROFILE_HEADER_SIZE 7
 
 typedef struct __llvm_profile_data {
-  const uint32_t NameSize;
-  const uint32_t NumCounters;
+  const uint64_t FuncKey;
   const uint64_t FuncHash;
-  const char *const Name;
   uint64_t *const Counters;
+  const uint32_t NumCounters;
 } __llvm_profile_data;
 
 /*!
@@ -52,8 +51,6 @@
 
 const __llvm_profile_data *__llvm_profile_begin_data(void);
 const __llvm_profile_data *__llvm_profile_end_data(void);
-const char *__llvm_profile_begin_names(void);
-const char *__llvm_profile_end_names(void);
 uint64_t *__llvm_profile_begin_counters(void);
 uint64_t *__llvm_profile_end_counters(void);
 
Index: lib/profile/InstrProfiling.c
===================================================================
--- lib/profile/InstrProfiling.c
+++ lib/profile/InstrProfiling.c
@@ -36,7 +36,7 @@
 __attribute__((visibility("hidden")))
 uint64_t __llvm_profile_get_version(void) {
   /* This should be bumped any time the output format changes. */
-  return 1;
+  return 2;
 }
 
 __attribute__((visibility("hidden")))
Index: lib/profile/InstrProfilingBuffer.c
===================================================================
--- lib/profile/InstrProfilingBuffer.c
+++ lib/profile/InstrProfilingBuffer.c
@@ -18,28 +18,22 @@
   const __llvm_profile_data *DataEnd = __llvm_profile_end_data();
   const uint64_t *CountersBegin = __llvm_profile_begin_counters();
   const uint64_t *CountersEnd = __llvm_profile_end_counters();
-  const char *NamesBegin = __llvm_profile_begin_names();
-  const char *NamesEnd = __llvm_profile_end_names();
 
   return __llvm_profile_get_size_for_buffer_internal(
-      DataBegin, DataEnd, CountersBegin, CountersEnd, NamesBegin, NamesEnd);
+      DataBegin, DataEnd, CountersBegin, CountersEnd);
 }
 
 #define PROFILE_RANGE_SIZE(Range) (Range##End - Range##Begin)
 
-__attribute__((visibility("hidden")))
-uint64_t __llvm_profile_get_size_for_buffer_internal(
+__attribute__((visibility("hidden"))) uint64_t
+    __llvm_profile_get_size_for_buffer_internal(
         const __llvm_profile_data *DataBegin,
         const __llvm_profile_data *DataEnd, const uint64_t *CountersBegin,
-        const uint64_t *CountersEnd, const char *NamesBegin,
-        const char *NamesEnd) {
+        const uint64_t *CountersEnd) {
   /* Match logic in __llvm_profile_write_buffer(). */
-  const uint64_t NamesSize = PROFILE_RANGE_SIZE(Names) * sizeof(char);
-  const uint64_t Padding = sizeof(uint64_t) - NamesSize % sizeof(uint64_t);
   return sizeof(uint64_t) * PROFILE_HEADER_SIZE +
-      PROFILE_RANGE_SIZE(Data) * sizeof(__llvm_profile_data) +
-      PROFILE_RANGE_SIZE(Counters) * sizeof(uint64_t) +
-      NamesSize + Padding;
+         PROFILE_RANGE_SIZE(Data) * sizeof(__llvm_profile_data) +
+         PROFILE_RANGE_SIZE(Counters) * sizeof(uint64_t);
 }
 
 __attribute__((visibility("hidden")))
@@ -51,19 +45,15 @@
   const __llvm_profile_data *DataEnd = __llvm_profile_end_data();
   const uint64_t *CountersBegin = __llvm_profile_begin_counters();
   const uint64_t *CountersEnd   = __llvm_profile_end_counters();
-  const char *NamesBegin = __llvm_profile_begin_names();
-  const char *NamesEnd   = __llvm_profile_end_names();
 
   return __llvm_profile_write_buffer_internal(Buffer, DataBegin, DataEnd,
-                                              CountersBegin, CountersEnd,
-                                              NamesBegin, NamesEnd);
+                                              CountersBegin, CountersEnd);
 }
 
-__attribute__((visibility("hidden")))
-int __llvm_profile_write_buffer_internal(
+__attribute__((visibility("hidden"))) int __llvm_profile_write_buffer_internal(
     char *Buffer, const __llvm_profile_data *DataBegin,
     const __llvm_profile_data *DataEnd, const uint64_t *CountersBegin,
-    const uint64_t *CountersEnd, const char *NamesBegin, const char *NamesEnd) {
+    const uint64_t *CountersEnd) {
   /* Match logic in __llvm_profile_get_size_for_buffer().
    * Match logic in __llvm_profile_write_file().
    */
@@ -71,11 +61,6 @@
   /* Calculate size of sections. */
   const uint64_t DataSize = DataEnd - DataBegin;
   const uint64_t CountersSize = CountersEnd - CountersBegin;
-  const uint64_t NamesSize = NamesEnd - NamesBegin;
-  const uint64_t Padding = sizeof(uint64_t) - NamesSize % sizeof(uint64_t);
-
-  /* Enough zeroes for padding. */
-  const char Zeroes[sizeof(uint64_t)] = {0};
 
   /* Create the header. */
   uint64_t Header[PROFILE_HEADER_SIZE];
@@ -83,9 +68,7 @@
   Header[1] = __llvm_profile_get_version();
   Header[2] = DataSize;
   Header[3] = CountersSize;
-  Header[4] = NamesSize;
-  Header[5] = (uintptr_t)CountersBegin;
-  Header[6] = (uintptr_t)NamesBegin;
+  Header[4] = (uintptr_t)CountersBegin;
 
   /* Write the data. */
 #define UPDATE_memcpy(Data, Size) \
@@ -96,8 +79,6 @@
   UPDATE_memcpy(Header,  PROFILE_HEADER_SIZE * sizeof(uint64_t));
   UPDATE_memcpy(DataBegin,     DataSize      * sizeof(__llvm_profile_data));
   UPDATE_memcpy(CountersBegin, CountersSize  * sizeof(uint64_t));
-  UPDATE_memcpy(NamesBegin,    NamesSize     * sizeof(char));
-  UPDATE_memcpy(Zeroes,        Padding       * sizeof(char));
 #undef UPDATE_memcpy
 
   return 0;
Index: lib/profile/InstrProfilingFile.c
===================================================================
--- lib/profile/InstrProfilingFile.c
+++ lib/profile/InstrProfilingFile.c
@@ -22,17 +22,10 @@
   const __llvm_profile_data *DataEnd = __llvm_profile_end_data();
   const uint64_t *CountersBegin = __llvm_profile_begin_counters();
   const uint64_t *CountersEnd   = __llvm_profile_end_counters();
-  const char *NamesBegin = __llvm_profile_begin_names();
-  const char *NamesEnd   = __llvm_profile_end_names();
 
   /* Calculate size of sections. */
   const uint64_t DataSize = DataEnd - DataBegin;
   const uint64_t CountersSize = CountersEnd - CountersBegin;
-  const uint64_t NamesSize = NamesEnd - NamesBegin;
-  const uint64_t Padding = sizeof(uint64_t) - NamesSize % sizeof(uint64_t);
-
-  /* Enough zeroes for padding. */
-  const char Zeroes[sizeof(uint64_t)] = {0};
 
   /* Create the header. */
   uint64_t Header[PROFILE_HEADER_SIZE];
@@ -40,9 +33,9 @@
   Header[1] = __llvm_profile_get_version();
   Header[2] = DataSize;
   Header[3] = CountersSize;
-  Header[4] = NamesSize;
+  Header[4] = 0; /* NameSize unused */
   Header[5] = (uintptr_t)CountersBegin;
-  Header[6] = (uintptr_t)NamesBegin;
+  Header[6] = 0; /* NamesBegin unused */
 
   /* Write the data. */
 #define CHECK_fwrite(Data, Size, Length, File) \
@@ -50,8 +43,6 @@
   CHECK_fwrite(Header,        sizeof(uint64_t), PROFILE_HEADER_SIZE, File);
   CHECK_fwrite(DataBegin,     sizeof(__llvm_profile_data), DataSize, File);
   CHECK_fwrite(CountersBegin, sizeof(uint64_t), CountersSize, File);
-  CHECK_fwrite(NamesBegin,    sizeof(char), NamesSize, File);
-  CHECK_fwrite(Zeroes,        sizeof(char), Padding, File);
 #undef CHECK_fwrite
 
   return 0;
Index: lib/profile/InstrProfilingInternal.h
===================================================================
--- lib/profile/InstrProfilingInternal.h
+++ lib/profile/InstrProfilingInternal.h
@@ -20,8 +20,7 @@
  */
 uint64_t __llvm_profile_get_size_for_buffer_internal(
     const __llvm_profile_data *DataBegin, const __llvm_profile_data *DataEnd,
-    const uint64_t *CountersBegin, const uint64_t *CountersEnd,
-    const char *NamesBegin, const char *NamesEnd);
+    const uint64_t *CountersBegin, const uint64_t *CountersEnd);
 
 /*!
  * \brief Write instrumentation data to the given buffer, given explicit
@@ -32,9 +31,10 @@
  * \pre \c Buffer is the start of a buffer at least as big as \a
  * __llvm_profile_get_size_for_buffer_internal().
  */
-int __llvm_profile_write_buffer_internal(
-    char *Buffer, const __llvm_profile_data *DataBegin,
-    const __llvm_profile_data *DataEnd, const uint64_t *CountersBegin,
-    const uint64_t *CountersEnd, const char *NamesBegin, const char *NamesEnd);
+int __llvm_profile_write_buffer_internal(char *Buffer,
+                                         const __llvm_profile_data *DataBegin,
+                                         const __llvm_profile_data *DataEnd,
+                                         const uint64_t *CountersBegin,
+                                         const uint64_t *CountersEnd);
 
 #endif
Index: lib/profile/InstrProfilingPlatformDarwin.c
===================================================================
--- lib/profile/InstrProfilingPlatformDarwin.c
+++ lib/profile/InstrProfilingPlatformDarwin.c
@@ -16,10 +16,6 @@
 __attribute__((visibility("hidden")))
 extern __llvm_profile_data DataEnd   __asm("section$end$__DATA$__llvm_prf_data");
 __attribute__((visibility("hidden")))
-extern char NamesStart __asm("section$start$__DATA$__llvm_prf_names");
-__attribute__((visibility("hidden")))
-extern char NamesEnd   __asm("section$end$__DATA$__llvm_prf_names");
-__attribute__((visibility("hidden")))
 extern uint64_t CountersStart __asm("section$start$__DATA$__llvm_prf_cnts");
 __attribute__((visibility("hidden")))
 extern uint64_t CountersEnd   __asm("section$end$__DATA$__llvm_prf_cnts");
@@ -33,10 +29,6 @@
   return &DataEnd;
 }
 __attribute__((visibility("hidden")))
-const char *__llvm_profile_begin_names(void) { return &NamesStart; }
-__attribute__((visibility("hidden")))
-const char *__llvm_profile_end_names(void) { return &NamesEnd; }
-__attribute__((visibility("hidden")))
 uint64_t *__llvm_profile_begin_counters(void) { return &CountersStart; }
 __attribute__((visibility("hidden")))
 uint64_t *__llvm_profile_end_counters(void) { return &CountersEnd; }
Index: lib/profile/InstrProfilingPlatformOther.c
===================================================================
--- lib/profile/InstrProfilingPlatformOther.c
+++ lib/profile/InstrProfilingPlatformOther.c
@@ -14,8 +14,6 @@
 
 static const __llvm_profile_data *DataFirst = NULL;
 static const __llvm_profile_data *DataLast = NULL;
-static const char *NamesFirst = NULL;
-static const char *NamesLast = NULL;
 static uint64_t *CountersFirst = NULL;
 static uint64_t *CountersLast = NULL;
 
@@ -33,8 +31,6 @@
   if (!DataFirst) {
     DataFirst = Data;
     DataLast = Data + 1;
-    NamesFirst = Data->Name;
-    NamesLast = Data->Name + Data->NameSize;
     CountersFirst = Data->Counters;
     CountersLast = Data->Counters + Data->NumCounters;
     return;
@@ -43,14 +39,12 @@
 #define UPDATE_FIRST(First, New) \
   First = New < First ? New : First
   UPDATE_FIRST(DataFirst, Data);
-  UPDATE_FIRST(NamesFirst, Data->Name);
   UPDATE_FIRST(CountersFirst, Data->Counters);
 #undef UPDATE_FIRST
 
 #define UPDATE_LAST(Last, New) \
   Last = New > Last ? New : Last
   UPDATE_LAST(DataLast, Data + 1);
-  UPDATE_LAST(NamesLast, Data->Name + Data->NameSize);
   UPDATE_LAST(CountersLast, Data->Counters + Data->NumCounters);
 #undef UPDATE_LAST
 }
@@ -64,10 +58,6 @@
   return DataLast;
 }
 __attribute__((visibility("hidden")))
-const char *__llvm_profile_begin_names(void) { return NamesFirst; }
-__attribute__((visibility("hidden")))
-const char *__llvm_profile_end_names(void) { return NamesLast; }
-__attribute__((visibility("hidden")))
 uint64_t *__llvm_profile_begin_counters(void) { return CountersFirst; }
 __attribute__((visibility("hidden")))
 uint64_t *__llvm_profile_end_counters(void) { return CountersLast; }
Index: test/Instrumentation/InstrProfiling/PR23499.ll
===================================================================
--- test/Instrumentation/InstrProfiling/PR23499.ll
+++ test/Instrumentation/InstrProfiling/PR23499.ll
@@ -1,21 +1,22 @@
 ;; Check that data associated with linkonce odr functions are placed in
 ;; the same comdat section as their associated function.
 
-; RUN: opt < %s -mtriple=x86_64-apple-macosx10.10.0 -instrprof -S | FileCheck %s
-; RUN: opt < %s -mtriple=x86_64-unknown-linux -instrprof -S | FileCheck %s
+; RUN: opt < %s -mtriple=x86_64-apple-macosx10.10.0 -instrprof -S | FileCheck %s -check-prefix=MACHO
+; RUN: opt < %s -mtriple=x86_64-unknown-linux -instrprof -S | FileCheck %s -check-prefix=ELF
 
 $_Z3barIvEvv = comdat any
 
-@__llvm_profile_name__Z3barIvEvv = linkonce_odr hidden constant [11 x i8] c"_Z3barIvEvv", align 1
+@__llvm_prf_nm__Z3barIvEvv = linkonce_odr hidden constant [11 x i8] c"_Z3barIvEvv", align 1
 
-; CHECK: @__llvm_profile_name__Z3barIvEvv = linkonce_odr hidden constant [11 x i8] c"_Z3barIvEvv", section "{{.*}}__llvm_prf_names", comdat($__llvm_profile_vars__Z3barIvEvv), align 1
-; CHECK: @__llvm_profile_counters__Z3barIvEvv = linkonce_odr hidden global [1 x i64] zeroinitializer, section "{{.*}}__llvm_prf_cnts", comdat($__llvm_profile_vars__Z3barIvEvv), align 8
-; CHECK: @__llvm_profile_data__Z3barIvEvv = linkonce_odr hidden constant { i32, i32, i64, i8*, i64* } { i32 11, i32 1, i64 0, i8* getelementptr inbounds ([11 x i8], [11 x i8]* @__llvm_profile_name__Z3barIvEvv, i32 0, i32 0), i64* getelementptr inbounds ([1 x i64], [1 x i64]* @__llvm_profile_counters__Z3barIvEvv, i32 0, i32 0) }, section "{{.*}}__llvm_prf_data", comdat($__llvm_profile_vars__Z3barIvEvv), align 8
+; CHECK: @__llvm_prf_nm__Z3barIvEvv = extern_weak hidden constant [11 x i8] c"_Z3barIvEvv", align 1
+; CHECK: @__llvm_prf_cnts__Z3barIvEvv = linkonce_odr hidden global [1 x i64] zeroinitializer, section "{{.*}}__llvm_prf_cnts", comdat($__llvm_prf_vars__Z3barIvEvv), align 8
+; ELF: @__llvm_prf_data__Z3barIvEvv = linkonce_odr hidden constant { i64, i64, i64*, i32 } { i64 4947693190065689389, i64 0, i64* getelementptr inbounds ([1 x i64], [1 x i64]* @__llvm_prf_cnts__Z3barIvEvv, i32 0, i32 0), i32 1 }, section "__llvm_prf_data", comdat($__llvm_prf_vars__Z3barIvEvv), align 8
+; MACHO: @__llvm_prf_data__Z3barIvEvv = linkonce_odr hidden constant { i64, i64, i64*, i32 } { i64 4947693190065689389, i64 0, i64* getelementptr inbounds ([1 x i64], [1 x i64]* @__llvm_prf_cnts__Z3barIvEvv, i32 0, i32 0), i32 1 }, section "__DATA,__llvm_prf_data", comdat($__llvm_prf_vars__Z3barIvEvv), align 8
 
 declare void @llvm.instrprof.increment(i8*, i64, i32, i32) #1
 
 define linkonce_odr void @_Z3barIvEvv() comdat {
 entry:
-  call void @llvm.instrprof.increment(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @__llvm_profile_name__Z3barIvEvv, i32 0, i32 0), i64 0, i32 1, i32 0)
+  call void @llvm.instrprof.increment(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @__llvm_prf_nm__Z3barIvEvv, i32 0, i32 0), i64 0, i32 1, i32 0)
   ret void
 }
Index: test/Instrumentation/InstrProfiling/linkage.ll
===================================================================
--- test/Instrumentation/InstrProfiling/linkage.ll
+++ test/Instrumentation/InstrProfiling/linkage.ll
@@ -3,36 +3,36 @@
 ; RUN: opt < %s -mtriple=x86_64-apple-macosx10.10.0 -instrprof -S | FileCheck %s
 ; RUN: opt < %s -mtriple=x86_64-unknown-linux -instrprof -S | FileCheck %s
 
-@__llvm_profile_name_foo = hidden constant [3 x i8] c"foo"
-@__llvm_profile_name_foo_weak = weak hidden constant [8 x i8] c"foo_weak"
-@"__llvm_profile_name_linkage.ll:foo_internal" = internal constant [23 x i8] c"linkage.ll:foo_internal"
-@__llvm_profile_name_foo_inline = linkonce_odr hidden constant [10 x i8] c"foo_inline"
+@__llvm_prf_nm_foo = hidden constant [3 x i8] c"foo"
+@__llvm_prf_nm_foo_weak = weak hidden constant [8 x i8] c"foo_weak"
+@"__llvm_prf_nm_linkage.ll:foo_internal" = internal constant [23 x i8] c"linkage.ll:foo_internal"
+@__llvm_prf_nm_foo_inline = linkonce_odr hidden constant [10 x i8] c"foo_inline"
 
-; CHECK: @__llvm_profile_counters_foo = hidden global
-; CHECK: @__llvm_profile_data_foo = hidden constant
+; CHECK: @__llvm_prf_cnts_foo = hidden global
+; CHECK: @__llvm_prf_data_foo = hidden constant
 define void @foo() {
-  call void @llvm.instrprof.increment(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @__llvm_profile_name_foo, i32 0, i32 0), i64 0, i32 1, i32 0)
+  call void @llvm.instrprof.increment(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @__llvm_prf_nm_foo, i32 0, i32 0), i64 0, i32 1, i32 0)
   ret void
 }
 
-; CHECK: @__llvm_profile_counters_foo_weak = weak hidden global
-; CHECK: @__llvm_profile_data_foo_weak = weak hidden constant
+; CHECK: @__llvm_prf_cnts_foo_weak = weak hidden global
+; CHECK: @__llvm_prf_data_foo_weak = weak hidden constant
 define weak void @foo_weak() {
-  call void @llvm.instrprof.increment(i8* getelementptr inbounds ([8 x i8], [8 x i8]* @__llvm_profile_name_foo_weak, i32 0, i32 0), i64 0, i32 1, i32 0)
+  call void @llvm.instrprof.increment(i8* getelementptr inbounds ([8 x i8], [8 x i8]* @__llvm_prf_nm_foo_weak, i32 0, i32 0), i64 0, i32 1, i32 0)
   ret void
 }
 
-; CHECK: @"__llvm_profile_counters_linkage.ll:foo_internal" = internal global
-; CHECK: @"__llvm_profile_data_linkage.ll:foo_internal" = internal constant
+; CHECK: @"__llvm_prf_cnts_linkage.ll:foo_internal" = internal global
+; CHECK: @"__llvm_prf_data_linkage.ll:foo_internal" = internal constant
 define internal void @foo_internal() {
-  call void @llvm.instrprof.increment(i8* getelementptr inbounds ([23 x i8], [23 x i8]* @"__llvm_profile_name_linkage.ll:foo_internal", i32 0, i32 0), i64 0, i32 1, i32 0)
+  call void @llvm.instrprof.increment(i8* getelementptr inbounds ([23 x i8], [23 x i8]* @"__llvm_prf_nm_linkage.ll:foo_internal", i32 0, i32 0), i64 0, i32 1, i32 0)
   ret void
 }
 
-; CHECK: @__llvm_profile_counters_foo_inline = linkonce_odr hidden global
-; CHECK: @__llvm_profile_data_foo_inline = linkonce_odr hidden constant
+; CHECK: @__llvm_prf_cnts_foo_inline = linkonce_odr hidden global
+; CHECK: @__llvm_prf_data_foo_inline = linkonce_odr hidden constant
 define linkonce_odr void @foo_inline() {
-  call void @llvm.instrprof.increment(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @__llvm_profile_name_foo_inline, i32 0, i32 0), i64 0, i32 1, i32 0)
+  call void @llvm.instrprof.increment(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @__llvm_prf_nm_foo_inline, i32 0, i32 0), i64 0, i32 1, i32 0)
   ret void
 }
 
Index: test/Instrumentation/InstrProfiling/platform.ll
===================================================================
--- test/Instrumentation/InstrProfiling/platform.ll
+++ test/Instrumentation/InstrProfiling/platform.ll
@@ -3,17 +3,17 @@
 ; RUN: opt < %s -mtriple=x86_64-apple-macosx10.10.0 -instrprof -S | FileCheck %s -check-prefix=MACHO
 ; RUN: opt < %s -mtriple=x86_64-unknown-linux -instrprof -S | FileCheck %s -check-prefix=ELF
 
-@__llvm_profile_name_foo = hidden constant [3 x i8] c"foo"
-; MACHO: @__llvm_profile_name_foo = hidden constant [3 x i8] c"foo", section "__DATA,__llvm_prf_names", align 1
-; ELF: @__llvm_profile_name_foo = hidden constant [3 x i8] c"foo", section "__llvm_prf_names", align 1
+@__llvm_prf_nm_foo = hidden constant [3 x i8] c"foo"
+; MACHO: @__llvm_prf_nm_foo = extern_weak hidden constant [3 x i8] c"foo"
+; ELF: @__llvm_prf_nm_foo = extern_weak hidden constant [3 x i8] c"foo"
 
-; MACHO: @__llvm_profile_counters_foo = hidden global [1 x i64] zeroinitializer, section "__DATA,__llvm_prf_cnts", align 8
-; ELF: @__llvm_profile_counters_foo = hidden global [1 x i64] zeroinitializer, section "__llvm_prf_cnts", align 8
+; MACHO: @__llvm_prf_cnts_foo = hidden global [1 x i64] zeroinitializer, section "__DATA,__llvm_prf_cnts", align 8
+; ELF: @__llvm_prf_cnts_foo = hidden global [1 x i64] zeroinitializer, section "__llvm_prf_cnts", align 8
 
-; MACHO: @__llvm_profile_data_foo = hidden constant {{.*}}, section "__DATA,__llvm_prf_data", align 8
-; ELF: @__llvm_profile_data_foo = hidden constant {{.*}}, section "__llvm_prf_data", align 8
+; MACHO: @__llvm_prf_data_foo = hidden constant {{.*}}, section "__DATA,__llvm_prf_data", align 8
+; ELF: @__llvm_prf_data_foo = hidden constant {{.*}}, section "__llvm_prf_data", align 8
 define void @foo() {
-  call void @llvm.instrprof.increment(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @__llvm_profile_name_foo, i32 0, i32 0), i64 0, i32 1, i32 0)
+  call void @llvm.instrprof.increment(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @__llvm_prf_nm_foo, i32 0, i32 0), i64 0, i32 1, i32 0)
   ret void
 }
 
Index: test/Instrumentation/InstrProfiling/profiling.ll
===================================================================
--- test/Instrumentation/InstrProfiling/profiling.ll
+++ test/Instrumentation/InstrProfiling/profiling.ll
@@ -2,37 +2,37 @@
 
 target triple = "x86_64-apple-macosx10.10.0"
 
-@__llvm_profile_name_foo = hidden constant [3 x i8] c"foo"
-; CHECK: @__llvm_profile_name_foo = hidden constant [3 x i8] c"foo", section "__DATA,__llvm_prf_names", align 1
-@__llvm_profile_name_bar = hidden constant [4 x i8] c"bar\00"
-; CHECK: @__llvm_profile_name_bar = hidden constant [4 x i8] c"bar\00", section "__DATA,__llvm_prf_names", align 1
-@baz_prof_name = hidden constant [3 x i8] c"baz"
-; CHECK: @baz_prof_name = hidden constant [3 x i8] c"baz", section "__DATA,__llvm_prf_names", align 1
+@__llvm_prf_nm_foo = hidden constant [3 x i8] c"foo"
+; CHECK: @__llvm_prf_nm_foo = extern_weak hidden constant [3 x i8] c"foo"
+@__llvm_prf_nm_bar = hidden constant [4 x i8] c"bar\00"
+; CHECK: @__llvm_prf_nm_bar = extern_weak hidden constant [4 x i8] c"bar\00"
+@__llvm_prf_nm_baz = hidden constant [3 x i8] c"baz"
+; CHECK: @__llvm_prf_nm_baz = extern_weak hidden constant [3 x i8] c"baz"
 
-; CHECK: @__llvm_profile_counters_foo = hidden global [1 x i64] zeroinitializer, section "__DATA,__llvm_prf_cnts", align 8
-; CHECK: @__llvm_profile_data_foo = hidden constant {{.*}}, section "__DATA,__llvm_prf_data", align 8
+; CHECK: @__llvm_prf_cnts_foo = hidden global [1 x i64] zeroinitializer, section "__DATA,__llvm_prf_cnts", align 8
+; CHECK: @__llvm_prf_data_foo = hidden constant {{.*}}, section "__DATA,__llvm_prf_data", align 8
 define void @foo() {
-  call void @llvm.instrprof.increment(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @__llvm_profile_name_foo, i32 0, i32 0), i64 0, i32 1, i32 0)
+  call void @llvm.instrprof.increment(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @__llvm_prf_nm_foo, i32 0, i32 0), i64 0, i32 1, i32 0)
   ret void
 }
 
-; CHECK: @__llvm_profile_counters_bar = hidden global [1 x i64] zeroinitializer, section "__DATA,__llvm_prf_cnts", align 8
-; CHECK: @__llvm_profile_data_bar = hidden constant {{.*}}, section "__DATA,__llvm_prf_data", align 8
+; CHECK: @__llvm_prf_cnts_bar = hidden global [1 x i64] zeroinitializer, section "__DATA,__llvm_prf_cnts", align 8
+; CHECK: @__llvm_prf_data_bar = hidden constant {{.*}}, section "__DATA,__llvm_prf_data", align 8
 define void @bar() {
-  call void @llvm.instrprof.increment(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @__llvm_profile_name_bar, i32 0, i32 0), i64 0, i32 1, i32 0)
+  call void @llvm.instrprof.increment(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @__llvm_prf_nm_bar, i32 0, i32 0), i64 0, i32 1, i32 0)
   ret void
 }
 
-; CHECK: @__llvm_profile_counters_baz = hidden global [3 x i64] zeroinitializer, section "__DATA,__llvm_prf_cnts", align 8
-; CHECK: @__llvm_profile_data_baz = hidden constant {{.*}}, section "__DATA,__llvm_prf_data", align 8
+; CHECK: @__llvm_prf_cnts_baz = hidden global [3 x i64] zeroinitializer, section "__DATA,__llvm_prf_cnts", align 8
+; CHECK: @__llvm_prf_data_baz = hidden constant {{.*}}, section "__DATA,__llvm_prf_data", align 8
 define void @baz() {
-  call void @llvm.instrprof.increment(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @baz_prof_name, i32 0, i32 0), i64 0, i32 3, i32 0)
-  call void @llvm.instrprof.increment(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @baz_prof_name, i32 0, i32 0), i64 0, i32 3, i32 1)
-  call void @llvm.instrprof.increment(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @baz_prof_name, i32 0, i32 0), i64 0, i32 3, i32 2)
+  call void @llvm.instrprof.increment(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @__llvm_prf_nm_baz, i32 0, i32 0), i64 0, i32 3, i32 0)
+  call void @llvm.instrprof.increment(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @__llvm_prf_nm_baz, i32 0, i32 0), i64 0, i32 3, i32 1)
+  call void @llvm.instrprof.increment(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @__llvm_prf_nm_baz, i32 0, i32 0), i64 0, i32 3, i32 2)
   ret void
 }
 
 declare void @llvm.instrprof.increment(i8*, i64, i32, i32)
 
 ; CHECK: @__llvm_profile_runtime = external global i32
-; CHECK: @llvm.used = appending global {{.*}} @__llvm_profile_data_foo {{.*}} @__llvm_profile_data_bar {{.*}} @__llvm_profile_data_baz {{.*}} section "llvm.metadata"
+; CHECK: @llvm.used = appending global {{.*}} @__llvm_prf_data_foo {{.*}} @__llvm_prf_data_bar {{.*}} @__llvm_prf_data_baz {{.*}} section "llvm.metadata"
Index: test/tools/llvm-profdata/c-general.test
===================================================================
--- test/tools/llvm-profdata/c-general.test
+++ test/tools/llvm-profdata/c-general.test
@@ -10,15 +10,15 @@
 REGENERATE: $ LLVM_PROFILE_FILE=$TESTDIR/Inputs/c-general.profraw ./a.out
 
 RUN: llvm-profdata show %p/Inputs/c-general.profraw -o - | FileCheck %s -check-prefix=CHECK
-RUN: llvm-profdata show %p/Inputs/c-general.profraw -o - --function=switches | FileCheck %s -check-prefix=SWITCHES -check-prefix=CHECK
+RUN: llvm-profdata show %p/Inputs/c-general.profraw -o - -instr-binary=%p/Inputs/c-general.bin --function=switches | FileCheck %s -check-prefix=SWITCHES -check-prefix=CHECK
 
 SWITCHES-LABEL: Counters:
 SWITCHES-NEXT:   switches:
-SWITCHES-NEXT:     Hash: 0x0000000000000013
+SWITCHES-NEXT:     Hash: 0x2618e4f23f2e8daa
 SWITCHES-NEXT:     Counters: 19
 SWITCHES-NEXT:     Function count: 1
 SWITCHES-LABEL: Functions shown: 1
 
-CHECK-LABEL: Total functions: 11
+CHECK-LABEL: Total functions: 12
 CHECK-NEXT: Maximum function count: 1
 CHECK-NEXT: Maximum internal block count: 100
Index: test/tools/llvm-profdata/general.proftext
===================================================================
--- test/tools/llvm-profdata/general.proftext
+++ test/tools/llvm-profdata/general.proftext
@@ -50,12 +50,6 @@
 # NOSUCHFUNC-NOT: Counters:
 # NOSUCHFUNC: Functions shown: 0
 
-# RUN: llvm-profdata show %t.profdata --function _ | FileCheck %s -check-prefix=SOMEFUNCS
-# SOMEFUNCS: Counters:
-# SOMEFUNCS: function_count_only:
-# SOMEFUNCS: large_numbers:
-# SOMEFUNCS: Functions shown: 3
-
 # RUN: llvm-profdata show %t.profdata | FileCheck %s -check-prefix=SUMMARY
 # SUMMARY-NOT: Counters:
 # SUMMARY-NOT: Functions shown:
Index: test/tools/llvm-profdata/multiple-inputs.test
===================================================================
--- test/tools/llvm-profdata/multiple-inputs.test
+++ test/tools/llvm-profdata/multiple-inputs.test
@@ -4,7 +4,6 @@
 RUN: llvm-profdata show %t -all-functions -counts | FileCheck %s --check-prefix=FOO3
 RUN: llvm-profdata merge %p/Inputs/foo3-2.proftext %p/Inputs/foo3-1.proftext -o %t
 RUN: llvm-profdata show %t -all-functions -counts | FileCheck %s --check-prefix=FOO3
-FOO3: foo:
 FOO3: Counters: 3
 FOO3: Function count: 8
 FOO3: Block counts: [7, 6]
@@ -14,7 +13,6 @@
 
 RUN: llvm-profdata merge %p/Inputs/empty.proftext %p/Inputs/foo3-1.proftext -o %t
 RUN: llvm-profdata show %t -all-functions -counts | FileCheck %s --check-prefix=FOO3EMPTY
-FOO3EMPTY: foo:
 FOO3EMPTY: Counters: 3
 FOO3EMPTY: Function count: 1
 FOO3EMPTY: Block counts: [2, 3]
@@ -24,11 +22,9 @@
 
 RUN: llvm-profdata merge %p/Inputs/foo3-1.proftext %p/Inputs/foo3bar3-1.proftext -o %t
 RUN: llvm-profdata show %t -all-functions -counts | FileCheck %s --check-prefix=FOO3FOO3BAR3
-FOO3FOO3BAR3: foo:
 FOO3FOO3BAR3: Counters: 3
 FOO3FOO3BAR3: Function count: 3
 FOO3FOO3BAR3: Block counts: [5, 8]
-FOO3FOO3BAR3: bar:
 FOO3FOO3BAR3: Counters: 3
 FOO3FOO3BAR3: Function count: 7
 FOO3FOO3BAR3: Block counts: [11, 13]
@@ -38,11 +34,9 @@
 
 RUN: llvm-profdata merge %p/Inputs/foo3-1.proftext %p/Inputs/bar3-1.proftext -o %t
 RUN: llvm-profdata show %t -all-functions -counts | FileCheck %s --check-prefix=DISJOINT
-DISJOINT: foo:
 DISJOINT: Counters: 3
 DISJOINT: Function count: 1
 DISJOINT: Block counts: [2, 3]
-DISJOINT: bar:
 DISJOINT: Counters: 3
 DISJOINT: Function count: 1
 DISJOINT: Block counts: [2, 3]
Index: tools/llvm-profdata/llvm-profdata.cpp
===================================================================
--- tools/llvm-profdata/llvm-profdata.cpp
+++ tools/llvm-profdata/llvm-profdata.cpp
@@ -13,6 +13,8 @@
 
 #include "llvm/ADT/StringRef.h"
 #include "llvm/IR/LLVMContext.h"
+#include "llvm/Object/MachOUniversal.h"
+#include "llvm/Object/ObjectFile.h"
 #include "llvm/ProfileData/InstrProfReader.h"
 #include "llvm/ProfileData/InstrProfWriter.h"
 #include "llvm/ProfileData/SampleProfReader.h"
@@ -28,6 +30,7 @@
 #include "llvm/Support/raw_ostream.h"
 
 using namespace llvm;
+using namespace object;
 
 static void exitWithError(const Twine &Message, StringRef Whence = "") {
   errs() << "error: ";
@@ -60,7 +63,7 @@
     auto Reader = std::move(ReaderOrErr.get());
     for (const auto &I : *Reader)
       if (std::error_code EC =
-              Writer.addFunctionCounts(I.Name, I.Hash, I.Counts))
+              Writer.addFunctionCounts(I.NameKey, I.Hash, I.Counts))
         errs() << Filename << ": " << I.Name << ": " << EC.message() << "\n";
     if (Reader->hasError())
       exitWithError(Reader->getError().message(), Filename);
@@ -133,7 +136,52 @@
   return 0;
 }
 
-static int showInstrProfile(std::string Filename, bool ShowCounts,
+static void populateSymtab(std::string binFilename, std::string Arch,
+                           std::unique_ptr<ProfSymtab> &ProfSyms) {
+  if (binFilename.empty())
+    return;
+  auto Buf = MemoryBuffer::getFileOrSTDIN(binFilename);
+  if (Buf.getError()) {
+    errs() << "warning: -instr-binary specifies an invalid file\n";
+    return;
+  }
+
+  MemoryBufferRef ObjectBuffer = Buf.get()->getMemBufferRef();
+  auto BinOrErr = object::createBinary(ObjectBuffer);
+  if (BinOrErr.getError()) {
+    errs() << "warning: -instr-binary specifies an invalid object file\n";
+    return;
+  }
+  auto Bin = std::move(BinOrErr.get());
+  std::unique_ptr<ObjectFile> OF;
+  if (auto *Universal = dyn_cast<object::MachOUniversalBinary>(Bin.get())) {
+    // If we have a universal binary, try to look up the object for the
+    // appropriate architecture.
+    auto ObjectFileOrErr = Universal->getObjectForArch(Arch);
+    if (std::error_code EC = ObjectFileOrErr.getError()) {
+      errs() << "warning: -instr-binary specifies an invalid file\n";
+      return;
+    }
+    OF = std::move(ObjectFileOrErr.get());
+  } else if (isa<object::ObjectFile>(Bin.get())) {
+    // For any other object file, upcast and take ownership.
+    OF.reset(cast<object::ObjectFile>(Bin.release()));
+    // If we've asked for a particular arch, make sure they match.
+    if (!Arch.empty() && OF->getArch() != Triple(Arch).getArch()) {
+      errs() << "warning: -instr-binary specifies an invalid file\n";
+      return;
+    }
+  } else {
+    // We can only handle object files.
+    errs() << "warning: -instr-binary specifies an invalid file\n";
+    return;
+  }
+
+  ProfSyms.reset(new ProfSymtab(OF->symbols()));
+}
+
+static int showInstrProfile(std::string Filename, std::string binFilename,
+                            std::string Arch, bool ShowCounts,
                             bool ShowAllFunctions, std::string ShowFunction,
                             raw_fd_ostream &OS) {
   auto ReaderOrErr = InstrProfReader::create(Filename);
@@ -141,12 +189,23 @@
     exitWithError(EC.message(), Filename);
 
   auto Reader = std::move(ReaderOrErr.get());
+  std::unique_ptr<ProfSymtab> ProfSyms;
+  populateSymtab(binFilename, Arch, ProfSyms);
   uint64_t MaxFunctionCount = 0, MaxBlockCount = 0;
   size_t ShownFunctions = 0, TotalFunctions = 0;
   for (const auto &Func : *Reader) {
+    StringRef FuncName = Func.Name;
+    if (FuncName.empty() && ProfSyms)
+      ProfSyms->getFunctionName(Func.NameKey, 0, FuncName);
+    uint64_t ShowFunctionKey = 0;
+    if (!ShowFunction.empty())
+      ShowFunctionKey = IndexedInstrProf::ComputeHash(
+          IndexedInstrProf::HashType, ShowFunction);
     bool Show =
-        ShowAllFunctions || (!ShowFunction.empty() &&
-                             Func.Name.find(ShowFunction) != Func.Name.npos);
+        ShowAllFunctions ||
+        (!ShowFunction.empty() &&
+         ((!FuncName.empty() && FuncName.find(ShowFunction) != FuncName.npos) ||
+          ShowFunctionKey == Func.NameKey));
 
     ++TotalFunctions;
     assert(Func.Counts.size() > 0 && "function missing entry counter");
@@ -157,9 +216,11 @@
       if (!ShownFunctions)
         OS << "Counters:\n";
       ++ShownFunctions;
-
-      OS << "  " << Func.Name << ":\n"
-         << "    Hash: " << format("0x%016" PRIx64, Func.Hash) << "\n"
+      if (FuncName.empty())
+        OS << "  " << format("%" PRIx64, Func.NameKey) << ":\n";
+      else
+        OS << "  " << FuncName << ":\n";
+      OS << "    Hash: " << format("0x%016" PRIx64, Func.Hash) << "\n"
          << "    Counters: " << Func.Counts.size() << "\n"
          << "    Function count: " << Func.Counts[0] << "\n";
     }
@@ -217,6 +278,12 @@
   cl::opt<std::string> ShowFunction("function",
                                     cl::desc("Details for matching functions"));
 
+  cl::opt<std::string> BinFilename(
+      "instr-binary",
+      cl::desc("Path of unstripped binary with instrumentation"));
+  cl::opt<std::string> Arch("arch",
+                            cl::desc("architecture of the profiled binary"));
+
   cl::opt<std::string> OutputFilename("output", cl::value_desc("output"),
                                       cl::init("-"), cl::desc("Output file"));
   cl::alias OutputFilenameA("o", cl::desc("Alias for --output"),
@@ -240,8 +307,8 @@
     errs() << "warning: -function argument ignored: showing all functions\n";
 
   if (ProfileKind == instr)
-    return showInstrProfile(Filename, ShowCounts, ShowAllFunctions,
-                            ShowFunction, OS);
+    return showInstrProfile(Filename, BinFilename, Arch, ShowCounts,
+                            ShowAllFunctions, ShowFunction, OS);
   else
     return showSampleProfile(Filename, ShowCounts, ShowAllFunctions,
                              ShowFunction, OS);
Index: unittests/ProfileData/InstrProfTest.cpp
===================================================================
--- unittests/ProfileData/InstrProfTest.cpp
+++ unittests/ProfileData/InstrProfTest.cpp
@@ -56,7 +56,9 @@
 
   auto I = Reader->begin(), E = Reader->end();
   ASSERT_TRUE(I != E);
-  ASSERT_EQ(StringRef("foo"), I->Name);
+  ASSERT_EQ(IndexedInstrProf::ComputeHash(IndexedInstrProf::HashType,
+                                          StringRef("foo")),
+            I->NameKey);
   ASSERT_EQ(0x1234U, I->Hash);
   ASSERT_EQ(4U, I->Counts.size());
   ASSERT_EQ(1U, I->Counts[0]);